diff --git a/llvm/docs/ReleaseNotes.rst b/llvm/docs/ReleaseNotes.rst --- a/llvm/docs/ReleaseNotes.rst +++ b/llvm/docs/ReleaseNotes.rst @@ -149,6 +149,8 @@ have been removed. * Removed ``LLVMPassManagerBuilderRef`` and functions interacting with it. These belonged to the no longer supported legacy pass manager. +* ``LLVMRunOptimizationPipeline`` was added as a convenience method to run a + default optimization pipeline. * As part of the opaque pointer transition, ``LLVMGetElementType`` no longer gives the pointee type of a pointer type. diff --git a/llvm/include/llvm-c/Transforms/PassBuilder.h b/llvm/include/llvm-c/Transforms/PassBuilder.h --- a/llvm/include/llvm-c/Transforms/PassBuilder.h +++ b/llvm/include/llvm-c/Transforms/PassBuilder.h @@ -50,6 +50,16 @@ LLVMTargetMachineRef TM, LLVMPassBuilderOptionsRef Options); +/** + * Construct and run an optimization pipeline over a module. + * + * This is a convenience method equivalent to + * `LLVMRunPasses(..., "default", ...)`. + */ +LLVMErrorRef LLVMRunOptimizationPipeline(LLVMModuleRef M, int SpeedLevel, + int SizeLevel, LLVMTargetMachineRef TM, + LLVMPassBuilderOptionsRef Options); + /** * Create a new set of options for a PassBuilder * diff --git a/llvm/include/llvm/Passes/OptimizationLevel.h b/llvm/include/llvm/Passes/OptimizationLevel.h --- a/llvm/include/llvm/Passes/OptimizationLevel.h +++ b/llvm/include/llvm/Passes/OptimizationLevel.h @@ -16,6 +16,7 @@ #define LLVM_PASSES_OPTIMIZATIONLEVEL_H #include +#include namespace llvm { @@ -121,6 +122,9 @@ unsigned getSpeedupLevel() const { return SpeedLevel; } unsigned getSizeLevel() const { return SizeLevel; } + + static std::optional fromSpeedAndSizeLevel(unsigned Speed, + unsigned Size); }; } // namespace llvm diff --git a/llvm/lib/Passes/OptimizationLevel.cpp b/llvm/lib/Passes/OptimizationLevel.cpp --- a/llvm/lib/Passes/OptimizationLevel.cpp +++ b/llvm/lib/Passes/OptimizationLevel.cpp @@ -28,3 +28,20 @@ const OptimizationLevel OptimizationLevel::Oz = { /*SpeedLevel*/ 2, /*SizeLevel*/ 2}; + +std::optional +OptimizationLevel::fromSpeedAndSizeLevel(unsigned Speed, unsigned Size) { + if (Speed == 0 && Size == 0) + return O0; + if (Speed == 1 && Size == 0) + return O1; + if (Speed == 2 && Size == 0) + return O2; + if (Speed == 3 && Size == 0) + return O3; + if (Speed == 2 && Size == 1) + return Os; + if (Speed == 2 && Size == 2) + return Oz; + return std::nullopt; +} diff --git a/llvm/lib/Passes/PassBuilderBindings.cpp b/llvm/lib/Passes/PassBuilderBindings.cpp --- a/llvm/lib/Passes/PassBuilderBindings.cpp +++ b/llvm/lib/Passes/PassBuilderBindings.cpp @@ -13,9 +13,11 @@ #include "llvm-c/Transforms/PassBuilder.h" #include "llvm/IR/Verifier.h" +#include "llvm/Passes/OptimizationLevel.h" #include "llvm/Passes/PassBuilder.h" #include "llvm/Passes/StandardInstrumentations.h" #include "llvm/Support/CBindingWrapping.h" +#include "llvm/Support/Error.h" using namespace llvm; @@ -79,6 +81,51 @@ return LLVMErrorSuccess; } +LLVMErrorRef LLVMRunOptimizationPipeline(LLVMModuleRef M, int SpeedLevel, + int SizeLevel, LLVMTargetMachineRef TM, + LLVMPassBuilderOptionsRef Options) { + std::optional OL = + OptimizationLevel::fromSpeedAndSizeLevel(SpeedLevel, SizeLevel); + if (!OL) { + return wrap(make_error( + formatv("invalid speed/size level combination: {0} {1}", SpeedLevel, + SizeLevel) + .str(), + inconvertibleErrorCode())); + } + TargetMachine *Machine = unwrap(TM); + LLVMPassBuilderOptions *PassOpts = unwrap(Options); + bool Debug = PassOpts->DebugLogging; + bool VerifyEach = PassOpts->VerifyEach; + + Module *Mod = unwrap(M); + PassInstrumentationCallbacks PIC; + PassBuilder PB(Machine, PassOpts->PTO, std::nullopt, &PIC); + + LoopAnalysisManager LAM; + FunctionAnalysisManager FAM; + CGSCCAnalysisManager CGAM; + ModuleAnalysisManager MAM; + PB.registerLoopAnalyses(LAM); + PB.registerFunctionAnalyses(FAM); + PB.registerCGSCCAnalyses(CGAM); + PB.registerModuleAnalyses(MAM); + PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); + + StandardInstrumentations SI(Mod->getContext(), Debug, VerifyEach); + SI.registerCallbacks(PIC, &FAM); + ModulePassManager MPM; + if (VerifyEach) + MPM.addPass(VerifierPass()); + if (*OL == OptimizationLevel::O0) + MPM.addPass(PB.buildO0DefaultPipeline(*OL)); + else + MPM.addPass(PB.buildPerModuleDefaultPipeline(*OL)); + + MPM.run(*Mod, MAM); + return LLVMErrorSuccess; +} + LLVMPassBuilderOptionsRef LLVMCreatePassBuilderOptions() { return wrap(new LLVMPassBuilderOptions()); } diff --git a/llvm/unittests/Passes/PassBuilderBindings/PassBuilderBindingsTest.cpp b/llvm/unittests/Passes/PassBuilderBindings/PassBuilderBindingsTest.cpp --- a/llvm/unittests/Passes/PassBuilderBindings/PassBuilderBindingsTest.cpp +++ b/llvm/unittests/Passes/PassBuilderBindings/PassBuilderBindingsTest.cpp @@ -69,6 +69,45 @@ LLVMDisposePassBuilderOptions(Options); } +TEST_F(PassBuilderCTest, Pipeline) { + LLVMPassBuilderOptionsRef Options = LLVMCreatePassBuilderOptions(); + LLVMPassBuilderOptionsSetLoopUnrolling(Options, 1); + LLVMPassBuilderOptionsSetVerifyEach(Options, 1); + LLVMPassBuilderOptionsSetDebugLogging(Options, 0); + if (LLVMErrorRef E = LLVMRunOptimizationPipeline(Module, 2, 0, TM, Options)) { + char *Msg = LLVMGetErrorMessage(E); + LLVMConsumeError(E); + FAIL() << "Failed to run passes: " << Msg; + } + LLVMDisposePassBuilderOptions(Options); +} + +TEST_F(PassBuilderCTest, O0Pipeline) { + LLVMPassBuilderOptionsRef Options = LLVMCreatePassBuilderOptions(); + LLVMPassBuilderOptionsSetLoopUnrolling(Options, 1); + LLVMPassBuilderOptionsSetVerifyEach(Options, 1); + LLVMPassBuilderOptionsSetDebugLogging(Options, 0); + if (LLVMErrorRef E = LLVMRunOptimizationPipeline(Module, 0, 0, TM, Options)) { + char *Msg = LLVMGetErrorMessage(E); + LLVMConsumeError(E); + FAIL() << "Failed to run passes: " << Msg; + } + LLVMDisposePassBuilderOptions(Options); +} + +TEST_F(PassBuilderCTest, BadPipeline) { + LLVMPassBuilderOptionsRef Options = LLVMCreatePassBuilderOptions(); + LLVMPassBuilderOptionsSetLoopUnrolling(Options, 1); + LLVMPassBuilderOptionsSetVerifyEach(Options, 1); + LLVMPassBuilderOptionsSetDebugLogging(Options, 0); + if (LLVMErrorRef E = LLVMRunOptimizationPipeline(Module, 3, 1, TM, Options)) { + LLVMConsumeError(E); + } else { + FAIL() << "Unexpectedly passed"; + } + LLVMDisposePassBuilderOptions(Options); +} + TEST_F(PassBuilderCTest, InvalidPassIsError) { LLVMPassBuilderOptionsRef Options = LLVMCreatePassBuilderOptions(); LLVMErrorRef E1 = LLVMRunPasses(Module, "", TM, Options);