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