From 2a623f67dc37c44529644dd7cceaa775a7534588 Mon Sep 17 00:00:00 2001 From: Prem Chintalapudi Date: Sat, 1 Jul 2023 19:58:06 -0400 Subject: [PATCH] Add Julia newpm passes and pipeline. --- deps/LLVMExtra/include/NewPM.h | 13 +- deps/LLVMExtra/lib/newpm.cpp | 39 ++- lib/libLLVM_extra.jl | 33 ++- lib/libLLVM_julia.jl | 15 +- src/interop.jl | 4 + src/interop/newpm.jl | 70 ++++++ src/newpm.jl | 1 + src/newpm/analyses.jl | 71 ++++++ src/newpm/analysismanager.jl | 42 ++-- src/newpm/custompass.jl | 12 +- src/newpm/passbuilder.jl | 51 +++- src/newpm/passes.jl | 146 ++++++++--- src/newpm/passmanager.jl | 10 +- test/newpm.jl | 435 +++++++++++++++++++++++++++++++-- 14 files changed, 823 insertions(+), 119 deletions(-) create mode 100644 src/interop/newpm.jl create mode 100644 src/newpm/analyses.jl diff --git a/deps/LLVMExtra/include/NewPM.h b/deps/LLVMExtra/include/NewPM.h index 807cfd30..5c09c8e4 100644 --- a/deps/LLVMExtra/include/NewPM.h +++ b/deps/LLVMExtra/include/NewPM.h @@ -26,19 +26,16 @@ typedef struct LLVMOpaqueModuleAnalysisManager *LLVMModuleAnalysisManagerRef; typedef struct LLVMOpaqueCGSCCAnalysisManager *LLVMCGSCCAnalysisManagerRef; typedef struct LLVMOpaqueFunctionAnalysisManager *LLVMFunctionAnalysisManagerRef; typedef struct LLVMOpaqueLoopAnalysisManager *LLVMLoopAnalysisManagerRef; -typedef struct LLVMOpaqueAAManager *LLVMAAManagerRef; LLVMModuleAnalysisManagerRef LLVMCreateNewPMModuleAnalysisManager(void); LLVMCGSCCAnalysisManagerRef LLVMCreateNewPMCGSCCAnalysisManager(void); LLVMFunctionAnalysisManagerRef LLVMCreateNewPMFunctionAnalysisManager(void); LLVMLoopAnalysisManagerRef LLVMCreateNewPMLoopAnalysisManager(void); -LLVMAAManagerRef LLVMCreateNewPMAAManager(void); void LLVMDisposeNewPMModuleAnalysisManager(LLVMModuleAnalysisManagerRef AM); void LLVMDisposeNewPMCGSCCAnalysisManager(LLVMCGSCCAnalysisManagerRef AM); void LLVMDisposeNewPMFunctionAnalysisManager(LLVMFunctionAnalysisManagerRef AM); void LLVMDisposeNewPMLoopAnalysisManager(LLVMLoopAnalysisManagerRef AM); -void LLVMDisposeNewPMAAManager(LLVMAAManagerRef AM); typedef struct LLVMOpaqueModulePassManager *LLVMModulePassManagerRef; typedef struct LLVMOpaqueCGSCCPassManager *LLVMCGSCCPassManagerRef; @@ -79,7 +76,6 @@ LLVMErrorRef LLVMPassBuilderParseModulePassPipeline(LLVMPassBuilderRef PB, LLVMM LLVMErrorRef LLVMPassBuilderParseCGSCCPassPipeline(LLVMPassBuilderRef PB, LLVMCGSCCPassManagerRef PM, const char *PipelineText, size_t PipelineTextLength); LLVMErrorRef LLVMPassBuilderParseFunctionPassPipeline(LLVMPassBuilderRef PB, LLVMFunctionPassManagerRef PM, const char *PipelineText, size_t PipelineTextLength); LLVMErrorRef LLVMPassBuilderParseLoopPassPipeline(LLVMPassBuilderRef PB, LLVMLoopPassManagerRef PM, const char *PipelineText, size_t PipelineTextLength); -LLVMErrorRef LLVMPassBuilderParseAAPipeline(LLVMPassBuilderRef PB, LLVMAAManagerRef AM, const char *PipelineText, size_t PipelineTextLength); void LLVMPassBuilderRegisterModuleAnalyses(LLVMPassBuilderRef PB, LLVMModuleAnalysisManagerRef AM); void LLVMPassBuilderRegisterCGSCCAnalyses(LLVMPassBuilderRef PB, LLVMCGSCCAnalysisManagerRef AM); @@ -95,7 +91,7 @@ void LLVMLPMAddLPM(LLVMLoopPassManagerRef PM, LLVMLoopPassManagerRef NestedPM); void LLVMMPMAddCGPM(LLVMModulePassManagerRef PM, LLVMCGSCCPassManagerRef NestedPM); void LLVMCGPMAddFPM(LLVMCGSCCPassManagerRef PM, LLVMFunctionPassManagerRef NestedPM); -void LLVMFPMAddLPM(LLVMFunctionPassManagerRef PM, LLVMLoopPassManagerRef NestedPM); +void LLVMFPMAddLPM(LLVMFunctionPassManagerRef PM, LLVMLoopPassManagerRef NestedPM, LLVMBool UseMemorySSA); void LLVMMPMAddFPM(LLVMModulePassManagerRef PM, LLVMFunctionPassManagerRef NestedPM); typedef LLVMPreservedAnalysesRef (*LLVMJuliaModulePassCallback)(LLVMModuleRef M, LLVMModuleAnalysisManagerRef AM, void *Thunk); @@ -104,6 +100,13 @@ typedef LLVMPreservedAnalysesRef (*LLVMJuliaFunctionPassCallback)(LLVMValueRef F void LLVMMPMAddJuliaPass(LLVMModulePassManagerRef PM, LLVMJuliaModulePassCallback Callback, void *Thunk); void LLVMFPMAddJuliaPass(LLVMFunctionPassManagerRef PM, LLVMJuliaFunctionPassCallback Callback, void *Thunk); +// Target Analyses +LLVMBool LLVMRegisterTargetIRAnalysis(LLVMFunctionAnalysisManagerRef FAM, LLVMTargetMachineRef TM); +LLVMBool LLVMRegisterTargetLibraryAnalysis(LLVMFunctionAnalysisManagerRef FAM, const char *Triple, size_t TripleLength); + +// Analyses +LLVMErrorRef LLVMRegisterAliasAnalyses(LLVMFunctionAnalysisManagerRef FAM, LLVMPassBuilderRef PB, LLVMTargetMachineRef TM, const char *Analyses, size_t AnalysesLength); + LLVM_C_EXTERN_C_END #endif diff --git a/deps/LLVMExtra/lib/newpm.cpp b/deps/LLVMExtra/lib/newpm.cpp index 3d2d84a1..8219561f 100644 --- a/deps/LLVMExtra/lib/newpm.cpp +++ b/deps/LLVMExtra/lib/newpm.cpp @@ -3,12 +3,14 @@ #if LLVM_VERSION_MAJOR >= 15 #include +#include #include #include #include #include +#include -#include "llvm/Support/CBindingWrapping.h" +#include using llvm::wrap; using llvm::unwrap; @@ -43,7 +45,6 @@ DEFINE_SIMPLE_CONVERSION_FUNCTIONS(llvm::ModuleAnalysisManager, LLVMModuleAnalys DEFINE_SIMPLE_CONVERSION_FUNCTIONS(llvm::CGSCCAnalysisManager, LLVMCGSCCAnalysisManagerRef) DEFINE_SIMPLE_CONVERSION_FUNCTIONS(llvm::FunctionAnalysisManager, LLVMFunctionAnalysisManagerRef) DEFINE_SIMPLE_CONVERSION_FUNCTIONS(llvm::LoopAnalysisManager, LLVMLoopAnalysisManagerRef) -DEFINE_SIMPLE_CONVERSION_FUNCTIONS(llvm::AAManager, LLVMAAManagerRef) LLVMModuleAnalysisManagerRef LLVMCreateNewPMModuleAnalysisManager(void) { return wrap(new llvm::ModuleAnalysisManager()); @@ -57,9 +58,6 @@ LLVMFunctionAnalysisManagerRef LLVMCreateNewPMFunctionAnalysisManager(void) { LLVMLoopAnalysisManagerRef LLVMCreateNewPMLoopAnalysisManager(void) { return wrap(new llvm::LoopAnalysisManager()); } -LLVMAAManagerRef LLVMCreateNewPMAAManager(void) { - return wrap(new llvm::AAManager()); -} void LLVMDisposeNewPMModuleAnalysisManager(LLVMModuleAnalysisManagerRef AM) { delete unwrap(AM); @@ -73,9 +71,6 @@ void LLVMDisposeNewPMFunctionAnalysisManager(LLVMFunctionAnalysisManagerRef AM) void LLVMDisposeNewPMLoopAnalysisManager(LLVMLoopAnalysisManagerRef AM) { delete unwrap(AM); } -void LLVMDisposeNewPMAAManager(LLVMAAManagerRef AM) { - delete unwrap(AM); -} DEFINE_SIMPLE_CONVERSION_FUNCTIONS(llvm::ModulePassManager, LLVMModulePassManagerRef) DEFINE_SIMPLE_CONVERSION_FUNCTIONS(llvm::CGSCCPassManager, LLVMCGSCCPassManagerRef) @@ -158,9 +153,6 @@ LLVMErrorRef LLVMPassBuilderParseFunctionPassPipeline(LLVMPassBuilderRef PB, LLV LLVMErrorRef LLVMPassBuilderParseLoopPassPipeline(LLVMPassBuilderRef PB, LLVMLoopPassManagerRef PM, const char *PipelineText, size_t PipelineTextLength) { return wrap(unwrap(PB)->parsePassPipeline(*unwrap(PM), llvm::StringRef(PipelineText, PipelineTextLength))); } -LLVMErrorRef LLVMPassBuilderParseAAPipeline(LLVMPassBuilderRef PB, LLVMAAManagerRef AM, const char *PipelineText, size_t PipelineTextLength) { - return wrap(unwrap(PB)->parseAAPipeline(*unwrap(AM), llvm::StringRef(PipelineText, PipelineTextLength))); -} void LLVMPassBuilderRegisterModuleAnalyses(LLVMPassBuilderRef PB, LLVMModuleAnalysisManagerRef AM) { unwrap(PB)->registerModuleAnalyses(*unwrap(AM)); @@ -198,8 +190,8 @@ void LLVMMPMAddCGPM(LLVMModulePassManagerRef PM, LLVMCGSCCPassManagerRef NestedP void LLVMCGPMAddFPM(LLVMCGSCCPassManagerRef PM, LLVMFunctionPassManagerRef NestedPM) { unwrap(PM)->addPass(llvm::createCGSCCToFunctionPassAdaptor(std::move(*unwrap(NestedPM)))); } -void LLVMFPMAddLPM(LLVMFunctionPassManagerRef PM, LLVMLoopPassManagerRef NestedPM) { - unwrap(PM)->addPass(llvm::createFunctionToLoopPassAdaptor(std::move(*unwrap(NestedPM)))); +void LLVMFPMAddLPM(LLVMFunctionPassManagerRef PM, LLVMLoopPassManagerRef NestedPM, LLVMBool UseMemorySSA) { + unwrap(PM)->addPass(llvm::createFunctionToLoopPassAdaptor(std::move(*unwrap(NestedPM)), UseMemorySSA)); } void LLVMMPMAddFPM(LLVMModulePassManagerRef PM, LLVMFunctionPassManagerRef NestedPM) { unwrap(PM)->addPass(llvm::createModuleToFunctionPassAdaptor(std::move(*unwrap(NestedPM)))); @@ -239,4 +231,25 @@ void LLVMFPMAddJuliaPass(LLVMFunctionPassManagerRef PM, LLVMJuliaFunctionPassCal unwrap(PM)->addPass(JuliaCustomFunctionPass(Callback, Thunk)); } +// Target Analyses + +LLVMBool LLVMRegisterTargetIRAnalysis(LLVMFunctionAnalysisManagerRef FAM, LLVMTargetMachineRef TM) { + return unwrap(FAM)->registerPass([&] { return llvm::TargetIRAnalysis(unwrap(TM)->getTargetIRAnalysis()); }); +} +LLVMBool LLVMRegisterTargetLibraryAnalysis(LLVMFunctionAnalysisManagerRef FAM, const char *Triple, size_t TripleLength) { + return unwrap(FAM)->registerPass([&] { return llvm::TargetLibraryAnalysis(llvm::TargetLibraryInfoImpl(llvm::Triple(llvm::StringRef(Triple, TripleLength)))); }); +} + +// Alias Analyses +LLVMErrorRef LLVMRegisterAliasAnalyses(LLVMFunctionAnalysisManagerRef FAM, LLVMPassBuilderRef PB, LLVMTargetMachineRef TM, const char *Analyses, size_t AnalysesLength) { + llvm::AAManager AA; + auto err = unwrap(PB)->parseAAPipeline(AA, llvm::StringRef(Analyses, AnalysesLength)); + if (err) + return wrap(std::move(err)); + if (TM) + unwrap(TM)->registerDefaultAliasAnalyses(AA); + unwrap(FAM)->registerPass([&] { return std::move(AA); }); + return LLVMErrorSuccess; +} + #endif diff --git a/lib/libLLVM_extra.jl b/lib/libLLVM_extra.jl index 130d4cd1..8000b3ba 100644 --- a/lib/libLLVM_extra.jl +++ b/lib/libLLVM_extra.jl @@ -510,10 +510,6 @@ mutable struct LLVMOpaqueLoopAnalysisManager end const LLVMLoopAnalysisManagerRef = Ptr{LLVMOpaqueLoopAnalysisManager} -mutable struct LLVMOpaqueAAManager end - -const LLVMAAManagerRef = Ptr{LLVMOpaqueAAManager} - function LLVMCreateNewPMModuleAnalysisManager() ccall((:LLVMCreateNewPMModuleAnalysisManager, libLLVMExtra), LLVMModuleAnalysisManagerRef, ()) end @@ -530,10 +526,6 @@ function LLVMCreateNewPMLoopAnalysisManager() ccall((:LLVMCreateNewPMLoopAnalysisManager, libLLVMExtra), LLVMLoopAnalysisManagerRef, ()) end -function LLVMCreateNewPMAAManager() - ccall((:LLVMCreateNewPMAAManager, libLLVMExtra), LLVMAAManagerRef, ()) -end - function LLVMDisposeNewPMModuleAnalysisManager(AM) ccall((:LLVMDisposeNewPMModuleAnalysisManager, libLLVMExtra), Cvoid, (LLVMModuleAnalysisManagerRef,), AM) end @@ -550,10 +542,6 @@ function LLVMDisposeNewPMLoopAnalysisManager(AM) ccall((:LLVMDisposeNewPMLoopAnalysisManager, libLLVMExtra), Cvoid, (LLVMLoopAnalysisManagerRef,), AM) end -function LLVMDisposeNewPMAAManager(AM) - ccall((:LLVMDisposeNewPMAAManager, libLLVMExtra), Cvoid, (LLVMAAManagerRef,), AM) -end - mutable struct LLVMOpaqueModulePassManager end const LLVMModulePassManagerRef = Ptr{LLVMOpaqueModulePassManager} @@ -666,10 +654,6 @@ function LLVMPassBuilderParseLoopPassPipeline(PB, PM, PipelineText, PipelineText ccall((:LLVMPassBuilderParseLoopPassPipeline, libLLVMExtra), LLVMErrorRef, (LLVMPassBuilderRef, LLVMLoopPassManagerRef, Cstring, Csize_t), PB, PM, PipelineText, PipelineTextLength) end -function LLVMPassBuilderParseAAPipeline(PB, AM, PipelineText, PipelineTextLength) - ccall((:LLVMPassBuilderParseAAPipeline, libLLVMExtra), LLVMErrorRef, (LLVMPassBuilderRef, LLVMAAManagerRef, Cstring, Csize_t), PB, AM, PipelineText, PipelineTextLength) -end - function LLVMPassBuilderRegisterModuleAnalyses(PB, AM) ccall((:LLVMPassBuilderRegisterModuleAnalyses, libLLVMExtra), Cvoid, (LLVMPassBuilderRef, LLVMModuleAnalysisManagerRef), PB, AM) end @@ -714,8 +698,8 @@ function LLVMCGPMAddFPM(PM, NestedPM) ccall((:LLVMCGPMAddFPM, libLLVMExtra), Cvoid, (LLVMCGSCCPassManagerRef, LLVMFunctionPassManagerRef), PM, NestedPM) end -function LLVMFPMAddLPM(PM, NestedPM) - ccall((:LLVMFPMAddLPM, libLLVMExtra), Cvoid, (LLVMFunctionPassManagerRef, LLVMLoopPassManagerRef), PM, NestedPM) +function LLVMFPMAddLPM(PM, NestedPM, UseMemorySSA) + ccall((:LLVMFPMAddLPM, libLLVMExtra), Cvoid, (LLVMFunctionPassManagerRef, LLVMLoopPassManagerRef, LLVMBool), PM, NestedPM, UseMemorySSA) end function LLVMMPMAddFPM(PM, NestedPM) @@ -735,5 +719,16 @@ end function LLVMFPMAddJuliaPass(PM, Callback, Thunk) ccall((:LLVMFPMAddJuliaPass, libLLVMExtra), Cvoid, (LLVMFunctionPassManagerRef, LLVMJuliaFunctionPassCallback, Ptr{Cvoid}), PM, Callback, Thunk) end -end # v"15" <= version() +function LLVMRegisterTargetIRAnalysis(FAM, TM) + ccall((:LLVMRegisterTargetIRAnalysis, libLLVMExtra), LLVMBool, (LLVMFunctionAnalysisManagerRef, LLVMTargetMachineRef), FAM, TM) +end + +function LLVMRegisterTargetLibraryAnalysis(FAM, Triple, TripleLength) + ccall((:LLVMRegisterTargetLibraryAnalysis, libLLVMExtra), LLVMBool, (LLVMFunctionAnalysisManagerRef, Cstring, Csize_t), FAM, Triple, TripleLength) +end + +function LLVMRegisterAliasAnalyses(FAM, PB, TM, Analyses, AnalysesLength) + ccall((:LLVMRegisterAliasAnalyses, libLLVMExtra), LLVMErrorRef, (LLVMFunctionAnalysisManagerRef, LLVMPassBuilderRef, LLVMTargetMachineRef, Cstring, Csize_t), FAM, PB, TM, Analyses, AnalysesLength) +end +end # v"15" <= version() diff --git a/lib/libLLVM_julia.jl b/lib/libLLVM_julia.jl index a937fe8f..8b446e12 100644 --- a/lib/libLLVM_julia.jl +++ b/lib/libLLVM_julia.jl @@ -60,6 +60,19 @@ function LLVMAddCPUFeaturesPass(PM) ccall(:LLVMExtraAddCPUFeaturesPass,Cvoid,(LLVMPassManagerRef,), PM) end +if VERSION >= v"1.10.0-DEV.1622" + +function LLVMRegisterJuliaPassBuilderCallbacks(PB) + ccall(:jl_register_passbuilder_callbacks,Cvoid,(LLVMPassBuilderRef,), PB) +end + +function LLVMAddJuliaPipelinePass(PM, PB, Speedup, Size, lower_intrinsics, dump_native, external_use, llvm_only) + ccall(:jl_build_newpm_pipeline,Cvoid,(LLVMModulePassManagerRef,LLVMPassBuilderRef,Cint,Cint,Cint,Cint,Cint,Cint), PM, PB, Speedup, Size, lower_intrinsics, dump_native, external_use, llvm_only) +end + +end + + if VERSION >= v"1.10.0-DEV.1395" mutable struct JLOpaqueJuliaOJIT end @@ -110,4 +123,4 @@ function JLJITGetIRCompileLayer(JIT) ccall(:JLJITGetIRCompileLayer, LLVMOrcIRCompileLayerRef, (JuliaOJITRef,), JIT) end -end # VERSION >= v"1.10.0-DEV.1395" +end diff --git a/src/interop.jl b/src/interop.jl index 01b857ec..ea5922f0 100644 --- a/src/interop.jl +++ b/src/interop.jl @@ -10,4 +10,8 @@ include("interop/pointer.jl") include("interop/utils.jl") include("interop/intrinsics.jl") +if LLVM.has_newpm() && VERSION >= v"1.10.0-DEV.1622" + include("interop/newpm.jl") +end + end diff --git a/src/interop/newpm.jl b/src/interop/newpm.jl new file mode 100644 index 00000000..4dfc8fa3 --- /dev/null +++ b/src/interop/newpm.jl @@ -0,0 +1,70 @@ +import ..LLVM: @module_pass, @function_pass, @loop_pass +import ..LLVM: is_module_pass, is_cgscc_pass, is_function_pass, is_loop_pass +import ..LLVM: pass_string, options_string, add! + +@module_pass "CPUFeatures" CPUFeaturesPass +@module_pass "RemoveNI" RemoveNIPass +@module_pass "LowerSIMDLoop" LowerSIMDLoopPass +@module_pass "FinalLowerGC" FinalLowerGCPass +@module_pass "RemoveJuliaAddrspaces" RemoveJuliaAddrspacesPass +@module_pass "RemoveAddrspaces" RemoveAddrspacesPass + +struct MultiVersioningPassOptions + external::Core.Bool +end +MultiVersioningPassOptions(; external::Core.Bool=false) = MultiVersioningPassOptions(external) +options_string(options::MultiVersioningPassOptions) = ifelse(options.external, "", "") +@module_pass "JuliaMultiVersioning" MultiVersioningPass MultiVersioningPassOptions + +struct LowerPTLSPassOptions + imaging::Core.Bool +end +LowerPTLSPassOptions(; imaging::Core.Bool=false) = LowerPTLSPassOptions(imaging) +options_string(options::LowerPTLSPassOptions) = ifelse(options.imaging, "", "") +@module_pass "LowerPTLSPass" LowerPTLSPass LowerPTLSPassOptions + +@function_pass "DemoteFloat16" DemoteFloat16Pass +@function_pass "CombineMulAdd" CombineMulAddPass +@function_pass "LateLowerGCFrame" LateLowerGCPass +@function_pass "AllocOpt" AllocOptPass +@function_pass "PropagateJuliaAddrspaces" PropagateJuliaAddrspacesPass +@function_pass "LowerExcHandlers" LowerExcHandlersPass + +struct GCInvariantVerifierPassOptions + strong::Core.Bool +end +GCInvariantVerifierPassOptions(; strong::Core.Bool=false) = GCInvariantVerifierPassOptions(strong) +options_string(options::GCInvariantVerifierPassOptions) = ifelse(options.strong, "", "") +@function_pass "GCInvariantVerifier" GCInvariantVerifierPass GCInvariantVerifierPassOptions + +@loop_pass "JuliaLICM" JuliaLICMPass + +# The entire Julia pipeline +struct JuliaPipelinePassOptions + speedup::Int + lower_intrinsics::Core.Bool + dump_native::Core.Bool + external_use::Core.Bool + llvm_only::Core.Bool +end +JuliaPipelinePassOptions(; speedup=Base.JLOptions().opt_level, lower_intrinsics::Core.Bool=true, + dump_native::Core.Bool=false, external_use::Core.Bool=false, + llvm_only::Core.Bool=false) = JuliaPipelinePassOptions(convert(Int, speedup), lower_intrinsics, dump_native, external_use, llvm_only) +function options_string(options::JuliaPipelinePassOptions) + optlevel = "O$(options.speedup)" + lower_intrinsics = ifelse(options.lower_intrinsics, "lower_intrinsics", "no_lower_intrinsics") + dump_native = ifelse(options.dump_native, "dump_native", "no_dump_native") + external_use = ifelse(options.external_use, "external_use", "no_external_use") + llvm_only = ifelse(options.llvm_only, "llvm_only", "no_llvm_only") + "<$optlevel;$lower_intrinsics;$dump_native;$external_use;$llvm_only>" +end +@module_pass "julia" JuliaPipelinePass JuliaPipelinePassOptions + +# We specialize the add! here because if we go through the PassBuilder parser, +# Julia won't insert the PassBuilder's callbacks in the right spots. +# Using the specific method call here allows insertion of those callbacks. +function add!(pm::NewPMModulePassManager, pb::PassBuilder, pass::JuliaPipelinePass) + API.LLVMAddJuliaPipelinePass(pm, pb, pass.options.speedup, 0, pass.options.lower_intrinsics, + pass.options.dump_native, pass.options.external_use, + pass.options.llvm_only) +end diff --git a/src/newpm.jl b/src/newpm.jl index cf3464bd..52107d0d 100644 --- a/src/newpm.jl +++ b/src/newpm.jl @@ -3,5 +3,6 @@ include("newpm/analysismanager.jl") include("newpm/passmanager.jl") include("newpm/instrumentation.jl") include("newpm/passbuilder.jl") +include("newpm/analyses.jl") include("newpm/passes.jl") include("newpm/custompass.jl") diff --git a/src/newpm/analyses.jl b/src/newpm/analyses.jl new file mode 100644 index 00000000..bd7c4ef0 --- /dev/null +++ b/src/newpm/analyses.jl @@ -0,0 +1,71 @@ +export NewPMAnalysis, NewPMAliasAnalysis + +export add!, analysis_string, analysis_managers + +abstract type NewPMAnalysis end +abstract type NewPMAliasAnalysis end + +macro alias_analysis(analysis_name, class_name) + quote + export $class_name + struct $class_name <: NewPMAliasAnalysis end + @eval analysis_string(::$class_name) = $analysis_name + end +end + +analysis_string(aa::AAManager) = join(aa.aas, ",") + +Base.show(io::IO, analysis::NewPMAnalysis) = print(io, analysis_string(analysis)) +Base.show(io::IO, aa::AAManager) = print(io, analysis_string(aa)) + +# Module Alias Analysis +@alias_analysis "globals-aa" GlobalsAA + +# Function Alias Analysis +@alias_analysis "basic-aa" BasicAA +@alias_analysis "cfl-anders-aa" CFLAndersAA +@alias_analysis "cfl-steens-aa" CFLSteensAA +@alias_analysis "objc-arc-aa" ObjCARCAA +@alias_analysis "scev-aa" SCEVAA +@alias_analysis "scoped-noalias-aa" ScopedNoAliasAA +@alias_analysis "tbaa" TypeBasedAA + +add!(am::AAManager, aa::NewPMAliasAnalysis) = push!(am.aas, analysis_string(aa)) +add!(am::AAManager, aas::AbstractVector{<:NewPMAliasAnalysis}) = append!(am.aas, analysis_string.(aas)) +add!(am::AAManager, tm::TargetMachine) = am.tm = tm + +export TargetIRAnalysis, TargetLibraryAnalysis + +struct TargetIRAnalysis + tm::TargetMachine +end +analysis_string(::TargetIRAnalysis) = "target-ir-analysis" + +struct TargetLibraryAnalysis + triple::String +end +analysis_string(::TargetLibraryAnalysis) = "target-library-analysis" + +add!(fam::FunctionAnalysisManager, analysis::TargetIRAnalysis) = convert(Core.Bool, API.LLVMRegisterTargetIRAnalysis(fam, analysis.tm)) +add!(fam::FunctionAnalysisManager, analysis::TargetLibraryAnalysis) = convert(Core.Bool, API.LLVMRegisterTargetLibraryAnalysis(fam, analysis.triple, length(analysis.triple))) + +function analysis_managers(f::Core.Function, pb::Union{Nothing,PassBuilder}=nothing, tm::Union{Nothing,TargetMachine}=nothing, aa_stack::AbstractVector{<:NewPMAliasAnalysis}=NewPMAliasAnalysis[]) + @dispose lam=LoopAnalysisManager() fam=FunctionAnalysisManager() cam=CGSCCAnalysisManager() mam=ModuleAnalysisManager() begin + if !isempty(aa_stack) + add!(fam, AAManager) do aam + add!(aam, aa_stack) + if !isnothing(tm) + add!(aam, tm) + end + end + end + if !isnothing(tm) + add!(fam, TargetIRAnalysis(tm)) + add!(fam, TargetLibraryAnalysis(triple(tm))) + end + if !isnothing(pb) + register!(pb, lam, fam, cam, mam) + end + f(lam, fam, cam, mam) + end +end diff --git a/src/newpm/analysismanager.jl b/src/newpm/analysismanager.jl index 614be415..3d5e5124 100644 --- a/src/newpm/analysismanager.jl +++ b/src/newpm/analysismanager.jl @@ -1,6 +1,6 @@ export AnalysisManager, ModuleAnalysisManager, CGSCCAnalysisManager, FunctionAnalysisManager, LoopAnalysisManager, AAManager -export dispose, analysis_managers +export dispose, add! abstract type AnalysisManager end @@ -12,36 +12,35 @@ end ref::API.LLVMCGSCCAnalysisManagerRef roots::Vector{Any} end -@checked struct FunctionAnalysisManager <: AnalysisManager +mutable struct AAManager + aas::Vector{String} + tm::Union{Nothing,TargetMachine} +end +@checked mutable struct FunctionAnalysisManager <: AnalysisManager ref::API.LLVMFunctionAnalysisManagerRef + aa::Union{Nothing,AAManager} roots::Vector{Any} end @checked struct LoopAnalysisManager <: AnalysisManager ref::API.LLVMLoopAnalysisManagerRef roots::Vector{Any} end -@checked struct AAManager - ref::API.LLVMAAManagerRef - roots::Vector{Any} -end Base.unsafe_convert(::Type{API.LLVMModuleAnalysisManagerRef}, am::ModuleAnalysisManager) = am.ref Base.unsafe_convert(::Type{API.LLVMCGSCCAnalysisManagerRef}, am::CGSCCAnalysisManager) = am.ref Base.unsafe_convert(::Type{API.LLVMFunctionAnalysisManagerRef}, am::FunctionAnalysisManager) = am.ref Base.unsafe_convert(::Type{API.LLVMLoopAnalysisManagerRef}, am::LoopAnalysisManager) = am.ref -Base.unsafe_convert(::Type{API.LLVMAAManagerRef}, am::AAManager) = am.ref ModuleAnalysisManager() = ModuleAnalysisManager(API.LLVMCreateNewPMModuleAnalysisManager(), []) CGSCCAnalysisManager() = CGSCCAnalysisManager(API.LLVMCreateNewPMCGSCCAnalysisManager(), []) -FunctionAnalysisManager() = FunctionAnalysisManager(API.LLVMCreateNewPMFunctionAnalysisManager(), []) +FunctionAnalysisManager() = FunctionAnalysisManager(API.LLVMCreateNewPMFunctionAnalysisManager(), nothing, []) LoopAnalysisManager() = LoopAnalysisManager(API.LLVMCreateNewPMLoopAnalysisManager(), []) -AAManager() = AAManager(API.LLVMCreateNewPMAAManager(), []) +AAManager() = AAManager([], nothing) dispose(mam::ModuleAnalysisManager) = API.LLVMDisposeNewPMModuleAnalysisManager(mam) dispose(cgmam::CGSCCAnalysisManager) = API.LLVMDisposeNewPMCGSCCAnalysisManager(cgmam) dispose(fam::FunctionAnalysisManager) = API.LLVMDisposeNewPMFunctionAnalysisManager(fam) dispose(lam::LoopAnalysisManager) = API.LLVMDisposeNewPMLoopAnalysisManager(lam) -dispose(aam::AAManager) = API.LLVMDisposeNewPMAAManager(aam) function ModuleAnalysisManager(f::Core.Function, args...; kwargs...) am = ModuleAnalysisManager(args...; kwargs...) @@ -75,17 +74,22 @@ function LoopAnalysisManager(f::Core.Function, args...; kwargs...) dispose(am) end end -function AAManager(f::Core.Function, args...; kwargs...) - am = AAManager(args...; kwargs...) - try - f(am) - finally - dispose(am) + +function add!(fam::FunctionAnalysisManager, aa::AAManager) + if isnothing(fam.aa) + fam.aa = aa + return true + else + return false end end -function analysis_managers(f::Core.Function) - @dispose lam=LoopAnalysisManager() fam=FunctionAnalysisManager() cgam=CGSCCAnalysisManager() mam=ModuleAnalysisManager() begin - f(lam, fam, cgam, mam) +function add!(f::Core.Function, fam::FunctionAnalysisManager, ::Type{AAManager}) + if !isnothing(fam.aa) + return false end + aa = AAManager() + f(aa) + add!(fam, aa) + return true end diff --git a/src/newpm/custompass.jl b/src/newpm/custompass.jl index 128c97f3..feb0e2b7 100644 --- a/src/newpm/custompass.jl +++ b/src/newpm/custompass.jl @@ -1,4 +1,4 @@ -export add! +export add!, legacy2newpm function module_pass_callback_impl(mod, mam, thunk) m = Module(mod) @@ -13,7 +13,7 @@ end function function_pass_callback_impl(fun, fam, thunk) f = Function(fun) - am = FunctionAnalysisManager(fam, Any[]) + am = FunctionAnalysisManager(fam, nothing, Any[]) pass = Base.unsafe_pointer_to_objref(thunk)::Ref{Core.Function} preserved = unsafe_run() do pa = pass[](f, am)::PreservedAnalyses @@ -35,3 +35,11 @@ function add!(f::Core.Function, fpm::NewPMFunctionPassManager) push!(fpm.roots, cb) GC.@preserve cb API.LLVMFPMAddJuliaPass(fpm, julia_function_pass_callback, Base.pointer_from_objref(cb)) end + +legacy2newpm(f::Core.Function) = (ir, am) -> begin + if f(ir) + return no_analyses_preserved() + else + return all_analyses_preserved() + end +end diff --git a/src/newpm/passbuilder.jl b/src/newpm/passbuilder.jl index 27519937..efed660c 100644 --- a/src/newpm/passbuilder.jl +++ b/src/newpm/passbuilder.jl @@ -4,16 +4,42 @@ export dispose, register!, cross_register_proxies!, parse! @checked struct PassBuilder ref::API.LLVMPassBuilderRef + owned_pic::Union{Nothing,PassInstrumentationCallbacks} roots::Vector{Any} end Base.unsafe_convert(::Type{API.LLVMPassBuilderRef}, pb::PassBuilder) = pb.ref -PassBuilder(tm::TargetMachine) = PassBuilder(API.LLVMCreatePassBuilder(tm, C_NULL), []) -PassBuilder(tm::TargetMachine, pic::PassInstrumentationCallbacks) = PassBuilder(API.LLVMCreatePassBuilder(tm, pic), []) -PassBuilder() = PassBuilder(API.LLVMCreatePassBuilder(C_NULL, C_NULL), []) +function create_passbuilder_internal(tm, pic) + pb = API.LLVMCreatePassBuilder(tm, pic) + if VERSION >= v"1.10.0-DEV.1622" + API.LLVMRegisterJuliaPassBuilderCallbacks(pb) + end + pb +end -dispose(pb::PassBuilder) = API.LLVMDisposePassBuilder(pb) +function PassBuilder(tm::Union{Nothing,TargetMachine} = nothing, pic::Union{Nothing,PassInstrumentationCallbacks} = nothing; si::Core.Bool=false) + if !isnothing(pic) && si + throw(ArgumentError("Cannot provide explicit PassInstrumentationCallbacks and request StandardInstrumentations!")) + end + tm_internal = ifelse(isnothing(tm), C_NULL, tm) + if !isnothing(pic) + pic_internal = pic + elseif si + pic_internal = StandardInstrumentationCallbacks() + else + pic_internal = C_NULL + end + pb = create_passbuilder_internal(tm_internal, pic_internal) + PassBuilder(pb, ifelse(si, pic_internal, nothing), []) +end + +function dispose(pb::PassBuilder) + API.LLVMDisposePassBuilder(pb) + if !isnothing(pb.owned_pic) + dispose(pb.owned_pic) + end +end function PassBuilder(f::Core.Function, args...; kwargs...) pb = PassBuilder(args...; kwargs...) @@ -26,8 +52,16 @@ end register!(pb::PassBuilder, am::ModuleAnalysisManager) = API.LLVMPassBuilderRegisterModuleAnalyses(pb, am) register!(pb::PassBuilder, am::CGSCCAnalysisManager) = API.LLVMPassBuilderRegisterCGSCCAnalyses(pb, am) -register!(pb::PassBuilder, am::FunctionAnalysisManager) = API.LLVMPassBuilderRegisterFunctionAnalyses(pb, am) register!(pb::PassBuilder, am::LoopAnalysisManager) = API.LLVMPassBuilderRegisterLoopAnalyses(pb, am) +# FunctionAnalysisManager is special because we can build alias analysis pipelines on top of it +function register!(pb::PassBuilder, am::FunctionAnalysisManager) + if !isnothing(am.aa) + pipeline = analysis_string(am.aa) + tm = ifelse(isnothing(am.aa.tm), C_NULL, am.aa.tm) + @check API.LLVMRegisterAliasAnalyses(am, pb, tm, pipeline, length(pipeline)) + end + API.LLVMPassBuilderRegisterFunctionAnalyses(pb, am) +end cross_register_proxies!(pb::PassBuilder, lam::LoopAnalysisManager, fam::FunctionAnalysisManager, cgam::CGSCCAnalysisManager, mam::ModuleAnalysisManager) = API.LLVMPassBuilderCrossRegisterProxies(pb, lam, fam, cgam, mam) @@ -43,3 +77,10 @@ parse!(pb::PassBuilder, pm::NewPMModulePassManager, s::String) = @check API.LLVM parse!(pb::PassBuilder, pm::NewPMCGSCCPassManager, s::String) = @check API.LLVMPassBuilderParseCGSCCPassPipeline(pb, pm, s, length(s)) parse!(pb::PassBuilder, pm::NewPMFunctionPassManager, s::String) = @check API.LLVMPassBuilderParseFunctionPassPipeline(pb, pm, s, length(s)) parse!(pb::PassBuilder, pm::NewPMLoopPassManager, s::String) = @check API.LLVMPassBuilderParseLoopPassPipeline(pb, pm, s, length(s)) + +function passbuilder(pm::NewPMPassManager)::PassBuilder + if isnothing(pm.pb) + throw(ArgumentError("PassManager was not initialized with a PassBuilder, please provide a PassBuilder to add!.")) + end + pm.pb +end diff --git a/src/newpm/passes.jl b/src/newpm/passes.jl index e9636a9d..db207adb 100644 --- a/src/newpm/passes.jl +++ b/src/newpm/passes.jl @@ -17,9 +17,9 @@ macro module_pass(pass_name, class_name, params) export $params export $class_name struct $class_name <: NewPMLLVMPass - options::$params + options::$(esc(params)) end - @eval $class_name() = $class_name($params()) + @eval $class_name(; kwargs...) = $class_name($params(; kwargs...)) @eval is_module_pass(::Type{$class_name}) = true @eval pass_string(pass::$class_name) = $pass_name * options_string(pass.options) end @@ -39,9 +39,9 @@ macro cgscc_pass(pass_name, class_name, params) export $params export $class_name struct $class_name <: NewPMLLVMPass - options::$params + options::$(esc(params)) end - @eval $class_name() = $class_name($params()) + @eval $class_name(; kwargs...) = $class_name($params(; kwargs...)) @eval is_cgscc_pass(::Type{$class_name}) = true @eval pass_string(pass::$class_name) = $pass_name * options_string(pass.options) end @@ -61,9 +61,9 @@ macro function_pass(pass_name, class_name, params) export $params export $class_name struct $class_name <: NewPMLLVMPass - options::$params + options::$(esc(params)) end - @eval $class_name() = $class_name($params()) + @eval $class_name(; kwargs...) = $class_name($params(; kwargs...)) @eval is_function_pass(::Type{$class_name}) = true @eval pass_string(pass::$class_name) = $pass_name * options_string(pass.options) end @@ -83,9 +83,9 @@ macro loop_pass(pass_name, class_name, params) export $params export $class_name struct $class_name <: NewPMLLVMPass - options::$params + options::$(esc(params)) end - @eval $class_name() = $class_name($params()) + @eval $class_name(; kwargs...) = $class_name($params(; kwargs...)) @eval is_loop_pass(::Type{$class_name}) = true @eval pass_string(pass::$class_name) = $pass_name * options_string(pass.options) end @@ -191,7 +191,7 @@ Base.show(io::IO, pass::NewPMLLVMPass) = print(io, pass_string(pass)) struct LoopExtractorPassOptions single::Core.Bool end -LoopExtractorPassOptions() = LoopExtractorPassOptions(false) +LoopExtractorPassOptions(; single::Core.Bool = false) = LoopExtractorPassOptions(single) options_string(options::LoopExtractorPassOptions) = ifelse(options.single, "", "") @module_pass "loop-extract" LoopExtractorPass LoopExtractorPassOptions @@ -199,7 +199,7 @@ struct HWAddressSanitizerPassOptions kernel::Core.Bool recover::Core.Bool end -HWAddressSanitizerPassOptions() = HWAddressSanitizerPassOptions(false, false) +HWAddressSanitizerPassOptions(; kernel::Core.Bool = false, recover::Core.Bool = false) = HWAddressSanitizerPassOptions(kernel, recover) function options_string(options::HWAddressSanitizerPassOptions) s = String[] if options.kernel @@ -219,7 +219,7 @@ end struct ModuleAddressSanitizerPassOptions kernel::Core.Bool end -ModuleAddressSanitizerPassOptions() = ModuleAddressSanitizerPassOptions(false) +ModuleAddressSanitizerPassOptions(; kernel::Core.Bool = false) = ModuleAddressSanitizerPassOptions(kernel) options_string(options::ModuleAddressSanitizerPassOptions) = ifelse(options.kernel, "", "") @module_pass "asan-module" ModuleAddressSanitizerPass ModuleAddressSanitizerPassOptions @@ -238,14 +238,14 @@ is_cgscc_pass(::Type{InvalidateAllAnalysesPass}) = true struct InlinerPassOptions onlymandatory::Core.Bool end -InlinerPassOptions() = InlinerPassOptions(false) +InlinerPassOptions(; onlymandatory::Core.Bool = false) = InlinerPassOptions(onlymandatory) options_string(options::InlinerPassOptions) = ifelse(options.onlymandatory, "", "") @cgscc_pass "inline" InlinerPass InlinerPassOptions struct CoroSplitPassOptions reusestorage::Core.Bool end -CoroSplitPassOptions() = CoroSplitPassOptions(false) +CoroSplitPassOptions(; reusestorage::Core.Bool = false) = CoroSplitPassOptions(reusestorage) options_string(options::CoroSplitPassOptions) = ifelse(options.reusestorage, "", "") @cgscc_pass "coro-split" CoroSplitPass CoroSplitPassOptions @@ -393,21 +393,21 @@ is_function_pass(::Type{VerifierPass}) = true struct EarlyCSEPassOptions memssa::Core.Bool end -EarlyCSEPassOptions() = EarlyCSEPassOptions(false) +EarlyCSEPassOptions(; memssa::Core.Bool = false) = EarlyCSEPassOptions(memssa) options_string(options::EarlyCSEPassOptions) = ifelse(options.memssa, "", "") @function_pass "early-cse" EarlyCSEPass EarlyCSEPassOptions struct EntryExitInstrumenterPassOptions postinline::Core.Bool end -EntryExitInstrumenterPassOptions() = EntryExitInstrumenterPassOptions(true) +EntryExitInstrumenterPassOptions(; postinline::Core.Bool = false) = EntryExitInstrumenterPassOptions(postinline) options_string(options::EntryExitInstrumenterPassOptions) = ifelse(options.postinline, "", "") @function_pass "ee-instrument" EntryExitInstrumenterPass EntryExitInstrumenterPassOptions struct LowerMatrixIntrinsicsPassOptions minimal::Core.Bool end -LowerMatrixIntrinsicsPassOptions() = LowerMatrixIntrinsicsPassOptions(false) +LowerMatrixIntrinsicsPassOptions(; minimal::Core.Bool = false) = LowerMatrixIntrinsicsPassOptions(minimal) options_string(options::LowerMatrixIntrinsicsPassOptions) = ifelse(options.minimal, "", "") @function_pass "lower-matrix-intrinsics" LowerMatrixIntrinsicsPass LowerMatrixIntrinsicsPassOptions @@ -420,7 +420,13 @@ struct LoopUnrollPassOptions runtime::Union{Nothing, Core.Bool} upperbound::Union{Nothing, Core.Bool} end -LoopUnrollPassOptions() = LoopUnrollPassOptions(2, nothing, nothing, nothing, nothing, nothing, nothing) +LoopUnrollPassOptions(; speedup::Int = 2, + fullunrollmax::Union{Nothing, Int} = nothing, + partial::Union{Nothing, Bool} = nothing, + peeling::Union{Nothing, Bool} = nothing, + profilepeeling::Union{Nothing, Bool} = nothing, + runtime::Union{Nothing, Bool} = nothing, + upperbound::Union{Nothing, Bool} = nothing) = LoopUnrollPassOptions(speedup, fullunrollmax, partial, peeling, profilepeeling, runtime, upperbound) function options_string(options::LoopUnrollPassOptions) final_options = String[] push!(final_options, "O$(options.speedup)") @@ -452,7 +458,10 @@ struct MemorySanitizerPassOptions eagerchecks::Core.Bool trackorigins::Int end -MemorySanitizerPassOptions() = MemorySanitizerPassOptions(false, false, false, 0) +MemorySanitizerPassOptions(; recover::Core.Bool = false, + kernel::Core.Bool = false, + eagerchecks::Core.Bool = false, + trackorigins::Int = 0) = MemorySanitizerPassOptions(recover, kernel, eagerchecks, trackorigins) function options_string(options::MemorySanitizerPassOptions) final_options = String[] if options.recover @@ -478,7 +487,13 @@ struct SimplifyCFGPassOptions sinkcommoninsts::Core.Bool bonusinstthreshold::Int end -SimplifyCFGPassOptions() = SimplifyCFGPassOptions(false, false, false, true, false, false, 1) +SimplifyCFGPassOptions(; forwardswitchcond::Core.Bool = false, + switchrangetoicmp::Core.Bool = false, + switchtolookup::Core.Bool = false, + keeploops::Core.Bool = true, + hoistcommoninsts::Core.Bool = false, + sinkcommoninsts::Core.Bool = false, + bonusinstthreshold::Int = 1) = SimplifyCFGPassOptions(forwardswitchcond, switchrangetoicmp, switchtolookup, keeploops, hoistcommoninsts, sinkcommoninsts, bonusinstthreshold) function options_string(options::SimplifyCFGPassOptions) forward = ifelse(options.forwardswitchcond, "forward-switch-cond", "no-forward-switch-cond") s2i = ifelse(options.switchrangetoicmp, "switch-range-to-icmp", "no-switch-range-to-icmp") @@ -495,7 +510,8 @@ struct LoopVectorizePassOptions interleaveforcedonly::Core.Bool vectorizeforcedonly::Core.Bool end -LoopVectorizePassOptions() = LoopVectorizePassOptions(false, false) +LoopVectorizePassOptions(; interleaveforcedonly::Core.Bool = false, + vectorizeforcedonly::Core.Bool = false) = LoopVectorizePassOptions(interleaveforcedonly, vectorizeforcedonly) function options_string(options::LoopVectorizePassOptions) interleave = ifelse(options.interleaveforcedonly, "interleave-forced-only", "no-interleave-forced-only") vectorize = ifelse(options.vectorizeforcedonly, "vectorize-forced-only", "no-vectorize-forced-only") @@ -506,7 +522,7 @@ end struct MergedLoadStoreMotionPassOptions splitfooterbb::Core.Bool end -MergedLoadStoreMotionPassOptions() = MergedLoadStoreMotionPassOptions(false) +MergedLoadStoreMotionPassOptions(; splitfooterbb::Core.Bool = false) = MergedLoadStoreMotionPassOptions(splitfooterbb) options_string(options::MergedLoadStoreMotionPassOptions) = ifelse(options.splitfooterbb, "", "") @function_pass "mldst-motion" MergedLoadStoreMotionPass MergedLoadStoreMotionPassOptions @@ -516,7 +532,10 @@ struct GVNPassOptions allowloadpresplitbackedge::Union{Nothing, Core.Bool} allowmemdep::Union{Nothing, Core.Bool} end -GVNPassOptions() = GVNPassOptions(nothing, nothing, nothing, nothing) +GVNPassOptions(; allowpre::Union{Nothing, Core.Bool} = nothing, + allowloadpre::Union{Nothing, Core.Bool} = nothing, + allowloadpresplitbackedge::Union{Nothing, Core.Bool} = nothing, + allowmemdep::Union{Nothing, Core.Bool} = nothing) = GVNPassOptions(allowpre, allowloadpre, allowloadpresplitbackedge, allowmemdep) function options_string(options::GVNPassOptions) final_options = String[] if options.allowpre !== nothing @@ -554,7 +573,7 @@ end struct StackLifetimePrinterPassOptions must::Core.Bool end -StackLifetimePrinterPassOptions() = StackLifetimePrinterPassOptions(false) +StackLifetimePrinterPassOptions(; must::Core.Bool = false) = StackLifetimePrinterPassOptions(must) function options_string(options::StackLifetimePrinterPassOptions) ifelse(options.must, "", "") end @@ -601,7 +620,7 @@ struct SimpleLoopUnswitchPassOptions nontrivial::Core.Bool trivial::Core.Bool end -SimpleLoopUnswitchPassOptions() = SimpleLoopUnswitchPassOptions(false, true) +SimpleLoopUnswitchPassOptions(; nontrivial::Core.Bool = false, trivial::Core.Bool = true) = SimpleLoopUnswitchPassOptions(nontrivial, trivial) function options_string(options::SimpleLoopUnswitchPassOptions) nontrivial = ifelse(options.nontrivial, "nontrivial", "no-nontrivial") trivial = ifelse(options.trivial, "trivial", "no-trivial") @@ -612,7 +631,7 @@ end struct LICMPassOptions allowspeculation::Core.Bool end -LICMPassOptions() = LICMPassOptions(true) +LICMPassOptions(; allowspeculation::Core.Bool = true) = LICMPassOptions(allowspeculation) options_string(options::LICMPassOptions) = ifelse(options.allowspeculation, "", "") @loop_pass "licm" LICMPass LICMPassOptions @@ -623,35 +642,98 @@ const LNICMPassOptions = LICMPassOptions function add!(pm::NewPMModulePassManager, pb::PassBuilder, pass::NewPMLLVMPass) if !is_module_pass(typeof(pass)) - error("Pass $pass is not a module pass") + throw(ArgumentError("Pass $pass is not a module pass")) end parse!(pb, pm, pass_string(pass)) end function add!(pm::NewPMCGSCCPassManager, pb::PassBuilder, pass::NewPMLLVMPass) if !is_cgscc_pass(typeof(pass)) - error("Pass $pass is not a cgscc pass") + throw(ArgumentError("Pass $pass is not a cgscc pass")) end parse!(pb, pm, pass_string(pass)) end function add!(pm::NewPMFunctionPassManager, pb::PassBuilder, pass::NewPMLLVMPass) if !is_function_pass(typeof(pass)) - error("Pass $pass is not a function pass") + throw(ArgumentError("Pass $pass is not a function pass")) end parse!(pb, pm, pass_string(pass)) end function add!(pm::NewPMLoopPassManager, pb::PassBuilder, pass::NewPMLLVMPass) if !is_loop_pass(typeof(pass)) - error("Pass $pass is not a loop pass") + throw(ArgumentError("Pass $pass is not a loop pass")) end parse!(pb, pm, pass_string(pass)) end function add!(pm::NewPMPassManager, pass::NewPMLLVMPass) - if isnothing(pm.pb) - error("PassManager was not initialized with a PassBuilder, please provide a PassBuilder to add!.") + add!(pm, passbuilder(pm), pass) +end + +function run!(pm::NewPMModulePassManager, m::Module, tm::Union{Nothing,TargetMachine}=nothing, aa_stack::AbstractVector{<:NewPMAliasAnalysis}=NewPMAliasAnalysis[]) + pb = passbuilder(pm) + analysis_managers(pb, tm, aa_stack) do lam, fam, cam, mam + dispose(run!(pm, m, mam)) + end +end + +function run!(pm::NewPMFunctionPassManager, f::Function, tm::Union{Nothing,TargetMachine}=nothing, aa_stack::AbstractVector{<:NewPMAliasAnalysis}=NewPMAliasAnalysis[]) + pb = passbuilder(pm) + analysis_managers(pb, tm, aa_stack) do lam, fam, cam, mam + dispose(run!(pm, f, fam)) + end +end + +function run!(pass::NewPMLLVMPass, m::Module, tm::Union{Nothing,TargetMachine}=nothing, aa_stack::AbstractVector{<:NewPMAliasAnalysis}=NewPMAliasAnalysis[]) + needs_globals_aa_recompute = any(aa_stack) do aa + isa(aa, GlobalsAA) + end + @dispose pic=StandardInstrumentationCallbacks() pb=PassBuilder(tm, pic) mpm=NewPMModulePassManager(pb) begin + # GlobalsAA needs to be computed before it can be used + if needs_globals_aa_recompute + add!(mpm, RecomputeGlobalsAAPass()) + end + if is_module_pass(typeof(pass)) + add!(mpm, pb, pass) + elseif is_cgscc_pass(typeof(pass)) + add!(mpm, NewPMCGSCCPassManager) do cpm + add!(cpm, pass) + end + elseif is_function_pass(typeof(pass)) + add!(mpm, NewPMFunctionPassManager) do fpm + add!(fpm, pass) + end + else + @assert is_loop_pass(typeof(pass)) + add!(mpm, NewPMFunctionPassManager) do fpm + add!(fpm, NewPMLoopPassManager) do lpm + add!(lpm, pass) + end + end + end + run!(mpm, m, tm, aa_stack) + end +end + +function run!(pass::NewPMLLVMPass, f::Function, tm::Union{Nothing,TargetMachine}=nothing, aa_stack::AbstractVector{<:NewPMAliasAnalysis}=NewPMAliasAnalysis[]) + needs_globals_aa_recompute = any(aa_stack) do aa + isa(aa, GlobalsAA) + end + if needs_globals_aa_recompute + throw(ArgumentError("GlobalsAA needs to be computed on a module, not a function!")) + end + @dispose pic=StandardInstrumentationCallbacks() pb=PassBuilder(tm, pic) fpm=NewPMFunctionPassManager(pb) begin + if is_function_pass(typeof(pass)) + add!(fpm, pb, pass) + elseif is_loop_pass(typeof(pass)) + add!(fpm, NewPMLoopPassManager) do lpm + add!(lpm, pass) + end + else + throw(ArgumentError("Pass $pass is not a function or loop pass")) + end + run!(fpm, f, tm, aa_stack) end - add!(pm, pm.pb::PassBuilder, pass) end diff --git a/src/newpm/passmanager.jl b/src/newpm/passmanager.jl index 2413818a..a60613e6 100644 --- a/src/newpm/passmanager.jl +++ b/src/newpm/passmanager.jl @@ -107,8 +107,8 @@ function add!(pm::NewPMCGSCCPassManager, pm2::NewPMFunctionPassManager) API.LLVMCGPMAddFPM(pm, pm2) append!(pm.roots, pm2.roots) end -function add!(pm::NewPMFunctionPassManager, pm2::NewPMLoopPassManager) - API.LLVMFPMAddLPM(pm, pm2) +function add!(pm::NewPMFunctionPassManager, pm2::NewPMLoopPassManager, UseMemorySSA::Core.Bool=false) + API.LLVMFPMAddLPM(pm, pm2, UseMemorySSA) append!(pm.roots, pm2.roots) end @@ -123,7 +123,7 @@ function add!(f::Core.Function, pm::NewPMModulePassManager, ::Type{NewPMModulePa end function add!(f::Core.Function, pm::NewPMCGSCCPassManager, ::Type{NewPMCGSCCPassManager}) - pm2 = NewPMCGSCCPassManager(om.pb) + pm2 = NewPMCGSCCPassManager(pm.pb) try f(pm2) add!(pm, pm2) @@ -182,11 +182,11 @@ function add!(f::Core.Function, pm::NewPMCGSCCPassManager, ::Type{NewPMFunctionP end end -function add!(f::Core.Function, pm::NewPMFunctionPassManager, ::Type{NewPMLoopPassManager}) +function add!(f::Core.Function, pm::NewPMFunctionPassManager, ::Type{NewPMLoopPassManager}, UseMemorySSA::Core.Bool=false) pm2 = NewPMLoopPassManager(pm.pb) try f(pm2) - add!(pm, pm2) + add!(pm, pm2, UseMemorySSA) finally dispose(pm2) end diff --git a/test/newpm.jl b/test/newpm.jl index 7d86d2c2..e07c31d6 100644 --- a/test/newpm.jl +++ b/test/newpm.jl @@ -131,7 +131,13 @@ host_t = Target(triple=host_triple) NewPMModulePassManager(pb) do mpm for pass in filter(is_module_pass, subtypes(NewPMLLVMPass)) - add!(mpm, pass()) + try + add!(mpm, pass()) + @test "Successfully added $(pass)!" != "" + catch err + @test "Failed to add $(pass)!" == "" + @error err + end end end @test "Successfully added all module passes!" != "" @@ -139,7 +145,13 @@ host_t = Target(triple=host_triple) NewPMModulePassManager(pb) do mpm add!(mpm, NewPMCGSCCPassManager) do cgpm for pass in filter(is_cgscc_pass, subtypes(NewPMLLVMPass)) - add!(cgpm, pass()) + try + add!(cgpm, pass()) + @test "Successfully added $(pass)!" != "" + catch err + @test "Failed to add $(pass)!" == "" + @error err + end end end end @@ -149,7 +161,13 @@ host_t = Target(triple=host_triple) NewPMModulePassManager(pb) do mpm add!(mpm, NewPMFunctionPassManager) do fpm for pass in filter(is_function_pass, subtypes(NewPMLLVMPass)) - add!(fpm, pass()) + try + add!(fpm, pass()) + @test "Successfully added $(pass)!" != "" + catch err + @test "Failed to add $(pass)!" == "" + @error err + end end end end @@ -160,13 +178,49 @@ host_t = Target(triple=host_triple) add!(mpm, NewPMFunctionPassManager) do fpm add!(fpm, NewPMLoopPassManager) do lpm for pass in filter(is_loop_pass, subtypes(NewPMLLVMPass)) - add!(lpm, pass()) + try + add!(lpm, pass()) + @test "Successfully added $(pass)!" != "" + catch err + @test "Failed to add $(pass)!" == "" + @error err + end end end end end @test "Successfully added all loop passes!" != "" + + NewPMModulePassManager(pb) do mpm + add!(mpm, NewPMModulePassManager) do mpm2 + add!(mpm2, NewPMCGSCCPassManager) do cgpm + add!(cgpm, NewPMCGSCCPassManager) do cgpm2 + add!(cgpm2, NewPMFunctionPassManager) do fpm + add!(fpm, NewPMFunctionPassManager) do fpm2 + add!(fpm2, NewPMLoopPassManager) do lpm + add!(lpm, NewPMLoopPassManager) do lpm2 + @test_throws LLVMException parse!(pb, lpm2, "nonexistent") + end + end + @test_throws LLVMException parse!(pb, fpm2, "nonexistent") + end + end + @test_throws LLVMException parse!(pb, cgpm2, "nonexistent") + end + end + @test_throws LLVMException parse!(pb, mpm2, "nonexistent") + end + end + + @test "Successfully added nested pass managers!" != "" + + # As of LLVM 15 this count is 279, may change with each version based on LLVM's whims + if VERSION >= v"1.10.0-DEV.1622" + @test length(subtypes(NewPMLLVMPass)) == 279 + else + @test length(subtypes(NewPMLLVMPass)) == 262 + end end end @@ -197,29 +251,374 @@ host_t = Target(triple=host_triple) end @test "Successfully added custom module and function passes!" != "" - + @dispose ctx=Context() builder=IRBuilder() mod=LLVM.Module("test") begin - pa = run!(mpm, mod, mam) - @test observed_modules == 1 - @test observed_functions == 0 - @test are_all_preserved(pa) - - + @dispose pa=run!(mpm, mod, mam) begin + @test observed_modules == 1 + @test observed_functions == 0 + @test are_all_preserved(pa) + end + ft = LLVM.FunctionType(LLVM.VoidType()) fn = LLVM.Function(mod, "SomeFunction", ft) - + entry = BasicBlock(fn, "entry") position!(builder, entry) - + ret!(builder) - - pa = run!(mpm, mod, mam) - @test observed_modules == 2 - @test observed_functions == 1 - @test are_all_preserved(pa) + + @dispose pa=run!(mpm, mod, mam) begin + @test observed_modules == 2 + @test observed_functions == 1 + @test are_all_preserved(pa) + end end end end end +function fake_custom_legacy_pass(counter::Ref{Int}) + return ir -> begin + counter[] += 1 + return false + end +end + +@dispose tm=TargetMachine(host_t, host_triple) pb=PassBuilder(tm; si=true) begin + + observed_modules = Ref{Int}(0) + observed_functions = Ref{Int}(0) + @dispose mpm=NewPMModulePassManager(pb) begin + add!(legacy2newpm(fake_custom_legacy_pass(observed_modules)), mpm) + add!(mpm, NewPMFunctionPassManager) do fpm + add!(legacy2newpm(fake_custom_legacy_pass(observed_functions)), fpm) + end + + @dispose ctx=Context() builder=IRBuilder() mod=LLVM.Module("test") begin + run!(mpm, mod) + + @test observed_modules[] == 1 + @test observed_functions[] == 0 + + ft = LLVM.FunctionType(LLVM.VoidType()) + fn = LLVM.Function(mod, "SomeFunction", ft) + + entry = BasicBlock(fn, "entry") + position!(builder, entry) + + ret!(builder) + + run!(mpm, mod) + @test observed_modules[] == 2 + @test observed_functions[] == 1 + end + end +end + end # testset "newpm custom passes" + +@testset "newpm analyses" begin + +host_triple = triple() +host_t = Target(triple=host_triple) + +@dispose tm=TargetMachine(host_t, host_triple) pb=PassBuilder(tm; si=true) begin + analysis_managers() do lam, fam, cam, mam + @test add!(fam, AAManager) do aam + # Do nothing + end + @test !add!(fam, AAManager) do aam + # Shouldn't run + @test "Ran an AA manager callback when another AA manager was already registered" + end + register!(pb, lam, fam, cam, mam) + end + @test "Registered an empty AA manager!" != "" + analysis_managers() do lam, fam, cam, mam + add!(fam, AAManager) do aam + add!(aam, BasicAA()) + end + register!(pb, lam, fam, cam, mam) + end + @test "Registered a single alias analysis pass!" != "" + analysis_managers() do lam, fam, cam, mam + add!(fam, AAManager) do aam + add!(aam, BasicAA()) + add!(aam, CFLAndersAA()) + add!(aam, CFLSteensAA()) + add!(aam, ObjCARCAA()) + add!(aam, ScopedNoAliasAA()) + add!(aam, TypeBasedAA()) + add!(aam, GlobalsAA()) + end + register!(pb, lam, fam, cam, mam) + end + @test "Registered all alias analysis passes!" != "" + analysis_managers() do lam, fam, cam, mam + add!(fam, TargetIRAnalysis(tm)) + add!(fam, TargetLibraryAnalysis(host_triple)) + register!(pb, lam, fam, cam, mam) + end + @test "Registered target analyses!" != "" + analysis_managers(nothing, tm, [BasicAA(), ScopedNoAliasAA(), TypeBasedAA()]) do lam, fam, cam, mam + register!(pb, lam, fam, cam, mam) + end + @test "Implicitly registered alias analyses and target analyses!" != "" +end + +end # testset "newpm analyses" + +@testset "newpm convenience functions" begin + +@dispose ctx=Context() builder=IRBuilder() mod=LLVM.Module("test") begin + ft = LLVM.FunctionType(LLVM.VoidType()) + fn = LLVM.Function(mod, "SomeFunction", ft) + + entry = BasicBlock(fn, "entry") + position!(builder, entry) + + ret!(builder) + + @test isnothing(run!(ForceFunctionAttrsPass(), mod)) + + @test "Successfully ran with just module pass and module!" != "" + + @test isnothing(run!(ArgumentPromotionPass(), mod)) + + @test "Successfully ran with just cgscc pass and module!" != "" + + @test isnothing(run!(SimplifyCFGPass(), mod)) + + @test "Successfully ran with just function pass and module!" != "" + + @test isnothing(run!(LICMPass(), mod)) + + @test "Successfully ran with just loop pass and module!" != "" + + @test isnothing(run!(SimplifyCFGPass(), fn)) + + @test "Successfully ran with just function pass and function!" != "" + + @test isnothing(run!(LICMPass(), fn)) + + @test "Successfully ran with just loop pass and function!" != "" + + host_triple = triple() + host_t = Target(triple=host_triple) + + @dispose tm=TargetMachine(host_t, host_triple) begin + @test isnothing(run!(SimplifyCFGPass(), fn, tm, [BasicAA(), ScopedNoAliasAA(), TypeBasedAA()])) + end + + @test "Successfully forwarded target machine and alias analyses!" != "" +end + +end # testset "newpm convenience functions" + +@testset "newpm error checking" begin +@dispose mpm=NewPMModulePassManager() begin + @test_throws ArgumentError add!(mpm, RecomputeGlobalsAAPass()) +end + +@dispose cpm=NewPMCGSCCPassManager() begin + @test_throws ArgumentError add!(cpm, ArgumentPromotionPass()) +end + +@dispose fpm=NewPMFunctionPassManager() begin + @test_throws ArgumentError add!(fpm, SimplifyCFGPass()) +end + +@dispose lpm=NewPMLoopPassManager() begin + @test_throws ArgumentError add!(lpm, LICMPass()) +end + +@dispose pic=PassInstrumentationCallbacks() begin + @test_throws ArgumentError PassBuilder(nothing, pic; si=true) +end + +@dispose pb=PassBuilder() begin + @dispose mpm=NewPMModulePassManager(pb) begin + @test_throws ArgumentError add!(mpm, SimplifyCFGPass()) + end + + @dispose cpm=NewPMCGSCCPassManager(pb) begin + @test_throws ArgumentError add!(cpm, SimplifyCFGPass()) + end + + @dispose fpm=NewPMFunctionPassManager(pb) begin + @test_throws ArgumentError add!(fpm, RecomputeGlobalsAAPass()) + end + + @dispose lpm=NewPMLoopPassManager(pb) begin + @test_throws ArgumentError add!(lpm, RecomputeGlobalsAAPass()) + end +end + +@dispose ctx=Context() builder=IRBuilder() mod=LLVM.Module("test") begin + ft = LLVM.FunctionType(LLVM.VoidType()) + fn = LLVM.Function(mod, "SomeFunction", ft) + + entry = BasicBlock(fn, "entry") + position!(builder, entry) + + ret!(builder) + + host_triple = triple() + host_t = Target(triple=host_triple) + + @dispose tm=TargetMachine(host_t, host_triple) begin + @test isnothing(run!(SimplifyCFGPass(), mod, tm, [BasicAA(), ScopedNoAliasAA(), TypeBasedAA(), GlobalsAA()])) + @test_throws ArgumentError run!(SimplifyCFGPass(), fn, tm, [BasicAA(), ScopedNoAliasAA(), TypeBasedAA(), GlobalsAA()]) + end +end + +end # testset "newpm error checking" + +if VERSION >= v"1.10.0-DEV.1622" + +using LLVM.Interop + +# Copy of the julia pipeline from julia/src/pipeline.cpp +@testset "newpm julia pipeline" begin +host_triple = triple() +host_t = Target(triple=host_triple) +@dispose tm=TargetMachine(host_t, host_triple) pic=StandardInstrumentationCallbacks() pb=PassBuilder(tm,pic) begin + basicSimplifyCFGOptions = SimplifyCFGPassOptions(; forwardswitchcond=true, switchrangetoicmp=true, switchtolookup=true) + aggressiveSimplifyCFGOptions = SimplifyCFGPassOptions(; forwardswitchcond=true, switchrangetoicmp=true, switchtolookup=true, hoistcommoninsts=true) + NewPMModulePassManager(pb) do mpm + add!(mpm, NewPMFunctionPassManager) do fpm + add!(fpm, GCInvariantVerifierPass()) + end + add!(mpm, VerifierPass()) + add!(mpm, ForceFunctionAttrsPass()) + add!(mpm, Annotation2MetadataPass()) + add!(mpm, ConstantMergePass()) + add!(mpm, NewPMFunctionPassManager) do fpm + add!(fpm, LowerExpectIntrinsicPass()) + add!(fpm, PropagateJuliaAddrspacesPass()) + add!(fpm, SimplifyCFGPass(basicSimplifyCFGOptions)) + add!(fpm, DCEPass()) + add!(fpm, SROAPass()) + end + add!(mpm, AlwaysInlinerPass()) + add!(mpm, NewPMCGSCCPassManager) do cgpm + add!(cgpm, NewPMFunctionPassManager) do fpm + add!(fpm, AllocOptPass()) + add!(fpm, Float2IntPass()) + add!(fpm, LowerConstantIntrinsicsPass()) + end + end + add!(mpm, CPUFeaturesPass()) + add!(mpm, NewPMFunctionPassManager) do fpm + add!(fpm, SROAPass()) + add!(fpm, InstCombinePass()) + add!(fpm, JumpThreadingPass()) + add!(fpm, CorrelatedValuePropagationPass()) + add!(fpm, ReassociatePass()) + add!(fpm, EarlyCSEPass()) + add!(fpm, AllocOptPass()) + end + add!(mpm, LowerSIMDLoopPass()) + add!(mpm, NewPMFunctionPassManager) do fpm + add!(fpm, NewPMLoopPassManager) do lpm + add!(lpm, LoopRotatePass()) + end + add!(fpm, NewPMLoopPassManager, #=UseMemorySSA=#true) do lpm + add!(lpm, LICMPass()) + add!(lpm, JuliaLICMPass()) + add!(lpm, SimpleLoopUnswitchPass()) + add!(lpm, LICMPass()) + add!(lpm, JuliaLICMPass()) + end + add!(fpm, IRCEPass()) + add!(fpm, NewPMLoopPassManager) do lpm + add!(lpm, LoopInstSimplifyPass()) + add!(lpm, LoopIdiomRecognizePass()) + add!(lpm, IndVarSimplifyPass()) + add!(lpm, LoopDeletionPass()) + add!(lpm, LoopFullUnrollPass()) + end + add!(fpm, SROAPass()) + add!(fpm, InstSimplifyPass()) + add!(fpm, GVNPass()) + add!(fpm, MemCpyOptPass()) + add!(fpm, SCCPPass()) + add!(fpm, CorrelatedValuePropagationPass()) + add!(fpm, DCEPass()) + add!(fpm, IRCEPass()) + add!(fpm, InstCombinePass()) + add!(fpm, JumpThreadingPass()) + add!(fpm, GVNPass()) + add!(fpm, DSEPass()) + add!(fpm, SimplifyCFGPass(aggressiveSimplifyCFGOptions)) + add!(fpm, AllocOptPass()) + add!(fpm, NewPMLoopPassManager) do lpm + add!(lpm, LoopDeletionPass()) + add!(lpm, LoopInstSimplifyPass()) + end + add!(fpm, LoopDistributePass()) + add!(fpm, InjectTLIMappings()) + add!(fpm, LoopVectorizePass()) + add!(fpm, LoopLoadEliminationPass()) + add!(fpm, InstCombinePass()) + add!(fpm, SimplifyCFGPass(aggressiveSimplifyCFGOptions)) + add!(fpm, SLPVectorizerPass()) + add!(fpm, VectorCombinePass()) + add!(fpm, ADCEPass()) + add!(fpm, LoopUnrollPass()) + add!(fpm, WarnMissedTransformationsPass()) + end + add!(mpm, NewPMFunctionPassManager) do fpm + add!(fpm, LowerExcHandlersPass()) + add!(fpm, GCInvariantVerifierPass()) + end + add!(mpm, RemoveNIPass()) + add!(mpm, NewPMFunctionPassManager) do fpm + add!(fpm, LateLowerGCPass()) + end + add!(mpm, FinalLowerGCPass()) + add!(mpm, NewPMFunctionPassManager) do fpm + add!(fpm, GVNPass()) + add!(fpm, SCCPPass()) + add!(fpm, DCEPass()) + end + add!(mpm, LowerPTLSPass()) + add!(mpm, NewPMFunctionPassManager) do fpm + add!(fpm, InstCombinePass()) + add!(fpm, SimplifyCFGPass(aggressiveSimplifyCFGOptions)) + end + add!(mpm, NewPMFunctionPassManager) do fpm + add!(fpm, CombineMulAddPass()) + add!(fpm, DivRemPairsPass()) + end + add!(mpm, NewPMFunctionPassManager) do fpm + add!(fpm, AnnotationRemarksPass()) + end + add!(mpm, NewPMFunctionPassManager) do fpm + add!(fpm, DemoteFloat16Pass()) + add!(fpm, GVNPass()) + end + + @test "Successfully created julia pipeline!" != "" + + @dispose ctx=Context() builder=IRBuilder() mod=LLVM.Module("test") begin + ft = LLVM.FunctionType(LLVM.VoidType()) + fn = LLVM.Function(mod, "SomeFunction", ft) + + entry = BasicBlock(fn, "entry") + position!(builder, entry) + + ret!(builder) + + run!(mpm, mod, tm, [BasicAA(), ScopedNoAliasAA(), TypeBasedAA()]) + end + end +end + +@test "Successfully ran julia pipeline!" != "" + +@test string(JuliaPipelinePass(; speedup=2)) == "julia" + +end # testset "newpm julia pipeline" + +end # VERSION >= v"1.10.0-DEV.1622"