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