MLIR  20.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 
24 namespace mlir {
25 class OpPassManager;
26 
27 namespace detail {
28 namespace 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.
32 LogicalResult
33 parseCommaSeparatedList(llvm::cl::Option &opt, StringRef argName,
34  StringRef optionStr,
35  function_ref<LogicalResult(StringRef)> elementParseFn);
36 template <typename ElementParser, typename ElementAppendFn>
37 LogicalResult 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.
52 template <typename T>
54  decltype(std::declval<raw_ostream &>() << std::declval<T>());
55 template <typename T>
56 using has_stream_operator = llvm::is_detected<has_stream_operator_trait, T>;
57 
58 /// Utility methods for printing option values.
59 template <typename ParserT>
60 static void printOptionValue(raw_ostream &os, const bool &value) {
61  os << (value ? StringRef("true") : StringRef("false"));
62 }
63 template <typename ParserT>
64 static 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 }
77 template <typename ParserT, typename DataT>
78 static std::enable_if_t<has_stream_operator<DataT>::value>
79 printOptionValue(raw_ostream &os, const DataT &value) {
80  os << value;
81 }
82 template <typename ParserT, typename DataT>
83 static std::enable_if_t<!has_stream_operator<DataT>::value>
84 printOptionValue(raw_ostream &os, const DataT &value) {
85  // If the value can't be streamed, fallback to checking for a print in the
86  // parser.
87  ParserT::print(os, value);
88 }
89 } // namespace pass_options
90 
91 /// Base container class and manager for all pass options.
92 class PassOptions : protected llvm::cl::SubCommand {
93 private:
94  /// This is the type-erased option base class. This provides some additional
95  /// hooks into the options that are not available via llvm::cl::Option.
96  class OptionBase {
97  public:
98  virtual ~OptionBase() = default;
99 
100  /// Out of line virtual function to provide home for the class.
101  virtual void anchor();
102 
103  /// Print the name and value of this option to the given stream.
104  virtual void print(raw_ostream &os) = 0;
105 
106  /// Return the argument string of this option.
107  StringRef getArgStr() const { return getOption()->ArgStr; }
108 
109  /// Returns true if this option has any value assigned to it.
110  bool hasValue() const { return optHasValue; }
111 
112  protected:
113  /// Return the main option instance.
114  virtual const llvm::cl::Option *getOption() const = 0;
115 
116  /// Copy the value from the given option into this one.
117  virtual void copyValueFrom(const OptionBase &other) = 0;
118 
119  /// Flag indicating if this option has a value.
120  bool optHasValue = false;
121 
122  /// Allow access to private methods.
123  friend PassOptions;
124  };
125 
126  /// This is the parser that is used by pass options that use literal options.
127  /// This is a thin wrapper around the llvm::cl::parser, that exposes some
128  /// additional methods.
129  template <typename DataType>
130  struct GenericOptionParser : public llvm::cl::parser<DataType> {
132 
133  /// Returns an argument name that maps to the specified value.
134  std::optional<StringRef> findArgStrForValue(const DataType &value) {
135  for (auto &it : this->Values)
136  if (it.V.compare(value))
137  return it.Name;
138  return std::nullopt;
139  }
140  };
141 
142  /// Utility methods for printing option values.
143  template <typename DataT>
144  static void printValue(raw_ostream &os, GenericOptionParser<DataT> &parser,
145  const DataT &value) {
146  if (std::optional<StringRef> argStr = parser.findArgStrForValue(value))
147  os << *argStr;
148  else
149  llvm_unreachable("unknown data value for option");
150  }
151  template <typename DataT, typename ParserT>
152  static void printValue(raw_ostream &os, ParserT &parser, const DataT &value) {
153  detail::pass_options::printOptionValue<ParserT>(os, value);
154  }
155 
156 public:
157  /// The specific parser to use depending on llvm::cl parser used. This is only
158  /// necessary because we need to provide additional methods for certain data
159  /// type parsers.
160  /// TODO: We should upstream the methods in GenericOptionParser to avoid the
161  /// need to do this.
162  template <typename DataType>
163  using OptionParser =
164  std::conditional_t<std::is_base_of<llvm::cl::generic_parser_base,
166  GenericOptionParser<DataType>,
168 
169  /// This class represents a specific pass option, with a provided data type.
170  template <typename DataType, typename OptionParser = OptionParser<DataType>>
171  class Option
172  : public llvm::cl::opt<DataType, /*ExternalStorage=*/false, OptionParser>,
173  public OptionBase {
174  public:
175  template <typename... Args>
176  Option(PassOptions &parent, StringRef arg, Args &&...args)
177  : llvm::cl::opt<DataType, /*ExternalStorage=*/false, OptionParser>(
178  arg, llvm::cl::sub(parent), std::forward<Args>(args)...) {
179  assert(!this->isPositional() && !this->isSink() &&
180  "sink and positional options are not supported");
181  parent.options.push_back(this);
182 
183  // Set a callback to track if this option has a value.
184  this->setCallback([this](const auto &) { this->optHasValue = true; });
185  }
186  ~Option() override = default;
187  using llvm::cl::opt<DataType, /*ExternalStorage=*/false,
188  OptionParser>::operator=;
189  Option &operator=(const Option &other) {
190  *this = other.getValue();
191  return *this;
192  }
193 
194  private:
195  /// Return the main option instance.
196  const llvm::cl::Option *getOption() const final { return this; }
197 
198  /// Print the name and value of this option to the given stream.
199  void print(raw_ostream &os) final {
200  os << this->ArgStr << '=';
201  printValue(os, this->getParser(), this->getValue());
202  }
203 
204  /// Copy the value from the given option into this one.
205  void copyValueFrom(const OptionBase &other) final {
206  this->setValue(static_cast<const Option<DataType, OptionParser> &>(other)
207  .getValue());
208  optHasValue = other.optHasValue;
209  }
210  };
211 
212  /// This class represents a specific pass option that contains a list of
213  /// values of the provided data type. The elements within the textual form of
214  /// this option are parsed assuming they are comma-separated. Delimited
215  /// sub-ranges within individual elements of the list may contain commas that
216  /// are not treated as separators for the top-level list.
217  template <typename DataType, typename OptionParser = OptionParser<DataType>>
219  : public llvm::cl::list<DataType, /*StorageClass=*/bool, OptionParser>,
220  public OptionBase {
221  public:
222  template <typename... Args>
223  ListOption(PassOptions &parent, StringRef arg, Args &&...args)
224  : llvm::cl::list<DataType, /*StorageClass=*/bool, OptionParser>(
225  arg, llvm::cl::sub(parent), std::forward<Args>(args)...),
226  elementParser(*this) {
227  assert(!this->isPositional() && !this->isSink() &&
228  "sink and positional options are not supported");
229  assert(!(this->getMiscFlags() & llvm::cl::MiscFlags::CommaSeparated) &&
230  "ListOption is implicitly comma separated, specifying "
231  "CommaSeparated is extraneous");
232  parent.options.push_back(this);
233  elementParser.initialize();
234  }
235  ~ListOption() override = default;
238  *this = ArrayRef<DataType>(other);
239  this->optHasValue = other.optHasValue;
240  return *this;
241  }
242 
243  bool handleOccurrence(unsigned pos, StringRef argName,
244  StringRef arg) override {
245  if (this->isDefaultAssigned()) {
246  this->clear();
247  this->overwriteDefault();
248  }
249  this->optHasValue = true;
251  *this, argName, arg, elementParser,
252  [&](const DataType &value) { this->addValue(value); }));
253  }
254 
255  /// Allow assigning from an ArrayRef.
257  ((std::vector<DataType> &)*this).assign(values.begin(), values.end());
258  optHasValue = true;
259  return *this;
260  }
261 
262  /// Allow accessing the data held by this option.
264  return static_cast<std::vector<DataType> &>(*this);
265  }
267  return static_cast<const std::vector<DataType> &>(*this);
268  }
269 
270  private:
271  /// Return the main option instance.
272  const llvm::cl::Option *getOption() const final { return this; }
273 
274  /// Print the name and value of this option to the given stream.
275  void print(raw_ostream &os) final {
276  // Don't print the list if empty. An empty option value can be treated as
277  // an element of the list in certain cases (e.g. ListOption<std::string>).
278  if ((**this).empty())
279  return;
280 
281  os << this->ArgStr << '=';
282  auto printElementFn = [&](const DataType &value) {
283  printValue(os, this->getParser(), value);
284  };
285  llvm::interleave(*this, os, printElementFn, ",");
286  }
287 
288  /// Copy the value from the given option into this one.
289  void copyValueFrom(const OptionBase &other) final {
290  *this = static_cast<const ListOption<DataType, OptionParser> &>(other);
291  }
292 
293  /// The parser to use for parsing the list elements.
294  OptionParser elementParser;
295  };
296 
297  PassOptions() = default;
298  /// Delete the copy constructor to avoid copying the internal options map.
299  PassOptions(const PassOptions &) = delete;
300  PassOptions(PassOptions &&) = delete;
301 
302  /// Copy the option values from 'other' into 'this', where 'other' has the
303  /// same options as 'this'.
304  void copyOptionValuesFrom(const PassOptions &other);
305 
306  /// Parse options out as key=value pairs that can then be handed off to the
307  /// `llvm::cl` command line passing infrastructure. Everything is space
308  /// separated.
309  LogicalResult parseFromString(StringRef options,
310  raw_ostream &errorStream = llvm::errs());
311 
312  /// Print the options held by this struct in a form that can be parsed via
313  /// 'parseFromString'.
314  void print(raw_ostream &os);
315 
316  /// Print the help string for the options held by this struct. `descIndent` is
317  /// the indent that the descriptions should be aligned.
318  void printHelp(size_t indent, size_t descIndent) const;
319 
320  /// Return the maximum width required when printing the help string.
321  size_t getOptionWidth() const;
322 
323 private:
324  /// A list of all of the opaque options.
325  std::vector<OptionBase *> options;
326 };
327 } // namespace detail
328 
329 //===----------------------------------------------------------------------===//
330 // PassPipelineOptions
331 //===----------------------------------------------------------------------===//
332 
333 /// Subclasses of PassPipelineOptions provide a set of options that can be used
334 /// to initialize a pass pipeline. See PassPipelineRegistration for usage
335 /// details.
336 ///
337 /// Usage:
338 ///
339 /// struct MyPipelineOptions : PassPipelineOptions<MyPassOptions> {
340 /// ListOption<int> someListFlag{*this, "flag-name", llvm::cl::desc("...")};
341 /// };
342 template <typename T>
344 public:
345  /// Factory that parses the provided options and returns a unique_ptr to the
346  /// struct.
347  static std::unique_ptr<T> createFromString(StringRef options) {
348  auto result = std::make_unique<T>();
349  if (failed(result->parseFromString(options)))
350  return nullptr;
351  return result;
352  }
353 };
354 
355 /// A default empty option struct to be used for passes that do not need to take
356 /// any options.
357 struct EmptyPipelineOptions : public PassPipelineOptions<EmptyPipelineOptions> {
358 };
359 } // namespace mlir
360 
361 //===----------------------------------------------------------------------===//
362 // MLIR Options
363 //===----------------------------------------------------------------------===//
364 
365 namespace llvm {
366 namespace cl {
367 //===----------------------------------------------------------------------===//
368 // std::vector+SmallVector
369 
370 namespace detail {
371 template <typename VectorT, typename ElementT>
372 class VectorParserBase : public basic_parser_impl {
373 public:
374  VectorParserBase(Option &opt) : basic_parser_impl(opt), elementParser(opt) {}
375 
376  using parser_data_type = VectorT;
377 
378  bool parse(Option &opt, StringRef argName, StringRef arg,
379  parser_data_type &vector) {
380  if (!arg.consume_front("[") || !arg.consume_back("]")) {
381  return opt.error("expected vector option to be wrapped with '[]'",
382  argName);
383  }
384 
386  opt, argName, arg, elementParser,
387  [&](const ElementT &value) { vector.push_back(value); }));
388  }
389 
390  static void print(raw_ostream &os, const VectorT &vector) {
391  llvm::interleave(
392  vector, os,
393  [&](const ElementT &value) {
395  llvm::cl::parser<ElementT>>(os, value);
396  },
397  ",");
398  }
399 
400  void printOptionInfo(const Option &opt, size_t globalWidth) const {
401  // Add the `vector<>` qualifier to the option info.
402  outs() << " --" << opt.ArgStr;
403  outs() << "=<vector<" << elementParser.getValueName() << ">>";
404  Option::printHelpStr(opt.HelpStr, globalWidth, getOptionWidth(opt));
405  }
406 
407  size_t getOptionWidth(const Option &opt) const {
408  // Add the `vector<>` qualifier to the option width.
409  StringRef vectorExt("vector<>");
410  return elementParser.getOptionWidth(opt) + vectorExt.size();
411  }
412 
413 private:
414  llvm::cl::parser<ElementT> elementParser;
415 };
416 } // namespace detail
417 
418 template <typename T>
419 class parser<std::vector<T>>
420  : public detail::VectorParserBase<std::vector<T>, T> {
421 public:
422  parser(Option &opt) : detail::VectorParserBase<std::vector<T>, T>(opt) {}
423 };
424 template <typename T, unsigned N>
425 class parser<SmallVector<T, N>>
426  : public detail::VectorParserBase<SmallVector<T, N>, T> {
427 public:
428  parser(Option &opt) : detail::VectorParserBase<SmallVector<T, N>, T>(opt) {}
429 };
430 
431 //===----------------------------------------------------------------------===//
432 // OpPassManager: OptionValue
433 
434 template <>
435 struct OptionValue<mlir::OpPassManager> final : GenericOptionValue {
437 
443 
444  /// Returns if the current option has a value.
445  bool hasValue() const { return value.get(); }
446 
447  /// Returns the current value of the option.
449  assert(hasValue() && "invalid option value");
450  return *value;
451  }
452 
453  /// Set the value of the option.
454  void setValue(const mlir::OpPassManager &newValue);
455  void setValue(StringRef pipelineStr);
456 
457  /// Compare the option with the provided value.
458  bool compare(const mlir::OpPassManager &rhs) const;
459  bool compare(const GenericOptionValue &rhs) const override {
460  const auto &rhsOV =
461  static_cast<const OptionValue<mlir::OpPassManager> &>(rhs);
462  if (!rhsOV.hasValue())
463  return false;
464  return compare(rhsOV.getValue());
465  }
466 
467 private:
468  void anchor() override;
469 
470  /// The underlying pass manager. We use a unique_ptr to avoid the need for the
471  /// full type definition.
472  std::unique_ptr<mlir::OpPassManager> value;
473 };
474 
475 //===----------------------------------------------------------------------===//
476 // OpPassManager: Parser
477 
478 extern template class basic_parser<mlir::OpPassManager>;
479 
480 template <>
482 public:
483  /// A utility struct used when parsing a pass manager that prevents the need
484  /// for a default constructor on OpPassManager.
485  struct ParsedPassManager {
487  ParsedPassManager(ParsedPassManager &&);
489  operator const mlir::OpPassManager &() const {
490  assert(value && "parsed value was invalid");
491  return *value;
492  }
493 
494  std::unique_ptr<mlir::OpPassManager> value;
495  };
496  using parser_data_type = ParsedPassManager;
498 
499  parser(Option &opt) : basic_parser(opt) {}
500 
501  bool parse(Option &, StringRef, StringRef arg, ParsedPassManager &value);
502 
503  /// Print an instance of the underling option value to the given stream.
504  static void print(raw_ostream &os, const mlir::OpPassManager &value);
505 
506  // Overload in subclass to provide a better default value.
507  StringRef getValueName() const override { return "pass-manager"; }
508 
509  void printOptionDiff(const Option &opt, mlir::OpPassManager &pm,
510  const OptVal &defaultValue, size_t globalWidth) const;
511 
512  // An out-of-line virtual method to provide a 'home' for this class.
513  void anchor() override;
514 };
515 
516 } // namespace cl
517 } // namespace llvm
518 
519 #endif // MLIR_PASS_PASSOPTIONS_H_
static Value min(ImplicitLocOpBuilder &builder, Value value, Value bound)
static void print(spirv::VerCapExtAttr triple, DialectAsmPrinter &printer)
size_t getOptionWidth(const Option &opt) const
Definition: PassOptions.h:407
bool parse(Option &opt, StringRef argName, StringRef arg, parser_data_type &vector)
Definition: PassOptions.h:378
void printOptionInfo(const Option &opt, size_t globalWidth) const
Definition: PassOptions.h:400
static void print(raw_ostream &os, const VectorT &vector)
Definition: PassOptions.h:390
static void print(raw_ostream &os, const mlir::OpPassManager &value)
Print an instance of the underling option value to the given stream.
StringRef getValueName() const override
Definition: PassOptions.h:507
void printOptionDiff(const Option &opt, mlir::OpPassManager &pm, const OptVal &defaultValue, size_t globalWidth) const
bool parse(Option &, StringRef, StringRef arg, ParsedPassManager &value)
This class represents a pass manager that runs passes on either a specific operation type,...
Definition: PassManager.h:47
Subclasses of PassPipelineOptions provide a set of options that can be used to initialize a pass pipe...
Definition: PassOptions.h:343
static std::unique_ptr< T > createFromString(StringRef options)
Factory that parses the provided options and returns a unique_ptr to the struct.
Definition: PassOptions.h:347
This class represents a specific pass option that contains a list of values of the provided data type...
Definition: PassOptions.h:220
ListOption< DataType, OptionParser > & operator=(ArrayRef< DataType > values)
Allow assigning from an ArrayRef.
Definition: PassOptions.h:256
ListOption(PassOptions &parent, StringRef arg, Args &&...args)
Definition: PassOptions.h:223
ListOption< DataType, OptionParser > & operator=(const ListOption< DataType, OptionParser > &other)
Definition: PassOptions.h:237
MutableArrayRef< DataType > operator*()
Allow accessing the data held by this option.
Definition: PassOptions.h:263
ArrayRef< DataType > operator*() const
Definition: PassOptions.h:266
bool handleOccurrence(unsigned pos, StringRef argName, StringRef arg) override
Definition: PassOptions.h:243
This class represents a specific pass option, with a provided data type.
Definition: PassOptions.h:173
Option & operator=(const Option &other)
Definition: PassOptions.h:189
Option(PassOptions &parent, StringRef arg, Args &&...args)
Definition: PassOptions.h:176
Base container class and manager for all pass options.
Definition: PassOptions.h:92
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.
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 depending on llvm::cl parser used.
Definition: PassOptions.h:167
PassOptions(PassOptions &&)=delete
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'.
PassOptions(const PassOptions &)=delete
Delete the copy constructor to avoid copying the internal options map.
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.
Definition: CallGraph.h:229
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:54
llvm::is_detected< has_stream_operator_trait, T > has_stream_operator
Definition: PassOptions.h:56
int compare(const Fraction &x, const Fraction &y)
Three-way comparison between two fractions.
Definition: Fraction.h:67
Include the generated interface declarations.
mlir::OpPassManager & getValue() const
Returns the current value of the option.
Definition: PassOptions.h:448
void setValue(const mlir::OpPassManager &newValue)
Set the value of the option.
OptionValue(const OptionValue< mlir::OpPassManager > &rhs)
bool compare(const mlir::OpPassManager &rhs) const
Compare the option with the provided value.
bool compare(const GenericOptionValue &rhs) const override
Definition: PassOptions.h:459
OptionValue< mlir::OpPassManager > & operator=(const mlir::OpPassManager &rhs)
OptionValue(const mlir::OpPassManager &value)
void setValue(StringRef pipelineStr)
bool hasValue() const
Returns if the current option has a value.
Definition: PassOptions.h:445
std::unique_ptr< mlir::OpPassManager > value
Definition: PassOptions.h:494
A default empty option struct to be used for passes that do not need to take any options.
Definition: PassOptions.h:357