1 | /** |
2 | * Copyright (c) Glow Contributors. See CONTRIBUTORS file. |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | */ |
16 | #ifndef GLOW_PASSMANAGER_PASSMANAGER_H |
17 | #define GLOW_PASSMANAGER_PASSMANAGER_H |
18 | |
19 | #include "glow/Backend/Backend.h" |
20 | |
21 | #include "llvm/ADT/SmallVector.h" |
22 | #include "llvm/Support/CommandLine.h" |
23 | |
24 | #include <atomic> |
25 | |
26 | namespace glow { |
27 | |
28 | struct CompilationContext; |
29 | class IRContainer; |
30 | class PassBase; |
31 | |
32 | /// A set of options and command-line options for a pass manager. |
33 | struct PassManagerOptions { |
34 | /// The unique pass manager id. |
35 | const std::string passManagerID; |
36 | /// Command-line options category to be used for this pass manager. |
37 | llvm::cl::OptionCategory passManagerCat; |
38 | |
39 | llvm::cl::opt<bool> verifyBeforeAllPassesOpt; |
40 | |
41 | llvm::cl::list<std::string> verifyBeforePassesOpt; |
42 | |
43 | llvm::cl::opt<bool> verifyAfterAllPassesOpt; |
44 | |
45 | llvm::cl::list<std::string> verifyAfterPassesOpt; |
46 | |
47 | llvm::cl::opt<bool> dumpIRBeforeAllPassesOpt; |
48 | |
49 | llvm::cl::list<std::string> dumpIRBeforePassesOpt; |
50 | |
51 | llvm::cl::opt<bool> dumpIRAfterAllPassesOpt; |
52 | |
53 | llvm::cl::list<std::string> dumpIRAfterPassesOpt; |
54 | |
55 | llvm::cl::opt<bool> printPassesOpt; |
56 | |
57 | llvm::cl::opt<unsigned> stopAfterPassNumOpt; |
58 | |
59 | PassManagerOptions(const char *id); |
60 | /// Helper to check if \p otherStr is in \p strList. |
61 | static bool listContainsString(const llvm::cl::list<std::string> &strList, |
62 | llvm::StringRef otherStr); |
63 | }; |
64 | |
65 | /// The base class for pass managers. It contains most of the logic common for |
66 | /// all pass managers, but provides a number of hooks that can be overridden by |
67 | /// concrete pass manager to customize the behavior. |
68 | class PassManagerBase : public Named { |
69 | |
70 | private: |
71 | /// The index of pass iteration |
72 | int iterationCount_ = 0; |
73 | |
74 | protected: |
75 | /// The index of the current pass being executed in the pipeline. |
76 | size_t passIdx_ = 0; |
77 | /// The Backend we have for backend-specific verification. |
78 | const Backend *backend_; |
79 | |
80 | /// Logic to execute before pass \p P is run on \p C, given \p cctx. \returns |
81 | /// if \p C was modified. |
82 | bool runPrePass(IRContainer *C, const CompilationContext &cctx, |
83 | const PassBase &P); |
84 | |
85 | /// A runPrePass customization point for the derived classes. |
86 | virtual void runPrePassHook(IRContainer *C, const CompilationContext &cctx, |
87 | const PassBase &P); |
88 | |
89 | /// Logic to execute after pass \p P is run on \p C, given \p cctx. \returns |
90 | /// if \p C was modified. |
91 | bool runPostPass(IRContainer *C, const CompilationContext &cctx, |
92 | const PassBase &P); |
93 | |
94 | /// A runPostPass customization point for the derived classes. |
95 | virtual void runPostPassHook(IRContainer *C, const CompilationContext &cctx, |
96 | const PassBase &P); |
97 | |
98 | // /// Runs a FunctionPass described by \p passConfig over \p C given \p cctx. |
99 | /// Run a pass configured by \p passConfig over IR \p C given \p cctx. |
100 | virtual bool runPass(const PassConfigBase &passConfig, IRContainer *C, |
101 | const CompilationContext &cctx); |
102 | |
103 | /// A runPass customization point for the derived classes. |
104 | virtual bool runPassHook(const PassConfigBase &passConfig, glow::PassBase &P, |
105 | IRContainer *C, const CompilationContext &cctx) = 0; |
106 | |
107 | /// Runs a pass corresponding to the provided \p passConfig on the IR |
108 | /// container \p C given \p cctx. |
109 | virtual bool runPassWithConfig(const PassConfigBase &passConfig, |
110 | IRContainer *C, |
111 | const CompilationContext &cctx) = 0; |
112 | |
113 | /// \returns the name of the pass corresponding to \p passConfig. |
114 | virtual llvm::StringRef |
115 | getNameOfPass(const PassConfigBase &passConfig) const = 0; |
116 | |
117 | /// Creates and \returns a Pass given a provided \p passConfig. |
118 | virtual std::unique_ptr<PassBase> |
119 | createFunctionPass(const PassConfigBase &passConfig) const = 0; |
120 | |
121 | /// Run the PassPipeline given the \ref pipeline_ and |
122 | /// \p cctx. \returns whether \p C was modified. |
123 | bool run(IRContainer *C, const CompilationContext &cctx); |
124 | |
125 | /// \returns the size of the pass pipeline. |
126 | virtual size_t getPipelineSize() const = 0; |
127 | |
128 | /// \returns the \p idx of the pass pipeline. |
129 | virtual const PassConfigBase &getPipelineElement(size_t idx) const = 0; |
130 | |
131 | /// Dump the IR of \p C into the output stream \p or into a file \p |
132 | /// outputFileName, depending on the backend type. |
133 | virtual void dumpIR(IRContainer *C, llvm::raw_ostream &os, |
134 | const std::string &outputFileName) const = 0; |
135 | |
136 | public: |
137 | /// Constructor. |
138 | PassManagerBase(llvm::StringRef name) : Named(name) {} |
139 | virtual ~PassManagerBase() = default; |
140 | |
141 | /// Dump a textual representation of the Manager to \p os. |
142 | void dump(llvm::raw_ostream &os = llvm::outs()) const; |
143 | |
144 | /// \returns the result of verification for a provided IR container \p C. |
145 | virtual bool verify(IRContainer &C) const = 0; |
146 | |
147 | /// \returns the result of a backend-specific verification for a provided IR |
148 | /// container \p C. |
149 | virtual bool verify(const Backend &B, IRContainer &C) const = 0; |
150 | |
151 | /// Get options of this pass manager. |
152 | virtual const PassManagerOptions &getOptions() const = 0; |
153 | /// Get the global pass counter associated with the pass manager. |
154 | virtual std::atomic<unsigned> &globalPassCounter() = 0; |
155 | /// Get the global pass counter associated with the pass manager. |
156 | virtual const std::atomic<unsigned> &globalPassCounter() const = 0; |
157 | }; |
158 | |
159 | template <typename IRPassTy, typename PassIDTy> |
160 | std::unique_ptr<IRPassTy> createFunctionPass(PassIDTy); |
161 | |
162 | /// Manager for running a series of FunctionPasses. Given some Function, |
163 | /// CompilationContext, and provided Pipeline, it will run all passes on the |
164 | /// Function. Enables easier debugging given runPrePass() and runPostPass() |
165 | /// calls, which can be modified to run some code before or before every pass. |
166 | template <typename IRPASS_PIPELINE, typename IRPASS> |
167 | class PassManager : public PassManagerBase { |
168 | public: |
169 | using IRPassTy = IRPASS; |
170 | using IRPassPipelineTy = IRPASS_PIPELINE; |
171 | using IRContainerTy = typename IRPassTy::IRContainerTy; |
172 | using PassIDTy = typename IRPassTy::PassIDTy; |
173 | using IRPassConfigTy = typename IRPassPipelineTy::IRPassConfigTy; |
174 | |
175 | private: |
176 | /// The pipeline of passes to run. |
177 | std::unique_ptr<IRPassPipelineTy> pipeline_; |
178 | /// Options and command-line options for this pass manager. |
179 | static PassManagerOptions &options_; |
180 | |
181 | /// Global pass counter used to identify each pass. |
182 | std::atomic<unsigned> globalPassCounter_; |
183 | |
184 | /// Creates and \returns a Pass given a provided \p passID. |
185 | std::unique_ptr<IRPassTy> createFunctionPass(PassIDTy passID) const; |
186 | |
187 | std::unique_ptr<PassBase> |
188 | createFunctionPass(const PassConfigBase &passConfig) const override { |
189 | return createFunctionPass( |
190 | static_cast<const IRPassConfigTy *>(&passConfig)->getPassID()); |
191 | } |
192 | |
193 | bool runPassHook(const PassConfigBase &passConfig, PassBase &P, |
194 | IRContainer *C, const CompilationContext &cctx) override; |
195 | |
196 | bool runPassWithConfig(const PassConfigBase &passConfig, IRContainer *C, |
197 | const CompilationContext &cctx) override { |
198 | return runPass(*static_cast<const IRPassConfigTy *>(&passConfig), |
199 | static_cast<IRContainerTy *>(C), cctx); |
200 | } |
201 | |
202 | llvm::StringRef |
203 | getNameOfPass(const PassConfigBase &passConfig) const override { |
204 | return glow::getNameOfPass( |
205 | static_cast<const IRPassConfigTy *>(&passConfig)->getPassID()); |
206 | } |
207 | |
208 | size_t getPipelineSize() const override { return getPipeline().size(); } |
209 | |
210 | const PassConfigBase &getPipelineElement(size_t idx) const override { |
211 | return getPipeline().at(idx); |
212 | } |
213 | |
214 | bool verify(IRContainer &C) const override { |
215 | return static_cast<IRContainerTy *>(&C)->verify(); |
216 | } |
217 | |
218 | bool verify(const Backend &B, IRContainer &C) const override { |
219 | return B.verify(*static_cast<IRContainerTy *>(&C)); |
220 | } |
221 | |
222 | public: |
223 | /// Constructor. |
224 | /// Create a pass manager with a given \p name, provided the \p pipeline and |
225 | /// an optional \p backend. |
226 | PassManager(llvm::StringRef name, std::unique_ptr<IRPassPipelineTy> pipeline, |
227 | const Backend *backend = nullptr) |
228 | : PassManagerBase(name), pipeline_(std::move(pipeline)) { |
229 | backend_ = backend; |
230 | passIdx_ = 0; |
231 | } |
232 | |
233 | PassManager(llvm::StringRef name, |
234 | const std::initializer_list<IRPassConfigTy> &configs, |
235 | const Backend *backend = nullptr) |
236 | : PassManagerBase(name) { |
237 | backend_ = backend; |
238 | passIdx_ = 0; |
239 | pipeline_ = glow::make_unique<IRPassPipelineTy>(configs); |
240 | } |
241 | |
242 | /// Constructor. |
243 | /// Create a pass with a given \p name, provided the pipeline definition in |
244 | /// file \p pipelineDefFilename and an optional \p backend. |
245 | PassManager(llvm::StringRef name, llvm::StringRef pipelineDefFilename, |
246 | const Backend *backend = nullptr) |
247 | : PassManagerBase(name), |
248 | pipeline_(glow::make_unique<IRPassPipelineTy>()) { |
249 | backend_ = backend; |
250 | passIdx_ = 0; |
251 | pipeline_->initFromFile(pipelineDefFilename); |
252 | } |
253 | |
254 | virtual ~PassManager() = default; |
255 | |
256 | /// Run the PassPipeline pipeline_ on the IR container \p C and |
257 | /// \p cctx. \returns whether \p C was modified. |
258 | bool run(IRContainerTy *C, const CompilationContext &cctx) { |
259 | return PassManagerBase::run(C, cctx); |
260 | } |
261 | |
262 | /// Getter for a reference to the Pipeline used by this PassManager. |
263 | const IRPassPipelineTy &getPipeline() const { return *pipeline_; }; |
264 | |
265 | /// Dump a textual representation of the PassManager to \p os. |
266 | void dump(llvm::raw_ostream &os = llvm::outs()) const { |
267 | PassManagerBase::dump(os); |
268 | getPipeline().dump(); |
269 | } |
270 | |
271 | void dumpIR(IRContainer *C, llvm::raw_ostream &os, |
272 | const std::string &outputFileName) const override; |
273 | |
274 | /// Get options of this pass manager. |
275 | const PassManagerOptions &getOptions() const override { return options_; } |
276 | |
277 | std::atomic<unsigned> &globalPassCounter() override { |
278 | return globalPassCounter_; |
279 | } |
280 | |
281 | const std::atomic<unsigned> &globalPassCounter() const override { |
282 | return globalPassCounter_; |
283 | } |
284 | }; |
285 | |
286 | } // namespace glow |
287 | |
288 | #endif // GLOW_PASSMANAGER_PASSMANAGER_H |
289 | |