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
21using namespace glow;
22
23/// Helper to check if \p otherStr is in \p strList.
24bool 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.
41PassManagerOptions::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
110void PassManagerBase::dump(llvm::raw_ostream &os) const {
111 os << getOptions().passManagerID << "PassManager " << getName()
112 << ": Current PassIdx: " << passIdx_
113 << "; Current globalPassCounter: " << globalPassCounter() << "\n";
114}
115
116bool 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
137bool 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
159void 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
174void 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
189bool 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
199bool 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