/
redgpu
/
ispc
Обзор
Документация
Войти
/
redgpu
/
ispc
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
test
src/opt.cpp
743 строки
31 KB
Dmitry Babokin
LLVM 17.0: StandardInstrumentations::registerCallbacks() requires MAM
04 авг 2023, 08:46
04 авг 2023, 08:46
529fb09
Код
Авторство
О чём код?
/* Copyright (c) 2010-2023, Intel Corporation SPDX-License-Identifier: BSD-3-Clause */ /** @file opt.cpp @brief Implementation of ISPC optimization pipeline. */ #include "opt.h" #include "ctx.h" #include "llvmutil.h" #include "module.h" #include "opt/ISPCPasses.h" #include "sym.h" #include "util.h" #include <map> #include <regex> #include <set> #include <sstream> #include <stdio.h> #include <llvm/ADT/SmallSet.h> #include <llvm/Analysis/BasicAliasAnalysis.h> #include <llvm/Analysis/ConstantFolding.h> #include <llvm/Analysis/GlobalsModRef.h> #include <llvm/Analysis/OptimizationRemarkEmitter.h> #include <llvm/Analysis/Passes.h> #include <llvm/Analysis/ScopedNoAliasAA.h> #include <llvm/Analysis/TargetLibraryInfo.h> #include <llvm/Analysis/TargetTransformInfo.h> #include <llvm/Analysis/TypeBasedAliasAnalysis.h> #include <llvm/BinaryFormat/Dwarf.h> #include <llvm/IR/DataLayout.h> #if ISPC_LLVM_VERSION >= ISPC_LLVM_16_0 #include <llvm/IRPrinter/IRPrintingPasses.h> #else #include <llvm/IR/IRPrintingPasses.h> #endif #include <llvm/IR/LegacyPassManager.h> #include <llvm/PassRegistry.h> #include <llvm/Passes/PassBuilder.h> #include <llvm/Passes/StandardInstrumentations.h> #include <llvm/Target/TargetMachine.h> #include <llvm/Target/TargetOptions.h> #if ISPC_LLVM_VERSION >= ISPC_LLVM_17_0 #include <llvm/TargetParser/Triple.h> #else #include <llvm/ADT/Triple.h> #endif #include <llvm/Transforms/IPO/ArgumentPromotion.h> #include <llvm/Transforms/IPO/ConstantMerge.h> #include <llvm/Transforms/IPO/DeadArgumentElimination.h> #include <llvm/Transforms/IPO/GlobalDCE.h> #include <llvm/Transforms/IPO/GlobalOpt.h> #include <llvm/Transforms/IPO/Inliner.h> #include <llvm/Transforms/IPO/SCCP.h> #include <llvm/Transforms/IPO/StripDeadPrototypes.h> #include <llvm/Transforms/InstCombine/InstCombine.h> #include <llvm/Transforms/Instrumentation.h> #include <llvm/Transforms/Scalar.h> #include <llvm/Transforms/Scalar/ADCE.h> #include <llvm/Transforms/Scalar/CorrelatedValuePropagation.h> #include <llvm/Transforms/Scalar/DCE.h> #include <llvm/Transforms/Scalar/DeadStoreElimination.h> #include <llvm/Transforms/Scalar/EarlyCSE.h> #include <llvm/Transforms/Scalar/GVN.h> #include <llvm/Transforms/Scalar/IndVarSimplify.h> #include <llvm/Transforms/Scalar/InstSimplifyPass.h> #include <llvm/Transforms/Scalar/JumpThreading.h> #include <llvm/Transforms/Scalar/LICM.h> #include <llvm/Transforms/Scalar/LoopDeletion.h> #include <llvm/Transforms/Scalar/LoopIdiomRecognize.h> #include <llvm/Transforms/Scalar/LoopRotation.h> #include <llvm/Transforms/Scalar/LoopUnrollPass.h> #include <llvm/Transforms/Scalar/LowerExpectIntrinsic.h> #include <llvm/Transforms/Scalar/LowerMatrixIntrinsics.h> #include <llvm/Transforms/Scalar/MemCpyOptimizer.h> #include <llvm/Transforms/Scalar/NewGVN.h> #include <llvm/Transforms/Scalar/Reassociate.h> #include <llvm/Transforms/Scalar/SCCP.h> #include <llvm/Transforms/Scalar/SROA.h> #include <llvm/Transforms/Scalar/SimpleLoopUnswitch.h> #include <llvm/Transforms/Scalar/SimplifyCFG.h> #include <llvm/Transforms/Scalar/TailRecursionElimination.h> #include <llvm/Transforms/Utils/Mem2Reg.h> #include <llvm/Transforms/Vectorize/LoadStoreVectorizer.h> #ifdef ISPC_HOST_IS_LINUX #include <alloca.h> #elif defined(ISPC_HOST_IS_WINDOWS) #include <malloc.h> #ifndef __MINGW32__ #define alloca _alloca #endif #endif // ISPC_HOST_IS_WINDOWS #ifdef ISPC_XE_ENABLED #include <llvm/GenXIntrinsics/GenXSPIRVWriterAdaptor.h> #endif using namespace ispc; /////////////////////////////////////////////////////////////////////////// // This is a wrap over class llvm::ModulePassManager. This duplicates PassManager function run() // and adds several add functions with some checks and debug passes. // This wrap can control: // - If we want to switch off optimization with given number. // - If we want to dump LLVM IR after optimization with given number. // - If we want to generate LLVM IR debug for gdb after optimization with given number. class DebugModulePassManager { public: DebugModulePassManager(llvm::Module &M, int optLevel) : m_passNumber(0), m_optLevel(optLevel) { m = &M; llvm::Triple targetTriple = llvm::Triple(m->getTargetTriple()); llvm::TargetLibraryInfoImpl targetLibraryInfo(targetTriple); targetMachine = g->target->GetTargetMachine(); // We have to register an llvm::OptNoneInstrumentation with a llvm::PassInstrumentationCallbacks, // which is then registered in the llvm::PassBuilder constructor. // This ensures that any function with optnone will not be optimized. OptNoneInst.registerCallbacks(PIC); if (g->debugPMTimeTrace) { // Enable time traces for optimization passes. TimePasses.registerCallbacks(PIC); } // Create the new pass manager builder using our target machine. #if ISPC_LLVM_VERSION >= ISPC_LLVM_16_0 pb = llvm::PassBuilder(targetMachine, llvm::PipelineTuningOptions(), std::nullopt, &PIC); #else pb = llvm::PassBuilder(targetMachine, llvm::PipelineTuningOptions(), llvm::None, &PIC); #endif // Register all the basic analyses with the managers. pb.registerModuleAnalyses(mam); pb.registerCGSCCAnalyses(cgam); pb.registerFunctionAnalyses(fam); pb.registerLoopAnalyses(lam); pb.crossRegisterProxies(lam, fam, cgam, mam); #if ISPC_LLVM_VERSION >= ISPC_LLVM_17_0 SI.registerCallbacks(PIC, &mam); #else SI.registerCallbacks(PIC, &fam); #endif // Register all the analysis passes fam.registerPass([&] { return targetMachine->getTargetIRAnalysis(); }); fam.registerPass([&] { return llvm::TargetLibraryAnalysis(targetLibraryInfo); }); // Add alias analysis for more aggressive optimizations if (m_optLevel != 0) { llvm::AAManager aam; // The order in which these are registered determines their priority when // being queried. // First we register the basic alias analysis that provides the majority of // per-function local AA logic. This is a stateless, on-demand local set of // AA techniques. aam.registerFunctionAnalysis<llvm::BasicAA>(); // Next we query fast, specialized alias analyses that wrap IR-embedded // information about aliasing. aam.registerFunctionAnalysis<llvm::ScopedNoAliasAA>(); aam.registerFunctionAnalysis<llvm::TypeBasedAA>(); // Add support for querying global aliasing information when available. // Because the `AAManager` is a function analysis and `GlobalsAA` is a module // analysis, all that the `AAManager` can do is query for any *cached* // results from `GlobalsAA` through a readonly proxy. // aam.registerModuleAnalysis<llvm::GlobalsAA>(); // Add target-specific alias analyses. if (targetMachine) { targetMachine->registerDefaultAliasAnalyses(aam); } fam.registerPass([aam] { return std::move(aam); }); } } llvm::PreservedAnalyses run() { return mpm.run(*m, mam); } enum Passes { Module, Function, Loop }; template <typename T> void addModulePass(T &&P, int stage = -1); template <typename T> void addPostOrderCGSCCPass(T &&P, int stage = -1); template <typename T> void addFunctionPass(T &&P, int stage = -1); template <typename T> void addLoopPass(T &&P, int stage = -1); // Start a new group of function passes void initFunctionPassManager(); // Add function passes to the ModulePassManager void commitFunctionToModulePassManager(); // Start a new group of loop passes void initLoopPassManager(); // Add loop passes to the FunctionPassManager void commitLoopToFunctionPassManager(bool memorySSA = false, bool blocksFreq = false); private: llvm::TargetMachine *targetMachine; llvm::PassBuilder pb; llvm::LoopAnalysisManager lam; llvm::FunctionAnalysisManager fam; llvm::CGSCCAnalysisManager cgam; llvm::ModuleAnalysisManager mam; llvm::ModulePassManager mpm; llvm::PassInstrumentationCallbacks PIC; llvm::PrintPassOptions PrintPassOpts{/*Verbose*/ true, /*SkipAnalyses*/ true, /*Indent*/ true}; #if ISPC_LLVM_VERSION >= ISPC_LLVM_16_0 llvm::StandardInstrumentations SI{*g->ctx, /*DebugLogging*/ g->debugPM, /*VerifyEach*/ false, PrintPassOpts}; #else llvm::StandardInstrumentations SI{/*DebugLogging*/ g->debugPM, /*VerifyEach*/ false, PrintPassOpts}; #endif llvm::OptNoneInstrumentation OptNoneInst{/*DebugLogging*/ false}; llvm::TimePassesHandler TimePasses{true}; std::vector<std::unique_ptr<llvm::raw_fd_ostream>> outputDebugDumps; std::vector<std::unique_ptr<llvm::FunctionPassManager>> fpmVec; std::vector<std::unique_ptr<llvm::LoopPassManager>> lpmVec; llvm::Module *m; bool m_isFPMOpen{false}; bool m_isLPMOpen{false}; int m_passNumber; int m_optLevel; // Add pass to pass manager and print IR if needed void addPassAndDebugPrint(std::string name, DebugModulePassManager::Passes kind); }; // Strips all non-alphanumeric characters from given string. static std::string lSanitize(std::string in) { llvm::Regex r("[^[:alnum:]]"); while (r.match(in)) in = r.sub("", in); return in; } // Get path to dump file static std::string getDumpFilePath(std::string className, int pnum) { std::ostringstream oss; oss << "ir_" << pnum << "_" << lSanitize(std::string{className}) << ".ll"; const std::string pathFile{oss.str()}; #ifdef ISPC_HOST_IS_WINDOWS const std::string pathSep{"\\"}; #else const std::string pathSep{"/"}; #endif // ISPC_HOST_IS_WINDOWS std::string pathDirFile; if (!g->dumpFilePath.empty()) { llvm::sys::fs::create_directories(g->dumpFilePath); pathDirFile = g->dumpFilePath + pathSep + pathFile; } else { pathDirFile = pathFile; } return pathDirFile; } template <typename T> void DebugModulePassManager::addModulePass(T &&P, int stage) { Assert(!m_isFPMOpen && "FunctionPassManager must be committed before adding module passes."); Assert(!m_isLPMOpen && "LoopPassManager must be committed before adding module passes."); // taking number of optimization m_passNumber = (stage == -1) ? (m_passNumber + 1) : stage; if (g->off_stages.find(m_passNumber) == g->off_stages.end()) { mpm.addPass(std::move(P)); addPassAndDebugPrint(T::name().str(), DebugModulePassManager::Passes::Module); } } template <typename T> void DebugModulePassManager::addPostOrderCGSCCPass(T &&P, int stage) { Assert(!m_isFPMOpen && "FunctionPassManager must be committed before adding PostOrderCGSCC passes."); Assert(!m_isLPMOpen && "LoopPassManager must be committed before adding PostOrderCGSCC passes."); // taking number of optimization m_passNumber = (stage == -1) ? (m_passNumber + 1) : stage; if (g->off_stages.find(m_passNumber) == g->off_stages.end()) { // Add PostOrderCGSCC pass to the ModulePassManager directly through adaptor mpm.addPass(llvm::createModuleToPostOrderCGSCCPassAdaptor(std::move(P))); addPassAndDebugPrint(T::name().str(), DebugModulePassManager::Passes::Module); } } template <typename T> void DebugModulePassManager::addFunctionPass(T &&P, int stage) { Assert(m_isFPMOpen && "FunctionPassManager must be initialized before adding function passes"); // taking number of optimization m_passNumber = (stage == -1) ? (m_passNumber + 1) : stage; if (g->off_stages.find(m_passNumber) == g->off_stages.end()) { fpmVec.back()->addPass(std::move(P)); addPassAndDebugPrint(T::name().str(), DebugModulePassManager::Passes::Function); } } template <typename T> void DebugModulePassManager::addLoopPass(T &&P, int stage) { Assert(m_isLPMOpen && "LoopPassManager must be initialized before adding function passes"); // taking number of optimization m_passNumber = (stage == -1) ? (m_passNumber + 1) : stage; if (g->off_stages.find(m_passNumber) == g->off_stages.end()) { // if not debug stage, add pass to loop pass manager lpmVec.back()->addPass(std::move(P)); addPassAndDebugPrint(T::name().str(), DebugModulePassManager::Passes::Loop); } } // Add pass to pass manager and print IR if needed void DebugModulePassManager::addPassAndDebugPrint(std::string name, DebugModulePassManager::Passes kind) { if (g->off_stages.find(m_passNumber) == g->off_stages.end()) { if (g->debug_stages.find(m_passNumber) != g->debug_stages.end()) { char banner[100]; snprintf(banner, sizeof(banner), "\n\n*****LLVM IR after phase : %s*****\n\n", name.c_str()); llvm::raw_ostream *outputStream = nullptr; if (g->dumpFile) { std::error_code EC; std::unique_ptr<llvm::raw_fd_ostream> outFile = std::make_unique<llvm::raw_fd_ostream>( getDumpFilePath(name, m_passNumber), EC, llvm::sys::fs::OF_None); if (!EC) { outputDebugDumps.push_back(std::move(outFile)); outputStream = outputDebugDumps.back().get(); } } if (kind == Passes::Function) { fpmVec.back()->addPass(llvm::PrintFunctionPass(outputStream ? *outputStream : llvm::outs(), banner)); } else if (kind == Passes::Module) { mpm.addPass(llvm::PrintModulePass(outputStream ? *outputStream : llvm::outs(), banner)); } else if (kind == Passes::Loop) { lpmVec.back()->addPass(llvm::PrintLoopPass(outputStream ? *outputStream : llvm::outs(), banner)); } } } } // Start a new group of function passes void DebugModulePassManager::initFunctionPassManager() { Assert(!m_isFPMOpen && "FunctionPassManager has been already initialized"); auto fpm = std::make_unique<llvm::FunctionPassManager>(); fpmVec.push_back(std::move(fpm)); m_isFPMOpen = true; } // Add function passes to the ModulePassManager void DebugModulePassManager::commitFunctionToModulePassManager() { Assert(m_isFPMOpen && "FunctionPassManager has not been initialized or already committed."); if (fpmVec.empty()) { return; } // Get the last element of fpmVec llvm::FunctionPassManager *lastFPM = fpmVec.back().get(); mpm.addPass(llvm::createModuleToFunctionPassAdaptor(std::move(*lastFPM))); m_isFPMOpen = false; } // Start a new group of loop passes void DebugModulePassManager::initLoopPassManager() { Assert(!m_isLPMOpen && "LoopPassManager has been already initialized"); auto lpm = std::make_unique<llvm::LoopPassManager>(); lpmVec.push_back(std::move(lpm)); m_isLPMOpen = true; } // Add loop passes to the FunctionPassManager void DebugModulePassManager::commitLoopToFunctionPassManager(bool memorySSA, bool useBlockFrequencyInfo) { Assert(m_isLPMOpen && "LoopPassManager has not been initialized or already committed."); if (fpmVec.empty() || lpmVec.empty()) { return; } // Get the last element of lpmVec llvm::LoopPassManager *lastLPM = lpmVec.back().get(); fpmVec.back()->addPass( llvm::createFunctionToLoopPassAdaptor(std::move(*lastLPM), memorySSA, useBlockFrequencyInfo)); m_isLPMOpen = false; } void ispc::Optimize(llvm::Module *module, int optLevel) { if (g->debugPrint) { printf("*** Code going into optimization ***\n"); module->print(llvm::errs(), nullptr); } DebugModulePassManager optPM(*module, optLevel); if (g->enableLLVMIntrinsics) { // Required for matrix intrinsics. This needs to happen before VerifierPass. // TODO : Limit pass to only when llvm.matrix.* intrinsics are used. optPM.initFunctionPassManager(); optPM.addFunctionPass(llvm::LowerMatrixIntrinsicsPass()); // llvm.matrix optPM.commitFunctionToModulePassManager(); } optPM.addModulePass(llvm::VerifierPass(), 0); optPM.initFunctionPassManager(); optPM.initLoopPassManager(); optPM.addLoopPass(llvm::IndVarSimplifyPass()); optPM.commitLoopToFunctionPassManager(); optPM.commitFunctionToModulePassManager(); llvm::SimplifyCFGOptions simplifyCFGopt; simplifyCFGopt.HoistCommonInsts = true; if (optLevel == 0) { // This is more or less the minimum set of optimizations that we // need to do to generate code that will actually run. (We can't // run absolutely no optimizations, since the front-end needs us to // take the various __pseudo_* functions it has emitted and turn // them into something that can actually execute. #ifdef ISPC_XE_ENABLED // mem2reg affects several acos/asin tests with O0 on Gen9, // seems like a problem with VC BE. if (g->target->isXeTarget()) { optPM.initFunctionPassManager(); optPM.addFunctionPass(llvm::PromotePass()); optPM.commitFunctionToModulePassManager(); } #endif optPM.initFunctionPassManager(); optPM.addFunctionPass(ImproveMemoryOpsPass(), 100); if (g->opt.disableHandlePseudoMemoryOps == false) optPM.addFunctionPass(ReplacePseudoMemoryOpsPass()); optPM.addFunctionPass(IntrinsicsOpt(), 102); optPM.addFunctionPass(IsCompileTimeConstantPass(true)); optPM.commitFunctionToModulePassManager(); optPM.addModulePass(llvm::ModuleInlinerWrapperPass()); optPM.addModulePass(MakeInternalFuncsStaticPass()); optPM.initFunctionPassManager(); optPM.addFunctionPass(llvm::SimplifyCFGPass(simplifyCFGopt)); optPM.commitFunctionToModulePassManager(); optPM.addModulePass(llvm::GlobalDCEPass()); #ifdef ISPC_XE_ENABLED if (g->target->isXeTarget()) { optPM.initFunctionPassManager(); optPM.addFunctionPass(llvm::PromotePass()); // This pass is needed for correct prints work #if ISPC_LLVM_VERSION >= ISPC_LLVM_16_0 // We don't have any LICM or SimplifyCFG passes scheduled after us, that would cleanup // the CFG mess SROAPass may created if allowed to modify CFG, so forbid that. optPM.addFunctionPass(llvm::SROAPass(llvm::SROAOptions::PreserveCFG)); #elif ISPC_LLVM_VERSION >= ISPC_LLVM_14_0 optPM.addFunctionPass(llvm::SROAPass()); #else optPM.addFunctionPass(llvm::SROA()); #endif optPM.addFunctionPass(ReplaceLLVMIntrinsics()); optPM.addFunctionPass(CheckIRForXeTarget()); optPM.addFunctionPass(MangleOpenCLBuiltins()); optPM.commitFunctionToModulePassManager(); // This pass is required to prepare LLVM IR for open source SPIR-V translator optPM.addModulePass( llvm::GenXSPIRVWriterAdaptor(true /*RewriteTypes*/, false /*RewriteSingleElementVectors*/)); optPM.addModulePass(llvm::GlobalDCEPass()); } #endif } else { optPM.addModulePass(llvm::GlobalDCEPass(), 184); optPM.initFunctionPassManager(); optPM.addFunctionPass(llvm::SimplifyCFGPass(simplifyCFGopt), 192); #if ISPC_LLVM_VERSION >= ISPC_LLVM_16_0 optPM.addFunctionPass(llvm::SROAPass(llvm::SROAOptions::ModifyCFG)); #elif ISPC_LLVM_VERSION >= ISPC_LLVM_14_0 optPM.addFunctionPass(llvm::SROAPass()); #else optPM.addFunctionPass(llvm::SROA()); #endif optPM.addFunctionPass(llvm::EarlyCSEPass()); optPM.addFunctionPass(llvm::LowerExpectIntrinsicPass()); // Early optimizations to try to reduce the total amount of code to // work with if we can optPM.addFunctionPass(llvm::ReassociatePass(), 200); optPM.addFunctionPass(llvm::InstSimplifyPass()); optPM.addFunctionPass(llvm::DCEPass()); optPM.addFunctionPass(llvm::SimplifyCFGPass(simplifyCFGopt)); optPM.addFunctionPass(llvm::PromotePass()); optPM.addFunctionPass(llvm::ADCEPass()); if (g->opt.disableGatherScatterOptimizations == false && g->target->getVectorWidth() > 1) { optPM.addFunctionPass(llvm::InstCombinePass(), 210); optPM.addFunctionPass(ImproveMemoryOpsPass()); } if (!g->opt.disableMaskAllOnOptimizations) { optPM.addFunctionPass(IntrinsicsOpt(), 215); optPM.addFunctionPass(InstructionSimplifyPass()); } optPM.addFunctionPass(llvm::DCEPass(), 220); // On to more serious optimizations #if ISPC_LLVM_VERSION >= ISPC_LLVM_16_0 optPM.addFunctionPass(llvm::SROAPass(llvm::SROAOptions::ModifyCFG)); #elif ISPC_LLVM_VERSION >= ISPC_LLVM_14_0 optPM.addFunctionPass(llvm::SROAPass()); #else optPM.addFunctionPass(llvm::SROA()); #endif optPM.addFunctionPass(llvm::InstCombinePass()); optPM.addFunctionPass(llvm::SimplifyCFGPass(simplifyCFGopt)); optPM.addFunctionPass(llvm::PromotePass()); optPM.addFunctionPass(llvm::ReassociatePass()); optPM.initLoopPassManager(); optPM.addLoopPass(llvm::LoopFullUnrollPass()); optPM.commitLoopToFunctionPassManager(false, true); optPM.addFunctionPass(ReplaceStdlibShiftPass(), 229); optPM.addFunctionPass(llvm::InstCombinePass()); optPM.addFunctionPass(llvm::SimplifyCFGPass(simplifyCFGopt)); optPM.commitFunctionToModulePassManager(); optPM.addModulePass(llvm::GlobalOptPass()); optPM.addModulePass(llvm::IPSCCPPass()); optPM.addModulePass(llvm::DeadArgumentEliminationPass()); // No such pass with new PM // https://reviews.llvm.org/D44415 // optPM.add(llvm::createPruneEHPass()); optPM.addPostOrderCGSCCPass(llvm::PostOrderFunctionAttrsPass()); optPM.addModulePass(llvm::ReversePostOrderFunctionAttrsPass()); // Next inline pass will remove functions, saved by __keep_funcs_live optPM.addModulePass(llvm::ModuleInlinerWrapperPass()); optPM.initFunctionPassManager(); optPM.addFunctionPass(llvm::InstSimplifyPass()); optPM.addFunctionPass(llvm::DCEPass()); optPM.addFunctionPass(llvm::SimplifyCFGPass(simplifyCFGopt)); optPM.addFunctionPass(llvm::ADCEPass()); optPM.addFunctionPass(llvm::InstCombinePass(), 241); optPM.addFunctionPass(llvm::JumpThreadingPass()); optPM.addFunctionPass(llvm::SimplifyCFGPass(simplifyCFGopt)); #if ISPC_LLVM_VERSION >= ISPC_LLVM_16_0 optPM.addFunctionPass(llvm::SROAPass(llvm::SROAOptions::ModifyCFG)); #elif ISPC_LLVM_VERSION >= ISPC_LLVM_14_0 optPM.addFunctionPass(llvm::SROAPass()); #else optPM.addFunctionPass(llvm::SROA()); #endif optPM.addFunctionPass(llvm::InstCombinePass()); optPM.commitFunctionToModulePassManager(); #ifdef ISPC_XE_ENABLED if (g->target->isXeTarget()) { // Inline optPM.initFunctionPassManager(); optPM.addFunctionPass(llvm::CorrelatedValuePropagationPass()); optPM.addFunctionPass(llvm::InstCombinePass()); optPM.commitFunctionToModulePassManager(); optPM.addModulePass(llvm::GlobalDCEPass()); optPM.initFunctionPassManager(); optPM.addFunctionPass(llvm::InstCombinePass()); optPM.addFunctionPass(llvm::EarlyCSEPass()); optPM.commitFunctionToModulePassManager(); optPM.addModulePass(llvm::GlobalDCEPass()); } #endif optPM.initFunctionPassManager(); optPM.addFunctionPass(llvm::TailCallElimPass()); if (!g->opt.disableMaskAllOnOptimizations) { optPM.addFunctionPass(IntrinsicsOpt(), 250); optPM.addFunctionPass(InstructionSimplifyPass()); } if (g->opt.disableGatherScatterOptimizations == false && g->target->getVectorWidth() > 1) { optPM.addFunctionPass(llvm::InstCombinePass(), 255); optPM.addFunctionPass(ImproveMemoryOpsPass()); if (g->opt.disableCoalescing == false) { // It is important to run this here to make it easier to // finding matching gathers we can coalesce.. optPM.addFunctionPass(llvm::EarlyCSEPass(), 260); optPM.addFunctionPass(GatherCoalescePass()); } } optPM.commitFunctionToModulePassManager(); optPM.addModulePass(llvm::ModuleInlinerWrapperPass(), 265); // If we didn't decide to inline a function, check to see if we can // transform it to pass arguments by value instead of by reference. optPM.addPostOrderCGSCCPass(llvm::ArgumentPromotionPass()); optPM.initFunctionPassManager(); optPM.addFunctionPass(llvm::InstSimplifyPass()); optPM.addFunctionPass(IntrinsicsOpt()); optPM.addFunctionPass(InstructionSimplifyPass()); if (g->opt.disableGatherScatterOptimizations == false && g->target->getVectorWidth() > 1) { optPM.addFunctionPass(llvm::InstCombinePass(), 270); optPM.addFunctionPass(ImproveMemoryOpsPass()); } optPM.commitFunctionToModulePassManager(); optPM.addModulePass(llvm::IPSCCPPass(), 275); optPM.addModulePass(llvm::DeadArgumentEliminationPass()); optPM.initFunctionPassManager(); optPM.addFunctionPass(llvm::ADCEPass()); optPM.addFunctionPass(llvm::InstCombinePass()); optPM.addFunctionPass(llvm::SimplifyCFGPass(simplifyCFGopt)); if (g->opt.disableHandlePseudoMemoryOps == false) { optPM.addFunctionPass(ReplacePseudoMemoryOpsPass(), 280); } optPM.addFunctionPass(IntrinsicsOpt(), 281); optPM.addFunctionPass(InstructionSimplifyPass()); optPM.commitFunctionToModulePassManager(); optPM.addModulePass(llvm::ModuleInlinerWrapperPass()); // If we didn't decide to inline a function, check to see if we can // transform it to pass arguments by value instead of by reference. optPM.addPostOrderCGSCCPass(llvm::ArgumentPromotionPass()); optPM.initFunctionPassManager(); #if ISPC_LLVM_VERSION >= ISPC_LLVM_16_0 optPM.addFunctionPass(llvm::SROAPass(llvm::SROAOptions::ModifyCFG)); #elif ISPC_LLVM_VERSION >= ISPC_LLVM_14_0 optPM.addFunctionPass(llvm::SROAPass()); #else optPM.addFunctionPass(llvm::SROA()); #endif optPM.addFunctionPass(llvm::InstCombinePass()); optPM.addFunctionPass(InstructionSimplifyPass()); optPM.addFunctionPass(llvm::SimplifyCFGPass(simplifyCFGopt)); optPM.addFunctionPass(llvm::ReassociatePass()); // We provide the opt remark emitter pass for LICM to use. optPM.addFunctionPass(llvm::RequireAnalysisPass<llvm::OptimizationRemarkEmitterAnalysis, llvm::Function>()); optPM.initLoopPassManager(); // Loop passes using MemorySSA optPM.addLoopPass(llvm::LoopRotatePass(), 291); #if ISPC_LLVM_VERSION >= ISPC_LLVM_15_0 // Use LLVM default options llvm::LICMOptions licmOpts; optPM.addLoopPass(llvm::LICMPass(licmOpts), 292); #else optPM.addLoopPass(llvm::LICMPass(), 292); #endif if (!g->target->isXeTarget()) { // SimpleLoopUnswitch is not a full equivalent of LoopUnswitch pass. // It produces much more basic blocks than LoopUnswitch which is // not efficient for Xe targets. Moreover when this pass is used // some integer division tests are failing on TGLLP Windows. // Disable this pass on Xe until the problem is fixed on BE side. optPM.addLoopPass(llvm::SimpleLoopUnswitchPass(false), 293); } optPM.commitLoopToFunctionPassManager(true, true); optPM.addFunctionPass(llvm::InstCombinePass()); optPM.addFunctionPass(InstructionSimplifyPass()); optPM.initLoopPassManager(); optPM.addLoopPass(llvm::IndVarSimplifyPass()); // Currently VC BE does not support memset/memcpy // so this pass is temporary disabled for Xe. if (!g->target->isXeTarget()) { optPM.addLoopPass(llvm::LoopIdiomRecognizePass()); } optPM.addLoopPass(llvm::LoopDeletionPass()); optPM.commitLoopToFunctionPassManager(); if (g->opt.unrollLoops) { optPM.addFunctionPass(llvm::LoopUnrollPass(), 300); } // For Xe targets NewGVN pass produces more efficient code due to better resolving of branches. // On CPU targets it is effective in optimizing certain types of code, // but it is not be beneficial in all cases. #if ISPC_LLVM_VERSION >= ISPC_LLVM_14_0 if (g->target->isXeTarget()) { optPM.addFunctionPass(llvm::NewGVNPass(), 301); } else { optPM.addFunctionPass(llvm::GVNPass(), 301); } #else optPM.addFunctionPass(llvm::GVN(), 301); #endif optPM.addFunctionPass(IsCompileTimeConstantPass(true)); optPM.addFunctionPass(IntrinsicsOpt()); optPM.addFunctionPass(InstructionSimplifyPass()); #ifdef ISPC_XE_ENABLED if (g->target->isXeTarget() && g->opt.disableGatherScatterOptimizations == false && g->target->getVectorWidth() > 1) { if (!g->opt.disableXeGatherCoalescing) { optPM.addFunctionPass(XeGatherCoalescing(), 321); // Try the llvm provided load/store vectorizer optPM.addFunctionPass(llvm::LoadStoreVectorizerPass(), 325); } } #endif // Currently VC BE does not support memset/memcpy // so this pass is temporary disabled for Xe. if (!g->target->isXeTarget()) { optPM.addFunctionPass(llvm::MemCpyOptPass()); } optPM.addFunctionPass(llvm::SCCPPass()); optPM.addFunctionPass(llvm::InstCombinePass()); optPM.addFunctionPass(InstructionSimplifyPass()); optPM.addFunctionPass(llvm::JumpThreadingPass()); optPM.addFunctionPass(llvm::CorrelatedValuePropagationPass()); optPM.addFunctionPass(llvm::DSEPass()); optPM.addFunctionPass(llvm::ADCEPass()); optPM.addFunctionPass(llvm::SimplifyCFGPass(simplifyCFGopt)); optPM.addFunctionPass(llvm::InstCombinePass()); optPM.addFunctionPass(InstructionSimplifyPass()); #ifdef ISPC_XE_ENABLED if (g->target->isXeTarget()) { optPM.addFunctionPass(ReplaceLLVMIntrinsics()); } #endif optPM.addFunctionPass(PeepholePass()); optPM.addFunctionPass(llvm::ADCEPass()); optPM.commitFunctionToModulePassManager(); optPM.addModulePass(llvm::ModuleInlinerWrapperPass()); optPM.addModulePass(llvm::StripDeadPrototypesPass()); optPM.addModulePass(MakeInternalFuncsStaticPass()); optPM.addModulePass(llvm::GlobalDCEPass()); optPM.addModulePass(llvm::ConstantMergePass()); #ifdef ISPC_XE_ENABLED if (g->target->isXeTarget()) { optPM.initFunctionPassManager(); optPM.addFunctionPass(CheckIRForXeTarget()); optPM.addFunctionPass(MangleOpenCLBuiltins()); optPM.commitFunctionToModulePassManager(); // This pass is required to prepare LLVM IR for open source SPIR-V translator optPM.addModulePass( llvm::GenXSPIRVWriterAdaptor(true /*RewriteTypes*/, false /*RewriteSingleElementVectors*/)); } #endif } // Finish up by making sure we didn't mess anything up in the IR along // the way. optPM.addModulePass(llvm::VerifierPass(), LAST_OPT_NUMBER); optPM.run(); if (g->debugPrint) { printf("\n*****\nFINAL OUTPUT\n*****\n"); module->print(llvm::errs(), nullptr); } }