1 //===- PassRegistry.cpp - Pass Registration Utilities ---------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include <utility> 10 11 #include "mlir/Pass/PassRegistry.h" 12 #include "mlir/Pass/Pass.h" 13 #include "mlir/Pass/PassManager.h" 14 #include "llvm/ADT/DenseMap.h" 15 #include "llvm/Support/Format.h" 16 #include "llvm/Support/ManagedStatic.h" 17 #include "llvm/Support/MemoryBuffer.h" 18 #include "llvm/Support/SourceMgr.h" 19 20 using namespace mlir; 21 using namespace detail; 22 23 /// Static mapping of all of the registered passes. 24 static llvm::ManagedStatic<llvm::StringMap<PassInfo>> passRegistry; 25 26 /// A mapping of the above pass registry entries to the corresponding TypeID 27 /// of the pass that they generate. 28 static llvm::ManagedStatic<llvm::StringMap<TypeID>> passRegistryTypeIDs; 29 30 /// Static mapping of all of the registered pass pipelines. 31 static llvm::ManagedStatic<llvm::StringMap<PassPipelineInfo>> 32 passPipelineRegistry; 33 34 /// Utility to create a default registry function from a pass instance. 35 static PassRegistryFunction 36 buildDefaultRegistryFn(const PassAllocatorFunction &allocator) { 37 return [=](OpPassManager &pm, StringRef options, 38 function_ref<LogicalResult(const Twine &)> errorHandler) { 39 std::unique_ptr<Pass> pass = allocator(); 40 LogicalResult result = pass->initializeOptions(options); 41 if ((pm.getNesting() == OpPassManager::Nesting::Explicit) && 42 pass->getOpName() && *pass->getOpName() != pm.getOpName()) 43 return errorHandler(llvm::Twine("Can't add pass '") + pass->getName() + 44 "' restricted to '" + *pass->getOpName() + 45 "' on a PassManager intended to run on '" + 46 pm.getOpName() + "', did you intend to nest?"); 47 pm.addPass(std::move(pass)); 48 return result; 49 }; 50 } 51 52 /// Utility to print the help string for a specific option. 53 static void printOptionHelp(StringRef arg, StringRef desc, size_t indent, 54 size_t descIndent, bool isTopLevel) { 55 size_t numSpaces = descIndent - indent - 4; 56 llvm::outs().indent(indent) 57 << "--" << llvm::left_justify(arg, numSpaces) << "- " << desc << '\n'; 58 } 59 60 //===----------------------------------------------------------------------===// 61 // PassRegistry 62 //===----------------------------------------------------------------------===// 63 64 /// Print the help information for this pass. This includes the argument, 65 /// description, and any pass options. `descIndent` is the indent that the 66 /// descriptions should be aligned. 67 void PassRegistryEntry::printHelpStr(size_t indent, size_t descIndent) const { 68 printOptionHelp(getPassArgument(), getPassDescription(), indent, descIndent, 69 /*isTopLevel=*/true); 70 // If this entry has options, print the help for those as well. 71 optHandler([=](const PassOptions &options) { 72 options.printHelp(indent, descIndent); 73 }); 74 } 75 76 /// Return the maximum width required when printing the options of this 77 /// entry. 78 size_t PassRegistryEntry::getOptionWidth() const { 79 size_t maxLen = 0; 80 optHandler([&](const PassOptions &options) mutable { 81 maxLen = options.getOptionWidth() + 2; 82 }); 83 return maxLen; 84 } 85 86 //===----------------------------------------------------------------------===// 87 // PassPipelineInfo 88 //===----------------------------------------------------------------------===// 89 90 void mlir::registerPassPipeline( 91 StringRef arg, StringRef description, const PassRegistryFunction &function, 92 std::function<void(function_ref<void(const PassOptions &)>)> optHandler) { 93 PassPipelineInfo pipelineInfo(arg, description, function, 94 std::move(optHandler)); 95 bool inserted = passPipelineRegistry->try_emplace(arg, pipelineInfo).second; 96 assert(inserted && "Pass pipeline registered multiple times"); 97 (void)inserted; 98 } 99 100 //===----------------------------------------------------------------------===// 101 // PassInfo 102 //===----------------------------------------------------------------------===// 103 104 PassInfo::PassInfo(StringRef arg, StringRef description, 105 const PassAllocatorFunction &allocator) 106 : PassRegistryEntry( 107 arg, description, buildDefaultRegistryFn(allocator), 108 // Use a temporary pass to provide an options instance. 109 [=](function_ref<void(const PassOptions &)> optHandler) { 110 optHandler(allocator()->passOptions); 111 }) {} 112 113 void mlir::registerPass(const PassAllocatorFunction &function) { 114 std::unique_ptr<Pass> pass = function(); 115 StringRef arg = pass->getArgument(); 116 if (arg.empty()) 117 llvm::report_fatal_error(llvm::Twine("Trying to register '") + 118 pass->getName() + 119 "' pass that does not override `getArgument()`"); 120 StringRef description = pass->getDescription(); 121 PassInfo passInfo(arg, description, function); 122 passRegistry->try_emplace(arg, passInfo); 123 124 // Verify that the registered pass has the same ID as any registered to this 125 // arg before it. 126 TypeID entryTypeID = pass->getTypeID(); 127 auto it = passRegistryTypeIDs->try_emplace(arg, entryTypeID).first; 128 if (it->second != entryTypeID) 129 llvm::report_fatal_error( 130 "pass allocator creates a different pass than previously " 131 "registered for pass " + 132 arg); 133 } 134 135 /// Returns the pass info for the specified pass argument or null if unknown. 136 const PassInfo *mlir::Pass::lookupPassInfo(StringRef passArg) { 137 auto it = passRegistry->find(passArg); 138 return it == passRegistry->end() ? nullptr : &it->second; 139 } 140 141 //===----------------------------------------------------------------------===// 142 // PassOptions 143 //===----------------------------------------------------------------------===// 144 145 /// Out of line virtual function to provide home for the class. 146 void detail::PassOptions::OptionBase::anchor() {} 147 148 /// Copy the option values from 'other'. 149 void detail::PassOptions::copyOptionValuesFrom(const PassOptions &other) { 150 assert(options.size() == other.options.size()); 151 if (options.empty()) 152 return; 153 for (auto optionsIt : llvm::zip(options, other.options)) 154 std::get<0>(optionsIt)->copyValueFrom(*std::get<1>(optionsIt)); 155 } 156 157 LogicalResult detail::PassOptions::parseFromString(StringRef options) { 158 // TODO: Handle escaping strings. 159 // NOTE: `options` is modified in place to always refer to the unprocessed 160 // part of the string. 161 while (!options.empty()) { 162 size_t spacePos = options.find(' '); 163 StringRef arg = options; 164 if (spacePos != StringRef::npos) { 165 arg = options.substr(0, spacePos); 166 options = options.substr(spacePos + 1); 167 } else { 168 options = StringRef(); 169 } 170 if (arg.empty()) 171 continue; 172 173 // At this point, arg refers to everything that is non-space in options 174 // upto the next space, and options refers to the rest of the string after 175 // that point. 176 177 // Split the individual option on '=' to form key and value. If there is no 178 // '=', then value is `StringRef()`. 179 size_t equalPos = arg.find('='); 180 StringRef key = arg; 181 StringRef value; 182 if (equalPos != StringRef::npos) { 183 key = arg.substr(0, equalPos); 184 value = arg.substr(equalPos + 1); 185 } 186 auto it = OptionsMap.find(key); 187 if (it == OptionsMap.end()) { 188 llvm::errs() << "<Pass-Options-Parser>: no such option " << key << "\n"; 189 return failure(); 190 } 191 if (llvm::cl::ProvidePositionalOption(it->second, value, 0)) 192 return failure(); 193 } 194 195 return success(); 196 } 197 198 /// Print the options held by this struct in a form that can be parsed via 199 /// 'parseFromString'. 200 void detail::PassOptions::print(raw_ostream &os) { 201 // If there are no options, there is nothing left to do. 202 if (OptionsMap.empty()) 203 return; 204 205 // Sort the options to make the ordering deterministic. 206 SmallVector<OptionBase *, 4> orderedOps(options.begin(), options.end()); 207 auto compareOptionArgs = [](OptionBase *const *lhs, OptionBase *const *rhs) { 208 return (*lhs)->getArgStr().compare((*rhs)->getArgStr()); 209 }; 210 llvm::array_pod_sort(orderedOps.begin(), orderedOps.end(), compareOptionArgs); 211 212 // Interleave the options with ' '. 213 os << '{'; 214 llvm::interleave( 215 orderedOps, os, [&](OptionBase *option) { option->print(os); }, " "); 216 os << '}'; 217 } 218 219 /// Print the help string for the options held by this struct. `descIndent` is 220 /// the indent within the stream that the descriptions should be aligned. 221 void detail::PassOptions::printHelp(size_t indent, size_t descIndent) const { 222 // Sort the options to make the ordering deterministic. 223 SmallVector<OptionBase *, 4> orderedOps(options.begin(), options.end()); 224 auto compareOptionArgs = [](OptionBase *const *lhs, OptionBase *const *rhs) { 225 return (*lhs)->getArgStr().compare((*rhs)->getArgStr()); 226 }; 227 llvm::array_pod_sort(orderedOps.begin(), orderedOps.end(), compareOptionArgs); 228 for (OptionBase *option : orderedOps) { 229 // TODO: printOptionInfo assumes a specific indent and will 230 // print options with values with incorrect indentation. We should add 231 // support to llvm::cl::Option for passing in a base indent to use when 232 // printing. 233 llvm::outs().indent(indent); 234 option->getOption()->printOptionInfo(descIndent - indent); 235 } 236 } 237 238 /// Return the maximum width required when printing the help string. 239 size_t detail::PassOptions::getOptionWidth() const { 240 size_t max = 0; 241 for (auto *option : options) 242 max = std::max(max, option->getOption()->getOptionWidth()); 243 return max; 244 } 245 246 //===----------------------------------------------------------------------===// 247 // TextualPassPipeline Parser 248 //===----------------------------------------------------------------------===// 249 250 namespace { 251 /// This class represents a textual description of a pass pipeline. 252 class TextualPipeline { 253 public: 254 /// Try to initialize this pipeline with the given pipeline text. 255 /// `errorStream` is the output stream to emit errors to. 256 LogicalResult initialize(StringRef text, raw_ostream &errorStream); 257 258 /// Add the internal pipeline elements to the provided pass manager. 259 LogicalResult 260 addToPipeline(OpPassManager &pm, 261 function_ref<LogicalResult(const Twine &)> errorHandler) const; 262 263 private: 264 /// A functor used to emit errors found during pipeline handling. The first 265 /// parameter corresponds to the raw location within the pipeline string. This 266 /// should always return failure. 267 using ErrorHandlerT = function_ref<LogicalResult(const char *, Twine)>; 268 269 /// A struct to capture parsed pass pipeline names. 270 /// 271 /// A pipeline is defined as a series of names, each of which may in itself 272 /// recursively contain a nested pipeline. A name is either the name of a pass 273 /// (e.g. "cse") or the name of an operation type (e.g. "builtin.func"). If 274 /// the name is the name of a pass, the InnerPipeline is empty, since passes 275 /// cannot contain inner pipelines. 276 struct PipelineElement { 277 PipelineElement(StringRef name) : name(name), registryEntry(nullptr) {} 278 279 StringRef name; 280 StringRef options; 281 const PassRegistryEntry *registryEntry; 282 std::vector<PipelineElement> innerPipeline; 283 }; 284 285 /// Parse the given pipeline text into the internal pipeline vector. This 286 /// function only parses the structure of the pipeline, and does not resolve 287 /// its elements. 288 LogicalResult parsePipelineText(StringRef text, ErrorHandlerT errorHandler); 289 290 /// Resolve the elements of the pipeline, i.e. connect passes and pipelines to 291 /// the corresponding registry entry. 292 LogicalResult 293 resolvePipelineElements(MutableArrayRef<PipelineElement> elements, 294 ErrorHandlerT errorHandler); 295 296 /// Resolve a single element of the pipeline. 297 LogicalResult resolvePipelineElement(PipelineElement &element, 298 ErrorHandlerT errorHandler); 299 300 /// Add the given pipeline elements to the provided pass manager. 301 LogicalResult 302 addToPipeline(ArrayRef<PipelineElement> elements, OpPassManager &pm, 303 function_ref<LogicalResult(const Twine &)> errorHandler) const; 304 305 std::vector<PipelineElement> pipeline; 306 }; 307 308 } // namespace 309 310 /// Try to initialize this pipeline with the given pipeline text. An option is 311 /// given to enable accurate error reporting. 312 LogicalResult TextualPipeline::initialize(StringRef text, 313 raw_ostream &errorStream) { 314 if (text.empty()) 315 return success(); 316 317 // Build a source manager to use for error reporting. 318 llvm::SourceMgr pipelineMgr; 319 pipelineMgr.AddNewSourceBuffer( 320 llvm::MemoryBuffer::getMemBuffer(text, "MLIR Textual PassPipeline Parser", 321 /*RequiresNullTerminator=*/false), 322 llvm::SMLoc()); 323 auto errorHandler = [&](const char *rawLoc, Twine msg) { 324 pipelineMgr.PrintMessage(errorStream, llvm::SMLoc::getFromPointer(rawLoc), 325 llvm::SourceMgr::DK_Error, msg); 326 return failure(); 327 }; 328 329 // Parse the provided pipeline string. 330 if (failed(parsePipelineText(text, errorHandler))) 331 return failure(); 332 return resolvePipelineElements(pipeline, errorHandler); 333 } 334 335 /// Add the internal pipeline elements to the provided pass manager. 336 LogicalResult TextualPipeline::addToPipeline( 337 OpPassManager &pm, 338 function_ref<LogicalResult(const Twine &)> errorHandler) const { 339 return addToPipeline(pipeline, pm, errorHandler); 340 } 341 342 /// Parse the given pipeline text into the internal pipeline vector. This 343 /// function only parses the structure of the pipeline, and does not resolve 344 /// its elements. 345 LogicalResult TextualPipeline::parsePipelineText(StringRef text, 346 ErrorHandlerT errorHandler) { 347 SmallVector<std::vector<PipelineElement> *, 4> pipelineStack = {&pipeline}; 348 for (;;) { 349 std::vector<PipelineElement> &pipeline = *pipelineStack.back(); 350 size_t pos = text.find_first_of(",(){"); 351 pipeline.emplace_back(/*name=*/text.substr(0, pos).trim()); 352 353 // If we have a single terminating name, we're done. 354 if (pos == StringRef::npos) 355 break; 356 357 text = text.substr(pos); 358 char sep = text[0]; 359 360 // Handle pulling ... from 'pass{...}' out as PipelineElement.options. 361 if (sep == '{') { 362 text = text.substr(1); 363 364 // Skip over everything until the closing '}' and store as options. 365 size_t close = StringRef::npos; 366 for (unsigned i = 0, e = text.size(), braceCount = 1; i < e; ++i) { 367 if (text[i] == '{') { 368 ++braceCount; 369 continue; 370 } 371 if (text[i] == '}' && --braceCount == 0) { 372 close = i; 373 break; 374 } 375 } 376 377 // Check to see if a closing options brace was found. 378 if (close == StringRef::npos) { 379 return errorHandler( 380 /*rawLoc=*/text.data() - 1, 381 "missing closing '}' while processing pass options"); 382 } 383 pipeline.back().options = text.substr(0, close); 384 text = text.substr(close + 1); 385 386 // Skip checking for '(' because nested pipelines cannot have options. 387 } else if (sep == '(') { 388 text = text.substr(1); 389 390 // Push the inner pipeline onto the stack to continue processing. 391 pipelineStack.push_back(&pipeline.back().innerPipeline); 392 continue; 393 } 394 395 // When handling the close parenthesis, we greedily consume them to avoid 396 // empty strings in the pipeline. 397 while (text.consume_front(")")) { 398 // If we try to pop the outer pipeline we have unbalanced parentheses. 399 if (pipelineStack.size() == 1) 400 return errorHandler(/*rawLoc=*/text.data() - 1, 401 "encountered extra closing ')' creating unbalanced " 402 "parentheses while parsing pipeline"); 403 404 pipelineStack.pop_back(); 405 } 406 407 // Check if we've finished parsing. 408 if (text.empty()) 409 break; 410 411 // Otherwise, the end of an inner pipeline always has to be followed by 412 // a comma, and then we can continue. 413 if (!text.consume_front(",")) 414 return errorHandler(text.data(), "expected ',' after parsing pipeline"); 415 } 416 417 // Check for unbalanced parentheses. 418 if (pipelineStack.size() > 1) 419 return errorHandler( 420 text.data(), 421 "encountered unbalanced parentheses while parsing pipeline"); 422 423 assert(pipelineStack.back() == &pipeline && 424 "wrong pipeline at the bottom of the stack"); 425 return success(); 426 } 427 428 /// Resolve the elements of the pipeline, i.e. connect passes and pipelines to 429 /// the corresponding registry entry. 430 LogicalResult TextualPipeline::resolvePipelineElements( 431 MutableArrayRef<PipelineElement> elements, ErrorHandlerT errorHandler) { 432 for (auto &elt : elements) 433 if (failed(resolvePipelineElement(elt, errorHandler))) 434 return failure(); 435 return success(); 436 } 437 438 /// Resolve a single element of the pipeline. 439 LogicalResult 440 TextualPipeline::resolvePipelineElement(PipelineElement &element, 441 ErrorHandlerT errorHandler) { 442 // If the inner pipeline of this element is not empty, this is an operation 443 // pipeline. 444 if (!element.innerPipeline.empty()) 445 return resolvePipelineElements(element.innerPipeline, errorHandler); 446 // Otherwise, this must be a pass or pass pipeline. 447 // Check to see if a pipeline was registered with this name. 448 auto pipelineRegistryIt = passPipelineRegistry->find(element.name); 449 if (pipelineRegistryIt != passPipelineRegistry->end()) { 450 element.registryEntry = &pipelineRegistryIt->second; 451 return success(); 452 } 453 454 // If not, then this must be a specific pass name. 455 if ((element.registryEntry = Pass::lookupPassInfo(element.name))) 456 return success(); 457 458 // Emit an error for the unknown pass. 459 auto *rawLoc = element.name.data(); 460 return errorHandler(rawLoc, "'" + element.name + 461 "' does not refer to a " 462 "registered pass or pass pipeline"); 463 } 464 465 /// Add the given pipeline elements to the provided pass manager. 466 LogicalResult TextualPipeline::addToPipeline( 467 ArrayRef<PipelineElement> elements, OpPassManager &pm, 468 function_ref<LogicalResult(const Twine &)> errorHandler) const { 469 for (auto &elt : elements) { 470 if (elt.registryEntry) { 471 if (failed(elt.registryEntry->addToPipeline(pm, elt.options, 472 errorHandler))) { 473 return errorHandler("failed to add `" + elt.name + "` with options `" + 474 elt.options + "`"); 475 } 476 } else if (failed(addToPipeline(elt.innerPipeline, pm.nest(elt.name), 477 errorHandler))) { 478 return errorHandler("failed to add `" + elt.name + "` with options `" + 479 elt.options + "` to inner pipeline"); 480 } 481 } 482 return success(); 483 } 484 485 /// This function parses the textual representation of a pass pipeline, and adds 486 /// the result to 'pm' on success. This function returns failure if the given 487 /// pipeline was invalid. 'errorStream' is an optional parameter that, if 488 /// non-null, will be used to emit errors found during parsing. 489 LogicalResult mlir::parsePassPipeline(StringRef pipeline, OpPassManager &pm, 490 raw_ostream &errorStream) { 491 TextualPipeline pipelineParser; 492 if (failed(pipelineParser.initialize(pipeline, errorStream))) 493 return failure(); 494 auto errorHandler = [&](Twine msg) { 495 errorStream << msg << "\n"; 496 return failure(); 497 }; 498 if (failed(pipelineParser.addToPipeline(pm, errorHandler))) 499 return failure(); 500 return success(); 501 } 502 503 //===----------------------------------------------------------------------===// 504 // PassNameParser 505 //===----------------------------------------------------------------------===// 506 507 namespace { 508 /// This struct represents the possible data entries in a parsed pass pipeline 509 /// list. 510 struct PassArgData { 511 PassArgData() = default; 512 PassArgData(const PassRegistryEntry *registryEntry) 513 : registryEntry(registryEntry) {} 514 515 /// This field is used when the parsed option corresponds to a registered pass 516 /// or pass pipeline. 517 const PassRegistryEntry *registryEntry{nullptr}; 518 519 /// This field is set when instance specific pass options have been provided 520 /// on the command line. 521 StringRef options; 522 523 /// This field is used when the parsed option corresponds to an explicit 524 /// pipeline. 525 TextualPipeline pipeline; 526 }; 527 } // namespace 528 529 namespace llvm { 530 namespace cl { 531 /// Define a valid OptionValue for the command line pass argument. 532 template <> 533 struct OptionValue<PassArgData> final 534 : OptionValueBase<PassArgData, /*isClass=*/true> { 535 OptionValue(const PassArgData &value) { this->setValue(value); } 536 OptionValue() = default; 537 void anchor() override {} 538 539 bool hasValue() const { return true; } 540 const PassArgData &getValue() const { return value; } 541 void setValue(const PassArgData &value) { this->value = value; } 542 543 PassArgData value; 544 }; 545 } // namespace cl 546 } // namespace llvm 547 548 namespace { 549 550 /// The name for the command line option used for parsing the textual pass 551 /// pipeline. 552 static constexpr StringLiteral passPipelineArg = "pass-pipeline"; 553 554 /// Adds command line option for each registered pass or pass pipeline, as well 555 /// as textual pass pipelines. 556 struct PassNameParser : public llvm::cl::parser<PassArgData> { 557 PassNameParser(llvm::cl::Option &opt) : llvm::cl::parser<PassArgData>(opt) {} 558 559 void initialize(); 560 void printOptionInfo(const llvm::cl::Option &opt, 561 size_t globalWidth) const override; 562 size_t getOptionWidth(const llvm::cl::Option &opt) const override; 563 bool parse(llvm::cl::Option &opt, StringRef argName, StringRef arg, 564 PassArgData &value); 565 566 /// If true, this parser only parses entries that correspond to a concrete 567 /// pass registry entry, and does not add a `pass-pipeline` argument, does not 568 /// include the options for pass entries, and does not include pass pipelines 569 /// entries. 570 bool passNamesOnly = false; 571 }; 572 } // namespace 573 574 void PassNameParser::initialize() { 575 llvm::cl::parser<PassArgData>::initialize(); 576 577 /// Add an entry for the textual pass pipeline option. 578 if (!passNamesOnly) { 579 addLiteralOption(passPipelineArg, PassArgData(), 580 "A textual description of a pass pipeline to run"); 581 } 582 583 /// Add the pass entries. 584 for (const auto &kv : *passRegistry) { 585 addLiteralOption(kv.second.getPassArgument(), &kv.second, 586 kv.second.getPassDescription()); 587 } 588 /// Add the pass pipeline entries. 589 if (!passNamesOnly) { 590 for (const auto &kv : *passPipelineRegistry) { 591 addLiteralOption(kv.second.getPassArgument(), &kv.second, 592 kv.second.getPassDescription()); 593 } 594 } 595 } 596 597 void PassNameParser::printOptionInfo(const llvm::cl::Option &opt, 598 size_t globalWidth) const { 599 // If this parser is just parsing pass names, print a simplified option 600 // string. 601 if (passNamesOnly) { 602 llvm::outs() << " --" << opt.ArgStr << "=<pass-arg>"; 603 opt.printHelpStr(opt.HelpStr, globalWidth, opt.ArgStr.size() + 18); 604 return; 605 } 606 607 // Print the information for the top-level option. 608 if (opt.hasArgStr()) { 609 llvm::outs() << " --" << opt.ArgStr; 610 opt.printHelpStr(opt.HelpStr, globalWidth, opt.ArgStr.size() + 7); 611 } else { 612 llvm::outs() << " " << opt.HelpStr << '\n'; 613 } 614 615 // Print the top-level pipeline argument. 616 printOptionHelp(passPipelineArg, 617 "A textual description of a pass pipeline to run", 618 /*indent=*/4, globalWidth, /*isTopLevel=*/!opt.hasArgStr()); 619 620 // Functor used to print the ordered entries of a registration map. 621 auto printOrderedEntries = [&](StringRef header, auto &map) { 622 llvm::SmallVector<PassRegistryEntry *, 32> orderedEntries; 623 for (auto &kv : map) 624 orderedEntries.push_back(&kv.second); 625 llvm::array_pod_sort( 626 orderedEntries.begin(), orderedEntries.end(), 627 [](PassRegistryEntry *const *lhs, PassRegistryEntry *const *rhs) { 628 return (*lhs)->getPassArgument().compare((*rhs)->getPassArgument()); 629 }); 630 631 llvm::outs().indent(4) << header << ":\n"; 632 for (PassRegistryEntry *entry : orderedEntries) 633 entry->printHelpStr(/*indent=*/6, globalWidth); 634 }; 635 636 // Print the available passes. 637 printOrderedEntries("Passes", *passRegistry); 638 639 // Print the available pass pipelines. 640 if (!passPipelineRegistry->empty()) 641 printOrderedEntries("Pass Pipelines", *passPipelineRegistry); 642 } 643 644 size_t PassNameParser::getOptionWidth(const llvm::cl::Option &opt) const { 645 size_t maxWidth = llvm::cl::parser<PassArgData>::getOptionWidth(opt) + 2; 646 647 // Check for any wider pass or pipeline options. 648 for (auto &entry : *passRegistry) 649 maxWidth = std::max(maxWidth, entry.second.getOptionWidth() + 4); 650 for (auto &entry : *passPipelineRegistry) 651 maxWidth = std::max(maxWidth, entry.second.getOptionWidth() + 4); 652 return maxWidth; 653 } 654 655 bool PassNameParser::parse(llvm::cl::Option &opt, StringRef argName, 656 StringRef arg, PassArgData &value) { 657 // Handle the pipeline option explicitly. 658 if (argName == passPipelineArg) 659 return failed(value.pipeline.initialize(arg, llvm::errs())); 660 661 // Otherwise, default to the base for handling. 662 if (llvm::cl::parser<PassArgData>::parse(opt, argName, arg, value)) 663 return true; 664 value.options = arg; 665 return false; 666 } 667 668 //===----------------------------------------------------------------------===// 669 // PassPipelineCLParser 670 //===----------------------------------------------------------------------===// 671 672 namespace mlir { 673 namespace detail { 674 struct PassPipelineCLParserImpl { 675 PassPipelineCLParserImpl(StringRef arg, StringRef description, 676 bool passNamesOnly) 677 : passList(arg, llvm::cl::desc(description)) { 678 passList.getParser().passNamesOnly = passNamesOnly; 679 passList.setValueExpectedFlag(llvm::cl::ValueExpected::ValueOptional); 680 } 681 682 /// Returns true if the given pass registry entry was registered at the 683 /// top-level of the parser, i.e. not within an explicit textual pipeline. 684 bool contains(const PassRegistryEntry *entry) const { 685 return llvm::any_of(passList, [&](const PassArgData &data) { 686 return data.registryEntry == entry; 687 }); 688 } 689 690 /// The set of passes and pass pipelines to run. 691 llvm::cl::list<PassArgData, bool, PassNameParser> passList; 692 }; 693 } // namespace detail 694 } // namespace mlir 695 696 /// Construct a pass pipeline parser with the given command line description. 697 PassPipelineCLParser::PassPipelineCLParser(StringRef arg, StringRef description) 698 : impl(std::make_unique<detail::PassPipelineCLParserImpl>( 699 arg, description, /*passNamesOnly=*/false)) {} 700 PassPipelineCLParser::~PassPipelineCLParser() = default; 701 702 /// Returns true if this parser contains any valid options to add. 703 bool PassPipelineCLParser::hasAnyOccurrences() const { 704 return impl->passList.getNumOccurrences() != 0; 705 } 706 707 /// Returns true if the given pass registry entry was registered at the 708 /// top-level of the parser, i.e. not within an explicit textual pipeline. 709 bool PassPipelineCLParser::contains(const PassRegistryEntry *entry) const { 710 return impl->contains(entry); 711 } 712 713 /// Adds the passes defined by this parser entry to the given pass manager. 714 LogicalResult PassPipelineCLParser::addToPipeline( 715 OpPassManager &pm, 716 function_ref<LogicalResult(const Twine &)> errorHandler) const { 717 for (auto &passIt : impl->passList) { 718 if (passIt.registryEntry) { 719 if (failed(passIt.registryEntry->addToPipeline(pm, passIt.options, 720 errorHandler))) 721 return failure(); 722 } else { 723 OpPassManager::Nesting nesting = pm.getNesting(); 724 pm.setNesting(OpPassManager::Nesting::Explicit); 725 LogicalResult status = passIt.pipeline.addToPipeline(pm, errorHandler); 726 pm.setNesting(nesting); 727 if (failed(status)) 728 return failure(); 729 } 730 } 731 return success(); 732 } 733 734 //===----------------------------------------------------------------------===// 735 // PassNameCLParser 736 737 /// Construct a pass pipeline parser with the given command line description. 738 PassNameCLParser::PassNameCLParser(StringRef arg, StringRef description) 739 : impl(std::make_unique<detail::PassPipelineCLParserImpl>( 740 arg, description, /*passNamesOnly=*/true)) { 741 impl->passList.setMiscFlag(llvm::cl::CommaSeparated); 742 } 743 PassNameCLParser::~PassNameCLParser() = default; 744 745 /// Returns true if this parser contains any valid options to add. 746 bool PassNameCLParser::hasAnyOccurrences() const { 747 return impl->passList.getNumOccurrences() != 0; 748 } 749 750 /// Returns true if the given pass registry entry was registered at the 751 /// top-level of the parser, i.e. not within an explicit textual pipeline. 752 bool PassNameCLParser::contains(const PassRegistryEntry *entry) const { 753 return impl->contains(entry); 754 } 755