diff --git a/doc/src/devdocs/llvm.md b/doc/src/devdocs/llvm.md index 9a833ca8af5162..6c6b33c2281dc3 100644 --- a/doc/src/devdocs/llvm.md +++ b/doc/src/devdocs/llvm.md @@ -9,18 +9,36 @@ Julia dynamically links against LLVM by default. Build with `USE_LLVM_SHLIB=0` t The code for lowering Julia AST to LLVM IR or interpreting it directly is in directory `src/`. -| File | Description | -|:------------------- |:---------------------------------------------------------- | -| `builtins.c` | Builtin functions | -| `ccall.cpp` | Lowering [`ccall`](@ref) | -| `cgutils.cpp` | Lowering utilities, notably for array and tuple accesses | -| `codegen.cpp` | Top-level of code generation, pass list, lowering builtins | -| `debuginfo.cpp` | Tracks debug information for JIT code | -| `disasm.cpp` | Handles native object file and JIT code diassembly | -| `gf.c` | Generic functions | -| `intrinsics.cpp` | Lowering intrinsics | -| `llvm-simdloop.cpp` | Custom LLVM pass for [`@simd`](@ref) | -| `sys.c` | I/O and operating system utility functions | +| File | Description | +|:-------------------------------- |:------------------------------------------------------------------ | +| `aotcompile.cpp` | Legacy pass manager pipeline, compiler C-interface entry | +| `builtins.c` | Builtin functions | +| `ccall.cpp` | Lowering [`ccall`](@ref) | +| `cgutils.cpp` | Lowering utilities, notably for array and tuple accesses | +| `codegen.cpp` | Top-level of code generation, pass list, lowering builtins | +| `debuginfo.cpp` | Tracks debug information for JIT code | +| `disasm.cpp` | Handles native object file and JIT code diassembly | +| `gf.c` | Generic functions | +| `intrinsics.cpp` | Lowering intrinsics | +| `jitlayers.cpp` | JIT-specific code, ORC compilation layers/utilities | +| `llvm-alloc-helpers.cpp` | Julia-specific escape analysis | +| `llvm-alloc-opt.cpp` | Custom LLVM pass to demote heap allocations to the stack | +| `llvm-cpufeatures.cpp` | Custom LLVM pass to lower CPU-based functions (e.g. haveFMA) | +| `llvm-demote-float16.cpp` | Custom LLVM pass to lower 16b float ops to 32b float ops | +| `llvm-final-gc-lowering.cpp` | Custom LLVM pass to lower GC calls to their final form | +| `llvm-gc-invariant-verifier.cpp` | Custom LLVM pass to verify Julia GC invariants | +| `llvm-julia-licm.cpp` | Custom LLVM pass to hoist/sink Julia-specific intrinsics | +| `llvm-late-gc-lowering.cpp` | Custom LLVM pass to root GC-tracked values | +| `llvm-lower-handlers.cpp` | Custom LLVM pass to lower try-catch blocks | +| `llvm-muladd.cpp` | Custom LLVM pass for fast-match FMA | +| `llvm-multiversioning.cpp` | Custom LLVM pass to generate sysimg code on multiple architectures | +| `llvm-propagate-addrspaces.cpp` | Custom LLVM pass to canonicalize addrspaces | +| `llvm-ptls.cpp` | Custom LLVM pass to lower TLS operations | +| `llvm-remove-addrspaces.cpp` | Custom LLVM pass to remove Julia addrspaces | +| `llvm-remove-ni.cpp` | Custom LLVM pass to remove Julia non-integral addrspaces | +| `llvm-simdloop.cpp` | Custom LLVM pass for [`@simd`](@ref) | +| `pipeline.cpp` | New pass manager pipeline, pass pipeline parsing | +| `sys.c` | I/O and operating system utility functions | Some of the `.cpp` files form a group that compile to a single object. @@ -77,12 +95,18 @@ LLVM tools as usual. `libjulia` can function as an LLVM pass plugin and can be loaded into LLVM tools, to make julia-specific passes available in this environment. In addition, it exposes the `-julia` meta-pass, which runs the entire Julia pass-pipeline over the IR. As an example, to generate a system -image, one could do: +image with the old pass manager, one could do: ``` opt -enable-new-pm=0 -load libjulia-codegen.so -julia -o opt.bc unopt.bc llc -o sys.o opt.bc cc -shared -o sys.so sys.o ``` +To generate a system image with the new pass manager, one could do: +``` +opt -load-pass-plugin=libjulia-codegen.so --passes='julia' -o opt.bc unopt.bc +llc -o sys.o opt.bc +cc -shared -o sys.so sys.o +``` This system image can then be loaded by `julia` as usual. It is also possible to dump an LLVM IR module for just one Julia function, diff --git a/src/aotcompile.cpp b/src/aotcompile.cpp index 141f96b332340a..9ba46687081d4b 100644 --- a/src/aotcompile.cpp +++ b/src/aotcompile.cpp @@ -562,7 +562,7 @@ void jl_dump_native_impl(void *native_code, addOptimizationPasses(&optimizer, jl_options.opt_level, true, true); addMachinePasses(&optimizer, jl_options.opt_level); #else - NewPM optimizer{std::move(TM), getOptLevel(jl_options.opt_level), {true, true, false}}; + NewPM optimizer{std::move(TM), getOptLevel(jl_options.opt_level), OptimizationOptions::defaults(true, true)}; #endif Type *T_size; @@ -961,45 +961,6 @@ void jl_add_optimization_passes_impl(LLVMPassManagerRef PM, int opt_level, int l addOptimizationPasses(unwrap(PM), opt_level, lower_intrinsics); } -// new pass manager plugin - -// NOTE: Instead of exporting all the constructors in passes.h we could -// forward the callbacks to the respective passes. LLVM seems to prefer this, -// and when we add the full pass builder having them directly will be helpful. -static void registerCallbacks(PassBuilder &PB) { - PB.registerPipelineParsingCallback( - [](StringRef Name, FunctionPassManager &PM, - ArrayRef InnerPipeline) { -#define FUNCTION_PASS(NAME, CREATE_PASS) if (Name == NAME) { PM.addPass(CREATE_PASS); return true; } -#include "llvm-julia-passes.inc" -#undef FUNCTION_PASS - return false; - }); - - PB.registerPipelineParsingCallback( - [](StringRef Name, ModulePassManager &PM, - ArrayRef InnerPipeline) { -#define MODULE_PASS(NAME, CREATE_PASS) if (Name == NAME) { PM.addPass(CREATE_PASS); return true; } -#include "llvm-julia-passes.inc" -#undef MODULE_PASS - return false; - }); - - PB.registerPipelineParsingCallback( - [](StringRef Name, LoopPassManager &PM, - ArrayRef InnerPipeline) { -#define LOOP_PASS(NAME, CREATE_PASS) if (Name == NAME) { PM.addPass(CREATE_PASS); return true; } -#include "llvm-julia-passes.inc" -#undef LOOP_PASS - return false; - }); -} - -extern "C" JL_DLLEXPORT ::llvm::PassPluginLibraryInfo -llvmGetPassPluginInfo() { - return {LLVM_PLUGIN_API_VERSION, "Julia", "1", registerCallbacks}; -} - // --- native code info, and dump function to IR and ASM --- // Get pointer to llvm::Function instance, compiling if necessary // for use in reflection from Julia. diff --git a/src/jitlayers.h b/src/jitlayers.h index 54a76630330f8b..1db02c39524876 100644 --- a/src/jitlayers.h +++ b/src/jitlayers.h @@ -78,9 +78,14 @@ struct OptimizationOptions { bool lower_intrinsics; bool dump_native; bool external_use; - - static constexpr OptimizationOptions defaults() { - return {true, false, false}; + bool llvm_only; + + static constexpr OptimizationOptions defaults( + bool lower_intrinsics=true, + bool dump_native=false, + bool external_use=false, + bool llvm_only=false) { + return {lower_intrinsics, dump_native, external_use, llvm_only}; } }; diff --git a/src/pipeline.cpp b/src/pipeline.cpp index f49ff112638655..d5bfa9fcdabb51 100644 --- a/src/pipeline.cpp +++ b/src/pipeline.cpp @@ -172,11 +172,10 @@ namespace { // } } - void addVerificationPasses(ModulePassManager &MPM) { - FunctionPassManager FPM; - FPM.addPass(GCInvariantVerifierPass()); - FPM.addPass(VerifierPass()); - MPM.addPass(llvm::createModuleToFunctionPassAdaptor(std::move(FPM))); + void addVerificationPasses(ModulePassManager &MPM, bool llvm_only) { + if (!llvm_only) + MPM.addPass(llvm::createModuleToFunctionPassAdaptor(GCInvariantVerifierPass())); + MPM.addPass(VerifierPass()); } auto basicSimplifyCFGOptions() { @@ -207,16 +206,17 @@ namespace { //the PassBuilder extension point callbacks //For now we'll maintain the insertion points even though they don't do anything //for the sake of documentation - void invokePipelineStartCallbacks(ModulePassManager &MPM, PassBuilder &PB, OptimizationLevel O) {} - void invokePeepholeEPCallbacks(FunctionPassManager &MPM, PassBuilder &PB, OptimizationLevel O) {} - void invokeEarlySimplificationCallbacks(ModulePassManager &MPM, PassBuilder &PB, OptimizationLevel O) {} - void invokeCGSCCCallbacks(CGSCCPassManager &MPM, PassBuilder &PB, OptimizationLevel O) {} - void invokeOptimizerEarlyCallbacks(ModulePassManager &MPM, PassBuilder &PB, OptimizationLevel O) {} - void invokeLateLoopOptimizationCallbacks(LoopPassManager &MPM, PassBuilder &PB, OptimizationLevel O) {} - void invokeLoopOptimizerEndCallbacks(LoopPassManager &MPM, PassBuilder &PB, OptimizationLevel O) {} - void invokeScalarOptimizerCallbacks(FunctionPassManager &MPM, PassBuilder &PB, OptimizationLevel O) {} - void invokeVectorizerCallbacks(FunctionPassManager &MPM, PassBuilder &PB, OptimizationLevel O) {} - void invokeOptimizerLastCallbacks(ModulePassManager &MPM, PassBuilder &PB, OptimizationLevel O) {} + //If PB is a nullptr, don't invoke anything (this happens when running julia from opt) + void invokePipelineStartCallbacks(ModulePassManager &MPM, PassBuilder *PB, OptimizationLevel O) {} + void invokePeepholeEPCallbacks(FunctionPassManager &MPM, PassBuilder *PB, OptimizationLevel O) {} + void invokeEarlySimplificationCallbacks(ModulePassManager &MPM, PassBuilder *PB, OptimizationLevel O) {} + void invokeCGSCCCallbacks(CGSCCPassManager &MPM, PassBuilder *PB, OptimizationLevel O) {} + void invokeOptimizerEarlyCallbacks(ModulePassManager &MPM, PassBuilder *PB, OptimizationLevel O) {} + void invokeLateLoopOptimizationCallbacks(LoopPassManager &MPM, PassBuilder *PB, OptimizationLevel O) {} + void invokeLoopOptimizerEndCallbacks(LoopPassManager &MPM, PassBuilder *PB, OptimizationLevel O) {} + void invokeScalarOptimizerCallbacks(FunctionPassManager &MPM, PassBuilder *PB, OptimizationLevel O) {} + void invokeVectorizerCallbacks(FunctionPassManager &MPM, PassBuilder *PB, OptimizationLevel O) {} + void invokeOptimizerLastCallbacks(ModulePassManager &MPM, PassBuilder *PB, OptimizationLevel O) {} } //The actual pipelines @@ -239,15 +239,17 @@ namespace { //? loop sink pass //? hot-cold splitting pass +#define JULIA_PASS(ADD_PASS) if (!options.llvm_only) { ADD_PASS; } else do;while (0) + //Use for O1 and below -void buildBasicPipeline(ModulePassManager &MPM, PassBuilder &PB, OptimizationLevel O, OptimizationOptions options) { +void buildBasicPipeline(ModulePassManager &MPM, PassBuilder *PB, OptimizationLevel O, OptimizationOptions options) { // #ifdef JL_DEBUG_BUILD - addVerificationPasses(MPM); + addVerificationPasses(MPM, options.llvm_only); // #endif invokePipelineStartCallbacks(MPM, PB, O); MPM.addPass(ConstantMergePass()); if (!options.dump_native) { - MPM.addPass(CPUFeatures()); + JULIA_PASS(MPM.addPass(CPUFeatures())); if (O.getSpeedupLevel() > 0) { MPM.addPass(createModuleToFunctionPassAdaptor(InstSimplifyPass())); } @@ -271,7 +273,7 @@ void buildBasicPipeline(ModulePassManager &MPM, PassBuilder &PB, OptimizationLev MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM))); } invokeOptimizerEarlyCallbacks(MPM, PB, O); - MPM.addPass(LowerSIMDLoop()); + JULIA_PASS(MPM.addPass(LowerSIMDLoop())); { FunctionPassManager FPM; { @@ -288,21 +290,21 @@ void buildBasicPipeline(ModulePassManager &MPM, PassBuilder &PB, OptimizationLev //TODO no barrier pass? { FunctionPassManager FPM; - FPM.addPass(LowerExcHandlers()); - FPM.addPass(GCInvariantVerifierPass(false)); + JULIA_PASS(FPM.addPass(LowerExcHandlers())); + JULIA_PASS(FPM.addPass(GCInvariantVerifierPass(false))); MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); } - MPM.addPass(RemoveNI()); - MPM.addPass(createModuleToFunctionPassAdaptor(LateLowerGC())); - MPM.addPass(FinalLowerGCPass()); - MPM.addPass(LowerPTLSPass(options.dump_native)); + JULIA_PASS(MPM.addPass(RemoveNI())); + JULIA_PASS(MPM.addPass(createModuleToFunctionPassAdaptor(LateLowerGC()))); + JULIA_PASS(MPM.addPass(FinalLowerGCPass())); + JULIA_PASS(MPM.addPass(LowerPTLSPass(options.dump_native))); } else { - MPM.addPass(RemoveNI()); + JULIA_PASS(MPM.addPass(RemoveNI())); } - MPM.addPass(LowerSIMDLoop()); // TODO why do we do this twice + JULIA_PASS(MPM.addPass(LowerSIMDLoop())); // TODO why do we do this twice if (options.dump_native) { - MPM.addPass(MultiVersioning(options.external_use)); - MPM.addPass(CPUFeatures()); + JULIA_PASS(MPM.addPass(MultiVersioning(options.external_use))); + JULIA_PASS(MPM.addPass(CPUFeatures())); if (O.getSpeedupLevel() > 0) { FunctionPassManager FPM; FPM.addPass(InstSimplifyPass()); @@ -312,19 +314,19 @@ void buildBasicPipeline(ModulePassManager &MPM, PassBuilder &PB, OptimizationLev } invokeOptimizerLastCallbacks(MPM, PB, O); addSanitizerPasses(MPM, O); - MPM.addPass(createModuleToFunctionPassAdaptor(DemoteFloat16())); + JULIA_PASS(MPM.addPass(createModuleToFunctionPassAdaptor(DemoteFloat16()))); } //Use for O2 and above -void buildFullPipeline(ModulePassManager &MPM, PassBuilder &PB, OptimizationLevel O, OptimizationOptions options) { +void buildFullPipeline(ModulePassManager &MPM, PassBuilder *PB, OptimizationLevel O, OptimizationOptions options) { // #ifdef JL_DEBUG_BUILD - addVerificationPasses(MPM); + addVerificationPasses(MPM, options.llvm_only); // #endif invokePipelineStartCallbacks(MPM, PB, O); MPM.addPass(ConstantMergePass()); { FunctionPassManager FPM; - FPM.addPass(PropagateJuliaAddrspacesPass()); + JULIA_PASS(FPM.addPass(PropagateJuliaAddrspacesPass())); //TODO consider not using even basic simplification //options here, and adding a run of CVP to take advantage //of the unsimplified codegen information (e.g. known @@ -342,7 +344,7 @@ void buildFullPipeline(ModulePassManager &MPM, PassBuilder &PB, OptimizationLeve invokeCGSCCCallbacks(CGPM, PB, O); { FunctionPassManager FPM; - FPM.addPass(AllocOptPass()); + JULIA_PASS(FPM.addPass(AllocOptPass())); FPM.addPass(InstCombinePass()); FPM.addPass(SimplifyCFGPass(basicSimplifyCFGOptions())); CGPM.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM))); @@ -350,9 +352,9 @@ void buildFullPipeline(ModulePassManager &MPM, PassBuilder &PB, OptimizationLeve MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM))); } if (options.dump_native) { - MPM.addPass(MultiVersioning(options.external_use)); + JULIA_PASS(MPM.addPass(MultiVersioning(options.external_use))); } - MPM.addPass(CPUFeatures()); + JULIA_PASS(MPM.addPass(CPUFeatures())); { FunctionPassManager FPM; FPM.addPass(SROAPass()); @@ -361,7 +363,7 @@ void buildFullPipeline(ModulePassManager &MPM, PassBuilder &PB, OptimizationLeve FPM.addPass(CorrelatedValuePropagationPass()); FPM.addPass(ReassociatePass()); FPM.addPass(EarlyCSEPass()); - FPM.addPass(AllocOptPass()); + JULIA_PASS(FPM.addPass(AllocOptPass())); invokePeepholeEPCallbacks(FPM, PB, O); MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); } @@ -375,10 +377,10 @@ void buildFullPipeline(ModulePassManager &MPM, PassBuilder &PB, OptimizationLeve //We don't know if the loop callbacks support MSSA FPM.addPass(createFunctionToLoopPassAdaptor(std::move(LPM1), /*UseMemorySSA = */false)); LPM2.addPass(LICMPass()); - LPM2.addPass(JuliaLICMPass()); + JULIA_PASS(LPM2.addPass(JuliaLICMPass())); LPM2.addPass(SimpleLoopUnswitchPass()); LPM2.addPass(LICMPass()); - LPM2.addPass(JuliaLICMPass()); + JULIA_PASS(LPM2.addPass(JuliaLICMPass())); //LICM needs MemorySSA now, so we must use it FPM.addPass(createFunctionToLoopPassAdaptor(std::move(LPM2), /*UseMemorySSA = */true)); } @@ -394,7 +396,7 @@ void buildFullPipeline(ModulePassManager &MPM, PassBuilder &PB, OptimizationLeve FPM.addPass(createFunctionToLoopPassAdaptor(std::move(LPM), /*UseMemorySSA = */false)); } FPM.addPass(LoopUnrollPass()); - FPM.addPass(AllocOptPass()); + JULIA_PASS(FPM.addPass(AllocOptPass())); FPM.addPass(SROAPass()); FPM.addPass(InstSimplifyPass()); FPM.addPass(GVNPass()); @@ -411,7 +413,7 @@ void buildFullPipeline(ModulePassManager &MPM, PassBuilder &PB, OptimizationLeve FPM.addPass(DSEPass()); invokePeepholeEPCallbacks(FPM, PB, O); FPM.addPass(SimplifyCFGPass(aggressiveSimplifyCFGOptions())); - FPM.addPass(AllocOptPass()); + JULIA_PASS(FPM.addPass(AllocOptPass())); { LoopPassManager LPM; LPM.addPass(LoopDeletionPass()); @@ -434,15 +436,15 @@ void buildFullPipeline(ModulePassManager &MPM, PassBuilder &PB, OptimizationLeve //TODO barrier pass? { FunctionPassManager FPM; - FPM.addPass(LowerExcHandlers()); - FPM.addPass(GCInvariantVerifierPass(false)); + JULIA_PASS(FPM.addPass(LowerExcHandlers())); + JULIA_PASS(FPM.addPass(GCInvariantVerifierPass(false))); MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); } // Needed **before** LateLowerGCFrame on LLVM < 12 // due to bug in `CreateAlignmentAssumption`. - MPM.addPass(RemoveNI()); - MPM.addPass(createModuleToFunctionPassAdaptor(LateLowerGC())); - MPM.addPass(FinalLowerGCPass()); + JULIA_PASS(MPM.addPass(RemoveNI())); + JULIA_PASS(MPM.addPass(createModuleToFunctionPassAdaptor(LateLowerGC()))); + JULIA_PASS(MPM.addPass(FinalLowerGCPass())); { FunctionPassManager FPM; FPM.addPass(GVNPass()); @@ -450,7 +452,7 @@ void buildFullPipeline(ModulePassManager &MPM, PassBuilder &PB, OptimizationLeve FPM.addPass(DCEPass()); MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); } - MPM.addPass(LowerPTLSPass(options.dump_native)); + JULIA_PASS(MPM.addPass(LowerPTLSPass(options.dump_native))); { FunctionPassManager FPM; FPM.addPass(InstCombinePass()); @@ -458,11 +460,11 @@ void buildFullPipeline(ModulePassManager &MPM, PassBuilder &PB, OptimizationLeve MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); } } else { - MPM.addPass(RemoveNI()); + JULIA_PASS(MPM.addPass(RemoveNI())); } { FunctionPassManager FPM; - FPM.addPass(CombineMulAdd()); + JULIA_PASS(FPM.addPass(CombineMulAdd())); FPM.addPass(DivRemPairsPass()); MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); } @@ -470,12 +472,14 @@ void buildFullPipeline(ModulePassManager &MPM, PassBuilder &PB, OptimizationLeve addSanitizerPasses(MPM, O); { FunctionPassManager FPM; - FPM.addPass(DemoteFloat16()); + JULIA_PASS(FPM.addPass(DemoteFloat16())); FPM.addPass(GVNPass()); MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); } } +#undef JULIA_PASS + namespace { auto createPIC(StandardInstrumentations &SI) { auto PIC = std::make_unique(); @@ -553,9 +557,9 @@ PIC->addClassToPassName(decltype(CREATE_PASS)::name(), NAME); ModulePassManager createMPM(PassBuilder &PB, OptimizationLevel O, OptimizationOptions options) { ModulePassManager MPM; if (O.getSpeedupLevel() < 2) - buildBasicPipeline(MPM, PB, O, options); + buildBasicPipeline(MPM, &PB, O, options); else - buildFullPipeline(MPM, PB, O, options); + buildFullPipeline(MPM, &PB, O, options); return MPM; } } @@ -602,3 +606,108 @@ OptimizationLevel getOptLevel(int optlevel) { } llvm_unreachable("cannot get here!"); } + +//This part is also basically stolen from LLVM's PassBuilder.cpp file +static llvm::Optional> parseJuliaPipelineOptions(StringRef name) { + if (name.consume_front("julia")) { + auto O = OptimizationLevel::O2; + auto options = OptimizationOptions::defaults(); + if (!name.empty() && (!name.consume_front("<") || !name.consume_back(">"))) { + assert(false && "Expected pass options to be enclosed in <>!"); + } + std::map option_pointers = { +#define OPTION(name) {#name, &options.name} + OPTION(lower_intrinsics), + OPTION(dump_native), + OPTION(external_use), + OPTION(llvm_only) +#undef OPTION + }; + while (!name.empty()) { + StringRef option; + std::tie(option, name) = name.split(';'); + bool enable = !option.consume_front("no_"); + auto it = option_pointers.find(option); + if (it == option_pointers.end()) { + if (option.consume_front("level=")) { + int level = 2; + if (option.getAsInteger(0, level)) { + assert(false && "Non-integer passed to julia level!"); + } + switch (std::min(std::max(level, 0), 3)) { + case 0: + O = OptimizationLevel::O0; + break; + case 1: + O = OptimizationLevel::O1; + break; + case 2: + O = OptimizationLevel::O2; + break; + case 3: + O = OptimizationLevel::O3; + break; + } + } else { + errs() << "Unable to find julia option '" << option << "'!"; + assert(false && "Invalid option passed to julia pass!"); + } + } else { + *it->second = enable; + } + } + return {{O, options}}; + } + return {}; +} + +// new pass manager plugin + +// NOTE: Instead of exporting all the constructors in passes.h we could +// forward the callbacks to the respective passes. LLVM seems to prefer this, +// and when we add the full pass builder having them directly will be helpful. +void registerCallbacks(PassBuilder &PB) { + PB.registerPipelineParsingCallback( + [](StringRef Name, FunctionPassManager &PM, + ArrayRef InnerPipeline) { +#define FUNCTION_PASS(NAME, CREATE_PASS) if (Name == NAME) { PM.addPass(CREATE_PASS); return true; } +#include "llvm-julia-passes.inc" +#undef FUNCTION_PASS + return false; + }); + + PB.registerPipelineParsingCallback( + [](StringRef Name, ModulePassManager &PM, + ArrayRef InnerPipeline) { +#define MODULE_PASS(NAME, CREATE_PASS) if (Name == NAME) { PM.addPass(CREATE_PASS); return true; } +#include "llvm-julia-passes.inc" +#undef MODULE_PASS + //Add full pipelines here + auto julia_options = parseJuliaPipelineOptions(Name); + if (julia_options) { + ModulePassManager pipeline; + if (julia_options->first.getSpeedupLevel() < 2) { + buildBasicPipeline(pipeline, nullptr, julia_options->first, julia_options->second); + } else { + buildFullPipeline(pipeline, nullptr, julia_options->first, julia_options->second); + } + PM.addPass(std::move(pipeline)); + return true; + } + return false; + }); + + PB.registerPipelineParsingCallback( + [](StringRef Name, LoopPassManager &PM, + ArrayRef InnerPipeline) { +#define LOOP_PASS(NAME, CREATE_PASS) if (Name == NAME) { PM.addPass(CREATE_PASS); return true; } +#include "llvm-julia-passes.inc" +#undef LOOP_PASS + return false; + }); +} + +extern "C" JL_DLLEXPORT ::llvm::PassPluginLibraryInfo +llvmGetPassPluginInfo() { + return {LLVM_PLUGIN_API_VERSION, "Julia", "1", registerCallbacks}; +}