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 
21 namespace mlir {
22 class OpPassManager;
23 class Pass;
24 
25 namespace detail {
26 class PassOptions;
27 } // end namespace detail
28 
29 /// A registry function that adds passes to the given pass manager. This should
30 /// also parse options and return success() if parsing succeeded.
31 using PassRegistryFunction =
32     std::function<LogicalResult(OpPassManager &, StringRef options)>;
33 using PassAllocatorFunction = std::function<std::unique_ptr<Pass>()>;
34 
35 //===----------------------------------------------------------------------===//
36 // PassRegistry
37 //===----------------------------------------------------------------------===//
38 
39 /// Structure to group information about a passes and pass pipelines (argument
40 /// to invoke via mlir-opt, description, pass pipeline builder).
41 class PassRegistryEntry {
42 public:
43   /// Adds this pass registry entry to the given pass manager. `options` is
44   /// an opaque string that will be parsed by the builder. The success of
45   /// parsing will be returned.
addToPipeline(OpPassManager & pm,StringRef options)46   LogicalResult addToPipeline(OpPassManager &pm, StringRef options) const {
47     assert(builder &&
48            "cannot call addToPipeline on PassRegistryEntry without builder");
49     return builder(pm, options);
50   }
51 
52   /// Returns the command line option that may be passed to 'mlir-opt' that will
53   /// cause this pass to run or null if there is no such argument.
getPassArgument()54   StringRef getPassArgument() const { return arg; }
55 
56   /// Returns a description for the pass, this never returns null.
getPassDescription()57   StringRef getPassDescription() const { return description; }
58 
59   /// Print the help information for this pass. This includes the argument,
60   /// description, and any pass options. `descIndent` is the indent that the
61   /// descriptions should be aligned.
62   void printHelpStr(size_t indent, size_t descIndent) const;
63 
64   /// Return the maximum width required when printing the options of this entry.
65   size_t getOptionWidth() const;
66 
67 protected:
PassRegistryEntry(StringRef arg,StringRef description,const PassRegistryFunction & builder,std::function<void (function_ref<void (const detail::PassOptions &)>)> optHandler)68   PassRegistryEntry(
69       StringRef arg, StringRef description, const PassRegistryFunction &builder,
70       std::function<void(function_ref<void(const detail::PassOptions &)>)>
71           optHandler)
72       : arg(arg), description(description), builder(builder),
73         optHandler(optHandler) {}
74 
75 private:
76   /// The argument with which to invoke the pass via mlir-opt.
77   StringRef arg;
78 
79   /// Description of the pass.
80   StringRef description;
81 
82   /// Function to register this entry to a pass manager pipeline.
83   PassRegistryFunction builder;
84 
85   /// Function to invoke a handler for a pass options instance.
86   std::function<void(function_ref<void(const detail::PassOptions &)>)>
87       optHandler;
88 };
89 
90 /// A structure to represent the information of a registered pass pipeline.
91 class PassPipelineInfo : public PassRegistryEntry {
92 public:
PassPipelineInfo(StringRef arg,StringRef description,const PassRegistryFunction & builder,std::function<void (function_ref<void (const detail::PassOptions &)>)> optHandler)93   PassPipelineInfo(
94       StringRef arg, StringRef description, const PassRegistryFunction &builder,
95       std::function<void(function_ref<void(const detail::PassOptions &)>)>
96           optHandler)
97       : PassRegistryEntry(arg, description, builder, optHandler) {}
98 };
99 
100 /// A structure to represent the information for a derived pass class.
101 class PassInfo : public PassRegistryEntry {
102 public:
103   /// PassInfo constructor should not be invoked directly, instead use
104   /// PassRegistration or registerPass.
105   PassInfo(StringRef arg, StringRef description, TypeID passID,
106            const PassAllocatorFunction &allocator);
107 };
108 
109 //===----------------------------------------------------------------------===//
110 // PassRegistration
111 //===----------------------------------------------------------------------===//
112 
113 /// Register a specific dialect pipeline registry function with the system,
114 /// typically used through the PassPipelineRegistration template.
115 void registerPassPipeline(
116     StringRef arg, StringRef description, const PassRegistryFunction &function,
117     std::function<void(function_ref<void(const detail::PassOptions &)>)>
118         optHandler);
119 
120 /// Register a specific dialect pass allocator function with the system,
121 /// typically used through the PassRegistration template.
122 void registerPass(StringRef arg, StringRef description,
123                   const PassAllocatorFunction &function);
124 
125 /// PassRegistration provides a global initializer that registers a Pass
126 /// allocation routine for a concrete pass instance. The third argument is
127 /// optional and provides a callback to construct a pass that does not have
128 /// a default constructor.
129 ///
130 /// Usage:
131 ///
132 ///   /// At namespace scope.
133 ///   static PassRegistration<MyPass> reg("my-pass", "My Pass Description.");
134 ///
135 template <typename ConcretePass> struct PassRegistration {
PassRegistrationPassRegistration136   PassRegistration(StringRef arg, StringRef description,
137                    const PassAllocatorFunction &constructor) {
138     registerPass(arg, description, constructor);
139   }
140 
PassRegistrationPassRegistration141   PassRegistration(StringRef arg, StringRef description)
142       : PassRegistration(arg, description,
143                          [] { return std::make_unique<ConcretePass>(); }) {}
144 };
145 
146 /// PassPipelineRegistration provides a global initializer that registers a Pass
147 /// pipeline builder routine.
148 ///
149 /// Usage:
150 ///
151 ///   // At namespace scope.
152 ///   void pipelineBuilder(OpPassManager &pm) {
153 ///      pm.addPass(new MyPass());
154 ///      pm.addPass(new MyOtherPass());
155 ///   }
156 ///
157 ///   static PassPipelineRegistration Unused("unused", "Unused pass",
158 ///                                          pipelineBuilder);
159 template <typename Options = EmptyPipelineOptions>
160 struct PassPipelineRegistration {
PassPipelineRegistrationPassPipelineRegistration161   PassPipelineRegistration(
162       StringRef arg, StringRef description,
163       std::function<void(OpPassManager &, const Options &options)> builder) {
164     registerPassPipeline(
165         arg, description,
166         [builder](OpPassManager &pm, StringRef optionsStr) {
167           Options options;
168           if (failed(options.parseFromString(optionsStr)))
169             return failure();
170           builder(pm, options);
171           return success();
172         },
173         [](function_ref<void(const detail::PassOptions &)> optHandler) {
174           optHandler(Options());
175         });
176   }
177 };
178 
179 /// Convenience specialization of PassPipelineRegistration for EmptyPassOptions
180 /// that does not pass an empty options struct to the pass builder function.
181 template <> struct PassPipelineRegistration<EmptyPipelineOptions> {
182   PassPipelineRegistration(StringRef arg, StringRef description,
183                            std::function<void(OpPassManager &)> builder) {
184     registerPassPipeline(
185         arg, description,
186         [builder](OpPassManager &pm, StringRef optionsStr) {
187           if (!optionsStr.empty())
188             return failure();
189           builder(pm);
190           return success();
191         },
192         [](function_ref<void(const detail::PassOptions &)>) {});
193   }
194 };
195 
196 /// This function parses the textual representation of a pass pipeline, and adds
197 /// the result to 'pm' on success. This function returns failure if the given
198 /// pipeline was invalid. 'errorStream' is the output stream used to emit errors
199 /// found during parsing.
200 LogicalResult parsePassPipeline(StringRef pipeline, OpPassManager &pm,
201                                 raw_ostream &errorStream = llvm::errs());
202 
203 //===----------------------------------------------------------------------===//
204 // PassPipelineCLParser
205 //===----------------------------------------------------------------------===//
206 
207 namespace detail {
208 struct PassPipelineCLParserImpl;
209 } // end namespace detail
210 
211 /// This class implements a command-line parser for MLIR passes. It registers a
212 /// cl option with a given argument and description. This parser will register
213 /// options for each of the passes and pipelines that have been registered with
214 /// the pass registry; Meaning that `-cse` will refer to the CSE pass in MLIR.
215 /// It also registers an argument, `pass-pipeline`, that supports parsing a
216 /// textual description of a pipeline.
217 class PassPipelineCLParser {
218 public:
219   /// Construct a pass pipeline parser with the given command line description.
220   PassPipelineCLParser(StringRef arg, StringRef description);
221   ~PassPipelineCLParser();
222 
223   /// Returns true if this parser contains any valid options to add.
224   bool hasAnyOccurrences() const;
225 
226   /// Returns true if the given pass registry entry was registered at the
227   /// top-level of the parser, i.e. not within an explicit textual pipeline.
228   bool contains(const PassRegistryEntry *entry) const;
229 
230   /// Adds the passes defined by this parser entry to the given pass manager.
231   /// Returns failure() if the pass could not be properly constructed due
232   /// to options parsing.
233   LogicalResult addToPipeline(OpPassManager &pm) const;
234 
235 private:
236   std::unique_ptr<detail::PassPipelineCLParserImpl> impl;
237 };
238 
239 } // end namespace mlir
240 
241 #endif // MLIR_PASS_PASSREGISTRY_H_
242