|
6 | 6 | #include <llvm/Passes/PassBuilder.h> |
7 | 7 | #include <llvm/Passes/StandardInstrumentations.h> |
8 | 8 | #include <llvm/Support/CBindingWrapping.h> |
| 9 | +#include <optional> |
9 | 10 |
|
10 | 11 | using namespace llvm; |
11 | 12 |
|
@@ -143,53 +144,166 @@ void LLVMPassBuilderExtensionsSetAAPipeline(LLVMPassBuilderExtensionsRef Extensi |
143 | 144 | } |
144 | 145 | #endif |
145 | 146 |
|
| 147 | +static bool checkParametrizedPassName(StringRef Name, StringRef PassName) { |
| 148 | + if (!Name.consume_front(PassName)) |
| 149 | + return false; |
| 150 | + // normal pass name w/o parameters == default parameters |
| 151 | + if (Name.empty()) |
| 152 | + return true; |
| 153 | +#if LLVM_VERSION_MAJOR >= 16 |
| 154 | + return Name.starts_with("<") && Name.ends_with(">"); |
| 155 | +#else |
| 156 | + return Name.startswith("<") && Name.endswith(">"); |
| 157 | +#endif |
| 158 | +} |
| 159 | + |
| 160 | +static std::optional<OptimizationLevel> parseOptLevel(StringRef S) { |
| 161 | + return StringSwitch<std::optional<OptimizationLevel>>(S) |
| 162 | + .Case("O0", OptimizationLevel::O0) |
| 163 | + .Case("O1", OptimizationLevel::O1) |
| 164 | + .Case("O2", OptimizationLevel::O2) |
| 165 | + .Case("O3", OptimizationLevel::O3) |
| 166 | + .Case("Os", OptimizationLevel::Os) |
| 167 | + .Case("Oz", OptimizationLevel::Oz) |
| 168 | + .Default(std::nullopt); |
| 169 | +} |
| 170 | + |
| 171 | +static Expected<OptimizationLevel> parseOptLevelParam(StringRef S) { |
| 172 | + std::optional<OptimizationLevel> OptLevel = parseOptLevel(S); |
| 173 | + if (OptLevel) |
| 174 | + return *OptLevel; |
| 175 | + return make_error<StringError>( |
| 176 | + formatv("invalid optimization level '{}'", S).str(), |
| 177 | + inconvertibleErrorCode()); |
| 178 | +} |
| 179 | + |
| 180 | +template <typename ParametersParseCallableT> |
| 181 | +static auto parsePassParameters(ParametersParseCallableT &&Parser, |
| 182 | + StringRef Name, StringRef PassName) |
| 183 | + -> decltype(Parser(StringRef{})) { |
| 184 | + using ParametersT = typename decltype(Parser(StringRef{}))::value_type; |
| 185 | + |
| 186 | + StringRef Params = Name; |
| 187 | + if (!Params.consume_front(PassName)) { |
| 188 | + llvm_unreachable( |
| 189 | + "unable to strip pass name from parametrized pass specification"); |
| 190 | + } |
| 191 | + if (!Params.empty() && |
| 192 | + (!Params.consume_front("<") || !Params.consume_back(">"))) { |
| 193 | + llvm_unreachable("invalid format for parametrized pass name"); |
| 194 | + } |
| 195 | + |
| 196 | + Expected<ParametersT> Result = Parser(Params); |
| 197 | + assert((Result || Result.template errorIsA<StringError>()) && |
| 198 | + "Pass parameter parser can only return StringErrors."); |
| 199 | + return Result; |
| 200 | +} |
| 201 | + |
| 202 | + |
146 | 203 | // Register target specific parsing callbacks |
147 | 204 | static void registerCallbackParsing(PassBuilder &PB) { |
148 | | - PB.registerPipelineParsingCallback( |
149 | | - [&](StringRef Name, FunctionPassManager &PM, |
150 | | - ArrayRef<PassBuilder::PipelineElement> InnerPipeline) { |
151 | | -#define FUNCTION_CALLBACK(NAME, INVOKE) if (Name == NAME) { PB.INVOKE(PM, OptimizationLevel::O2); return true; } |
152 | | -#include "callbacks.inc" |
153 | | -#undef FUNCTION_CALLBACK |
154 | | - return false; |
155 | | - } |
156 | | - ); |
157 | | - |
158 | | - PB.registerPipelineParsingCallback( |
159 | | - [&](StringRef Name, ModulePassManager &PM, |
160 | | - ArrayRef<PassBuilder::PipelineElement> InnerPipeline) { |
161 | | -#define MODULE_CALLBACK(NAME, INVOKE) if (Name == NAME) { PB.INVOKE(PM, OptimizationLevel::O2); return true; } |
162 | | -#include "callbacks.inc" |
163 | | -#undef MODULE_CALLBACK |
164 | | -#if LLVM_VERSION_MAJOR >= 20 |
165 | | -#define MODULE_LTO_CALLBACK(NAME, INVOKE) if (Name == NAME) { PB.INVOKE(PM, OptimizationLevel::O2, ThinOrFullLTOPhase::None); return true; } |
| 205 | + PB.registerPipelineParsingCallback( |
| 206 | + [&](StringRef Name, ModulePassManager &PM, |
| 207 | + ArrayRef<PassBuilder::PipelineElement>) { |
| 208 | +#define MODULE_CALLBACK(NAME, INVOKE) \ |
| 209 | + if (checkParametrizedPassName(Name, NAME)) { \ |
| 210 | + auto L = parsePassParameters(parseOptLevelParam, Name, NAME); \ |
| 211 | + if (!L) { \ |
| 212 | + errs() << NAME ": " << toString(L.takeError()) << '\n'; \ |
| 213 | + return false; \ |
| 214 | + } \ |
| 215 | + PB.INVOKE(PM, L.get()); \ |
| 216 | + return true; \ |
| 217 | + } |
| 218 | + #include "callbacks.inc" |
| 219 | + return false; |
| 220 | + }); |
| 221 | + |
| 222 | + // Module-level callbacks with LTO phase (use Phase::None for string API) |
| 223 | + PB.registerPipelineParsingCallback( |
| 224 | + [&](StringRef Name, ModulePassManager &PM, |
| 225 | + ArrayRef<PassBuilder::PipelineElement>) { |
| 226 | +#if LLVM_VERSION_MAJOR > 20 |
| 227 | +#define MODULE_LTO_CALLBACK(NAME, INVOKE) \ |
| 228 | + if (checkParametrizedPassName(Name, NAME)) { \ |
| 229 | + auto L = parsePassParameters(parseOptLevelParam, Name, NAME); \ |
| 230 | + if (!L) { \ |
| 231 | + errs() << NAME ": " << toString(L.takeError()) << '\n'; \ |
| 232 | + return false; \ |
| 233 | + } \ |
| 234 | + PB.INVOKE(PM, L.get(), ThinOrFullLTOPhase::None); \ |
| 235 | + return true; \ |
| 236 | + } |
| 237 | + #include "callbacks.inc" |
166 | 238 | #else |
167 | | -#define MODULE_LTO_CALLBACK(NAME, INVOKE) if (Name == NAME) { PB.INVOKE(PM, OptimizationLevel::O2); return true; } |
| 239 | +#define MODULE_LTO_CALLBACK(NAME, INVOKE) \ |
| 240 | + if (checkParametrizedPassName(Name, NAME)) { \ |
| 241 | + auto L = parsePassParameters(parseOptLevelParam, Name, NAME); \ |
| 242 | + if (!L) { \ |
| 243 | + errs() << NAME ": " << toString(L.takeError()) << '\n'; \ |
| 244 | + return false; \ |
| 245 | + } \ |
| 246 | + PB.INVOKE(PM, L.get()); \ |
| 247 | + return true; \ |
| 248 | + } |
| 249 | + #include "callbacks.inc" |
168 | 250 | #endif |
169 | | -#include "callbacks.inc" |
170 | | -#undef MODULE_LTO_CALLBACK |
171 | | - return false; |
172 | | - } |
173 | | - ); |
174 | | - |
175 | | - PB.registerPipelineParsingCallback( |
176 | | - [&](StringRef Name, CGSCCPassManager &CGPM, |
177 | | - ArrayRef<PassBuilder::PipelineElement> InnerPipeline) { |
178 | | -#define CGSCC_CALLBACK(NAME, INVOKE) if (Name == NAME) { PB.INVOKE(CGPM, OptimizationLevel::O2); return true; } |
179 | | -#include "callbacks.inc" |
180 | | -#undef CGSCC_CALLBACK |
181 | | - return false; |
182 | | - } |
183 | | - ); |
184 | | - PB.registerPipelineParsingCallback( |
185 | | - [&](StringRef Name, LoopPassManager &PM, |
186 | | - ArrayRef<PassBuilder::PipelineElement> InnerPipeline) { |
187 | | -#define LOOP_CALLBACK(NAME, INVOKE) if (Name == NAME) { PB.INVOKE(PM, OptimizationLevel::O2); return true; } |
188 | | -#include "callbacks.inc" |
189 | | -#undef LOOP_CALLBACK |
190 | | - return false; |
| 251 | + return false; |
| 252 | + }); |
| 253 | + |
| 254 | + // Function-level callbacks |
| 255 | + PB.registerPipelineParsingCallback( |
| 256 | + [&](StringRef Name, FunctionPassManager &PM, |
| 257 | + ArrayRef<PassBuilder::PipelineElement>) { |
| 258 | +#define FUNCTION_CALLBACK(NAME, INVOKE) \ |
| 259 | + if (checkParametrizedPassName(Name, NAME)) { \ |
| 260 | + auto L = parsePassParameters(parseOptLevelParam, Name, NAME); \ |
| 261 | + if (!L) { \ |
| 262 | + errs() << NAME ": " << toString(L.takeError()) << '\n'; \ |
| 263 | + return false; \ |
| 264 | + } \ |
| 265 | + PB.INVOKE(PM, L.get()); \ |
| 266 | + return true; \ |
| 267 | + } |
| 268 | + #include "callbacks.inc" |
| 269 | + return false; |
| 270 | + }); |
| 271 | + |
| 272 | + // CGSCC-level callbacks |
| 273 | + PB.registerPipelineParsingCallback( |
| 274 | + [&](StringRef Name, CGSCCPassManager &PM, |
| 275 | + ArrayRef<PassBuilder::PipelineElement>) { |
| 276 | +#define CGSCC_CALLBACK(NAME, INVOKE) \ |
| 277 | + if (checkParametrizedPassName(Name, NAME)) { \ |
| 278 | + auto L = parsePassParameters(parseOptLevelParam, Name, NAME); \ |
| 279 | + if (!L) { \ |
| 280 | + errs() << NAME ": " << toString(L.takeError()) << '\n'; \ |
| 281 | + return false; \ |
| 282 | + } \ |
| 283 | + PB.INVOKE(PM, L.get()); \ |
| 284 | + return true; \ |
| 285 | + } |
| 286 | + #include "callbacks.inc" |
| 287 | + return false; |
| 288 | + }); |
| 289 | + |
| 290 | + // Loop-level callbacks |
| 291 | + PB.registerPipelineParsingCallback( |
| 292 | + [&](StringRef Name, LoopPassManager &PM, |
| 293 | + ArrayRef<PassBuilder::PipelineElement>) { |
| 294 | +#define LOOP_CALLBACK(NAME, INVOKE) \ |
| 295 | + if (checkParametrizedPassName(Name, NAME)) { \ |
| 296 | + auto L = parsePassParameters(parseOptLevelParam, Name, NAME); \ |
| 297 | + if (!L) { \ |
| 298 | + errs() << NAME ": " << toString(L.takeError()) << '\n'; \ |
| 299 | + return false; \ |
| 300 | + } \ |
| 301 | + PB.INVOKE(PM, L.get()); \ |
| 302 | + return true; \ |
191 | 303 | } |
192 | | - ); |
| 304 | + #include "callbacks.inc" |
| 305 | + return false; |
| 306 | + }); |
193 | 307 | } |
194 | 308 |
|
195 | 309 | // Vendored API entrypoint |
|
0 commit comments