1 //===- Standard pass instrumentations handling ----------------*- 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 /// \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"
16 #include "llvm/ADT/Any.h"
17 #include "llvm/ADT/Optional.h"
18 #include "llvm/ADT/StringRef.h"
19 #include "llvm/Analysis/CallGraphSCCPass.h"
20 #include "llvm/Analysis/LazyCallGraph.h"
21 #include "llvm/Analysis/LoopInfo.h"
22 #include "llvm/IR/Function.h"
23 #include "llvm/IR/Module.h"
24 #include "llvm/IR/PassInstrumentation.h"
25 #include "llvm/IR/PrintPasses.h"
26 #include "llvm/IR/Verifier.h"
27 #include "llvm/Support/CommandLine.h"
28 #include "llvm/Support/Debug.h"
29 #include "llvm/Support/FormatVariadic.h"
30 #include "llvm/Support/raw_ostream.h"
31 #include <unordered_set>
32 #include <vector>
33
34 using namespace llvm;
35
36 cl::opt<bool> PreservedCFGCheckerInstrumentation::VerifyPreservedCFG(
37 "verify-cfg-preserved", cl::Hidden,
38 #ifdef NDEBUG
39 cl::init(false));
40 #else
41 cl::init(false));
42 #endif
43
44 // FIXME: Change `-debug-pass-manager` from boolean to enum type. Similar to
45 // `-debug-pass` in legacy PM.
46 static cl::opt<bool>
47 DebugPMVerbose("debug-pass-manager-verbose", cl::Hidden, cl::init(false),
48 cl::desc("Print all pass management debugging information. "
49 "`-debug-pass-manager` must also be specified"));
50
51 // An option that prints out the IR after passes, similar to
52 // -print-after-all except that it only prints the IR after passes that
53 // change the IR. Those passes that do not make changes to the IR are
54 // reported as not making any changes. In addition, the initial IR is
55 // also reported. Other hidden options affect the output from this
56 // option. -filter-passes will limit the output to the named passes
57 // that actually change the IR and other passes are reported as filtered out.
58 // The specified passes will either be reported as making no changes (with
59 // no IR reported) or the changed IR will be reported. Also, the
60 // -filter-print-funcs and -print-module-scope options will do similar
61 // filtering based on function name, reporting changed IRs as functions(or
62 // modules if -print-module-scope is specified) for a particular function
63 // or indicating that the IR has been filtered out. The extra options
64 // can be combined, allowing only changed IRs for certain passes on certain
65 // functions to be reported in different formats, with the rest being
66 // reported as filtered out. The -print-before-changed option will print
67 // the IR as it was before each pass that changed it.
68 static cl::opt<bool> PrintChanged("print-changed",
69 cl::desc("Print changed IRs"),
70 cl::init(false), cl::Hidden);
71 // An option that supports the -print-changed option. See
72 // the description for -print-changed for an explanation of the use
73 // of this option. Note that this option has no effect without -print-changed.
74 static cl::list<std::string>
75 PrintPassesList("filter-passes", cl::value_desc("pass names"),
76 cl::desc("Only consider IR changes for passes whose names "
77 "match for the print-changed option"),
78 cl::CommaSeparated, cl::Hidden);
79 // An option that supports the -print-changed option. See
80 // the description for -print-changed for an explanation of the use
81 // of this option. Note that this option has no effect without -print-changed.
82 static cl::opt<bool>
83 PrintChangedBefore("print-before-changed",
84 cl::desc("Print before passes that change them"),
85 cl::init(false), cl::Hidden);
86
87 namespace {
88
89 /// Extracting Module out of \p IR unit. Also fills a textual description
90 /// of \p IR for use in header when printing.
91 Optional<std::pair<const Module *, std::string>>
unwrapModule(Any IR,bool Force=false)92 unwrapModule(Any IR, bool Force = false) {
93 if (any_isa<const Module *>(IR))
94 return std::make_pair(any_cast<const Module *>(IR), std::string());
95
96 if (any_isa<const Function *>(IR)) {
97 const Function *F = any_cast<const Function *>(IR);
98 if (!Force && !isFunctionInPrintList(F->getName()))
99 return None;
100
101 const Module *M = F->getParent();
102 return std::make_pair(M, formatv(" (function: {0})", F->getName()).str());
103 }
104
105 if (any_isa<const LazyCallGraph::SCC *>(IR)) {
106 const LazyCallGraph::SCC *C = any_cast<const LazyCallGraph::SCC *>(IR);
107 for (const LazyCallGraph::Node &N : *C) {
108 const Function &F = N.getFunction();
109 if (Force || (!F.isDeclaration() && isFunctionInPrintList(F.getName()))) {
110 const Module *M = F.getParent();
111 return std::make_pair(M, formatv(" (scc: {0})", C->getName()).str());
112 }
113 }
114 assert(!Force && "Expected to have made a pair when forced.");
115 return None;
116 }
117
118 if (any_isa<const Loop *>(IR)) {
119 const Loop *L = any_cast<const Loop *>(IR);
120 const Function *F = L->getHeader()->getParent();
121 if (!Force && !isFunctionInPrintList(F->getName()))
122 return None;
123 const Module *M = F->getParent();
124 std::string LoopName;
125 raw_string_ostream ss(LoopName);
126 L->getHeader()->printAsOperand(ss, false);
127 return std::make_pair(M, formatv(" (loop: {0})", ss.str()).str());
128 }
129
130 llvm_unreachable("Unknown IR unit");
131 }
132
printIR(raw_ostream & OS,const Function * F,StringRef Banner,StringRef Extra=StringRef (),bool Brief=false)133 void printIR(raw_ostream &OS, const Function *F, StringRef Banner,
134 StringRef Extra = StringRef(), bool Brief = false) {
135 if (Brief) {
136 OS << F->getName() << '\n';
137 return;
138 }
139
140 if (!isFunctionInPrintList(F->getName()))
141 return;
142 OS << Banner << Extra << "\n" << static_cast<const Value &>(*F);
143 }
144
printIR(raw_ostream & OS,const Module * M,StringRef Banner,StringRef Extra=StringRef (),bool Brief=false,bool ShouldPreserveUseListOrder=false)145 void printIR(raw_ostream &OS, const Module *M, StringRef Banner,
146 StringRef Extra = StringRef(), bool Brief = false,
147 bool ShouldPreserveUseListOrder = false) {
148 if (Brief) {
149 OS << M->getName() << '\n';
150 return;
151 }
152
153 if (isFunctionInPrintList("*") || forcePrintModuleIR()) {
154 OS << Banner << Extra << "\n";
155 M->print(OS, nullptr, ShouldPreserveUseListOrder);
156 } else {
157 for (const auto &F : M->functions()) {
158 printIR(OS, &F, Banner, Extra);
159 }
160 }
161 }
162
printIR(raw_ostream & OS,const LazyCallGraph::SCC * C,StringRef Banner,StringRef Extra=StringRef (),bool Brief=false)163 void printIR(raw_ostream &OS, const LazyCallGraph::SCC *C, StringRef Banner,
164 StringRef Extra = StringRef(), bool Brief = false) {
165 if (Brief) {
166 OS << *C << '\n';
167 return;
168 }
169
170 bool BannerPrinted = false;
171 for (const LazyCallGraph::Node &N : *C) {
172 const Function &F = N.getFunction();
173 if (!F.isDeclaration() && isFunctionInPrintList(F.getName())) {
174 if (!BannerPrinted) {
175 OS << Banner << Extra << "\n";
176 BannerPrinted = true;
177 }
178 F.print(OS);
179 }
180 }
181 }
182
printIR(raw_ostream & OS,const Loop * L,StringRef Banner,bool Brief=false)183 void printIR(raw_ostream &OS, const Loop *L, StringRef Banner,
184 bool Brief = false) {
185 if (Brief) {
186 OS << *L;
187 return;
188 }
189
190 const Function *F = L->getHeader()->getParent();
191 if (!isFunctionInPrintList(F->getName()))
192 return;
193 printLoop(const_cast<Loop &>(*L), OS, std::string(Banner));
194 }
195
196 /// Generic IR-printing helper that unpacks a pointer to IRUnit wrapped into
197 /// llvm::Any and does actual print job.
unwrapAndPrint(raw_ostream & OS,Any IR,StringRef Banner,bool ForceModule=false,bool Brief=false,bool ShouldPreserveUseListOrder=false)198 void unwrapAndPrint(raw_ostream &OS, Any IR, StringRef Banner,
199 bool ForceModule = false, bool Brief = false,
200 bool ShouldPreserveUseListOrder = false) {
201 if (ForceModule) {
202 if (auto UnwrappedModule = unwrapModule(IR))
203 printIR(OS, UnwrappedModule->first, Banner, UnwrappedModule->second,
204 Brief, ShouldPreserveUseListOrder);
205 return;
206 }
207
208 if (any_isa<const Module *>(IR)) {
209 const Module *M = any_cast<const Module *>(IR);
210 assert(M && "module should be valid for printing");
211 printIR(OS, M, Banner, "", Brief, ShouldPreserveUseListOrder);
212 return;
213 }
214
215 if (any_isa<const Function *>(IR)) {
216 const Function *F = any_cast<const Function *>(IR);
217 assert(F && "function should be valid for printing");
218 printIR(OS, F, Banner, "", Brief);
219 return;
220 }
221
222 if (any_isa<const LazyCallGraph::SCC *>(IR)) {
223 const LazyCallGraph::SCC *C = any_cast<const LazyCallGraph::SCC *>(IR);
224 assert(C && "scc should be valid for printing");
225 std::string Extra = std::string(formatv(" (scc: {0})", C->getName()));
226 printIR(OS, C, Banner, Extra, Brief);
227 return;
228 }
229
230 if (any_isa<const Loop *>(IR)) {
231 const Loop *L = any_cast<const Loop *>(IR);
232 assert(L && "Loop should be valid for printing");
233 printIR(OS, L, Banner, Brief);
234 return;
235 }
236 llvm_unreachable("Unknown wrapped IR type");
237 }
238
239 // Return true when this is a pass for which changes should be ignored
isIgnored(StringRef PassID)240 bool isIgnored(StringRef PassID) {
241 return isSpecialPass(PassID,
242 {"PassManager", "PassAdaptor", "AnalysisManagerProxy"});
243 }
244
245 } // namespace
246
247 template <typename IRUnitT>
~ChangeReporter()248 ChangeReporter<IRUnitT>::~ChangeReporter<IRUnitT>() {
249 assert(BeforeStack.empty() && "Problem with Change Printer stack.");
250 }
251
252 template <typename IRUnitT>
isInterestingFunction(const Function & F)253 bool ChangeReporter<IRUnitT>::isInterestingFunction(const Function &F) {
254 return isFunctionInPrintList(F.getName());
255 }
256
257 template <typename IRUnitT>
isInterestingPass(StringRef PassID)258 bool ChangeReporter<IRUnitT>::isInterestingPass(StringRef PassID) {
259 if (isIgnored(PassID))
260 return false;
261
262 static std::unordered_set<std::string> PrintPassNames(PrintPassesList.begin(),
263 PrintPassesList.end());
264 return PrintPassNames.empty() || PrintPassNames.count(PassID.str());
265 }
266
267 // Return true when this is a pass on IR for which printing
268 // of changes is desired.
269 template <typename IRUnitT>
isInteresting(Any IR,StringRef PassID)270 bool ChangeReporter<IRUnitT>::isInteresting(Any IR, StringRef PassID) {
271 if (!isInterestingPass(PassID))
272 return false;
273 if (any_isa<const Function *>(IR))
274 return isInterestingFunction(*any_cast<const Function *>(IR));
275 return true;
276 }
277
278 template <typename IRUnitT>
saveIRBeforePass(Any IR,StringRef PassID)279 void ChangeReporter<IRUnitT>::saveIRBeforePass(Any IR, StringRef PassID) {
280 // Always need to place something on the stack because invalidated passes
281 // are not given the IR so it cannot be determined whether the pass was for
282 // something that was filtered out.
283 BeforeStack.emplace_back();
284
285 if (!isInteresting(IR, PassID))
286 return;
287 // Is this the initial IR?
288 if (InitialIR) {
289 InitialIR = false;
290 handleInitialIR(IR);
291 }
292
293 // Save the IR representation on the stack.
294 IRUnitT &Data = BeforeStack.back();
295 generateIRRepresentation(IR, PassID, Data);
296 }
297
298 template <typename IRUnitT>
handleIRAfterPass(Any IR,StringRef PassID)299 void ChangeReporter<IRUnitT>::handleIRAfterPass(Any IR, StringRef PassID) {
300 assert(!BeforeStack.empty() && "Unexpected empty stack encountered.");
301 std::string Name;
302
303 // unwrapModule has inconsistent handling of names for function IRs.
304 if (any_isa<const Function *>(IR)) {
305 const Function *F = any_cast<const Function *>(IR);
306 Name = formatv(" (function: {0})", F->getName()).str();
307 } else {
308 if (auto UM = unwrapModule(IR))
309 Name = UM->second;
310 }
311 if (Name == "")
312 Name = " (module)";
313
314 if (isIgnored(PassID))
315 handleIgnored(PassID, Name);
316 else if (!isInteresting(IR, PassID))
317 handleFiltered(PassID, Name);
318 else {
319 // Get the before rep from the stack
320 IRUnitT &Before = BeforeStack.back();
321 // Create the after rep
322 IRUnitT After;
323 generateIRRepresentation(IR, PassID, After);
324
325 // Was there a change in IR?
326 if (same(Before, After))
327 omitAfter(PassID, Name);
328 else
329 handleAfter(PassID, Name, Before, After, IR);
330 }
331 BeforeStack.pop_back();
332 }
333
334 template <typename IRUnitT>
handleInvalidatedPass(StringRef PassID)335 void ChangeReporter<IRUnitT>::handleInvalidatedPass(StringRef PassID) {
336 assert(!BeforeStack.empty() && "Unexpected empty stack encountered.");
337
338 // Always flag it as invalidated as we cannot determine when
339 // a pass for a filtered function is invalidated since we do not
340 // get the IR in the call. Also, the output is just alternate
341 // forms of the banner anyway.
342 handleInvalidated(PassID);
343 BeforeStack.pop_back();
344 }
345
346 template <typename IRUnitT>
registerRequiredCallbacks(PassInstrumentationCallbacks & PIC)347 void ChangeReporter<IRUnitT>::registerRequiredCallbacks(
348 PassInstrumentationCallbacks &PIC) {
349 PIC.registerBeforeNonSkippedPassCallback(
350 [this](StringRef P, Any IR) { saveIRBeforePass(IR, P); });
351
352 PIC.registerAfterPassCallback(
353 [this](StringRef P, Any IR, const PreservedAnalyses &) {
354 handleIRAfterPass(IR, P);
355 });
356 PIC.registerAfterPassInvalidatedCallback(
357 [this](StringRef P, const PreservedAnalyses &) {
358 handleInvalidatedPass(P);
359 });
360 }
361
362 template <typename IRUnitT>
TextChangeReporter()363 TextChangeReporter<IRUnitT>::TextChangeReporter()
364 : ChangeReporter<IRUnitT>(), Out(dbgs()) {}
365
366 template <typename IRUnitT>
handleInitialIR(Any IR)367 void TextChangeReporter<IRUnitT>::handleInitialIR(Any IR) {
368 // Always print the module.
369 // Unwrap and print directly to avoid filtering problems in general routines.
370 auto UnwrappedModule = unwrapModule(IR, /*Force=*/true);
371 assert(UnwrappedModule && "Expected module to be unwrapped when forced.");
372 Out << "*** IR Dump At Start: ***" << UnwrappedModule->second << "\n";
373 UnwrappedModule->first->print(Out, nullptr,
374 /*ShouldPreserveUseListOrder=*/true);
375 }
376
377 template <typename IRUnitT>
omitAfter(StringRef PassID,std::string & Name)378 void TextChangeReporter<IRUnitT>::omitAfter(StringRef PassID,
379 std::string &Name) {
380 Out << formatv("*** IR Dump After {0}{1} omitted because no change ***\n",
381 PassID, Name);
382 }
383
384 template <typename IRUnitT>
handleInvalidated(StringRef PassID)385 void TextChangeReporter<IRUnitT>::handleInvalidated(StringRef PassID) {
386 Out << formatv("*** IR Pass {0} invalidated ***\n", PassID);
387 }
388
389 template <typename IRUnitT>
handleFiltered(StringRef PassID,std::string & Name)390 void TextChangeReporter<IRUnitT>::handleFiltered(StringRef PassID,
391 std::string &Name) {
392 SmallString<20> Banner =
393 formatv("*** IR Dump After {0}{1} filtered out ***\n", PassID, Name);
394 Out << Banner;
395 }
396
397 template <typename IRUnitT>
handleIgnored(StringRef PassID,std::string & Name)398 void TextChangeReporter<IRUnitT>::handleIgnored(StringRef PassID,
399 std::string &Name) {
400 Out << formatv("*** IR Pass {0}{1} ignored ***\n", PassID, Name);
401 }
402
~IRChangedPrinter()403 IRChangedPrinter::~IRChangedPrinter() {}
404
registerCallbacks(PassInstrumentationCallbacks & PIC)405 void IRChangedPrinter::registerCallbacks(PassInstrumentationCallbacks &PIC) {
406 if (PrintChanged)
407 TextChangeReporter<std::string>::registerRequiredCallbacks(PIC);
408 }
409
generateIRRepresentation(Any IR,StringRef PassID,std::string & Output)410 void IRChangedPrinter::generateIRRepresentation(Any IR, StringRef PassID,
411 std::string &Output) {
412 raw_string_ostream OS(Output);
413 // use the after banner for all cases so it will match
414 SmallString<20> Banner = formatv("*** IR Dump After {0} ***", PassID);
415 unwrapAndPrint(OS, IR, Banner, forcePrintModuleIR(),
416 /*Brief=*/false, /*ShouldPreserveUseListOrder=*/true);
417
418 OS.str();
419 }
420
handleAfter(StringRef PassID,std::string & Name,const std::string & Before,const std::string & After,Any)421 void IRChangedPrinter::handleAfter(StringRef PassID, std::string &Name,
422 const std::string &Before,
423 const std::string &After, Any) {
424 assert(After.find("*** IR Dump") == 0 && "Unexpected banner format.");
425 StringRef AfterRef = After;
426 StringRef Banner =
427 AfterRef.take_until([](char C) -> bool { return C == '\n'; });
428
429 // Report the IR before the changes when requested.
430 if (PrintChangedBefore) {
431 Out << "*** IR Dump Before" << Banner.substr(17);
432 // LazyCallGraph::SCC already has "(scc:..." in banner so only add
433 // in the name if it isn't already there.
434 if (Name.substr(0, 6) != " (scc:" && !forcePrintModuleIR())
435 Out << Name;
436
437 StringRef BeforeRef = Before;
438 Out << BeforeRef.substr(Banner.size());
439 }
440
441 Out << Banner;
442
443 // LazyCallGraph::SCC already has "(scc:..." in banner so only add
444 // in the name if it isn't already there.
445 if (Name.substr(0, 6) != " (scc:" && !forcePrintModuleIR())
446 Out << Name;
447
448 Out << After.substr(Banner.size());
449 }
450
same(const std::string & S1,const std::string & S2)451 bool IRChangedPrinter::same(const std::string &S1, const std::string &S2) {
452 return S1 == S2;
453 }
454
~PrintIRInstrumentation()455 PrintIRInstrumentation::~PrintIRInstrumentation() {
456 assert(ModuleDescStack.empty() && "ModuleDescStack is not empty at exit");
457 }
458
pushModuleDesc(StringRef PassID,Any IR)459 void PrintIRInstrumentation::pushModuleDesc(StringRef PassID, Any IR) {
460 assert(StoreModuleDesc);
461 const Module *M = nullptr;
462 std::string Extra;
463 if (auto UnwrappedModule = unwrapModule(IR))
464 std::tie(M, Extra) = UnwrappedModule.getValue();
465 ModuleDescStack.emplace_back(M, Extra, PassID);
466 }
467
468 PrintIRInstrumentation::PrintModuleDesc
popModuleDesc(StringRef PassID)469 PrintIRInstrumentation::popModuleDesc(StringRef PassID) {
470 assert(!ModuleDescStack.empty() && "empty ModuleDescStack");
471 PrintModuleDesc ModuleDesc = ModuleDescStack.pop_back_val();
472 assert(std::get<2>(ModuleDesc).equals(PassID) && "malformed ModuleDescStack");
473 return ModuleDesc;
474 }
475
printBeforePass(StringRef PassID,Any IR)476 void PrintIRInstrumentation::printBeforePass(StringRef PassID, Any IR) {
477 if (isIgnored(PassID))
478 return;
479
480 // Saving Module for AfterPassInvalidated operations.
481 // Note: here we rely on a fact that we do not change modules while
482 // traversing the pipeline, so the latest captured module is good
483 // for all print operations that has not happen yet.
484 if (StoreModuleDesc && shouldPrintAfterPass(PassID))
485 pushModuleDesc(PassID, IR);
486
487 if (!shouldPrintBeforePass(PassID))
488 return;
489
490 SmallString<20> Banner = formatv("*** IR Dump Before {0} ***", PassID);
491 unwrapAndPrint(dbgs(), IR, Banner, forcePrintModuleIR());
492 return;
493 }
494
printAfterPass(StringRef PassID,Any IR)495 void PrintIRInstrumentation::printAfterPass(StringRef PassID, Any IR) {
496 if (isIgnored(PassID))
497 return;
498
499 if (!shouldPrintAfterPass(PassID))
500 return;
501
502 if (StoreModuleDesc)
503 popModuleDesc(PassID);
504
505 SmallString<20> Banner = formatv("*** IR Dump After {0} ***", PassID);
506 unwrapAndPrint(dbgs(), IR, Banner, forcePrintModuleIR());
507 }
508
printAfterPassInvalidated(StringRef PassID)509 void PrintIRInstrumentation::printAfterPassInvalidated(StringRef PassID) {
510 StringRef PassName = PIC->getPassNameForClassName(PassID);
511 if (!StoreModuleDesc || !shouldPrintAfterPass(PassName))
512 return;
513
514 if (isIgnored(PassID))
515 return;
516
517 const Module *M;
518 std::string Extra;
519 StringRef StoredPassID;
520 std::tie(M, Extra, StoredPassID) = popModuleDesc(PassID);
521 // Additional filtering (e.g. -filter-print-func) can lead to module
522 // printing being skipped.
523 if (!M)
524 return;
525
526 SmallString<20> Banner =
527 formatv("*** IR Dump After {0} *** invalidated: ", PassID);
528 printIR(dbgs(), M, Banner, Extra);
529 }
530
shouldPrintBeforePass(StringRef PassID)531 bool PrintIRInstrumentation::shouldPrintBeforePass(StringRef PassID) {
532 if (shouldPrintBeforeAll())
533 return true;
534
535 StringRef PassName = PIC->getPassNameForClassName(PassID);
536 for (const auto &P : printBeforePasses()) {
537 if (PassName == P)
538 return true;
539 }
540 return false;
541 }
542
shouldPrintAfterPass(StringRef PassID)543 bool PrintIRInstrumentation::shouldPrintAfterPass(StringRef PassID) {
544 if (shouldPrintAfterAll())
545 return true;
546
547 StringRef PassName = PIC->getPassNameForClassName(PassID);
548 for (const auto &P : printAfterPasses()) {
549 if (PassName == P)
550 return true;
551 }
552 return false;
553 }
554
registerCallbacks(PassInstrumentationCallbacks & PIC)555 void PrintIRInstrumentation::registerCallbacks(
556 PassInstrumentationCallbacks &PIC) {
557 this->PIC = &PIC;
558
559 // BeforePass callback is not just for printing, it also saves a Module
560 // for later use in AfterPassInvalidated.
561 StoreModuleDesc = forcePrintModuleIR() && shouldPrintAfterSomePass();
562 if (shouldPrintBeforeSomePass() || StoreModuleDesc)
563 PIC.registerBeforeNonSkippedPassCallback(
564 [this](StringRef P, Any IR) { this->printBeforePass(P, IR); });
565
566 if (shouldPrintAfterSomePass()) {
567 PIC.registerAfterPassCallback(
568 [this](StringRef P, Any IR, const PreservedAnalyses &) {
569 this->printAfterPass(P, IR);
570 });
571 PIC.registerAfterPassInvalidatedCallback(
572 [this](StringRef P, const PreservedAnalyses &) {
573 this->printAfterPassInvalidated(P);
574 });
575 }
576 }
577
registerCallbacks(PassInstrumentationCallbacks & PIC)578 void OptNoneInstrumentation::registerCallbacks(
579 PassInstrumentationCallbacks &PIC) {
580 PIC.registerShouldRunOptionalPassCallback(
581 [this](StringRef P, Any IR) { return this->shouldRun(P, IR); });
582 }
583
shouldRun(StringRef PassID,Any IR)584 bool OptNoneInstrumentation::shouldRun(StringRef PassID, Any IR) {
585 const Function *F = nullptr;
586 if (any_isa<const Function *>(IR)) {
587 F = any_cast<const Function *>(IR);
588 } else if (any_isa<const Loop *>(IR)) {
589 F = any_cast<const Loop *>(IR)->getHeader()->getParent();
590 }
591 bool ShouldRun = !(F && F->hasOptNone());
592 if (!ShouldRun && DebugLogging) {
593 errs() << "Skipping pass " << PassID << " on " << F->getName()
594 << " due to optnone attribute\n";
595 }
596 return ShouldRun;
597 }
598
getBisectDescription(Any IR)599 static std::string getBisectDescription(Any IR) {
600 if (any_isa<const Module *>(IR)) {
601 const Module *M = any_cast<const Module *>(IR);
602 assert(M && "module should be valid for printing");
603 return "module (" + M->getName().str() + ")";
604 }
605
606 if (any_isa<const Function *>(IR)) {
607 const Function *F = any_cast<const Function *>(IR);
608 assert(F && "function should be valid for printing");
609 return "function (" + F->getName().str() + ")";
610 }
611
612 if (any_isa<const LazyCallGraph::SCC *>(IR)) {
613 const LazyCallGraph::SCC *C = any_cast<const LazyCallGraph::SCC *>(IR);
614 assert(C && "scc should be valid for printing");
615 return "SCC " + C->getName();
616 }
617
618 if (any_isa<const Loop *>(IR)) {
619 return "loop";
620 }
621
622 llvm_unreachable("Unknown wrapped IR type");
623 }
624
registerCallbacks(PassInstrumentationCallbacks & PIC)625 void OptBisectInstrumentation::registerCallbacks(
626 PassInstrumentationCallbacks &PIC) {
627 if (!isEnabled())
628 return;
629
630 PIC.registerShouldRunOptionalPassCallback([this](StringRef PassID, Any IR) {
631 return isIgnored(PassID) || checkPass(PassID, getBisectDescription(IR));
632 });
633 }
634
registerCallbacks(PassInstrumentationCallbacks & PIC)635 void PrintPassInstrumentation::registerCallbacks(
636 PassInstrumentationCallbacks &PIC) {
637 if (!DebugLogging)
638 return;
639
640 std::vector<StringRef> SpecialPasses = {"PassManager"};
641 if (!DebugPMVerbose)
642 SpecialPasses.emplace_back("PassAdaptor");
643
644 PIC.registerBeforeSkippedPassCallback(
645 [SpecialPasses](StringRef PassID, Any IR) {
646 assert(!isSpecialPass(PassID, SpecialPasses) &&
647 "Unexpectedly skipping special pass");
648
649 dbgs() << "Skipping pass: " << PassID << " on ";
650 unwrapAndPrint(dbgs(), IR, "", false, true);
651 });
652
653 PIC.registerBeforeNonSkippedPassCallback(
654 [SpecialPasses](StringRef PassID, Any IR) {
655 if (isSpecialPass(PassID, SpecialPasses))
656 return;
657
658 dbgs() << "Running pass: " << PassID << " on ";
659 unwrapAndPrint(dbgs(), IR, "", false, true);
660 });
661
662 PIC.registerBeforeAnalysisCallback([](StringRef PassID, Any IR) {
663 dbgs() << "Running analysis: " << PassID << " on ";
664 unwrapAndPrint(dbgs(), IR, "", false, true);
665 });
666 }
667
CFG(const Function * F,bool TrackBBLifetime)668 PreservedCFGCheckerInstrumentation::CFG::CFG(const Function *F,
669 bool TrackBBLifetime) {
670 if (TrackBBLifetime)
671 BBGuards = DenseMap<intptr_t, BBGuard>(F->size());
672 for (const auto &BB : *F) {
673 if (BBGuards)
674 BBGuards->try_emplace(intptr_t(&BB), &BB);
675 for (auto *Succ : successors(&BB)) {
676 Graph[&BB][Succ]++;
677 if (BBGuards)
678 BBGuards->try_emplace(intptr_t(Succ), Succ);
679 }
680 }
681 }
682
printBBName(raw_ostream & out,const BasicBlock * BB)683 static void printBBName(raw_ostream &out, const BasicBlock *BB) {
684 if (BB->hasName()) {
685 out << BB->getName() << "<" << BB << ">";
686 return;
687 }
688
689 if (!BB->getParent()) {
690 out << "unnamed_removed<" << BB << ">";
691 return;
692 }
693
694 if (BB == &BB->getParent()->getEntryBlock()) {
695 out << "entry"
696 << "<" << BB << ">";
697 return;
698 }
699
700 unsigned FuncOrderBlockNum = 0;
701 for (auto &FuncBB : *BB->getParent()) {
702 if (&FuncBB == BB)
703 break;
704 FuncOrderBlockNum++;
705 }
706 out << "unnamed_" << FuncOrderBlockNum << "<" << BB << ">";
707 }
708
printDiff(raw_ostream & out,const CFG & Before,const CFG & After)709 void PreservedCFGCheckerInstrumentation::CFG::printDiff(raw_ostream &out,
710 const CFG &Before,
711 const CFG &After) {
712 assert(!After.isPoisoned());
713
714 // Print function name.
715 const CFG *FuncGraph = nullptr;
716 if (!After.Graph.empty())
717 FuncGraph = &After;
718 else if (!Before.isPoisoned() && !Before.Graph.empty())
719 FuncGraph = &Before;
720
721 if (FuncGraph)
722 out << "In function @"
723 << FuncGraph->Graph.begin()->first->getParent()->getName() << "\n";
724
725 if (Before.isPoisoned()) {
726 out << "Some blocks were deleted\n";
727 return;
728 }
729
730 // Find and print graph differences.
731 if (Before.Graph.size() != After.Graph.size())
732 out << "Different number of non-leaf basic blocks: before="
733 << Before.Graph.size() << ", after=" << After.Graph.size() << "\n";
734
735 for (auto &BB : Before.Graph) {
736 auto BA = After.Graph.find(BB.first);
737 if (BA == After.Graph.end()) {
738 out << "Non-leaf block ";
739 printBBName(out, BB.first);
740 out << " is removed (" << BB.second.size() << " successors)\n";
741 }
742 }
743
744 for (auto &BA : After.Graph) {
745 auto BB = Before.Graph.find(BA.first);
746 if (BB == Before.Graph.end()) {
747 out << "Non-leaf block ";
748 printBBName(out, BA.first);
749 out << " is added (" << BA.second.size() << " successors)\n";
750 continue;
751 }
752
753 if (BB->second == BA.second)
754 continue;
755
756 out << "Different successors of block ";
757 printBBName(out, BA.first);
758 out << " (unordered):\n";
759 out << "- before (" << BB->second.size() << "): ";
760 for (auto &SuccB : BB->second) {
761 printBBName(out, SuccB.first);
762 if (SuccB.second != 1)
763 out << "(" << SuccB.second << "), ";
764 else
765 out << ", ";
766 }
767 out << "\n";
768 out << "- after (" << BA.second.size() << "): ";
769 for (auto &SuccA : BA.second) {
770 printBBName(out, SuccA.first);
771 if (SuccA.second != 1)
772 out << "(" << SuccA.second << "), ";
773 else
774 out << ", ";
775 }
776 out << "\n";
777 }
778 }
779
registerCallbacks(PassInstrumentationCallbacks & PIC)780 void PreservedCFGCheckerInstrumentation::registerCallbacks(
781 PassInstrumentationCallbacks &PIC) {
782 if (!VerifyPreservedCFG)
783 return;
784
785 PIC.registerBeforeNonSkippedPassCallback([this](StringRef P, Any IR) {
786 if (any_isa<const Function *>(IR))
787 GraphStackBefore.emplace_back(P, CFG(any_cast<const Function *>(IR)));
788 else
789 GraphStackBefore.emplace_back(P, None);
790 });
791
792 PIC.registerAfterPassInvalidatedCallback(
793 [this](StringRef P, const PreservedAnalyses &PassPA) {
794 auto Before = GraphStackBefore.pop_back_val();
795 assert(Before.first == P &&
796 "Before and After callbacks must correspond");
797 (void)Before;
798 });
799
800 PIC.registerAfterPassCallback([this](StringRef P, Any IR,
801 const PreservedAnalyses &PassPA) {
802 auto Before = GraphStackBefore.pop_back_val();
803 assert(Before.first == P && "Before and After callbacks must correspond");
804 auto &GraphBefore = Before.second;
805
806 if (!PassPA.allAnalysesInSetPreserved<CFGAnalyses>())
807 return;
808
809 if (any_isa<const Function *>(IR)) {
810 assert(GraphBefore && "Must be built in BeforePassCallback");
811 CFG GraphAfter(any_cast<const Function *>(IR), false /* NeedsGuard */);
812 if (GraphAfter == *GraphBefore)
813 return;
814
815 dbgs() << "Error: " << P
816 << " reported it preserved CFG, but changes detected:\n";
817 CFG::printDiff(dbgs(), *GraphBefore, GraphAfter);
818 report_fatal_error(Twine("Preserved CFG changed by ", P));
819 }
820 });
821 }
822
registerCallbacks(PassInstrumentationCallbacks & PIC)823 void VerifyInstrumentation::registerCallbacks(
824 PassInstrumentationCallbacks &PIC) {
825 PIC.registerAfterPassCallback(
826 [this](StringRef P, Any IR, const PreservedAnalyses &PassPA) {
827 if (isIgnored(P) || P == "VerifierPass")
828 return;
829 if (any_isa<const Function *>(IR) || any_isa<const Loop *>(IR)) {
830 const Function *F;
831 if (any_isa<const Loop *>(IR))
832 F = any_cast<const Loop *>(IR)->getHeader()->getParent();
833 else
834 F = any_cast<const Function *>(IR);
835 if (DebugLogging)
836 dbgs() << "Verifying function " << F->getName() << "\n";
837
838 if (verifyFunction(*F))
839 report_fatal_error("Broken function found, compilation aborted!");
840 } else if (any_isa<const Module *>(IR) ||
841 any_isa<const LazyCallGraph::SCC *>(IR)) {
842 const Module *M;
843 if (any_isa<const LazyCallGraph::SCC *>(IR))
844 M = any_cast<const LazyCallGraph::SCC *>(IR)
845 ->begin()
846 ->getFunction()
847 .getParent();
848 else
849 M = any_cast<const Module *>(IR);
850 if (DebugLogging)
851 dbgs() << "Verifying module " << M->getName() << "\n";
852
853 if (verifyModule(*M))
854 report_fatal_error("Broken module found, compilation aborted!");
855 }
856 });
857 }
858
registerCallbacks(PassInstrumentationCallbacks & PIC)859 void StandardInstrumentations::registerCallbacks(
860 PassInstrumentationCallbacks &PIC) {
861 PrintIR.registerCallbacks(PIC);
862 PrintPass.registerCallbacks(PIC);
863 TimePasses.registerCallbacks(PIC);
864 OptNone.registerCallbacks(PIC);
865 OptBisect.registerCallbacks(PIC);
866 PreservedCFGChecker.registerCallbacks(PIC);
867 PrintChangedIR.registerCallbacks(PIC);
868 if (VerifyEach)
869 Verify.registerCallbacks(PIC);
870 }
871
872 namespace llvm {
873
874 template class ChangeReporter<std::string>;
875 template class TextChangeReporter<std::string>;
876
877 } // namespace llvm
878