diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -1015,6 +1015,9 @@ default: llvm_unreachable("Invalid optimization level!"); + case 0: + return PassBuilder::OptimizationLevel::O0; + case 1: return PassBuilder::OptimizationLevel::O1; @@ -1247,6 +1250,10 @@ ModulePassManager MPM(CodeGenOpts.DebugPassManager); if (!CodeGenOpts.DisableLLVMPasses) { + // Map our optimization levels into one of the distinct levels used to + // configure the pipeline. + PassBuilder::OptimizationLevel Level = mapToLevel(CodeGenOpts); + bool IsThinLTO = CodeGenOpts.PrepareForThinLTO; bool IsLTO = CodeGenOpts.PrepareForLTO; @@ -1295,10 +1302,6 @@ MPM.addPass(NameAnonGlobalPass()); } } else { - // Map our optimization levels into one of the distinct levels used to - // configure the pipeline. - PassBuilder::OptimizationLevel Level = mapToLevel(CodeGenOpts); - // If we reached here with a non-empty index file name, then the index // file was empty and we are not performing ThinLTO backend compilation // (used in testing in a distributed build environment). Drop any the type @@ -1433,6 +1436,8 @@ } if (CodeGenOpts.OptimizationLevel == 0) { + PB.runRegisteredEPCallbacks(MPM, Level, CodeGenOpts.DebugPassManager); + // FIXME: the backends do not handle matrix intrinsics currently. Make // sure they are also lowered in O0. A lightweight version of the pass // should run in the backend pipeline on demand. diff --git a/clang/test/CodeGen/bpf-O0.c b/clang/test/CodeGen/bpf-O0.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/bpf-O0.c @@ -0,0 +1,6 @@ +// RUN: %clang -O0 %s -target bpf -g -c -o /dev/null -fexperimental-new-pass-manager + +struct ss { + int a; +}; +int foo() { return __builtin_btf_type_id(0, 0) + __builtin_preserve_type_info(*(struct ss *)0, 0); } diff --git a/llvm/include/llvm/Passes/PassBuilder.h b/llvm/include/llvm/Passes/PassBuilder.h --- a/llvm/include/llvm/Passes/PassBuilder.h +++ b/llvm/include/llvm/Passes/PassBuilder.h @@ -608,15 +608,20 @@ /// Register a callback for a default optimizer pipeline extension point /// /// This extension point allows adding optimizations at the very end of the - /// function optimization pipeline. A key difference between this and the - /// legacy PassManager's OptimizerLast callback is that this extension point - /// is not triggered at O0. Extensions to the O0 pipeline should append their - /// passes to the end of the overall pipeline. + /// function optimization pipeline. void registerOptimizerLastEPCallback( const std::function &C) { OptimizerLastEPCallbacks.push_back(C); } + /// Run all registered extension point callbacks + /// + /// This runs the registered callbacks in the order they would be run in a + /// typical build*Pipeline(). This allows for reusing register*EPCallback() + /// between O0 and O[123] pipelines. + void runRegisteredEPCallbacks(ModulePassManager &MPM, OptimizationLevel Level, + bool DebugLogging); + /// Register a callback for parsing an AliasAnalysis Name to populate /// the given AAManager \p AA void registerParseAACallback( diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp --- a/llvm/lib/Passes/PassBuilder.cpp +++ b/llvm/lib/Passes/PassBuilder.cpp @@ -1654,6 +1654,49 @@ return MPM; } +void PassBuilder::runRegisteredEPCallbacks(ModulePassManager &MPM, + OptimizationLevel Level, + bool DebugLogging) { + assert(Level == OptimizationLevel::O0 && + "runRegisteredEPCallbacks should only be used with O0"); + for (auto &C : PipelineStartEPCallbacks) + C(MPM); + if (!LateLoopOptimizationsEPCallbacks.empty()) { + LoopPassManager LPM(DebugLogging); + for (auto &C : LateLoopOptimizationsEPCallbacks) + C(LPM, Level); + MPM.addPass(createModuleToFunctionPassAdaptor( + createFunctionToLoopPassAdaptor(std::move(LPM)))); + } + if (!LoopOptimizerEndEPCallbacks.empty()) { + LoopPassManager LPM(DebugLogging); + for (auto &C : LoopOptimizerEndEPCallbacks) + C(LPM, Level); + MPM.addPass(createModuleToFunctionPassAdaptor( + createFunctionToLoopPassAdaptor(std::move(LPM)))); + } + if (!ScalarOptimizerLateEPCallbacks.empty()) { + FunctionPassManager FPM(DebugLogging); + for (auto &C : ScalarOptimizerLateEPCallbacks) + C(FPM, Level); + MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); + } + if (!CGSCCOptimizerLateEPCallbacks.empty()) { + CGSCCPassManager CGPM(DebugLogging); + for (auto &C : CGSCCOptimizerLateEPCallbacks) + C(CGPM, Level); + MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM))); + } + if (!VectorizerStartEPCallbacks.empty()) { + FunctionPassManager FPM(DebugLogging); + for (auto &C : VectorizerStartEPCallbacks) + C(FPM, Level); + MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); + } + for (auto &C : OptimizerLastEPCallbacks) + C(MPM, Level); +} + AAManager PassBuilder::buildDefaultAAPipeline() { AAManager AA; @@ -2240,6 +2283,8 @@ MPM.addPass(createModuleToFunctionPassAdaptor(CoroCleanupPass())); } + runRegisteredEPCallbacks(MPM, L, DebugLogging); + // Do nothing else at all! return Error::success(); } diff --git a/llvm/test/CodeGen/BPF/optnone-2.ll b/llvm/test/CodeGen/BPF/optnone-2.ll --- a/llvm/test/CodeGen/BPF/optnone-2.ll +++ b/llvm/test/CodeGen/BPF/optnone-2.ll @@ -1,5 +1,5 @@ ; RUN: opt < %s -passes='default' | llc -march=bpfel -filetype=asm -o /dev/null - -; TODO: add -O0 once that's supported +; RUN: opt < %s -passes='default' | llc -march=bpfel -filetype=asm -o /dev/null - ; IR generated by ; $ cat /tmp/a.c diff --git a/llvm/test/Other/new-pm-O0-ep-callbacks.ll b/llvm/test/Other/new-pm-O0-ep-callbacks.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Other/new-pm-O0-ep-callbacks.ll @@ -0,0 +1,24 @@ +; RUN: opt -disable-output -debug-pass-manager -passes-ep-late-loop-optimizations=no-op-loop -passes='default' 2>&1 < %s | FileCheck %s +; RUN: opt -disable-output -debug-pass-manager -passes-ep-loop-optimizer-end=no-op-loop -passes='default' 2>&1 < %s | FileCheck %s +; RUN: opt -disable-output -debug-pass-manager -passes-ep-scalar-optimizer-late=no-op-function -passes='default' 2>&1 < %s | FileCheck %s +; RUN: opt -disable-output -debug-pass-manager -passes-ep-cgscc-optimizer-late=no-op-cgscc -passes='default' 2>&1 < %s | FileCheck %s +; RUN: opt -disable-output -debug-pass-manager -passes-ep-vectorizer-start=no-op-function -passes='default' 2>&1 < %s | FileCheck %s +; RUN: opt -disable-output -debug-pass-manager -passes-ep-pipeline-start=no-op-module -passes='default' 2>&1 < %s | FileCheck %s +; RUN: opt -disable-output -debug-pass-manager -passes-ep-optimizer-last=no-op-function -passes='default' 2>&1 < %s | FileCheck %s + +; CHECK: Running pass: NoOp + +declare void @bar() local_unnamed_addr + +define void @foo(i32 %n) local_unnamed_addr { +entry: + br label %loop +loop: + %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ] + %iv.next = add i32 %iv, 1 + tail call void @bar() + %cmp = icmp eq i32 %iv, %n + br i1 %cmp, label %exit, label %loop +exit: + ret void +}