xref: /freebsd/contrib/llvm-project/llvm/lib/Passes/StandardInstrumentations.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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/StringRef.h"
18 #include "llvm/Analysis/LazyCallGraph.h"
19 #include "llvm/Analysis/LoopInfo.h"
20 #include "llvm/CodeGen/MIRPrinter.h"
21 #include "llvm/CodeGen/MachineFunction.h"
22 #include "llvm/CodeGen/MachineModuleInfo.h"
23 #include "llvm/CodeGen/MachineVerifier.h"
24 #include "llvm/IR/Constants.h"
25 #include "llvm/IR/Function.h"
26 #include "llvm/IR/Module.h"
27 #include "llvm/IR/PassInstrumentation.h"
28 #include "llvm/IR/PassManager.h"
29 #include "llvm/IR/PrintPasses.h"
30 #include "llvm/IR/StructuralHash.h"
31 #include "llvm/IR/Verifier.h"
32 #include "llvm/Support/CommandLine.h"
33 #include "llvm/Support/Debug.h"
34 #include "llvm/Support/Error.h"
35 #include "llvm/Support/FormatVariadic.h"
36 #include "llvm/Support/GraphWriter.h"
37 #include "llvm/Support/Path.h"
38 #include "llvm/Support/Program.h"
39 #include "llvm/Support/Regex.h"
40 #include "llvm/Support/Signals.h"
41 #include "llvm/Support/raw_ostream.h"
42 #include "llvm/Support/xxhash.h"
43 #include <unordered_map>
44 #include <unordered_set>
45 #include <utility>
46 #include <vector>
47 
48 using namespace llvm;
49 
50 static cl::opt<bool> VerifyAnalysisInvalidation("verify-analysis-invalidation",
51                                                 cl::Hidden,
52 #ifdef EXPENSIVE_CHECKS
53                                                 cl::init(true)
54 #else
55                                                 cl::init(false)
56 #endif
57 );
58 
59 // An option that supports the -print-changed option.  See
60 // the description for -print-changed for an explanation of the use
61 // of this option.  Note that this option has no effect without -print-changed.
62 static cl::opt<bool>
63     PrintChangedBefore("print-before-changed",
64                        cl::desc("Print before passes that change them"),
65                        cl::init(false), cl::Hidden);
66 
67 // An option for specifying the dot used by
68 // print-changed=[dot-cfg | dot-cfg-quiet]
69 static cl::opt<std::string>
70     DotBinary("print-changed-dot-path", cl::Hidden, cl::init("dot"),
71               cl::desc("system dot used by change reporters"));
72 
73 // An option that determines the colour used for elements that are only
74 // in the before part.  Must be a colour named in appendix J of
75 // https://graphviz.org/pdf/dotguide.pdf
76 static cl::opt<std::string>
77     BeforeColour("dot-cfg-before-color",
78                  cl::desc("Color for dot-cfg before elements"), cl::Hidden,
79                  cl::init("red"));
80 // An option that determines the colour used for elements that are only
81 // in the after part.  Must be a colour named in appendix J of
82 // https://graphviz.org/pdf/dotguide.pdf
83 static cl::opt<std::string>
84     AfterColour("dot-cfg-after-color",
85                 cl::desc("Color for dot-cfg after elements"), cl::Hidden,
86                 cl::init("forestgreen"));
87 // An option that determines the colour used for elements that are in both
88 // the before and after parts.  Must be a colour named in appendix J of
89 // https://graphviz.org/pdf/dotguide.pdf
90 static cl::opt<std::string>
91     CommonColour("dot-cfg-common-color",
92                  cl::desc("Color for dot-cfg common elements"), cl::Hidden,
93                  cl::init("black"));
94 
95 // An option that determines where the generated website file (named
96 // passes.html) and the associated pdf files (named diff_*.pdf) are saved.
97 static cl::opt<std::string> DotCfgDir(
98     "dot-cfg-dir",
99     cl::desc("Generate dot files into specified directory for changed IRs"),
100     cl::Hidden, cl::init("./"));
101 
102 // Options to print the IR that was being processed when a pass crashes.
103 static cl::opt<std::string> PrintOnCrashPath(
104     "print-on-crash-path",
105     cl::desc("Print the last form of the IR before crash to a file"),
106     cl::Hidden);
107 
108 static cl::opt<bool> PrintOnCrash(
109     "print-on-crash",
110     cl::desc("Print the last form of the IR before crash (use -print-on-crash-path to dump to a file)"),
111     cl::Hidden);
112 
113 static cl::opt<std::string> OptBisectPrintIRPath(
114     "opt-bisect-print-ir-path",
115     cl::desc("Print IR to path when opt-bisect-limit is reached"), cl::Hidden);
116 
117 static cl::opt<bool> PrintPassNumbers(
118     "print-pass-numbers", cl::init(false), cl::Hidden,
119     cl::desc("Print pass names and their ordinals"));
120 
121 static cl::opt<unsigned> PrintBeforePassNumber(
122     "print-before-pass-number", cl::init(0), cl::Hidden,
123     cl::desc("Print IR before the pass with this number as "
124              "reported by print-pass-numbers"));
125 
126 static cl::opt<unsigned>
127     PrintAfterPassNumber("print-after-pass-number", cl::init(0), cl::Hidden,
128                          cl::desc("Print IR after the pass with this number as "
129                                   "reported by print-pass-numbers"));
130 
131 static cl::opt<std::string> IRDumpDirectory(
132     "ir-dump-directory",
133     cl::desc("If specified, IR printed using the "
134              "-print-[before|after]{-all} options will be dumped into "
135              "files in this directory rather than written to stderr"),
136     cl::Hidden, cl::value_desc("filename"));
137 
138 static cl::opt<bool>
139     DroppedVarStats("dropped-variable-stats", cl::Hidden,
140                     cl::desc("Dump dropped debug variables stats"),
141                     cl::init(false));
142 
unwrapIR(Any IR)143 template <typename IRUnitT> static const IRUnitT *unwrapIR(Any IR) {
144   const IRUnitT **IRPtr = llvm::any_cast<const IRUnitT *>(&IR);
145   return IRPtr ? *IRPtr : nullptr;
146 }
147 
148 namespace {
149 
150 // An option for specifying an executable that will be called with the IR
151 // everytime it changes in the opt pipeline.  It will also be called on
152 // the initial IR as it enters the pipeline.  The executable will be passed
153 // the name of a temporary file containing the IR and the PassID.  This may
154 // be used, for example, to call llc on the IR and run a test to determine
155 // which pass makes a change that changes the functioning of the IR.
156 // The usual modifier options work as expected.
157 static cl::opt<std::string>
158     TestChanged("exec-on-ir-change", cl::Hidden, cl::init(""),
159                 cl::desc("exe called with module IR after each pass that "
160                          "changes it"));
161 
162 /// Extract Module out of \p IR unit. May return nullptr if \p IR does not match
163 /// certain global filters. Will never return nullptr if \p Force is true.
unwrapModule(Any IR,bool Force=false)164 const Module *unwrapModule(Any IR, bool Force = false) {
165   if (const auto *M = unwrapIR<Module>(IR))
166     return M;
167 
168   if (const auto *F = unwrapIR<Function>(IR)) {
169     if (!Force && !isFunctionInPrintList(F->getName()))
170       return nullptr;
171 
172     return F->getParent();
173   }
174 
175   if (const auto *C = unwrapIR<LazyCallGraph::SCC>(IR)) {
176     for (const LazyCallGraph::Node &N : *C) {
177       const Function &F = N.getFunction();
178       if (Force || (!F.isDeclaration() && isFunctionInPrintList(F.getName()))) {
179         return F.getParent();
180       }
181     }
182     assert(!Force && "Expected a module");
183     return nullptr;
184   }
185 
186   if (const auto *L = unwrapIR<Loop>(IR)) {
187     const Function *F = L->getHeader()->getParent();
188     if (!Force && !isFunctionInPrintList(F->getName()))
189       return nullptr;
190     return F->getParent();
191   }
192 
193   if (const auto *MF = unwrapIR<MachineFunction>(IR)) {
194     if (!Force && !isFunctionInPrintList(MF->getName()))
195       return nullptr;
196     return MF->getFunction().getParent();
197   }
198 
199   llvm_unreachable("Unknown IR unit");
200 }
201 
printIR(raw_ostream & OS,const Function * F)202 void printIR(raw_ostream &OS, const Function *F) {
203   if (!isFunctionInPrintList(F->getName()))
204     return;
205   OS << *F;
206 }
207 
printIR(raw_ostream & OS,const Module * M)208 void printIR(raw_ostream &OS, const Module *M) {
209   if (isFunctionInPrintList("*") || forcePrintModuleIR()) {
210     M->print(OS, nullptr);
211   } else {
212     for (const auto &F : M->functions()) {
213       printIR(OS, &F);
214     }
215   }
216 }
217 
printIR(raw_ostream & OS,const LazyCallGraph::SCC * C)218 void printIR(raw_ostream &OS, const LazyCallGraph::SCC *C) {
219   for (const LazyCallGraph::Node &N : *C) {
220     const Function &F = N.getFunction();
221     if (!F.isDeclaration() && isFunctionInPrintList(F.getName())) {
222       F.print(OS);
223     }
224   }
225 }
226 
printIR(raw_ostream & OS,const Loop * L)227 void printIR(raw_ostream &OS, const Loop *L) {
228   const Function *F = L->getHeader()->getParent();
229   if (!isFunctionInPrintList(F->getName()))
230     return;
231   printLoop(const_cast<Loop &>(*L), OS);
232 }
233 
printIR(raw_ostream & OS,const MachineFunction * MF)234 void printIR(raw_ostream &OS, const MachineFunction *MF) {
235   if (!isFunctionInPrintList(MF->getName()))
236     return;
237   MF->print(OS);
238 }
239 
getIRName(Any IR)240 std::string getIRName(Any IR) {
241   if (unwrapIR<Module>(IR))
242     return "[module]";
243 
244   if (const auto *F = unwrapIR<Function>(IR))
245     return F->getName().str();
246 
247   if (const auto *C = unwrapIR<LazyCallGraph::SCC>(IR))
248     return C->getName();
249 
250   if (const auto *L = unwrapIR<Loop>(IR))
251     return "loop %" + L->getName().str() + " in function " +
252            L->getHeader()->getParent()->getName().str();
253 
254   if (const auto *MF = unwrapIR<MachineFunction>(IR))
255     return MF->getName().str();
256 
257   llvm_unreachable("Unknown wrapped IR type");
258 }
259 
moduleContainsFilterPrintFunc(const Module & M)260 bool moduleContainsFilterPrintFunc(const Module &M) {
261   return any_of(M.functions(),
262                 [](const Function &F) {
263                   return isFunctionInPrintList(F.getName());
264                 }) ||
265          isFunctionInPrintList("*");
266 }
267 
sccContainsFilterPrintFunc(const LazyCallGraph::SCC & C)268 bool sccContainsFilterPrintFunc(const LazyCallGraph::SCC &C) {
269   return any_of(C,
270                 [](const LazyCallGraph::Node &N) {
271                   return isFunctionInPrintList(N.getName());
272                 }) ||
273          isFunctionInPrintList("*");
274 }
275 
shouldPrintIR(Any IR)276 bool shouldPrintIR(Any IR) {
277   if (const auto *M = unwrapIR<Module>(IR))
278     return moduleContainsFilterPrintFunc(*M);
279 
280   if (const auto *F = unwrapIR<Function>(IR))
281     return isFunctionInPrintList(F->getName());
282 
283   if (const auto *C = unwrapIR<LazyCallGraph::SCC>(IR))
284     return sccContainsFilterPrintFunc(*C);
285 
286   if (const auto *L = unwrapIR<Loop>(IR))
287     return isFunctionInPrintList(L->getHeader()->getParent()->getName());
288 
289   if (const auto *MF = unwrapIR<MachineFunction>(IR))
290     return isFunctionInPrintList(MF->getName());
291   llvm_unreachable("Unknown wrapped IR type");
292 }
293 
294 /// Generic IR-printing helper that unpacks a pointer to IRUnit wrapped into
295 /// Any and does actual print job.
unwrapAndPrint(raw_ostream & OS,Any IR)296 void unwrapAndPrint(raw_ostream &OS, Any IR) {
297   if (!shouldPrintIR(IR))
298     return;
299 
300   if (forcePrintModuleIR()) {
301     auto *M = unwrapModule(IR);
302     assert(M && "should have unwrapped module");
303     printIR(OS, M);
304     return;
305   }
306 
307   if (const auto *M = unwrapIR<Module>(IR)) {
308     printIR(OS, M);
309     return;
310   }
311 
312   if (const auto *F = unwrapIR<Function>(IR)) {
313     printIR(OS, F);
314     return;
315   }
316 
317   if (const auto *C = unwrapIR<LazyCallGraph::SCC>(IR)) {
318     printIR(OS, C);
319     return;
320   }
321 
322   if (const auto *L = unwrapIR<Loop>(IR)) {
323     printIR(OS, L);
324     return;
325   }
326 
327   if (const auto *MF = unwrapIR<MachineFunction>(IR)) {
328     printIR(OS, MF);
329     return;
330   }
331   llvm_unreachable("Unknown wrapped IR type");
332 }
333 
334 // Return true when this is a pass for which changes should be ignored
isIgnored(StringRef PassID)335 bool isIgnored(StringRef PassID) {
336   return isSpecialPass(PassID,
337                        {"PassManager", "PassAdaptor", "AnalysisManagerProxy",
338                         "DevirtSCCRepeatedPass", "ModuleInlinerWrapperPass",
339                         "VerifierPass", "PrintModulePass", "PrintMIRPass",
340                         "PrintMIRPreparePass"});
341 }
342 
makeHTMLReady(StringRef SR)343 std::string makeHTMLReady(StringRef SR) {
344   std::string S;
345   while (true) {
346     StringRef Clean =
347         SR.take_until([](char C) { return C == '<' || C == '>'; });
348     S.append(Clean.str());
349     SR = SR.drop_front(Clean.size());
350     if (SR.size() == 0)
351       return S;
352     S.append(SR[0] == '<' ? "&lt;" : "&gt;");
353     SR = SR.drop_front();
354   }
355   llvm_unreachable("problems converting string to HTML");
356 }
357 
358 // Return the module when that is the appropriate level of comparison for \p IR.
getModuleForComparison(Any IR)359 const Module *getModuleForComparison(Any IR) {
360   if (const auto *M = unwrapIR<Module>(IR))
361     return M;
362   if (const auto *C = unwrapIR<LazyCallGraph::SCC>(IR))
363     return C->begin()->getFunction().getParent();
364   return nullptr;
365 }
366 
isInterestingFunction(const Function & F)367 bool isInterestingFunction(const Function &F) {
368   return isFunctionInPrintList(F.getName());
369 }
370 
371 // Return true when this is a pass on IR for which printing
372 // of changes is desired.
isInteresting(Any IR,StringRef PassID,StringRef PassName)373 bool isInteresting(Any IR, StringRef PassID, StringRef PassName) {
374   if (isIgnored(PassID) || !isPassInPrintList(PassName))
375     return false;
376   if (const auto *F = unwrapIR<Function>(IR))
377     return isInterestingFunction(*F);
378   return true;
379 }
380 
381 } // namespace
382 
~ChangeReporter()383 template <typename T> ChangeReporter<T>::~ChangeReporter() {
384   assert(BeforeStack.empty() && "Problem with Change Printer stack.");
385 }
386 
387 template <typename T>
saveIRBeforePass(Any IR,StringRef PassID,StringRef PassName)388 void ChangeReporter<T>::saveIRBeforePass(Any IR, StringRef PassID,
389                                          StringRef PassName) {
390   // Is this the initial IR?
391   if (InitialIR) {
392     InitialIR = false;
393     if (VerboseMode)
394       handleInitialIR(IR);
395   }
396 
397   // Always need to place something on the stack because invalidated passes
398   // are not given the IR so it cannot be determined whether the pass was for
399   // something that was filtered out.
400   BeforeStack.emplace_back();
401 
402   if (!isInteresting(IR, PassID, PassName))
403     return;
404 
405   // Save the IR representation on the stack.
406   T &Data = BeforeStack.back();
407   generateIRRepresentation(IR, PassID, Data);
408 }
409 
410 template <typename T>
handleIRAfterPass(Any IR,StringRef PassID,StringRef PassName)411 void ChangeReporter<T>::handleIRAfterPass(Any IR, StringRef PassID,
412                                           StringRef PassName) {
413   assert(!BeforeStack.empty() && "Unexpected empty stack encountered.");
414 
415   std::string Name = getIRName(IR);
416 
417   if (isIgnored(PassID)) {
418     if (VerboseMode)
419       handleIgnored(PassID, Name);
420   } else if (!isInteresting(IR, PassID, PassName)) {
421     if (VerboseMode)
422       handleFiltered(PassID, Name);
423   } else {
424     // Get the before rep from the stack
425     T &Before = BeforeStack.back();
426     // Create the after rep
427     T After;
428     generateIRRepresentation(IR, PassID, After);
429 
430     // Was there a change in IR?
431     if (Before == After) {
432       if (VerboseMode)
433         omitAfter(PassID, Name);
434     } else
435       handleAfter(PassID, Name, Before, After, IR);
436   }
437   BeforeStack.pop_back();
438 }
439 
440 template <typename T>
handleInvalidatedPass(StringRef PassID)441 void ChangeReporter<T>::handleInvalidatedPass(StringRef PassID) {
442   assert(!BeforeStack.empty() && "Unexpected empty stack encountered.");
443 
444   // Always flag it as invalidated as we cannot determine when
445   // a pass for a filtered function is invalidated since we do not
446   // get the IR in the call.  Also, the output is just alternate
447   // forms of the banner anyway.
448   if (VerboseMode)
449     handleInvalidated(PassID);
450   BeforeStack.pop_back();
451 }
452 
453 template <typename T>
registerRequiredCallbacks(PassInstrumentationCallbacks & PIC)454 void ChangeReporter<T>::registerRequiredCallbacks(
455     PassInstrumentationCallbacks &PIC) {
456   PIC.registerBeforeNonSkippedPassCallback([&PIC, this](StringRef P, Any IR) {
457     saveIRBeforePass(IR, P, PIC.getPassNameForClassName(P));
458   });
459 
460   PIC.registerAfterPassCallback(
461       [&PIC, this](StringRef P, Any IR, const PreservedAnalyses &) {
462         handleIRAfterPass(IR, P, PIC.getPassNameForClassName(P));
463       });
464   PIC.registerAfterPassInvalidatedCallback(
465       [this](StringRef P, const PreservedAnalyses &) {
466         handleInvalidatedPass(P);
467       });
468 }
469 
470 template <typename T>
TextChangeReporter(bool Verbose)471 TextChangeReporter<T>::TextChangeReporter(bool Verbose)
472     : ChangeReporter<T>(Verbose), Out(dbgs()) {}
473 
handleInitialIR(Any IR)474 template <typename T> void TextChangeReporter<T>::handleInitialIR(Any IR) {
475   // Always print the module.
476   // Unwrap and print directly to avoid filtering problems in general routines.
477   auto *M = unwrapModule(IR, /*Force=*/true);
478   assert(M && "Expected module to be unwrapped when forced.");
479   Out << "*** IR Dump At Start ***\n";
480   M->print(Out, nullptr);
481 }
482 
483 template <typename T>
omitAfter(StringRef PassID,std::string & Name)484 void TextChangeReporter<T>::omitAfter(StringRef PassID, std::string &Name) {
485   Out << formatv("*** IR Dump After {0} on {1} omitted because no change ***\n",
486                  PassID, Name);
487 }
488 
489 template <typename T>
handleInvalidated(StringRef PassID)490 void TextChangeReporter<T>::handleInvalidated(StringRef PassID) {
491   Out << formatv("*** IR Pass {0} invalidated ***\n", PassID);
492 }
493 
494 template <typename T>
handleFiltered(StringRef PassID,std::string & Name)495 void TextChangeReporter<T>::handleFiltered(StringRef PassID,
496                                            std::string &Name) {
497   SmallString<20> Banner =
498       formatv("*** IR Dump After {0} on {1} filtered out ***\n", PassID, Name);
499   Out << Banner;
500 }
501 
502 template <typename T>
handleIgnored(StringRef PassID,std::string & Name)503 void TextChangeReporter<T>::handleIgnored(StringRef PassID, std::string &Name) {
504   Out << formatv("*** IR Pass {0} on {1} ignored ***\n", PassID, Name);
505 }
506 
507 IRChangedPrinter::~IRChangedPrinter() = default;
508 
registerCallbacks(PassInstrumentationCallbacks & PIC)509 void IRChangedPrinter::registerCallbacks(PassInstrumentationCallbacks &PIC) {
510   if (PrintChanged == ChangePrinter::Verbose ||
511       PrintChanged == ChangePrinter::Quiet)
512     TextChangeReporter<std::string>::registerRequiredCallbacks(PIC);
513 }
514 
generateIRRepresentation(Any IR,StringRef PassID,std::string & Output)515 void IRChangedPrinter::generateIRRepresentation(Any IR, StringRef PassID,
516                                                 std::string &Output) {
517   raw_string_ostream OS(Output);
518   unwrapAndPrint(OS, IR);
519   OS.str();
520 }
521 
handleAfter(StringRef PassID,std::string & Name,const std::string & Before,const std::string & After,Any)522 void IRChangedPrinter::handleAfter(StringRef PassID, std::string &Name,
523                                    const std::string &Before,
524                                    const std::string &After, Any) {
525   // Report the IR before the changes when requested.
526   if (PrintChangedBefore)
527     Out << "*** IR Dump Before " << PassID << " on " << Name << " ***\n"
528         << Before;
529 
530   // We might not get anything to print if we only want to print a specific
531   // function but it gets deleted.
532   if (After.empty()) {
533     Out << "*** IR Deleted After " << PassID << " on " << Name << " ***\n";
534     return;
535   }
536 
537   Out << "*** IR Dump After " << PassID << " on " << Name << " ***\n" << After;
538 }
539 
~IRChangedTester()540 IRChangedTester::~IRChangedTester() {}
541 
registerCallbacks(PassInstrumentationCallbacks & PIC)542 void IRChangedTester::registerCallbacks(PassInstrumentationCallbacks &PIC) {
543   if (TestChanged != "")
544     TextChangeReporter<std::string>::registerRequiredCallbacks(PIC);
545 }
546 
handleIR(const std::string & S,StringRef PassID)547 void IRChangedTester::handleIR(const std::string &S, StringRef PassID) {
548   // Store the body into a temporary file
549   static SmallVector<int> FD{-1};
550   SmallVector<StringRef> SR{S};
551   static SmallVector<std::string> FileName{""};
552   if (prepareTempFiles(FD, SR, FileName)) {
553     dbgs() << "Unable to create temporary file.";
554     return;
555   }
556   static ErrorOr<std::string> Exe = sys::findProgramByName(TestChanged);
557   if (!Exe) {
558     dbgs() << "Unable to find test-changed executable.";
559     return;
560   }
561 
562   StringRef Args[] = {TestChanged, FileName[0], PassID};
563   int Result = sys::ExecuteAndWait(*Exe, Args);
564   if (Result < 0) {
565     dbgs() << "Error executing test-changed executable.";
566     return;
567   }
568 
569   if (cleanUpTempFiles(FileName))
570     dbgs() << "Unable to remove temporary file.";
571 }
572 
handleInitialIR(Any IR)573 void IRChangedTester::handleInitialIR(Any IR) {
574   // Always test the initial module.
575   // Unwrap and print directly to avoid filtering problems in general routines.
576   std::string S;
577   generateIRRepresentation(IR, "Initial IR", S);
578   handleIR(S, "Initial IR");
579 }
580 
omitAfter(StringRef PassID,std::string & Name)581 void IRChangedTester::omitAfter(StringRef PassID, std::string &Name) {}
handleInvalidated(StringRef PassID)582 void IRChangedTester::handleInvalidated(StringRef PassID) {}
handleFiltered(StringRef PassID,std::string & Name)583 void IRChangedTester::handleFiltered(StringRef PassID, std::string &Name) {}
handleIgnored(StringRef PassID,std::string & Name)584 void IRChangedTester::handleIgnored(StringRef PassID, std::string &Name) {}
handleAfter(StringRef PassID,std::string & Name,const std::string & Before,const std::string & After,Any)585 void IRChangedTester::handleAfter(StringRef PassID, std::string &Name,
586                                   const std::string &Before,
587                                   const std::string &After, Any) {
588   handleIR(After, PassID);
589 }
590 
591 template <typename T>
report(const OrderedChangedData & Before,const OrderedChangedData & After,function_ref<void (const T *,const T *)> HandlePair)592 void OrderedChangedData<T>::report(
593     const OrderedChangedData &Before, const OrderedChangedData &After,
594     function_ref<void(const T *, const T *)> HandlePair) {
595   const auto &BFD = Before.getData();
596   const auto &AFD = After.getData();
597   std::vector<std::string>::const_iterator BI = Before.getOrder().begin();
598   std::vector<std::string>::const_iterator BE = Before.getOrder().end();
599   std::vector<std::string>::const_iterator AI = After.getOrder().begin();
600   std::vector<std::string>::const_iterator AE = After.getOrder().end();
601 
602   auto HandlePotentiallyRemovedData = [&](std::string S) {
603     // The order in LLVM may have changed so check if still exists.
604     if (!AFD.count(S)) {
605       // This has been removed.
606       HandlePair(&BFD.find(*BI)->getValue(), nullptr);
607     }
608   };
609   auto HandleNewData = [&](std::vector<const T *> &Q) {
610     // Print out any queued up new sections
611     for (const T *NBI : Q)
612       HandlePair(nullptr, NBI);
613     Q.clear();
614   };
615 
616   // Print out the data in the after order, with before ones interspersed
617   // appropriately (ie, somewhere near where they were in the before list).
618   // Start at the beginning of both lists.  Loop through the
619   // after list.  If an element is common, then advance in the before list
620   // reporting the removed ones until the common one is reached.  Report any
621   // queued up new ones and then report the common one.  If an element is not
622   // common, then enqueue it for reporting.  When the after list is exhausted,
623   // loop through the before list, reporting any removed ones.  Finally,
624   // report the rest of the enqueued new ones.
625   std::vector<const T *> NewDataQueue;
626   while (AI != AE) {
627     if (!BFD.count(*AI)) {
628       // This section is new so place it in the queue.  This will cause it
629       // to be reported after deleted sections.
630       NewDataQueue.emplace_back(&AFD.find(*AI)->getValue());
631       ++AI;
632       continue;
633     }
634     // This section is in both; advance and print out any before-only
635     // until we get to it.
636     // It's possible that this section has moved to be later than before. This
637     // will mess up printing most blocks side by side, but it's a rare case and
638     // it's better than crashing.
639     while (BI != BE && *BI != *AI) {
640       HandlePotentiallyRemovedData(*BI);
641       ++BI;
642     }
643     // Report any new sections that were queued up and waiting.
644     HandleNewData(NewDataQueue);
645 
646     const T &AData = AFD.find(*AI)->getValue();
647     const T &BData = BFD.find(*AI)->getValue();
648     HandlePair(&BData, &AData);
649     if (BI != BE)
650       ++BI;
651     ++AI;
652   }
653 
654   // Check any remaining before sections to see if they have been removed
655   while (BI != BE) {
656     HandlePotentiallyRemovedData(*BI);
657     ++BI;
658   }
659 
660   HandleNewData(NewDataQueue);
661 }
662 
663 template <typename T>
compare(bool CompareModule,std::function<void (bool InModule,unsigned Minor,const FuncDataT<T> & Before,const FuncDataT<T> & After)> CompareFunc)664 void IRComparer<T>::compare(
665     bool CompareModule,
666     std::function<void(bool InModule, unsigned Minor,
667                        const FuncDataT<T> &Before, const FuncDataT<T> &After)>
668         CompareFunc) {
669   if (!CompareModule) {
670     // Just handle the single function.
671     assert(Before.getData().size() == 1 && After.getData().size() == 1 &&
672            "Expected only one function.");
673     CompareFunc(false, 0, Before.getData().begin()->getValue(),
674                 After.getData().begin()->getValue());
675     return;
676   }
677 
678   unsigned Minor = 0;
679   FuncDataT<T> Missing("");
680   IRDataT<T>::report(Before, After,
681                      [&](const FuncDataT<T> *B, const FuncDataT<T> *A) {
682                        assert((B || A) && "Both functions cannot be missing.");
683                        if (!B)
684                          B = &Missing;
685                        else if (!A)
686                          A = &Missing;
687                        CompareFunc(true, Minor++, *B, *A);
688                      });
689 }
690 
analyzeIR(Any IR,IRDataT<T> & Data)691 template <typename T> void IRComparer<T>::analyzeIR(Any IR, IRDataT<T> &Data) {
692   if (const Module *M = getModuleForComparison(IR)) {
693     // Create data for each existing/interesting function in the module.
694     for (const Function &F : *M)
695       generateFunctionData(Data, F);
696     return;
697   }
698 
699   if (const auto *F = unwrapIR<Function>(IR)) {
700     generateFunctionData(Data, *F);
701     return;
702   }
703 
704   if (const auto *L = unwrapIR<Loop>(IR)) {
705     auto *F = L->getHeader()->getParent();
706     generateFunctionData(Data, *F);
707     return;
708   }
709 
710   if (const auto *MF = unwrapIR<MachineFunction>(IR)) {
711     generateFunctionData(Data, *MF);
712     return;
713   }
714 
715   llvm_unreachable("Unknown IR unit");
716 }
717 
shouldGenerateData(const Function & F)718 static bool shouldGenerateData(const Function &F) {
719   return !F.isDeclaration() && isFunctionInPrintList(F.getName());
720 }
721 
shouldGenerateData(const MachineFunction & MF)722 static bool shouldGenerateData(const MachineFunction &MF) {
723   return isFunctionInPrintList(MF.getName());
724 }
725 
726 template <typename T>
727 template <typename FunctionT>
generateFunctionData(IRDataT<T> & Data,const FunctionT & F)728 bool IRComparer<T>::generateFunctionData(IRDataT<T> &Data, const FunctionT &F) {
729   if (shouldGenerateData(F)) {
730     FuncDataT<T> FD(F.front().getName().str());
731     int I = 0;
732     for (const auto &B : F) {
733       std::string BBName = B.getName().str();
734       if (BBName.empty()) {
735         BBName = formatv("{0}", I);
736         ++I;
737       }
738       FD.getOrder().emplace_back(BBName);
739       FD.getData().insert({BBName, B});
740     }
741     Data.getOrder().emplace_back(F.getName());
742     Data.getData().insert({F.getName(), FD});
743     return true;
744   }
745   return false;
746 }
747 
~PrintIRInstrumentation()748 PrintIRInstrumentation::~PrintIRInstrumentation() {
749   assert(PassRunDescriptorStack.empty() &&
750          "PassRunDescriptorStack is not empty at exit");
751 }
752 
writeIRFileDisplayName(raw_ostream & ResultStream,Any IR)753 static void writeIRFileDisplayName(raw_ostream &ResultStream, Any IR) {
754   const Module *M = unwrapModule(IR, /*Force=*/true);
755   assert(M && "should have unwrapped module");
756   uint64_t NameHash = xxh3_64bits(M->getName());
757   unsigned MaxHashWidth = sizeof(uint64_t) * 2;
758   write_hex(ResultStream, NameHash, HexPrintStyle::Lower, MaxHashWidth);
759   if (unwrapIR<Module>(IR)) {
760     ResultStream << "-module";
761   } else if (const auto *F = unwrapIR<Function>(IR)) {
762     ResultStream << "-function-";
763     auto FunctionNameHash = xxh3_64bits(F->getName());
764     write_hex(ResultStream, FunctionNameHash, HexPrintStyle::Lower,
765               MaxHashWidth);
766   } else if (const auto *C = unwrapIR<LazyCallGraph::SCC>(IR)) {
767     ResultStream << "-scc-";
768     auto SCCNameHash = xxh3_64bits(C->getName());
769     write_hex(ResultStream, SCCNameHash, HexPrintStyle::Lower, MaxHashWidth);
770   } else if (const auto *L = unwrapIR<Loop>(IR)) {
771     ResultStream << "-loop-";
772     auto LoopNameHash = xxh3_64bits(L->getName());
773     write_hex(ResultStream, LoopNameHash, HexPrintStyle::Lower, MaxHashWidth);
774   } else if (const auto *MF = unwrapIR<MachineFunction>(IR)) {
775     ResultStream << "-machine-function-";
776     auto MachineFunctionNameHash = xxh3_64bits(MF->getName());
777     write_hex(ResultStream, MachineFunctionNameHash, HexPrintStyle::Lower,
778               MaxHashWidth);
779   } else {
780     llvm_unreachable("Unknown wrapped IR type");
781   }
782 }
783 
getIRFileDisplayName(Any IR)784 static std::string getIRFileDisplayName(Any IR) {
785   std::string Result;
786   raw_string_ostream ResultStream(Result);
787   writeIRFileDisplayName(ResultStream, IR);
788   return Result;
789 }
790 
getFileSuffix(IRDumpFileSuffixType Type)791 StringRef PrintIRInstrumentation::getFileSuffix(IRDumpFileSuffixType Type) {
792   static constexpr std::array FileSuffixes = {"-before.ll", "-after.ll",
793                                               "-invalidated.ll"};
794   return FileSuffixes[static_cast<size_t>(Type)];
795 }
796 
fetchDumpFilename(StringRef PassName,StringRef IRFileDisplayName,unsigned PassNumber,IRDumpFileSuffixType SuffixType)797 std::string PrintIRInstrumentation::fetchDumpFilename(
798     StringRef PassName, StringRef IRFileDisplayName, unsigned PassNumber,
799     IRDumpFileSuffixType SuffixType) {
800   assert(!IRDumpDirectory.empty() &&
801          "The flag -ir-dump-directory must be passed to dump IR to files");
802 
803   SmallString<64> Filename;
804   raw_svector_ostream FilenameStream(Filename);
805   FilenameStream << PassNumber;
806   FilenameStream << '-' << IRFileDisplayName << '-';
807   FilenameStream << PassName;
808   FilenameStream << getFileSuffix(SuffixType);
809 
810   SmallString<128> ResultPath;
811   sys::path::append(ResultPath, IRDumpDirectory, Filename);
812   return std::string(ResultPath);
813 }
814 
pushPassRunDescriptor(StringRef PassID,Any IR,unsigned PassNumber)815 void PrintIRInstrumentation::pushPassRunDescriptor(StringRef PassID, Any IR,
816                                                    unsigned PassNumber) {
817   const Module *M = unwrapModule(IR);
818   PassRunDescriptorStack.emplace_back(M, PassNumber, getIRFileDisplayName(IR),
819                                       getIRName(IR), PassID);
820 }
821 
822 PrintIRInstrumentation::PassRunDescriptor
popPassRunDescriptor(StringRef PassID)823 PrintIRInstrumentation::popPassRunDescriptor(StringRef PassID) {
824   assert(!PassRunDescriptorStack.empty() && "empty PassRunDescriptorStack");
825   PassRunDescriptor Descriptor = PassRunDescriptorStack.pop_back_val();
826   assert(Descriptor.PassID == PassID && "malformed PassRunDescriptorStack");
827   return Descriptor;
828 }
829 
830 // Callers are responsible for closing the returned file descriptor
prepareDumpIRFileDescriptor(const StringRef DumpIRFilename)831 static int prepareDumpIRFileDescriptor(const StringRef DumpIRFilename) {
832   std::error_code EC;
833   auto ParentPath = llvm::sys::path::parent_path(DumpIRFilename);
834   if (!ParentPath.empty()) {
835     std::error_code EC = llvm::sys::fs::create_directories(ParentPath);
836     if (EC)
837       report_fatal_error(Twine("Failed to create directory ") + ParentPath +
838                          " to support -ir-dump-directory: " + EC.message());
839   }
840   int Result = 0;
841   EC = sys::fs::openFile(DumpIRFilename, Result, sys::fs::CD_OpenAlways,
842                          sys::fs::FA_Write, sys::fs::OF_Text);
843   if (EC)
844     report_fatal_error(Twine("Failed to open ") + DumpIRFilename +
845                        " to support -ir-dump-directory: " + EC.message());
846   return Result;
847 }
848 
printBeforePass(StringRef PassID,Any IR)849 void PrintIRInstrumentation::printBeforePass(StringRef PassID, Any IR) {
850   if (isIgnored(PassID))
851     return;
852 
853   // Saving Module for AfterPassInvalidated operations.
854   // Note: here we rely on a fact that we do not change modules while
855   // traversing the pipeline, so the latest captured module is good
856   // for all print operations that has not happen yet.
857   if (shouldPrintAfterPass(PassID))
858     pushPassRunDescriptor(PassID, IR, CurrentPassNumber);
859 
860   if (!shouldPrintIR(IR))
861     return;
862 
863   ++CurrentPassNumber;
864 
865   if (shouldPrintPassNumbers())
866     dbgs() << " Running pass " << CurrentPassNumber << " " << PassID
867            << " on " << getIRName(IR) << "\n";
868 
869   if (shouldPrintAfterCurrentPassNumber())
870     pushPassRunDescriptor(PassID, IR, CurrentPassNumber);
871 
872   if (!shouldPrintBeforePass(PassID) && !shouldPrintBeforeCurrentPassNumber())
873     return;
874 
875   auto WriteIRToStream = [&](raw_ostream &Stream) {
876     Stream << "; *** IR Dump Before ";
877     if (shouldPrintBeforeSomePassNumber())
878       Stream << CurrentPassNumber << "-";
879     Stream << PassID << " on " << getIRName(IR) << " ***\n";
880     unwrapAndPrint(Stream, IR);
881   };
882 
883   if (!IRDumpDirectory.empty()) {
884     std::string DumpIRFilename =
885         fetchDumpFilename(PassID, getIRFileDisplayName(IR), CurrentPassNumber,
886                           IRDumpFileSuffixType::Before);
887     llvm::raw_fd_ostream DumpIRFileStream{
888         prepareDumpIRFileDescriptor(DumpIRFilename), /* shouldClose */ true};
889     WriteIRToStream(DumpIRFileStream);
890   } else {
891     WriteIRToStream(dbgs());
892   }
893 }
894 
printAfterPass(StringRef PassID,Any IR)895 void PrintIRInstrumentation::printAfterPass(StringRef PassID, Any IR) {
896   if (isIgnored(PassID))
897     return;
898 
899   if (!shouldPrintAfterPass(PassID) && !shouldPrintAfterCurrentPassNumber())
900     return;
901 
902   auto [M, PassNumber, IRFileDisplayName, IRName, StoredPassID] =
903       popPassRunDescriptor(PassID);
904   assert(StoredPassID == PassID && "mismatched PassID");
905 
906   if (!shouldPrintIR(IR) ||
907       (!shouldPrintAfterPass(PassID) && !shouldPrintAfterCurrentPassNumber()))
908     return;
909 
910   auto WriteIRToStream = [&](raw_ostream &Stream, const StringRef IRName) {
911     Stream << "; *** IR Dump After ";
912     if (shouldPrintAfterSomePassNumber())
913       Stream << CurrentPassNumber << "-";
914     Stream << StringRef(formatv("{0}", PassID)) << " on " << IRName << " ***\n";
915     unwrapAndPrint(Stream, IR);
916   };
917 
918   if (!IRDumpDirectory.empty()) {
919     std::string DumpIRFilename =
920         fetchDumpFilename(PassID, getIRFileDisplayName(IR), CurrentPassNumber,
921                           IRDumpFileSuffixType::After);
922     llvm::raw_fd_ostream DumpIRFileStream{
923         prepareDumpIRFileDescriptor(DumpIRFilename),
924         /* shouldClose */ true};
925     WriteIRToStream(DumpIRFileStream, IRName);
926   } else {
927     WriteIRToStream(dbgs(), IRName);
928   }
929 }
930 
printAfterPassInvalidated(StringRef PassID)931 void PrintIRInstrumentation::printAfterPassInvalidated(StringRef PassID) {
932   if (isIgnored(PassID))
933     return;
934 
935   if (!shouldPrintAfterPass(PassID) && !shouldPrintAfterCurrentPassNumber())
936     return;
937 
938   auto [M, PassNumber, IRFileDisplayName, IRName, StoredPassID] =
939       popPassRunDescriptor(PassID);
940   assert(StoredPassID == PassID && "mismatched PassID");
941   // Additional filtering (e.g. -filter-print-func) can lead to module
942   // printing being skipped.
943   if (!M ||
944       (!shouldPrintAfterPass(PassID) && !shouldPrintAfterCurrentPassNumber()))
945     return;
946 
947   auto WriteIRToStream = [&](raw_ostream &Stream, const Module *M,
948                              const StringRef IRName) {
949     SmallString<20> Banner;
950     Banner = formatv("; *** IR Dump After {0} on {1} (invalidated) ***", PassID,
951                      IRName);
952     Stream << Banner << "\n";
953     printIR(Stream, M);
954   };
955 
956   if (!IRDumpDirectory.empty()) {
957     std::string DumpIRFilename =
958         fetchDumpFilename(PassID, IRFileDisplayName, PassNumber,
959                           IRDumpFileSuffixType::Invalidated);
960     llvm::raw_fd_ostream DumpIRFileStream{
961         prepareDumpIRFileDescriptor(DumpIRFilename),
962         /*shouldClose=*/true};
963     WriteIRToStream(DumpIRFileStream, M, IRName);
964   } else {
965     WriteIRToStream(dbgs(), M, IRName);
966   }
967 }
968 
shouldPrintBeforePass(StringRef PassID)969 bool PrintIRInstrumentation::shouldPrintBeforePass(StringRef PassID) {
970   if (shouldPrintBeforeAll())
971     return true;
972 
973   StringRef PassName = PIC->getPassNameForClassName(PassID);
974   return is_contained(printBeforePasses(), PassName);
975 }
976 
shouldPrintAfterPass(StringRef PassID)977 bool PrintIRInstrumentation::shouldPrintAfterPass(StringRef PassID) {
978   if (shouldPrintAfterAll())
979     return true;
980 
981   StringRef PassName = PIC->getPassNameForClassName(PassID);
982   return is_contained(printAfterPasses(), PassName);
983 }
984 
shouldPrintBeforeCurrentPassNumber()985 bool PrintIRInstrumentation::shouldPrintBeforeCurrentPassNumber() {
986   return shouldPrintBeforeSomePassNumber() &&
987          (CurrentPassNumber == PrintBeforePassNumber);
988 }
989 
shouldPrintAfterCurrentPassNumber()990 bool PrintIRInstrumentation::shouldPrintAfterCurrentPassNumber() {
991   return shouldPrintAfterSomePassNumber() &&
992          (CurrentPassNumber == PrintAfterPassNumber);
993 }
994 
shouldPrintPassNumbers()995 bool PrintIRInstrumentation::shouldPrintPassNumbers() {
996   return PrintPassNumbers;
997 }
998 
shouldPrintBeforeSomePassNumber()999 bool PrintIRInstrumentation::shouldPrintBeforeSomePassNumber() {
1000   return PrintBeforePassNumber > 0;
1001 }
1002 
shouldPrintAfterSomePassNumber()1003 bool PrintIRInstrumentation::shouldPrintAfterSomePassNumber() {
1004   return PrintAfterPassNumber > 0;
1005 }
1006 
registerCallbacks(PassInstrumentationCallbacks & PIC)1007 void PrintIRInstrumentation::registerCallbacks(
1008     PassInstrumentationCallbacks &PIC) {
1009   this->PIC = &PIC;
1010 
1011   // BeforePass callback is not just for printing, it also saves a Module
1012   // for later use in AfterPassInvalidated and keeps tracks of the
1013   // CurrentPassNumber.
1014   if (shouldPrintPassNumbers() || shouldPrintBeforeSomePassNumber() ||
1015       shouldPrintAfterSomePassNumber() || shouldPrintBeforeSomePass() ||
1016       shouldPrintAfterSomePass())
1017     PIC.registerBeforeNonSkippedPassCallback(
1018         [this](StringRef P, Any IR) { this->printBeforePass(P, IR); });
1019 
1020   if (shouldPrintAfterSomePass() || shouldPrintAfterSomePassNumber()) {
1021     PIC.registerAfterPassCallback(
1022         [this](StringRef P, Any IR, const PreservedAnalyses &) {
1023           this->printAfterPass(P, IR);
1024         });
1025     PIC.registerAfterPassInvalidatedCallback(
1026         [this](StringRef P, const PreservedAnalyses &) {
1027           this->printAfterPassInvalidated(P);
1028         });
1029   }
1030 }
1031 
registerCallbacks(PassInstrumentationCallbacks & PIC)1032 void OptNoneInstrumentation::registerCallbacks(
1033     PassInstrumentationCallbacks &PIC) {
1034   PIC.registerShouldRunOptionalPassCallback(
1035       [this](StringRef P, Any IR) { return this->shouldRun(P, IR); });
1036 }
1037 
shouldRun(StringRef PassID,Any IR)1038 bool OptNoneInstrumentation::shouldRun(StringRef PassID, Any IR) {
1039   bool ShouldRun = true;
1040   if (const auto *F = unwrapIR<Function>(IR))
1041     ShouldRun = !F->hasOptNone();
1042   else if (const auto *L = unwrapIR<Loop>(IR))
1043     ShouldRun = !L->getHeader()->getParent()->hasOptNone();
1044   else if (const auto *MF = unwrapIR<MachineFunction>(IR))
1045     ShouldRun = !MF->getFunction().hasOptNone();
1046 
1047   if (!ShouldRun && DebugLogging) {
1048     errs() << "Skipping pass " << PassID << " on " << getIRName(IR)
1049            << " due to optnone attribute\n";
1050   }
1051   return ShouldRun;
1052 }
1053 
shouldRun(StringRef PassName,Any IR)1054 bool OptPassGateInstrumentation::shouldRun(StringRef PassName, Any IR) {
1055   if (isIgnored(PassName))
1056     return true;
1057 
1058   bool ShouldRun =
1059       Context.getOptPassGate().shouldRunPass(PassName, getIRName(IR));
1060   if (!ShouldRun && !this->HasWrittenIR && !OptBisectPrintIRPath.empty()) {
1061     // FIXME: print IR if limit is higher than number of opt-bisect
1062     // invocations
1063     this->HasWrittenIR = true;
1064     const Module *M = unwrapModule(IR, /*Force=*/true);
1065     assert((M && &M->getContext() == &Context) && "Missing/Mismatching Module");
1066     std::error_code EC;
1067     raw_fd_ostream OS(OptBisectPrintIRPath, EC);
1068     if (EC)
1069       report_fatal_error(errorCodeToError(EC));
1070     M->print(OS, nullptr);
1071   }
1072   return ShouldRun;
1073 }
1074 
registerCallbacks(PassInstrumentationCallbacks & PIC)1075 void OptPassGateInstrumentation::registerCallbacks(
1076     PassInstrumentationCallbacks &PIC) {
1077   const OptPassGate &PassGate = Context.getOptPassGate();
1078   if (!PassGate.isEnabled())
1079     return;
1080 
1081   PIC.registerShouldRunOptionalPassCallback([this](StringRef PassName, Any IR) {
1082     return this->shouldRun(PassName, IR);
1083   });
1084 }
1085 
print()1086 raw_ostream &PrintPassInstrumentation::print() {
1087   if (Opts.Indent) {
1088     assert(Indent >= 0);
1089     dbgs().indent(Indent);
1090   }
1091   return dbgs();
1092 }
1093 
registerCallbacks(PassInstrumentationCallbacks & PIC)1094 void PrintPassInstrumentation::registerCallbacks(
1095     PassInstrumentationCallbacks &PIC) {
1096   if (!Enabled)
1097     return;
1098 
1099   std::vector<StringRef> SpecialPasses;
1100   if (!Opts.Verbose) {
1101     SpecialPasses.emplace_back("PassManager");
1102     SpecialPasses.emplace_back("PassAdaptor");
1103   }
1104 
1105   PIC.registerBeforeSkippedPassCallback([this, SpecialPasses](StringRef PassID,
1106                                                               Any IR) {
1107     assert(!isSpecialPass(PassID, SpecialPasses) &&
1108            "Unexpectedly skipping special pass");
1109 
1110     print() << "Skipping pass: " << PassID << " on " << getIRName(IR) << "\n";
1111   });
1112   PIC.registerBeforeNonSkippedPassCallback([this, SpecialPasses](
1113                                                StringRef PassID, Any IR) {
1114     if (isSpecialPass(PassID, SpecialPasses))
1115       return;
1116 
1117     auto &OS = print();
1118     OS << "Running pass: " << PassID << " on " << getIRName(IR);
1119     if (const auto *F = unwrapIR<Function>(IR)) {
1120       unsigned Count = F->getInstructionCount();
1121       OS << " (" << Count << " instruction";
1122       if (Count != 1)
1123         OS << 's';
1124       OS << ')';
1125     } else if (const auto *C = unwrapIR<LazyCallGraph::SCC>(IR)) {
1126       int Count = C->size();
1127       OS << " (" << Count << " node";
1128       if (Count != 1)
1129         OS << 's';
1130       OS << ')';
1131     }
1132     OS << "\n";
1133     Indent += 2;
1134   });
1135   PIC.registerAfterPassCallback(
1136       [this, SpecialPasses](StringRef PassID, Any IR,
1137                             const PreservedAnalyses &) {
1138         if (isSpecialPass(PassID, SpecialPasses))
1139           return;
1140 
1141         Indent -= 2;
1142       });
1143   PIC.registerAfterPassInvalidatedCallback(
1144       [this, SpecialPasses](StringRef PassID, Any IR) {
1145         if (isSpecialPass(PassID, SpecialPasses))
1146           return;
1147 
1148         Indent -= 2;
1149       });
1150 
1151   if (!Opts.SkipAnalyses) {
1152     PIC.registerBeforeAnalysisCallback([this](StringRef PassID, Any IR) {
1153       print() << "Running analysis: " << PassID << " on " << getIRName(IR)
1154               << "\n";
1155       Indent += 2;
1156     });
1157     PIC.registerAfterAnalysisCallback(
1158         [this](StringRef PassID, Any IR) { Indent -= 2; });
1159     PIC.registerAnalysisInvalidatedCallback([this](StringRef PassID, Any IR) {
1160       print() << "Invalidating analysis: " << PassID << " on " << getIRName(IR)
1161               << "\n";
1162     });
1163     PIC.registerAnalysesClearedCallback([this](StringRef IRName) {
1164       print() << "Clearing all analysis results for: " << IRName << "\n";
1165     });
1166   }
1167 }
1168 
CFG(const Function * F,bool TrackBBLifetime)1169 PreservedCFGCheckerInstrumentation::CFG::CFG(const Function *F,
1170                                              bool TrackBBLifetime) {
1171   if (TrackBBLifetime)
1172     BBGuards = DenseMap<intptr_t, BBGuard>(F->size());
1173   for (const auto &BB : *F) {
1174     if (BBGuards)
1175       BBGuards->try_emplace(intptr_t(&BB), &BB);
1176     for (const auto *Succ : successors(&BB)) {
1177       Graph[&BB][Succ]++;
1178       if (BBGuards)
1179         BBGuards->try_emplace(intptr_t(Succ), Succ);
1180     }
1181   }
1182 }
1183 
printBBName(raw_ostream & out,const BasicBlock * BB)1184 static void printBBName(raw_ostream &out, const BasicBlock *BB) {
1185   if (BB->hasName()) {
1186     out << BB->getName() << "<" << BB << ">";
1187     return;
1188   }
1189 
1190   if (!BB->getParent()) {
1191     out << "unnamed_removed<" << BB << ">";
1192     return;
1193   }
1194 
1195   if (BB->isEntryBlock()) {
1196     out << "entry"
1197         << "<" << BB << ">";
1198     return;
1199   }
1200 
1201   unsigned FuncOrderBlockNum = 0;
1202   for (auto &FuncBB : *BB->getParent()) {
1203     if (&FuncBB == BB)
1204       break;
1205     FuncOrderBlockNum++;
1206   }
1207   out << "unnamed_" << FuncOrderBlockNum << "<" << BB << ">";
1208 }
1209 
printDiff(raw_ostream & out,const CFG & Before,const CFG & After)1210 void PreservedCFGCheckerInstrumentation::CFG::printDiff(raw_ostream &out,
1211                                                         const CFG &Before,
1212                                                         const CFG &After) {
1213   assert(!After.isPoisoned());
1214   if (Before.isPoisoned()) {
1215     out << "Some blocks were deleted\n";
1216     return;
1217   }
1218 
1219   // Find and print graph differences.
1220   if (Before.Graph.size() != After.Graph.size())
1221     out << "Different number of non-leaf basic blocks: before="
1222         << Before.Graph.size() << ", after=" << After.Graph.size() << "\n";
1223 
1224   for (auto &BB : Before.Graph) {
1225     auto BA = After.Graph.find(BB.first);
1226     if (BA == After.Graph.end()) {
1227       out << "Non-leaf block ";
1228       printBBName(out, BB.first);
1229       out << " is removed (" << BB.second.size() << " successors)\n";
1230     }
1231   }
1232 
1233   for (auto &BA : After.Graph) {
1234     auto BB = Before.Graph.find(BA.first);
1235     if (BB == Before.Graph.end()) {
1236       out << "Non-leaf block ";
1237       printBBName(out, BA.first);
1238       out << " is added (" << BA.second.size() << " successors)\n";
1239       continue;
1240     }
1241 
1242     if (BB->second == BA.second)
1243       continue;
1244 
1245     out << "Different successors of block ";
1246     printBBName(out, BA.first);
1247     out << " (unordered):\n";
1248     out << "- before (" << BB->second.size() << "): ";
1249     for (auto &SuccB : BB->second) {
1250       printBBName(out, SuccB.first);
1251       if (SuccB.second != 1)
1252         out << "(" << SuccB.second << "), ";
1253       else
1254         out << ", ";
1255     }
1256     out << "\n";
1257     out << "- after (" << BA.second.size() << "): ";
1258     for (auto &SuccA : BA.second) {
1259       printBBName(out, SuccA.first);
1260       if (SuccA.second != 1)
1261         out << "(" << SuccA.second << "), ";
1262       else
1263         out << ", ";
1264     }
1265     out << "\n";
1266   }
1267 }
1268 
1269 // PreservedCFGCheckerInstrumentation uses PreservedCFGCheckerAnalysis to check
1270 // passes, that reported they kept CFG analyses up-to-date, did not actually
1271 // change CFG. This check is done as follows. Before every functional pass in
1272 // BeforeNonSkippedPassCallback a CFG snapshot (an instance of
1273 // PreservedCFGCheckerInstrumentation::CFG) is requested from
1274 // FunctionAnalysisManager as a result of PreservedCFGCheckerAnalysis. When the
1275 // functional pass finishes and reports that CFGAnalyses or AllAnalyses are
1276 // up-to-date then the cached result of PreservedCFGCheckerAnalysis (if
1277 // available) is checked to be equal to a freshly created CFG snapshot.
1278 struct PreservedCFGCheckerAnalysis
1279     : public AnalysisInfoMixin<PreservedCFGCheckerAnalysis> {
1280   friend AnalysisInfoMixin<PreservedCFGCheckerAnalysis>;
1281 
1282   static AnalysisKey Key;
1283 
1284 public:
1285   /// Provide the result type for this analysis pass.
1286   using Result = PreservedCFGCheckerInstrumentation::CFG;
1287 
1288   /// Run the analysis pass over a function and produce CFG.
runPreservedCFGCheckerAnalysis1289   Result run(Function &F, FunctionAnalysisManager &FAM) {
1290     return Result(&F, /* TrackBBLifetime */ true);
1291   }
1292 };
1293 
1294 AnalysisKey PreservedCFGCheckerAnalysis::Key;
1295 
1296 struct PreservedFunctionHashAnalysis
1297     : public AnalysisInfoMixin<PreservedFunctionHashAnalysis> {
1298   static AnalysisKey Key;
1299 
1300   struct FunctionHash {
1301     uint64_t Hash;
1302   };
1303 
1304   using Result = FunctionHash;
1305 
runPreservedFunctionHashAnalysis1306   Result run(Function &F, FunctionAnalysisManager &FAM) {
1307     return Result{StructuralHash(F)};
1308   }
1309 };
1310 
1311 AnalysisKey PreservedFunctionHashAnalysis::Key;
1312 
1313 struct PreservedModuleHashAnalysis
1314     : public AnalysisInfoMixin<PreservedModuleHashAnalysis> {
1315   static AnalysisKey Key;
1316 
1317   struct ModuleHash {
1318     uint64_t Hash;
1319   };
1320 
1321   using Result = ModuleHash;
1322 
runPreservedModuleHashAnalysis1323   Result run(Module &F, ModuleAnalysisManager &FAM) {
1324     return Result{StructuralHash(F)};
1325   }
1326 };
1327 
1328 AnalysisKey PreservedModuleHashAnalysis::Key;
1329 
invalidate(Function & F,const PreservedAnalyses & PA,FunctionAnalysisManager::Invalidator &)1330 bool PreservedCFGCheckerInstrumentation::CFG::invalidate(
1331     Function &F, const PreservedAnalyses &PA,
1332     FunctionAnalysisManager::Invalidator &) {
1333   auto PAC = PA.getChecker<PreservedCFGCheckerAnalysis>();
1334   return !(PAC.preserved() || PAC.preservedSet<AllAnalysesOn<Function>>() ||
1335            PAC.preservedSet<CFGAnalyses>());
1336 }
1337 
GetFunctions(Any IR)1338 static SmallVector<Function *, 1> GetFunctions(Any IR) {
1339   SmallVector<Function *, 1> Functions;
1340 
1341   if (const auto *MaybeF = unwrapIR<Function>(IR)) {
1342     Functions.push_back(const_cast<Function *>(MaybeF));
1343   } else if (const auto *MaybeM = unwrapIR<Module>(IR)) {
1344     for (Function &F : *const_cast<Module *>(MaybeM))
1345       Functions.push_back(&F);
1346   }
1347   return Functions;
1348 }
1349 
registerCallbacks(PassInstrumentationCallbacks & PIC,ModuleAnalysisManager & MAM)1350 void PreservedCFGCheckerInstrumentation::registerCallbacks(
1351     PassInstrumentationCallbacks &PIC, ModuleAnalysisManager &MAM) {
1352   if (!VerifyAnalysisInvalidation)
1353     return;
1354 
1355   bool Registered = false;
1356   PIC.registerBeforeNonSkippedPassCallback([this, &MAM, Registered](
1357                                                StringRef P, Any IR) mutable {
1358 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
1359     assert(&PassStack.emplace_back(P));
1360 #endif
1361     (void)this;
1362 
1363     auto &FAM = MAM.getResult<FunctionAnalysisManagerModuleProxy>(
1364                        *const_cast<Module *>(unwrapModule(IR, /*Force=*/true)))
1365                     .getManager();
1366     if (!Registered) {
1367       FAM.registerPass([&] { return PreservedCFGCheckerAnalysis(); });
1368       FAM.registerPass([&] { return PreservedFunctionHashAnalysis(); });
1369       MAM.registerPass([&] { return PreservedModuleHashAnalysis(); });
1370       Registered = true;
1371     }
1372 
1373     for (Function *F : GetFunctions(IR)) {
1374       // Make sure a fresh CFG snapshot is available before the pass.
1375       FAM.getResult<PreservedCFGCheckerAnalysis>(*F);
1376       FAM.getResult<PreservedFunctionHashAnalysis>(*F);
1377     }
1378 
1379     if (const auto *MPtr = unwrapIR<Module>(IR)) {
1380       auto &M = *const_cast<Module *>(MPtr);
1381       MAM.getResult<PreservedModuleHashAnalysis>(M);
1382     }
1383   });
1384 
1385   PIC.registerAfterPassInvalidatedCallback(
1386       [this](StringRef P, const PreservedAnalyses &PassPA) {
1387 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
1388         assert(PassStack.pop_back_val() == P &&
1389                "Before and After callbacks must correspond");
1390 #endif
1391         (void)this;
1392       });
1393 
1394   PIC.registerAfterPassCallback([this, &MAM](StringRef P, Any IR,
1395                                              const PreservedAnalyses &PassPA) {
1396 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
1397     assert(PassStack.pop_back_val() == P &&
1398            "Before and After callbacks must correspond");
1399 #endif
1400     (void)this;
1401 
1402     // We have to get the FAM via the MAM, rather than directly use a passed in
1403     // FAM because if MAM has not cached the FAM, it won't invalidate function
1404     // analyses in FAM.
1405     auto &FAM = MAM.getResult<FunctionAnalysisManagerModuleProxy>(
1406                        *const_cast<Module *>(unwrapModule(IR, /*Force=*/true)))
1407                     .getManager();
1408 
1409     for (Function *F : GetFunctions(IR)) {
1410       if (auto *HashBefore =
1411               FAM.getCachedResult<PreservedFunctionHashAnalysis>(*F)) {
1412         if (HashBefore->Hash != StructuralHash(*F)) {
1413           report_fatal_error(formatv(
1414               "Function @{0} changed by {1} without invalidating analyses",
1415               F->getName(), P));
1416         }
1417       }
1418 
1419       auto CheckCFG = [](StringRef Pass, StringRef FuncName,
1420                          const CFG &GraphBefore, const CFG &GraphAfter) {
1421         if (GraphAfter == GraphBefore)
1422           return;
1423 
1424         dbgs()
1425             << "Error: " << Pass
1426             << " does not invalidate CFG analyses but CFG changes detected in "
1427                "function @"
1428             << FuncName << ":\n";
1429         CFG::printDiff(dbgs(), GraphBefore, GraphAfter);
1430         report_fatal_error(Twine("CFG unexpectedly changed by ", Pass));
1431       };
1432 
1433       if (auto *GraphBefore =
1434               FAM.getCachedResult<PreservedCFGCheckerAnalysis>(*F))
1435         CheckCFG(P, F->getName(), *GraphBefore,
1436                  CFG(F, /* TrackBBLifetime */ false));
1437     }
1438     if (const auto *MPtr = unwrapIR<Module>(IR)) {
1439       auto &M = *const_cast<Module *>(MPtr);
1440       if (auto *HashBefore =
1441               MAM.getCachedResult<PreservedModuleHashAnalysis>(M)) {
1442         if (HashBefore->Hash != StructuralHash(M)) {
1443           report_fatal_error(formatv(
1444               "Module changed by {0} without invalidating analyses", P));
1445         }
1446       }
1447     }
1448   });
1449 }
1450 
registerCallbacks(PassInstrumentationCallbacks & PIC,ModuleAnalysisManager * MAM)1451 void VerifyInstrumentation::registerCallbacks(PassInstrumentationCallbacks &PIC,
1452                                               ModuleAnalysisManager *MAM) {
1453   PIC.registerAfterPassCallback(
1454       [this, MAM](StringRef P, Any IR, const PreservedAnalyses &PassPA) {
1455         if (isIgnored(P) || P == "VerifierPass")
1456           return;
1457         const auto *F = unwrapIR<Function>(IR);
1458         if (!F) {
1459           if (const auto *L = unwrapIR<Loop>(IR))
1460             F = L->getHeader()->getParent();
1461         }
1462 
1463         if (F) {
1464           if (DebugLogging)
1465             dbgs() << "Verifying function " << F->getName() << "\n";
1466 
1467           if (verifyFunction(*F, &errs()))
1468             report_fatal_error(formatv("Broken function found after pass "
1469                                        "\"{0}\", compilation aborted!",
1470                                        P));
1471         } else {
1472           const auto *M = unwrapIR<Module>(IR);
1473           if (!M) {
1474             if (const auto *C = unwrapIR<LazyCallGraph::SCC>(IR))
1475               M = C->begin()->getFunction().getParent();
1476           }
1477 
1478           if (M) {
1479             if (DebugLogging)
1480               dbgs() << "Verifying module " << M->getName() << "\n";
1481 
1482             if (verifyModule(*M, &errs()))
1483               report_fatal_error(formatv("Broken module found after pass "
1484                                          "\"{0}\", compilation aborted!",
1485                                          P));
1486           }
1487 
1488           if (auto *MF = unwrapIR<MachineFunction>(IR)) {
1489             if (DebugLogging)
1490               dbgs() << "Verifying machine function " << MF->getName() << '\n';
1491             std::string Banner =
1492                 formatv("Broken machine function found after pass "
1493                         "\"{0}\", compilation aborted!",
1494                         P);
1495             if (MAM) {
1496               Module &M = const_cast<Module &>(*MF->getFunction().getParent());
1497               auto &MFAM =
1498                   MAM->getResult<MachineFunctionAnalysisManagerModuleProxy>(M)
1499                       .getManager();
1500               MachineVerifierPass Verifier(Banner);
1501               Verifier.run(const_cast<MachineFunction &>(*MF), MFAM);
1502             } else {
1503               verifyMachineFunction(Banner, *MF);
1504             }
1505           }
1506         }
1507       });
1508 }
1509 
1510 InLineChangePrinter::~InLineChangePrinter() = default;
1511 
generateIRRepresentation(Any IR,StringRef PassID,IRDataT<EmptyData> & D)1512 void InLineChangePrinter::generateIRRepresentation(Any IR,
1513                                                    StringRef PassID,
1514                                                    IRDataT<EmptyData> &D) {
1515   IRComparer<EmptyData>::analyzeIR(IR, D);
1516 }
1517 
handleAfter(StringRef PassID,std::string & Name,const IRDataT<EmptyData> & Before,const IRDataT<EmptyData> & After,Any IR)1518 void InLineChangePrinter::handleAfter(StringRef PassID, std::string &Name,
1519                                       const IRDataT<EmptyData> &Before,
1520                                       const IRDataT<EmptyData> &After,
1521                                       Any IR) {
1522   SmallString<20> Banner =
1523       formatv("*** IR Dump After {0} on {1} ***\n", PassID, Name);
1524   Out << Banner;
1525   IRComparer<EmptyData>(Before, After)
1526       .compare(getModuleForComparison(IR),
1527                [&](bool InModule, unsigned Minor,
1528                    const FuncDataT<EmptyData> &Before,
1529                    const FuncDataT<EmptyData> &After) -> void {
1530                  handleFunctionCompare(Name, "", PassID, " on ", InModule,
1531                                        Minor, Before, After);
1532                });
1533   Out << "\n";
1534 }
1535 
handleFunctionCompare(StringRef Name,StringRef Prefix,StringRef PassID,StringRef Divider,bool InModule,unsigned Minor,const FuncDataT<EmptyData> & Before,const FuncDataT<EmptyData> & After)1536 void InLineChangePrinter::handleFunctionCompare(
1537     StringRef Name, StringRef Prefix, StringRef PassID, StringRef Divider,
1538     bool InModule, unsigned Minor, const FuncDataT<EmptyData> &Before,
1539     const FuncDataT<EmptyData> &After) {
1540   // Print a banner when this is being shown in the context of a module
1541   if (InModule)
1542     Out << "\n*** IR for function " << Name << " ***\n";
1543 
1544   FuncDataT<EmptyData>::report(
1545       Before, After,
1546       [&](const BlockDataT<EmptyData> *B, const BlockDataT<EmptyData> *A) {
1547         StringRef BStr = B ? B->getBody() : "\n";
1548         StringRef AStr = A ? A->getBody() : "\n";
1549         const std::string Removed =
1550             UseColour ? "\033[31m-%l\033[0m\n" : "-%l\n";
1551         const std::string Added = UseColour ? "\033[32m+%l\033[0m\n" : "+%l\n";
1552         const std::string NoChange = " %l\n";
1553         Out << doSystemDiff(BStr, AStr, Removed, Added, NoChange);
1554       });
1555 }
1556 
registerCallbacks(PassInstrumentationCallbacks & PIC)1557 void InLineChangePrinter::registerCallbacks(PassInstrumentationCallbacks &PIC) {
1558   if (PrintChanged == ChangePrinter::DiffVerbose ||
1559       PrintChanged == ChangePrinter::DiffQuiet ||
1560       PrintChanged == ChangePrinter::ColourDiffVerbose ||
1561       PrintChanged == ChangePrinter::ColourDiffQuiet)
1562     TextChangeReporter<IRDataT<EmptyData>>::registerRequiredCallbacks(PIC);
1563 }
1564 
TimeProfilingPassesHandler()1565 TimeProfilingPassesHandler::TimeProfilingPassesHandler() {}
1566 
registerCallbacks(PassInstrumentationCallbacks & PIC)1567 void TimeProfilingPassesHandler::registerCallbacks(
1568     PassInstrumentationCallbacks &PIC) {
1569   if (!getTimeTraceProfilerInstance())
1570     return;
1571   PIC.registerBeforeNonSkippedPassCallback(
1572       [this](StringRef P, Any IR) { this->runBeforePass(P, IR); });
1573   PIC.registerAfterPassCallback(
1574       [this](StringRef P, Any IR, const PreservedAnalyses &) {
1575         this->runAfterPass();
1576       },
1577       true);
1578   PIC.registerAfterPassInvalidatedCallback(
1579       [this](StringRef P, const PreservedAnalyses &) { this->runAfterPass(); },
1580       true);
1581   PIC.registerBeforeAnalysisCallback(
1582       [this](StringRef P, Any IR) { this->runBeforePass(P, IR); });
1583   PIC.registerAfterAnalysisCallback(
1584       [this](StringRef P, Any IR) { this->runAfterPass(); }, true);
1585 }
1586 
runBeforePass(StringRef PassID,Any IR)1587 void TimeProfilingPassesHandler::runBeforePass(StringRef PassID, Any IR) {
1588   timeTraceProfilerBegin(PassID, getIRName(IR));
1589 }
1590 
runAfterPass()1591 void TimeProfilingPassesHandler::runAfterPass() { timeTraceProfilerEnd(); }
1592 
1593 namespace {
1594 
1595 class DisplayNode;
1596 class DotCfgDiffDisplayGraph;
1597 
1598 // Base class for a node or edge in the dot-cfg-changes graph.
1599 class DisplayElement {
1600 public:
1601   // Is this in before, after, or both?
getColour() const1602   StringRef getColour() const { return Colour; }
1603 
1604 protected:
DisplayElement(StringRef Colour)1605   DisplayElement(StringRef Colour) : Colour(Colour) {}
1606   const StringRef Colour;
1607 };
1608 
1609 // An edge representing a transition between basic blocks in the
1610 // dot-cfg-changes graph.
1611 class DisplayEdge : public DisplayElement {
1612 public:
DisplayEdge(std::string Value,DisplayNode & Node,StringRef Colour)1613   DisplayEdge(std::string Value, DisplayNode &Node, StringRef Colour)
1614       : DisplayElement(Colour), Value(Value), Node(Node) {}
1615   // The value on which the transition is made.
getValue() const1616   std::string getValue() const { return Value; }
1617   // The node (representing a basic block) reached by this transition.
getDestinationNode() const1618   const DisplayNode &getDestinationNode() const { return Node; }
1619 
1620 protected:
1621   std::string Value;
1622   const DisplayNode &Node;
1623 };
1624 
1625 // A node in the dot-cfg-changes graph which represents a basic block.
1626 class DisplayNode : public DisplayElement {
1627 public:
1628   // \p C is the content for the node, \p T indicates the colour for the
1629   // outline of the node
DisplayNode(std::string Content,StringRef Colour)1630   DisplayNode(std::string Content, StringRef Colour)
1631       : DisplayElement(Colour), Content(Content) {}
1632 
1633   // Iterator to the child nodes.  Required by GraphWriter.
1634   using ChildIterator = std::unordered_set<DisplayNode *>::const_iterator;
children_begin() const1635   ChildIterator children_begin() const { return Children.cbegin(); }
children_end() const1636   ChildIterator children_end() const { return Children.cend(); }
1637 
1638   // Iterator for the edges.  Required by GraphWriter.
1639   using EdgeIterator = std::vector<DisplayEdge *>::const_iterator;
edges_begin() const1640   EdgeIterator edges_begin() const { return EdgePtrs.cbegin(); }
edges_end() const1641   EdgeIterator edges_end() const { return EdgePtrs.cend(); }
1642 
1643   // Create an edge to \p Node on value \p Value, with colour \p Colour.
1644   void createEdge(StringRef Value, DisplayNode &Node, StringRef Colour);
1645 
1646   // Return the content of this node.
getContent() const1647   std::string getContent() const { return Content; }
1648 
1649   // Return the edge to node \p S.
getEdge(const DisplayNode & To) const1650   const DisplayEdge &getEdge(const DisplayNode &To) const {
1651     assert(EdgeMap.find(&To) != EdgeMap.end() && "Expected to find edge.");
1652     return *EdgeMap.find(&To)->second;
1653   }
1654 
1655   // Return the value for the transition to basic block \p S.
1656   // Required by GraphWriter.
getEdgeSourceLabel(const DisplayNode & Sink) const1657   std::string getEdgeSourceLabel(const DisplayNode &Sink) const {
1658     return getEdge(Sink).getValue();
1659   }
1660 
1661   void createEdgeMap();
1662 
1663 protected:
1664   const std::string Content;
1665 
1666   // Place to collect all of the edges.  Once they are all in the vector,
1667   // the vector will not reallocate so then we can use pointers to them,
1668   // which are required by the graph writing routines.
1669   std::vector<DisplayEdge> Edges;
1670 
1671   std::vector<DisplayEdge *> EdgePtrs;
1672   std::unordered_set<DisplayNode *> Children;
1673   std::unordered_map<const DisplayNode *, const DisplayEdge *> EdgeMap;
1674 
1675   // Safeguard adding of edges.
1676   bool AllEdgesCreated = false;
1677 };
1678 
1679 // Class representing a difference display (corresponds to a pdf file).
1680 class DotCfgDiffDisplayGraph {
1681 public:
DotCfgDiffDisplayGraph(std::string Name)1682   DotCfgDiffDisplayGraph(std::string Name) : GraphName(Name) {}
1683 
1684   // Generate the file into \p DotFile.
1685   void generateDotFile(StringRef DotFile);
1686 
1687   // Iterator to the nodes.  Required by GraphWriter.
1688   using NodeIterator = std::vector<DisplayNode *>::const_iterator;
nodes_begin() const1689   NodeIterator nodes_begin() const {
1690     assert(NodeGenerationComplete && "Unexpected children iterator creation");
1691     return NodePtrs.cbegin();
1692   }
nodes_end() const1693   NodeIterator nodes_end() const {
1694     assert(NodeGenerationComplete && "Unexpected children iterator creation");
1695     return NodePtrs.cend();
1696   }
1697 
1698   // Record the index of the entry node.  At this point, we can build up
1699   // vectors of pointers that are required by the graph routines.
setEntryNode(unsigned N)1700   void setEntryNode(unsigned N) {
1701     // At this point, there will be no new nodes.
1702     assert(!NodeGenerationComplete && "Unexpected node creation");
1703     NodeGenerationComplete = true;
1704     for (auto &N : Nodes)
1705       NodePtrs.emplace_back(&N);
1706 
1707     EntryNode = NodePtrs[N];
1708   }
1709 
1710   // Create a node.
createNode(std::string C,StringRef Colour)1711   void createNode(std::string C, StringRef Colour) {
1712     assert(!NodeGenerationComplete && "Unexpected node creation");
1713     Nodes.emplace_back(C, Colour);
1714   }
1715   // Return the node at index \p N to avoid problems with vectors reallocating.
getNode(unsigned N)1716   DisplayNode &getNode(unsigned N) {
1717     assert(N < Nodes.size() && "Node is out of bounds");
1718     return Nodes[N];
1719   }
size() const1720   unsigned size() const {
1721     assert(NodeGenerationComplete && "Unexpected children iterator creation");
1722     return Nodes.size();
1723   }
1724 
1725   // Return the name of the graph.  Required by GraphWriter.
getGraphName() const1726   std::string getGraphName() const { return GraphName; }
1727 
1728   // Return the string representing the differences for basic block \p Node.
1729   // Required by GraphWriter.
getNodeLabel(const DisplayNode & Node) const1730   std::string getNodeLabel(const DisplayNode &Node) const {
1731     return Node.getContent();
1732   }
1733 
1734   // Return a string with colour information for Dot.  Required by GraphWriter.
getNodeAttributes(const DisplayNode & Node) const1735   std::string getNodeAttributes(const DisplayNode &Node) const {
1736     return attribute(Node.getColour());
1737   }
1738 
1739   // Return a string with colour information for Dot.  Required by GraphWriter.
getEdgeColorAttr(const DisplayNode & From,const DisplayNode & To) const1740   std::string getEdgeColorAttr(const DisplayNode &From,
1741                                const DisplayNode &To) const {
1742     return attribute(From.getEdge(To).getColour());
1743   }
1744 
1745   // Get the starting basic block.  Required by GraphWriter.
getEntryNode() const1746   DisplayNode *getEntryNode() const {
1747     assert(NodeGenerationComplete && "Unexpected children iterator creation");
1748     return EntryNode;
1749   }
1750 
1751 protected:
1752   // Return the string containing the colour to use as a Dot attribute.
attribute(StringRef Colour) const1753   std::string attribute(StringRef Colour) const {
1754     return "color=" + Colour.str();
1755   }
1756 
1757   bool NodeGenerationComplete = false;
1758   const std::string GraphName;
1759   std::vector<DisplayNode> Nodes;
1760   std::vector<DisplayNode *> NodePtrs;
1761   DisplayNode *EntryNode = nullptr;
1762 };
1763 
createEdge(StringRef Value,DisplayNode & Node,StringRef Colour)1764 void DisplayNode::createEdge(StringRef Value, DisplayNode &Node,
1765                              StringRef Colour) {
1766   assert(!AllEdgesCreated && "Expected to be able to still create edges.");
1767   Edges.emplace_back(Value.str(), Node, Colour);
1768   Children.insert(&Node);
1769 }
1770 
createEdgeMap()1771 void DisplayNode::createEdgeMap() {
1772   // No more edges will be added so we can now use pointers to the edges
1773   // as the vector will not grow and reallocate.
1774   AllEdgesCreated = true;
1775   for (auto &E : Edges)
1776     EdgeMap.insert({&E.getDestinationNode(), &E});
1777 }
1778 
1779 class DotCfgDiffNode;
1780 class DotCfgDiff;
1781 
1782 // A class representing a basic block in the Dot difference graph.
1783 class DotCfgDiffNode {
1784 public:
1785   DotCfgDiffNode() = delete;
1786 
1787   // Create a node in Dot difference graph \p G representing the basic block
1788   // represented by \p BD with colour \p Colour (where it exists).
DotCfgDiffNode(DotCfgDiff & G,unsigned N,const BlockDataT<DCData> & BD,StringRef Colour)1789   DotCfgDiffNode(DotCfgDiff &G, unsigned N, const BlockDataT<DCData> &BD,
1790                  StringRef Colour)
1791       : Graph(G), N(N), Data{&BD, nullptr}, Colour(Colour) {}
DotCfgDiffNode(const DotCfgDiffNode & DN)1792   DotCfgDiffNode(const DotCfgDiffNode &DN)
1793       : Graph(DN.Graph), N(DN.N), Data{DN.Data[0], DN.Data[1]},
1794         Colour(DN.Colour), EdgesMap(DN.EdgesMap), Children(DN.Children),
1795         Edges(DN.Edges) {}
1796 
getIndex() const1797   unsigned getIndex() const { return N; }
1798 
1799   // The label of the basic block
getLabel() const1800   StringRef getLabel() const {
1801     assert(Data[0] && "Expected Data[0] to be set.");
1802     return Data[0]->getLabel();
1803   }
1804   // Return the colour for this block
getColour() const1805   StringRef getColour() const { return Colour; }
1806   // Change this basic block from being only in before to being common.
1807   // Save the pointer to \p Other.
setCommon(const BlockDataT<DCData> & Other)1808   void setCommon(const BlockDataT<DCData> &Other) {
1809     assert(!Data[1] && "Expected only one block datum");
1810     Data[1] = &Other;
1811     Colour = CommonColour;
1812   }
1813   // Add an edge to \p E of colour {\p Value, \p Colour}.
addEdge(unsigned E,StringRef Value,StringRef Colour)1814   void addEdge(unsigned E, StringRef Value, StringRef Colour) {
1815     // This is a new edge or it is an edge being made common.
1816     assert((EdgesMap.count(E) == 0 || Colour == CommonColour) &&
1817            "Unexpected edge count and color.");
1818     EdgesMap[E] = {Value.str(), Colour};
1819   }
1820   // Record the children and create edges.
1821   void finalize(DotCfgDiff &G);
1822 
1823   // Return the colour of the edge to node \p S.
getEdgeColour(const unsigned S) const1824   StringRef getEdgeColour(const unsigned S) const {
1825     assert(EdgesMap.count(S) == 1 && "Expected to find edge.");
1826     return EdgesMap.at(S).second;
1827   }
1828 
1829   // Return the string representing the basic block.
1830   std::string getBodyContent() const;
1831 
1832   void createDisplayEdges(DotCfgDiffDisplayGraph &Graph, unsigned DisplayNode,
1833                           std::map<const unsigned, unsigned> &NodeMap) const;
1834 
1835 protected:
1836   DotCfgDiff &Graph;
1837   const unsigned N;
1838   const BlockDataT<DCData> *Data[2];
1839   StringRef Colour;
1840   std::map<const unsigned, std::pair<std::string, StringRef>> EdgesMap;
1841   std::vector<unsigned> Children;
1842   std::vector<unsigned> Edges;
1843 };
1844 
1845 // Class representing the difference graph between two functions.
1846 class DotCfgDiff {
1847 public:
1848   // \p Title is the title given to the graph.  \p EntryNodeName is the
1849   // entry node for the function.  \p Before and \p After are the before
1850   // after versions of the function, respectively.  \p Dir is the directory
1851   // in which to store the results.
1852   DotCfgDiff(StringRef Title, const FuncDataT<DCData> &Before,
1853              const FuncDataT<DCData> &After);
1854 
1855   DotCfgDiff(const DotCfgDiff &) = delete;
1856   DotCfgDiff &operator=(const DotCfgDiff &) = delete;
1857 
1858   DotCfgDiffDisplayGraph createDisplayGraph(StringRef Title,
1859                                             StringRef EntryNodeName);
1860 
1861   // Return a string consisting of the labels for the \p Source and \p Sink.
1862   // The combination allows distinguishing changing transitions on the
1863   // same value (ie, a transition went to X before and goes to Y after).
1864   // Required by GraphWriter.
getEdgeSourceLabel(const unsigned & Source,const unsigned & Sink) const1865   StringRef getEdgeSourceLabel(const unsigned &Source,
1866                                const unsigned &Sink) const {
1867     std::string S =
1868         getNode(Source).getLabel().str() + " " + getNode(Sink).getLabel().str();
1869     assert(EdgeLabels.count(S) == 1 && "Expected to find edge label.");
1870     return EdgeLabels.find(S)->getValue();
1871   }
1872 
1873   // Return the number of basic blocks (nodes).  Required by GraphWriter.
size() const1874   unsigned size() const { return Nodes.size(); }
1875 
getNode(unsigned N) const1876   const DotCfgDiffNode &getNode(unsigned N) const {
1877     assert(N < Nodes.size() && "Unexpected index for node reference");
1878     return Nodes[N];
1879   }
1880 
1881 protected:
1882   // Return the string surrounded by HTML to make it the appropriate colour.
1883   std::string colourize(std::string S, StringRef Colour) const;
1884 
createNode(StringRef Label,const BlockDataT<DCData> & BD,StringRef C)1885   void createNode(StringRef Label, const BlockDataT<DCData> &BD, StringRef C) {
1886     unsigned Pos = Nodes.size();
1887     Nodes.emplace_back(*this, Pos, BD, C);
1888     NodePosition.insert({Label, Pos});
1889   }
1890 
1891   // TODO Nodes should probably be a StringMap<DotCfgDiffNode> after the
1892   // display graph is separated out, which would remove the need for
1893   // NodePosition.
1894   std::vector<DotCfgDiffNode> Nodes;
1895   StringMap<unsigned> NodePosition;
1896   const std::string GraphName;
1897 
1898   StringMap<std::string> EdgeLabels;
1899 };
1900 
getBodyContent() const1901 std::string DotCfgDiffNode::getBodyContent() const {
1902   if (Colour == CommonColour) {
1903     assert(Data[1] && "Expected Data[1] to be set.");
1904 
1905     StringRef SR[2];
1906     for (unsigned I = 0; I < 2; ++I) {
1907       SR[I] = Data[I]->getBody();
1908       // drop initial '\n' if present
1909       SR[I].consume_front("\n");
1910       // drop predecessors as they can be big and are redundant
1911       SR[I] = SR[I].drop_until([](char C) { return C == '\n'; }).drop_front();
1912     }
1913 
1914     SmallString<80> OldLineFormat = formatv(
1915         "<FONT COLOR=\"{0}\">%l</FONT><BR align=\"left\"/>", BeforeColour);
1916     SmallString<80> NewLineFormat = formatv(
1917         "<FONT COLOR=\"{0}\">%l</FONT><BR align=\"left\"/>", AfterColour);
1918     SmallString<80> UnchangedLineFormat = formatv(
1919         "<FONT COLOR=\"{0}\">%l</FONT><BR align=\"left\"/>", CommonColour);
1920     std::string Diff = Data[0]->getLabel().str();
1921     Diff += ":\n<BR align=\"left\"/>" +
1922             doSystemDiff(makeHTMLReady(SR[0]), makeHTMLReady(SR[1]),
1923                          OldLineFormat, NewLineFormat, UnchangedLineFormat);
1924 
1925     // Diff adds in some empty colour changes which are not valid HTML
1926     // so remove them.  Colours are all lowercase alpha characters (as
1927     // listed in https://graphviz.org/pdf/dotguide.pdf).
1928     Regex R("<FONT COLOR=\"\\w+\"></FONT>");
1929     while (true) {
1930       std::string Error;
1931       std::string S = R.sub("", Diff, &Error);
1932       if (Error != "")
1933         return Error;
1934       if (S == Diff)
1935         return Diff;
1936       Diff = S;
1937     }
1938     llvm_unreachable("Should not get here");
1939   }
1940 
1941   // Put node out in the appropriate colour.
1942   assert(!Data[1] && "Data[1] is set unexpectedly.");
1943   std::string Body = makeHTMLReady(Data[0]->getBody());
1944   const StringRef BS = Body;
1945   StringRef BS1 = BS;
1946   // Drop leading newline, if present.
1947   if (BS.front() == '\n')
1948     BS1 = BS1.drop_front(1);
1949   // Get label.
1950   StringRef Label = BS1.take_until([](char C) { return C == ':'; });
1951   // drop predecessors as they can be big and are redundant
1952   BS1 = BS1.drop_until([](char C) { return C == '\n'; }).drop_front();
1953 
1954   std::string S = "<FONT COLOR=\"" + Colour.str() + "\">" + Label.str() + ":";
1955 
1956   // align each line to the left.
1957   while (BS1.size()) {
1958     S.append("<BR align=\"left\"/>");
1959     StringRef Line = BS1.take_until([](char C) { return C == '\n'; });
1960     S.append(Line.str());
1961     BS1 = BS1.drop_front(Line.size() + 1);
1962   }
1963   S.append("<BR align=\"left\"/></FONT>");
1964   return S;
1965 }
1966 
colourize(std::string S,StringRef Colour) const1967 std::string DotCfgDiff::colourize(std::string S, StringRef Colour) const {
1968   if (S.length() == 0)
1969     return S;
1970   return "<FONT COLOR=\"" + Colour.str() + "\">" + S + "</FONT>";
1971 }
1972 
DotCfgDiff(StringRef Title,const FuncDataT<DCData> & Before,const FuncDataT<DCData> & After)1973 DotCfgDiff::DotCfgDiff(StringRef Title, const FuncDataT<DCData> &Before,
1974                        const FuncDataT<DCData> &After)
1975     : GraphName(Title.str()) {
1976   StringMap<StringRef> EdgesMap;
1977 
1978   // Handle each basic block in the before IR.
1979   for (auto &B : Before.getData()) {
1980     StringRef Label = B.getKey();
1981     const BlockDataT<DCData> &BD = B.getValue();
1982     createNode(Label, BD, BeforeColour);
1983 
1984     // Create transitions with names made up of the from block label, the value
1985     // on which the transition is made and the to block label.
1986     for (StringMap<std::string>::const_iterator Sink = BD.getData().begin(),
1987                                                 E = BD.getData().end();
1988          Sink != E; ++Sink) {
1989       std::string Key = (Label + " " + Sink->getKey().str()).str() + " " +
1990                         BD.getData().getSuccessorLabel(Sink->getKey()).str();
1991       EdgesMap.insert({Key, BeforeColour});
1992     }
1993   }
1994 
1995   // Handle each basic block in the after IR
1996   for (auto &A : After.getData()) {
1997     StringRef Label = A.getKey();
1998     const BlockDataT<DCData> &BD = A.getValue();
1999     auto It = NodePosition.find(Label);
2000     if (It == NodePosition.end())
2001       // This only exists in the after IR.  Create the node.
2002       createNode(Label, BD, AfterColour);
2003     else
2004       Nodes[It->second].setCommon(BD);
2005     // Add in the edges between the nodes (as common or only in after).
2006     for (StringMap<std::string>::const_iterator Sink = BD.getData().begin(),
2007                                                 E = BD.getData().end();
2008          Sink != E; ++Sink) {
2009       std::string Key = (Label + " " + Sink->getKey().str()).str() + " " +
2010                         BD.getData().getSuccessorLabel(Sink->getKey()).str();
2011       auto [It, Inserted] = EdgesMap.try_emplace(Key, AfterColour);
2012       if (!Inserted)
2013         It->second = CommonColour;
2014     }
2015   }
2016 
2017   // Now go through the map of edges and add them to the node.
2018   for (auto &E : EdgesMap) {
2019     // Extract the source, sink and value from the edge key.
2020     StringRef S = E.getKey();
2021     auto SP1 = S.rsplit(' ');
2022     auto &SourceSink = SP1.first;
2023     auto SP2 = SourceSink.split(' ');
2024     StringRef Source = SP2.first;
2025     StringRef Sink = SP2.second;
2026     StringRef Value = SP1.second;
2027 
2028     assert(NodePosition.count(Source) == 1 && "Expected to find node.");
2029     DotCfgDiffNode &SourceNode = Nodes[NodePosition[Source]];
2030     assert(NodePosition.count(Sink) == 1 && "Expected to find node.");
2031     unsigned SinkNode = NodePosition[Sink];
2032     StringRef Colour = E.second;
2033 
2034     // Look for an edge from Source to Sink
2035     auto [It, Inserted] = EdgeLabels.try_emplace(SourceSink);
2036     if (Inserted)
2037       It->getValue() = colourize(Value.str(), Colour);
2038     else {
2039       StringRef V = It->getValue();
2040       std::string NV = colourize(V.str() + " " + Value.str(), Colour);
2041       Colour = CommonColour;
2042       It->getValue() = NV;
2043     }
2044     SourceNode.addEdge(SinkNode, Value, Colour);
2045   }
2046   for (auto &I : Nodes)
2047     I.finalize(*this);
2048 }
2049 
createDisplayGraph(StringRef Title,StringRef EntryNodeName)2050 DotCfgDiffDisplayGraph DotCfgDiff::createDisplayGraph(StringRef Title,
2051                                                       StringRef EntryNodeName) {
2052   assert(NodePosition.count(EntryNodeName) == 1 &&
2053          "Expected to find entry block in map.");
2054   unsigned Entry = NodePosition[EntryNodeName];
2055   assert(Entry < Nodes.size() && "Expected to find entry node");
2056   DotCfgDiffDisplayGraph G(Title.str());
2057 
2058   std::map<const unsigned, unsigned> NodeMap;
2059 
2060   int EntryIndex = -1;
2061   unsigned Index = 0;
2062   for (auto &I : Nodes) {
2063     if (I.getIndex() == Entry)
2064       EntryIndex = Index;
2065     G.createNode(I.getBodyContent(), I.getColour());
2066     NodeMap.insert({I.getIndex(), Index++});
2067   }
2068   assert(EntryIndex >= 0 && "Expected entry node index to be set.");
2069   G.setEntryNode(EntryIndex);
2070 
2071   for (auto &I : NodeMap) {
2072     unsigned SourceNode = I.first;
2073     unsigned DisplayNode = I.second;
2074     getNode(SourceNode).createDisplayEdges(G, DisplayNode, NodeMap);
2075   }
2076   return G;
2077 }
2078 
createDisplayEdges(DotCfgDiffDisplayGraph & DisplayGraph,unsigned DisplayNodeIndex,std::map<const unsigned,unsigned> & NodeMap) const2079 void DotCfgDiffNode::createDisplayEdges(
2080     DotCfgDiffDisplayGraph &DisplayGraph, unsigned DisplayNodeIndex,
2081     std::map<const unsigned, unsigned> &NodeMap) const {
2082 
2083   DisplayNode &SourceDisplayNode = DisplayGraph.getNode(DisplayNodeIndex);
2084 
2085   for (auto I : Edges) {
2086     unsigned SinkNodeIndex = I;
2087     StringRef Colour = getEdgeColour(SinkNodeIndex);
2088     const DotCfgDiffNode *SinkNode = &Graph.getNode(SinkNodeIndex);
2089 
2090     StringRef Label = Graph.getEdgeSourceLabel(getIndex(), SinkNodeIndex);
2091     DisplayNode &SinkDisplayNode = DisplayGraph.getNode(SinkNode->getIndex());
2092     SourceDisplayNode.createEdge(Label, SinkDisplayNode, Colour);
2093   }
2094   SourceDisplayNode.createEdgeMap();
2095 }
2096 
finalize(DotCfgDiff & G)2097 void DotCfgDiffNode::finalize(DotCfgDiff &G) {
2098   for (auto E : EdgesMap) {
2099     Children.emplace_back(E.first);
2100     Edges.emplace_back(E.first);
2101   }
2102 }
2103 
2104 } // namespace
2105 
2106 namespace llvm {
2107 
2108 template <> struct GraphTraits<DotCfgDiffDisplayGraph *> {
2109   using NodeRef = const DisplayNode *;
2110   using ChildIteratorType = DisplayNode::ChildIterator;
2111   using nodes_iterator = DotCfgDiffDisplayGraph::NodeIterator;
2112   using EdgeRef = const DisplayEdge *;
2113   using ChildEdgeIterator = DisplayNode::EdgeIterator;
2114 
getEntryNodellvm::GraphTraits2115   static NodeRef getEntryNode(const DotCfgDiffDisplayGraph *G) {
2116     return G->getEntryNode();
2117   }
child_beginllvm::GraphTraits2118   static ChildIteratorType child_begin(NodeRef N) {
2119     return N->children_begin();
2120   }
child_endllvm::GraphTraits2121   static ChildIteratorType child_end(NodeRef N) { return N->children_end(); }
nodes_beginllvm::GraphTraits2122   static nodes_iterator nodes_begin(const DotCfgDiffDisplayGraph *G) {
2123     return G->nodes_begin();
2124   }
nodes_endllvm::GraphTraits2125   static nodes_iterator nodes_end(const DotCfgDiffDisplayGraph *G) {
2126     return G->nodes_end();
2127   }
child_edge_beginllvm::GraphTraits2128   static ChildEdgeIterator child_edge_begin(NodeRef N) {
2129     return N->edges_begin();
2130   }
child_edge_endllvm::GraphTraits2131   static ChildEdgeIterator child_edge_end(NodeRef N) { return N->edges_end(); }
edge_destllvm::GraphTraits2132   static NodeRef edge_dest(EdgeRef E) { return &E->getDestinationNode(); }
sizellvm::GraphTraits2133   static unsigned size(const DotCfgDiffDisplayGraph *G) { return G->size(); }
2134 };
2135 
2136 template <>
2137 struct DOTGraphTraits<DotCfgDiffDisplayGraph *> : public DefaultDOTGraphTraits {
DOTGraphTraitsllvm::DOTGraphTraits2138   explicit DOTGraphTraits(bool Simple = false)
2139       : DefaultDOTGraphTraits(Simple) {}
2140 
renderNodesUsingHTMLllvm::DOTGraphTraits2141   static bool renderNodesUsingHTML() { return true; }
getGraphNamellvm::DOTGraphTraits2142   static std::string getGraphName(const DotCfgDiffDisplayGraph *DiffData) {
2143     return DiffData->getGraphName();
2144   }
2145   static std::string
getGraphPropertiesllvm::DOTGraphTraits2146   getGraphProperties(const DotCfgDiffDisplayGraph *DiffData) {
2147     return "\tsize=\"190, 190\";\n";
2148   }
getNodeLabelllvm::DOTGraphTraits2149   static std::string getNodeLabel(const DisplayNode *Node,
2150                                   const DotCfgDiffDisplayGraph *DiffData) {
2151     return DiffData->getNodeLabel(*Node);
2152   }
getNodeAttributesllvm::DOTGraphTraits2153   static std::string getNodeAttributes(const DisplayNode *Node,
2154                                        const DotCfgDiffDisplayGraph *DiffData) {
2155     return DiffData->getNodeAttributes(*Node);
2156   }
getEdgeSourceLabelllvm::DOTGraphTraits2157   static std::string getEdgeSourceLabel(const DisplayNode *From,
2158                                         DisplayNode::ChildIterator &To) {
2159     return From->getEdgeSourceLabel(**To);
2160   }
getEdgeAttributesllvm::DOTGraphTraits2161   static std::string getEdgeAttributes(const DisplayNode *From,
2162                                        DisplayNode::ChildIterator &To,
2163                                        const DotCfgDiffDisplayGraph *DiffData) {
2164     return DiffData->getEdgeColorAttr(*From, **To);
2165   }
2166 };
2167 
2168 } // namespace llvm
2169 
2170 namespace {
2171 
generateDotFile(StringRef DotFile)2172 void DotCfgDiffDisplayGraph::generateDotFile(StringRef DotFile) {
2173   std::error_code EC;
2174   raw_fd_ostream OutStream(DotFile, EC);
2175   if (EC) {
2176     errs() << "Error: " << EC.message() << "\n";
2177     return;
2178   }
2179   WriteGraph(OutStream, this, false);
2180   OutStream.flush();
2181   OutStream.close();
2182 }
2183 
2184 } // namespace
2185 
2186 namespace llvm {
2187 
DCData(const BasicBlock & B)2188 DCData::DCData(const BasicBlock &B) {
2189   // Build up transition labels.
2190   const Instruction *Term = B.getTerminator();
2191   if (const BranchInst *Br = dyn_cast<const BranchInst>(Term))
2192     if (Br->isUnconditional())
2193       addSuccessorLabel(Br->getSuccessor(0)->getName().str(), "");
2194     else {
2195       addSuccessorLabel(Br->getSuccessor(0)->getName().str(), "true");
2196       addSuccessorLabel(Br->getSuccessor(1)->getName().str(), "false");
2197     }
2198   else if (const SwitchInst *Sw = dyn_cast<const SwitchInst>(Term)) {
2199     addSuccessorLabel(Sw->case_default()->getCaseSuccessor()->getName().str(),
2200                       "default");
2201     for (auto &C : Sw->cases()) {
2202       assert(C.getCaseValue() && "Expected to find case value.");
2203       SmallString<20> Value = formatv("{0}", C.getCaseValue()->getSExtValue());
2204       addSuccessorLabel(C.getCaseSuccessor()->getName().str(), Value);
2205     }
2206   } else
2207     for (const BasicBlock *Succ : successors(&B))
2208       addSuccessorLabel(Succ->getName().str(), "");
2209 }
2210 
DCData(const MachineBasicBlock & B)2211 DCData::DCData(const MachineBasicBlock &B) {
2212   for (const MachineBasicBlock *Succ : successors(&B))
2213     addSuccessorLabel(Succ->getName().str(), "");
2214 }
2215 
DotCfgChangeReporter(bool Verbose)2216 DotCfgChangeReporter::DotCfgChangeReporter(bool Verbose)
2217     : ChangeReporter<IRDataT<DCData>>(Verbose) {}
2218 
handleFunctionCompare(StringRef Name,StringRef Prefix,StringRef PassID,StringRef Divider,bool InModule,unsigned Minor,const FuncDataT<DCData> & Before,const FuncDataT<DCData> & After)2219 void DotCfgChangeReporter::handleFunctionCompare(
2220     StringRef Name, StringRef Prefix, StringRef PassID, StringRef Divider,
2221     bool InModule, unsigned Minor, const FuncDataT<DCData> &Before,
2222     const FuncDataT<DCData> &After) {
2223   assert(HTML && "Expected outstream to be set");
2224   SmallString<8> Extender;
2225   SmallString<8> Number;
2226   // Handle numbering and file names.
2227   if (InModule) {
2228     Extender = formatv("{0}_{1}", N, Minor);
2229     Number = formatv("{0}.{1}", N, Minor);
2230   } else {
2231     Extender = formatv("{0}", N);
2232     Number = formatv("{0}", N);
2233   }
2234   // Create a temporary file name for the dot file.
2235   SmallVector<char, 128> SV;
2236   sys::fs::createUniquePath("cfgdot-%%%%%%.dot", SV, true);
2237   std::string DotFile = Twine(SV).str();
2238 
2239   SmallString<20> PDFFileName = formatv("diff_{0}.pdf", Extender);
2240   SmallString<200> Text;
2241 
2242   Text = formatv("{0}.{1}{2}{3}{4}", Number, Prefix, makeHTMLReady(PassID),
2243                  Divider, Name);
2244 
2245   DotCfgDiff Diff(Text, Before, After);
2246   std::string EntryBlockName = After.getEntryBlockName();
2247   // Use the before entry block if the after entry block was removed.
2248   if (EntryBlockName == "")
2249     EntryBlockName = Before.getEntryBlockName();
2250   assert(EntryBlockName != "" && "Expected to find entry block");
2251 
2252   DotCfgDiffDisplayGraph DG = Diff.createDisplayGraph(Text, EntryBlockName);
2253   DG.generateDotFile(DotFile);
2254 
2255   *HTML << genHTML(Text, DotFile, PDFFileName);
2256   std::error_code EC = sys::fs::remove(DotFile);
2257   if (EC)
2258     errs() << "Error: " << EC.message() << "\n";
2259 }
2260 
genHTML(StringRef Text,StringRef DotFile,StringRef PDFFileName)2261 std::string DotCfgChangeReporter::genHTML(StringRef Text, StringRef DotFile,
2262                                           StringRef PDFFileName) {
2263   SmallString<20> PDFFile = formatv("{0}/{1}", DotCfgDir, PDFFileName);
2264   // Create the PDF file.
2265   static ErrorOr<std::string> DotExe = sys::findProgramByName(DotBinary);
2266   if (!DotExe)
2267     return "Unable to find dot executable.";
2268 
2269   StringRef Args[] = {DotBinary, "-Tpdf", "-o", PDFFile, DotFile};
2270   int Result = sys::ExecuteAndWait(*DotExe, Args, std::nullopt);
2271   if (Result < 0)
2272     return "Error executing system dot.";
2273 
2274   // Create the HTML tag refering to the PDF file.
2275   SmallString<200> S = formatv(
2276       "  <a href=\"{0}\" target=\"_blank\">{1}</a><br/>\n", PDFFileName, Text);
2277   return S.c_str();
2278 }
2279 
handleInitialIR(Any IR)2280 void DotCfgChangeReporter::handleInitialIR(Any IR) {
2281   assert(HTML && "Expected outstream to be set");
2282   *HTML << "<button type=\"button\" class=\"collapsible\">0. "
2283         << "Initial IR (by function)</button>\n"
2284         << "<div class=\"content\">\n"
2285         << "  <p>\n";
2286   // Create representation of IR
2287   IRDataT<DCData> Data;
2288   IRComparer<DCData>::analyzeIR(IR, Data);
2289   // Now compare it against itself, which will have everything the
2290   // same and will generate the files.
2291   IRComparer<DCData>(Data, Data)
2292       .compare(getModuleForComparison(IR),
2293                [&](bool InModule, unsigned Minor,
2294                    const FuncDataT<DCData> &Before,
2295                    const FuncDataT<DCData> &After) -> void {
2296                  handleFunctionCompare("", " ", "Initial IR", "", InModule,
2297                                        Minor, Before, After);
2298                });
2299   *HTML << "  </p>\n"
2300         << "</div><br/>\n";
2301   ++N;
2302 }
2303 
generateIRRepresentation(Any IR,StringRef PassID,IRDataT<DCData> & Data)2304 void DotCfgChangeReporter::generateIRRepresentation(Any IR, StringRef PassID,
2305                                                     IRDataT<DCData> &Data) {
2306   IRComparer<DCData>::analyzeIR(IR, Data);
2307 }
2308 
omitAfter(StringRef PassID,std::string & Name)2309 void DotCfgChangeReporter::omitAfter(StringRef PassID, std::string &Name) {
2310   assert(HTML && "Expected outstream to be set");
2311   SmallString<20> Banner =
2312       formatv("  <a>{0}. Pass {1} on {2} omitted because no change</a><br/>\n",
2313               N, makeHTMLReady(PassID), Name);
2314   *HTML << Banner;
2315   ++N;
2316 }
2317 
handleAfter(StringRef PassID,std::string & Name,const IRDataT<DCData> & Before,const IRDataT<DCData> & After,Any IR)2318 void DotCfgChangeReporter::handleAfter(StringRef PassID, std::string &Name,
2319                                        const IRDataT<DCData> &Before,
2320                                        const IRDataT<DCData> &After, Any IR) {
2321   assert(HTML && "Expected outstream to be set");
2322   IRComparer<DCData>(Before, After)
2323       .compare(getModuleForComparison(IR),
2324                [&](bool InModule, unsigned Minor,
2325                    const FuncDataT<DCData> &Before,
2326                    const FuncDataT<DCData> &After) -> void {
2327                  handleFunctionCompare(Name, " Pass ", PassID, " on ", InModule,
2328                                        Minor, Before, After);
2329                });
2330   *HTML << "    </p></div>\n";
2331   ++N;
2332 }
2333 
handleInvalidated(StringRef PassID)2334 void DotCfgChangeReporter::handleInvalidated(StringRef PassID) {
2335   assert(HTML && "Expected outstream to be set");
2336   SmallString<20> Banner =
2337       formatv("  <a>{0}. {1} invalidated</a><br/>\n", N, makeHTMLReady(PassID));
2338   *HTML << Banner;
2339   ++N;
2340 }
2341 
handleFiltered(StringRef PassID,std::string & Name)2342 void DotCfgChangeReporter::handleFiltered(StringRef PassID, std::string &Name) {
2343   assert(HTML && "Expected outstream to be set");
2344   SmallString<20> Banner =
2345       formatv("  <a>{0}. Pass {1} on {2} filtered out</a><br/>\n", N,
2346               makeHTMLReady(PassID), Name);
2347   *HTML << Banner;
2348   ++N;
2349 }
2350 
handleIgnored(StringRef PassID,std::string & Name)2351 void DotCfgChangeReporter::handleIgnored(StringRef PassID, std::string &Name) {
2352   assert(HTML && "Expected outstream to be set");
2353   SmallString<20> Banner = formatv("  <a>{0}. {1} on {2} ignored</a><br/>\n", N,
2354                                    makeHTMLReady(PassID), Name);
2355   *HTML << Banner;
2356   ++N;
2357 }
2358 
initializeHTML()2359 bool DotCfgChangeReporter::initializeHTML() {
2360   std::error_code EC;
2361   HTML = std::make_unique<raw_fd_ostream>(DotCfgDir + "/passes.html", EC);
2362   if (EC) {
2363     HTML = nullptr;
2364     return false;
2365   }
2366 
2367   *HTML << "<!doctype html>"
2368         << "<html>"
2369         << "<head>"
2370         << "<style>.collapsible { "
2371         << "background-color: #777;"
2372         << " color: white;"
2373         << " cursor: pointer;"
2374         << " padding: 18px;"
2375         << " width: 100%;"
2376         << " border: none;"
2377         << " text-align: left;"
2378         << " outline: none;"
2379         << " font-size: 15px;"
2380         << "} .active, .collapsible:hover {"
2381         << " background-color: #555;"
2382         << "} .content {"
2383         << " padding: 0 18px;"
2384         << " display: none;"
2385         << " overflow: hidden;"
2386         << " background-color: #f1f1f1;"
2387         << "}"
2388         << "</style>"
2389         << "<title>passes.html</title>"
2390         << "</head>\n"
2391         << "<body>";
2392   return true;
2393 }
2394 
~DotCfgChangeReporter()2395 DotCfgChangeReporter::~DotCfgChangeReporter() {
2396   if (!HTML)
2397     return;
2398   *HTML
2399       << "<script>var coll = document.getElementsByClassName(\"collapsible\");"
2400       << "var i;"
2401       << "for (i = 0; i < coll.length; i++) {"
2402       << "coll[i].addEventListener(\"click\", function() {"
2403       << " this.classList.toggle(\"active\");"
2404       << " var content = this.nextElementSibling;"
2405       << " if (content.style.display === \"block\"){"
2406       << " content.style.display = \"none\";"
2407       << " }"
2408       << " else {"
2409       << " content.style.display= \"block\";"
2410       << " }"
2411       << " });"
2412       << " }"
2413       << "</script>"
2414       << "</body>"
2415       << "</html>\n";
2416   HTML->flush();
2417   HTML->close();
2418 }
2419 
registerCallbacks(PassInstrumentationCallbacks & PIC)2420 void DotCfgChangeReporter::registerCallbacks(
2421     PassInstrumentationCallbacks &PIC) {
2422   if (PrintChanged == ChangePrinter::DotCfgVerbose ||
2423        PrintChanged == ChangePrinter::DotCfgQuiet) {
2424     SmallString<128> OutputDir;
2425     sys::fs::expand_tilde(DotCfgDir, OutputDir);
2426     sys::fs::make_absolute(OutputDir);
2427     assert(!OutputDir.empty() && "expected output dir to be non-empty");
2428     DotCfgDir = OutputDir.c_str();
2429     if (initializeHTML()) {
2430       ChangeReporter<IRDataT<DCData>>::registerRequiredCallbacks(PIC);
2431       return;
2432     }
2433     dbgs() << "Unable to open output stream for -cfg-dot-changed\n";
2434   }
2435 }
2436 
StandardInstrumentations(LLVMContext & Context,bool DebugLogging,bool VerifyEach,PrintPassOptions PrintPassOpts)2437 StandardInstrumentations::StandardInstrumentations(
2438     LLVMContext &Context, bool DebugLogging, bool VerifyEach,
2439     PrintPassOptions PrintPassOpts)
2440     : PrintPass(DebugLogging, PrintPassOpts), OptNone(DebugLogging),
2441       OptPassGate(Context),
2442       PrintChangedIR(PrintChanged == ChangePrinter::Verbose),
2443       PrintChangedDiff(PrintChanged == ChangePrinter::DiffVerbose ||
2444                            PrintChanged == ChangePrinter::ColourDiffVerbose,
2445                        PrintChanged == ChangePrinter::ColourDiffVerbose ||
2446                            PrintChanged == ChangePrinter::ColourDiffQuiet),
2447       WebsiteChangeReporter(PrintChanged == ChangePrinter::DotCfgVerbose),
2448       Verify(DebugLogging), DroppedStatsIR(DroppedVarStats),
2449       VerifyEach(VerifyEach) {}
2450 
2451 PrintCrashIRInstrumentation *PrintCrashIRInstrumentation::CrashReporter =
2452     nullptr;
2453 
reportCrashIR()2454 void PrintCrashIRInstrumentation::reportCrashIR() {
2455   if (!PrintOnCrashPath.empty()) {
2456     std::error_code EC;
2457     raw_fd_ostream Out(PrintOnCrashPath, EC);
2458     if (EC)
2459       report_fatal_error(errorCodeToError(EC));
2460     Out << SavedIR;
2461   } else {
2462     dbgs() << SavedIR;
2463   }
2464 }
2465 
SignalHandler(void *)2466 void PrintCrashIRInstrumentation::SignalHandler(void *) {
2467   // Called by signal handlers so do not lock here
2468   // Is the PrintCrashIRInstrumentation still alive?
2469   if (!CrashReporter)
2470     return;
2471 
2472   assert((PrintOnCrash || !PrintOnCrashPath.empty()) &&
2473          "Did not expect to get here without option set.");
2474   CrashReporter->reportCrashIR();
2475 }
2476 
~PrintCrashIRInstrumentation()2477 PrintCrashIRInstrumentation::~PrintCrashIRInstrumentation() {
2478   if (!CrashReporter)
2479     return;
2480 
2481   assert((PrintOnCrash || !PrintOnCrashPath.empty()) &&
2482          "Did not expect to get here without option set.");
2483   CrashReporter = nullptr;
2484 }
2485 
registerCallbacks(PassInstrumentationCallbacks & PIC)2486 void PrintCrashIRInstrumentation::registerCallbacks(
2487     PassInstrumentationCallbacks &PIC) {
2488   if ((!PrintOnCrash && PrintOnCrashPath.empty()) || CrashReporter)
2489     return;
2490 
2491   sys::AddSignalHandler(SignalHandler, nullptr);
2492   CrashReporter = this;
2493 
2494   PIC.registerBeforeNonSkippedPassCallback(
2495       [&PIC, this](StringRef PassID, Any IR) {
2496         SavedIR.clear();
2497         raw_string_ostream OS(SavedIR);
2498         OS << formatv("*** Dump of {0}IR Before Last Pass {1}",
2499                       llvm::forcePrintModuleIR() ? "Module " : "", PassID);
2500         if (!isInteresting(IR, PassID, PIC.getPassNameForClassName(PassID))) {
2501           OS << " Filtered Out ***\n";
2502           return;
2503         }
2504         OS << " Started ***\n";
2505         unwrapAndPrint(OS, IR);
2506       });
2507 }
2508 
registerCallbacks(PassInstrumentationCallbacks & PIC,ModuleAnalysisManager * MAM)2509 void StandardInstrumentations::registerCallbacks(
2510     PassInstrumentationCallbacks &PIC, ModuleAnalysisManager *MAM) {
2511   PrintIR.registerCallbacks(PIC);
2512   PrintPass.registerCallbacks(PIC);
2513   TimePasses.registerCallbacks(PIC);
2514   OptNone.registerCallbacks(PIC);
2515   OptPassGate.registerCallbacks(PIC);
2516   PrintChangedIR.registerCallbacks(PIC);
2517   PseudoProbeVerification.registerCallbacks(PIC);
2518   if (VerifyEach)
2519     Verify.registerCallbacks(PIC, MAM);
2520   PrintChangedDiff.registerCallbacks(PIC);
2521   WebsiteChangeReporter.registerCallbacks(PIC);
2522   ChangeTester.registerCallbacks(PIC);
2523   PrintCrashIR.registerCallbacks(PIC);
2524   DroppedStatsIR.registerCallbacks(PIC);
2525   if (MAM)
2526     PreservedCFGChecker.registerCallbacks(PIC, *MAM);
2527 
2528   // TimeProfiling records the pass running time cost.
2529   // Its 'BeforePassCallback' can be appended at the tail of all the
2530   // BeforeCallbacks by calling `registerCallbacks` in the end.
2531   // Its 'AfterPassCallback' is put at the front of all the
2532   // AfterCallbacks by its `registerCallbacks`. This is necessary
2533   // to ensure that other callbacks are not included in the timings.
2534   TimeProfilingPasses.registerCallbacks(PIC);
2535 }
2536 
2537 template class ChangeReporter<std::string>;
2538 template class TextChangeReporter<std::string>;
2539 
2540 template class BlockDataT<EmptyData>;
2541 template class FuncDataT<EmptyData>;
2542 template class IRDataT<EmptyData>;
2543 template class ChangeReporter<IRDataT<EmptyData>>;
2544 template class TextChangeReporter<IRDataT<EmptyData>>;
2545 template class IRComparer<EmptyData>;
2546 
2547 } // namespace llvm
2548