13 #include "llvm/ADT/DenseMap.h"
14 #include "llvm/ADT/ScopeExit.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"
24 using namespace detail;
27 static llvm::ManagedStatic<llvm::StringMap<PassInfo>>
passRegistry;
34 static llvm::ManagedStatic<llvm::StringMap<PassPipelineInfo>>
42 std::unique_ptr<Pass> pass = allocator();
45 std::optional<StringRef> pmOpName = pm.
getOpName();
46 std::optional<StringRef> passOpName = pass->getOpName();
48 passOpName && *pmOpName != *passOpName) {
49 return errorHandler(llvm::Twine(
"Can't add pass '") + pass->getName() +
50 "' restricted to '" + *pass->getOpName() +
51 "' on a PassManager intended to run on '" +
61 size_t descIndent,
bool isTopLevel) {
62 size_t numSpaces = descIndent - indent - 4;
63 llvm::outs().indent(indent)
64 <<
"--" << llvm::left_justify(arg, numSpaces) <<
"- " << desc <<
'\n';
75 printOptionHelp(getPassArgument(), getPassDescription(), indent, descIndent,
79 options.printHelp(indent, descIndent);
88 maxLen =
options.getOptionWidth() + 2;
101 std::move(optHandler));
105 report_fatal_error(
"Pass pipeline " + arg +
" registered multiple times");
120 optHandler(allocator()->passOptions);
124 std::unique_ptr<Pass> pass =
function();
125 StringRef arg = pass->getArgument();
127 llvm::report_fatal_error(llvm::Twine(
"Trying to register '") +
129 "' pass that does not override `getArgument()`");
130 StringRef description = pass->getDescription();
131 PassInfo passInfo(arg, description,
function);
136 TypeID entryTypeID = pass->getTypeID();
138 if (it->second != entryTypeID)
139 llvm::report_fatal_error(
140 "pass allocator creates a different pass than previously "
141 "registered for pass " +
148 return it ==
passRegistry->end() ? nullptr : &it->second;
163 llvm::cl::Option &opt, StringRef argName, StringRef optionStr,
167 llvm::unique_function<size_t(StringRef,
size_t,
char)> findChar =
168 [&](StringRef str,
size_t index,
char c) ->
size_t {
169 for (
size_t i = index, e = str.size(); i < e; ++i) {
174 i = findChar(str, i + 1,
'}');
175 else if (str[i] ==
'(')
176 i = findChar(str, i + 1,
')');
177 else if (str[i] ==
'[')
178 i = findChar(str, i + 1,
']');
179 else if (str[i] ==
'\"')
180 i = str.find_first_of(
'\"', i + 1);
181 else if (str[i] ==
'\'')
182 i = str.find_first_of(
'\'', i + 1);
184 return StringRef::npos;
187 size_t nextElePos = findChar(optionStr, 0,
',');
188 while (nextElePos != StringRef::npos) {
190 if (
failed(elementParseFn(optionStr.substr(0, nextElePos))))
193 optionStr = optionStr.substr(nextElePos + 1);
194 nextElePos = findChar(optionStr, 0,
',');
196 return elementParseFn(optionStr.substr(0, nextElePos));
200 void detail::PassOptions::OptionBase::anchor() {}
204 assert(options.size() == other.options.size());
207 for (
auto optionsIt : llvm::zip(options, other.options))
208 std::get<0>(optionsIt)->copyValueFrom(*std::get<1>(optionsIt));
214 static std::tuple<StringRef, StringRef, StringRef>
218 auto extractArgAndUpdateOptions = [&](
size_t argSize) {
219 StringRef str =
options.take_front(argSize).trim();
225 auto tryProcessPunct = [&](
size_t ¤tPos,
char punct) {
226 if (
options[currentPos] != punct)
228 size_t nextIt =
options.find_first_of(punct, currentPos + 1);
229 if (nextIt != StringRef::npos)
236 for (
size_t argEndIt = 0, optionsE =
options.size();; ++argEndIt) {
238 if (argEndIt == optionsE ||
options[argEndIt] ==
' ') {
239 argName = extractArgAndUpdateOptions(argEndIt);
240 return std::make_tuple(argName, StringRef(),
options);
244 if (
options[argEndIt] ==
'=') {
245 argName = extractArgAndUpdateOptions(argEndIt);
252 for (
size_t argEndIt = 0, optionsE =
options.size();; ++argEndIt) {
254 if (argEndIt == optionsE ||
options[argEndIt] ==
' ') {
255 StringRef value = extractArgAndUpdateOptions(argEndIt);
256 return std::make_tuple(argName, value,
options);
261 if (tryProcessPunct(argEndIt,
'\'') || tryProcessPunct(argEndIt,
'"'))
266 size_t braceCount = 1;
267 for (++argEndIt; argEndIt != optionsE; ++argEndIt) {
269 if (tryProcessPunct(argEndIt,
'\'') || tryProcessPunct(argEndIt,
'"'))
273 else if (
options[argEndIt] ==
'}' && --braceCount == 0)
280 llvm_unreachable(
"unexpected control flow in pass option parsing");
284 raw_ostream &errorStream) {
288 StringRef key, value;
293 auto it = OptionsMap.find(key);
294 if (it == OptionsMap.end()) {
295 errorStream <<
"<Pass-Options-Parser>: no such option " << key <<
"\n";
298 if (llvm::cl::ProvidePositionalOption(it->second, value, 0))
309 if (OptionsMap.empty())
314 auto compareOptionArgs = [](OptionBase *
const *lhs, OptionBase *
const *rhs) {
315 return (*lhs)->getArgStr().compare((*rhs)->getArgStr());
317 llvm::array_pod_sort(orderedOps.begin(), orderedOps.end(), compareOptionArgs);
322 orderedOps, os, [&](OptionBase *option) { option->print(os); },
" ");
331 auto compareOptionArgs = [](OptionBase *
const *lhs, OptionBase *
const *rhs) {
332 return (*lhs)->getArgStr().compare((*rhs)->getArgStr());
334 llvm::array_pod_sort(orderedOps.begin(), orderedOps.end(), compareOptionArgs);
335 for (OptionBase *option : orderedOps) {
340 llvm::outs().indent(indent);
341 option->getOption()->printOptionInfo(descIndent - indent);
360 llvm::cl::OptionValue<OpPassManager>::OptionValue() =
default;
361 llvm::cl::OptionValue<OpPassManager>::OptionValue(
365 llvm::cl::OptionValue<OpPassManager>::OptionValue(
370 llvm::cl::OptionValue<OpPassManager> &
371 llvm::cl::OptionValue<OpPassManager>::operator=(
377 llvm::cl::OptionValue<OpPassManager>::~OptionValue<OpPassManager>() =
default;
379 void llvm::cl::OptionValue<OpPassManager>::setValue(
384 value = std::make_unique<mlir::OpPassManager>(newValue);
386 void llvm::cl::OptionValue<OpPassManager>::setValue(StringRef pipelineStr) {
388 assert(
succeeded(pipeline) &&
"invalid pass pipeline");
394 std::string lhsStr, rhsStr;
396 raw_string_ostream lhsStream(lhsStr);
397 value->printAsTextualPipeline(lhsStream);
399 raw_string_ostream rhsStream(rhsStr);
404 return lhsStr == rhsStr;
407 void llvm::cl::OptionValue<OpPassManager>::anchor() {}
419 ParsedPassManager &value) {
423 value.value = std::make_unique<OpPassManager>(std::move(*pipeline));
433 const Option &opt,
OpPassManager &pm,
const OptVal &defaultValue,
434 size_t globalWidth)
const {
435 printOptionName(opt, globalWidth);
439 if (defaultValue.hasValue()) {
440 outs().indent(2) <<
" (default: ";
441 defaultValue.getValue().printAsTextualPipeline(outs());
452 ParsedPassManager &&) =
default;
462 class TextualPipeline {
466 LogicalResult initialize(StringRef text, raw_ostream &errorStream);
486 struct PipelineElement {
487 PipelineElement(StringRef name) : name(name) {}
492 std::vector<PipelineElement> innerPipeline;
498 LogicalResult parsePipelineText(StringRef text, ErrorHandlerT errorHandler);
504 ErrorHandlerT errorHandler);
507 LogicalResult resolvePipelineElement(PipelineElement &element,
508 ErrorHandlerT errorHandler);
515 std::vector<PipelineElement> pipeline;
523 raw_ostream &errorStream) {
528 llvm::SourceMgr pipelineMgr;
529 pipelineMgr.AddNewSourceBuffer(
530 llvm::MemoryBuffer::getMemBuffer(text,
"MLIR Textual PassPipeline Parser",
533 auto errorHandler = [&](
const char *rawLoc, Twine msg) {
534 pipelineMgr.PrintMessage(errorStream, SMLoc::getFromPointer(rawLoc),
535 llvm::SourceMgr::DK_Error, msg);
540 if (
failed(parsePipelineText(text, errorHandler)))
542 return resolvePipelineElements(pipeline, errorHandler);
554 auto restore = llvm::make_scope_exit([&]() { pm.
setNesting(nesting); });
556 return addToPipeline(pipeline, pm, errorHandler);
562 LogicalResult TextualPipeline::parsePipelineText(StringRef text,
563 ErrorHandlerT errorHandler) {
566 std::vector<PipelineElement> &pipeline = *pipelineStack.back();
567 size_t pos = text.find_first_of(
",(){");
568 pipeline.emplace_back(text.substr(0, pos).trim());
571 if (pos == StringRef::npos)
574 text = text.substr(pos);
579 text = text.substr(1);
582 size_t close = StringRef::npos;
583 for (
unsigned i = 0, e = text.size(), braceCount = 1; i < e; ++i) {
584 if (text[i] ==
'{') {
588 if (text[i] ==
'}' && --braceCount == 0) {
595 if (close == StringRef::npos) {
598 "missing closing '}' while processing pass options");
600 pipeline.back().options = text.substr(0, close);
601 text = text.substr(close + 1);
607 }
else if (sep ==
'(') {
608 text = text.substr(1);
611 pipelineStack.push_back(&pipeline.back().innerPipeline);
617 while (text.consume_front(
")")) {
619 if (pipelineStack.size() == 1)
620 return errorHandler(text.data() - 1,
621 "encountered extra closing ')' creating unbalanced "
622 "parentheses while parsing pipeline");
624 pipelineStack.pop_back();
635 if (!text.consume_front(
","))
636 return errorHandler(text.data(),
"expected ',' after parsing pipeline");
640 if (pipelineStack.size() > 1)
643 "encountered unbalanced parentheses while parsing pipeline");
645 assert(pipelineStack.back() == &pipeline &&
646 "wrong pipeline at the bottom of the stack");
654 for (
auto &elt : elements)
655 if (
failed(resolvePipelineElement(elt, errorHandler)))
662 TextualPipeline::resolvePipelineElement(PipelineElement &element,
663 ErrorHandlerT errorHandler) {
666 if (!element.innerPipeline.empty())
667 return resolvePipelineElements(element.innerPipeline, errorHandler);
679 auto *rawLoc = element.name.data();
680 return errorHandler(rawLoc,
"'" + element.name +
681 "' does not refer to a "
682 "registered pass or pass pipeline");
689 for (
auto &elt : elements) {
690 if (elt.registryEntry) {
691 if (
failed(elt.registryEntry->addToPipeline(pm, elt.options,
693 return errorHandler(
"failed to add `" + elt.name +
"` with options `" +
696 }
else if (
failed(addToPipeline(elt.innerPipeline, pm.
nest(elt.name),
698 return errorHandler(
"failed to add `" + elt.name +
"` with options `" +
699 elt.options +
"` to inner pipeline");
706 raw_ostream &errorStream) {
707 TextualPipeline pipelineParser;
708 if (
failed(pipelineParser.initialize(pipeline, errorStream)))
710 auto errorHandler = [&](Twine msg) {
711 errorStream << msg <<
"\n";
714 if (
failed(pipelineParser.addToPipeline(pm, errorHandler)))
720 raw_ostream &errorStream) {
721 pipeline = pipeline.trim();
723 size_t pipelineStart = pipeline.find_first_of(
'(');
724 if (pipelineStart == 0 || pipelineStart == StringRef::npos ||
725 !pipeline.consume_back(
")")) {
726 errorStream <<
"expected pass pipeline to be wrapped with the anchor "
727 "operation type, e.g. 'builtin.module(...)'";
731 StringRef opName = pipeline.take_front(pipelineStart).rtrim();
747 PassArgData() =
default;
749 : registryEntry(registryEntry) {}
772 const PassArgData &
getValue()
const {
return value; }
773 void setValue(
const PassArgData &value) { this->value = value; }
784 #define PASS_PIPELINE_ARG "pass-pipeline"
792 void printOptionInfo(
const llvm::cl::Option &opt,
793 size_t globalWidth)
const override;
794 size_t getOptionWidth(
const llvm::cl::Option &opt)
const override;
795 bool parse(llvm::cl::Option &opt, StringRef argName, StringRef arg,
801 bool passNamesOnly =
false;
805 void PassNameParser::initialize() {
810 addLiteralOption(kv.second.getPassArgument(), &kv.second,
811 kv.second.getPassDescription());
814 if (!passNamesOnly) {
816 addLiteralOption(kv.second.getPassArgument(), &kv.second,
817 kv.second.getPassDescription());
822 void PassNameParser::printOptionInfo(
const llvm::cl::Option &opt,
823 size_t globalWidth)
const {
827 llvm::outs() <<
" --" << opt.ArgStr <<
"=<pass-arg>";
828 opt.printHelpStr(opt.HelpStr, globalWidth, opt.ArgStr.size() + 18);
833 if (opt.hasArgStr()) {
834 llvm::outs() <<
" --" << opt.ArgStr;
835 opt.printHelpStr(opt.HelpStr, globalWidth, opt.ArgStr.size() + 7);
837 llvm::outs() <<
" " << opt.HelpStr <<
'\n';
841 auto printOrderedEntries = [&](StringRef header,
auto &map) {
844 orderedEntries.push_back(&kv.second);
845 llvm::array_pod_sort(
846 orderedEntries.begin(), orderedEntries.end(),
848 return (*lhs)->getPassArgument().compare((*rhs)->getPassArgument());
851 llvm::outs().indent(4) << header <<
":\n";
853 entry->printHelpStr(6, globalWidth);
864 size_t PassNameParser::getOptionWidth(
const llvm::cl::Option &opt)
const {
869 maxWidth =
std::max(maxWidth, entry.second.getOptionWidth() + 4);
871 maxWidth =
std::max(maxWidth, entry.second.getOptionWidth() + 4);
876 StringRef arg, PassArgData &value) {
892 : passList(arg,
llvm::cl::desc(description)) {
893 passList.getParser().passNamesOnly = passNamesOnly;
894 passList.setValueExpectedFlag(llvm::cl::ValueExpected::ValueOptional);
900 return llvm::any_of(passList, [&](
const PassArgData &data) {
901 return data.registryEntry == entry;
906 llvm::cl::list<PassArgData, bool, PassNameParser>
passList;
914 arg, description, false)),
917 llvm::cl::desc(
"Textual description of the pass pipeline to run")) {}
922 passPipelineAlias.emplace(alias,
924 llvm::cl::aliasopt(passPipeline));
931 return passPipeline.getNumOccurrences() != 0 ||
932 impl->passList.getNumOccurrences() != 0;
938 return impl->contains(entry);
945 if (passPipeline.getNumOccurrences()) {
946 if (
impl->passList.getNumOccurrences())
949 "' option can't be used with individual pass options");
951 llvm::raw_string_ostream os(errMsg);
954 return errorHandler(errMsg);
955 pm = std::move(*parsed);
959 for (
auto &passIt :
impl->passList) {
960 if (
failed(passIt.registryEntry->addToPipeline(pm, passIt.options,
973 arg, description, true)) {
974 impl->passList.setMiscFlag(llvm::cl::CommaSeparated);
980 return impl->passList.getNumOccurrences() != 0;
986 return impl->contains(entry);
static llvm::ManagedStatic< PassManagerOptions > options
static llvm::ManagedStatic< llvm::StringMap< PassPipelineInfo > > passPipelineRegistry
Static mapping of all of the registered pass pipelines.
#define PASS_PIPELINE_ARG
The name for the command line option used for parsing the textual pass pipeline.
static llvm::ManagedStatic< llvm::StringMap< PassInfo > > passRegistry
Static mapping of all of the registered passes.
static PassRegistryFunction buildDefaultRegistryFn(const PassAllocatorFunction &allocator)
Utility to create a default registry function from a pass instance.
static void printOptionHelp(StringRef arg, StringRef desc, size_t indent, size_t descIndent, bool isTopLevel)
Utility to print the help string for a specific option.
static llvm::ManagedStatic< llvm::StringMap< TypeID > > passRegistryTypeIDs
A mapping of the above pass registry entries to the corresponding TypeID of the pass that they genera...
static std::tuple< StringRef, StringRef, StringRef > parseNextArg(StringRef options)
Parse in the next argument from the given options string.
static Value max(ImplicitLocOpBuilder &builder, Value value, Value bound)
static void print(spirv::VerCapExtAttr triple, DialectAsmPrinter &printer)
This class provides support for representing a failure result, or a valid value of type T.
This class represents a pass manager that runs passes on either a specific operation type,...
void printAsTextualPipeline(raw_ostream &os) const
Prints out the passes of the pass manager as the textual representation of pipelines.
std::optional< OperationName > getOpName(MLIRContext &context) const
Return the operation name that this pass manager operates on, or std::nullopt if this is an op-agnost...
void setNesting(Nesting nesting)
Enable or disable the implicit nesting on this particular PassManager.
void addPass(std::unique_ptr< Pass > pass)
Add the given pass to this pass manager.
Nesting getNesting()
Return the current nesting mode.
Nesting
This enum represents the nesting behavior of the pass manager.
@ Explicit
Explicit nesting behavior.
StringRef getOpAnchorName() const
Return the name used to anchor this pass manager.
OpPassManager & nest(OperationName nestedName)
Nest a new operation pass manager for the given operation kind under this pass manager.
A structure to represent the information for a derived pass class.
static const PassInfo * lookup(StringRef passArg)
Returns the pass info for the specified pass class or null if unknown.
PassInfo(StringRef arg, StringRef description, const PassAllocatorFunction &allocator)
PassInfo constructor should not be invoked directly, instead use PassRegistration or registerPass.
bool hasAnyOccurrences() const
Returns true if this parser contains any valid options to add.
PassNameCLParser(StringRef arg, StringRef description)
Construct a parser with the given command line description.
bool contains(const PassRegistryEntry *entry) const
Returns true if the given pass registry entry was registered at the top-level of the parser,...
This class implements a command-line parser for MLIR passes.
bool hasAnyOccurrences() const
Returns true if this parser contains any valid options to add.
PassPipelineCLParser(StringRef arg, StringRef description)
Construct a pass pipeline parser with the given command line description.
LogicalResult addToPipeline(OpPassManager &pm, function_ref< LogicalResult(const Twine &)> errorHandler) const
Adds the passes defined by this parser entry to the given pass manager.
bool contains(const PassRegistryEntry *entry) const
Returns true if the given pass registry entry was registered at the top-level of the parser,...
A structure to represent the information of a registered pass pipeline.
static const PassPipelineInfo * lookup(StringRef pipelineArg)
Returns the pass pipeline info for the specified pass pipeline or null if unknown.
Structure to group information about a passes and pass pipelines (argument to invoke via mlir-opt,...
void printHelpStr(size_t indent, size_t descIndent) const
Print the help information for this pass.
size_t getOptionWidth() const
Return the maximum width required when printing the options of this entry.
This class provides an efficient unique identifier for a specific C++ type.
Base container class and manager for all pass options.
size_t getOptionWidth() const
Return the maximum width required when printing the help string.
void printHelp(size_t indent, size_t descIndent) const
Print the help string for the options held by this struct.
LogicalResult parseFromString(StringRef options, raw_ostream &errorStream=llvm::errs())
Parse options out as key=value pairs that can then be handed off to the llvm::cl command line passing...
void copyOptionValuesFrom(const PassOptions &other)
Copy the option values from 'other' into 'this', where 'other' has the same options as 'this'.
void print(raw_ostream &os)
Print the options held by this struct in a form that can be parsed via 'parseFromString'.
Include the generated interface declarations.
LogicalResult parseCommaSeparatedList(llvm::cl::Option &opt, StringRef argName, StringRef optionStr, function_ref< LogicalResult(StringRef)> elementParseFn)
Parse a string containing a list of comma-delimited elements, invoking the given parser for each sub-...
int compare(const Fraction &x, const Fraction &y)
Three-way comparison between two fractions.
QueryRef parse(llvm::StringRef line, const QuerySession &qs)
Include the generated interface declarations.
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
std::function< std::unique_ptr< Pass >()> PassAllocatorFunction
bool succeeded(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a success value.
void registerPass(const PassAllocatorFunction &function)
Register a specific dialect pass allocator function with the system, typically used through the PassR...
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
void registerPassPipeline(StringRef arg, StringRef description, const PassRegistryFunction &function, std::function< void(function_ref< void(const detail::PassOptions &)>)> optHandler)
Register a specific dialect pipeline registry function with the system, typically used through the Pa...
LogicalResult parsePassPipeline(StringRef pipeline, OpPassManager &pm, raw_ostream &errorStream=llvm::errs())
Parse the textual representation of a pass pipeline, adding the result to 'pm' on success.
bool failed(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value.
std::function< LogicalResult(OpPassManager &, StringRef options, function_ref< LogicalResult(const Twine &)> errorHandler)> PassRegistryFunction
A registry function that adds passes to the given pass manager.
Define a valid OptionValue for the command line pass argument.
OptionValue(const PassArgData &value)
void setValue(const PassArgData &value)
const PassArgData & getValue() const
mlir::OpPassManager & getValue() const
Returns the current value of the option.
bool hasValue() const
Returns if the current option has a value.
This class represents an efficient way to signal success or failure.
llvm::cl::list< PassArgData, bool, PassNameParser > passList
The set of passes and pass pipelines to run.
PassPipelineCLParserImpl(StringRef arg, StringRef description, bool passNamesOnly)
bool contains(const PassRegistryEntry *entry) const
Returns true if the given pass registry entry was registered at the top-level of the parser,...