1 //===- PassRegistry.h - Pass Registration 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 information about compiler
10 // passes.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef MLIR_PASS_PASSREGISTRY_H_
15 #define MLIR_PASS_PASSREGISTRY_H_
16 
17 #include "mlir/Pass/PassOptions.h"
18 #include "mlir/Support/TypeID.h"
19 #include <functional>
20 #include <utility>
21 
22 namespace mlir {
23 class OpPassManager;
24 class ParserConfig;
25 class Pass;
26 class PassManager;
27 
28 namespace detail {
29 class PassOptions;
30 } // namespace detail
31 
32 /// A registry function that adds passes to the given pass manager. This should
33 /// also parse options and return success() if parsing succeeded.
34 /// `errorHandler` is a functor used to emit errors during parsing.
35 /// parameter corresponds to the raw location within the pipeline string. This
36 /// should always return failure.
37 using PassRegistryFunction = std::function<LogicalResult(
38     OpPassManager &, StringRef options,
39     function_ref<LogicalResult(const Twine &)> errorHandler)>;
40 using PassAllocatorFunction = std::function<std::unique_ptr<Pass>()>;
41 
42 //===----------------------------------------------------------------------===//
43 // PassRegistry
44 //===----------------------------------------------------------------------===//
45 
46 /// Structure to group information about a passes and pass pipelines (argument
47 /// to invoke via mlir-opt, description, pass pipeline builder).
48 class PassRegistryEntry {
49 public:
50   /// Adds this pass registry entry to the given pass manager. `options` is
51   /// an opaque string that will be parsed by the builder. The success of
52   /// parsing will be returned.
53   LogicalResult
addToPipeline(OpPassManager & pm,StringRef options,function_ref<LogicalResult (const Twine &)> errorHandler)54   addToPipeline(OpPassManager &pm, StringRef options,
55                 function_ref<LogicalResult(const Twine &)> errorHandler) const {
56     assert(builder &&
57            "cannot call addToPipeline on PassRegistryEntry without builder");
58     return builder(pm, options, errorHandler);
59   }
60 
61   /// Returns the command line option that may be passed to 'mlir-opt' that will
62   /// cause this pass to run or null if there is no such argument.
getPassArgument()63   StringRef getPassArgument() const { return arg; }
64 
65   /// Returns a description for the pass, this never returns null.
getPassDescription()66   StringRef getPassDescription() const { return description; }
67 
68   /// Print the help information for this pass. This includes the argument,
69   /// description, and any pass options. `descIndent` is the indent that the
70   /// descriptions should be aligned.
71   void printHelpStr(size_t indent, size_t descIndent) const;
72 
73   /// Return the maximum width required when printing the options of this entry.
74   size_t getOptionWidth() const;
75 
76 protected:
PassRegistryEntry(StringRef arg,StringRef description,const PassRegistryFunction & builder,std::function<void (function_ref<void (const detail::PassOptions &)>)> optHandler)77   PassRegistryEntry(
78       StringRef arg, StringRef description, const PassRegistryFunction &builder,
79       std::function<void(function_ref<void(const detail::PassOptions &)>)>
80           optHandler)
81       : arg(arg), description(description), builder(builder),
82         optHandler(std::move(optHandler)) {}
83 
84 private:
85   /// The argument with which to invoke the pass via mlir-opt.
86   std::string arg;
87 
88   /// Description of the pass.
89   std::string description;
90 
91   /// Function to register this entry to a pass manager pipeline.
92   PassRegistryFunction builder;
93 
94   /// Function to invoke a handler for a pass options instance.
95   std::function<void(function_ref<void(const detail::PassOptions &)>)>
96       optHandler;
97 };
98 
99 /// A structure to represent the information of a registered pass pipeline.
100 class PassPipelineInfo : public PassRegistryEntry {
101 public:
PassPipelineInfo(StringRef arg,StringRef description,const PassRegistryFunction & builder,std::function<void (function_ref<void (const detail::PassOptions &)>)> optHandler)102   PassPipelineInfo(
103       StringRef arg, StringRef description, const PassRegistryFunction &builder,
104       std::function<void(function_ref<void(const detail::PassOptions &)>)>
105           optHandler)
106       : PassRegistryEntry(arg, description, builder, std::move(optHandler)) {}
107 };
108 
109 /// A structure to represent the information for a derived pass class.
110 class PassInfo : public PassRegistryEntry {
111 public:
112   /// PassInfo constructor should not be invoked directly, instead use
113   /// PassRegistration or registerPass.
114   PassInfo(StringRef arg, StringRef description,
115            const PassAllocatorFunction &allocator);
116 };
117 
118 //===----------------------------------------------------------------------===//
119 // PassRegistration
120 //===----------------------------------------------------------------------===//
121 
122 /// Register a specific dialect pipeline registry function with the system,
123 /// typically used through the PassPipelineRegistration template.
124 void registerPassPipeline(
125     StringRef arg, StringRef description, const PassRegistryFunction &function,
126     std::function<void(function_ref<void(const detail::PassOptions &)>)>
127         optHandler);
128 
129 /// Register a specific dialect pass allocator function with the system,
130 /// typically used through the PassRegistration template.
131 void registerPass(const PassAllocatorFunction &function);
132 
133 /// PassRegistration provides a global initializer that registers a Pass
134 /// allocation routine for a concrete pass instance. The argument is
135 /// optional and provides a callback to construct a pass that does not have
136 /// a default constructor.
137 ///
138 /// Usage:
139 ///
140 ///   /// At namespace scope.
141 ///   static PassRegistration<MyPass> reg;
142 ///
143 template <typename ConcretePass>
144 struct PassRegistration {
PassRegistrationPassRegistration145   PassRegistration(const PassAllocatorFunction &constructor) {
146     registerPass(constructor);
147   }
PassRegistrationPassRegistration148   PassRegistration()
149       : PassRegistration([] { return std::make_unique<ConcretePass>(); }) {}
150 };
151 
152 /// PassPipelineRegistration provides a global initializer that registers a Pass
153 /// pipeline builder routine.
154 ///
155 /// Usage:
156 ///
157 ///   // At namespace scope.
158 ///   void pipelineBuilder(OpPassManager &pm) {
159 ///      pm.addPass(new MyPass());
160 ///      pm.addPass(new MyOtherPass());
161 ///   }
162 ///
163 ///   static PassPipelineRegistration Unused("unused", "Unused pass",
164 ///                                          pipelineBuilder);
165 template <typename Options = EmptyPipelineOptions>
166 struct PassPipelineRegistration {
PassPipelineRegistrationPassPipelineRegistration167   PassPipelineRegistration(
168       StringRef arg, StringRef description,
169       std::function<void(OpPassManager &, const Options &options)> builder) {
170     registerPassPipeline(
171         arg, description,
172         [builder](OpPassManager &pm, StringRef optionsStr,
173                   function_ref<LogicalResult(const Twine &)> errorHandler) {
174           Options options;
175           if (failed(options.parseFromString(optionsStr)))
176             return failure();
177           builder(pm, options);
178           return success();
179         },
180         [](function_ref<void(const detail::PassOptions &)> optHandler) {
181           optHandler(Options());
182         });
183   }
184 };
185 
186 /// Convenience specialization of PassPipelineRegistration for EmptyPassOptions
187 /// that does not pass an empty options struct to the pass builder function.
188 template <>
189 struct PassPipelineRegistration<EmptyPipelineOptions> {
190   PassPipelineRegistration(
191       StringRef arg, StringRef description,
192       const std::function<void(OpPassManager &)> &builder) {
193     registerPassPipeline(
194         arg, description,
195         [builder](OpPassManager &pm, StringRef optionsStr,
196                   function_ref<LogicalResult(const Twine &)> errorHandler) {
197           if (!optionsStr.empty())
198             return failure();
199           builder(pm);
200           return success();
201         },
202         [](function_ref<void(const detail::PassOptions &)>) {});
203   }
204 };
205 
206 /// Parse the textual representation of a pass pipeline, adding the result to
207 /// 'pm' on success. Returns failure if the given pipeline was invalid.
208 /// 'errorStream' is the output stream used to emit errors found during parsing.
209 LogicalResult parsePassPipeline(StringRef pipeline, OpPassManager &pm,
210                                 raw_ostream &errorStream = llvm::errs());
211 
212 /// Parse the given textual representation of a pass pipeline, and return the
213 /// parsed pipeline on success. The given pipeline string should be wrapped with
214 /// the desired type of operation to root the created operation, i.e.
215 /// `builtin.module(cse)` over `cse`. Returns failure if the given pipeline was
216 /// invalid. 'errorStream' is the output stream used to emit errors found during
217 /// parsing.
218 FailureOr<OpPassManager>
219 parsePassPipeline(StringRef pipeline, raw_ostream &errorStream = llvm::errs());
220 
221 //===----------------------------------------------------------------------===//
222 // PassPipelineCLParser
223 //===----------------------------------------------------------------------===//
224 
225 namespace detail {
226 struct PassPipelineCLParserImpl;
227 } // namespace detail
228 
229 /// This class implements a command-line parser for MLIR passes. It registers a
230 /// cl option with a given argument and description. This parser will register
231 /// options for each of the passes and pipelines that have been registered with
232 /// the pass registry; Meaning that `-cse` will refer to the CSE pass in MLIR.
233 /// It also registers an argument, `pass-pipeline`, that supports parsing a
234 /// textual description of a pipeline.
235 class PassPipelineCLParser {
236 public:
237   /// Construct a pass pipeline parser with the given command line description.
238   PassPipelineCLParser(StringRef arg, StringRef description);
239   ~PassPipelineCLParser();
240 
241   /// Returns true if this parser contains any valid options to add.
242   bool hasAnyOccurrences() const;
243 
244   /// Returns true if the given pass registry entry was registered at the
245   /// top-level of the parser, i.e. not within an explicit textual pipeline.
246   bool contains(const PassRegistryEntry *entry) const;
247 
248   /// Adds the passes defined by this parser entry to the given pass manager.
249   /// Returns failure() if the pass could not be properly constructed due
250   /// to options parsing.
251   LogicalResult
252   addToPipeline(OpPassManager &pm,
253                 function_ref<LogicalResult(const Twine &)> errorHandler) const;
254 
255 private:
256   std::unique_ptr<detail::PassPipelineCLParserImpl> impl;
257 };
258 
259 /// This class implements a command-line parser specifically for MLIR pass
260 /// names. It registers a cl option with a given argument and description that
261 /// accepts a comma delimited list of pass names.
262 class PassNameCLParser {
263 public:
264   /// Construct a parser with the given command line description.
265   PassNameCLParser(StringRef arg, StringRef description);
266   ~PassNameCLParser();
267 
268   /// Returns true if this parser contains any valid options to add.
269   bool hasAnyOccurrences() const;
270 
271   /// Returns true if the given pass registry entry was registered at the
272   /// top-level of the parser, i.e. not within an explicit textual pipeline.
273   bool contains(const PassRegistryEntry *entry) const;
274 
275 private:
276   std::unique_ptr<detail::PassPipelineCLParserImpl> impl;
277 };
278 
279 //===----------------------------------------------------------------------===//
280 // Pass Reproducer
281 //===----------------------------------------------------------------------===//
282 
283 /// Attach an assembly resource parser that handles MLIR reproducer
284 /// configurations. Any found reproducer information will be attached to the
285 /// given pass manager, e.g. the reproducer pipeline, verification flags, etc.
286 // FIXME: Remove the `enableThreading` flag when possible. Some tools, e.g.
287 //        mlir-opt, force disable threading during parsing.
288 void attachPassReproducerAsmResource(ParserConfig &config, PassManager &pm,
289                                      bool &enableThreading);
290 
291 } // namespace mlir
292 
293 #endif // MLIR_PASS_PASSREGISTRY_H_
294