MLIR 22.0.0git
PassOptions.h
Go to the documentation of this file.
1//===- PassOptions.h - Pass Option Utilities --------------------*- C++ -*-===//
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// This file contains utilities for registering options with compiler passes and
10// pipelines.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef MLIR_PASS_PASSOPTIONS_H_
15#define MLIR_PASS_PASSOPTIONS_H_
16
17#include "mlir/Support/LLVM.h"
18#include "llvm/ADT/FunctionExtras.h"
19#include "llvm/ADT/StringRef.h"
20#include "llvm/Support/CommandLine.h"
21#include "llvm/Support/Compiler.h"
22#include <memory>
23
24namespace mlir {
25class OpPassManager;
26
27namespace detail {
28namespace pass_options {
29/// Parse a string containing a list of comma-delimited elements, invoking the
30/// given parser for each sub-element and passing them to the provided
31/// element-append functor.
32LogicalResult
33parseCommaSeparatedList(llvm::cl::Option &opt, StringRef argName,
34 StringRef optionStr,
35 function_ref<LogicalResult(StringRef)> elementParseFn);
36template <typename ElementParser, typename ElementAppendFn>
37LogicalResult parseCommaSeparatedList(llvm::cl::Option &opt, StringRef argName,
38 StringRef optionStr,
39 ElementParser &elementParser,
40 ElementAppendFn &&appendFn) {
42 opt, argName, optionStr, [&](StringRef valueStr) {
43 typename ElementParser::parser_data_type value = {};
44 if (elementParser.parse(opt, argName, valueStr, value))
45 return failure();
46 appendFn(value);
47 return success();
48 });
49}
50
51/// Trait used to detect if a type has a operator<< method.
52template <typename T>
54 decltype(std::declval<raw_ostream &>() << std::declval<T>());
55template <typename T>
56using has_stream_operator = llvm::is_detected<has_stream_operator_trait, T>;
57
58/// Utility methods for printing option values.
59template <typename ParserT>
60static void printOptionValue(raw_ostream &os, const bool &value) {
61 os << (value ? StringRef("true") : StringRef("false"));
62}
63template <typename ParserT>
64static void printOptionValue(raw_ostream &os, const std::string &str) {
65 // Check if the string needs to be escaped before writing it to the ostream.
66 const size_t spaceIndex = str.find_first_of(' ');
67 const size_t escapeIndex =
68 std::min({str.find_first_of('{'), str.find_first_of('\''),
69 str.find_first_of('"')});
70 const bool requiresEscape = spaceIndex < escapeIndex;
71 if (requiresEscape)
72 os << "{";
73 os << str;
74 if (requiresEscape)
75 os << "}";
76}
77template <typename ParserT, typename DataT>
78static void printOptionValue(raw_ostream &os, const DataT &value) {
80 os << value;
81 else
82 // If the value can't be streamed, fallback to checking for a print in the
83 // parser.
84 ParserT::print(os, value);
85}
86} // namespace pass_options
87
88/// Base container class and manager for all pass options.
90private:
91 /// This is the type-erased option base class. This provides some additional
92 /// hooks into the options that are not available via llvm::cl::Option.
93 class OptionBase {
94 public:
95 virtual ~OptionBase() = default;
96
97 /// Out of line virtual function to provide home for the class.
98 virtual void anchor();
99
100 /// Print the name and value of this option to the given stream.
101 virtual void print(raw_ostream &os) = 0;
102
103 /// Return the argument string of this option.
104 StringRef getArgStr() const { return getOption()->ArgStr; }
105
106 /// Returns true if this option has any value assigned to it.
107 bool hasValue() const { return optHasValue; }
108
109 protected:
110 /// Return the main option instance.
111 virtual const llvm::cl::Option *getOption() const = 0;
112
113 /// Copy the value from the given option into this one.
114 virtual void copyValueFrom(const OptionBase &other) = 0;
115
116 /// Flag indicating if this option has a value.
117 bool optHasValue = false;
118
119 /// Allow access to private methods.
120 friend PassOptions;
121 };
122
123 /// This is the parser that is used by pass options that use literal options.
124 /// This is a thin wrapper around the llvm::cl::parser, that exposes some
125 /// additional methods.
126 template <typename DataType>
127 struct GenericOptionParser : public llvm::cl::parser<DataType> {
128 using llvm::cl::parser<DataType>::parser;
129
130 /// Returns an argument name that maps to the specified value.
131 std::optional<StringRef> findArgStrForValue(const DataType &value) {
132 for (auto &it : this->Values)
133 if (it.V.compare(value))
134 return it.Name;
135 return std::nullopt;
136 }
137 };
138
139 /// This is the parser that is used by pass options that wrap PassOptions
140 /// instances. Like GenericOptionParser, this is a thin wrapper around
141 /// llvm::cl::basic_parser.
142 template <typename PassOptionsT>
143 struct PassOptionsParser : public llvm::cl::basic_parser<PassOptionsT> {
144 using llvm::cl::basic_parser<PassOptionsT>::basic_parser;
145 // Parse the options object by delegating to
146 // `PassOptionsT::parseFromString`.
147 bool parse(llvm::cl::Option &, StringRef, StringRef arg,
148 PassOptionsT &value) {
149 return failed(value.parseFromString(arg));
150 }
151
152 // Print the options object by delegating to `PassOptionsT::print`.
153 static void print(llvm::raw_ostream &os, const PassOptionsT &value) {
154 value.print(os);
155 }
156 };
157
158 /// Utility methods for printing option values.
159 template <typename DataT>
160 static void printValue(raw_ostream &os, GenericOptionParser<DataT> &parser,
161 const DataT &value) {
162 if (std::optional<StringRef> argStr = parser.findArgStrForValue(value))
163 os << *argStr;
164 else
165 llvm_unreachable("unknown data value for option");
166 }
167 template <typename DataT, typename ParserT>
168 static void printValue(raw_ostream &os, ParserT &parser, const DataT &value) {
170 }
171
172public:
173 /// The specific parser to use. This is necessary because we need to provide
174 /// additional methods for certain data type parsers.
175 template <typename DataType>
176 using OptionParser = std::conditional_t<
177 // If the data type is derived from PassOptions, use the
178 // PassOptionsParser.
179 std::is_base_of_v<PassOptions, DataType>, PassOptionsParser<DataType>,
180 // Otherwise, use GenericOptionParser where it is well formed, and fall
181 // back to llvm::cl::parser otherwise.
182 // TODO: We should upstream the methods in GenericOptionParser to avoid
183 // the need to do this.
184 std::conditional_t<std::is_base_of<llvm::cl::generic_parser_base,
186 GenericOptionParser<DataType>,
188
189 /// This class represents a specific pass option, with a provided
190 /// data type.
191 template <typename DataType, typename OptionParser = OptionParser<DataType>>
192 class Option
193 : public llvm::cl::opt<DataType, /*ExternalStorage=*/false, OptionParser>,
194 public OptionBase {
195 public:
196 template <typename... Args>
197 Option(PassOptions &parent, StringRef arg, Args &&...args)
198 : llvm::cl::opt<DataType, /*ExternalStorage=*/false, OptionParser>(
199 arg, llvm::cl::sub(parent), std::forward<Args>(args)...) {
200 assert(!this->isPositional() && !this->isSink() &&
201 "sink and positional options are not supported");
202 parent.options.push_back(this);
203
204 // Set a callback to track if this option has a value.
205 this->setCallback([this](const auto &) { this->optHasValue = true; });
206 }
207 ~Option() override = default;
208 using llvm::cl::opt<DataType, /*ExternalStorage=*/false,
209 OptionParser>::operator=;
210 Option &operator=(const Option &other) {
211 *this = other.getValue();
212 return *this;
213 }
214
215 private:
216 /// Return the main option instance.
217 const llvm::cl::Option *getOption() const final { return this; }
218
219 /// Print the name and value of this option to the given stream.
220 void print(raw_ostream &os) final {
221 os << this->ArgStr << '=';
222 printValue(os, this->getParser(), this->getValue());
223 }
224
225 /// Copy the value from the given option into this one.
226 void copyValueFrom(const OptionBase &other) final {
227 this->setValue(static_cast<const Option<DataType, OptionParser> &>(other)
228 .getValue());
229 optHasValue = other.optHasValue;
230 }
231 };
232
233 /// This class represents a specific pass option that contains a list of
234 /// values of the provided data type. The elements within the textual form of
235 /// this option are parsed assuming they are comma-separated. Delimited
236 /// sub-ranges within individual elements of the list may contain commas that
237 /// are not treated as separators for the top-level list.
238 template <typename DataType, typename OptionParser = OptionParser<DataType>>
240 : public llvm::cl::list<DataType, /*StorageClass=*/bool, OptionParser>,
241 public OptionBase {
242 public:
243 template <typename... Args>
244 ListOption(PassOptions &parent, StringRef arg, Args &&...args)
245 : llvm::cl::list<DataType, /*StorageClass=*/bool, OptionParser>(
246 arg, llvm::cl::sub(parent), std::forward<Args>(args)...),
247 elementParser(*this) {
248 assert(!this->isPositional() && !this->isSink() &&
249 "sink and positional options are not supported");
250 assert(!(this->getMiscFlags() & llvm::cl::MiscFlags::CommaSeparated) &&
251 "ListOption is implicitly comma separated, specifying "
252 "CommaSeparated is extraneous");
253
254 // Make the default explicitly "empty" if no default was given.
255 if (!this->isDefaultAssigned())
256 this->setInitialValues({});
257
258 parent.options.push_back(this);
259 elementParser.initialize();
260 }
261 ~ListOption() override = default;
264 *this = ArrayRef<DataType>(other);
265 this->optHasValue = other.optHasValue;
266 return *this;
267 }
268
269 bool handleOccurrence(unsigned pos, StringRef argName,
270 StringRef arg) override {
271 if (this->isDefaultAssigned()) {
272 this->clear();
273 this->overwriteDefault();
274 }
275 this->optHasValue = true;
277 *this, argName, arg, elementParser,
278 [&](const DataType &value) { this->addValue(value); }));
279 }
280
281 /// Allow assigning from an ArrayRef.
283 ((std::vector<DataType> &)*this).assign(values.begin(), values.end());
284 optHasValue = true;
285 return *this;
286 }
287
288 /// Allow accessing the data held by this option.
290 return static_cast<std::vector<DataType> &>(*this);
291 }
293 return static_cast<const std::vector<DataType> &>(*this);
294 }
295
296 private:
297 /// Return the main option instance.
298 const llvm::cl::Option *getOption() const final { return this; }
299
300 /// Print the name and value of this option to the given stream.
301 /// Note that there is currently a limitation with regards to
302 /// `ListOption<string>`: parsing 'option=""` will result in `option` being
303 /// set to the empty list, not to a size-1 list containing an empty string.
304 void print(raw_ostream &os) final {
305 // Don't print the list if the value is the default value.
306 if (this->isDefaultAssigned() &&
307 this->getDefault().size() == (**this).size()) {
308 unsigned i = 0;
309 for (unsigned e = (**this).size(); i < e; i++) {
310 if (!this->getDefault()[i].compare((**this)[i]))
311 break;
312 }
313 if (i == (**this).size())
314 return;
315 }
316
317 os << this->ArgStr << "={";
318 auto printElementFn = [&](const DataType &value) {
319 printValue(os, this->getParser(), value);
320 };
321 llvm::interleave(*this, os, printElementFn, ",");
322 os << "}";
323 }
324
325 /// Copy the value from the given option into this one.
326 void copyValueFrom(const OptionBase &other) final {
327 *this = static_cast<const ListOption<DataType, OptionParser> &>(other);
328 }
329
330 /// The parser to use for parsing the list elements.
332 };
333
334 PassOptions() = default;
335 /// Delete the copy constructor to avoid copying the internal options map.
336 PassOptions(const PassOptions &) = delete;
337 PassOptions(PassOptions &&) = delete;
338
339 /// Copy the option values from 'other' into 'this', where 'other' has the
340 /// same options as 'this'.
341 void copyOptionValuesFrom(const PassOptions &other);
342
343 /// Parse options out as key=value pairs that can then be handed off to the
344 /// `llvm::cl` command line passing infrastructure. Everything is space
345 /// separated.
346 LogicalResult parseFromString(StringRef options,
347 raw_ostream &errorStream = llvm::errs());
348
349 /// Print the options held by this struct in a form that can be parsed via
350 /// 'parseFromString'.
351 void print(raw_ostream &os) const;
352
353 /// Print the help string for the options held by this struct. `descIndent` is
354 /// the indent that the descriptions should be aligned.
355 void printHelp(size_t indent, size_t descIndent) const;
356
357 /// Return the maximum width required when printing the help string.
358 size_t getOptionWidth() const;
359
360private:
361 /// A list of all of the opaque options.
362 std::vector<OptionBase *> options;
363};
364} // namespace detail
365
366//===----------------------------------------------------------------------===//
367// PassPipelineOptions
368//===----------------------------------------------------------------------===//
369
370/// Subclasses of PassPipelineOptions provide a set of options that can be used
371/// to initialize a pass pipeline. See PassPipelineRegistration for usage
372/// details.
373///
374/// Usage:
375///
376/// struct MyPipelineOptions : PassPipelineOptions<MyPassOptions> {
377/// ListOption<int> someListFlag{*this, "flag-name", llvm::cl::desc("...")};
378/// };
379template <typename T>
380class PassPipelineOptions : public virtual detail::PassOptions {
381public:
382 /// Factory that parses the provided options and returns a unique_ptr to the
383 /// struct.
384 static std::unique_ptr<T> createFromString(StringRef options) {
385 auto result = std::make_unique<T>();
386 if (failed(result->parseFromString(options)))
387 return nullptr;
388 return result;
389 }
390};
391
392/// A default empty option struct to be used for passes that do not need to take
393/// any options.
394struct EmptyPipelineOptions : public PassPipelineOptions<EmptyPipelineOptions> {
395};
396} // namespace mlir
397
398//===----------------------------------------------------------------------===//
399// MLIR Options
400//===----------------------------------------------------------------------===//
401
402namespace llvm {
403namespace cl {
404//===----------------------------------------------------------------------===//
405// std::vector+SmallVector
406//===----------------------------------------------------------------------===//
407
408namespace detail {
409template <typename VectorT, typename ElementT>
410class VectorParserBase : public basic_parser_impl {
411public:
412 VectorParserBase(Option &opt) : basic_parser_impl(opt), elementParser(opt) {}
413
414 using parser_data_type = VectorT;
415
416 bool parse(Option &opt, StringRef argName, StringRef arg,
417 parser_data_type &vector) {
418 if (!arg.consume_front("[") || !arg.consume_back("]")) {
419 return opt.error("expected vector option to be wrapped with '[]'",
420 argName);
421 }
422
424 opt, argName, arg, elementParser,
425 [&](const ElementT &value) { vector.push_back(value); }));
426 }
427
428 static void print(raw_ostream &os, const VectorT &vector) {
429 llvm::interleave(
430 vector, os,
431 [&](const ElementT &value) {
433 llvm::cl::parser<ElementT>>(os, value);
434 },
435 ",");
436 }
437
438 void printOptionInfo(const Option &opt, size_t globalWidth) const {
439 // Add the `vector<>` qualifier to the option info.
440 outs() << " --" << opt.ArgStr;
441 outs() << "=<vector<" << elementParser.getValueName() << ">>";
442 Option::printHelpStr(opt.HelpStr, globalWidth, getOptionWidth(opt));
443 }
444
445 size_t getOptionWidth(const Option &opt) const {
446 // Add the `vector<>` qualifier to the option width.
447 StringRef vectorExt("vector<>");
448 return elementParser.getOptionWidth(opt) + vectorExt.size();
449 }
450
451private:
453};
454} // namespace detail
455
456template <typename T>
457class parser<std::vector<T>>
458 : public detail::VectorParserBase<std::vector<T>, T> {
459public:
460 parser(Option &opt) : detail::VectorParserBase<std::vector<T>, T>(opt) {}
461};
462template <typename T, unsigned N>
463class parser<SmallVector<T, N>>
464 : public detail::VectorParserBase<SmallVector<T, N>, T> {
465public:
466 parser(Option &opt) : detail::VectorParserBase<SmallVector<T, N>, T>(opt) {}
467};
468
469//===----------------------------------------------------------------------===//
470// OpPassManager: OptionValue
471//===----------------------------------------------------------------------===//
472
473template <>
476
482
483 /// Returns if the current option has a value.
484 bool hasValue() const { return value.get(); }
485
486 /// Returns the current value of the option.
488 assert(hasValue() && "invalid option value");
489 return *value;
490 }
491
492 /// Set the value of the option.
493 void setValue(const mlir::OpPassManager &newValue);
494 void setValue(StringRef pipelineStr);
495
496 /// Compare the option with the provided value.
497 bool compare(const mlir::OpPassManager &rhs) const;
498 bool compare(const GenericOptionValue &rhs) const override {
499 const auto &rhsOV =
500 static_cast<const OptionValue<mlir::OpPassManager> &>(rhs);
501 if (!rhsOV.hasValue())
502 return false;
503 return compare(rhsOV.getValue());
504 }
505
506private:
507 void anchor() override;
508
509 /// The underlying pass manager. We use a unique_ptr to avoid the need for the
510 /// full type definition.
511 std::unique_ptr<mlir::OpPassManager> value;
512};
513
514//===----------------------------------------------------------------------===//
515// OpPassManager: Parser
516//===----------------------------------------------------------------------===//
517
518extern template class basic_parser<mlir::OpPassManager>;
519
520template <>
522public:
523 /// A utility struct used when parsing a pass manager that prevents the need
524 /// for a default constructor on OpPassManager.
529 operator const mlir::OpPassManager &() const {
530 assert(value && "parsed value was invalid");
531 return *value;
532 }
533
534 std::unique_ptr<mlir::OpPassManager> value;
535 };
537 using OptVal = OptionValue<mlir::OpPassManager>;
538
539 parser(Option &opt) : basic_parser(opt) {}
540
541 bool parse(Option &, StringRef, StringRef arg, ParsedPassManager &value);
542
543 /// Print an instance of the underling option value to the given stream.
544 static void print(raw_ostream &os, const mlir::OpPassManager &value);
545
546 // Overload in subclass to provide a better default value.
547 StringRef getValueName() const override { return "pass-manager"; }
548
549 void printOptionDiff(const Option &opt, mlir::OpPassManager &pm,
550 const OptVal &defaultValue, size_t globalWidth) const;
551
552 // An out-of-line virtual method to provide a 'home' for this class.
553 void anchor() override;
554};
555
556} // namespace cl
557} // namespace llvm
558
559#endif // MLIR_PASS_PASSOPTIONS_H_
return success()
values clear()
false
Parses a map_entries map type from a string format back into its numeric value.
static llvm::ManagedStatic< PassManagerOptions > options
static void print(spirv::VerCapExtAttr triple, DialectAsmPrinter &printer)
This class represents a pass manager that runs passes on either a specific operation type,...
Definition PassManager.h:46
ListOption< DataType, OptionParser > & operator=(const ListOption< DataType, OptionParser > &other)
ListOption< DataType, OptionParser > & operator=(ArrayRef< DataType > values)
Allow assigning from an ArrayRef.
ArrayRef< DataType > operator*() const
ListOption(PassOptions &parent, StringRef arg, Args &&...args)
MutableArrayRef< DataType > operator*()
Allow accessing the data held by this option.
bool handleOccurrence(unsigned pos, StringRef argName, StringRef arg) override
Option & operator=(const Option &other)
Option(PassOptions &parent, StringRef arg, Args &&...args)
Base container class and manager for all pass options.
Definition PassOptions.h:89
mlir::detail::PassOptions::ListOption elementParser
std::conditional_t< std::is_base_of_v< PassOptions, DataType >, PassOptionsParser< DataType >, std::conditional_t< std::is_base_of< llvm::cl::generic_parser_base, llvm::cl::parser< DataType > >::value, GenericOptionParser< DataType >, llvm::cl::parser< DataType > > > OptionParser
The specific parser to use.
void printOptionDiff(const Option &opt, mlir::OpPassManager &pm, const OptVal &defaultValue, size_t globalWidth) const
StringRef getValueName() const override
static void print(raw_ostream &os, const mlir::OpPassManager &value)
Print an instance of the underling option value to the given stream.
OptionValue< mlir::OpPassManager > OptVal
bool parse(Option &, StringRef, StringRef arg, ParsedPassManager &value)
The OpAsmOpInterface, see OpAsmInterface.td for more details.
Definition CallGraph.h:229
llvm::is_detected< has_stream_operator_trait, T > has_stream_operator
Definition PassOptions.h:56
static void printOptionValue(raw_ostream &os, const bool &value)
Utility methods for printing option values.
Definition PassOptions.h:60
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-...
decltype(std::declval< raw_ostream & >()<< std::declval< T >()) has_stream_operator_trait
Trait used to detect if a type has a operator<< method.
Definition PassOptions.h:53
AttrTypeReplacer.
QueryRef parse(llvm::StringRef line, const QuerySession &qs)
Definition Query.cpp:21
detail::InFlightRemark failed(Location loc, RemarkOpts opts)
Report an optimization remark that failed.
Definition Remarks.h:561
Include the generated interface declarations.
llvm::function_ref< Fn > function_ref
Definition LLVM.h:152
bool compare(const GenericOptionValue &rhs) const override
mlir::OpPassManager & getValue() const
Returns the current value of the option.
bool compare(const mlir::OpPassManager &rhs) const
Compare the option with the provided value.
void setValue(const mlir::OpPassManager &newValue)
Set the value of the option.
void setValue(StringRef pipelineStr)
OptionValue(const mlir::OpPassManager &value)
bool hasValue() const
Returns if the current option has a value.
OptionValue(const OptionValue< mlir::OpPassManager > &rhs)
OptionValue< mlir::OpPassManager > & operator=(const mlir::OpPassManager &rhs)
A utility struct used when parsing a pass manager that prevents the need for a default constructor on...
std::unique_ptr< mlir::OpPassManager > value