[clang][modules] Don't prevent translation of FW_Private includes when explicitly...
[llvm-project.git] / llvm / lib / Passes / StandardInstrumentations.cpp
blob06cc58c0219632dc8573a6464e9b7bd72ec9c8c6
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 //===----------------------------------------------------------------------===//
15 #include "llvm/Passes/StandardInstrumentations.h"
16 #include "llvm/ADT/Any.h"
17 #include "llvm/ADT/StableHashing.h"
18 #include "llvm/ADT/StringRef.h"
19 #include "llvm/Analysis/CallGraphSCCPass.h"
20 #include "llvm/Analysis/LazyCallGraph.h"
21 #include "llvm/Analysis/LoopInfo.h"
22 #include "llvm/IR/Constants.h"
23 #include "llvm/IR/Function.h"
24 #include "llvm/IR/Module.h"
25 #include "llvm/IR/PassInstrumentation.h"
26 #include "llvm/IR/PassManager.h"
27 #include "llvm/IR/PrintPasses.h"
28 #include "llvm/IR/StructuralHash.h"
29 #include "llvm/IR/Verifier.h"
30 #include "llvm/Support/CommandLine.h"
31 #include "llvm/Support/CrashRecoveryContext.h"
32 #include "llvm/Support/Debug.h"
33 #include "llvm/Support/Error.h"
34 #include "llvm/Support/FormatVariadic.h"
35 #include "llvm/Support/GraphWriter.h"
36 #include "llvm/Support/MemoryBuffer.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 <unordered_map>
43 #include <unordered_set>
44 #include <utility>
45 #include <vector>
47 using namespace llvm;
49 static cl::opt<bool> VerifyAnalysisInvalidation("verify-analysis-invalidation",
50 cl::Hidden,
51 #ifdef EXPENSIVE_CHECKS
52 cl::init(true)
53 #else
54 cl::init(false)
55 #endif
58 // An option that supports the -print-changed option. See
59 // the description for -print-changed for an explanation of the use
60 // of this option. Note that this option has no effect without -print-changed.
61 static cl::opt<bool>
62 PrintChangedBefore("print-before-changed",
63 cl::desc("Print before passes that change them"),
64 cl::init(false), cl::Hidden);
66 // An option for specifying the dot used by
67 // print-changed=[dot-cfg | dot-cfg-quiet]
68 static cl::opt<std::string>
69 DotBinary("print-changed-dot-path", cl::Hidden, cl::init("dot"),
70 cl::desc("system dot used by change reporters"));
72 // An option that determines the colour used for elements that are only
73 // in the before part. Must be a colour named in appendix J of
74 // https://graphviz.org/pdf/dotguide.pdf
75 static cl::opt<std::string>
76 BeforeColour("dot-cfg-before-color",
77 cl::desc("Color for dot-cfg before elements"), cl::Hidden,
78 cl::init("red"));
79 // An option that determines the colour used for elements that are only
80 // in the after part. Must be a colour named in appendix J of
81 // https://graphviz.org/pdf/dotguide.pdf
82 static cl::opt<std::string>
83 AfterColour("dot-cfg-after-color",
84 cl::desc("Color for dot-cfg after elements"), cl::Hidden,
85 cl::init("forestgreen"));
86 // An option that determines the colour used for elements that are in both
87 // the before and after parts. Must be a colour named in appendix J of
88 // https://graphviz.org/pdf/dotguide.pdf
89 static cl::opt<std::string>
90 CommonColour("dot-cfg-common-color",
91 cl::desc("Color for dot-cfg common elements"), cl::Hidden,
92 cl::init("black"));
94 // An option that determines where the generated website file (named
95 // passes.html) and the associated pdf files (named diff_*.pdf) are saved.
96 static cl::opt<std::string> DotCfgDir(
97 "dot-cfg-dir",
98 cl::desc("Generate dot files into specified directory for changed IRs"),
99 cl::Hidden, cl::init("./"));
101 // Options to print the IR that was being processed when a pass crashes.
102 static cl::opt<std::string> PrintOnCrashPath(
103 "print-on-crash-path",
104 cl::desc("Print the last form of the IR before crash to a file"),
105 cl::Hidden);
107 static cl::opt<bool> PrintOnCrash(
108 "print-on-crash",
109 cl::desc("Print the last form of the IR before crash (use -print-on-crash-path to dump to a file)"),
110 cl::Hidden);
112 static cl::opt<std::string> OptBisectPrintIRPath(
113 "opt-bisect-print-ir-path",
114 cl::desc("Print IR to path when opt-bisect-limit is reached"), cl::Hidden);
116 static cl::opt<bool> PrintPassNumbers(
117 "print-pass-numbers", cl::init(false), cl::Hidden,
118 cl::desc("Print pass names and their ordinals"));
120 static cl::opt<unsigned>
121 PrintAtPassNumber("print-at-pass-number", cl::init(0), cl::Hidden,
122 cl::desc("Print IR at pass with this number as "
123 "reported by print-passes-names"));
125 static cl::opt<std::string> IRDumpDirectory(
126 "ir-dump-directory",
127 cl::desc("If specified, IR printed using the "
128 "-print-[before|after]{-all} options will be dumped into "
129 "files in this directory rather than written to stderr"),
130 cl::Hidden, cl::value_desc("filename"));
132 namespace {
134 // An option for specifying an executable that will be called with the IR
135 // everytime it changes in the opt pipeline. It will also be called on
136 // the initial IR as it enters the pipeline. The executable will be passed
137 // the name of a temporary file containing the IR and the PassID. This may
138 // be used, for example, to call llc on the IR and run a test to determine
139 // which pass makes a change that changes the functioning of the IR.
140 // The usual modifier options work as expected.
141 static cl::opt<std::string>
142 TestChanged("exec-on-ir-change", cl::Hidden, cl::init(""),
143 cl::desc("exe called with module IR after each pass that "
144 "changes it"));
146 /// Extract Module out of \p IR unit. May return nullptr if \p IR does not match
147 /// certain global filters. Will never return nullptr if \p Force is true.
148 const Module *unwrapModule(Any IR, bool Force = false) {
149 if (const auto **M = llvm::any_cast<const Module *>(&IR))
150 return *M;
152 if (const auto **F = llvm::any_cast<const Function *>(&IR)) {
153 if (!Force && !isFunctionInPrintList((*F)->getName()))
154 return nullptr;
156 return (*F)->getParent();
159 if (const auto **C = llvm::any_cast<const LazyCallGraph::SCC *>(&IR)) {
160 for (const LazyCallGraph::Node &N : **C) {
161 const Function &F = N.getFunction();
162 if (Force || (!F.isDeclaration() && isFunctionInPrintList(F.getName()))) {
163 return F.getParent();
166 assert(!Force && "Expected a module");
167 return nullptr;
170 if (const auto **L = llvm::any_cast<const Loop *>(&IR)) {
171 const Function *F = (*L)->getHeader()->getParent();
172 if (!Force && !isFunctionInPrintList(F->getName()))
173 return nullptr;
174 return F->getParent();
177 llvm_unreachable("Unknown IR unit");
180 void printIR(raw_ostream &OS, const Function *F) {
181 if (!isFunctionInPrintList(F->getName()))
182 return;
183 OS << *F;
186 void printIR(raw_ostream &OS, const Module *M) {
187 if (isFunctionInPrintList("*") || forcePrintModuleIR()) {
188 M->print(OS, nullptr);
189 } else {
190 for (const auto &F : M->functions()) {
191 printIR(OS, &F);
196 void printIR(raw_ostream &OS, const LazyCallGraph::SCC *C) {
197 for (const LazyCallGraph::Node &N : *C) {
198 const Function &F = N.getFunction();
199 if (!F.isDeclaration() && isFunctionInPrintList(F.getName())) {
200 F.print(OS);
205 void printIR(raw_ostream &OS, const Loop *L) {
206 const Function *F = L->getHeader()->getParent();
207 if (!isFunctionInPrintList(F->getName()))
208 return;
209 printLoop(const_cast<Loop &>(*L), OS);
212 std::string getIRName(Any IR) {
213 if (llvm::any_cast<const Module *>(&IR))
214 return "[module]";
216 if (const auto **F = llvm::any_cast<const Function *>(&IR))
217 return (*F)->getName().str();
219 if (const auto **C = llvm::any_cast<const LazyCallGraph::SCC *>(&IR))
220 return (*C)->getName();
222 if (const auto **L = llvm::any_cast<const Loop *>(&IR))
223 return (*L)->getName().str();
225 llvm_unreachable("Unknown wrapped IR type");
228 bool moduleContainsFilterPrintFunc(const Module &M) {
229 return any_of(M.functions(),
230 [](const Function &F) {
231 return isFunctionInPrintList(F.getName());
232 }) ||
233 isFunctionInPrintList("*");
236 bool sccContainsFilterPrintFunc(const LazyCallGraph::SCC &C) {
237 return any_of(C,
238 [](const LazyCallGraph::Node &N) {
239 return isFunctionInPrintList(N.getName());
240 }) ||
241 isFunctionInPrintList("*");
244 bool shouldPrintIR(Any IR) {
245 if (const auto **M = llvm::any_cast<const Module *>(&IR))
246 return moduleContainsFilterPrintFunc(**M);
248 if (const auto **F = llvm::any_cast<const Function *>(&IR))
249 return isFunctionInPrintList((*F)->getName());
251 if (const auto **C = llvm::any_cast<const LazyCallGraph::SCC *>(&IR))
252 return sccContainsFilterPrintFunc(**C);
254 if (const auto **L = llvm::any_cast<const Loop *>(&IR))
255 return isFunctionInPrintList((*L)->getHeader()->getParent()->getName());
256 llvm_unreachable("Unknown wrapped IR type");
259 /// Generic IR-printing helper that unpacks a pointer to IRUnit wrapped into
260 /// Any and does actual print job.
261 void unwrapAndPrint(raw_ostream &OS, Any IR) {
262 if (!shouldPrintIR(IR))
263 return;
265 if (forcePrintModuleIR()) {
266 auto *M = unwrapModule(IR);
267 assert(M && "should have unwrapped module");
268 printIR(OS, M);
269 return;
272 if (const auto **M = llvm::any_cast<const Module *>(&IR)) {
273 printIR(OS, *M);
274 return;
277 if (const auto **F = llvm::any_cast<const Function *>(&IR)) {
278 printIR(OS, *F);
279 return;
282 if (const auto **C = llvm::any_cast<const LazyCallGraph::SCC *>(&IR)) {
283 printIR(OS, *C);
284 return;
287 if (const auto **L = llvm::any_cast<const Loop *>(&IR)) {
288 printIR(OS, *L);
289 return;
291 llvm_unreachable("Unknown wrapped IR type");
294 // Return true when this is a pass for which changes should be ignored
295 bool isIgnored(StringRef PassID) {
296 return isSpecialPass(PassID,
297 {"PassManager", "PassAdaptor", "AnalysisManagerProxy",
298 "DevirtSCCRepeatedPass", "ModuleInlinerWrapperPass",
299 "VerifierPass", "PrintModulePass"});
302 std::string makeHTMLReady(StringRef SR) {
303 std::string S;
304 while (true) {
305 StringRef Clean =
306 SR.take_until([](char C) { return C == '<' || C == '>'; });
307 S.append(Clean.str());
308 SR = SR.drop_front(Clean.size());
309 if (SR.size() == 0)
310 return S;
311 S.append(SR[0] == '<' ? "&lt;" : "&gt;");
312 SR = SR.drop_front();
314 llvm_unreachable("problems converting string to HTML");
317 // Return the module when that is the appropriate level of comparison for \p IR.
318 const Module *getModuleForComparison(Any IR) {
319 if (const auto **M = llvm::any_cast<const Module *>(&IR))
320 return *M;
321 if (const auto **C = llvm::any_cast<const LazyCallGraph::SCC *>(&IR))
322 return (*C)
323 ->begin()
324 ->getFunction()
325 .getParent();
326 return nullptr;
329 bool isInterestingFunction(const Function &F) {
330 return isFunctionInPrintList(F.getName());
333 // Return true when this is a pass on IR for which printing
334 // of changes is desired.
335 bool isInteresting(Any IR, StringRef PassID, StringRef PassName) {
336 if (isIgnored(PassID) || !isPassInPrintList(PassName))
337 return false;
338 if (const auto **F = llvm::any_cast<const Function *>(&IR))
339 return isInterestingFunction(**F);
340 return true;
343 } // namespace
345 template <typename T> ChangeReporter<T>::~ChangeReporter() {
346 assert(BeforeStack.empty() && "Problem with Change Printer stack.");
349 template <typename T>
350 void ChangeReporter<T>::saveIRBeforePass(Any IR, StringRef PassID,
351 StringRef PassName) {
352 // Is this the initial IR?
353 if (InitialIR) {
354 InitialIR = false;
355 if (VerboseMode)
356 handleInitialIR(IR);
359 // Always need to place something on the stack because invalidated passes
360 // are not given the IR so it cannot be determined whether the pass was for
361 // something that was filtered out.
362 BeforeStack.emplace_back();
364 if (!isInteresting(IR, PassID, PassName))
365 return;
367 // Save the IR representation on the stack.
368 T &Data = BeforeStack.back();
369 generateIRRepresentation(IR, PassID, Data);
372 template <typename T>
373 void ChangeReporter<T>::handleIRAfterPass(Any IR, StringRef PassID,
374 StringRef PassName) {
375 assert(!BeforeStack.empty() && "Unexpected empty stack encountered.");
377 std::string Name = getIRName(IR);
379 if (isIgnored(PassID)) {
380 if (VerboseMode)
381 handleIgnored(PassID, Name);
382 } else if (!isInteresting(IR, PassID, PassName)) {
383 if (VerboseMode)
384 handleFiltered(PassID, Name);
385 } else {
386 // Get the before rep from the stack
387 T &Before = BeforeStack.back();
388 // Create the after rep
389 T After;
390 generateIRRepresentation(IR, PassID, After);
392 // Was there a change in IR?
393 if (Before == After) {
394 if (VerboseMode)
395 omitAfter(PassID, Name);
396 } else
397 handleAfter(PassID, Name, Before, After, IR);
399 BeforeStack.pop_back();
402 template <typename T>
403 void ChangeReporter<T>::handleInvalidatedPass(StringRef PassID) {
404 assert(!BeforeStack.empty() && "Unexpected empty stack encountered.");
406 // Always flag it as invalidated as we cannot determine when
407 // a pass for a filtered function is invalidated since we do not
408 // get the IR in the call. Also, the output is just alternate
409 // forms of the banner anyway.
410 if (VerboseMode)
411 handleInvalidated(PassID);
412 BeforeStack.pop_back();
415 template <typename T>
416 void ChangeReporter<T>::registerRequiredCallbacks(
417 PassInstrumentationCallbacks &PIC) {
418 PIC.registerBeforeNonSkippedPassCallback([&PIC, this](StringRef P, Any IR) {
419 saveIRBeforePass(IR, P, PIC.getPassNameForClassName(P));
422 PIC.registerAfterPassCallback(
423 [&PIC, this](StringRef P, Any IR, const PreservedAnalyses &) {
424 handleIRAfterPass(IR, P, PIC.getPassNameForClassName(P));
426 PIC.registerAfterPassInvalidatedCallback(
427 [this](StringRef P, const PreservedAnalyses &) {
428 handleInvalidatedPass(P);
432 template <typename T>
433 TextChangeReporter<T>::TextChangeReporter(bool Verbose)
434 : ChangeReporter<T>(Verbose), Out(dbgs()) {}
436 template <typename T> void TextChangeReporter<T>::handleInitialIR(Any IR) {
437 // Always print the module.
438 // Unwrap and print directly to avoid filtering problems in general routines.
439 auto *M = unwrapModule(IR, /*Force=*/true);
440 assert(M && "Expected module to be unwrapped when forced.");
441 Out << "*** IR Dump At Start ***\n";
442 M->print(Out, nullptr);
445 template <typename T>
446 void TextChangeReporter<T>::omitAfter(StringRef PassID, std::string &Name) {
447 Out << formatv("*** IR Dump After {0} on {1} omitted because no change ***\n",
448 PassID, Name);
451 template <typename T>
452 void TextChangeReporter<T>::handleInvalidated(StringRef PassID) {
453 Out << formatv("*** IR Pass {0} invalidated ***\n", PassID);
456 template <typename T>
457 void TextChangeReporter<T>::handleFiltered(StringRef PassID,
458 std::string &Name) {
459 SmallString<20> Banner =
460 formatv("*** IR Dump After {0} on {1} filtered out ***\n", PassID, Name);
461 Out << Banner;
464 template <typename T>
465 void TextChangeReporter<T>::handleIgnored(StringRef PassID, std::string &Name) {
466 Out << formatv("*** IR Pass {0} on {1} ignored ***\n", PassID, Name);
469 IRChangedPrinter::~IRChangedPrinter() = default;
471 void IRChangedPrinter::registerCallbacks(PassInstrumentationCallbacks &PIC) {
472 if (PrintChanged == ChangePrinter::Verbose ||
473 PrintChanged == ChangePrinter::Quiet)
474 TextChangeReporter<std::string>::registerRequiredCallbacks(PIC);
477 void IRChangedPrinter::generateIRRepresentation(Any IR, StringRef PassID,
478 std::string &Output) {
479 raw_string_ostream OS(Output);
480 unwrapAndPrint(OS, IR);
481 OS.str();
484 void IRChangedPrinter::handleAfter(StringRef PassID, std::string &Name,
485 const std::string &Before,
486 const std::string &After, Any) {
487 // Report the IR before the changes when requested.
488 if (PrintChangedBefore)
489 Out << "*** IR Dump Before " << PassID << " on " << Name << " ***\n"
490 << Before;
492 // We might not get anything to print if we only want to print a specific
493 // function but it gets deleted.
494 if (After.empty()) {
495 Out << "*** IR Deleted After " << PassID << " on " << Name << " ***\n";
496 return;
499 Out << "*** IR Dump After " << PassID << " on " << Name << " ***\n" << After;
502 IRChangedTester::~IRChangedTester() {}
504 void IRChangedTester::registerCallbacks(PassInstrumentationCallbacks &PIC) {
505 if (TestChanged != "")
506 TextChangeReporter<std::string>::registerRequiredCallbacks(PIC);
509 void IRChangedTester::handleIR(const std::string &S, StringRef PassID) {
510 // Store the body into a temporary file
511 static SmallVector<int> FD{-1};
512 SmallVector<StringRef> SR{S};
513 static SmallVector<std::string> FileName{""};
514 if (prepareTempFiles(FD, SR, FileName)) {
515 dbgs() << "Unable to create temporary file.";
516 return;
518 static ErrorOr<std::string> Exe = sys::findProgramByName(TestChanged);
519 if (!Exe) {
520 dbgs() << "Unable to find test-changed executable.";
521 return;
524 StringRef Args[] = {TestChanged, FileName[0], PassID};
525 int Result = sys::ExecuteAndWait(*Exe, Args);
526 if (Result < 0) {
527 dbgs() << "Error executing test-changed executable.";
528 return;
531 if (cleanUpTempFiles(FileName))
532 dbgs() << "Unable to remove temporary file.";
535 void IRChangedTester::handleInitialIR(Any IR) {
536 // Always test the initial module.
537 // Unwrap and print directly to avoid filtering problems in general routines.
538 std::string S;
539 generateIRRepresentation(IR, "Initial IR", S);
540 handleIR(S, "Initial IR");
543 void IRChangedTester::omitAfter(StringRef PassID, std::string &Name) {}
544 void IRChangedTester::handleInvalidated(StringRef PassID) {}
545 void IRChangedTester::handleFiltered(StringRef PassID, std::string &Name) {}
546 void IRChangedTester::handleIgnored(StringRef PassID, std::string &Name) {}
547 void IRChangedTester::handleAfter(StringRef PassID, std::string &Name,
548 const std::string &Before,
549 const std::string &After, Any) {
550 handleIR(After, PassID);
553 template <typename T>
554 void OrderedChangedData<T>::report(
555 const OrderedChangedData &Before, const OrderedChangedData &After,
556 function_ref<void(const T *, const T *)> HandlePair) {
557 const auto &BFD = Before.getData();
558 const auto &AFD = After.getData();
559 std::vector<std::string>::const_iterator BI = Before.getOrder().begin();
560 std::vector<std::string>::const_iterator BE = Before.getOrder().end();
561 std::vector<std::string>::const_iterator AI = After.getOrder().begin();
562 std::vector<std::string>::const_iterator AE = After.getOrder().end();
564 auto HandlePotentiallyRemovedData = [&](std::string S) {
565 // The order in LLVM may have changed so check if still exists.
566 if (!AFD.count(S)) {
567 // This has been removed.
568 HandlePair(&BFD.find(*BI)->getValue(), nullptr);
571 auto HandleNewData = [&](std::vector<const T *> &Q) {
572 // Print out any queued up new sections
573 for (const T *NBI : Q)
574 HandlePair(nullptr, NBI);
575 Q.clear();
578 // Print out the data in the after order, with before ones interspersed
579 // appropriately (ie, somewhere near where they were in the before list).
580 // Start at the beginning of both lists. Loop through the
581 // after list. If an element is common, then advance in the before list
582 // reporting the removed ones until the common one is reached. Report any
583 // queued up new ones and then report the common one. If an element is not
584 // common, then enqueue it for reporting. When the after list is exhausted,
585 // loop through the before list, reporting any removed ones. Finally,
586 // report the rest of the enqueued new ones.
587 std::vector<const T *> NewDataQueue;
588 while (AI != AE) {
589 if (!BFD.count(*AI)) {
590 // This section is new so place it in the queue. This will cause it
591 // to be reported after deleted sections.
592 NewDataQueue.emplace_back(&AFD.find(*AI)->getValue());
593 ++AI;
594 continue;
596 // This section is in both; advance and print out any before-only
597 // until we get to it.
598 // It's possible that this section has moved to be later than before. This
599 // will mess up printing most blocks side by side, but it's a rare case and
600 // it's better than crashing.
601 while (BI != BE && *BI != *AI) {
602 HandlePotentiallyRemovedData(*BI);
603 ++BI;
605 // Report any new sections that were queued up and waiting.
606 HandleNewData(NewDataQueue);
608 const T &AData = AFD.find(*AI)->getValue();
609 const T &BData = BFD.find(*AI)->getValue();
610 HandlePair(&BData, &AData);
611 if (BI != BE)
612 ++BI;
613 ++AI;
616 // Check any remaining before sections to see if they have been removed
617 while (BI != BE) {
618 HandlePotentiallyRemovedData(*BI);
619 ++BI;
622 HandleNewData(NewDataQueue);
625 template <typename T>
626 void IRComparer<T>::compare(
627 bool CompareModule,
628 std::function<void(bool InModule, unsigned Minor,
629 const FuncDataT<T> &Before, const FuncDataT<T> &After)>
630 CompareFunc) {
631 if (!CompareModule) {
632 // Just handle the single function.
633 assert(Before.getData().size() == 1 && After.getData().size() == 1 &&
634 "Expected only one function.");
635 CompareFunc(false, 0, Before.getData().begin()->getValue(),
636 After.getData().begin()->getValue());
637 return;
640 unsigned Minor = 0;
641 FuncDataT<T> Missing("");
642 IRDataT<T>::report(Before, After,
643 [&](const FuncDataT<T> *B, const FuncDataT<T> *A) {
644 assert((B || A) && "Both functions cannot be missing.");
645 if (!B)
646 B = &Missing;
647 else if (!A)
648 A = &Missing;
649 CompareFunc(true, Minor++, *B, *A);
653 template <typename T> void IRComparer<T>::analyzeIR(Any IR, IRDataT<T> &Data) {
654 if (const Module *M = getModuleForComparison(IR)) {
655 // Create data for each existing/interesting function in the module.
656 for (const Function &F : *M)
657 generateFunctionData(Data, F);
658 return;
661 const Function **FPtr = llvm::any_cast<const Function *>(&IR);
662 const Function *F = FPtr ? *FPtr : nullptr;
663 if (!F) {
664 const Loop **L = llvm::any_cast<const Loop *>(&IR);
665 assert(L && "Unknown IR unit.");
666 F = (*L)->getHeader()->getParent();
668 assert(F && "Unknown IR unit.");
669 generateFunctionData(Data, *F);
672 template <typename T>
673 bool IRComparer<T>::generateFunctionData(IRDataT<T> &Data, const Function &F) {
674 if (!F.isDeclaration() && isFunctionInPrintList(F.getName())) {
675 FuncDataT<T> FD(F.getEntryBlock().getName().str());
676 int I = 0;
677 for (const auto &B : F) {
678 std::string BBName = B.getName().str();
679 if (BBName.empty()) {
680 BBName = formatv("{0}", I);
681 ++I;
683 FD.getOrder().emplace_back(BBName);
684 FD.getData().insert({BBName, B});
686 Data.getOrder().emplace_back(F.getName());
687 Data.getData().insert({F.getName(), FD});
688 return true;
690 return false;
693 PrintIRInstrumentation::~PrintIRInstrumentation() {
694 assert(PassRunDescriptorStack.empty() &&
695 "PassRunDescriptorStack is not empty at exit");
698 static SmallString<32> getIRFileDisplayName(Any IR) {
699 SmallString<32> Result;
700 raw_svector_ostream ResultStream(Result);
701 const Module *M = unwrapModule(IR);
702 stable_hash NameHash = stable_hash_combine_string(M->getName());
703 unsigned int MaxHashWidth = sizeof(stable_hash) * 8 / 4;
704 write_hex(ResultStream, NameHash, HexPrintStyle::Lower, MaxHashWidth);
705 if (llvm::any_cast<const Module *>(&IR)) {
706 ResultStream << "-module";
707 } else if (const Function **F = llvm::any_cast<const Function *>(&IR)) {
708 ResultStream << "-function-";
709 stable_hash FunctionNameHash = stable_hash_combine_string((*F)->getName());
710 write_hex(ResultStream, FunctionNameHash, HexPrintStyle::Lower,
711 MaxHashWidth);
712 } else if (const LazyCallGraph::SCC **C =
713 llvm::any_cast<const LazyCallGraph::SCC *>(&IR)) {
714 ResultStream << "-scc-";
715 stable_hash SCCNameHash = stable_hash_combine_string((*C)->getName());
716 write_hex(ResultStream, SCCNameHash, HexPrintStyle::Lower, MaxHashWidth);
717 } else if (const Loop **L = llvm::any_cast<const Loop *>(&IR)) {
718 ResultStream << "-loop-";
719 stable_hash LoopNameHash = stable_hash_combine_string((*L)->getName());
720 write_hex(ResultStream, LoopNameHash, HexPrintStyle::Lower, MaxHashWidth);
721 } else {
722 llvm_unreachable("Unknown wrapped IR type");
724 return Result;
727 std::string PrintIRInstrumentation::fetchDumpFilename(StringRef PassName,
728 Any IR) {
729 const StringRef RootDirectory = IRDumpDirectory;
730 assert(!RootDirectory.empty() &&
731 "The flag -ir-dump-directory must be passed to dump IR to files");
732 SmallString<128> ResultPath;
733 ResultPath += RootDirectory;
734 SmallString<64> Filename;
735 raw_svector_ostream FilenameStream(Filename);
736 FilenameStream << CurrentPassNumber;
737 FilenameStream << "-";
738 FilenameStream << getIRFileDisplayName(IR);
739 FilenameStream << "-";
740 FilenameStream << PassName;
741 sys::path::append(ResultPath, Filename);
742 return std::string(ResultPath);
745 enum class IRDumpFileSuffixType {
746 Before,
747 After,
748 Invalidated,
751 static StringRef getFileSuffix(IRDumpFileSuffixType Type) {
752 static constexpr std::array FileSuffixes = {"-before.ll", "-after.ll",
753 "-invalidated.ll"};
754 return FileSuffixes[static_cast<size_t>(Type)];
757 void PrintIRInstrumentation::pushPassRunDescriptor(
758 StringRef PassID, Any IR, std::string &DumpIRFilename) {
759 const Module *M = unwrapModule(IR);
760 PassRunDescriptorStack.emplace_back(
761 PassRunDescriptor(M, DumpIRFilename, getIRName(IR), PassID));
764 PrintIRInstrumentation::PassRunDescriptor
765 PrintIRInstrumentation::popPassRunDescriptor(StringRef PassID) {
766 assert(!PassRunDescriptorStack.empty() && "empty PassRunDescriptorStack");
767 PassRunDescriptor Descriptor = PassRunDescriptorStack.pop_back_val();
768 assert(Descriptor.PassID.equals(PassID) &&
769 "malformed PassRunDescriptorStack");
770 return Descriptor;
773 // Callers are responsible for closing the returned file descriptor
774 static int prepareDumpIRFileDescriptor(const StringRef DumpIRFilename) {
775 std::error_code EC;
776 auto ParentPath = llvm::sys::path::parent_path(DumpIRFilename);
777 if (!ParentPath.empty()) {
778 std::error_code EC = llvm::sys::fs::create_directories(ParentPath);
779 if (EC)
780 report_fatal_error(Twine("Failed to create directory ") + ParentPath +
781 " to support -ir-dump-directory: " + EC.message());
783 int Result = 0;
784 EC = sys::fs::openFile(DumpIRFilename, Result, sys::fs::CD_OpenAlways,
785 sys::fs::FA_Write, sys::fs::OF_None);
786 if (EC)
787 report_fatal_error(Twine("Failed to open ") + DumpIRFilename +
788 " to support -ir-dump-directory: " + EC.message());
789 return Result;
792 void PrintIRInstrumentation::printBeforePass(StringRef PassID, Any IR) {
793 if (isIgnored(PassID))
794 return;
796 std::string DumpIRFilename;
797 if (!IRDumpDirectory.empty() &&
798 (shouldPrintBeforePass(PassID) || shouldPrintAfterPass(PassID)))
799 DumpIRFilename = fetchDumpFilename(PassID, IR);
801 // Saving Module for AfterPassInvalidated operations.
802 // Note: here we rely on a fact that we do not change modules while
803 // traversing the pipeline, so the latest captured module is good
804 // for all print operations that has not happen yet.
805 if (shouldPrintPassNumbers() || shouldPrintAtPassNumber() ||
806 shouldPrintAfterPass(PassID))
807 pushPassRunDescriptor(PassID, IR, DumpIRFilename);
809 if (!shouldPrintIR(IR))
810 return;
812 ++CurrentPassNumber;
814 if (shouldPrintPassNumbers())
815 dbgs() << " Running pass " << CurrentPassNumber << " " << PassID
816 << " on " << getIRName(IR) << "\n";
818 if (!shouldPrintBeforePass(PassID))
819 return;
821 auto WriteIRToStream = [&](raw_ostream &Stream) {
822 Stream << "; *** IR Dump Before " << PassID << " on " << getIRName(IR)
823 << " ***\n";
824 unwrapAndPrint(Stream, IR);
827 if (!DumpIRFilename.empty()) {
828 DumpIRFilename += getFileSuffix(IRDumpFileSuffixType::Before);
829 llvm::raw_fd_ostream DumpIRFileStream{
830 prepareDumpIRFileDescriptor(DumpIRFilename), /* shouldClose */ true};
831 WriteIRToStream(DumpIRFileStream);
832 } else {
833 WriteIRToStream(dbgs());
837 void PrintIRInstrumentation::printAfterPass(StringRef PassID, Any IR) {
838 if (isIgnored(PassID))
839 return;
841 if (!shouldPrintAfterPass(PassID) && !shouldPrintPassNumbers() &&
842 !shouldPrintAtPassNumber())
843 return;
845 auto [M, DumpIRFilename, IRName, StoredPassID] = popPassRunDescriptor(PassID);
846 assert(StoredPassID == PassID && "mismatched PassID");
848 if (!shouldPrintIR(IR) || !shouldPrintAfterPass(PassID))
849 return;
851 auto WriteIRToStream = [&](raw_ostream &Stream, const StringRef IRName) {
852 Stream << "; *** IR Dump "
853 << (shouldPrintAtPassNumber()
854 ? StringRef(formatv("At {0}-{1}", CurrentPassNumber, PassID))
855 : StringRef(formatv("After {0}", PassID)))
856 << " on " << IRName << " ***\n";
857 unwrapAndPrint(Stream, IR);
860 if (!IRDumpDirectory.empty()) {
861 assert(!DumpIRFilename.empty() && "DumpIRFilename must not be empty and "
862 "should be set in printBeforePass");
863 const std::string DumpIRFilenameWithSuffix =
864 DumpIRFilename + getFileSuffix(IRDumpFileSuffixType::After).str();
865 llvm::raw_fd_ostream DumpIRFileStream{
866 prepareDumpIRFileDescriptor(DumpIRFilenameWithSuffix),
867 /* shouldClose */ true};
868 WriteIRToStream(DumpIRFileStream, IRName);
869 } else {
870 WriteIRToStream(dbgs(), IRName);
874 void PrintIRInstrumentation::printAfterPassInvalidated(StringRef PassID) {
875 if (isIgnored(PassID))
876 return;
878 if (!shouldPrintAfterPass(PassID) && !shouldPrintPassNumbers() &&
879 !shouldPrintAtPassNumber())
880 return;
882 auto [M, DumpIRFilename, IRName, StoredPassID] = popPassRunDescriptor(PassID);
883 assert(StoredPassID == PassID && "mismatched PassID");
884 // Additional filtering (e.g. -filter-print-func) can lead to module
885 // printing being skipped.
886 if (!M || !shouldPrintAfterPass(PassID))
887 return;
889 auto WriteIRToStream = [&](raw_ostream &Stream, const Module *M,
890 const StringRef IRName) {
891 SmallString<20> Banner;
892 if (shouldPrintAtPassNumber())
893 Banner = formatv("; *** IR Dump At {0}-{1} on {2} (invalidated) ***",
894 CurrentPassNumber, PassID, IRName);
895 else
896 Banner = formatv("; *** IR Dump After {0} on {1} (invalidated) ***",
897 PassID, IRName);
898 Stream << Banner << "\n";
899 printIR(Stream, M);
902 if (!IRDumpDirectory.empty()) {
903 assert(!DumpIRFilename.empty() && "DumpIRFilename must not be empty and "
904 "should be set in printBeforePass");
905 const std::string DumpIRFilenameWithSuffix =
906 DumpIRFilename + getFileSuffix(IRDumpFileSuffixType::Invalidated).str();
907 llvm::raw_fd_ostream DumpIRFileStream{
908 prepareDumpIRFileDescriptor(DumpIRFilenameWithSuffix),
909 /* shouldClose */ true};
910 WriteIRToStream(DumpIRFileStream, M, IRName);
911 } else {
912 WriteIRToStream(dbgs(), M, IRName);
916 bool PrintIRInstrumentation::shouldPrintBeforePass(StringRef PassID) {
917 if (shouldPrintBeforeAll())
918 return true;
920 StringRef PassName = PIC->getPassNameForClassName(PassID);
921 return is_contained(printBeforePasses(), PassName);
924 bool PrintIRInstrumentation::shouldPrintAfterPass(StringRef PassID) {
925 if (shouldPrintAfterAll())
926 return true;
928 if (shouldPrintAtPassNumber() && CurrentPassNumber == PrintAtPassNumber)
929 return true;
931 StringRef PassName = PIC->getPassNameForClassName(PassID);
932 return is_contained(printAfterPasses(), PassName);
935 bool PrintIRInstrumentation::shouldPrintPassNumbers() {
936 return PrintPassNumbers;
939 bool PrintIRInstrumentation::shouldPrintAtPassNumber() {
940 return PrintAtPassNumber > 0;
943 void PrintIRInstrumentation::registerCallbacks(
944 PassInstrumentationCallbacks &PIC) {
945 this->PIC = &PIC;
947 // BeforePass callback is not just for printing, it also saves a Module
948 // for later use in AfterPassInvalidated.
949 if (shouldPrintPassNumbers() || shouldPrintAtPassNumber() ||
950 shouldPrintBeforeSomePass() || shouldPrintAfterSomePass())
951 PIC.registerBeforeNonSkippedPassCallback(
952 [this](StringRef P, Any IR) { this->printBeforePass(P, IR); });
954 if (shouldPrintPassNumbers() || shouldPrintAtPassNumber() ||
955 shouldPrintAfterSomePass()) {
956 PIC.registerAfterPassCallback(
957 [this](StringRef P, Any IR, const PreservedAnalyses &) {
958 this->printAfterPass(P, IR);
960 PIC.registerAfterPassInvalidatedCallback(
961 [this](StringRef P, const PreservedAnalyses &) {
962 this->printAfterPassInvalidated(P);
967 void OptNoneInstrumentation::registerCallbacks(
968 PassInstrumentationCallbacks &PIC) {
969 PIC.registerShouldRunOptionalPassCallback(
970 [this](StringRef P, Any IR) { return this->shouldRun(P, IR); });
973 bool OptNoneInstrumentation::shouldRun(StringRef PassID, Any IR) {
974 const Function **FPtr = llvm::any_cast<const Function *>(&IR);
975 const Function *F = FPtr ? *FPtr : nullptr;
976 if (!F) {
977 if (const auto **L = llvm::any_cast<const Loop *>(&IR))
978 F = (*L)->getHeader()->getParent();
980 bool ShouldRun = !(F && F->hasOptNone());
981 if (!ShouldRun && DebugLogging) {
982 errs() << "Skipping pass " << PassID << " on " << F->getName()
983 << " due to optnone attribute\n";
985 return ShouldRun;
988 bool OptPassGateInstrumentation::shouldRun(StringRef PassName, Any IR) {
989 if (isIgnored(PassName))
990 return true;
992 bool ShouldRun =
993 Context.getOptPassGate().shouldRunPass(PassName, getIRName(IR));
994 if (!ShouldRun && !this->HasWrittenIR && !OptBisectPrintIRPath.empty()) {
995 // FIXME: print IR if limit is higher than number of opt-bisect
996 // invocations
997 this->HasWrittenIR = true;
998 const Module *M = unwrapModule(IR, /*Force=*/true);
999 assert((M && &M->getContext() == &Context) && "Missing/Mismatching Module");
1000 std::error_code EC;
1001 raw_fd_ostream OS(OptBisectPrintIRPath, EC);
1002 if (EC)
1003 report_fatal_error(errorCodeToError(EC));
1004 M->print(OS, nullptr);
1006 return ShouldRun;
1009 void OptPassGateInstrumentation::registerCallbacks(
1010 PassInstrumentationCallbacks &PIC) {
1011 OptPassGate &PassGate = Context.getOptPassGate();
1012 if (!PassGate.isEnabled())
1013 return;
1015 PIC.registerShouldRunOptionalPassCallback([this](StringRef PassName, Any IR) {
1016 return this->shouldRun(PassName, IR);
1020 raw_ostream &PrintPassInstrumentation::print() {
1021 if (Opts.Indent) {
1022 assert(Indent >= 0);
1023 dbgs().indent(Indent);
1025 return dbgs();
1028 void PrintPassInstrumentation::registerCallbacks(
1029 PassInstrumentationCallbacks &PIC) {
1030 if (!Enabled)
1031 return;
1033 std::vector<StringRef> SpecialPasses;
1034 if (!Opts.Verbose) {
1035 SpecialPasses.emplace_back("PassManager");
1036 SpecialPasses.emplace_back("PassAdaptor");
1039 PIC.registerBeforeSkippedPassCallback([this, SpecialPasses](StringRef PassID,
1040 Any IR) {
1041 assert(!isSpecialPass(PassID, SpecialPasses) &&
1042 "Unexpectedly skipping special pass");
1044 print() << "Skipping pass: " << PassID << " on " << getIRName(IR) << "\n";
1046 PIC.registerBeforeNonSkippedPassCallback([this, SpecialPasses](
1047 StringRef PassID, Any IR) {
1048 if (isSpecialPass(PassID, SpecialPasses))
1049 return;
1051 auto &OS = print();
1052 OS << "Running pass: " << PassID << " on " << getIRName(IR);
1053 if (const auto **F = llvm::any_cast<const Function *>(&IR)) {
1054 unsigned Count = (*F)->getInstructionCount();
1055 OS << " (" << Count << " instruction";
1056 if (Count != 1)
1057 OS << 's';
1058 OS << ')';
1059 } else if (const auto **C =
1060 llvm::any_cast<const LazyCallGraph::SCC *>(&IR)) {
1061 int Count = (*C)->size();
1062 OS << " (" << Count << " node";
1063 if (Count != 1)
1064 OS << 's';
1065 OS << ')';
1067 OS << "\n";
1068 Indent += 2;
1070 PIC.registerAfterPassCallback(
1071 [this, SpecialPasses](StringRef PassID, Any IR,
1072 const PreservedAnalyses &) {
1073 if (isSpecialPass(PassID, SpecialPasses))
1074 return;
1076 Indent -= 2;
1078 PIC.registerAfterPassInvalidatedCallback(
1079 [this, SpecialPasses](StringRef PassID, Any IR) {
1080 if (isSpecialPass(PassID, SpecialPasses))
1081 return;
1083 Indent -= 2;
1086 if (!Opts.SkipAnalyses) {
1087 PIC.registerBeforeAnalysisCallback([this](StringRef PassID, Any IR) {
1088 print() << "Running analysis: " << PassID << " on " << getIRName(IR)
1089 << "\n";
1090 Indent += 2;
1092 PIC.registerAfterAnalysisCallback(
1093 [this](StringRef PassID, Any IR) { Indent -= 2; });
1094 PIC.registerAnalysisInvalidatedCallback([this](StringRef PassID, Any IR) {
1095 print() << "Invalidating analysis: " << PassID << " on " << getIRName(IR)
1096 << "\n";
1098 PIC.registerAnalysesClearedCallback([this](StringRef IRName) {
1099 print() << "Clearing all analysis results for: " << IRName << "\n";
1104 PreservedCFGCheckerInstrumentation::CFG::CFG(const Function *F,
1105 bool TrackBBLifetime) {
1106 if (TrackBBLifetime)
1107 BBGuards = DenseMap<intptr_t, BBGuard>(F->size());
1108 for (const auto &BB : *F) {
1109 if (BBGuards)
1110 BBGuards->try_emplace(intptr_t(&BB), &BB);
1111 for (const auto *Succ : successors(&BB)) {
1112 Graph[&BB][Succ]++;
1113 if (BBGuards)
1114 BBGuards->try_emplace(intptr_t(Succ), Succ);
1119 static void printBBName(raw_ostream &out, const BasicBlock *BB) {
1120 if (BB->hasName()) {
1121 out << BB->getName() << "<" << BB << ">";
1122 return;
1125 if (!BB->getParent()) {
1126 out << "unnamed_removed<" << BB << ">";
1127 return;
1130 if (BB->isEntryBlock()) {
1131 out << "entry"
1132 << "<" << BB << ">";
1133 return;
1136 unsigned FuncOrderBlockNum = 0;
1137 for (auto &FuncBB : *BB->getParent()) {
1138 if (&FuncBB == BB)
1139 break;
1140 FuncOrderBlockNum++;
1142 out << "unnamed_" << FuncOrderBlockNum << "<" << BB << ">";
1145 void PreservedCFGCheckerInstrumentation::CFG::printDiff(raw_ostream &out,
1146 const CFG &Before,
1147 const CFG &After) {
1148 assert(!After.isPoisoned());
1149 if (Before.isPoisoned()) {
1150 out << "Some blocks were deleted\n";
1151 return;
1154 // Find and print graph differences.
1155 if (Before.Graph.size() != After.Graph.size())
1156 out << "Different number of non-leaf basic blocks: before="
1157 << Before.Graph.size() << ", after=" << After.Graph.size() << "\n";
1159 for (auto &BB : Before.Graph) {
1160 auto BA = After.Graph.find(BB.first);
1161 if (BA == After.Graph.end()) {
1162 out << "Non-leaf block ";
1163 printBBName(out, BB.first);
1164 out << " is removed (" << BB.second.size() << " successors)\n";
1168 for (auto &BA : After.Graph) {
1169 auto BB = Before.Graph.find(BA.first);
1170 if (BB == Before.Graph.end()) {
1171 out << "Non-leaf block ";
1172 printBBName(out, BA.first);
1173 out << " is added (" << BA.second.size() << " successors)\n";
1174 continue;
1177 if (BB->second == BA.second)
1178 continue;
1180 out << "Different successors of block ";
1181 printBBName(out, BA.first);
1182 out << " (unordered):\n";
1183 out << "- before (" << BB->second.size() << "): ";
1184 for (auto &SuccB : BB->second) {
1185 printBBName(out, SuccB.first);
1186 if (SuccB.second != 1)
1187 out << "(" << SuccB.second << "), ";
1188 else
1189 out << ", ";
1191 out << "\n";
1192 out << "- after (" << BA.second.size() << "): ";
1193 for (auto &SuccA : BA.second) {
1194 printBBName(out, SuccA.first);
1195 if (SuccA.second != 1)
1196 out << "(" << SuccA.second << "), ";
1197 else
1198 out << ", ";
1200 out << "\n";
1204 // PreservedCFGCheckerInstrumentation uses PreservedCFGCheckerAnalysis to check
1205 // passes, that reported they kept CFG analyses up-to-date, did not actually
1206 // change CFG. This check is done as follows. Before every functional pass in
1207 // BeforeNonSkippedPassCallback a CFG snapshot (an instance of
1208 // PreservedCFGCheckerInstrumentation::CFG) is requested from
1209 // FunctionAnalysisManager as a result of PreservedCFGCheckerAnalysis. When the
1210 // functional pass finishes and reports that CFGAnalyses or AllAnalyses are
1211 // up-to-date then the cached result of PreservedCFGCheckerAnalysis (if
1212 // available) is checked to be equal to a freshly created CFG snapshot.
1213 struct PreservedCFGCheckerAnalysis
1214 : public AnalysisInfoMixin<PreservedCFGCheckerAnalysis> {
1215 friend AnalysisInfoMixin<PreservedCFGCheckerAnalysis>;
1217 static AnalysisKey Key;
1219 public:
1220 /// Provide the result type for this analysis pass.
1221 using Result = PreservedCFGCheckerInstrumentation::CFG;
1223 /// Run the analysis pass over a function and produce CFG.
1224 Result run(Function &F, FunctionAnalysisManager &FAM) {
1225 return Result(&F, /* TrackBBLifetime */ true);
1229 AnalysisKey PreservedCFGCheckerAnalysis::Key;
1231 struct PreservedFunctionHashAnalysis
1232 : public AnalysisInfoMixin<PreservedFunctionHashAnalysis> {
1233 static AnalysisKey Key;
1235 struct FunctionHash {
1236 uint64_t Hash;
1239 using Result = FunctionHash;
1241 Result run(Function &F, FunctionAnalysisManager &FAM) {
1242 return Result{StructuralHash(F)};
1246 AnalysisKey PreservedFunctionHashAnalysis::Key;
1248 struct PreservedModuleHashAnalysis
1249 : public AnalysisInfoMixin<PreservedModuleHashAnalysis> {
1250 static AnalysisKey Key;
1252 struct ModuleHash {
1253 uint64_t Hash;
1256 using Result = ModuleHash;
1258 Result run(Module &F, ModuleAnalysisManager &FAM) {
1259 return Result{StructuralHash(F)};
1263 AnalysisKey PreservedModuleHashAnalysis::Key;
1265 bool PreservedCFGCheckerInstrumentation::CFG::invalidate(
1266 Function &F, const PreservedAnalyses &PA,
1267 FunctionAnalysisManager::Invalidator &) {
1268 auto PAC = PA.getChecker<PreservedCFGCheckerAnalysis>();
1269 return !(PAC.preserved() || PAC.preservedSet<AllAnalysesOn<Function>>() ||
1270 PAC.preservedSet<CFGAnalyses>());
1273 static SmallVector<Function *, 1> GetFunctions(Any IR) {
1274 SmallVector<Function *, 1> Functions;
1276 if (const auto **MaybeF = llvm::any_cast<const Function *>(&IR)) {
1277 Functions.push_back(*const_cast<Function **>(MaybeF));
1278 } else if (const auto **MaybeM = llvm::any_cast<const Module *>(&IR)) {
1279 for (Function &F : **const_cast<Module **>(MaybeM))
1280 Functions.push_back(&F);
1282 return Functions;
1285 void PreservedCFGCheckerInstrumentation::registerCallbacks(
1286 PassInstrumentationCallbacks &PIC, ModuleAnalysisManager &MAM) {
1287 if (!VerifyAnalysisInvalidation)
1288 return;
1290 bool Registered = false;
1291 PIC.registerBeforeNonSkippedPassCallback([this, &MAM, Registered](
1292 StringRef P, Any IR) mutable {
1293 #ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
1294 assert(&PassStack.emplace_back(P));
1295 #endif
1296 (void)this;
1298 auto &FAM = MAM.getResult<FunctionAnalysisManagerModuleProxy>(
1299 *const_cast<Module *>(unwrapModule(IR, /*Force=*/true)))
1300 .getManager();
1301 if (!Registered) {
1302 FAM.registerPass([&] { return PreservedCFGCheckerAnalysis(); });
1303 FAM.registerPass([&] { return PreservedFunctionHashAnalysis(); });
1304 MAM.registerPass([&] { return PreservedModuleHashAnalysis(); });
1305 Registered = true;
1308 for (Function *F : GetFunctions(IR)) {
1309 // Make sure a fresh CFG snapshot is available before the pass.
1310 FAM.getResult<PreservedCFGCheckerAnalysis>(*F);
1311 FAM.getResult<PreservedFunctionHashAnalysis>(*F);
1314 if (auto *MaybeM = llvm::any_cast<const Module *>(&IR)) {
1315 Module &M = **const_cast<Module **>(MaybeM);
1316 MAM.getResult<PreservedModuleHashAnalysis>(M);
1320 PIC.registerAfterPassInvalidatedCallback(
1321 [this](StringRef P, const PreservedAnalyses &PassPA) {
1322 #ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
1323 assert(PassStack.pop_back_val() == P &&
1324 "Before and After callbacks must correspond");
1325 #endif
1326 (void)this;
1329 PIC.registerAfterPassCallback([this, &MAM](StringRef P, Any IR,
1330 const PreservedAnalyses &PassPA) {
1331 #ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
1332 assert(PassStack.pop_back_val() == P &&
1333 "Before and After callbacks must correspond");
1334 #endif
1335 (void)this;
1337 // We have to get the FAM via the MAM, rather than directly use a passed in
1338 // FAM because if MAM has not cached the FAM, it won't invalidate function
1339 // analyses in FAM.
1340 auto &FAM = MAM.getResult<FunctionAnalysisManagerModuleProxy>(
1341 *const_cast<Module *>(unwrapModule(IR, /*Force=*/true)))
1342 .getManager();
1344 for (Function *F : GetFunctions(IR)) {
1345 if (auto *HashBefore =
1346 FAM.getCachedResult<PreservedFunctionHashAnalysis>(*F)) {
1347 if (HashBefore->Hash != StructuralHash(*F)) {
1348 report_fatal_error(formatv(
1349 "Function @{0} changed by {1} without invalidating analyses",
1350 F->getName(), P));
1354 auto CheckCFG = [](StringRef Pass, StringRef FuncName,
1355 const CFG &GraphBefore, const CFG &GraphAfter) {
1356 if (GraphAfter == GraphBefore)
1357 return;
1359 dbgs()
1360 << "Error: " << Pass
1361 << " does not invalidate CFG analyses but CFG changes detected in "
1362 "function @"
1363 << FuncName << ":\n";
1364 CFG::printDiff(dbgs(), GraphBefore, GraphAfter);
1365 report_fatal_error(Twine("CFG unexpectedly changed by ", Pass));
1368 if (auto *GraphBefore =
1369 FAM.getCachedResult<PreservedCFGCheckerAnalysis>(*F))
1370 CheckCFG(P, F->getName(), *GraphBefore,
1371 CFG(F, /* TrackBBLifetime */ false));
1373 if (auto *MaybeM = llvm::any_cast<const Module *>(&IR)) {
1374 Module &M = **const_cast<Module **>(MaybeM);
1375 if (auto *HashBefore =
1376 MAM.getCachedResult<PreservedModuleHashAnalysis>(M)) {
1377 if (HashBefore->Hash != StructuralHash(M)) {
1378 report_fatal_error(formatv(
1379 "Module changed by {0} without invalidating analyses", P));
1386 void VerifyInstrumentation::registerCallbacks(
1387 PassInstrumentationCallbacks &PIC) {
1388 PIC.registerAfterPassCallback(
1389 [this](StringRef P, Any IR, const PreservedAnalyses &PassPA) {
1390 if (isIgnored(P) || P == "VerifierPass")
1391 return;
1392 const Function **FPtr = llvm::any_cast<const Function *>(&IR);
1393 const Function *F = FPtr ? *FPtr : nullptr;
1394 if (!F) {
1395 if (const auto **L = llvm::any_cast<const Loop *>(&IR))
1396 F = (*L)->getHeader()->getParent();
1399 if (F) {
1400 if (DebugLogging)
1401 dbgs() << "Verifying function " << F->getName() << "\n";
1403 if (verifyFunction(*F, &errs()))
1404 report_fatal_error("Broken function found, compilation aborted!");
1405 } else {
1406 const Module **MPtr = llvm::any_cast<const Module *>(&IR);
1407 const Module *M = MPtr ? *MPtr : nullptr;
1408 if (!M) {
1409 if (const auto **C =
1410 llvm::any_cast<const LazyCallGraph::SCC *>(&IR))
1411 M = (*C)->begin()->getFunction().getParent();
1414 if (M) {
1415 if (DebugLogging)
1416 dbgs() << "Verifying module " << M->getName() << "\n";
1418 if (verifyModule(*M, &errs()))
1419 report_fatal_error("Broken module found, compilation aborted!");
1425 InLineChangePrinter::~InLineChangePrinter() = default;
1427 void InLineChangePrinter::generateIRRepresentation(Any IR,
1428 StringRef PassID,
1429 IRDataT<EmptyData> &D) {
1430 IRComparer<EmptyData>::analyzeIR(IR, D);
1433 void InLineChangePrinter::handleAfter(StringRef PassID, std::string &Name,
1434 const IRDataT<EmptyData> &Before,
1435 const IRDataT<EmptyData> &After,
1436 Any IR) {
1437 SmallString<20> Banner =
1438 formatv("*** IR Dump After {0} on {1} ***\n", PassID, Name);
1439 Out << Banner;
1440 IRComparer<EmptyData>(Before, After)
1441 .compare(getModuleForComparison(IR),
1442 [&](bool InModule, unsigned Minor,
1443 const FuncDataT<EmptyData> &Before,
1444 const FuncDataT<EmptyData> &After) -> void {
1445 handleFunctionCompare(Name, "", PassID, " on ", InModule,
1446 Minor, Before, After);
1448 Out << "\n";
1451 void InLineChangePrinter::handleFunctionCompare(
1452 StringRef Name, StringRef Prefix, StringRef PassID, StringRef Divider,
1453 bool InModule, unsigned Minor, const FuncDataT<EmptyData> &Before,
1454 const FuncDataT<EmptyData> &After) {
1455 // Print a banner when this is being shown in the context of a module
1456 if (InModule)
1457 Out << "\n*** IR for function " << Name << " ***\n";
1459 FuncDataT<EmptyData>::report(
1460 Before, After,
1461 [&](const BlockDataT<EmptyData> *B, const BlockDataT<EmptyData> *A) {
1462 StringRef BStr = B ? B->getBody() : "\n";
1463 StringRef AStr = A ? A->getBody() : "\n";
1464 const std::string Removed =
1465 UseColour ? "\033[31m-%l\033[0m\n" : "-%l\n";
1466 const std::string Added = UseColour ? "\033[32m+%l\033[0m\n" : "+%l\n";
1467 const std::string NoChange = " %l\n";
1468 Out << doSystemDiff(BStr, AStr, Removed, Added, NoChange);
1472 void InLineChangePrinter::registerCallbacks(PassInstrumentationCallbacks &PIC) {
1473 if (PrintChanged == ChangePrinter::DiffVerbose ||
1474 PrintChanged == ChangePrinter::DiffQuiet ||
1475 PrintChanged == ChangePrinter::ColourDiffVerbose ||
1476 PrintChanged == ChangePrinter::ColourDiffQuiet)
1477 TextChangeReporter<IRDataT<EmptyData>>::registerRequiredCallbacks(PIC);
1480 TimeProfilingPassesHandler::TimeProfilingPassesHandler() {}
1482 void TimeProfilingPassesHandler::registerCallbacks(
1483 PassInstrumentationCallbacks &PIC) {
1484 if (!getTimeTraceProfilerInstance())
1485 return;
1486 PIC.registerBeforeNonSkippedPassCallback(
1487 [this](StringRef P, Any IR) { this->runBeforePass(P, IR); });
1488 PIC.registerAfterPassCallback(
1489 [this](StringRef P, Any IR, const PreservedAnalyses &) {
1490 this->runAfterPass();
1492 true);
1493 PIC.registerAfterPassInvalidatedCallback(
1494 [this](StringRef P, const PreservedAnalyses &) { this->runAfterPass(); },
1495 true);
1496 PIC.registerBeforeAnalysisCallback(
1497 [this](StringRef P, Any IR) { this->runBeforePass(P, IR); });
1498 PIC.registerAfterAnalysisCallback(
1499 [this](StringRef P, Any IR) { this->runAfterPass(); }, true);
1502 void TimeProfilingPassesHandler::runBeforePass(StringRef PassID, Any IR) {
1503 timeTraceProfilerBegin(PassID, getIRName(IR));
1506 void TimeProfilingPassesHandler::runAfterPass() { timeTraceProfilerEnd(); }
1508 namespace {
1510 class DisplayNode;
1511 class DotCfgDiffDisplayGraph;
1513 // Base class for a node or edge in the dot-cfg-changes graph.
1514 class DisplayElement {
1515 public:
1516 // Is this in before, after, or both?
1517 StringRef getColour() const { return Colour; }
1519 protected:
1520 DisplayElement(StringRef Colour) : Colour(Colour) {}
1521 const StringRef Colour;
1524 // An edge representing a transition between basic blocks in the
1525 // dot-cfg-changes graph.
1526 class DisplayEdge : public DisplayElement {
1527 public:
1528 DisplayEdge(std::string Value, DisplayNode &Node, StringRef Colour)
1529 : DisplayElement(Colour), Value(Value), Node(Node) {}
1530 // The value on which the transition is made.
1531 std::string getValue() const { return Value; }
1532 // The node (representing a basic block) reached by this transition.
1533 const DisplayNode &getDestinationNode() const { return Node; }
1535 protected:
1536 std::string Value;
1537 const DisplayNode &Node;
1540 // A node in the dot-cfg-changes graph which represents a basic block.
1541 class DisplayNode : public DisplayElement {
1542 public:
1543 // \p C is the content for the node, \p T indicates the colour for the
1544 // outline of the node
1545 DisplayNode(std::string Content, StringRef Colour)
1546 : DisplayElement(Colour), Content(Content) {}
1548 // Iterator to the child nodes. Required by GraphWriter.
1549 using ChildIterator = std::unordered_set<DisplayNode *>::const_iterator;
1550 ChildIterator children_begin() const { return Children.cbegin(); }
1551 ChildIterator children_end() const { return Children.cend(); }
1553 // Iterator for the edges. Required by GraphWriter.
1554 using EdgeIterator = std::vector<DisplayEdge *>::const_iterator;
1555 EdgeIterator edges_begin() const { return EdgePtrs.cbegin(); }
1556 EdgeIterator edges_end() const { return EdgePtrs.cend(); }
1558 // Create an edge to \p Node on value \p Value, with colour \p Colour.
1559 void createEdge(StringRef Value, DisplayNode &Node, StringRef Colour);
1561 // Return the content of this node.
1562 std::string getContent() const { return Content; }
1564 // Return the edge to node \p S.
1565 const DisplayEdge &getEdge(const DisplayNode &To) const {
1566 assert(EdgeMap.find(&To) != EdgeMap.end() && "Expected to find edge.");
1567 return *EdgeMap.find(&To)->second;
1570 // Return the value for the transition to basic block \p S.
1571 // Required by GraphWriter.
1572 std::string getEdgeSourceLabel(const DisplayNode &Sink) const {
1573 return getEdge(Sink).getValue();
1576 void createEdgeMap();
1578 protected:
1579 const std::string Content;
1581 // Place to collect all of the edges. Once they are all in the vector,
1582 // the vector will not reallocate so then we can use pointers to them,
1583 // which are required by the graph writing routines.
1584 std::vector<DisplayEdge> Edges;
1586 std::vector<DisplayEdge *> EdgePtrs;
1587 std::unordered_set<DisplayNode *> Children;
1588 std::unordered_map<const DisplayNode *, const DisplayEdge *> EdgeMap;
1590 // Safeguard adding of edges.
1591 bool AllEdgesCreated = false;
1594 // Class representing a difference display (corresponds to a pdf file).
1595 class DotCfgDiffDisplayGraph {
1596 public:
1597 DotCfgDiffDisplayGraph(std::string Name) : GraphName(Name) {}
1599 // Generate the file into \p DotFile.
1600 void generateDotFile(StringRef DotFile);
1602 // Iterator to the nodes. Required by GraphWriter.
1603 using NodeIterator = std::vector<DisplayNode *>::const_iterator;
1604 NodeIterator nodes_begin() const {
1605 assert(NodeGenerationComplete && "Unexpected children iterator creation");
1606 return NodePtrs.cbegin();
1608 NodeIterator nodes_end() const {
1609 assert(NodeGenerationComplete && "Unexpected children iterator creation");
1610 return NodePtrs.cend();
1613 // Record the index of the entry node. At this point, we can build up
1614 // vectors of pointers that are required by the graph routines.
1615 void setEntryNode(unsigned N) {
1616 // At this point, there will be no new nodes.
1617 assert(!NodeGenerationComplete && "Unexpected node creation");
1618 NodeGenerationComplete = true;
1619 for (auto &N : Nodes)
1620 NodePtrs.emplace_back(&N);
1622 EntryNode = NodePtrs[N];
1625 // Create a node.
1626 void createNode(std::string C, StringRef Colour) {
1627 assert(!NodeGenerationComplete && "Unexpected node creation");
1628 Nodes.emplace_back(C, Colour);
1630 // Return the node at index \p N to avoid problems with vectors reallocating.
1631 DisplayNode &getNode(unsigned N) {
1632 assert(N < Nodes.size() && "Node is out of bounds");
1633 return Nodes[N];
1635 unsigned size() const {
1636 assert(NodeGenerationComplete && "Unexpected children iterator creation");
1637 return Nodes.size();
1640 // Return the name of the graph. Required by GraphWriter.
1641 std::string getGraphName() const { return GraphName; }
1643 // Return the string representing the differences for basic block \p Node.
1644 // Required by GraphWriter.
1645 std::string getNodeLabel(const DisplayNode &Node) const {
1646 return Node.getContent();
1649 // Return a string with colour information for Dot. Required by GraphWriter.
1650 std::string getNodeAttributes(const DisplayNode &Node) const {
1651 return attribute(Node.getColour());
1654 // Return a string with colour information for Dot. Required by GraphWriter.
1655 std::string getEdgeColorAttr(const DisplayNode &From,
1656 const DisplayNode &To) const {
1657 return attribute(From.getEdge(To).getColour());
1660 // Get the starting basic block. Required by GraphWriter.
1661 DisplayNode *getEntryNode() const {
1662 assert(NodeGenerationComplete && "Unexpected children iterator creation");
1663 return EntryNode;
1666 protected:
1667 // Return the string containing the colour to use as a Dot attribute.
1668 std::string attribute(StringRef Colour) const {
1669 return "color=" + Colour.str();
1672 bool NodeGenerationComplete = false;
1673 const std::string GraphName;
1674 std::vector<DisplayNode> Nodes;
1675 std::vector<DisplayNode *> NodePtrs;
1676 DisplayNode *EntryNode = nullptr;
1679 void DisplayNode::createEdge(StringRef Value, DisplayNode &Node,
1680 StringRef Colour) {
1681 assert(!AllEdgesCreated && "Expected to be able to still create edges.");
1682 Edges.emplace_back(Value.str(), Node, Colour);
1683 Children.insert(&Node);
1686 void DisplayNode::createEdgeMap() {
1687 // No more edges will be added so we can now use pointers to the edges
1688 // as the vector will not grow and reallocate.
1689 AllEdgesCreated = true;
1690 for (auto &E : Edges)
1691 EdgeMap.insert({&E.getDestinationNode(), &E});
1694 class DotCfgDiffNode;
1695 class DotCfgDiff;
1697 // A class representing a basic block in the Dot difference graph.
1698 class DotCfgDiffNode {
1699 public:
1700 DotCfgDiffNode() = delete;
1702 // Create a node in Dot difference graph \p G representing the basic block
1703 // represented by \p BD with colour \p Colour (where it exists).
1704 DotCfgDiffNode(DotCfgDiff &G, unsigned N, const BlockDataT<DCData> &BD,
1705 StringRef Colour)
1706 : Graph(G), N(N), Data{&BD, nullptr}, Colour(Colour) {}
1707 DotCfgDiffNode(const DotCfgDiffNode &DN)
1708 : Graph(DN.Graph), N(DN.N), Data{DN.Data[0], DN.Data[1]},
1709 Colour(DN.Colour), EdgesMap(DN.EdgesMap), Children(DN.Children),
1710 Edges(DN.Edges) {}
1712 unsigned getIndex() const { return N; }
1714 // The label of the basic block
1715 StringRef getLabel() const {
1716 assert(Data[0] && "Expected Data[0] to be set.");
1717 return Data[0]->getLabel();
1719 // Return the colour for this block
1720 StringRef getColour() const { return Colour; }
1721 // Change this basic block from being only in before to being common.
1722 // Save the pointer to \p Other.
1723 void setCommon(const BlockDataT<DCData> &Other) {
1724 assert(!Data[1] && "Expected only one block datum");
1725 Data[1] = &Other;
1726 Colour = CommonColour;
1728 // Add an edge to \p E of colour {\p Value, \p Colour}.
1729 void addEdge(unsigned E, StringRef Value, StringRef Colour) {
1730 // This is a new edge or it is an edge being made common.
1731 assert((EdgesMap.count(E) == 0 || Colour == CommonColour) &&
1732 "Unexpected edge count and color.");
1733 EdgesMap[E] = {Value.str(), Colour};
1735 // Record the children and create edges.
1736 void finalize(DotCfgDiff &G);
1738 // Return the colour of the edge to node \p S.
1739 StringRef getEdgeColour(const unsigned S) const {
1740 assert(EdgesMap.count(S) == 1 && "Expected to find edge.");
1741 return EdgesMap.at(S).second;
1744 // Return the string representing the basic block.
1745 std::string getBodyContent() const;
1747 void createDisplayEdges(DotCfgDiffDisplayGraph &Graph, unsigned DisplayNode,
1748 std::map<const unsigned, unsigned> &NodeMap) const;
1750 protected:
1751 DotCfgDiff &Graph;
1752 const unsigned N;
1753 const BlockDataT<DCData> *Data[2];
1754 StringRef Colour;
1755 std::map<const unsigned, std::pair<std::string, StringRef>> EdgesMap;
1756 std::vector<unsigned> Children;
1757 std::vector<unsigned> Edges;
1760 // Class representing the difference graph between two functions.
1761 class DotCfgDiff {
1762 public:
1763 // \p Title is the title given to the graph. \p EntryNodeName is the
1764 // entry node for the function. \p Before and \p After are the before
1765 // after versions of the function, respectively. \p Dir is the directory
1766 // in which to store the results.
1767 DotCfgDiff(StringRef Title, const FuncDataT<DCData> &Before,
1768 const FuncDataT<DCData> &After);
1770 DotCfgDiff(const DotCfgDiff &) = delete;
1771 DotCfgDiff &operator=(const DotCfgDiff &) = delete;
1773 DotCfgDiffDisplayGraph createDisplayGraph(StringRef Title,
1774 StringRef EntryNodeName);
1776 // Return a string consisting of the labels for the \p Source and \p Sink.
1777 // The combination allows distinguishing changing transitions on the
1778 // same value (ie, a transition went to X before and goes to Y after).
1779 // Required by GraphWriter.
1780 StringRef getEdgeSourceLabel(const unsigned &Source,
1781 const unsigned &Sink) const {
1782 std::string S =
1783 getNode(Source).getLabel().str() + " " + getNode(Sink).getLabel().str();
1784 assert(EdgeLabels.count(S) == 1 && "Expected to find edge label.");
1785 return EdgeLabels.find(S)->getValue();
1788 // Return the number of basic blocks (nodes). Required by GraphWriter.
1789 unsigned size() const { return Nodes.size(); }
1791 const DotCfgDiffNode &getNode(unsigned N) const {
1792 assert(N < Nodes.size() && "Unexpected index for node reference");
1793 return Nodes[N];
1796 protected:
1797 // Return the string surrounded by HTML to make it the appropriate colour.
1798 std::string colourize(std::string S, StringRef Colour) const;
1800 void createNode(StringRef Label, const BlockDataT<DCData> &BD, StringRef C) {
1801 unsigned Pos = Nodes.size();
1802 Nodes.emplace_back(*this, Pos, BD, C);
1803 NodePosition.insert({Label, Pos});
1806 // TODO Nodes should probably be a StringMap<DotCfgDiffNode> after the
1807 // display graph is separated out, which would remove the need for
1808 // NodePosition.
1809 std::vector<DotCfgDiffNode> Nodes;
1810 StringMap<unsigned> NodePosition;
1811 const std::string GraphName;
1813 StringMap<std::string> EdgeLabels;
1816 std::string DotCfgDiffNode::getBodyContent() const {
1817 if (Colour == CommonColour) {
1818 assert(Data[1] && "Expected Data[1] to be set.");
1820 StringRef SR[2];
1821 for (unsigned I = 0; I < 2; ++I) {
1822 SR[I] = Data[I]->getBody();
1823 // drop initial '\n' if present
1824 if (SR[I][0] == '\n')
1825 SR[I] = SR[I].drop_front();
1826 // drop predecessors as they can be big and are redundant
1827 SR[I] = SR[I].drop_until([](char C) { return C == '\n'; }).drop_front();
1830 SmallString<80> OldLineFormat = formatv(
1831 "<FONT COLOR=\"{0}\">%l</FONT><BR align=\"left\"/>", BeforeColour);
1832 SmallString<80> NewLineFormat = formatv(
1833 "<FONT COLOR=\"{0}\">%l</FONT><BR align=\"left\"/>", AfterColour);
1834 SmallString<80> UnchangedLineFormat = formatv(
1835 "<FONT COLOR=\"{0}\">%l</FONT><BR align=\"left\"/>", CommonColour);
1836 std::string Diff = Data[0]->getLabel().str();
1837 Diff += ":\n<BR align=\"left\"/>" +
1838 doSystemDiff(makeHTMLReady(SR[0]), makeHTMLReady(SR[1]),
1839 OldLineFormat, NewLineFormat, UnchangedLineFormat);
1841 // Diff adds in some empty colour changes which are not valid HTML
1842 // so remove them. Colours are all lowercase alpha characters (as
1843 // listed in https://graphviz.org/pdf/dotguide.pdf).
1844 Regex R("<FONT COLOR=\"\\w+\"></FONT>");
1845 while (true) {
1846 std::string Error;
1847 std::string S = R.sub("", Diff, &Error);
1848 if (Error != "")
1849 return Error;
1850 if (S == Diff)
1851 return Diff;
1852 Diff = S;
1854 llvm_unreachable("Should not get here");
1857 // Put node out in the appropriate colour.
1858 assert(!Data[1] && "Data[1] is set unexpectedly.");
1859 std::string Body = makeHTMLReady(Data[0]->getBody());
1860 const StringRef BS = Body;
1861 StringRef BS1 = BS;
1862 // Drop leading newline, if present.
1863 if (BS.front() == '\n')
1864 BS1 = BS1.drop_front(1);
1865 // Get label.
1866 StringRef Label = BS1.take_until([](char C) { return C == ':'; });
1867 // drop predecessors as they can be big and are redundant
1868 BS1 = BS1.drop_until([](char C) { return C == '\n'; }).drop_front();
1870 std::string S = "<FONT COLOR=\"" + Colour.str() + "\">" + Label.str() + ":";
1872 // align each line to the left.
1873 while (BS1.size()) {
1874 S.append("<BR align=\"left\"/>");
1875 StringRef Line = BS1.take_until([](char C) { return C == '\n'; });
1876 S.append(Line.str());
1877 BS1 = BS1.drop_front(Line.size() + 1);
1879 S.append("<BR align=\"left\"/></FONT>");
1880 return S;
1883 std::string DotCfgDiff::colourize(std::string S, StringRef Colour) const {
1884 if (S.length() == 0)
1885 return S;
1886 return "<FONT COLOR=\"" + Colour.str() + "\">" + S + "</FONT>";
1889 DotCfgDiff::DotCfgDiff(StringRef Title, const FuncDataT<DCData> &Before,
1890 const FuncDataT<DCData> &After)
1891 : GraphName(Title.str()) {
1892 StringMap<StringRef> EdgesMap;
1894 // Handle each basic block in the before IR.
1895 for (auto &B : Before.getData()) {
1896 StringRef Label = B.getKey();
1897 const BlockDataT<DCData> &BD = B.getValue();
1898 createNode(Label, BD, BeforeColour);
1900 // Create transitions with names made up of the from block label, the value
1901 // on which the transition is made and the to block label.
1902 for (StringMap<std::string>::const_iterator Sink = BD.getData().begin(),
1903 E = BD.getData().end();
1904 Sink != E; ++Sink) {
1905 std::string Key = (Label + " " + Sink->getKey().str()).str() + " " +
1906 BD.getData().getSuccessorLabel(Sink->getKey()).str();
1907 EdgesMap.insert({Key, BeforeColour});
1911 // Handle each basic block in the after IR
1912 for (auto &A : After.getData()) {
1913 StringRef Label = A.getKey();
1914 const BlockDataT<DCData> &BD = A.getValue();
1915 unsigned C = NodePosition.count(Label);
1916 if (C == 0)
1917 // This only exists in the after IR. Create the node.
1918 createNode(Label, BD, AfterColour);
1919 else {
1920 assert(C == 1 && "Unexpected multiple nodes.");
1921 Nodes[NodePosition[Label]].setCommon(BD);
1923 // Add in the edges between the nodes (as common or only in after).
1924 for (StringMap<std::string>::const_iterator Sink = BD.getData().begin(),
1925 E = BD.getData().end();
1926 Sink != E; ++Sink) {
1927 std::string Key = (Label + " " + Sink->getKey().str()).str() + " " +
1928 BD.getData().getSuccessorLabel(Sink->getKey()).str();
1929 unsigned C = EdgesMap.count(Key);
1930 if (C == 0)
1931 EdgesMap.insert({Key, AfterColour});
1932 else {
1933 EdgesMap[Key] = CommonColour;
1938 // Now go through the map of edges and add them to the node.
1939 for (auto &E : EdgesMap) {
1940 // Extract the source, sink and value from the edge key.
1941 StringRef S = E.getKey();
1942 auto SP1 = S.rsplit(' ');
1943 auto &SourceSink = SP1.first;
1944 auto SP2 = SourceSink.split(' ');
1945 StringRef Source = SP2.first;
1946 StringRef Sink = SP2.second;
1947 StringRef Value = SP1.second;
1949 assert(NodePosition.count(Source) == 1 && "Expected to find node.");
1950 DotCfgDiffNode &SourceNode = Nodes[NodePosition[Source]];
1951 assert(NodePosition.count(Sink) == 1 && "Expected to find node.");
1952 unsigned SinkNode = NodePosition[Sink];
1953 StringRef Colour = E.second;
1955 // Look for an edge from Source to Sink
1956 if (EdgeLabels.count(SourceSink) == 0)
1957 EdgeLabels.insert({SourceSink, colourize(Value.str(), Colour)});
1958 else {
1959 StringRef V = EdgeLabels.find(SourceSink)->getValue();
1960 std::string NV = colourize(V.str() + " " + Value.str(), Colour);
1961 Colour = CommonColour;
1962 EdgeLabels[SourceSink] = NV;
1964 SourceNode.addEdge(SinkNode, Value, Colour);
1966 for (auto &I : Nodes)
1967 I.finalize(*this);
1970 DotCfgDiffDisplayGraph DotCfgDiff::createDisplayGraph(StringRef Title,
1971 StringRef EntryNodeName) {
1972 assert(NodePosition.count(EntryNodeName) == 1 &&
1973 "Expected to find entry block in map.");
1974 unsigned Entry = NodePosition[EntryNodeName];
1975 assert(Entry < Nodes.size() && "Expected to find entry node");
1976 DotCfgDiffDisplayGraph G(Title.str());
1978 std::map<const unsigned, unsigned> NodeMap;
1980 int EntryIndex = -1;
1981 unsigned Index = 0;
1982 for (auto &I : Nodes) {
1983 if (I.getIndex() == Entry)
1984 EntryIndex = Index;
1985 G.createNode(I.getBodyContent(), I.getColour());
1986 NodeMap.insert({I.getIndex(), Index++});
1988 assert(EntryIndex >= 0 && "Expected entry node index to be set.");
1989 G.setEntryNode(EntryIndex);
1991 for (auto &I : NodeMap) {
1992 unsigned SourceNode = I.first;
1993 unsigned DisplayNode = I.second;
1994 getNode(SourceNode).createDisplayEdges(G, DisplayNode, NodeMap);
1996 return G;
1999 void DotCfgDiffNode::createDisplayEdges(
2000 DotCfgDiffDisplayGraph &DisplayGraph, unsigned DisplayNodeIndex,
2001 std::map<const unsigned, unsigned> &NodeMap) const {
2003 DisplayNode &SourceDisplayNode = DisplayGraph.getNode(DisplayNodeIndex);
2005 for (auto I : Edges) {
2006 unsigned SinkNodeIndex = I;
2007 StringRef Colour = getEdgeColour(SinkNodeIndex);
2008 const DotCfgDiffNode *SinkNode = &Graph.getNode(SinkNodeIndex);
2010 StringRef Label = Graph.getEdgeSourceLabel(getIndex(), SinkNodeIndex);
2011 DisplayNode &SinkDisplayNode = DisplayGraph.getNode(SinkNode->getIndex());
2012 SourceDisplayNode.createEdge(Label, SinkDisplayNode, Colour);
2014 SourceDisplayNode.createEdgeMap();
2017 void DotCfgDiffNode::finalize(DotCfgDiff &G) {
2018 for (auto E : EdgesMap) {
2019 Children.emplace_back(E.first);
2020 Edges.emplace_back(E.first);
2024 } // namespace
2026 namespace llvm {
2028 template <> struct GraphTraits<DotCfgDiffDisplayGraph *> {
2029 using NodeRef = const DisplayNode *;
2030 using ChildIteratorType = DisplayNode::ChildIterator;
2031 using nodes_iterator = DotCfgDiffDisplayGraph::NodeIterator;
2032 using EdgeRef = const DisplayEdge *;
2033 using ChildEdgeIterator = DisplayNode::EdgeIterator;
2035 static NodeRef getEntryNode(const DotCfgDiffDisplayGraph *G) {
2036 return G->getEntryNode();
2038 static ChildIteratorType child_begin(NodeRef N) {
2039 return N->children_begin();
2041 static ChildIteratorType child_end(NodeRef N) { return N->children_end(); }
2042 static nodes_iterator nodes_begin(const DotCfgDiffDisplayGraph *G) {
2043 return G->nodes_begin();
2045 static nodes_iterator nodes_end(const DotCfgDiffDisplayGraph *G) {
2046 return G->nodes_end();
2048 static ChildEdgeIterator child_edge_begin(NodeRef N) {
2049 return N->edges_begin();
2051 static ChildEdgeIterator child_edge_end(NodeRef N) { return N->edges_end(); }
2052 static NodeRef edge_dest(EdgeRef E) { return &E->getDestinationNode(); }
2053 static unsigned size(const DotCfgDiffDisplayGraph *G) { return G->size(); }
2056 template <>
2057 struct DOTGraphTraits<DotCfgDiffDisplayGraph *> : public DefaultDOTGraphTraits {
2058 explicit DOTGraphTraits(bool Simple = false)
2059 : DefaultDOTGraphTraits(Simple) {}
2061 static bool renderNodesUsingHTML() { return true; }
2062 static std::string getGraphName(const DotCfgDiffDisplayGraph *DiffData) {
2063 return DiffData->getGraphName();
2065 static std::string
2066 getGraphProperties(const DotCfgDiffDisplayGraph *DiffData) {
2067 return "\tsize=\"190, 190\";\n";
2069 static std::string getNodeLabel(const DisplayNode *Node,
2070 const DotCfgDiffDisplayGraph *DiffData) {
2071 return DiffData->getNodeLabel(*Node);
2073 static std::string getNodeAttributes(const DisplayNode *Node,
2074 const DotCfgDiffDisplayGraph *DiffData) {
2075 return DiffData->getNodeAttributes(*Node);
2077 static std::string getEdgeSourceLabel(const DisplayNode *From,
2078 DisplayNode::ChildIterator &To) {
2079 return From->getEdgeSourceLabel(**To);
2081 static std::string getEdgeAttributes(const DisplayNode *From,
2082 DisplayNode::ChildIterator &To,
2083 const DotCfgDiffDisplayGraph *DiffData) {
2084 return DiffData->getEdgeColorAttr(*From, **To);
2088 } // namespace llvm
2090 namespace {
2092 void DotCfgDiffDisplayGraph::generateDotFile(StringRef DotFile) {
2093 std::error_code EC;
2094 raw_fd_ostream OutStream(DotFile, EC);
2095 if (EC) {
2096 errs() << "Error: " << EC.message() << "\n";
2097 return;
2099 WriteGraph(OutStream, this, false);
2100 OutStream.flush();
2101 OutStream.close();
2104 } // namespace
2106 namespace llvm {
2108 DCData::DCData(const BasicBlock &B) {
2109 // Build up transition labels.
2110 const Instruction *Term = B.getTerminator();
2111 if (const BranchInst *Br = dyn_cast<const BranchInst>(Term))
2112 if (Br->isUnconditional())
2113 addSuccessorLabel(Br->getSuccessor(0)->getName().str(), "");
2114 else {
2115 addSuccessorLabel(Br->getSuccessor(0)->getName().str(), "true");
2116 addSuccessorLabel(Br->getSuccessor(1)->getName().str(), "false");
2118 else if (const SwitchInst *Sw = dyn_cast<const SwitchInst>(Term)) {
2119 addSuccessorLabel(Sw->case_default()->getCaseSuccessor()->getName().str(),
2120 "default");
2121 for (auto &C : Sw->cases()) {
2122 assert(C.getCaseValue() && "Expected to find case value.");
2123 SmallString<20> Value = formatv("{0}", C.getCaseValue()->getSExtValue());
2124 addSuccessorLabel(C.getCaseSuccessor()->getName().str(), Value);
2126 } else
2127 for (const_succ_iterator I = succ_begin(&B), E = succ_end(&B); I != E; ++I)
2128 addSuccessorLabel((*I)->getName().str(), "");
2131 DotCfgChangeReporter::DotCfgChangeReporter(bool Verbose)
2132 : ChangeReporter<IRDataT<DCData>>(Verbose) {}
2134 void DotCfgChangeReporter::handleFunctionCompare(
2135 StringRef Name, StringRef Prefix, StringRef PassID, StringRef Divider,
2136 bool InModule, unsigned Minor, const FuncDataT<DCData> &Before,
2137 const FuncDataT<DCData> &After) {
2138 assert(HTML && "Expected outstream to be set");
2139 SmallString<8> Extender;
2140 SmallString<8> Number;
2141 // Handle numbering and file names.
2142 if (InModule) {
2143 Extender = formatv("{0}_{1}", N, Minor);
2144 Number = formatv("{0}.{1}", N, Minor);
2145 } else {
2146 Extender = formatv("{0}", N);
2147 Number = formatv("{0}", N);
2149 // Create a temporary file name for the dot file.
2150 SmallVector<char, 128> SV;
2151 sys::fs::createUniquePath("cfgdot-%%%%%%.dot", SV, true);
2152 std::string DotFile = Twine(SV).str();
2154 SmallString<20> PDFFileName = formatv("diff_{0}.pdf", Extender);
2155 SmallString<200> Text;
2157 Text = formatv("{0}.{1}{2}{3}{4}", Number, Prefix, makeHTMLReady(PassID),
2158 Divider, Name);
2160 DotCfgDiff Diff(Text, Before, After);
2161 std::string EntryBlockName = After.getEntryBlockName();
2162 // Use the before entry block if the after entry block was removed.
2163 if (EntryBlockName == "")
2164 EntryBlockName = Before.getEntryBlockName();
2165 assert(EntryBlockName != "" && "Expected to find entry block");
2167 DotCfgDiffDisplayGraph DG = Diff.createDisplayGraph(Text, EntryBlockName);
2168 DG.generateDotFile(DotFile);
2170 *HTML << genHTML(Text, DotFile, PDFFileName);
2171 std::error_code EC = sys::fs::remove(DotFile);
2172 if (EC)
2173 errs() << "Error: " << EC.message() << "\n";
2176 std::string DotCfgChangeReporter::genHTML(StringRef Text, StringRef DotFile,
2177 StringRef PDFFileName) {
2178 SmallString<20> PDFFile = formatv("{0}/{1}", DotCfgDir, PDFFileName);
2179 // Create the PDF file.
2180 static ErrorOr<std::string> DotExe = sys::findProgramByName(DotBinary);
2181 if (!DotExe)
2182 return "Unable to find dot executable.";
2184 StringRef Args[] = {DotBinary, "-Tpdf", "-o", PDFFile, DotFile};
2185 int Result = sys::ExecuteAndWait(*DotExe, Args, std::nullopt);
2186 if (Result < 0)
2187 return "Error executing system dot.";
2189 // Create the HTML tag refering to the PDF file.
2190 SmallString<200> S = formatv(
2191 " <a href=\"{0}\" target=\"_blank\">{1}</a><br/>\n", PDFFileName, Text);
2192 return S.c_str();
2195 void DotCfgChangeReporter::handleInitialIR(Any IR) {
2196 assert(HTML && "Expected outstream to be set");
2197 *HTML << "<button type=\"button\" class=\"collapsible\">0. "
2198 << "Initial IR (by function)</button>\n"
2199 << "<div class=\"content\">\n"
2200 << " <p>\n";
2201 // Create representation of IR
2202 IRDataT<DCData> Data;
2203 IRComparer<DCData>::analyzeIR(IR, Data);
2204 // Now compare it against itself, which will have everything the
2205 // same and will generate the files.
2206 IRComparer<DCData>(Data, Data)
2207 .compare(getModuleForComparison(IR),
2208 [&](bool InModule, unsigned Minor,
2209 const FuncDataT<DCData> &Before,
2210 const FuncDataT<DCData> &After) -> void {
2211 handleFunctionCompare("", " ", "Initial IR", "", InModule,
2212 Minor, Before, After);
2214 *HTML << " </p>\n"
2215 << "</div><br/>\n";
2216 ++N;
2219 void DotCfgChangeReporter::generateIRRepresentation(Any IR, StringRef PassID,
2220 IRDataT<DCData> &Data) {
2221 IRComparer<DCData>::analyzeIR(IR, Data);
2224 void DotCfgChangeReporter::omitAfter(StringRef PassID, std::string &Name) {
2225 assert(HTML && "Expected outstream to be set");
2226 SmallString<20> Banner =
2227 formatv(" <a>{0}. Pass {1} on {2} omitted because no change</a><br/>\n",
2228 N, makeHTMLReady(PassID), Name);
2229 *HTML << Banner;
2230 ++N;
2233 void DotCfgChangeReporter::handleAfter(StringRef PassID, std::string &Name,
2234 const IRDataT<DCData> &Before,
2235 const IRDataT<DCData> &After, Any IR) {
2236 assert(HTML && "Expected outstream to be set");
2237 IRComparer<DCData>(Before, After)
2238 .compare(getModuleForComparison(IR),
2239 [&](bool InModule, unsigned Minor,
2240 const FuncDataT<DCData> &Before,
2241 const FuncDataT<DCData> &After) -> void {
2242 handleFunctionCompare(Name, " Pass ", PassID, " on ", InModule,
2243 Minor, Before, After);
2245 *HTML << " </p></div>\n";
2246 ++N;
2249 void DotCfgChangeReporter::handleInvalidated(StringRef PassID) {
2250 assert(HTML && "Expected outstream to be set");
2251 SmallString<20> Banner =
2252 formatv(" <a>{0}. {1} invalidated</a><br/>\n", N, makeHTMLReady(PassID));
2253 *HTML << Banner;
2254 ++N;
2257 void DotCfgChangeReporter::handleFiltered(StringRef PassID, std::string &Name) {
2258 assert(HTML && "Expected outstream to be set");
2259 SmallString<20> Banner =
2260 formatv(" <a>{0}. Pass {1} on {2} filtered out</a><br/>\n", N,
2261 makeHTMLReady(PassID), Name);
2262 *HTML << Banner;
2263 ++N;
2266 void DotCfgChangeReporter::handleIgnored(StringRef PassID, std::string &Name) {
2267 assert(HTML && "Expected outstream to be set");
2268 SmallString<20> Banner = formatv(" <a>{0}. {1} on {2} ignored</a><br/>\n", N,
2269 makeHTMLReady(PassID), Name);
2270 *HTML << Banner;
2271 ++N;
2274 bool DotCfgChangeReporter::initializeHTML() {
2275 std::error_code EC;
2276 HTML = std::make_unique<raw_fd_ostream>(DotCfgDir + "/passes.html", EC);
2277 if (EC) {
2278 HTML = nullptr;
2279 return false;
2282 *HTML << "<!doctype html>"
2283 << "<html>"
2284 << "<head>"
2285 << "<style>.collapsible { "
2286 << "background-color: #777;"
2287 << " color: white;"
2288 << " cursor: pointer;"
2289 << " padding: 18px;"
2290 << " width: 100%;"
2291 << " border: none;"
2292 << " text-align: left;"
2293 << " outline: none;"
2294 << " font-size: 15px;"
2295 << "} .active, .collapsible:hover {"
2296 << " background-color: #555;"
2297 << "} .content {"
2298 << " padding: 0 18px;"
2299 << " display: none;"
2300 << " overflow: hidden;"
2301 << " background-color: #f1f1f1;"
2302 << "}"
2303 << "</style>"
2304 << "<title>passes.html</title>"
2305 << "</head>\n"
2306 << "<body>";
2307 return true;
2310 DotCfgChangeReporter::~DotCfgChangeReporter() {
2311 if (!HTML)
2312 return;
2313 *HTML
2314 << "<script>var coll = document.getElementsByClassName(\"collapsible\");"
2315 << "var i;"
2316 << "for (i = 0; i < coll.length; i++) {"
2317 << "coll[i].addEventListener(\"click\", function() {"
2318 << " this.classList.toggle(\"active\");"
2319 << " var content = this.nextElementSibling;"
2320 << " if (content.style.display === \"block\"){"
2321 << " content.style.display = \"none\";"
2322 << " }"
2323 << " else {"
2324 << " content.style.display= \"block\";"
2325 << " }"
2326 << " });"
2327 << " }"
2328 << "</script>"
2329 << "</body>"
2330 << "</html>\n";
2331 HTML->flush();
2332 HTML->close();
2335 void DotCfgChangeReporter::registerCallbacks(
2336 PassInstrumentationCallbacks &PIC) {
2337 if (PrintChanged == ChangePrinter::DotCfgVerbose ||
2338 PrintChanged == ChangePrinter::DotCfgQuiet) {
2339 SmallString<128> OutputDir;
2340 sys::fs::expand_tilde(DotCfgDir, OutputDir);
2341 sys::fs::make_absolute(OutputDir);
2342 assert(!OutputDir.empty() && "expected output dir to be non-empty");
2343 DotCfgDir = OutputDir.c_str();
2344 if (initializeHTML()) {
2345 ChangeReporter<IRDataT<DCData>>::registerRequiredCallbacks(PIC);
2346 return;
2348 dbgs() << "Unable to open output stream for -cfg-dot-changed\n";
2352 StandardInstrumentations::StandardInstrumentations(
2353 LLVMContext &Context, bool DebugLogging, bool VerifyEach,
2354 PrintPassOptions PrintPassOpts)
2355 : PrintPass(DebugLogging, PrintPassOpts),
2356 OptNone(DebugLogging),
2357 OptPassGate(Context),
2358 PrintChangedIR(PrintChanged == ChangePrinter::Verbose),
2359 PrintChangedDiff(PrintChanged == ChangePrinter::DiffVerbose ||
2360 PrintChanged == ChangePrinter::ColourDiffVerbose,
2361 PrintChanged == ChangePrinter::ColourDiffVerbose ||
2362 PrintChanged == ChangePrinter::ColourDiffQuiet),
2363 WebsiteChangeReporter(PrintChanged == ChangePrinter::DotCfgVerbose),
2364 Verify(DebugLogging), VerifyEach(VerifyEach) {}
2366 PrintCrashIRInstrumentation *PrintCrashIRInstrumentation::CrashReporter =
2367 nullptr;
2369 void PrintCrashIRInstrumentation::reportCrashIR() {
2370 if (!PrintOnCrashPath.empty()) {
2371 std::error_code EC;
2372 raw_fd_ostream Out(PrintOnCrashPath, EC);
2373 if (EC)
2374 report_fatal_error(errorCodeToError(EC));
2375 Out << SavedIR;
2376 } else {
2377 dbgs() << SavedIR;
2381 void PrintCrashIRInstrumentation::SignalHandler(void *) {
2382 // Called by signal handlers so do not lock here
2383 // Is the PrintCrashIRInstrumentation still alive?
2384 if (!CrashReporter)
2385 return;
2387 assert((PrintOnCrash || !PrintOnCrashPath.empty()) &&
2388 "Did not expect to get here without option set.");
2389 CrashReporter->reportCrashIR();
2392 PrintCrashIRInstrumentation::~PrintCrashIRInstrumentation() {
2393 if (!CrashReporter)
2394 return;
2396 assert((PrintOnCrash || !PrintOnCrashPath.empty()) &&
2397 "Did not expect to get here without option set.");
2398 CrashReporter = nullptr;
2401 void PrintCrashIRInstrumentation::registerCallbacks(
2402 PassInstrumentationCallbacks &PIC) {
2403 if ((!PrintOnCrash && PrintOnCrashPath.empty()) || CrashReporter)
2404 return;
2406 sys::AddSignalHandler(SignalHandler, nullptr);
2407 CrashReporter = this;
2409 PIC.registerBeforeNonSkippedPassCallback(
2410 [&PIC, this](StringRef PassID, Any IR) {
2411 SavedIR.clear();
2412 raw_string_ostream OS(SavedIR);
2413 OS << formatv("*** Dump of {0}IR Before Last Pass {1}",
2414 llvm::forcePrintModuleIR() ? "Module " : "", PassID);
2415 if (!isInteresting(IR, PassID, PIC.getPassNameForClassName(PassID))) {
2416 OS << " Filtered Out ***\n";
2417 return;
2419 OS << " Started ***\n";
2420 unwrapAndPrint(OS, IR);
2424 void StandardInstrumentations::registerCallbacks(
2425 PassInstrumentationCallbacks &PIC, ModuleAnalysisManager *MAM) {
2426 PrintIR.registerCallbacks(PIC);
2427 PrintPass.registerCallbacks(PIC);
2428 TimePasses.registerCallbacks(PIC);
2429 OptNone.registerCallbacks(PIC);
2430 OptPassGate.registerCallbacks(PIC);
2431 PrintChangedIR.registerCallbacks(PIC);
2432 PseudoProbeVerification.registerCallbacks(PIC);
2433 if (VerifyEach)
2434 Verify.registerCallbacks(PIC);
2435 PrintChangedDiff.registerCallbacks(PIC);
2436 WebsiteChangeReporter.registerCallbacks(PIC);
2437 ChangeTester.registerCallbacks(PIC);
2438 PrintCrashIR.registerCallbacks(PIC);
2439 if (MAM)
2440 PreservedCFGChecker.registerCallbacks(PIC, *MAM);
2442 // TimeProfiling records the pass running time cost.
2443 // Its 'BeforePassCallback' can be appended at the tail of all the
2444 // BeforeCallbacks by calling `registerCallbacks` in the end.
2445 // Its 'AfterPassCallback' is put at the front of all the
2446 // AfterCallbacks by its `registerCallbacks`. This is necessary
2447 // to ensure that other callbacks are not included in the timings.
2448 TimeProfilingPasses.registerCallbacks(PIC);
2451 template class ChangeReporter<std::string>;
2452 template class TextChangeReporter<std::string>;
2454 template class BlockDataT<EmptyData>;
2455 template class FuncDataT<EmptyData>;
2456 template class IRDataT<EmptyData>;
2457 template class ChangeReporter<IRDataT<EmptyData>>;
2458 template class TextChangeReporter<IRDataT<EmptyData>>;
2459 template class IRComparer<EmptyData>;
2461 } // namespace llvm