blob: d4a6784985a2323a8a852282c585dda7b2bbf7b6 [file] [log] [blame]
Fedor Sergeev662e5682018-09-24 16:08:15 +00001//===- Standard pass instrumentations handling ----------------*- C++ -*--===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Fedor Sergeev662e5682018-09-24 16:08:15 +00006//
7//===----------------------------------------------------------------------===//
8/// \file
9///
10/// This file defines IR-printing pass instrumentation callbacks as well as
11/// StandardInstrumentations class that manages standard pass instrumentations.
12///
13//===----------------------------------------------------------------------===//
14
15#include "llvm/Passes/StandardInstrumentations.h"
Arthur Eubanksb13b8582020-07-21 09:48:22 -070016#include "llvm/ADT/Any.h"
Fedor Sergeev2d94c222018-12-21 11:49:05 +000017#include "llvm/ADT/Optional.h"
Fedor Sergeev662e5682018-09-24 16:08:15 +000018#include "llvm/Analysis/CallGraphSCCPass.h"
19#include "llvm/Analysis/LazyCallGraph.h"
20#include "llvm/Analysis/LoopInfo.h"
21#include "llvm/IR/Function.h"
22#include "llvm/IR/IRPrintingPasses.h"
23#include "llvm/IR/Module.h"
24#include "llvm/IR/PassInstrumentation.h"
Arthur Eubanksb13b8582020-07-21 09:48:22 -070025#include "llvm/Support/CommandLine.h"
Fedor Sergeev662e5682018-09-24 16:08:15 +000026#include "llvm/Support/Debug.h"
27#include "llvm/Support/FormatVariadic.h"
28#include "llvm/Support/raw_ostream.h"
Yuanfang Chen555cf422020-07-28 17:08:24 -070029#include <vector>
Fedor Sergeev662e5682018-09-24 16:08:15 +000030
31using namespace llvm;
32
Arthur Eubanksb13b8582020-07-21 09:48:22 -070033// TODO: remove once all required passes are marked as such.
34static cl::opt<bool>
35 EnableOptnone("enable-npm-optnone", cl::init(false),
36 cl::desc("Enable skipping optional passes optnone functions "
37 "under new pass manager"));
38
Yuanfang Chen555cf422020-07-28 17:08:24 -070039// FIXME: Change `-debug-pass-manager` from boolean to enum type. Similar to
40// `-debug-pass` in legacy PM.
41static cl::opt<bool>
42 DebugPMVerbose("debug-pass-manager-verbose", cl::Hidden, cl::init(false),
43 cl::desc("Print all pass management debugging information. "
44 "`-debug-pass-manager` must also be specified"));
45
Fedor Sergeev662e5682018-09-24 16:08:15 +000046namespace {
Fedor Sergeev662e5682018-09-24 16:08:15 +000047
Fedor Sergeev2d94c222018-12-21 11:49:05 +000048/// Extracting Module out of \p IR unit. Also fills a textual description
49/// of \p IR for use in header when printing.
50Optional<std::pair<const Module *, std::string>> unwrapModule(Any IR) {
51 if (any_isa<const Module *>(IR))
52 return std::make_pair(any_cast<const Module *>(IR), std::string());
Fedor Sergeev662e5682018-09-24 16:08:15 +000053
Fedor Sergeev2d94c222018-12-21 11:49:05 +000054 if (any_isa<const Function *>(IR)) {
Fedor Sergeev662e5682018-09-24 16:08:15 +000055 const Function *F = any_cast<const Function *>(IR);
56 if (!llvm::isFunctionInPrintList(F->getName()))
Fedor Sergeev2d94c222018-12-21 11:49:05 +000057 return None;
58 const Module *M = F->getParent();
59 return std::make_pair(M, formatv(" (function: {0})", F->getName()).str());
60 }
61
62 if (any_isa<const LazyCallGraph::SCC *>(IR)) {
Fedor Sergeev0dc6ac92018-10-15 10:46:35 +000063 const LazyCallGraph::SCC *C = any_cast<const LazyCallGraph::SCC *>(IR);
Fedor Sergeev0dc6ac92018-10-15 10:46:35 +000064 for (const LazyCallGraph::Node &N : *C) {
65 const Function &F = N.getFunction();
66 if (!F.isDeclaration() && isFunctionInPrintList(F.getName())) {
Fedor Sergeev2d94c222018-12-21 11:49:05 +000067 const Module *M = F.getParent();
68 return std::make_pair(M, formatv(" (scc: {0})", C->getName()).str());
Fedor Sergeev0dc6ac92018-10-15 10:46:35 +000069 }
70 }
Fedor Sergeev2d94c222018-12-21 11:49:05 +000071 return None;
72 }
73
74 if (any_isa<const Loop *>(IR)) {
Fedor Sergeev662e5682018-09-24 16:08:15 +000075 const Loop *L = any_cast<const Loop *>(IR);
76 const Function *F = L->getHeader()->getParent();
77 if (!isFunctionInPrintList(F->getName()))
Fedor Sergeev2d94c222018-12-21 11:49:05 +000078 return None;
79 const Module *M = F->getParent();
80 std::string LoopName;
81 raw_string_ostream ss(LoopName);
82 L->getHeader()->printAsOperand(ss, false);
83 return std::make_pair(M, formatv(" (loop: {0})", ss.str()).str());
Fedor Sergeev662e5682018-09-24 16:08:15 +000084 }
Fedor Sergeev2d94c222018-12-21 11:49:05 +000085
86 llvm_unreachable("Unknown IR unit");
Fedor Sergeev662e5682018-09-24 16:08:15 +000087}
88
Yuanfang Chen555cf422020-07-28 17:08:24 -070089void printIR(const Function *F, StringRef Banner, StringRef Extra = StringRef(),
90 bool Brief = false) {
91 if (Brief) {
92 dbgs() << F->getName() << '\n';
93 return;
94 }
95
Fedor Sergeev2d94c222018-12-21 11:49:05 +000096 if (!llvm::isFunctionInPrintList(F->getName()))
97 return;
98 dbgs() << Banner << Extra << "\n" << static_cast<const Value &>(*F);
99}
Hongtao Yubae33a72020-02-23 15:13:27 -0800100
Yuanfang Chen555cf422020-07-28 17:08:24 -0700101void printIR(const Module *M, StringRef Banner, StringRef Extra = StringRef(),
102 bool Brief = false) {
103 if (Brief) {
104 dbgs() << M->getName() << '\n';
105 return;
106 }
107
Hongtao Yubae33a72020-02-23 15:13:27 -0800108 if (llvm::isFunctionInPrintList("*") || llvm::forcePrintModuleIR()) {
109 dbgs() << Banner << Extra << "\n";
110 M->print(dbgs(), nullptr, false);
111 } else {
112 for (const auto &F : M->functions()) {
113 printIR(&F, Banner, Extra);
114 }
115 }
116}
117
Fedor Sergeev2d94c222018-12-21 11:49:05 +0000118void printIR(const LazyCallGraph::SCC *C, StringRef Banner,
Yuanfang Chen555cf422020-07-28 17:08:24 -0700119 StringRef Extra = StringRef(), bool Brief = false) {
120 if (Brief) {
121 dbgs() << *C << '\n';
122 return;
123 }
124
Fedor Sergeev2d94c222018-12-21 11:49:05 +0000125 bool BannerPrinted = false;
126 for (const LazyCallGraph::Node &N : *C) {
127 const Function &F = N.getFunction();
128 if (!F.isDeclaration() && llvm::isFunctionInPrintList(F.getName())) {
129 if (!BannerPrinted) {
130 dbgs() << Banner << Extra << "\n";
131 BannerPrinted = true;
132 }
133 F.print(dbgs());
134 }
135 }
136}
Yuanfang Chen555cf422020-07-28 17:08:24 -0700137
138void printIR(const Loop *L, StringRef Banner, bool Brief = false) {
139 if (Brief) {
140 dbgs() << *L;
141 return;
142 }
143
Fedor Sergeev2d94c222018-12-21 11:49:05 +0000144 const Function *F = L->getHeader()->getParent();
145 if (!llvm::isFunctionInPrintList(F->getName()))
146 return;
Benjamin Krameradcd0262020-01-28 20:23:46 +0100147 llvm::printLoop(const_cast<Loop &>(*L), dbgs(), std::string(Banner));
Fedor Sergeev2d94c222018-12-21 11:49:05 +0000148}
149
150/// Generic IR-printing helper that unpacks a pointer to IRUnit wrapped into
151/// llvm::Any and does actual print job.
Yuanfang Chen555cf422020-07-28 17:08:24 -0700152void unwrapAndPrint(Any IR, StringRef Banner, bool ForceModule = false,
153 bool Brief = false) {
Fedor Sergeev2d94c222018-12-21 11:49:05 +0000154 if (ForceModule) {
155 if (auto UnwrappedModule = unwrapModule(IR))
156 printIR(UnwrappedModule->first, Banner, UnwrappedModule->second);
157 return;
158 }
159
160 if (any_isa<const Module *>(IR)) {
161 const Module *M = any_cast<const Module *>(IR);
162 assert(M && "module should be valid for printing");
Yuanfang Chen555cf422020-07-28 17:08:24 -0700163 printIR(M, Banner, "", Brief);
Fedor Sergeev2d94c222018-12-21 11:49:05 +0000164 return;
165 }
166
167 if (any_isa<const Function *>(IR)) {
168 const Function *F = any_cast<const Function *>(IR);
169 assert(F && "function should be valid for printing");
Yuanfang Chen555cf422020-07-28 17:08:24 -0700170 printIR(F, Banner, "", Brief);
Fedor Sergeev2d94c222018-12-21 11:49:05 +0000171 return;
172 }
173
174 if (any_isa<const LazyCallGraph::SCC *>(IR)) {
175 const LazyCallGraph::SCC *C = any_cast<const LazyCallGraph::SCC *>(IR);
176 assert(C && "scc should be valid for printing");
Benjamin Krameradcd0262020-01-28 20:23:46 +0100177 std::string Extra = std::string(formatv(" (scc: {0})", C->getName()));
Yuanfang Chen555cf422020-07-28 17:08:24 -0700178 printIR(C, Banner, Extra, Brief);
Fedor Sergeev2d94c222018-12-21 11:49:05 +0000179 return;
180 }
181
182 if (any_isa<const Loop *>(IR)) {
183 const Loop *L = any_cast<const Loop *>(IR);
184 assert(L && "Loop should be valid for printing");
Yuanfang Chen555cf422020-07-28 17:08:24 -0700185 printIR(L, Banner, Brief);
Fedor Sergeev2d94c222018-12-21 11:49:05 +0000186 return;
187 }
188 llvm_unreachable("Unknown wrapped IR type");
189}
190
191} // namespace
192
193PrintIRInstrumentation::~PrintIRInstrumentation() {
194 assert(ModuleDescStack.empty() && "ModuleDescStack is not empty at exit");
195}
196
197void PrintIRInstrumentation::pushModuleDesc(StringRef PassID, Any IR) {
198 assert(StoreModuleDesc);
199 const Module *M = nullptr;
200 std::string Extra;
201 if (auto UnwrappedModule = unwrapModule(IR))
202 std::tie(M, Extra) = UnwrappedModule.getValue();
203 ModuleDescStack.emplace_back(M, Extra, PassID);
204}
205
206PrintIRInstrumentation::PrintModuleDesc
207PrintIRInstrumentation::popModuleDesc(StringRef PassID) {
208 assert(!ModuleDescStack.empty() && "empty ModuleDescStack");
209 PrintModuleDesc ModuleDesc = ModuleDescStack.pop_back_val();
210 assert(std::get<2>(ModuleDesc).equals(PassID) && "malformed ModuleDescStack");
211 return ModuleDesc;
212}
213
Yuanfang Chen7a2e1122020-07-28 16:31:46 -0700214void PrintIRInstrumentation::printBeforePass(StringRef PassID, Any IR) {
Fedor Sergeev2d94c222018-12-21 11:49:05 +0000215 if (PassID.startswith("PassManager<") || PassID.contains("PassAdaptor<"))
Yuanfang Chen7a2e1122020-07-28 16:31:46 -0700216 return;
Fedor Sergeev2d94c222018-12-21 11:49:05 +0000217
218 // Saving Module for AfterPassInvalidated operations.
219 // Note: here we rely on a fact that we do not change modules while
220 // traversing the pipeline, so the latest captured module is good
221 // for all print operations that has not happen yet.
222 if (StoreModuleDesc && llvm::shouldPrintAfterPass(PassID))
223 pushModuleDesc(PassID, IR);
224
Fedor Sergeev662e5682018-09-24 16:08:15 +0000225 if (!llvm::shouldPrintBeforePass(PassID))
Yuanfang Chen7a2e1122020-07-28 16:31:46 -0700226 return;
Fedor Sergeev662e5682018-09-24 16:08:15 +0000227
Fedor Sergeev662e5682018-09-24 16:08:15 +0000228 SmallString<20> Banner = formatv("*** IR Dump Before {0} ***", PassID);
Fedor Sergeev2d94c222018-12-21 11:49:05 +0000229 unwrapAndPrint(IR, Banner, llvm::forcePrintModuleIR());
Yuanfang Chen7a2e1122020-07-28 16:31:46 -0700230 return;
Fedor Sergeev662e5682018-09-24 16:08:15 +0000231}
232
Fedor Sergeev2d94c222018-12-21 11:49:05 +0000233void PrintIRInstrumentation::printAfterPass(StringRef PassID, Any IR) {
234 if (PassID.startswith("PassManager<") || PassID.contains("PassAdaptor<"))
235 return;
236
Fedor Sergeev662e5682018-09-24 16:08:15 +0000237 if (!llvm::shouldPrintAfterPass(PassID))
238 return;
239
Fedor Sergeev2d94c222018-12-21 11:49:05 +0000240 if (StoreModuleDesc)
241 popModuleDesc(PassID);
242
243 SmallString<20> Banner = formatv("*** IR Dump After {0} ***", PassID);
244 unwrapAndPrint(IR, Banner, llvm::forcePrintModuleIR());
245}
246
247void PrintIRInstrumentation::printAfterPassInvalidated(StringRef PassID) {
248 if (!StoreModuleDesc || !llvm::shouldPrintAfterPass(PassID))
249 return;
250
Fedor Sergeev662e5682018-09-24 16:08:15 +0000251 if (PassID.startswith("PassManager<") || PassID.contains("PassAdaptor<"))
252 return;
253
Fedor Sergeev2d94c222018-12-21 11:49:05 +0000254 const Module *M;
255 std::string Extra;
256 StringRef StoredPassID;
257 std::tie(M, Extra, StoredPassID) = popModuleDesc(PassID);
258 // Additional filtering (e.g. -filter-print-func) can lead to module
259 // printing being skipped.
260 if (!M)
261 return;
262
263 SmallString<20> Banner =
264 formatv("*** IR Dump After {0} *** invalidated: ", PassID);
265 printIR(M, Banner, Extra);
Fedor Sergeev662e5682018-09-24 16:08:15 +0000266}
Fedor Sergeev2d94c222018-12-21 11:49:05 +0000267
268void PrintIRInstrumentation::registerCallbacks(
269 PassInstrumentationCallbacks &PIC) {
270 // BeforePass callback is not just for printing, it also saves a Module
271 // for later use in AfterPassInvalidated.
272 StoreModuleDesc = llvm::forcePrintModuleIR() && llvm::shouldPrintAfterPass();
273 if (llvm::shouldPrintBeforePass() || StoreModuleDesc)
Yuanfang Chen7a2e1122020-07-28 16:31:46 -0700274 PIC.registerBeforeNonSkippedPassCallback(
275 [this](StringRef P, Any IR) { this->printBeforePass(P, IR); });
Fedor Sergeev2d94c222018-12-21 11:49:05 +0000276
277 if (llvm::shouldPrintAfterPass()) {
278 PIC.registerAfterPassCallback(
279 [this](StringRef P, Any IR) { this->printAfterPass(P, IR); });
280 PIC.registerAfterPassInvalidatedCallback(
281 [this](StringRef P) { this->printAfterPassInvalidated(P); });
282 }
283}
Fedor Sergeev662e5682018-09-24 16:08:15 +0000284
Arthur Eubanksb13b8582020-07-21 09:48:22 -0700285void OptNoneInstrumentation::registerCallbacks(
286 PassInstrumentationCallbacks &PIC) {
287 PIC.registerBeforePassCallback(
288 [this](StringRef P, Any IR) { return this->skip(P, IR); });
289}
290
291bool OptNoneInstrumentation::skip(StringRef PassID, Any IR) {
292 if (!EnableOptnone)
293 return true;
294 const Function *F = nullptr;
295 if (any_isa<const Function *>(IR)) {
296 F = any_cast<const Function *>(IR);
297 } else if (any_isa<const Loop *>(IR)) {
298 F = any_cast<const Loop *>(IR)->getHeader()->getParent();
299 }
300 if (F && F->hasOptNone()) {
301 if (DebugLogging)
302 dbgs() << "Skipping pass: " << PassID << " (optnone)\n";
303 return false;
304 }
305 return true;
306}
307
Yuanfang Chen555cf422020-07-28 17:08:24 -0700308void PrintPassInstrumentation::registerCallbacks(
309 PassInstrumentationCallbacks &PIC) {
310 if (!DebugLogging)
311 return;
312
313 std::vector<StringRef> SpecialPasses = {"PassManager"};
314 if (!DebugPMVerbose)
315 SpecialPasses.emplace_back("PassAdaptor");
316
317 PIC.registerBeforeNonSkippedPassCallback(
318 [SpecialPasses](StringRef PassID, Any IR) {
319 if (isSpecialPass(PassID, SpecialPasses))
320 return;
321
322 dbgs() << "Running pass: " << PassID << " on ";
323 unwrapAndPrint(IR, "", false, true);
324 });
325
326 PIC.registerBeforeAnalysisCallback([](StringRef PassID, Any IR) {
327 dbgs() << "Running analysis: " << PassID << " on ";
328 unwrapAndPrint(IR, "", false, true);
329 });
330}
331
Fedor Sergeev662e5682018-09-24 16:08:15 +0000332void StandardInstrumentations::registerCallbacks(
333 PassInstrumentationCallbacks &PIC) {
Fedor Sergeev2d94c222018-12-21 11:49:05 +0000334 PrintIR.registerCallbacks(PIC);
Yuanfang Chen555cf422020-07-28 17:08:24 -0700335 PrintPass.registerCallbacks(PIC);
Fedor Sergeev884e52a2018-10-05 22:32:01 +0000336 TimePasses.registerCallbacks(PIC);
Arthur Eubanksb13b8582020-07-21 09:48:22 -0700337 OptNone.registerCallbacks(PIC);
Fedor Sergeev662e5682018-09-24 16:08:15 +0000338}