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 | |
17 | #include "glow/PassManager/PassManager.h" |
18 | |
19 | #include <glog/logging.h> |
20 | |
21 | using namespace glow; |
22 | |
23 | /// Helper to check if \p otherStr is in \p strList. |
24 | bool PassManagerOptions::listContainsString( |
25 | const llvm::cl::list<std::string> &strList, llvm::StringRef otherStr) { |
26 | for (llvm::StringRef str : strList) { |
27 | if (str == otherStr) { |
28 | return true; |
29 | } |
30 | } |
31 | return false; |
32 | } |
33 | |
34 | /// Construct pass manager command-line options. Use a provided identifier \p id |
35 | /// to create different option names for different pass managers. |
36 | /// |
37 | /// NOTE: The names of the command-line options are created dynamically using |
38 | /// the unique \p id. It is important to make those strings live until the end |
39 | /// of the execution due to the way how LLVM's command-line registration |
40 | /// machinery works. |
41 | PassManagerOptions::PassManagerOptions(const char *id) |
42 | : passManagerID(id), passManagerCat{staticStrFormat( |
43 | "%s Pass Manager Options" , id)}, |
44 | verifyBeforeAllPassesOpt{ |
45 | llvm::StringRef(staticStrFormat("verify-before-all-%s-passes" , id)), |
46 | llvm::cl::desc("Verify the IR before all passes." ), |
47 | llvm::cl::Optional, llvm::cl::cat(passManagerCat)}, |
48 | |
49 | verifyBeforePassesOpt{ |
50 | llvm::StringRef(staticStrFormat("verify-before-%s-passes" , id)), |
51 | llvm::cl::desc("Verify the IR before the listed passes." ), |
52 | llvm::cl::value_desc("Comma separated pass names (e.g. DSE, DCE)" ), |
53 | llvm::cl::ZeroOrMore, |
54 | llvm::cl::CommaSeparated, |
55 | llvm::cl::cat(passManagerCat)}, |
56 | |
57 | verifyAfterAllPassesOpt{ |
58 | llvm::StringRef(staticStrFormat("verify-after-all-%s-passes" , id)), |
59 | llvm::cl::desc("Verify the IR after all passes." ), llvm::cl::Optional, |
60 | llvm::cl::cat(passManagerCat)}, |
61 | |
62 | verifyAfterPassesOpt{ |
63 | llvm::StringRef(staticStrFormat("verify-after-%s-passes" , id)), |
64 | llvm::cl::desc("Verify the IR after the listed passes." ), |
65 | llvm::cl::value_desc("Comma separated pass names (e.g. DSE, DCE)" ), |
66 | llvm::cl::ZeroOrMore, |
67 | llvm::cl::CommaSeparated, |
68 | llvm::cl::cat(passManagerCat)}, |
69 | |
70 | dumpIRBeforeAllPassesOpt{ |
71 | llvm::StringRef(staticStrFormat("dump-%s-before-all-passes" , id)), |
72 | llvm::cl::desc("Debug option to dump the IR before all passes." ), |
73 | llvm::cl::Optional, llvm::cl::cat(passManagerCat)}, |
74 | |
75 | dumpIRBeforePassesOpt{ |
76 | llvm::StringRef(staticStrFormat("dump-%s-before-passes" , id)), |
77 | llvm::cl::desc("Debug option to dump the IR before the " |
78 | "listed passes." ), |
79 | llvm::cl::value_desc("Comma separated pass names (e.g. DSE, DCE)" ), |
80 | llvm::cl::ZeroOrMore, |
81 | llvm::cl::CommaSeparated, |
82 | llvm::cl::cat(passManagerCat)}, |
83 | |
84 | dumpIRAfterAllPassesOpt{ |
85 | llvm::StringRef(staticStrFormat("dump-%s-after-all-passes" , id)), |
86 | llvm::cl::desc("Debug option to dump the IR after all passes." ), |
87 | llvm::cl::Optional, llvm::cl::cat(passManagerCat)}, |
88 | |
89 | dumpIRAfterPassesOpt{ |
90 | llvm::StringRef(staticStrFormat("dump-%s-after-passes" , id)), |
91 | llvm::cl::desc("Debug option to dump the IR after listed passes." ), |
92 | llvm::cl::value_desc("Comma separated pass names (e.g. DSE, DCE)" ), |
93 | llvm::cl::ZeroOrMore, |
94 | llvm::cl::CommaSeparated, |
95 | llvm::cl::cat(passManagerCat)}, |
96 | |
97 | printPassesOpt{ |
98 | llvm::StringRef(staticStrFormat("print-%s-passes" , id)), |
99 | llvm::cl::desc("Print all of the passes run by the pass manager." ), |
100 | llvm::cl::Optional, llvm::cl::cat(passManagerCat)}, |
101 | |
102 | stopAfterPassNumOpt{ |
103 | llvm::StringRef(staticStrFormat("stop-%s-passes-after-num" , id)), |
104 | llvm::cl::desc( |
105 | "Number of passes to run before preventing running any " |
106 | "passes. Used for debugging." ), |
107 | llvm::cl::init(std::numeric_limits<unsigned>::max()), |
108 | llvm::cl::cat(passManagerCat)} {} |
109 | |
110 | void PassManagerBase::dump(llvm::raw_ostream &os) const { |
111 | os << getOptions().passManagerID << "PassManager " << getName() |
112 | << ": Current PassIdx: " << passIdx_ |
113 | << "; Current globalPassCounter: " << globalPassCounter() << "\n" ; |
114 | } |
115 | |
116 | bool PassManagerBase::runPrePass(IRContainer *C, const CompilationContext &cctx, |
117 | const PassBase &P) { |
118 | if (getOptions().printPassesOpt) { |
119 | LOG(INFO) << "Starting Pass #" << globalPassCounter() << ": " |
120 | << P.getName().str() << " on Function: \"" |
121 | << C->getName().str() + "\"\n" ; |
122 | } |
123 | runPrePassHook(C, cctx, P); |
124 | if (getOptions().verifyBeforeAllPassesOpt || |
125 | PassManagerOptions::listContainsString(getOptions().verifyBeforePassesOpt, |
126 | P.getName())) { |
127 | if (backend_) { |
128 | // Do backend-specific verification. |
129 | CHECK(verify(*backend_, *C)); |
130 | } else { |
131 | CHECK(verify(*C)); |
132 | } |
133 | } |
134 | return false; |
135 | } |
136 | |
137 | bool PassManagerBase::runPostPass(IRContainer *C, |
138 | const CompilationContext &cctx, |
139 | const PassBase &P) { |
140 | if (getOptions().printPassesOpt) { |
141 | LOG(INFO) << "Finished Pass #" << globalPassCounter() << ": " |
142 | << P.getName().str() << " on Function: \"" |
143 | << C->getName().str() + "\"\n" ; |
144 | } |
145 | runPostPassHook(C, cctx, P); |
146 | if (getOptions().verifyAfterAllPassesOpt || |
147 | PassManagerOptions::listContainsString(getOptions().verifyAfterPassesOpt, |
148 | P.getName())) { |
149 | if (backend_) { |
150 | // Do backend-specific verification. |
151 | CHECK(verify(*backend_, *C)); |
152 | } else { |
153 | CHECK(verify(*C)); |
154 | } |
155 | } |
156 | return false; |
157 | } |
158 | |
159 | void PassManagerBase::runPrePassHook(IRContainer *C, |
160 | const CompilationContext &cctx, |
161 | const PassBase &P) { |
162 | if (getOptions().dumpIRBeforeAllPassesOpt || |
163 | PassManagerOptions::listContainsString(getOptions().dumpIRBeforePassesOpt, |
164 | P.getName())) { |
165 | glow::outs() << getOptions().passManagerID << " before pass " << P.getName() |
166 | << "\n" ; |
167 | dumpIR(C, glow::outs(), |
168 | C->getName().str() + "_PrePass_" + P.getName().str() + "_n" + |
169 | std::to_string(globalPassCounter()) + "_" + |
170 | std::to_string(iterationCount_++) + ".dot" ); |
171 | } |
172 | } |
173 | |
174 | void PassManagerBase::runPostPassHook(IRContainer *C, |
175 | const CompilationContext &cctx, |
176 | const PassBase &P) { |
177 | if (getOptions().dumpIRAfterAllPassesOpt || |
178 | PassManagerOptions::listContainsString(getOptions().dumpIRAfterPassesOpt, |
179 | P.getName())) { |
180 | glow::outs() << getOptions().passManagerID << " after pass " << P.getName() |
181 | << "\n" ; |
182 | dumpIR(C, glow::outs(), |
183 | C->getName().str() + "_PostPass_" + P.getName().str() + "_n" + |
184 | std::to_string(globalPassCounter()) + "_" + |
185 | std::to_string(iterationCount_++) + ".dot" ); |
186 | } |
187 | } |
188 | |
189 | bool PassManagerBase::runPass(const PassConfigBase &passConfig, IRContainer *F, |
190 | const CompilationContext &cctx) { |
191 | auto pass = createFunctionPass(passConfig); |
192 | auto &P = *pass; |
193 | bool changed = runPrePass(F, cctx, P); |
194 | changed |= runPassHook(passConfig, P, F, cctx); |
195 | changed |= runPostPass(F, cctx, P); |
196 | return changed; |
197 | } |
198 | |
199 | bool PassManagerBase::run(IRContainer *C, const CompilationContext &cctx) { |
200 | bool changed = false; |
201 | size_t e = getPipelineSize(); |
202 | for (passIdx_ = 0; passIdx_ < e; passIdx_++) { |
203 | const PassConfigBase &passConfig = getPipelineElement(passIdx_); |
204 | |
205 | // If we've exceeded the number of passes to run then early exit. |
206 | if (++globalPassCounter() > getOptions().stopAfterPassNumOpt) { |
207 | return changed; |
208 | } |
209 | |
210 | // Skip some passes if specified by the config that they shouldn't be |
211 | // executed in this compilation mode. |
212 | if (!passConfig.isEnabledForCompilationMode(cctx.compMode)) { |
213 | continue; |
214 | } |
215 | |
216 | switch (passConfig.getConvergenceMode()) { |
217 | case ConvergenceMode::OnePass: |
218 | changed |= runPassWithConfig(passConfig, C, cctx); |
219 | break; |
220 | |
221 | case ConvergenceMode::UntilFixedPoint: |
222 | while (runPassWithConfig(passConfig, C, cctx)) { |
223 | changed = true; |
224 | VLOG_IF_EVERY_N(0, google::COUNTER > 1, 100) |
225 | << "Warning: " << getNameOfPass(passConfig).str() |
226 | << " Pass applied another 100 iterations without reaching fixed " |
227 | "point" ; |
228 | } |
229 | break; |
230 | } |
231 | } |
232 | return changed; |
233 | } |
234 | |