diff options
author | Gabriel Baraldi <baraldigabriel@gmail.com> | 2025-09-19 14:31:04 -0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-09-19 10:31:04 -0700 |
commit | 21f5f32cc6feacdacd9a22bc74f3e6ceb2a258c4 (patch) | |
tree | 3bc148b04e20694c5968e37323c7a2a2c1199631 /llvm/lib/Passes/PassBuilder.cpp | |
parent | 90d03a0386a6b9640e50513f6948cd2549937208 (diff) | |
download | llvm-21f5f32cc6feacdacd9a22bc74f3e6ceb2a258c4.zip llvm-21f5f32cc6feacdacd9a22bc74f3e6ceb2a258c4.tar.gz llvm-21f5f32cc6feacdacd9a22bc74f3e6ceb2a258c4.tar.bz2 |
[PassBuilder] Add callback invoking to PassBuilder string API (#157153)
This is a very rough state of what this can look like, but I didn't want
to spend too much time on what could be a dead end.
Currently the only way to invoke callbacks is by using the default
pipelines, this is an issue if you want to define your own pipeline
using the C string API (we do that in LLVM.jl in julia) so I extended
the api to allow for invoking those callbacks just like one would call a
pass of that kind.
There are some questions about the params that these callbacks take and
also I'm missing some of them (some of them are also invoked by the
backend so we may not want to expose them)
Code written with AI help, bugs are mine. (Not sure what policy for this
is on LLVM)
Diffstat (limited to 'llvm/lib/Passes/PassBuilder.cpp')
-rw-r--r-- | llvm/lib/Passes/PassBuilder.cpp | 131 |
1 files changed, 111 insertions, 20 deletions
diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp index bf36c13..e4dab4a 100644 --- a/llvm/lib/Passes/PassBuilder.cpp +++ b/llvm/lib/Passes/PassBuilder.cpp @@ -189,6 +189,7 @@ #include "llvm/Support/CodeGen.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/Regex.h" @@ -481,6 +482,26 @@ public: } // namespace +static std::optional<OptimizationLevel> parseOptLevel(StringRef S) { + return StringSwitch<std::optional<OptimizationLevel>>(S) + .Case("O0", OptimizationLevel::O0) + .Case("O1", OptimizationLevel::O1) + .Case("O2", OptimizationLevel::O2) + .Case("O3", OptimizationLevel::O3) + .Case("Os", OptimizationLevel::Os) + .Case("Oz", OptimizationLevel::Oz) + .Default(std::nullopt); +} + +static Expected<OptimizationLevel> parseOptLevelParam(StringRef S) { + std::optional<OptimizationLevel> OptLevel = parseOptLevel(S); + if (OptLevel) + return *OptLevel; + return make_error<StringError>( + formatv("invalid optimization level '{}'", S).str(), + inconvertibleErrorCode()); +} + PassBuilder::PassBuilder(TargetMachine *TM, PipelineTuningOptions PTO, std::optional<PGOOptions> PGOOpt, PassInstrumentationCallbacks *PIC) @@ -530,6 +551,96 @@ PassBuilder::PassBuilder(TargetMachine *TM, PipelineTuningOptions PTO, #include "llvm/Passes/MachinePassRegistry.def" }); } + + // Module-level callbacks without LTO phase + registerPipelineParsingCallback( + [this](StringRef Name, ModulePassManager &PM, + ArrayRef<PassBuilder::PipelineElement>) { +#define MODULE_CALLBACK(NAME, INVOKE) \ + if (PassBuilder::checkParametrizedPassName(Name, NAME)) { \ + auto L = PassBuilder::parsePassParameters(parseOptLevelParam, Name, NAME); \ + if (!L) { \ + errs() << NAME ": " << toString(L.takeError()) << '\n'; \ + return false; \ + } \ + INVOKE(PM, L.get()); \ + return true; \ + } +#include "PassRegistry.def" + return false; + }); + + // Module-level callbacks with LTO phase (use Phase::None for string API) + registerPipelineParsingCallback( + [this](StringRef Name, ModulePassManager &PM, + ArrayRef<PassBuilder::PipelineElement>) { +#define MODULE_LTO_CALLBACK(NAME, INVOKE) \ + if (PassBuilder::checkParametrizedPassName(Name, NAME)) { \ + auto L = PassBuilder::parsePassParameters(parseOptLevelParam, Name, NAME); \ + if (!L) { \ + errs() << NAME ": " << toString(L.takeError()) << '\n'; \ + return false; \ + } \ + INVOKE(PM, L.get(), ThinOrFullLTOPhase::None); \ + return true; \ + } +#include "PassRegistry.def" + return false; + }); + + // Function-level callbacks + registerPipelineParsingCallback( + [this](StringRef Name, FunctionPassManager &PM, + ArrayRef<PassBuilder::PipelineElement>) { +#define FUNCTION_CALLBACK(NAME, INVOKE) \ + if (PassBuilder::checkParametrizedPassName(Name, NAME)) { \ + auto L = PassBuilder::parsePassParameters(parseOptLevelParam, Name, NAME); \ + if (!L) { \ + errs() << NAME ": " << toString(L.takeError()) << '\n'; \ + return false; \ + } \ + INVOKE(PM, L.get()); \ + return true; \ + } +#include "PassRegistry.def" + return false; + }); + + // CGSCC-level callbacks + registerPipelineParsingCallback( + [this](StringRef Name, CGSCCPassManager &PM, + ArrayRef<PassBuilder::PipelineElement>) { +#define CGSCC_CALLBACK(NAME, INVOKE) \ + if (PassBuilder::checkParametrizedPassName(Name, NAME)) { \ + auto L = PassBuilder::parsePassParameters(parseOptLevelParam, Name, NAME); \ + if (!L) { \ + errs() << NAME ": " << toString(L.takeError()) << '\n'; \ + return false; \ + } \ + INVOKE(PM, L.get()); \ + return true; \ + } +#include "PassRegistry.def" + return false; + }); + + // Loop-level callbacks + registerPipelineParsingCallback( + [this](StringRef Name, LoopPassManager &PM, + ArrayRef<PassBuilder::PipelineElement>) { +#define LOOP_CALLBACK(NAME, INVOKE) \ + if (PassBuilder::checkParametrizedPassName(Name, NAME)) { \ + auto L = PassBuilder::parsePassParameters(parseOptLevelParam, Name, NAME); \ + if (!L) { \ + errs() << NAME ": " << toString(L.takeError()) << '\n'; \ + return false; \ + } \ + INVOKE(PM, L.get()); \ + return true; \ + } +#include "PassRegistry.def" + return false; + }); } void PassBuilder::registerModuleAnalyses(ModuleAnalysisManager &MAM) { @@ -615,26 +726,6 @@ static std::optional<int> parseDevirtPassName(StringRef Name) { return Count; } -static std::optional<OptimizationLevel> parseOptLevel(StringRef S) { - return StringSwitch<std::optional<OptimizationLevel>>(S) - .Case("O0", OptimizationLevel::O0) - .Case("O1", OptimizationLevel::O1) - .Case("O2", OptimizationLevel::O2) - .Case("O3", OptimizationLevel::O3) - .Case("Os", OptimizationLevel::Os) - .Case("Oz", OptimizationLevel::Oz) - .Default(std::nullopt); -} - -static Expected<OptimizationLevel> parseOptLevelParam(StringRef S) { - std::optional<OptimizationLevel> OptLevel = parseOptLevel(S); - if (OptLevel) - return *OptLevel; - return make_error<StringError>( - formatv("invalid optimization level '{}'", S).str(), - inconvertibleErrorCode()); -} - Expected<bool> PassBuilder::parseSinglePassOption(StringRef Params, StringRef OptionName, StringRef PassName) { |