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");
287 StringRef key, value;
292 auto it = OptionsMap.find(key);
293 if (it == OptionsMap.end()) {
294 llvm::errs() <<
"<Pass-Options-Parser>: no such option " << key <<
"\n";
297 if (llvm::cl::ProvidePositionalOption(it->second, value, 0))
308 if (OptionsMap.empty())
313 auto compareOptionArgs = [](OptionBase *
const *lhs, OptionBase *
const *rhs) {
314 return (*lhs)->getArgStr().compare((*rhs)->getArgStr());
316 llvm::array_pod_sort(orderedOps.begin(), orderedOps.end(), compareOptionArgs);
321 orderedOps, os, [&](OptionBase *option) { option->print(os); },
" ");
330 auto compareOptionArgs = [](OptionBase *
const *lhs, OptionBase *
const *rhs) {
331 return (*lhs)->getArgStr().compare((*rhs)->getArgStr());
333 llvm::array_pod_sort(orderedOps.begin(), orderedOps.end(), compareOptionArgs);
334 for (OptionBase *option : orderedOps) {
339 llvm::outs().indent(indent);
340 option->getOption()->printOptionInfo(descIndent - indent);
359 llvm::cl::OptionValue<OpPassManager>::OptionValue() =
default;
360 llvm::cl::OptionValue<OpPassManager>::OptionValue(
364 llvm::cl::OptionValue<OpPassManager>::OptionValue(
369 llvm::cl::OptionValue<OpPassManager> &
370 llvm::cl::OptionValue<OpPassManager>::operator=(
376 llvm::cl::OptionValue<OpPassManager>::~OptionValue<OpPassManager>() =
default;
378 void llvm::cl::OptionValue<OpPassManager>::setValue(
383 value = std::make_unique<mlir::OpPassManager>(newValue);
385 void llvm::cl::OptionValue<OpPassManager>::setValue(StringRef pipelineStr) {
387 assert(
succeeded(pipeline) &&
"invalid pass pipeline");
393 std::string lhsStr, rhsStr;
395 raw_string_ostream lhsStream(lhsStr);
396 value->printAsTextualPipeline(lhsStream);
398 raw_string_ostream rhsStream(rhsStr);
403 return lhsStr == rhsStr;
406 void llvm::cl::OptionValue<OpPassManager>::anchor() {}
418 ParsedPassManager &value) {
422 value.value = std::make_unique<OpPassManager>(std::move(*pipeline));
432 const Option &opt,
OpPassManager &pm,
const OptVal &defaultValue,
433 size_t globalWidth)
const {
434 printOptionName(opt, globalWidth);
438 if (defaultValue.hasValue()) {
439 outs().indent(2) <<
" (default: ";
440 defaultValue.getValue().printAsTextualPipeline(outs());
451 ParsedPassManager &&) =
default;
461 class TextualPipeline {
465 LogicalResult initialize(StringRef text, raw_ostream &errorStream);
485 struct PipelineElement {
486 PipelineElement(StringRef name) : name(name) {}
491 std::vector<PipelineElement> innerPipeline;
497 LogicalResult parsePipelineText(StringRef text, ErrorHandlerT errorHandler);
503 ErrorHandlerT errorHandler);
506 LogicalResult resolvePipelineElement(PipelineElement &element,
507 ErrorHandlerT errorHandler);
514 std::vector<PipelineElement> pipeline;
522 raw_ostream &errorStream) {
527 llvm::SourceMgr pipelineMgr;
528 pipelineMgr.AddNewSourceBuffer(
529 llvm::MemoryBuffer::getMemBuffer(text,
"MLIR Textual PassPipeline Parser",
532 auto errorHandler = [&](
const char *rawLoc, Twine msg) {
533 pipelineMgr.PrintMessage(errorStream, SMLoc::getFromPointer(rawLoc),
534 llvm::SourceMgr::DK_Error, msg);
539 if (
failed(parsePipelineText(text, errorHandler)))
541 return resolvePipelineElements(pipeline, errorHandler);
553 auto restore = llvm::make_scope_exit([&]() { pm.
setNesting(nesting); });
555 return addToPipeline(pipeline, pm, errorHandler);
561 LogicalResult TextualPipeline::parsePipelineText(StringRef text,
562 ErrorHandlerT errorHandler) {
565 std::vector<PipelineElement> &pipeline = *pipelineStack.back();
566 size_t pos = text.find_first_of(
",(){");
567 pipeline.emplace_back(text.substr(0, pos).trim());
570 if (pos == StringRef::npos)
573 text = text.substr(pos);
578 text = text.substr(1);
581 size_t close = StringRef::npos;
582 for (
unsigned i = 0, e = text.size(), braceCount = 1; i < e; ++i) {
583 if (text[i] ==
'{') {
587 if (text[i] ==
'}' && --braceCount == 0) {
594 if (close == StringRef::npos) {
597 "missing closing '}' while processing pass options");
599 pipeline.back().options = text.substr(0, close);
600 text = text.substr(close + 1);
606 }
else if (sep ==
'(') {
607 text = text.substr(1);
610 pipelineStack.push_back(&pipeline.back().innerPipeline);
616 while (text.consume_front(
")")) {
618 if (pipelineStack.size() == 1)
619 return errorHandler(text.data() - 1,
620 "encountered extra closing ')' creating unbalanced "
621 "parentheses while parsing pipeline");
623 pipelineStack.pop_back();
634 if (!text.consume_front(
","))
635 return errorHandler(text.data(),
"expected ',' after parsing pipeline");
639 if (pipelineStack.size() > 1)
642 "encountered unbalanced parentheses while parsing pipeline");
644 assert(pipelineStack.back() == &pipeline &&
645 "wrong pipeline at the bottom of the stack");
653 for (
auto &elt : elements)
654 if (
failed(resolvePipelineElement(elt, errorHandler)))
661 TextualPipeline::resolvePipelineElement(PipelineElement &element,
662 ErrorHandlerT errorHandler) {
665 if (!element.innerPipeline.empty())
666 return resolvePipelineElements(element.innerPipeline, errorHandler);
678 auto *rawLoc = element.name.data();
679 return errorHandler(rawLoc,
"'" + element.name +
680 "' does not refer to a "
681 "registered pass or pass pipeline");
688 for (
auto &elt : elements) {
689 if (elt.registryEntry) {
690 if (
failed(elt.registryEntry->addToPipeline(pm, elt.options,
692 return errorHandler(
"failed to add `" + elt.name +
"` with options `" +
695 }
else if (
failed(addToPipeline(elt.innerPipeline, pm.
nest(elt.name),
697 return errorHandler(
"failed to add `" + elt.name +
"` with options `" +
698 elt.options +
"` to inner pipeline");
705 raw_ostream &errorStream) {
706 TextualPipeline pipelineParser;
707 if (
failed(pipelineParser.initialize(pipeline, errorStream)))
709 auto errorHandler = [&](Twine msg) {
710 errorStream << msg <<
"\n";
713 if (
failed(pipelineParser.addToPipeline(pm, errorHandler)))
719 raw_ostream &errorStream) {
720 pipeline = pipeline.trim();
722 size_t pipelineStart = pipeline.find_first_of(
'(');
723 if (pipelineStart == 0 || pipelineStart == StringRef::npos ||
724 !pipeline.consume_back(
")")) {
725 errorStream <<
"expected pass pipeline to be wrapped with the anchor "
726 "operation type, e.g. 'builtin.module(...)'";
730 StringRef opName = pipeline.take_front(pipelineStart).rtrim();
746 PassArgData() =
default;
748 : registryEntry(registryEntry) {}
771 const PassArgData &
getValue()
const {
return value; }
772 void setValue(
const PassArgData &value) { this->value = value; }
783 #define PASS_PIPELINE_ARG "pass-pipeline"
791 void printOptionInfo(
const llvm::cl::Option &opt,
792 size_t globalWidth)
const override;
793 size_t getOptionWidth(
const llvm::cl::Option &opt)
const override;
794 bool parse(llvm::cl::Option &opt, StringRef argName, StringRef arg,
800 bool passNamesOnly =
false;
804 void PassNameParser::initialize() {
809 addLiteralOption(kv.second.getPassArgument(), &kv.second,
810 kv.second.getPassDescription());
813 if (!passNamesOnly) {
815 addLiteralOption(kv.second.getPassArgument(), &kv.second,
816 kv.second.getPassDescription());
821 void PassNameParser::printOptionInfo(
const llvm::cl::Option &opt,
822 size_t globalWidth)
const {
826 llvm::outs() <<
" --" << opt.ArgStr <<
"=<pass-arg>";
827 opt.printHelpStr(opt.HelpStr, globalWidth, opt.ArgStr.size() + 18);
832 if (opt.hasArgStr()) {
833 llvm::outs() <<
" --" << opt.ArgStr;
834 opt.printHelpStr(opt.HelpStr, globalWidth, opt.ArgStr.size() + 7);
836 llvm::outs() <<
" " << opt.HelpStr <<
'\n';
840 auto printOrderedEntries = [&](StringRef header,
auto &map) {
843 orderedEntries.push_back(&kv.second);
844 llvm::array_pod_sort(
845 orderedEntries.begin(), orderedEntries.end(),
847 return (*lhs)->getPassArgument().compare((*rhs)->getPassArgument());
850 llvm::outs().indent(4) << header <<
":\n";
852 entry->printHelpStr(6, globalWidth);
863 size_t PassNameParser::getOptionWidth(
const llvm::cl::Option &opt)
const {
868 maxWidth =
std::max(maxWidth, entry.second.getOptionWidth() + 4);
870 maxWidth =
std::max(maxWidth, entry.second.getOptionWidth() + 4);
875 StringRef arg, PassArgData &value) {
891 : passList(arg,
llvm::cl::desc(description)) {
892 passList.getParser().passNamesOnly = passNamesOnly;
893 passList.setValueExpectedFlag(llvm::cl::ValueExpected::ValueOptional);
899 return llvm::any_of(passList, [&](
const PassArgData &data) {
900 return data.registryEntry == entry;
905 llvm::cl::list<PassArgData, bool, PassNameParser>
passList;
913 arg, description, false)),
916 llvm::cl::desc(
"Textual description of the pass pipeline to run")) {}
921 passPipelineAlias.emplace(alias,
923 llvm::cl::aliasopt(passPipeline));
930 return passPipeline.getNumOccurrences() != 0 ||
931 impl->passList.getNumOccurrences() != 0;
937 return impl->contains(entry);
944 if (passPipeline.getNumOccurrences()) {
945 if (
impl->passList.getNumOccurrences())
948 "' option can't be used with individual pass options");
950 llvm::raw_string_ostream os(errMsg);
953 return errorHandler(errMsg);
954 pm = std::move(*parsed);
958 for (
auto &passIt :
impl->passList) {
959 if (
failed(passIt.registryEntry->addToPipeline(pm, passIt.options,
972 arg, description, true)) {
973 impl->passList.setMiscFlag(llvm::cl::CommaSeparated);
979 return impl->passList.getNumOccurrences() != 0;
985 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)
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,...