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