LLVM 17.0.0git
StandardInstrumentations.cpp
Go to the documentation of this file.
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
16#include "llvm/ADT/Any.h"
17#include "llvm/ADT/StringRef.h"
21#include "llvm/IR/Constants.h"
22#include "llvm/IR/Function.h"
23#include "llvm/IR/Module.h"
25#include "llvm/IR/PassManager.h"
26#include "llvm/IR/PrintPasses.h"
28#include "llvm/IR/Verifier.h"
31#include "llvm/Support/Debug.h"
32#include "llvm/Support/Error.h"
37#include "llvm/Support/Regex.h"
40#include <unordered_map>
41#include <unordered_set>
42#include <utility>
43#include <vector>
44
45using namespace llvm;
46
47static cl::opt<bool> VerifyAnalysisInvalidation("verify-analysis-invalidation",
49#ifdef EXPENSIVE_CHECKS
50 cl::init(true)
51#else
52 cl::init(false)
53#endif
54);
55
56// An option that supports the -print-changed option. See
57// the description for -print-changed for an explanation of the use
58// of this option. Note that this option has no effect without -print-changed.
59static cl::opt<bool>
60 PrintChangedBefore("print-before-changed",
61 cl::desc("Print before passes that change them"),
62 cl::init(false), cl::Hidden);
63
64// An option for specifying the dot used by
65// print-changed=[dot-cfg | dot-cfg-quiet]
67 DotBinary("print-changed-dot-path", cl::Hidden, cl::init("dot"),
68 cl::desc("system dot used by change reporters"));
69
70// An option that determines the colour used for elements that are only
71// in the before part. Must be a colour named in appendix J of
72// https://graphviz.org/pdf/dotguide.pdf
74 BeforeColour("dot-cfg-before-color",
75 cl::desc("Color for dot-cfg before elements"), cl::Hidden,
76 cl::init("red"));
77// An option that determines the colour used for elements that are only
78// in the after part. Must be a colour named in appendix J of
79// https://graphviz.org/pdf/dotguide.pdf
81 AfterColour("dot-cfg-after-color",
82 cl::desc("Color for dot-cfg after elements"), cl::Hidden,
83 cl::init("forestgreen"));
84// An option that determines the colour used for elements that are in both
85// the before and after parts. Must be a colour named in appendix J of
86// https://graphviz.org/pdf/dotguide.pdf
88 CommonColour("dot-cfg-common-color",
89 cl::desc("Color for dot-cfg common elements"), cl::Hidden,
90 cl::init("black"));
91
92// An option that determines where the generated website file (named
93// passes.html) and the associated pdf files (named diff_*.pdf) are saved.
95 "dot-cfg-dir",
96 cl::desc("Generate dot files into specified directory for changed IRs"),
97 cl::Hidden, cl::init("./"));
98
99// An option to print the IR that was being processed when a pass crashes.
100static cl::opt<bool>
101 PrintCrashIR("print-on-crash",
102 cl::desc("Print the last form of the IR before crash"),
103 cl::Hidden);
104
106 "opt-bisect-print-ir-path",
107 cl::desc("Print IR to path when opt-bisect-limit is reached"), cl::Hidden);
108
109namespace {
110
111// An option for specifying an executable that will be called with the IR
112// everytime it changes in the opt pipeline. It will also be called on
113// the initial IR as it enters the pipeline. The executable will be passed
114// the name of a temporary file containing the IR and the PassID. This may
115// be used, for example, to call llc on the IR and run a test to determine
116// which pass makes a change that changes the functioning of the IR.
117// The usual modifier options work as expected.
119 TestChanged("exec-on-ir-change", cl::Hidden, cl::init(""),
120 cl::desc("exe called with module IR after each pass that "
121 "changes it"));
122
123/// Extract Module out of \p IR unit. May return nullptr if \p IR does not match
124/// certain global filters. Will never return nullptr if \p Force is true.
125const Module *unwrapModule(Any IR, bool Force = false) {
126 if (const auto **M = any_cast<const Module *>(&IR))
127 return *M;
128
129 if (const auto **F = any_cast<const Function *>(&IR)) {
130 if (!Force && !isFunctionInPrintList((*F)->getName()))
131 return nullptr;
132
133 return (*F)->getParent();
134 }
135
136 if (const auto **C = any_cast<const LazyCallGraph::SCC *>(&IR)) {
137 for (const LazyCallGraph::Node &N : **C) {
138 const Function &F = N.getFunction();
139 if (Force || (!F.isDeclaration() && isFunctionInPrintList(F.getName()))) {
140 return F.getParent();
141 }
142 }
143 assert(!Force && "Expected a module");
144 return nullptr;
145 }
146
147 if (const auto **L = any_cast<const Loop *>(&IR)) {
148 const Function *F = (*L)->getHeader()->getParent();
149 if (!Force && !isFunctionInPrintList(F->getName()))
150 return nullptr;
151 return F->getParent();
152 }
153
154 llvm_unreachable("Unknown IR unit");
155}
156
157void printIR(raw_ostream &OS, const Function *F) {
158 if (!isFunctionInPrintList(F->getName()))
159 return;
160 OS << *F;
161}
162
163void printIR(raw_ostream &OS, const Module *M) {
165 M->print(OS, nullptr);
166 } else {
167 for (const auto &F : M->functions()) {
168 printIR(OS, &F);
169 }
170 }
171}
172
173void printIR(raw_ostream &OS, const LazyCallGraph::SCC *C) {
174 for (const LazyCallGraph::Node &N : *C) {
175 const Function &F = N.getFunction();
176 if (!F.isDeclaration() && isFunctionInPrintList(F.getName())) {
177 F.print(OS);
178 }
180}
181
182void printIR(raw_ostream &OS, const Loop *L) {
183 const Function *F = L->getHeader()->getParent();
184 if (!isFunctionInPrintList(F->getName()))
185 return;
186 printLoop(const_cast<Loop &>(*L), OS);
188
189std::string getIRName(Any IR) {
190 if (any_cast<const Module *>(&IR))
191 return "[module]";
192
193 if (const auto **F = any_cast<const Function *>(&IR))
194 return (*F)->getName().str();
195
196 if (const auto **C = any_cast<const LazyCallGraph::SCC *>(&IR))
197 return (*C)->getName();
198
199 if (const auto **L = any_cast<const Loop *>(&IR))
200 return (*L)->getName().str();
201
202 llvm_unreachable("Unknown wrapped IR type");
203}
204
205bool moduleContainsFilterPrintFunc(const Module &M) {
206 return any_of(M.functions(),
207 [](const Function &F) {
208 return isFunctionInPrintList(F.getName());
209 }) ||
211}
212
213bool sccContainsFilterPrintFunc(const LazyCallGraph::SCC &C) {
214 return any_of(C,
215 [](const LazyCallGraph::Node &N) {
216 return isFunctionInPrintList(N.getName());
217 }) ||
219}
220
221bool shouldPrintIR(Any IR) {
222 if (const auto **M = any_cast<const Module *>(&IR))
223 return moduleContainsFilterPrintFunc(**M);
224
225 if (const auto **F = any_cast<const Function *>(&IR))
226 return isFunctionInPrintList((*F)->getName());
227
228 if (const auto **C = any_cast<const LazyCallGraph::SCC *>(&IR))
229 return sccContainsFilterPrintFunc(**C);
231 if (const auto **L = any_cast<const Loop *>(&IR))
232 return isFunctionInPrintList((*L)->getHeader()->getParent()->getName());
233 llvm_unreachable("Unknown wrapped IR type");
235
236/// Generic IR-printing helper that unpacks a pointer to IRUnit wrapped into
237/// Any and does actual print job.
238void unwrapAndPrint(raw_ostream &OS, Any IR) {
239 if (!shouldPrintIR(IR))
240 return;
241
242 if (forcePrintModuleIR()) {
243 auto *M = unwrapModule(IR);
244 assert(M && "should have unwrapped module");
245 printIR(OS, M);
246 return;
247 }
248
249 if (const auto **M = any_cast<const Module *>(&IR)) {
250 printIR(OS, *M);
251 return;
252 }
253
254 if (const auto **F = any_cast<const Function *>(&IR)) {
255 printIR(OS, *F);
256 return;
257 }
258
259 if (const auto **C = any_cast<const LazyCallGraph::SCC *>(&IR)) {
260 printIR(OS, *C);
261 return;
262 }
263
264 if (const auto **L = any_cast<const Loop *>(&IR)) {
265 printIR(OS, *L);
266 return;
267 }
268 llvm_unreachable("Unknown wrapped IR type");
269}
270
271// Return true when this is a pass for which changes should be ignored
272bool isIgnored(StringRef PassID) {
273 return isSpecialPass(PassID,
274 {"PassManager", "PassAdaptor", "AnalysisManagerProxy",
275 "DevirtSCCRepeatedPass", "ModuleInlinerWrapperPass"});
276}
277
278std::string makeHTMLReady(StringRef SR) {
279 std::string S;
280 while (true) {
281 StringRef Clean =
282 SR.take_until([](char C) { return C == '<' || C == '>'; });
283 S.append(Clean.str());
284 SR = SR.drop_front(Clean.size());
285 if (SR.size() == 0)
286 return S;
287 S.append(SR[0] == '<' ? "&lt;" : "&gt;");
288 SR = SR.drop_front();
289 }
290 llvm_unreachable("problems converting string to HTML");
291}
292
293// Return the module when that is the appropriate level of comparison for \p IR.
294const Module *getModuleForComparison(Any IR) {
295 if (const auto **M = any_cast<const Module *>(&IR))
296 return *M;
297 if (const auto **C = any_cast<const LazyCallGraph::SCC *>(&IR))
298 return (*C)
299 ->begin()
300 ->getFunction()
301 .getParent();
302 return nullptr;
303}
304
305bool isInterestingFunction(const Function &F) {
306 return isFunctionInPrintList(F.getName());
307}
308
309// Return true when this is a pass on IR for which printing
310// of changes is desired.
312 if (isIgnored(PassID) || !isPassInPrintList(PassName))
313 return false;
314 if (const auto **F = any_cast<const Function *>(&IR))
315 return isInterestingFunction(**F);
316 return true;
317}
318
319} // namespace
320
321template <typename T> ChangeReporter<T>::~ChangeReporter() {
322 assert(BeforeStack.empty() && "Problem with Change Printer stack.");
323}
324
325template <typename T>
328 // Is this the initial IR?
329 if (InitialIR) {
330 InitialIR = false;
331 if (VerboseMode)
332 handleInitialIR(IR);
333 }
334
335 // Always need to place something on the stack because invalidated passes
336 // are not given the IR so it cannot be determined whether the pass was for
337 // something that was filtered out.
338 BeforeStack.emplace_back();
339
340 if (!isInteresting(IR, PassID, PassName))
341 return;
342
343 // Save the IR representation on the stack.
344 T &Data = BeforeStack.back();
345 generateIRRepresentation(IR, PassID, Data);
346}
347
348template <typename T>
351 assert(!BeforeStack.empty() && "Unexpected empty stack encountered.");
352
353 std::string Name = getIRName(IR);
354
355 if (isIgnored(PassID)) {
356 if (VerboseMode)
357 handleIgnored(PassID, Name);
358 } else if (!isInteresting(IR, PassID, PassName)) {
359 if (VerboseMode)
360 handleFiltered(PassID, Name);
361 } else {
362 // Get the before rep from the stack
363 T &Before = BeforeStack.back();
364 // Create the after rep
365 T After;
366 generateIRRepresentation(IR, PassID, After);
367
368 // Was there a change in IR?
369 if (Before == After) {
370 if (VerboseMode)
371 omitAfter(PassID, Name);
372 } else
373 handleAfter(PassID, Name, Before, After, IR);
374 }
375 BeforeStack.pop_back();
376}
377
378template <typename T>
380 assert(!BeforeStack.empty() && "Unexpected empty stack encountered.");
381
382 // Always flag it as invalidated as we cannot determine when
383 // a pass for a filtered function is invalidated since we do not
384 // get the IR in the call. Also, the output is just alternate
385 // forms of the banner anyway.
386 if (VerboseMode)
387 handleInvalidated(PassID);
388 BeforeStack.pop_back();
389}
390
391template <typename T>
395 saveIRBeforePass(IR, P, PIC.getPassNameForClassName(P));
396 });
397
399 [&PIC, this](StringRef P, Any IR, const PreservedAnalyses &) {
400 handleIRAfterPass(IR, P, PIC.getPassNameForClassName(P));
401 });
403 [this](StringRef P, const PreservedAnalyses &) {
404 handleInvalidatedPass(P);
405 });
406}
407
408template <typename T>
410 : ChangeReporter<T>(Verbose), Out(dbgs()) {}
411
412template <typename T> void TextChangeReporter<T>::handleInitialIR(Any IR) {
413 // Always print the module.
414 // Unwrap and print directly to avoid filtering problems in general routines.
415 auto *M = unwrapModule(IR, /*Force=*/true);
416 assert(M && "Expected module to be unwrapped when forced.");
417 Out << "*** IR Dump At Start ***\n";
418 M->print(Out, nullptr);
419}
420
421template <typename T>
423 Out << formatv("*** IR Dump After {0} on {1} omitted because no change ***\n",
424 PassID, Name);
425}
426
427template <typename T>
429 Out << formatv("*** IR Pass {0} invalidated ***\n", PassID);
430}
431
432template <typename T>
434 std::string &Name) {
435 SmallString<20> Banner =
436 formatv("*** IR Dump After {0} on {1} filtered out ***\n", PassID, Name);
437 Out << Banner;
438}
439
440template <typename T>
442 Out << formatv("*** IR Pass {0} on {1} ignored ***\n", PassID, Name);
443}
444
446
451}
452
454 std::string &Output) {
455 raw_string_ostream OS(Output);
456 unwrapAndPrint(OS, IR);
457 OS.str();
458}
459
461 const std::string &Before,
462 const std::string &After, Any) {
463 // Report the IR before the changes when requested.
465 Out << "*** IR Dump Before " << PassID << " on " << Name << " ***\n"
466 << Before;
467
468 // We might not get anything to print if we only want to print a specific
469 // function but it gets deleted.
470 if (After.empty()) {
471 Out << "*** IR Deleted After " << PassID << " on " << Name << " ***\n";
472 return;
473 }
474
475 Out << "*** IR Dump After " << PassID << " on " << Name << " ***\n" << After;
476}
477
479
481 if (TestChanged != "")
483}
484
485void IRChangedTester::handleIR(const std::string &S, StringRef PassID) {
486 // Store the body into a temporary file
487 static SmallVector<int> FD{-1};
489 static SmallVector<std::string> FileName{""};
490 if (auto Err = prepareTempFiles(FD, SR, FileName)) {
491 dbgs() << "Unable to create temporary file.";
492 return;
493 }
494 static ErrorOr<std::string> Exe = sys::findProgramByName(TestChanged);
495 if (!Exe) {
496 dbgs() << "Unable to find test-changed executable.";
497 return;
498 }
499
500 StringRef Args[] = {TestChanged, FileName[0], PassID};
501 int Result = sys::ExecuteAndWait(*Exe, Args);
502 if (Result < 0) {
503 dbgs() << "Error executing test-changed executable.";
504 return;
505 }
506
507 if (auto Err = cleanUpTempFiles(FileName))
508 dbgs() << "Unable to remove temporary file.";
509}
510
512 // Always test the initial module.
513 // Unwrap and print directly to avoid filtering problems in general routines.
514 std::string S;
515 generateIRRepresentation(IR, "Initial IR", S);
516 handleIR(S, "Initial IR");
517}
518
519void IRChangedTester::omitAfter(StringRef PassID, std::string &Name) {}
521void IRChangedTester::handleFiltered(StringRef PassID, std::string &Name) {}
522void IRChangedTester::handleIgnored(StringRef PassID, std::string &Name) {}
524 const std::string &Before,
525 const std::string &After, Any) {
526 handleIR(After, PassID);
527}
528
529template <typename T>
531 const OrderedChangedData &Before, const OrderedChangedData &After,
532 function_ref<void(const T *, const T *)> HandlePair) {
533 const auto &BFD = Before.getData();
534 const auto &AFD = After.getData();
535 std::vector<std::string>::const_iterator BI = Before.getOrder().begin();
536 std::vector<std::string>::const_iterator BE = Before.getOrder().end();
537 std::vector<std::string>::const_iterator AI = After.getOrder().begin();
538 std::vector<std::string>::const_iterator AE = After.getOrder().end();
539
540 auto HandlePotentiallyRemovedData = [&](std::string S) {
541 // The order in LLVM may have changed so check if still exists.
542 if (!AFD.count(S)) {
543 // This has been removed.
544 HandlePair(&BFD.find(*BI)->getValue(), nullptr);
545 }
546 };
547 auto HandleNewData = [&](std::vector<const T *> &Q) {
548 // Print out any queued up new sections
549 for (const T *NBI : Q)
550 HandlePair(nullptr, NBI);
551 Q.clear();
552 };
553
554 // Print out the data in the after order, with before ones interspersed
555 // appropriately (ie, somewhere near where they were in the before list).
556 // Start at the beginning of both lists. Loop through the
557 // after list. If an element is common, then advance in the before list
558 // reporting the removed ones until the common one is reached. Report any
559 // queued up new ones and then report the common one. If an element is not
560 // common, then enqueue it for reporting. When the after list is exhausted,
561 // loop through the before list, reporting any removed ones. Finally,
562 // report the rest of the enqueued new ones.
563 std::vector<const T *> NewDataQueue;
564 while (AI != AE) {
565 if (!BFD.count(*AI)) {
566 // This section is new so place it in the queue. This will cause it
567 // to be reported after deleted sections.
568 NewDataQueue.emplace_back(&AFD.find(*AI)->getValue());
569 ++AI;
570 continue;
571 }
572 // This section is in both; advance and print out any before-only
573 // until we get to it.
574 // It's possible that this section has moved to be later than before. This
575 // will mess up printing most blocks side by side, but it's a rare case and
576 // it's better than crashing.
577 while (BI != BE && *BI != *AI) {
578 HandlePotentiallyRemovedData(*BI);
579 ++BI;
580 }
581 // Report any new sections that were queued up and waiting.
582 HandleNewData(NewDataQueue);
583
584 const T &AData = AFD.find(*AI)->getValue();
585 const T &BData = BFD.find(*AI)->getValue();
586 HandlePair(&BData, &AData);
587 if (BI != BE)
588 ++BI;
589 ++AI;
590 }
591
592 // Check any remaining before sections to see if they have been removed
593 while (BI != BE) {
594 HandlePotentiallyRemovedData(*BI);
595 ++BI;
596 }
597
598 HandleNewData(NewDataQueue);
599}
600
601template <typename T>
603 bool CompareModule,
604 std::function<void(bool InModule, unsigned Minor,
605 const FuncDataT<T> &Before, const FuncDataT<T> &After)>
606 CompareFunc) {
607 if (!CompareModule) {
608 // Just handle the single function.
609 assert(Before.getData().size() == 1 && After.getData().size() == 1 &&
610 "Expected only one function.");
611 CompareFunc(false, 0, Before.getData().begin()->getValue(),
612 After.getData().begin()->getValue());
613 return;
614 }
615
616 unsigned Minor = 0;
617 FuncDataT<T> Missing("");
618 IRDataT<T>::report(Before, After,
619 [&](const FuncDataT<T> *B, const FuncDataT<T> *A) {
620 assert((B || A) && "Both functions cannot be missing.");
621 if (!B)
622 B = &Missing;
623 else if (!A)
624 A = &Missing;
625 CompareFunc(true, Minor++, *B, *A);
626 });
627}
628
629template <typename T> void IRComparer<T>::analyzeIR(Any IR, IRDataT<T> &Data) {
630 if (const Module *M = getModuleForComparison(IR)) {
631 // Create data for each existing/interesting function in the module.
632 for (const Function &F : *M)
633 generateFunctionData(Data, F);
634 return;
635 }
636
637 const Function **FPtr = any_cast<const Function *>(&IR);
638 const Function *F = FPtr ? *FPtr : nullptr;
639 if (!F) {
640 const Loop **L = any_cast<const Loop *>(&IR);
641 assert(L && "Unknown IR unit.");
642 F = (*L)->getHeader()->getParent();
643 }
644 assert(F && "Unknown IR unit.");
645 generateFunctionData(Data, *F);
646}
647
648template <typename T>
650 if (!F.isDeclaration() && isFunctionInPrintList(F.getName())) {
651 FuncDataT<T> FD(F.getEntryBlock().getName().str());
652 int I = 0;
653 for (const auto &B : F) {
654 std::string BBName = B.getName().str();
655 if (BBName.empty()) {
656 BBName = formatv("{0}", I);
657 ++I;
658 }
659 FD.getOrder().emplace_back(BBName);
660 FD.getData().insert({BBName, B});
661 }
662 Data.getOrder().emplace_back(F.getName());
663 Data.getData().insert({F.getName(), FD});
664 return true;
665 }
666 return false;
667}
668
670 assert(ModuleDescStack.empty() && "ModuleDescStack is not empty at exit");
671}
672
673void PrintIRInstrumentation::pushModuleDesc(StringRef PassID, Any IR) {
674 const Module *M = unwrapModule(IR);
675 ModuleDescStack.emplace_back(M, getIRName(IR), PassID);
676}
677
678PrintIRInstrumentation::PrintModuleDesc
679PrintIRInstrumentation::popModuleDesc(StringRef PassID) {
680 assert(!ModuleDescStack.empty() && "empty ModuleDescStack");
681 PrintModuleDesc ModuleDesc = ModuleDescStack.pop_back_val();
682 assert(std::get<2>(ModuleDesc).equals(PassID) && "malformed ModuleDescStack");
683 return ModuleDesc;
684}
685
686void PrintIRInstrumentation::printBeforePass(StringRef PassID, Any IR) {
687 if (isIgnored(PassID))
688 return;
689
690 // Saving Module for AfterPassInvalidated operations.
691 // Note: here we rely on a fact that we do not change modules while
692 // traversing the pipeline, so the latest captured module is good
693 // for all print operations that has not happen yet.
694 if (shouldPrintAfterPass(PassID))
695 pushModuleDesc(PassID, IR);
696
697 if (!shouldPrintBeforePass(PassID))
698 return;
699
700 if (!shouldPrintIR(IR))
701 return;
702
703 dbgs() << "*** IR Dump Before " << PassID << " on " << getIRName(IR)
704 << " ***\n";
705 unwrapAndPrint(dbgs(), IR);
706}
707
708void PrintIRInstrumentation::printAfterPass(StringRef PassID, Any IR) {
709 if (isIgnored(PassID))
710 return;
711
712 if (!shouldPrintAfterPass(PassID))
713 return;
714
715 const Module *M;
716 std::string IRName;
717 StringRef StoredPassID;
718 std::tie(M, IRName, StoredPassID) = popModuleDesc(PassID);
719 assert(StoredPassID == PassID && "mismatched PassID");
720
721 if (!shouldPrintIR(IR))
722 return;
723
724 dbgs() << "*** IR Dump After " << PassID << " on " << IRName << " ***\n";
725 unwrapAndPrint(dbgs(), IR);
726}
727
728void PrintIRInstrumentation::printAfterPassInvalidated(StringRef PassID) {
730 if (!shouldPrintAfterPass(PassName))
731 return;
732
733 if (isIgnored(PassID))
734 return;
735
736 const Module *M;
737 std::string IRName;
738 StringRef StoredPassID;
739 std::tie(M, IRName, StoredPassID) = popModuleDesc(PassID);
740 assert(StoredPassID == PassID && "mismatched PassID");
741 // Additional filtering (e.g. -filter-print-func) can lead to module
742 // printing being skipped.
743 if (!M)
744 return;
745
746 SmallString<20> Banner =
747 formatv("*** IR Dump After {0} on {1} (invalidated) ***", PassID, IRName);
748 dbgs() << Banner << "\n";
749 printIR(dbgs(), M);
750}
751
752bool PrintIRInstrumentation::shouldPrintBeforePass(StringRef PassID) {
754 return true;
755
758}
759
760bool PrintIRInstrumentation::shouldPrintAfterPass(StringRef PassID) {
762 return true;
763
766}
767
770 this->PIC = &PIC;
771
772 // BeforePass callback is not just for printing, it also saves a Module
773 // for later use in AfterPassInvalidated.
776 [this](StringRef P, Any IR) { this->printBeforePass(P, IR); });
777
780 [this](StringRef P, Any IR, const PreservedAnalyses &) {
781 this->printAfterPass(P, IR);
782 });
784 [this](StringRef P, const PreservedAnalyses &) {
785 this->printAfterPassInvalidated(P);
786 });
787 }
788}
789
793 [this](StringRef P, Any IR) { return this->shouldRun(P, IR); });
794}
795
796bool OptNoneInstrumentation::shouldRun(StringRef PassID, Any IR) {
797 const Function **FPtr = any_cast<const Function *>(&IR);
798 const Function *F = FPtr ? *FPtr : nullptr;
799 if (!F) {
800 if (const auto **L = any_cast<const Loop *>(&IR))
801 F = (*L)->getHeader()->getParent();
802 }
803 bool ShouldRun = !(F && F->hasOptNone());
804 if (!ShouldRun && DebugLogging) {
805 errs() << "Skipping pass " << PassID << " on " << F->getName()
806 << " due to optnone attribute\n";
807 }
808 return ShouldRun;
809}
810
812 if (isIgnored(PassName))
813 return true;
814
815 bool ShouldRun =
816 Context.getOptPassGate().shouldRunPass(PassName, getIRName(IR));
817 if (!ShouldRun && !this->HasWrittenIR && !OptBisectPrintIRPath.empty()) {
818 // FIXME: print IR if limit is higher than number of opt-bisect
819 // invocations
820 this->HasWrittenIR = true;
821 const Module *M = unwrapModule(IR, /*Force=*/true);
822 assert((M && &M->getContext() == &Context) && "Missing/Mismatching Module");
823 std::error_code EC;
825 if (EC)
827 M->print(OS, nullptr);
828 }
829 return ShouldRun;
830}
831
834 OptPassGate &PassGate = Context.getOptPassGate();
835 if (!PassGate.isEnabled())
836 return;
837
839 return this->shouldRun(PassName, IR);
840 });
841}
842
843raw_ostream &PrintPassInstrumentation::print() {
844 if (Opts.Indent) {
845 assert(Indent >= 0);
846 dbgs().indent(Indent);
847 }
848 return dbgs();
849}
850
853 if (!Enabled)
854 return;
855
856 std::vector<StringRef> SpecialPasses;
857 if (!Opts.Verbose) {
858 SpecialPasses.emplace_back("PassManager");
859 SpecialPasses.emplace_back("PassAdaptor");
860 }
861
862 PIC.registerBeforeSkippedPassCallback([this, SpecialPasses](StringRef PassID,
863 Any IR) {
864 assert(!isSpecialPass(PassID, SpecialPasses) &&
865 "Unexpectedly skipping special pass");
866
867 print() << "Skipping pass: " << PassID << " on " << getIRName(IR) << "\n";
868 });
869 PIC.registerBeforeNonSkippedPassCallback([this, SpecialPasses](
870 StringRef PassID, Any IR) {
871 if (isSpecialPass(PassID, SpecialPasses))
872 return;
873
874 auto &OS = print();
875 OS << "Running pass: " << PassID << " on " << getIRName(IR);
876 if (const auto **F = any_cast<const Function *>(&IR)) {
877 unsigned Count = (*F)->getInstructionCount();
878 OS << " (" << Count << " instruction";
879 if (Count != 1)
880 OS << 's';
881 OS << ')';
882 } else if (const auto **C = any_cast<const LazyCallGraph::SCC *>(&IR)) {
883 int Count = (*C)->size();
884 OS << " (" << Count << " node";
885 if (Count != 1)
886 OS << 's';
887 OS << ')';
888 }
889 OS << "\n";
890 Indent += 2;
891 });
893 [this, SpecialPasses](StringRef PassID, Any IR,
894 const PreservedAnalyses &) {
895 if (isSpecialPass(PassID, SpecialPasses))
896 return;
897
898 Indent -= 2;
899 });
901 [this, SpecialPasses](StringRef PassID, Any IR) {
902 if (isSpecialPass(PassID, SpecialPasses))
903 return;
904
905 Indent -= 2;
906 });
907
908 if (!Opts.SkipAnalyses) {
910 print() << "Running analysis: " << PassID << " on " << getIRName(IR)
911 << "\n";
912 Indent += 2;
913 });
915 [this](StringRef PassID, Any IR) { Indent -= 2; });
917 print() << "Invalidating analysis: " << PassID << " on " << getIRName(IR)
918 << "\n";
919 });
921 print() << "Clearing all analysis results for: " << IRName << "\n";
922 });
923 }
924}
925
927 bool TrackBBLifetime) {
928 if (TrackBBLifetime)
930 for (const auto &BB : *F) {
931 if (BBGuards)
932 BBGuards->try_emplace(intptr_t(&BB), &BB);
933 for (const auto *Succ : successors(&BB)) {
934 Graph[&BB][Succ]++;
935 if (BBGuards)
936 BBGuards->try_emplace(intptr_t(Succ), Succ);
937 }
938 }
939}
940
941static void printBBName(raw_ostream &out, const BasicBlock *BB) {
942 if (BB->hasName()) {
943 out << BB->getName() << "<" << BB << ">";
944 return;
945 }
946
947 if (!BB->getParent()) {
948 out << "unnamed_removed<" << BB << ">";
949 return;
950 }
951
952 if (BB->isEntryBlock()) {
953 out << "entry"
954 << "<" << BB << ">";
955 return;
956 }
957
958 unsigned FuncOrderBlockNum = 0;
959 for (auto &FuncBB : *BB->getParent()) {
960 if (&FuncBB == BB)
961 break;
962 FuncOrderBlockNum++;
963 }
964 out << "unnamed_" << FuncOrderBlockNum << "<" << BB << ">";
965}
966
968 const CFG &Before,
969 const CFG &After) {
970 assert(!After.isPoisoned());
971 if (Before.isPoisoned()) {
972 out << "Some blocks were deleted\n";
973 return;
974 }
975
976 // Find and print graph differences.
977 if (Before.Graph.size() != After.Graph.size())
978 out << "Different number of non-leaf basic blocks: before="
979 << Before.Graph.size() << ", after=" << After.Graph.size() << "\n";
980
981 for (auto &BB : Before.Graph) {
982 auto BA = After.Graph.find(BB.first);
983 if (BA == After.Graph.end()) {
984 out << "Non-leaf block ";
985 printBBName(out, BB.first);
986 out << " is removed (" << BB.second.size() << " successors)\n";
987 }
988 }
989
990 for (auto &BA : After.Graph) {
991 auto BB = Before.Graph.find(BA.first);
992 if (BB == Before.Graph.end()) {
993 out << "Non-leaf block ";
994 printBBName(out, BA.first);
995 out << " is added (" << BA.second.size() << " successors)\n";
996 continue;
997 }
998
999 if (BB->second == BA.second)
1000 continue;
1001
1002 out << "Different successors of block ";
1003 printBBName(out, BA.first);
1004 out << " (unordered):\n";
1005 out << "- before (" << BB->second.size() << "): ";
1006 for (auto &SuccB : BB->second) {
1007 printBBName(out, SuccB.first);
1008 if (SuccB.second != 1)
1009 out << "(" << SuccB.second << "), ";
1010 else
1011 out << ", ";
1012 }
1013 out << "\n";
1014 out << "- after (" << BA.second.size() << "): ";
1015 for (auto &SuccA : BA.second) {
1016 printBBName(out, SuccA.first);
1017 if (SuccA.second != 1)
1018 out << "(" << SuccA.second << "), ";
1019 else
1020 out << ", ";
1021 }
1022 out << "\n";
1023 }
1024}
1025
1026// PreservedCFGCheckerInstrumentation uses PreservedCFGCheckerAnalysis to check
1027// passes, that reported they kept CFG analyses up-to-date, did not actually
1028// change CFG. This check is done as follows. Before every functional pass in
1029// BeforeNonSkippedPassCallback a CFG snapshot (an instance of
1030// PreservedCFGCheckerInstrumentation::CFG) is requested from
1031// FunctionAnalysisManager as a result of PreservedCFGCheckerAnalysis. When the
1032// functional pass finishes and reports that CFGAnalyses or AllAnalyses are
1033// up-to-date then the cached result of PreservedCFGCheckerAnalysis (if
1034// available) is checked to be equal to a freshly created CFG snapshot.
1036 : public AnalysisInfoMixin<PreservedCFGCheckerAnalysis> {
1038
1040
1041public:
1042 /// Provide the result type for this analysis pass.
1044
1045 /// Run the analysis pass over a function and produce CFG.
1047 return Result(&F, /* TrackBBLifetime */ true);
1048 }
1049};
1050
1052
1054 : public AnalysisInfoMixin<PreservedFunctionHashAnalysis> {
1056
1059 };
1060
1062
1064 return Result{StructuralHash(F)};
1065 }
1066};
1067
1069
1071 : public AnalysisInfoMixin<PreservedModuleHashAnalysis> {
1073
1074 struct ModuleHash {
1076 };
1077
1079
1081 return Result{StructuralHash(F)};
1082 }
1083};
1084
1086
1088 Function &F, const PreservedAnalyses &PA,
1090 auto PAC = PA.getChecker<PreservedCFGCheckerAnalysis>();
1091 return !(PAC.preserved() || PAC.preservedSet<AllAnalysesOn<Function>>() ||
1092 PAC.preservedSet<CFGAnalyses>());
1093}
1094
1097
1098 if (const auto **MaybeF = any_cast<const Function *>(&IR)) {
1099 Functions.push_back(*const_cast<Function **>(MaybeF));
1100 } else if (const auto **MaybeM = any_cast<const Module *>(&IR)) {
1101 for (Function &F : **const_cast<Module **>(MaybeM))
1102 Functions.push_back(&F);
1103 }
1104 return Functions;
1105}
1106
1110 return;
1111
1112 bool Registered = false;
1113 PIC.registerBeforeNonSkippedPassCallback([this, &MAM, Registered](
1114 StringRef P, Any IR) mutable {
1115#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
1116 assert(&PassStack.emplace_back(P));
1117#endif
1118 (void)this;
1119
1121 *const_cast<Module *>(unwrapModule(IR, /*Force=*/true)))
1122 .getManager();
1123 if (!Registered) {
1124 FAM.registerPass([&] { return PreservedCFGCheckerAnalysis(); });
1126 MAM.registerPass([&] { return PreservedModuleHashAnalysis(); });
1127 Registered = true;
1128 }
1129
1130 for (Function *F : GetFunctions(IR)) {
1131 // Make sure a fresh CFG snapshot is available before the pass.
1134 }
1135
1136 if (auto *MaybeM = any_cast<const Module *>(&IR)) {
1137 Module &M = **const_cast<Module **>(MaybeM);
1139 }
1140 });
1141
1143 [this](StringRef P, const PreservedAnalyses &PassPA) {
1144#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
1145 assert(PassStack.pop_back_val() == P &&
1146 "Before and After callbacks must correspond");
1147#endif
1148 (void)this;
1149 });
1150
1152 const PreservedAnalyses &PassPA) {
1153#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
1154 assert(PassStack.pop_back_val() == P &&
1155 "Before and After callbacks must correspond");
1156#endif
1157 (void)this;
1158
1159 // We have to get the FAM via the MAM, rather than directly use a passed in
1160 // FAM because if MAM has not cached the FAM, it won't invalidate function
1161 // analyses in FAM.
1163 *const_cast<Module *>(unwrapModule(IR, /*Force=*/true)))
1164 .getManager();
1165
1166 for (Function *F : GetFunctions(IR)) {
1167 if (auto *HashBefore =
1169 if (HashBefore->Hash != StructuralHash(*F)) {
1171 "Function @{0} changed by {1} without invalidating analyses",
1172 F->getName(), P));
1173 }
1174 }
1175
1176 auto CheckCFG = [](StringRef Pass, StringRef FuncName,
1177 const CFG &GraphBefore, const CFG &GraphAfter) {
1178 if (GraphAfter == GraphBefore)
1179 return;
1180
1181 dbgs()
1182 << "Error: " << Pass
1183 << " does not invalidate CFG analyses but CFG changes detected in "
1184 "function @"
1185 << FuncName << ":\n";
1186 CFG::printDiff(dbgs(), GraphBefore, GraphAfter);
1187 report_fatal_error(Twine("CFG unexpectedly changed by ", Pass));
1188 };
1189
1190 if (auto *GraphBefore =
1192 CheckCFG(P, F->getName(), *GraphBefore,
1193 CFG(F, /* TrackBBLifetime */ false));
1194 }
1195 if (auto *MaybeM = any_cast<const Module *>(&IR)) {
1196 Module &M = **const_cast<Module **>(MaybeM);
1197 if (auto *HashBefore =
1199 if (HashBefore->Hash != StructuralHash(M)) {
1201 "Module changed by {0} without invalidating analyses", P));
1202 }
1203 }
1204 }
1205 });
1206}
1207
1211 [this](StringRef P, Any IR, const PreservedAnalyses &PassPA) {
1212 if (isIgnored(P) || P == "VerifierPass")
1213 return;
1214 const Function **FPtr = any_cast<const Function *>(&IR);
1215 const Function *F = FPtr ? *FPtr : nullptr;
1216 if (!F) {
1217 if (const auto **L = any_cast<const Loop *>(&IR))
1218 F = (*L)->getHeader()->getParent();
1219 }
1220
1221 if (F) {
1222 if (DebugLogging)
1223 dbgs() << "Verifying function " << F->getName() << "\n";
1224
1225 if (verifyFunction(*F, &errs()))
1226 report_fatal_error("Broken function found, compilation aborted!");
1227 } else {
1228 const Module **MPtr = any_cast<const Module *>(&IR);
1229 const Module *M = MPtr ? *MPtr : nullptr;
1230 if (!M) {
1231 if (const auto **C = any_cast<const LazyCallGraph::SCC *>(&IR))
1232 M = (*C)->begin()->getFunction().getParent();
1233 }
1234
1235 if (M) {
1236 if (DebugLogging)
1237 dbgs() << "Verifying module " << M->getName() << "\n";
1238
1239 if (verifyModule(*M, &errs()))
1240 report_fatal_error("Broken module found, compilation aborted!");
1241 }
1242 }
1243 });
1244}
1245
1247
1249 StringRef PassID,
1252}
1253
1255 const IRDataT<EmptyData> &Before,
1256 const IRDataT<EmptyData> &After,
1257 Any IR) {
1258 SmallString<20> Banner =
1259 formatv("*** IR Dump After {0} on {1} ***\n", PassID, Name);
1260 Out << Banner;
1261 IRComparer<EmptyData>(Before, After)
1262 .compare(getModuleForComparison(IR),
1263 [&](bool InModule, unsigned Minor,
1264 const FuncDataT<EmptyData> &Before,
1265 const FuncDataT<EmptyData> &After) -> void {
1266 handleFunctionCompare(Name, "", PassID, " on ", InModule,
1267 Minor, Before, After);
1268 });
1269 Out << "\n";
1270}
1271
1273 StringRef Name, StringRef Prefix, StringRef PassID, StringRef Divider,
1274 bool InModule, unsigned Minor, const FuncDataT<EmptyData> &Before,
1275 const FuncDataT<EmptyData> &After) {
1276 // Print a banner when this is being shown in the context of a module
1277 if (InModule)
1278 Out << "\n*** IR for function " << Name << " ***\n";
1279
1281 Before, After,
1282 [&](const BlockDataT<EmptyData> *B, const BlockDataT<EmptyData> *A) {
1283 StringRef BStr = B ? B->getBody() : "\n";
1284 StringRef AStr = A ? A->getBody() : "\n";
1285 const std::string Removed =
1286 UseColour ? "\033[31m-%l\033[0m\n" : "-%l\n";
1287 const std::string Added = UseColour ? "\033[32m+%l\033[0m\n" : "+%l\n";
1288 const std::string NoChange = " %l\n";
1289 Out << doSystemDiff(BStr, AStr, Removed, Added, NoChange);
1290 });
1291}
1292
1298 TextChangeReporter<IRDataT<EmptyData>>::registerRequiredCallbacks(PIC);
1299}
1300
1302
1306 return;
1308 [this](StringRef P, Any IR) { this->runBeforePass(P, IR); });
1310 [this](StringRef P, Any IR, const PreservedAnalyses &) {
1311 this->runAfterPass();
1312 },
1313 true);
1315 [this](StringRef P, const PreservedAnalyses &) { this->runAfterPass(); },
1316 true);
1318 [this](StringRef P, Any IR) { this->runBeforePass(P, IR); });
1320 [this](StringRef P, Any IR) { this->runAfterPass(); }, true);
1321}
1322
1323void TimeProfilingPassesHandler::runBeforePass(StringRef PassID, Any IR) {
1324 timeTraceProfilerBegin(PassID, getIRName(IR));
1325}
1326
1327void TimeProfilingPassesHandler::runAfterPass() { timeTraceProfilerEnd(); }
1328
1329namespace {
1330
1331class DisplayNode;
1332class DotCfgDiffDisplayGraph;
1333
1334// Base class for a node or edge in the dot-cfg-changes graph.
1335class DisplayElement {
1336public:
1337 // Is this in before, after, or both?
1338 StringRef getColour() const { return Colour; }
1339
1340protected:
1341 DisplayElement(StringRef Colour) : Colour(Colour) {}
1342 const StringRef Colour;
1343};
1344
1345// An edge representing a transition between basic blocks in the
1346// dot-cfg-changes graph.
1347class DisplayEdge : public DisplayElement {
1348public:
1349 DisplayEdge(std::string Value, DisplayNode &Node, StringRef Colour)
1350 : DisplayElement(Colour), Value(Value), Node(Node) {}
1351 // The value on which the transition is made.
1352 std::string getValue() const { return Value; }
1353 // The node (representing a basic block) reached by this transition.
1354 const DisplayNode &getDestinationNode() const { return Node; }
1355
1356protected:
1357 std::string Value;
1358 const DisplayNode &Node;
1359};
1360
1361// A node in the dot-cfg-changes graph which represents a basic block.
1362class DisplayNode : public DisplayElement {
1363public:
1364 // \p C is the content for the node, \p T indicates the colour for the
1365 // outline of the node
1366 DisplayNode(std::string Content, StringRef Colour)
1367 : DisplayElement(Colour), Content(Content) {}
1368
1369 // Iterator to the child nodes. Required by GraphWriter.
1370 using ChildIterator = std::unordered_set<DisplayNode *>::const_iterator;
1371 ChildIterator children_begin() const { return Children.cbegin(); }
1372 ChildIterator children_end() const { return Children.cend(); }
1373
1374 // Iterator for the edges. Required by GraphWriter.
1375 using EdgeIterator = std::vector<DisplayEdge *>::const_iterator;
1376 EdgeIterator edges_begin() const { return EdgePtrs.cbegin(); }
1377 EdgeIterator edges_end() const { return EdgePtrs.cend(); }
1378
1379 // Create an edge to \p Node on value \p Value, with colour \p Colour.
1380 void createEdge(StringRef Value, DisplayNode &Node, StringRef Colour);
1381
1382 // Return the content of this node.
1383 std::string getContent() const { return Content; }
1384
1385 // Return the edge to node \p S.
1386 const DisplayEdge &getEdge(const DisplayNode &To) const {
1387 assert(EdgeMap.find(&To) != EdgeMap.end() && "Expected to find edge.");
1388 return *EdgeMap.find(&To)->second;
1389 }
1390
1391 // Return the value for the transition to basic block \p S.
1392 // Required by GraphWriter.
1393 std::string getEdgeSourceLabel(const DisplayNode &Sink) const {
1394 return getEdge(Sink).getValue();
1395 }
1396
1397 void createEdgeMap();
1398
1399protected:
1400 const std::string Content;
1401
1402 // Place to collect all of the edges. Once they are all in the vector,
1403 // the vector will not reallocate so then we can use pointers to them,
1404 // which are required by the graph writing routines.
1405 std::vector<DisplayEdge> Edges;
1406
1407 std::vector<DisplayEdge *> EdgePtrs;
1408 std::unordered_set<DisplayNode *> Children;
1409 std::unordered_map<const DisplayNode *, const DisplayEdge *> EdgeMap;
1410
1411 // Safeguard adding of edges.
1412 bool AllEdgesCreated = false;
1413};
1414
1415// Class representing a difference display (corresponds to a pdf file).
1416class DotCfgDiffDisplayGraph {
1417public:
1418 DotCfgDiffDisplayGraph(std::string Name) : GraphName(Name) {}
1419
1420 // Generate the file into \p DotFile.
1421 void generateDotFile(StringRef DotFile);
1422
1423 // Iterator to the nodes. Required by GraphWriter.
1424 using NodeIterator = std::vector<DisplayNode *>::const_iterator;
1425 NodeIterator nodes_begin() const {
1426 assert(NodeGenerationComplete && "Unexpected children iterator creation");
1427 return NodePtrs.cbegin();
1428 }
1429 NodeIterator nodes_end() const {
1430 assert(NodeGenerationComplete && "Unexpected children iterator creation");
1431 return NodePtrs.cend();
1432 }
1433
1434 // Record the index of the entry node. At this point, we can build up
1435 // vectors of pointers that are required by the graph routines.
1436 void setEntryNode(unsigned N) {
1437 // At this point, there will be no new nodes.
1438 assert(!NodeGenerationComplete && "Unexpected node creation");
1439 NodeGenerationComplete = true;
1440 for (auto &N : Nodes)
1441 NodePtrs.emplace_back(&N);
1442
1443 EntryNode = NodePtrs[N];
1444 }
1445
1446 // Create a node.
1447 void createNode(std::string C, StringRef Colour) {
1448 assert(!NodeGenerationComplete && "Unexpected node creation");
1449 Nodes.emplace_back(C, Colour);
1450 }
1451 // Return the node at index \p N to avoid problems with vectors reallocating.
1452 DisplayNode &getNode(unsigned N) {
1453 assert(N < Nodes.size() && "Node is out of bounds");
1454 return Nodes[N];
1455 }
1456 unsigned size() const {
1457 assert(NodeGenerationComplete && "Unexpected children iterator creation");
1458 return Nodes.size();
1459 }
1460
1461 // Return the name of the graph. Required by GraphWriter.
1462 std::string getGraphName() const { return GraphName; }
1463
1464 // Return the string representing the differences for basic block \p Node.
1465 // Required by GraphWriter.
1466 std::string getNodeLabel(const DisplayNode &Node) const {
1467 return Node.getContent();
1468 }
1469
1470 // Return a string with colour information for Dot. Required by GraphWriter.
1471 std::string getNodeAttributes(const DisplayNode &Node) const {
1472 return attribute(Node.getColour());
1473 }
1474
1475 // Return a string with colour information for Dot. Required by GraphWriter.
1476 std::string getEdgeColorAttr(const DisplayNode &From,
1477 const DisplayNode &To) const {
1478 return attribute(From.getEdge(To).getColour());
1479 }
1480
1481 // Get the starting basic block. Required by GraphWriter.
1482 DisplayNode *getEntryNode() const {
1483 assert(NodeGenerationComplete && "Unexpected children iterator creation");
1484 return EntryNode;
1485 }
1486
1487protected:
1488 // Return the string containing the colour to use as a Dot attribute.
1489 std::string attribute(StringRef Colour) const {
1490 return "color=" + Colour.str();
1491 }
1492
1493 bool NodeGenerationComplete = false;
1494 const std::string GraphName;
1495 std::vector<DisplayNode> Nodes;
1496 std::vector<DisplayNode *> NodePtrs;
1497 DisplayNode *EntryNode = nullptr;
1498};
1499
1500void DisplayNode::createEdge(StringRef Value, DisplayNode &Node,
1501 StringRef Colour) {
1502 assert(!AllEdgesCreated && "Expected to be able to still create edges.");
1503 Edges.emplace_back(Value.str(), Node, Colour);
1504 Children.insert(&Node);
1505}
1506
1507void DisplayNode::createEdgeMap() {
1508 // No more edges will be added so we can now use pointers to the edges
1509 // as the vector will not grow and reallocate.
1510 AllEdgesCreated = true;
1511 for (auto &E : Edges)
1512 EdgeMap.insert({&E.getDestinationNode(), &E});
1513}
1514
1515class DotCfgDiffNode;
1516class DotCfgDiff;
1517
1518// A class representing a basic block in the Dot difference graph.
1519class DotCfgDiffNode {
1520public:
1521 DotCfgDiffNode() = delete;
1522
1523 // Create a node in Dot difference graph \p G representing the basic block
1524 // represented by \p BD with colour \p Colour (where it exists).
1525 DotCfgDiffNode(DotCfgDiff &G, unsigned N, const BlockDataT<DCData> &BD,
1526 StringRef Colour)
1527 : Graph(G), N(N), Data{&BD, nullptr}, Colour(Colour) {}
1528 DotCfgDiffNode(const DotCfgDiffNode &DN)
1529 : Graph(DN.Graph), N(DN.N), Data{DN.Data[0], DN.Data[1]},
1530 Colour(DN.Colour), EdgesMap(DN.EdgesMap), Children(DN.Children),
1531 Edges(DN.Edges) {}
1532
1533 unsigned getIndex() const { return N; }
1534
1535 // The label of the basic block
1536 StringRef getLabel() const {
1537 assert(Data[0] && "Expected Data[0] to be set.");
1538 return Data[0]->getLabel();
1539 }
1540 // Return the colour for this block
1541 StringRef getColour() const { return Colour; }
1542 // Change this basic block from being only in before to being common.
1543 // Save the pointer to \p Other.
1544 void setCommon(const BlockDataT<DCData> &Other) {
1545 assert(!Data[1] && "Expected only one block datum");
1546 Data[1] = &Other;
1547 Colour = CommonColour;
1548 }
1549 // Add an edge to \p E of colour {\p Value, \p Colour}.
1550 void addEdge(unsigned E, StringRef Value, StringRef Colour) {
1551 // This is a new edge or it is an edge being made common.
1552 assert((EdgesMap.count(E) == 0 || Colour == CommonColour) &&
1553 "Unexpected edge count and color.");
1554 EdgesMap[E] = {Value.str(), Colour};
1555 }
1556 // Record the children and create edges.
1557 void finalize(DotCfgDiff &G);
1558
1559 // Return the colour of the edge to node \p S.
1560 StringRef getEdgeColour(const unsigned S) const {
1561 assert(EdgesMap.count(S) == 1 && "Expected to find edge.");
1562 return EdgesMap.at(S).second;
1563 }
1564
1565 // Return the string representing the basic block.
1566 std::string getBodyContent() const;
1567
1568 void createDisplayEdges(DotCfgDiffDisplayGraph &Graph, unsigned DisplayNode,
1569 std::map<const unsigned, unsigned> &NodeMap) const;
1570
1571protected:
1572 DotCfgDiff &Graph;
1573 const unsigned N;
1574 const BlockDataT<DCData> *Data[2];
1575 StringRef Colour;
1576 std::map<const unsigned, std::pair<std::string, StringRef>> EdgesMap;
1577 std::vector<unsigned> Children;
1578 std::vector<unsigned> Edges;
1579};
1580
1581// Class representing the difference graph between two functions.
1582class DotCfgDiff {
1583public:
1584 // \p Title is the title given to the graph. \p EntryNodeName is the
1585 // entry node for the function. \p Before and \p After are the before
1586 // after versions of the function, respectively. \p Dir is the directory
1587 // in which to store the results.
1588 DotCfgDiff(StringRef Title, const FuncDataT<DCData> &Before,
1589 const FuncDataT<DCData> &After);
1590
1591 DotCfgDiff(const DotCfgDiff &) = delete;
1592 DotCfgDiff &operator=(const DotCfgDiff &) = delete;
1593
1594 DotCfgDiffDisplayGraph createDisplayGraph(StringRef Title,
1595 StringRef EntryNodeName);
1596
1597 // Return a string consisting of the labels for the \p Source and \p Sink.
1598 // The combination allows distinguishing changing transitions on the
1599 // same value (ie, a transition went to X before and goes to Y after).
1600 // Required by GraphWriter.
1601 StringRef getEdgeSourceLabel(const unsigned &Source,
1602 const unsigned &Sink) const {
1603 std::string S =
1604 getNode(Source).getLabel().str() + " " + getNode(Sink).getLabel().str();
1605 assert(EdgeLabels.count(S) == 1 && "Expected to find edge label.");
1606 return EdgeLabels.find(S)->getValue();
1607 }
1608
1609 // Return the number of basic blocks (nodes). Required by GraphWriter.
1610 unsigned size() const { return Nodes.size(); }
1611
1612 const DotCfgDiffNode &getNode(unsigned N) const {
1613 assert(N < Nodes.size() && "Unexpected index for node reference");
1614 return Nodes[N];
1615 }
1616
1617protected:
1618 // Return the string surrounded by HTML to make it the appropriate colour.
1619 std::string colourize(std::string S, StringRef Colour) const;
1620
1621 void createNode(StringRef Label, const BlockDataT<DCData> &BD, StringRef C) {
1622 unsigned Pos = Nodes.size();
1623 Nodes.emplace_back(*this, Pos, BD, C);
1624 NodePosition.insert({Label, Pos});
1625 }
1626
1627 // TODO Nodes should probably be a StringMap<DotCfgDiffNode> after the
1628 // display graph is separated out, which would remove the need for
1629 // NodePosition.
1630 std::vector<DotCfgDiffNode> Nodes;
1631 StringMap<unsigned> NodePosition;
1632 const std::string GraphName;
1633
1634 StringMap<std::string> EdgeLabels;
1635};
1636
1637std::string DotCfgDiffNode::getBodyContent() const {
1638 if (Colour == CommonColour) {
1639 assert(Data[1] && "Expected Data[1] to be set.");
1640
1641 StringRef SR[2];
1642 for (unsigned I = 0; I < 2; ++I) {
1643 SR[I] = Data[I]->getBody();
1644 // drop initial '\n' if present
1645 if (SR[I][0] == '\n')
1646 SR[I] = SR[I].drop_front();
1647 // drop predecessors as they can be big and are redundant
1648 SR[I] = SR[I].drop_until([](char C) { return C == '\n'; }).drop_front();
1649 }
1650
1651 SmallString<80> OldLineFormat = formatv(
1652 "<FONT COLOR=\"{0}\">%l</FONT><BR align=\"left\"/>", BeforeColour);
1653 SmallString<80> NewLineFormat = formatv(
1654 "<FONT COLOR=\"{0}\">%l</FONT><BR align=\"left\"/>", AfterColour);
1655 SmallString<80> UnchangedLineFormat = formatv(
1656 "<FONT COLOR=\"{0}\">%l</FONT><BR align=\"left\"/>", CommonColour);
1657 std::string Diff = Data[0]->getLabel().str();
1658 Diff += ":\n<BR align=\"left\"/>" +
1659 doSystemDiff(makeHTMLReady(SR[0]), makeHTMLReady(SR[1]),
1660 OldLineFormat, NewLineFormat, UnchangedLineFormat);
1661
1662 // Diff adds in some empty colour changes which are not valid HTML
1663 // so remove them. Colours are all lowercase alpha characters (as
1664 // listed in https://graphviz.org/pdf/dotguide.pdf).
1665 Regex R("<FONT COLOR=\"\\w+\"></FONT>");
1666 while (true) {
1667 std::string Error;
1668 std::string S = R.sub("", Diff, &Error);
1669 if (Error != "")
1670 return Error;
1671 if (S == Diff)
1672 return Diff;
1673 Diff = S;
1674 }
1675 llvm_unreachable("Should not get here");
1676 }
1677
1678 // Put node out in the appropriate colour.
1679 assert(!Data[1] && "Data[1] is set unexpectedly.");
1680 std::string Body = makeHTMLReady(Data[0]->getBody());
1681 const StringRef BS = Body;
1682 StringRef BS1 = BS;
1683 // Drop leading newline, if present.
1684 if (BS.front() == '\n')
1685 BS1 = BS1.drop_front(1);
1686 // Get label.
1687 StringRef Label = BS1.take_until([](char C) { return C == ':'; });
1688 // drop predecessors as they can be big and are redundant
1689 BS1 = BS1.drop_until([](char C) { return C == '\n'; }).drop_front();
1690
1691 std::string S = "<FONT COLOR=\"" + Colour.str() + "\">" + Label.str() + ":";
1692
1693 // align each line to the left.
1694 while (BS1.size()) {
1695 S.append("<BR align=\"left\"/>");
1696 StringRef Line = BS1.take_until([](char C) { return C == '\n'; });
1697 S.append(Line.str());
1698 BS1 = BS1.drop_front(Line.size() + 1);
1699 }
1700 S.append("<BR align=\"left\"/></FONT>");
1701 return S;
1702}
1703
1704std::string DotCfgDiff::colourize(std::string S, StringRef Colour) const {
1705 if (S.length() == 0)
1706 return S;
1707 return "<FONT COLOR=\"" + Colour.str() + "\">" + S + "</FONT>";
1708}
1709
1710DotCfgDiff::DotCfgDiff(StringRef Title, const FuncDataT<DCData> &Before,
1711 const FuncDataT<DCData> &After)
1712 : GraphName(Title.str()) {
1713 StringMap<StringRef> EdgesMap;
1714
1715 // Handle each basic block in the before IR.
1716 for (auto &B : Before.getData()) {
1717 StringRef Label = B.getKey();
1718 const BlockDataT<DCData> &BD = B.getValue();
1719 createNode(Label, BD, BeforeColour);
1720
1721 // Create transitions with names made up of the from block label, the value
1722 // on which the transition is made and the to block label.
1723 for (StringMap<std::string>::const_iterator Sink = BD.getData().begin(),
1724 E = BD.getData().end();
1725 Sink != E; ++Sink) {
1726 std::string Key = (Label + " " + Sink->getKey().str()).str() + " " +
1727 BD.getData().getSuccessorLabel(Sink->getKey()).str();
1728 EdgesMap.insert({Key, BeforeColour});
1729 }
1730 }
1731
1732 // Handle each basic block in the after IR
1733 for (auto &A : After.getData()) {
1734 StringRef Label = A.getKey();
1735 const BlockDataT<DCData> &BD = A.getValue();
1736 unsigned C = NodePosition.count(Label);
1737 if (C == 0)
1738 // This only exists in the after IR. Create the node.
1739 createNode(Label, BD, AfterColour);
1740 else {
1741 assert(C == 1 && "Unexpected multiple nodes.");
1742 Nodes[NodePosition[Label]].setCommon(BD);
1743 }
1744 // Add in the edges between the nodes (as common or only in after).
1745 for (StringMap<std::string>::const_iterator Sink = BD.getData().begin(),
1746 E = BD.getData().end();
1747 Sink != E; ++Sink) {
1748 std::string Key = (Label + " " + Sink->getKey().str()).str() + " " +
1749 BD.getData().getSuccessorLabel(Sink->getKey()).str();
1750 unsigned C = EdgesMap.count(Key);
1751 if (C == 0)
1752 EdgesMap.insert({Key, AfterColour});
1753 else {
1754 EdgesMap[Key] = CommonColour;
1755 }
1756 }
1757 }
1758
1759 // Now go through the map of edges and add them to the node.
1760 for (auto &E : EdgesMap) {
1761 // Extract the source, sink and value from the edge key.
1762 StringRef S = E.getKey();
1763 auto SP1 = S.rsplit(' ');
1764 auto &SourceSink = SP1.first;
1765 auto SP2 = SourceSink.split(' ');
1766 StringRef Source = SP2.first;
1767 StringRef Sink = SP2.second;
1768 StringRef Value = SP1.second;
1769
1770 assert(NodePosition.count(Source) == 1 && "Expected to find node.");
1771 DotCfgDiffNode &SourceNode = Nodes[NodePosition[Source]];
1772 assert(NodePosition.count(Sink) == 1 && "Expected to find node.");
1773 unsigned SinkNode = NodePosition[Sink];
1774 StringRef Colour = E.second;
1775
1776 // Look for an edge from Source to Sink
1777 if (EdgeLabels.count(SourceSink) == 0)
1778 EdgeLabels.insert({SourceSink, colourize(Value.str(), Colour)});
1779 else {
1780 StringRef V = EdgeLabels.find(SourceSink)->getValue();
1781 std::string NV = colourize(V.str() + " " + Value.str(), Colour);
1782 Colour = CommonColour;
1783 EdgeLabels[SourceSink] = NV;
1784 }
1785 SourceNode.addEdge(SinkNode, Value, Colour);
1786 }
1787 for (auto &I : Nodes)
1788 I.finalize(*this);
1789}
1790
1791DotCfgDiffDisplayGraph DotCfgDiff::createDisplayGraph(StringRef Title,
1792 StringRef EntryNodeName) {
1793 assert(NodePosition.count(EntryNodeName) == 1 &&
1794 "Expected to find entry block in map.");
1795 unsigned Entry = NodePosition[EntryNodeName];
1796 assert(Entry < Nodes.size() && "Expected to find entry node");
1797 DotCfgDiffDisplayGraph G(Title.str());
1798
1799 std::map<const unsigned, unsigned> NodeMap;
1800
1801 int EntryIndex = -1;
1802 unsigned Index = 0;
1803 for (auto &I : Nodes) {
1804 if (I.getIndex() == Entry)
1805 EntryIndex = Index;
1806 G.createNode(I.getBodyContent(), I.getColour());
1807 NodeMap.insert({I.getIndex(), Index++});
1808 }
1809 assert(EntryIndex >= 0 && "Expected entry node index to be set.");
1810 G.setEntryNode(EntryIndex);
1811
1812 for (auto &I : NodeMap) {
1813 unsigned SourceNode = I.first;
1814 unsigned DisplayNode = I.second;
1815 getNode(SourceNode).createDisplayEdges(G, DisplayNode, NodeMap);
1816 }
1817 return G;
1818}
1819
1820void DotCfgDiffNode::createDisplayEdges(
1821 DotCfgDiffDisplayGraph &DisplayGraph, unsigned DisplayNodeIndex,
1822 std::map<const unsigned, unsigned> &NodeMap) const {
1823
1824 DisplayNode &SourceDisplayNode = DisplayGraph.getNode(DisplayNodeIndex);
1825
1826 for (auto I : Edges) {
1827 unsigned SinkNodeIndex = I;
1828 StringRef Colour = getEdgeColour(SinkNodeIndex);
1829 const DotCfgDiffNode *SinkNode = &Graph.getNode(SinkNodeIndex);
1830
1831 StringRef Label = Graph.getEdgeSourceLabel(getIndex(), SinkNodeIndex);
1832 DisplayNode &SinkDisplayNode = DisplayGraph.getNode(SinkNode->getIndex());
1833 SourceDisplayNode.createEdge(Label, SinkDisplayNode, Colour);
1834 }
1835 SourceDisplayNode.createEdgeMap();
1836}
1837
1838void DotCfgDiffNode::finalize(DotCfgDiff &G) {
1839 for (auto E : EdgesMap) {
1840 Children.emplace_back(E.first);
1841 Edges.emplace_back(E.first);
1842 }
1843}
1844
1845} // namespace
1846
1847namespace llvm {
1848
1849template <> struct GraphTraits<DotCfgDiffDisplayGraph *> {
1850 using NodeRef = const DisplayNode *;
1851 using ChildIteratorType = DisplayNode::ChildIterator;
1852 using nodes_iterator = DotCfgDiffDisplayGraph::NodeIterator;
1853 using EdgeRef = const DisplayEdge *;
1854 using ChildEdgeIterator = DisplayNode::EdgeIterator;
1855
1856 static NodeRef getEntryNode(const DotCfgDiffDisplayGraph *G) {
1857 return G->getEntryNode();
1858 }
1860 return N->children_begin();
1861 }
1862 static ChildIteratorType child_end(NodeRef N) { return N->children_end(); }
1863 static nodes_iterator nodes_begin(const DotCfgDiffDisplayGraph *G) {
1864 return G->nodes_begin();
1865 }
1866 static nodes_iterator nodes_end(const DotCfgDiffDisplayGraph *G) {
1867 return G->nodes_end();
1868 }
1870 return N->edges_begin();
1871 }
1872 static ChildEdgeIterator child_edge_end(NodeRef N) { return N->edges_end(); }
1873 static NodeRef edge_dest(EdgeRef E) { return &E->getDestinationNode(); }
1874 static unsigned size(const DotCfgDiffDisplayGraph *G) { return G->size(); }
1875};
1876
1877template <>
1878struct DOTGraphTraits<DotCfgDiffDisplayGraph *> : public DefaultDOTGraphTraits {
1879 explicit DOTGraphTraits(bool Simple = false)
1880 : DefaultDOTGraphTraits(Simple) {}
1881
1882 static bool renderNodesUsingHTML() { return true; }
1883 static std::string getGraphName(const DotCfgDiffDisplayGraph *DiffData) {
1884 return DiffData->getGraphName();
1885 }
1886 static std::string
1887 getGraphProperties(const DotCfgDiffDisplayGraph *DiffData) {
1888 return "\tsize=\"190, 190\";\n";
1889 }
1890 static std::string getNodeLabel(const DisplayNode *Node,
1891 const DotCfgDiffDisplayGraph *DiffData) {
1892 return DiffData->getNodeLabel(*Node);
1893 }
1894 static std::string getNodeAttributes(const DisplayNode *Node,
1895 const DotCfgDiffDisplayGraph *DiffData) {
1896 return DiffData->getNodeAttributes(*Node);
1897 }
1898 static std::string getEdgeSourceLabel(const DisplayNode *From,
1899 DisplayNode::ChildIterator &To) {
1900 return From->getEdgeSourceLabel(**To);
1901 }
1902 static std::string getEdgeAttributes(const DisplayNode *From,
1903 DisplayNode::ChildIterator &To,
1904 const DotCfgDiffDisplayGraph *DiffData) {
1905 return DiffData->getEdgeColorAttr(*From, **To);
1906 }
1907};
1908
1909} // namespace llvm
1910
1911namespace {
1912
1913void DotCfgDiffDisplayGraph::generateDotFile(StringRef DotFile) {
1914 std::error_code EC;
1915 raw_fd_ostream OutStream(DotFile, EC);
1916 if (EC) {
1917 errs() << "Error: " << EC.message() << "\n";
1918 return;
1919 }
1920 WriteGraph(OutStream, this, false);
1921 OutStream.flush();
1922 OutStream.close();
1923}
1924
1925} // namespace
1926
1927namespace llvm {
1928
1930 // Build up transition labels.
1931 const Instruction *Term = B.getTerminator();
1932 if (const BranchInst *Br = dyn_cast<const BranchInst>(Term))
1933 if (Br->isUnconditional())
1934 addSuccessorLabel(Br->getSuccessor(0)->getName().str(), "");
1935 else {
1936 addSuccessorLabel(Br->getSuccessor(0)->getName().str(), "true");
1937 addSuccessorLabel(Br->getSuccessor(1)->getName().str(), "false");
1938 }
1939 else if (const SwitchInst *Sw = dyn_cast<const SwitchInst>(Term)) {
1940 addSuccessorLabel(Sw->case_default()->getCaseSuccessor()->getName().str(),
1941 "default");
1942 for (auto &C : Sw->cases()) {
1943 assert(C.getCaseValue() && "Expected to find case value.");
1944 SmallString<20> Value = formatv("{0}", C.getCaseValue()->getSExtValue());
1945 addSuccessorLabel(C.getCaseSuccessor()->getName().str(), Value);
1946 }
1947 } else
1948 for (const_succ_iterator I = succ_begin(&B), E = succ_end(&B); I != E; ++I)
1949 addSuccessorLabel((*I)->getName().str(), "");
1950}
1951
1954
1956 StringRef Name, StringRef Prefix, StringRef PassID, StringRef Divider,
1957 bool InModule, unsigned Minor, const FuncDataT<DCData> &Before,
1958 const FuncDataT<DCData> &After) {
1959 assert(HTML && "Expected outstream to be set");
1960 SmallString<8> Extender;
1962 // Handle numbering and file names.
1963 if (InModule) {
1964 Extender = formatv("{0}_{1}", N, Minor);
1965 Number = formatv("{0}.{1}", N, Minor);
1966 } else {
1967 Extender = formatv("{0}", N);
1968 Number = formatv("{0}", N);
1969 }
1970 // Create a temporary file name for the dot file.
1972 sys::fs::createUniquePath("cfgdot-%%%%%%.dot", SV, true);
1973 std::string DotFile = Twine(SV).str();
1974
1975 SmallString<20> PDFFileName = formatv("diff_{0}.pdf", Extender);
1977
1978 Text = formatv("{0}.{1}{2}{3}{4}", Number, Prefix, makeHTMLReady(PassID),
1979 Divider, Name);
1980
1981 DotCfgDiff Diff(Text, Before, After);
1982 std::string EntryBlockName = After.getEntryBlockName();
1983 // Use the before entry block if the after entry block was removed.
1984 if (EntryBlockName == "")
1985 EntryBlockName = Before.getEntryBlockName();
1986 assert(EntryBlockName != "" && "Expected to find entry block");
1987
1988 DotCfgDiffDisplayGraph DG = Diff.createDisplayGraph(Text, EntryBlockName);
1989 DG.generateDotFile(DotFile);
1990
1991 *HTML << genHTML(Text, DotFile, PDFFileName);
1992 std::error_code EC = sys::fs::remove(DotFile);
1993 if (EC)
1994 errs() << "Error: " << EC.message() << "\n";
1995}
1996
1998 StringRef PDFFileName) {
1999 SmallString<20> PDFFile = formatv("{0}/{1}", DotCfgDir, PDFFileName);
2000 // Create the PDF file.
2002 if (!DotExe)
2003 return "Unable to find dot executable.";
2004
2005 StringRef Args[] = {DotBinary, "-Tpdf", "-o", PDFFile, DotFile};
2006 int Result = sys::ExecuteAndWait(*DotExe, Args, std::nullopt);
2007 if (Result < 0)
2008 return "Error executing system dot.";
2009
2010 // Create the HTML tag refering to the PDF file.
2012 " <a href=\"{0}\" target=\"_blank\">{1}</a><br/>\n", PDFFileName, Text);
2013 return S.c_str();
2014}
2015
2017 assert(HTML && "Expected outstream to be set");
2018 *HTML << "<button type=\"button\" class=\"collapsible\">0. "
2019 << "Initial IR (by function)</button>\n"
2020 << "<div class=\"content\">\n"
2021 << " <p>\n";
2022 // Create representation of IR
2025 // Now compare it against itself, which will have everything the
2026 // same and will generate the files.
2028 .compare(getModuleForComparison(IR),
2029 [&](bool InModule, unsigned Minor,
2030 const FuncDataT<DCData> &Before,
2031 const FuncDataT<DCData> &After) -> void {
2032 handleFunctionCompare("", " ", "Initial IR", "", InModule,
2033 Minor, Before, After);
2034 });
2035 *HTML << " </p>\n"
2036 << "</div><br/>\n";
2037 ++N;
2038}
2039
2043}
2044
2046 assert(HTML && "Expected outstream to be set");
2047 SmallString<20> Banner =
2048 formatv(" <a>{0}. Pass {1} on {2} omitted because no change</a><br/>\n",
2049 N, makeHTMLReady(PassID), Name);
2050 *HTML << Banner;
2051 ++N;
2052}
2053
2055 const IRDataT<DCData> &Before,
2056 const IRDataT<DCData> &After, Any IR) {
2057 assert(HTML && "Expected outstream to be set");
2058 IRComparer<DCData>(Before, After)
2059 .compare(getModuleForComparison(IR),
2060 [&](bool InModule, unsigned Minor,
2061 const FuncDataT<DCData> &Before,
2062 const FuncDataT<DCData> &After) -> void {
2063 handleFunctionCompare(Name, " Pass ", PassID, " on ", InModule,
2064 Minor, Before, After);
2065 });
2066 *HTML << " </p></div>\n";
2067 ++N;
2068}
2069
2071 assert(HTML && "Expected outstream to be set");
2072 SmallString<20> Banner =
2073 formatv(" <a>{0}. {1} invalidated</a><br/>\n", N, makeHTMLReady(PassID));
2074 *HTML << Banner;
2075 ++N;
2076}
2077
2079 assert(HTML && "Expected outstream to be set");
2080 SmallString<20> Banner =
2081 formatv(" <a>{0}. Pass {1} on {2} filtered out</a><br/>\n", N,
2082 makeHTMLReady(PassID), Name);
2083 *HTML << Banner;
2084 ++N;
2085}
2086
2088 assert(HTML && "Expected outstream to be set");
2089 SmallString<20> Banner = formatv(" <a>{0}. {1} on {2} ignored</a><br/>\n", N,
2090 makeHTMLReady(PassID), Name);
2091 *HTML << Banner;
2092 ++N;
2093}
2094
2096 std::error_code EC;
2097 HTML = std::make_unique<raw_fd_ostream>(DotCfgDir + "/passes.html", EC);
2098 if (EC) {
2099 HTML = nullptr;
2100 return false;
2101 }
2102
2103 *HTML << "<!doctype html>"
2104 << "<html>"
2105 << "<head>"
2106 << "<style>.collapsible { "
2107 << "background-color: #777;"
2108 << " color: white;"
2109 << " cursor: pointer;"
2110 << " padding: 18px;"
2111 << " width: 100%;"
2112 << " border: none;"
2113 << " text-align: left;"
2114 << " outline: none;"
2115 << " font-size: 15px;"
2116 << "} .active, .collapsible:hover {"
2117 << " background-color: #555;"
2118 << "} .content {"
2119 << " padding: 0 18px;"
2120 << " display: none;"
2121 << " overflow: hidden;"
2122 << " background-color: #f1f1f1;"
2123 << "}"
2124 << "</style>"
2125 << "<title>passes.html</title>"
2126 << "</head>\n"
2127 << "<body>";
2128 return true;
2129}
2130
2132 if (!HTML)
2133 return;
2134 *HTML
2135 << "<script>var coll = document.getElementsByClassName(\"collapsible\");"
2136 << "var i;"
2137 << "for (i = 0; i < coll.length; i++) {"
2138 << "coll[i].addEventListener(\"click\", function() {"
2139 << " this.classList.toggle(\"active\");"
2140 << " var content = this.nextElementSibling;"
2141 << " if (content.style.display === \"block\"){"
2142 << " content.style.display = \"none\";"
2143 << " }"
2144 << " else {"
2145 << " content.style.display= \"block\";"
2146 << " }"
2147 << " });"
2148 << " }"
2149 << "</script>"
2150 << "</body>"
2151 << "</html>\n";
2152 HTML->flush();
2153 HTML->close();
2154}
2155
2160 SmallString<128> OutputDir;
2161 sys::fs::expand_tilde(DotCfgDir, OutputDir);
2162 sys::fs::make_absolute(OutputDir);
2163 assert(!OutputDir.empty() && "expected output dir to be non-empty");
2164 DotCfgDir = OutputDir.c_str();
2165 if (initializeHTML()) {
2167 return;
2168 }
2169 dbgs() << "Unable to open output stream for -cfg-dot-changed\n";
2170 }
2171}
2172
2174 LLVMContext &Context, bool DebugLogging, bool VerifyEach,
2175 PrintPassOptions PrintPassOpts)
2176 : PrintPass(DebugLogging, PrintPassOpts),
2177 OptNone(DebugLogging),
2179 PrintChangedIR(PrintChanged == ChangePrinter::Verbose),
2180 PrintChangedDiff(PrintChanged == ChangePrinter::DiffVerbose ||
2184 WebsiteChangeReporter(PrintChanged == ChangePrinter::DotCfgVerbose),
2185 Verify(DebugLogging), VerifyEach(VerifyEach) {}
2186
2187PrintCrashIRInstrumentation *PrintCrashIRInstrumentation::CrashReporter =
2188 nullptr;
2189
2191
2192void PrintCrashIRInstrumentation::SignalHandler(void *) {
2193 // Called by signal handlers so do not lock here
2194 // Is the PrintCrashIRInstrumentation still alive?
2195 if (!CrashReporter)
2196 return;
2197
2198 assert(PrintCrashIR && "Did not expect to get here without option set.");
2199 CrashReporter->reportCrashIR();
2200}
2201
2203 if (!CrashReporter)
2204 return;
2205
2206 assert(PrintCrashIR && "Did not expect to get here without option set.");
2207 CrashReporter = nullptr;
2208}
2209
2212 if (!PrintCrashIR || CrashReporter)
2213 return;
2214
2215 sys::AddSignalHandler(SignalHandler, nullptr);
2216 CrashReporter = this;
2217
2219 Any IR) {
2220 SavedIR.clear();
2222 OS << formatv("*** Dump of {0}IR Before Last Pass {1}",
2223 llvm::forcePrintModuleIR() ? "Module " : "", PassID);
2224 if (!isInteresting(IR, PassID, PIC.getPassNameForClassName(PassID))) {
2225 OS << " Filtered Out ***\n";
2226 return;
2227 }
2228 OS << " Started ***\n";
2229 unwrapAndPrint(OS, IR);
2230 });
2231}
2232
2235 PrintIR.registerCallbacks(PIC);
2236 PrintPass.registerCallbacks(PIC);
2237 TimePasses.registerCallbacks(PIC);
2238 OptNone.registerCallbacks(PIC);
2239 OptPassGate.registerCallbacks(PIC);
2240 PrintChangedIR.registerCallbacks(PIC);
2241 PseudoProbeVerification.registerCallbacks(PIC);
2242 if (VerifyEach)
2243 Verify.registerCallbacks(PIC);
2244 PrintChangedDiff.registerCallbacks(PIC);
2245 WebsiteChangeReporter.registerCallbacks(PIC);
2246 ChangeTester.registerCallbacks(PIC);
2247 PrintCrashIR.registerCallbacks(PIC);
2248 if (MAM)
2249 PreservedCFGChecker.registerCallbacks(PIC, *MAM);
2250
2251 // TimeProfiling records the pass running time cost.
2252 // Its 'BeforePassCallback' can be appended at the tail of all the
2253 // BeforeCallbacks by calling `registerCallbacks` in the end.
2254 // Its 'AfterPassCallback' is put at the front of all the
2255 // AfterCallbacks by its `registerCallbacks`. This is necessary
2256 // to ensure that other callbacks are not included in the timings.
2257 TimeProfilingPasses.registerCallbacks(PIC);
2258}
2259
2260template class ChangeReporter<std::string>;
2261template class TextChangeReporter<std::string>;
2262
2263template class BlockDataT<EmptyData>;
2264template class FuncDataT<EmptyData>;
2265template class IRDataT<EmptyData>;
2266template class ChangeReporter<IRDataT<EmptyData>>;
2268template class IRComparer<EmptyData>;
2269
2270} // namespace llvm
arc branch finalize
This file provides Any, a non-template class modeled in the spirit of std::any.
BlockVerifier::State From
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
T Content
std::string Name
std::optional< std::vector< StOtherPiece > > Other
Definition: ELFYAML.cpp:1260
static bool isInteresting(const SCEV *S, const Instruction *I, const Loop *L, ScalarEvolution *SE, LoopInfo *LI)
isInteresting - Test whether the given expression is "interesting" when used by the given expression,...
Definition: IVUsers.cpp:56
static void addEdge(SmallVectorImpl< LazyCallGraph::Edge > &Edges, DenseMap< LazyCallGraph::Node *, int > &EdgeIndexMap, LazyCallGraph::Node &N, LazyCallGraph::Edge::Kind EK)
Implements a lazy call graph analysis and related passes for the new pass manager.
Statically lint checks LLVM IR
Definition: Lint.cpp:746
#define F(x, y, z)
Definition: MD5.cpp:55
#define I(x, y, z)
Definition: MD5.cpp:58
#define G(x, y, z)
Definition: MD5.cpp:56
static std::string getNodeLabel(const ValueInfo &VI, GlobalValueSummary *GVS)
Module.h This file contains the declarations for the Module class.
LLVMContext & Context
return ToRemove size() > 0
#define P(N)
ppc ctr loops PowerPC CTR Loops Verify
FunctionAnalysisManager FAM
ModuleAnalysisManager MAM
bool VerifyEach
PassInstrumentationCallbacks PIC
This file defines the Pass Instrumentation classes that provide instrumentation points into the pass ...
This header defines various interfaces for pass management in LLVM.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
raw_pwrite_stream & OS
static cl::opt< std::string > BeforeColour("dot-cfg-before-color", cl::desc("Color for dot-cfg before elements"), cl::Hidden, cl::init("red"))
static cl::opt< std::string > OptBisectPrintIRPath("opt-bisect-print-ir-path", cl::desc("Print IR to path when opt-bisect-limit is reached"), cl::Hidden)
static cl::opt< bool > PrintChangedBefore("print-before-changed", cl::desc("Print before passes that change them"), cl::init(false), cl::Hidden)
static cl::opt< std::string > DotCfgDir("dot-cfg-dir", cl::desc("Generate dot files into specified directory for changed IRs"), cl::Hidden, cl::init("./"))
static cl::opt< bool > VerifyAnalysisInvalidation("verify-analysis-invalidation", cl::Hidden, cl::init(false))
static cl::opt< std::string > CommonColour("dot-cfg-common-color", cl::desc("Color for dot-cfg common elements"), cl::Hidden, cl::init("black"))
static SmallVector< Function *, 1 > GetFunctions(Any IR)
static void printBBName(raw_ostream &out, const BasicBlock *BB)
static cl::opt< std::string > DotBinary("print-changed-dot-path", cl::Hidden, cl::init("dot"), cl::desc("system dot used by change reporters"))
static cl::opt< std::string > AfterColour("dot-cfg-after-color", cl::desc("Color for dot-cfg after elements"), cl::Hidden, cl::init("forestgreen"))
static cl::opt< bool > PrintCrashIR("print-on-crash", cl::desc("Print the last form of the IR before crash"), cl::Hidden)
This header defines a class that provides bookkeeping for all standard (i.e in-tree) pass instrumenta...
@ Text
Definition: TextStubV5.cpp:112
static const char PassName[]
This templated class represents "all analyses that operate over <a particular IR unit>" (e....
Definition: PassManager.h:90
API to communicate dependencies between analyses during invalidation.
Definition: PassManager.h:661
A container for analyses that lazily runs them and caches their results.
Definition: PassManager.h:620
PassT::Result * getCachedResult(IRUnitT &IR) const
Get the cached result of an analysis pass for a given IR unit.
Definition: PassManager.h:793
bool registerPass(PassBuilderT &&PassBuilder)
Register an analysis pass with the manager.
Definition: PassManager.h:836
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Definition: PassManager.h:774
Definition: Any.h:28
LLVM Basic Block Representation.
Definition: BasicBlock.h:56
bool isEntryBlock() const
Return true if this is the entry block of the containing function.
Definition: BasicBlock.cpp:395
const Function * getParent() const
Return the enclosing method, or null if none.
Definition: BasicBlock.h:112
const T & getData() const
Conditional or Unconditional Branch instruction.
Represents analyses that only rely on functions' control flow.
Definition: PassManager.h:113
void saveIRBeforePass(Any IR, StringRef PassID, StringRef PassName)
void handleIRAfterPass(Any IR, StringRef PassID, StringRef PassName)
void registerRequiredCallbacks(PassInstrumentationCallbacks &PIC)
void handleInvalidatedPass(StringRef PassID)
void addSuccessorLabel(StringRef Succ, StringRef Label)
DCData(const BasicBlock &B)
std::unique_ptr< raw_fd_ostream > HTML
void handleInvalidated(StringRef PassID) override
void generateIRRepresentation(Any IR, StringRef PassID, IRDataT< DCData > &Output) override
static std::string genHTML(StringRef Text, StringRef DotFile, StringRef PDFFileName)
void handleFunctionCompare(StringRef Name, StringRef Prefix, StringRef PassID, StringRef Divider, bool InModule, unsigned Minor, const FuncDataT< DCData > &Before, const FuncDataT< DCData > &After)
void registerCallbacks(PassInstrumentationCallbacks &PIC)
void handleIgnored(StringRef PassID, std::string &Name) override
void handleAfter(StringRef PassID, std::string &Name, const IRDataT< DCData > &Before, const IRDataT< DCData > &After, Any) override
void handleFiltered(StringRef PassID, std::string &Name) override
void omitAfter(StringRef PassID, std::string &Name) override
Represents either an error or a value T.
Definition: ErrorOr.h:56
Lightweight error class with error context and mandatory checking.
Definition: Error.h:156
std::string getEntryBlockName() const
~IRChangedPrinter() override
void handleAfter(StringRef PassID, std::string &Name, const std::string &Before, const std::string &After, Any) override
void registerCallbacks(PassInstrumentationCallbacks &PIC)
void generateIRRepresentation(Any IR, StringRef PassID, std::string &Output) override
void handleIgnored(StringRef PassID, std::string &Name) override
void handleAfter(StringRef PassID, std::string &Name, const std::string &Before, const std::string &After, Any) override
void omitAfter(StringRef PassID, std::string &Name) override
void handleInvalidated(StringRef PassID) override
void handleIR(const std::string &IR, StringRef PassID)
void handleInitialIR(Any IR) override
void registerCallbacks(PassInstrumentationCallbacks &PIC)
void handleFiltered(StringRef PassID, std::string &Name) override
static void analyzeIR(Any IR, IRDataT< T > &Data)
void compare(bool CompareModule, std::function< void(bool InModule, unsigned Minor, const FuncDataT< T > &Before, const FuncDataT< T > &After)> CompareFunc)
static bool generateFunctionData(IRDataT< T > &Data, const Function &F)
void registerCallbacks(PassInstrumentationCallbacks &PIC)
void handleAfter(StringRef PassID, std::string &Name, const IRDataT< EmptyData > &Before, const IRDataT< EmptyData > &After, Any) override
void generateIRRepresentation(Any IR, StringRef PassID, IRDataT< EmptyData > &Output) override
void handleFunctionCompare(StringRef Name, StringRef Prefix, StringRef PassID, StringRef Divider, bool InModule, unsigned Minor, const FuncDataT< EmptyData > &Before, const FuncDataT< EmptyData > &After)
An analysis over an "outer" IR unit that provides access to an analysis manager over an "inner" IR un...
Definition: PassManager.h:933
This is an important class for using LLVM in a threaded context.
Definition: LLVMContext.h:67
OptPassGate & getOptPassGate() const
Access the object which can disable optional passes and individual optimizations at compile time.
A node in the call graph.
An SCC of the call graph.
Represents a single loop in the control flow graph.
Definition: LoopInfo.h:547
A Module instance is used to store all the information related to an LLVM module.
Definition: Module.h:65
void registerCallbacks(PassInstrumentationCallbacks &PIC)
void registerCallbacks(PassInstrumentationCallbacks &PIC)
bool shouldRun(StringRef PassName, Any IR)
Extensions to this class implement mechanisms to disable passes and individual optimizations at compi...
Definition: OptBisect.h:26
virtual bool isEnabled() const
isEnabled() should return true before calling shouldRunPass().
Definition: OptBisect.h:38
virtual bool shouldRunPass(const StringRef PassName, StringRef IRDescription)
IRDescription is a textual description of the IR unit the pass is running over.
Definition: OptBisect.h:32
static void report(const OrderedChangedData &Before, const OrderedChangedData &After, function_ref< void(const T *, const T *)> HandlePair)
std::vector< std::string > & getOrder()
This class manages callbacks registration, as well as provides a way for PassInstrumentation to pass ...
void registerAfterPassInvalidatedCallback(CallableT C, bool ToFront=false)
void registerAnalysisInvalidatedCallback(CallableT C)
StringRef getPassNameForClassName(StringRef ClassName)
Get the pass name for a given pass class name.
void registerAfterAnalysisCallback(CallableT C, bool ToFront=false)
void registerBeforeNonSkippedPassCallback(CallableT C)
void registerBeforeSkippedPassCallback(CallableT C)
void registerShouldRunOptionalPassCallback(CallableT C)
void registerAfterPassCallback(CallableT C, bool ToFront=false)
Pass interface - Implemented by all 'passes'.
Definition: Pass.h:91
A set of analyses that are preserved following a run of a transformation pass.
Definition: PassManager.h:152
PreservedAnalysisChecker getChecker() const
Build a checker for this PreservedAnalyses and the specified analysis type.
Definition: PassManager.h:310
void registerCallbacks(PassInstrumentationCallbacks &PIC, ModuleAnalysisManager &MAM)
void registerCallbacks(PassInstrumentationCallbacks &PIC)
void registerCallbacks(PassInstrumentationCallbacks &PIC)
void registerCallbacks(PassInstrumentationCallbacks &PIC)
void registerCallbacks(PassInstrumentationCallbacks &PIC)
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Definition: SmallString.h:26
const char * c_str()
Definition: SmallString.h:264
bool empty() const
Definition: SmallVector.h:94
reference emplace_back(ArgTypes &&... Args)
Definition: SmallVector.h:941
void push_back(const T &Elt)
Definition: SmallVector.h:416
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1200
void registerCallbacks(PassInstrumentationCallbacks &PIC, ModuleAnalysisManager *MAM=nullptr)
StandardInstrumentations(LLVMContext &Context, bool DebugLogging, bool VerifyEach=false, PrintPassOptions PrintPassOpts=PrintPassOptions())
unsigned size() const
Definition: StringMap.h:95
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
Definition: StringMap.h:111
iterator begin()
Definition: StringMap.h:203
size_type count(StringRef Key) const
count - Return 1 if the element is in the map, 0 otherwise.
Definition: StringMap.h:256
bool insert(MapEntryTy *KeyValue)
insert - Insert the specified key/value pair into the map.
Definition: StringMap.h:286
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
std::string str() const
str - Get the contents as an std::string.
Definition: StringRef.h:222
StringRef drop_front(size_t N=1) const
Return a StringRef equal to 'this' but with the first N elements dropped.
Definition: StringRef.h:596
StringRef drop_until(function_ref< bool(char)> F) const
Return a StringRef equal to 'this', but with all characters not satisfying the given predicate droppe...
Definition: StringRef.h:616
constexpr size_t size() const
size - Get the string size.
Definition: StringRef.h:137
char front() const
front - Get the first character in the string.
Definition: StringRef.h:140
StringRef take_until(function_ref< bool(char)> F) const
Return the longest prefix of 'this' such that no character in the prefix satisfies the given predicat...
Definition: StringRef.h:590
std::pair< StringRef, StringRef > rsplit(StringRef Separator) const
Split into two substrings around the last occurrence of a separator string.
Definition: StringRef.h:720
Multiway switch.
void handleInitialIR(Any IR) override
void handleInvalidated(StringRef PassID) override
void omitAfter(StringRef PassID, std::string &Name) override
void handleIgnored(StringRef PassID, std::string &Name) override
void handleFiltered(StringRef PassID, std::string &Name) override
void registerCallbacks(PassInstrumentationCallbacks &PIC)
void registerCallbacks(PassInstrumentationCallbacks &PIC)
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:81
std::string str() const
Return the twine contents as a std::string.
Definition: Twine.cpp:17
LLVM Value Representation.
Definition: Value.h:74
bool hasName() const
Definition: Value.h:261
StringRef getName() const
Return a constant reference to the value's name.
Definition: Value.cpp:308
void registerCallbacks(PassInstrumentationCallbacks &PIC)
An efficient, type-erasing, non-owning reference to a callable.
A raw_ostream that writes to a file descriptor.
Definition: raw_ostream.h:454
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:52
raw_ostream & indent(unsigned NumSpaces)
indent - Insert 'NumSpaces' spaces.
A raw_ostream that writes to an std::string.
Definition: raw_ostream.h:642
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Key
PAL metadata keys.
@ C
The default llvm calling convention, compatible with C.
Definition: CallingConv.h:34
initializer< Ty > init(const Ty &Val)
Definition: CommandLine.h:445
DiagnosticInfoOptimizationBase::Argument NV
void make_absolute(const Twine &current_directory, SmallVectorImpl< char > &path)
Make path an absolute path.
Definition: Path.cpp:906
void expand_tilde(const Twine &path, SmallVectorImpl< char > &output)
Expands ~ expressions to the user's home directory.
std::error_code remove(const Twine &path, bool IgnoreNonExisting=true)
Remove path.
void createUniquePath(const Twine &Model, SmallVectorImpl< char > &ResultPath, bool MakeAbsolute)
Create a potentially unique file name but does not create it.
Definition: Path.cpp:796
void AddSignalHandler(SignalHandlerCallback FnPtr, void *Cookie)
Add a function to be called when an abort/kill signal is delivered to the process.
int ExecuteAndWait(StringRef Program, ArrayRef< StringRef > Args, std::optional< ArrayRef< StringRef > > Env=std::nullopt, ArrayRef< std::optional< StringRef > > Redirects={}, unsigned SecondsToWait=0, unsigned MemoryLimit=0, std::string *ErrMsg=nullptr, bool *ExecutionFailed=nullptr, std::optional< ProcessStatistics > *ProcStat=nullptr, BitVector *AffinityMask=nullptr)
This function executes the program using the arguments provided.
Definition: Program.cpp:32
ErrorOr< std::string > findProgramByName(StringRef Name, ArrayRef< StringRef > Paths={})
Find the first executable file Name in Paths.
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
Interval::succ_iterator succ_end(Interval *I)
Definition: Interval.h:102
auto formatv(const char *Fmt, Ts &&... Vals) -> formatv_object< decltype(std::make_tuple(detail::build_format_adapter(std::forward< Ts >(Vals))...))>
ChangePrinter
Definition: PrintPasses.h:18
std::error_code prepareTempFiles(SmallVector< int > &FD, ArrayRef< StringRef > SR, SmallVector< std::string > &FileName)
bool forcePrintModuleIR()
std::vector< std::string > printAfterPasses()
bool verifyFunction(const Function &F, raw_ostream *OS=nullptr)
Check a function for errors, useful for use when debugging a pass.
Definition: Verifier.cpp:6465
auto successors(const MachineBasicBlock *BB)
bool DisplayGraph(StringRef Filename, bool wait=true, GraphProgram::Name program=GraphProgram::DOT)
Interval::succ_iterator succ_begin(Interval *I)
succ_begin/succ_end - define methods so that Intervals may be used just like BasicBlocks can with the...
Definition: Interval.h:99
bool shouldPrintBeforeAll()
raw_ostream & WriteGraph(raw_ostream &O, const GraphType &G, bool ShortNames=false, const Twine &Title="")
Definition: GraphWriter.h:359
bool shouldPrintAfterAll()
cl::opt< ChangePrinter > PrintChanged
TimeTraceProfiler * getTimeTraceProfilerInstance()
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1789
std::vector< std::string > printBeforePasses()
bool shouldPrintBeforeSomePass()
This is a helper to determine whether to print IR before or after a pass.
bool shouldPrintAfterSomePass()
void timeTraceProfilerBegin(StringRef Name, StringRef Detail)
Manually begin a time section, with the given Name and Detail.
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
bool isFunctionInPrintList(StringRef FunctionName)
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
Definition: Error.cpp:145
bool isPassInPrintList(StringRef PassName)
bool isSpecialPass(StringRef PassID, const std::vector< StringRef > &Specials)
void timeTraceProfilerEnd()
Manually end the last time section.
std::error_code cleanUpTempFiles(ArrayRef< std::string > FileName)
raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
std::string doSystemDiff(StringRef Before, StringRef After, StringRef OldLineFormat, StringRef NewLineFormat, StringRef UnchangedLineFormat)
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition: STLExtras.h:1939
Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
Definition: Error.cpp:92
std::array< uint32_t, 5 > ModuleHash
160 bits SHA1
void printLoop(Loop &L, raw_ostream &OS, const std::string &Banner="")
Function to print a loop's contents as LLVM's text IR assembly.
Definition: LoopInfo.cpp:977
uint64_t StructuralHash(const Function &F)
bool verifyModule(const Module &M, raw_ostream *OS=nullptr, bool *BrokenDebugInfo=nullptr)
Check a module for errors.
Definition: Verifier.cpp:6476
#define N
Result run(Function &F, FunctionAnalysisManager &FAM)
Run the analysis pass over a function and produce CFG.
Result run(Function &F, FunctionAnalysisManager &FAM)
Result run(Module &F, ModuleAnalysisManager &FAM)
A CRTP mix-in that provides informational APIs needed for analysis passes.
Definition: PassManager.h:394
A special type used by analysis passes to provide an address that identifies that particular analysis...
Definition: PassManager.h:69
static std::string getEdgeAttributes(const DisplayNode *From, DisplayNode::ChildIterator &To, const DotCfgDiffDisplayGraph *DiffData)
static std::string getGraphName(const DotCfgDiffDisplayGraph *DiffData)
static std::string getEdgeSourceLabel(const DisplayNode *From, DisplayNode::ChildIterator &To)
static std::string getNodeAttributes(const DisplayNode *Node, const DotCfgDiffDisplayGraph *DiffData)
static std::string getNodeLabel(const DisplayNode *Node, const DotCfgDiffDisplayGraph *DiffData)
static std::string getGraphProperties(const DotCfgDiffDisplayGraph *DiffData)
DOTGraphTraits - Template class that can be specialized to customize how graphs are converted to 'dot...
DefaultDOTGraphTraits - This class provides the default implementations of all of the DOTGraphTraits ...
static unsigned size(const DotCfgDiffDisplayGraph *G)
static NodeRef getEntryNode(const DotCfgDiffDisplayGraph *G)
DotCfgDiffDisplayGraph::NodeIterator nodes_iterator
static nodes_iterator nodes_begin(const DotCfgDiffDisplayGraph *G)
static ChildEdgeIterator child_edge_begin(NodeRef N)
static nodes_iterator nodes_end(const DotCfgDiffDisplayGraph *G)
std::optional< DenseMap< intptr_t, BBGuard > > BBGuards
static void printDiff(raw_ostream &out, const CFG &Before, const CFG &After)
CFG(const Function *F, bool TrackBBLifetime)
bool invalidate(Function &F, const PreservedAnalyses &PA, FunctionAnalysisManager::Invalidator &)
DenseMap< const BasicBlock *, DenseMap< const BasicBlock *, unsigned > > Graph
bool SkipAnalyses
Don't print information for analyses.
bool Verbose
Print adaptors and pass managers.
bool Indent
Indent based on hierarchy.