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// Options to print the IR that was being processed when a pass crashes.
101 "print-on-crash-path",
102 cl::desc("Print the last form of the IR before crash to a file"),
103 cl::Hidden);
104
106 "print-on-crash",
107 cl::desc("Print the last form of the IR before crash (use -print-on-crash-path to dump to a file)"),
108 cl::Hidden);
109
111 "opt-bisect-print-ir-path",
112 cl::desc("Print IR to path when opt-bisect-limit is reached"), cl::Hidden);
113
115 "print-pass-numbers", cl::init(false), cl::Hidden,
116 cl::desc("Print pass names and their ordinals"));
117
119 PrintAtPassNumber("print-at-pass-number", cl::init(0), cl::Hidden,
120 cl::desc("Print IR at pass with this number as "
121 "reported by print-passes-names"));
122
123namespace {
124
125// An option for specifying an executable that will be called with the IR
126// everytime it changes in the opt pipeline. It will also be called on
127// the initial IR as it enters the pipeline. The executable will be passed
128// the name of a temporary file containing the IR and the PassID. This may
129// be used, for example, to call llc on the IR and run a test to determine
130// which pass makes a change that changes the functioning of the IR.
131// The usual modifier options work as expected.
133 TestChanged("exec-on-ir-change", cl::Hidden, cl::init(""),
134 cl::desc("exe called with module IR after each pass that "
135 "changes it"));
136
137/// Extract Module out of \p IR unit. May return nullptr if \p IR does not match
138/// certain global filters. Will never return nullptr if \p Force is true.
139const Module *unwrapModule(Any IR, bool Force = false) {
140 if (const auto **M = any_cast<const Module *>(&IR))
141 return *M;
142
143 if (const auto **F = any_cast<const Function *>(&IR)) {
144 if (!Force && !isFunctionInPrintList((*F)->getName()))
145 return nullptr;
146
147 return (*F)->getParent();
148 }
149
150 if (const auto **C = any_cast<const LazyCallGraph::SCC *>(&IR)) {
151 for (const LazyCallGraph::Node &N : **C) {
152 const Function &F = N.getFunction();
153 if (Force || (!F.isDeclaration() && isFunctionInPrintList(F.getName()))) {
154 return F.getParent();
155 }
156 }
157 assert(!Force && "Expected a module");
158 return nullptr;
159 }
160
161 if (const auto **L = any_cast<const Loop *>(&IR)) {
162 const Function *F = (*L)->getHeader()->getParent();
163 if (!Force && !isFunctionInPrintList(F->getName()))
164 return nullptr;
165 return F->getParent();
166 }
167
168 llvm_unreachable("Unknown IR unit");
169}
170
171void printIR(raw_ostream &OS, const Function *F) {
172 if (!isFunctionInPrintList(F->getName()))
173 return;
174 OS << *F;
175}
176
177void printIR(raw_ostream &OS, const Module *M) {
179 M->print(OS, nullptr);
180 } else {
181 for (const auto &F : M->functions()) {
182 printIR(OS, &F);
183 }
185}
186
187void printIR(raw_ostream &OS, const LazyCallGraph::SCC *C) {
188 for (const LazyCallGraph::Node &N : *C) {
189 const Function &F = N.getFunction();
190 if (!F.isDeclaration() && isFunctionInPrintList(F.getName())) {
191 F.print(OS);
193 }
194}
195
196void printIR(raw_ostream &OS, const Loop *L) {
197 const Function *F = L->getHeader()->getParent();
198 if (!isFunctionInPrintList(F->getName()))
199 return;
200 printLoop(const_cast<Loop &>(*L), OS);
201}
202
203std::string getIRName(Any IR) {
204 if (any_cast<const Module *>(&IR))
205 return "[module]";
206
207 if (const auto **F = any_cast<const Function *>(&IR))
208 return (*F)->getName().str();
209
210 if (const auto **C = any_cast<const LazyCallGraph::SCC *>(&IR))
211 return (*C)->getName();
212
213 if (const auto **L = any_cast<const Loop *>(&IR))
214 return (*L)->getName().str();
215
216 llvm_unreachable("Unknown wrapped IR type");
217}
218
219bool moduleContainsFilterPrintFunc(const Module &M) {
220 return any_of(M.functions(),
221 [](const Function &F) {
222 return isFunctionInPrintList(F.getName());
223 }) ||
225}
226
227bool sccContainsFilterPrintFunc(const LazyCallGraph::SCC &C) {
228 return any_of(C,
229 [](const LazyCallGraph::Node &N) {
230 return isFunctionInPrintList(N.getName());
231 }) ||
234
235bool shouldPrintIR(Any IR) {
236 if (const auto **M = any_cast<const Module *>(&IR))
237 return moduleContainsFilterPrintFunc(**M);
238
239 if (const auto **F = any_cast<const Function *>(&IR))
240 return isFunctionInPrintList((*F)->getName());
242 if (const auto **C = any_cast<const LazyCallGraph::SCC *>(&IR))
243 return sccContainsFilterPrintFunc(**C);
244
245 if (const auto **L = any_cast<const Loop *>(&IR))
246 return isFunctionInPrintList((*L)->getHeader()->getParent()->getName());
247 llvm_unreachable("Unknown wrapped IR type");
248}
249
250/// Generic IR-printing helper that unpacks a pointer to IRUnit wrapped into
251/// Any and does actual print job.
252void unwrapAndPrint(raw_ostream &OS, Any IR) {
253 if (!shouldPrintIR(IR))
254 return;
255
256 if (forcePrintModuleIR()) {
257 auto *M = unwrapModule(IR);
258 assert(M && "should have unwrapped module");
259 printIR(OS, M);
260 return;
261 }
262
263 if (const auto **M = any_cast<const Module *>(&IR)) {
264 printIR(OS, *M);
265 return;
266 }
267
268 if (const auto **F = any_cast<const Function *>(&IR)) {
269 printIR(OS, *F);
270 return;
271 }
272
273 if (const auto **C = any_cast<const LazyCallGraph::SCC *>(&IR)) {
274 printIR(OS, *C);
275 return;
276 }
277
278 if (const auto **L = any_cast<const Loop *>(&IR)) {
279 printIR(OS, *L);
280 return;
281 }
282 llvm_unreachable("Unknown wrapped IR type");
283}
284
285// Return true when this is a pass for which changes should be ignored
286bool isIgnored(StringRef PassID) {
287 return isSpecialPass(PassID,
288 {"PassManager", "PassAdaptor", "AnalysisManagerProxy",
289 "DevirtSCCRepeatedPass", "ModuleInlinerWrapperPass"});
290}
291
292std::string makeHTMLReady(StringRef SR) {
293 std::string S;
294 while (true) {
295 StringRef Clean =
296 SR.take_until([](char C) { return C == '<' || C == '>'; });
297 S.append(Clean.str());
298 SR = SR.drop_front(Clean.size());
299 if (SR.size() == 0)
300 return S;
301 S.append(SR[0] == '<' ? "&lt;" : "&gt;");
302 SR = SR.drop_front();
303 }
304 llvm_unreachable("problems converting string to HTML");
305}
306
307// Return the module when that is the appropriate level of comparison for \p IR.
308const Module *getModuleForComparison(Any IR) {
309 if (const auto **M = any_cast<const Module *>(&IR))
310 return *M;
311 if (const auto **C = any_cast<const LazyCallGraph::SCC *>(&IR))
312 return (*C)
313 ->begin()
314 ->getFunction()
315 .getParent();
316 return nullptr;
317}
318
319bool isInterestingFunction(const Function &F) {
320 return isFunctionInPrintList(F.getName());
321}
322
323// Return true when this is a pass on IR for which printing
324// of changes is desired.
326 if (isIgnored(PassID) || !isPassInPrintList(PassName))
327 return false;
328 if (const auto **F = any_cast<const Function *>(&IR))
329 return isInterestingFunction(**F);
330 return true;
331}
332
333} // namespace
334
335template <typename T> ChangeReporter<T>::~ChangeReporter() {
336 assert(BeforeStack.empty() && "Problem with Change Printer stack.");
337}
338
339template <typename T>
342 // Is this the initial IR?
343 if (InitialIR) {
344 InitialIR = false;
345 if (VerboseMode)
346 handleInitialIR(IR);
347 }
348
349 // Always need to place something on the stack because invalidated passes
350 // are not given the IR so it cannot be determined whether the pass was for
351 // something that was filtered out.
352 BeforeStack.emplace_back();
353
354 if (!isInteresting(IR, PassID, PassName))
355 return;
356
357 // Save the IR representation on the stack.
358 T &Data = BeforeStack.back();
359 generateIRRepresentation(IR, PassID, Data);
360}
361
362template <typename T>
365 assert(!BeforeStack.empty() && "Unexpected empty stack encountered.");
366
367 std::string Name = getIRName(IR);
368
369 if (isIgnored(PassID)) {
370 if (VerboseMode)
371 handleIgnored(PassID, Name);
372 } else if (!isInteresting(IR, PassID, PassName)) {
373 if (VerboseMode)
374 handleFiltered(PassID, Name);
375 } else {
376 // Get the before rep from the stack
377 T &Before = BeforeStack.back();
378 // Create the after rep
379 T After;
380 generateIRRepresentation(IR, PassID, After);
381
382 // Was there a change in IR?
383 if (Before == After) {
384 if (VerboseMode)
385 omitAfter(PassID, Name);
386 } else
387 handleAfter(PassID, Name, Before, After, IR);
388 }
389 BeforeStack.pop_back();
390}
391
392template <typename T>
394 assert(!BeforeStack.empty() && "Unexpected empty stack encountered.");
395
396 // Always flag it as invalidated as we cannot determine when
397 // a pass for a filtered function is invalidated since we do not
398 // get the IR in the call. Also, the output is just alternate
399 // forms of the banner anyway.
400 if (VerboseMode)
401 handleInvalidated(PassID);
402 BeforeStack.pop_back();
403}
404
405template <typename T>
409 saveIRBeforePass(IR, P, PIC.getPassNameForClassName(P));
410 });
411
413 [&PIC, this](StringRef P, Any IR, const PreservedAnalyses &) {
414 handleIRAfterPass(IR, P, PIC.getPassNameForClassName(P));
415 });
417 [this](StringRef P, const PreservedAnalyses &) {
418 handleInvalidatedPass(P);
419 });
420}
421
422template <typename T>
424 : ChangeReporter<T>(Verbose), Out(dbgs()) {}
425
426template <typename T> void TextChangeReporter<T>::handleInitialIR(Any IR) {
427 // Always print the module.
428 // Unwrap and print directly to avoid filtering problems in general routines.
429 auto *M = unwrapModule(IR, /*Force=*/true);
430 assert(M && "Expected module to be unwrapped when forced.");
431 Out << "*** IR Dump At Start ***\n";
432 M->print(Out, nullptr);
433}
434
435template <typename T>
437 Out << formatv("*** IR Dump After {0} on {1} omitted because no change ***\n",
438 PassID, Name);
439}
440
441template <typename T>
443 Out << formatv("*** IR Pass {0} invalidated ***\n", PassID);
444}
445
446template <typename T>
448 std::string &Name) {
449 SmallString<20> Banner =
450 formatv("*** IR Dump After {0} on {1} filtered out ***\n", PassID, Name);
451 Out << Banner;
452}
453
454template <typename T>
456 Out << formatv("*** IR Pass {0} on {1} ignored ***\n", PassID, Name);
457}
458
460
465}
466
468 std::string &Output) {
469 raw_string_ostream OS(Output);
470 unwrapAndPrint(OS, IR);
471 OS.str();
472}
473
475 const std::string &Before,
476 const std::string &After, Any) {
477 // Report the IR before the changes when requested.
479 Out << "*** IR Dump Before " << PassID << " on " << Name << " ***\n"
480 << Before;
481
482 // We might not get anything to print if we only want to print a specific
483 // function but it gets deleted.
484 if (After.empty()) {
485 Out << "*** IR Deleted After " << PassID << " on " << Name << " ***\n";
486 return;
487 }
488
489 Out << "*** IR Dump After " << PassID << " on " << Name << " ***\n" << After;
490}
491
493
495 if (TestChanged != "")
497}
498
499void IRChangedTester::handleIR(const std::string &S, StringRef PassID) {
500 // Store the body into a temporary file
501 static SmallVector<int> FD{-1};
503 static SmallVector<std::string> FileName{""};
504 if (auto Err = prepareTempFiles(FD, SR, FileName)) {
505 dbgs() << "Unable to create temporary file.";
506 return;
507 }
508 static ErrorOr<std::string> Exe = sys::findProgramByName(TestChanged);
509 if (!Exe) {
510 dbgs() << "Unable to find test-changed executable.";
511 return;
512 }
513
514 StringRef Args[] = {TestChanged, FileName[0], PassID};
515 int Result = sys::ExecuteAndWait(*Exe, Args);
516 if (Result < 0) {
517 dbgs() << "Error executing test-changed executable.";
518 return;
519 }
520
521 if (auto Err = cleanUpTempFiles(FileName))
522 dbgs() << "Unable to remove temporary file.";
523}
524
526 // Always test the initial module.
527 // Unwrap and print directly to avoid filtering problems in general routines.
528 std::string S;
529 generateIRRepresentation(IR, "Initial IR", S);
530 handleIR(S, "Initial IR");
531}
532
533void IRChangedTester::omitAfter(StringRef PassID, std::string &Name) {}
535void IRChangedTester::handleFiltered(StringRef PassID, std::string &Name) {}
536void IRChangedTester::handleIgnored(StringRef PassID, std::string &Name) {}
538 const std::string &Before,
539 const std::string &After, Any) {
540 handleIR(After, PassID);
541}
542
543template <typename T>
545 const OrderedChangedData &Before, const OrderedChangedData &After,
546 function_ref<void(const T *, const T *)> HandlePair) {
547 const auto &BFD = Before.getData();
548 const auto &AFD = After.getData();
549 std::vector<std::string>::const_iterator BI = Before.getOrder().begin();
550 std::vector<std::string>::const_iterator BE = Before.getOrder().end();
551 std::vector<std::string>::const_iterator AI = After.getOrder().begin();
552 std::vector<std::string>::const_iterator AE = After.getOrder().end();
553
554 auto HandlePotentiallyRemovedData = [&](std::string S) {
555 // The order in LLVM may have changed so check if still exists.
556 if (!AFD.count(S)) {
557 // This has been removed.
558 HandlePair(&BFD.find(*BI)->getValue(), nullptr);
559 }
560 };
561 auto HandleNewData = [&](std::vector<const T *> &Q) {
562 // Print out any queued up new sections
563 for (const T *NBI : Q)
564 HandlePair(nullptr, NBI);
565 Q.clear();
566 };
567
568 // Print out the data in the after order, with before ones interspersed
569 // appropriately (ie, somewhere near where they were in the before list).
570 // Start at the beginning of both lists. Loop through the
571 // after list. If an element is common, then advance in the before list
572 // reporting the removed ones until the common one is reached. Report any
573 // queued up new ones and then report the common one. If an element is not
574 // common, then enqueue it for reporting. When the after list is exhausted,
575 // loop through the before list, reporting any removed ones. Finally,
576 // report the rest of the enqueued new ones.
577 std::vector<const T *> NewDataQueue;
578 while (AI != AE) {
579 if (!BFD.count(*AI)) {
580 // This section is new so place it in the queue. This will cause it
581 // to be reported after deleted sections.
582 NewDataQueue.emplace_back(&AFD.find(*AI)->getValue());
583 ++AI;
584 continue;
585 }
586 // This section is in both; advance and print out any before-only
587 // until we get to it.
588 // It's possible that this section has moved to be later than before. This
589 // will mess up printing most blocks side by side, but it's a rare case and
590 // it's better than crashing.
591 while (BI != BE && *BI != *AI) {
592 HandlePotentiallyRemovedData(*BI);
593 ++BI;
594 }
595 // Report any new sections that were queued up and waiting.
596 HandleNewData(NewDataQueue);
597
598 const T &AData = AFD.find(*AI)->getValue();
599 const T &BData = BFD.find(*AI)->getValue();
600 HandlePair(&BData, &AData);
601 if (BI != BE)
602 ++BI;
603 ++AI;
604 }
605
606 // Check any remaining before sections to see if they have been removed
607 while (BI != BE) {
608 HandlePotentiallyRemovedData(*BI);
609 ++BI;
610 }
611
612 HandleNewData(NewDataQueue);
613}
614
615template <typename T>
617 bool CompareModule,
618 std::function<void(bool InModule, unsigned Minor,
619 const FuncDataT<T> &Before, const FuncDataT<T> &After)>
620 CompareFunc) {
621 if (!CompareModule) {
622 // Just handle the single function.
623 assert(Before.getData().size() == 1 && After.getData().size() == 1 &&
624 "Expected only one function.");
625 CompareFunc(false, 0, Before.getData().begin()->getValue(),
626 After.getData().begin()->getValue());
627 return;
628 }
629
630 unsigned Minor = 0;
631 FuncDataT<T> Missing("");
632 IRDataT<T>::report(Before, After,
633 [&](const FuncDataT<T> *B, const FuncDataT<T> *A) {
634 assert((B || A) && "Both functions cannot be missing.");
635 if (!B)
636 B = &Missing;
637 else if (!A)
638 A = &Missing;
639 CompareFunc(true, Minor++, *B, *A);
640 });
641}
642
643template <typename T> void IRComparer<T>::analyzeIR(Any IR, IRDataT<T> &Data) {
644 if (const Module *M = getModuleForComparison(IR)) {
645 // Create data for each existing/interesting function in the module.
646 for (const Function &F : *M)
647 generateFunctionData(Data, F);
648 return;
649 }
650
651 const Function **FPtr = any_cast<const Function *>(&IR);
652 const Function *F = FPtr ? *FPtr : nullptr;
653 if (!F) {
654 const Loop **L = any_cast<const Loop *>(&IR);
655 assert(L && "Unknown IR unit.");
656 F = (*L)->getHeader()->getParent();
657 }
658 assert(F && "Unknown IR unit.");
659 generateFunctionData(Data, *F);
660}
661
662template <typename T>
664 if (!F.isDeclaration() && isFunctionInPrintList(F.getName())) {
665 FuncDataT<T> FD(F.getEntryBlock().getName().str());
666 int I = 0;
667 for (const auto &B : F) {
668 std::string BBName = B.getName().str();
669 if (BBName.empty()) {
670 BBName = formatv("{0}", I);
671 ++I;
672 }
673 FD.getOrder().emplace_back(BBName);
674 FD.getData().insert({BBName, B});
675 }
676 Data.getOrder().emplace_back(F.getName());
677 Data.getData().insert({F.getName(), FD});
678 return true;
679 }
680 return false;
681}
682
684 assert(ModuleDescStack.empty() && "ModuleDescStack is not empty at exit");
685}
686
687void PrintIRInstrumentation::pushModuleDesc(StringRef PassID, Any IR) {
688 const Module *M = unwrapModule(IR);
689 ModuleDescStack.emplace_back(M, getIRName(IR), PassID);
690}
691
692PrintIRInstrumentation::PrintModuleDesc
693PrintIRInstrumentation::popModuleDesc(StringRef PassID) {
694 assert(!ModuleDescStack.empty() && "empty ModuleDescStack");
695 PrintModuleDesc ModuleDesc = ModuleDescStack.pop_back_val();
696 assert(std::get<2>(ModuleDesc).equals(PassID) && "malformed ModuleDescStack");
697 return ModuleDesc;
698}
699
700void PrintIRInstrumentation::printBeforePass(StringRef PassID, Any IR) {
701 if (isIgnored(PassID))
702 return;
703
704 // Saving Module for AfterPassInvalidated operations.
705 // Note: here we rely on a fact that we do not change modules while
706 // traversing the pipeline, so the latest captured module is good
707 // for all print operations that has not happen yet.
708 if (shouldPrintPassNumbers() || shouldPrintAtPassNumber() ||
709 shouldPrintAfterPass(PassID))
710 pushModuleDesc(PassID, IR);
711
712 if (!shouldPrintIR(IR))
713 return;
714
715 ++CurrentPassNumber;
716
717 if (shouldPrintPassNumbers())
718 dbgs() << " Running pass " << CurrentPassNumber << " " << PassID << "\n";
719
720 if (!shouldPrintBeforePass(PassID))
721 return;
722
723 dbgs() << "*** IR Dump Before " << PassID << " on " << getIRName(IR)
724 << " ***\n";
725 unwrapAndPrint(dbgs(), IR);
726}
727
728void PrintIRInstrumentation::printAfterPass(StringRef PassID, Any IR) {
729 if (isIgnored(PassID))
730 return;
731
732 if (!shouldPrintAfterPass(PassID) && !shouldPrintPassNumbers() &&
733 !shouldPrintAtPassNumber())
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
742 if (!shouldPrintIR(IR) || !shouldPrintAfterPass(PassID))
743 return;
744
745 dbgs() << "*** IR Dump "
746 << (shouldPrintAtPassNumber()
747 ? StringRef(formatv("At {0}-{1}", CurrentPassNumber, PassID))
748 : StringRef(formatv("After {0}", PassID)))
749 << " on " << IRName << " ***\n";
750 unwrapAndPrint(dbgs(), IR);
751}
752
753void PrintIRInstrumentation::printAfterPassInvalidated(StringRef PassID) {
754 if (isIgnored(PassID))
755 return;
756
757 if (!shouldPrintAfterPass(PassID) && !shouldPrintPassNumbers() &&
758 !shouldPrintAtPassNumber())
759 return;
760
761 const Module *M;
762 std::string IRName;
763 StringRef StoredPassID;
764 std::tie(M, IRName, StoredPassID) = popModuleDesc(PassID);
765 assert(StoredPassID == PassID && "mismatched PassID");
766 // Additional filtering (e.g. -filter-print-func) can lead to module
767 // printing being skipped.
768 if (!M || !shouldPrintAfterPass(PassID))
769 return;
770
771 SmallString<20> Banner;
772 if (shouldPrintAtPassNumber())
773 Banner = formatv("*** IR Dump At {0}-{1} on {2} (invalidated) ***",
774 CurrentPassNumber, PassID, IRName);
775 else
776 Banner = formatv("*** IR Dump After {0} on {1} (invalidated) ***",
777 PassID, IRName);
778 dbgs() << Banner << "\n";
779 printIR(dbgs(), M);
780}
781
782bool PrintIRInstrumentation::shouldPrintBeforePass(StringRef PassID) {
784 return true;
785
788}
789
790bool PrintIRInstrumentation::shouldPrintAfterPass(StringRef PassID) {
792 return true;
793
794 if (shouldPrintAtPassNumber() && CurrentPassNumber == PrintAtPassNumber)
795 return true;
796
799}
800
801bool PrintIRInstrumentation::shouldPrintPassNumbers() {
802 return PrintPassNumbers;
803}
804
805bool PrintIRInstrumentation::shouldPrintAtPassNumber() {
806 return PrintAtPassNumber > 0;
807}
808
811 this->PIC = &PIC;
812
813 // BeforePass callback is not just for printing, it also saves a Module
814 // for later use in AfterPassInvalidated.
815 if (shouldPrintPassNumbers() || shouldPrintAtPassNumber() ||
818 [this](StringRef P, Any IR) { this->printBeforePass(P, IR); });
819
820 if (shouldPrintPassNumbers() || shouldPrintAtPassNumber() ||
823 [this](StringRef P, Any IR, const PreservedAnalyses &) {
824 this->printAfterPass(P, IR);
825 });
827 [this](StringRef P, const PreservedAnalyses &) {
828 this->printAfterPassInvalidated(P);
829 });
830 }
831}
832
836 [this](StringRef P, Any IR) { return this->shouldRun(P, IR); });
837}
838
839bool OptNoneInstrumentation::shouldRun(StringRef PassID, Any IR) {
840 const Function **FPtr = any_cast<const Function *>(&IR);
841 const Function *F = FPtr ? *FPtr : nullptr;
842 if (!F) {
843 if (const auto **L = any_cast<const Loop *>(&IR))
844 F = (*L)->getHeader()->getParent();
845 }
846 bool ShouldRun = !(F && F->hasOptNone());
847 if (!ShouldRun && DebugLogging) {
848 errs() << "Skipping pass " << PassID << " on " << F->getName()
849 << " due to optnone attribute\n";
850 }
851 return ShouldRun;
852}
853
855 if (isIgnored(PassName))
856 return true;
857
858 bool ShouldRun =
859 Context.getOptPassGate().shouldRunPass(PassName, getIRName(IR));
860 if (!ShouldRun && !this->HasWrittenIR && !OptBisectPrintIRPath.empty()) {
861 // FIXME: print IR if limit is higher than number of opt-bisect
862 // invocations
863 this->HasWrittenIR = true;
864 const Module *M = unwrapModule(IR, /*Force=*/true);
865 assert((M && &M->getContext() == &Context) && "Missing/Mismatching Module");
866 std::error_code EC;
868 if (EC)
870 M->print(OS, nullptr);
871 }
872 return ShouldRun;
873}
874
877 OptPassGate &PassGate = Context.getOptPassGate();
878 if (!PassGate.isEnabled())
879 return;
880
882 return this->shouldRun(PassName, IR);
883 });
884}
885
886raw_ostream &PrintPassInstrumentation::print() {
887 if (Opts.Indent) {
888 assert(Indent >= 0);
889 dbgs().indent(Indent);
890 }
891 return dbgs();
892}
893
896 if (!Enabled)
897 return;
898
899 std::vector<StringRef> SpecialPasses;
900 if (!Opts.Verbose) {
901 SpecialPasses.emplace_back("PassManager");
902 SpecialPasses.emplace_back("PassAdaptor");
903 }
904
905 PIC.registerBeforeSkippedPassCallback([this, SpecialPasses](StringRef PassID,
906 Any IR) {
907 assert(!isSpecialPass(PassID, SpecialPasses) &&
908 "Unexpectedly skipping special pass");
909
910 print() << "Skipping pass: " << PassID << " on " << getIRName(IR) << "\n";
911 });
912 PIC.registerBeforeNonSkippedPassCallback([this, SpecialPasses](
913 StringRef PassID, Any IR) {
914 if (isSpecialPass(PassID, SpecialPasses))
915 return;
916
917 auto &OS = print();
918 OS << "Running pass: " << PassID << " on " << getIRName(IR);
919 if (const auto **F = any_cast<const Function *>(&IR)) {
920 unsigned Count = (*F)->getInstructionCount();
921 OS << " (" << Count << " instruction";
922 if (Count != 1)
923 OS << 's';
924 OS << ')';
925 } else if (const auto **C = any_cast<const LazyCallGraph::SCC *>(&IR)) {
926 int Count = (*C)->size();
927 OS << " (" << Count << " node";
928 if (Count != 1)
929 OS << 's';
930 OS << ')';
931 }
932 OS << "\n";
933 Indent += 2;
934 });
936 [this, SpecialPasses](StringRef PassID, Any IR,
937 const PreservedAnalyses &) {
938 if (isSpecialPass(PassID, SpecialPasses))
939 return;
940
941 Indent -= 2;
942 });
944 [this, SpecialPasses](StringRef PassID, Any IR) {
945 if (isSpecialPass(PassID, SpecialPasses))
946 return;
947
948 Indent -= 2;
949 });
950
951 if (!Opts.SkipAnalyses) {
953 print() << "Running analysis: " << PassID << " on " << getIRName(IR)
954 << "\n";
955 Indent += 2;
956 });
958 [this](StringRef PassID, Any IR) { Indent -= 2; });
960 print() << "Invalidating analysis: " << PassID << " on " << getIRName(IR)
961 << "\n";
962 });
964 print() << "Clearing all analysis results for: " << IRName << "\n";
965 });
966 }
967}
968
970 bool TrackBBLifetime) {
971 if (TrackBBLifetime)
973 for (const auto &BB : *F) {
974 if (BBGuards)
975 BBGuards->try_emplace(intptr_t(&BB), &BB);
976 for (const auto *Succ : successors(&BB)) {
977 Graph[&BB][Succ]++;
978 if (BBGuards)
979 BBGuards->try_emplace(intptr_t(Succ), Succ);
980 }
981 }
982}
983
984static void printBBName(raw_ostream &out, const BasicBlock *BB) {
985 if (BB->hasName()) {
986 out << BB->getName() << "<" << BB << ">";
987 return;
988 }
989
990 if (!BB->getParent()) {
991 out << "unnamed_removed<" << BB << ">";
992 return;
993 }
994
995 if (BB->isEntryBlock()) {
996 out << "entry"
997 << "<" << BB << ">";
998 return;
999 }
1000
1001 unsigned FuncOrderBlockNum = 0;
1002 for (auto &FuncBB : *BB->getParent()) {
1003 if (&FuncBB == BB)
1004 break;
1005 FuncOrderBlockNum++;
1006 }
1007 out << "unnamed_" << FuncOrderBlockNum << "<" << BB << ">";
1008}
1009
1011 const CFG &Before,
1012 const CFG &After) {
1013 assert(!After.isPoisoned());
1014 if (Before.isPoisoned()) {
1015 out << "Some blocks were deleted\n";
1016 return;
1017 }
1018
1019 // Find and print graph differences.
1020 if (Before.Graph.size() != After.Graph.size())
1021 out << "Different number of non-leaf basic blocks: before="
1022 << Before.Graph.size() << ", after=" << After.Graph.size() << "\n";
1023
1024 for (auto &BB : Before.Graph) {
1025 auto BA = After.Graph.find(BB.first);
1026 if (BA == After.Graph.end()) {
1027 out << "Non-leaf block ";
1028 printBBName(out, BB.first);
1029 out << " is removed (" << BB.second.size() << " successors)\n";
1030 }
1031 }
1032
1033 for (auto &BA : After.Graph) {
1034 auto BB = Before.Graph.find(BA.first);
1035 if (BB == Before.Graph.end()) {
1036 out << "Non-leaf block ";
1037 printBBName(out, BA.first);
1038 out << " is added (" << BA.second.size() << " successors)\n";
1039 continue;
1040 }
1041
1042 if (BB->second == BA.second)
1043 continue;
1044
1045 out << "Different successors of block ";
1046 printBBName(out, BA.first);
1047 out << " (unordered):\n";
1048 out << "- before (" << BB->second.size() << "): ";
1049 for (auto &SuccB : BB->second) {
1050 printBBName(out, SuccB.first);
1051 if (SuccB.second != 1)
1052 out << "(" << SuccB.second << "), ";
1053 else
1054 out << ", ";
1055 }
1056 out << "\n";
1057 out << "- after (" << BA.second.size() << "): ";
1058 for (auto &SuccA : BA.second) {
1059 printBBName(out, SuccA.first);
1060 if (SuccA.second != 1)
1061 out << "(" << SuccA.second << "), ";
1062 else
1063 out << ", ";
1064 }
1065 out << "\n";
1066 }
1067}
1068
1069// PreservedCFGCheckerInstrumentation uses PreservedCFGCheckerAnalysis to check
1070// passes, that reported they kept CFG analyses up-to-date, did not actually
1071// change CFG. This check is done as follows. Before every functional pass in
1072// BeforeNonSkippedPassCallback a CFG snapshot (an instance of
1073// PreservedCFGCheckerInstrumentation::CFG) is requested from
1074// FunctionAnalysisManager as a result of PreservedCFGCheckerAnalysis. When the
1075// functional pass finishes and reports that CFGAnalyses or AllAnalyses are
1076// up-to-date then the cached result of PreservedCFGCheckerAnalysis (if
1077// available) is checked to be equal to a freshly created CFG snapshot.
1079 : public AnalysisInfoMixin<PreservedCFGCheckerAnalysis> {
1081
1083
1084public:
1085 /// Provide the result type for this analysis pass.
1087
1088 /// Run the analysis pass over a function and produce CFG.
1090 return Result(&F, /* TrackBBLifetime */ true);
1091 }
1092};
1093
1095
1097 : public AnalysisInfoMixin<PreservedFunctionHashAnalysis> {
1099
1102 };
1103
1105
1107 return Result{StructuralHash(F)};
1108 }
1109};
1110
1112
1114 : public AnalysisInfoMixin<PreservedModuleHashAnalysis> {
1116
1117 struct ModuleHash {
1119 };
1120
1122
1124 return Result{StructuralHash(F)};
1125 }
1126};
1127
1129
1131 Function &F, const PreservedAnalyses &PA,
1133 auto PAC = PA.getChecker<PreservedCFGCheckerAnalysis>();
1134 return !(PAC.preserved() || PAC.preservedSet<AllAnalysesOn<Function>>() ||
1135 PAC.preservedSet<CFGAnalyses>());
1136}
1137
1140
1141 if (const auto **MaybeF = any_cast<const Function *>(&IR)) {
1142 Functions.push_back(*const_cast<Function **>(MaybeF));
1143 } else if (const auto **MaybeM = any_cast<const Module *>(&IR)) {
1144 for (Function &F : **const_cast<Module **>(MaybeM))
1145 Functions.push_back(&F);
1146 }
1147 return Functions;
1148}
1149
1153 return;
1154
1155 bool Registered = false;
1156 PIC.registerBeforeNonSkippedPassCallback([this, &MAM, Registered](
1157 StringRef P, Any IR) mutable {
1158#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
1159 assert(&PassStack.emplace_back(P));
1160#endif
1161 (void)this;
1162
1164 *const_cast<Module *>(unwrapModule(IR, /*Force=*/true)))
1165 .getManager();
1166 if (!Registered) {
1167 FAM.registerPass([&] { return PreservedCFGCheckerAnalysis(); });
1169 MAM.registerPass([&] { return PreservedModuleHashAnalysis(); });
1170 Registered = true;
1171 }
1172
1173 for (Function *F : GetFunctions(IR)) {
1174 // Make sure a fresh CFG snapshot is available before the pass.
1177 }
1178
1179 if (auto *MaybeM = any_cast<const Module *>(&IR)) {
1180 Module &M = **const_cast<Module **>(MaybeM);
1182 }
1183 });
1184
1186 [this](StringRef P, const PreservedAnalyses &PassPA) {
1187#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
1188 assert(PassStack.pop_back_val() == P &&
1189 "Before and After callbacks must correspond");
1190#endif
1191 (void)this;
1192 });
1193
1195 const PreservedAnalyses &PassPA) {
1196#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
1197 assert(PassStack.pop_back_val() == P &&
1198 "Before and After callbacks must correspond");
1199#endif
1200 (void)this;
1201
1202 // We have to get the FAM via the MAM, rather than directly use a passed in
1203 // FAM because if MAM has not cached the FAM, it won't invalidate function
1204 // analyses in FAM.
1206 *const_cast<Module *>(unwrapModule(IR, /*Force=*/true)))
1207 .getManager();
1208
1209 for (Function *F : GetFunctions(IR)) {
1210 if (auto *HashBefore =
1212 if (HashBefore->Hash != StructuralHash(*F)) {
1214 "Function @{0} changed by {1} without invalidating analyses",
1215 F->getName(), P));
1216 }
1217 }
1218
1219 auto CheckCFG = [](StringRef Pass, StringRef FuncName,
1220 const CFG &GraphBefore, const CFG &GraphAfter) {
1221 if (GraphAfter == GraphBefore)
1222 return;
1223
1224 dbgs()
1225 << "Error: " << Pass
1226 << " does not invalidate CFG analyses but CFG changes detected in "
1227 "function @"
1228 << FuncName << ":\n";
1229 CFG::printDiff(dbgs(), GraphBefore, GraphAfter);
1230 report_fatal_error(Twine("CFG unexpectedly changed by ", Pass));
1231 };
1232
1233 if (auto *GraphBefore =
1235 CheckCFG(P, F->getName(), *GraphBefore,
1236 CFG(F, /* TrackBBLifetime */ false));
1237 }
1238 if (auto *MaybeM = any_cast<const Module *>(&IR)) {
1239 Module &M = **const_cast<Module **>(MaybeM);
1240 if (auto *HashBefore =
1242 if (HashBefore->Hash != StructuralHash(M)) {
1244 "Module changed by {0} without invalidating analyses", P));
1245 }
1246 }
1247 }
1248 });
1249}
1250
1254 [this](StringRef P, Any IR, const PreservedAnalyses &PassPA) {
1255 if (isIgnored(P) || P == "VerifierPass")
1256 return;
1257 const Function **FPtr = any_cast<const Function *>(&IR);
1258 const Function *F = FPtr ? *FPtr : nullptr;
1259 if (!F) {
1260 if (const auto **L = any_cast<const Loop *>(&IR))
1261 F = (*L)->getHeader()->getParent();
1262 }
1263
1264 if (F) {
1265 if (DebugLogging)
1266 dbgs() << "Verifying function " << F->getName() << "\n";
1267
1268 if (verifyFunction(*F, &errs()))
1269 report_fatal_error("Broken function found, compilation aborted!");
1270 } else {
1271 const Module **MPtr = any_cast<const Module *>(&IR);
1272 const Module *M = MPtr ? *MPtr : nullptr;
1273 if (!M) {
1274 if (const auto **C = any_cast<const LazyCallGraph::SCC *>(&IR))
1275 M = (*C)->begin()->getFunction().getParent();
1276 }
1277
1278 if (M) {
1279 if (DebugLogging)
1280 dbgs() << "Verifying module " << M->getName() << "\n";
1281
1282 if (verifyModule(*M, &errs()))
1283 report_fatal_error("Broken module found, compilation aborted!");
1284 }
1285 }
1286 });
1287}
1288
1290
1292 StringRef PassID,
1295}
1296
1298 const IRDataT<EmptyData> &Before,
1299 const IRDataT<EmptyData> &After,
1300 Any IR) {
1301 SmallString<20> Banner =
1302 formatv("*** IR Dump After {0} on {1} ***\n", PassID, Name);
1303 Out << Banner;
1304 IRComparer<EmptyData>(Before, After)
1305 .compare(getModuleForComparison(IR),
1306 [&](bool InModule, unsigned Minor,
1307 const FuncDataT<EmptyData> &Before,
1308 const FuncDataT<EmptyData> &After) -> void {
1309 handleFunctionCompare(Name, "", PassID, " on ", InModule,
1310 Minor, Before, After);
1311 });
1312 Out << "\n";
1313}
1314
1316 StringRef Name, StringRef Prefix, StringRef PassID, StringRef Divider,
1317 bool InModule, unsigned Minor, const FuncDataT<EmptyData> &Before,
1318 const FuncDataT<EmptyData> &After) {
1319 // Print a banner when this is being shown in the context of a module
1320 if (InModule)
1321 Out << "\n*** IR for function " << Name << " ***\n";
1322
1324 Before, After,
1325 [&](const BlockDataT<EmptyData> *B, const BlockDataT<EmptyData> *A) {
1326 StringRef BStr = B ? B->getBody() : "\n";
1327 StringRef AStr = A ? A->getBody() : "\n";
1328 const std::string Removed =
1329 UseColour ? "\033[31m-%l\033[0m\n" : "-%l\n";
1330 const std::string Added = UseColour ? "\033[32m+%l\033[0m\n" : "+%l\n";
1331 const std::string NoChange = " %l\n";
1332 Out << doSystemDiff(BStr, AStr, Removed, Added, NoChange);
1333 });
1334}
1335
1341 TextChangeReporter<IRDataT<EmptyData>>::registerRequiredCallbacks(PIC);
1342}
1343
1345
1349 return;
1351 [this](StringRef P, Any IR) { this->runBeforePass(P, IR); });
1353 [this](StringRef P, Any IR, const PreservedAnalyses &) {
1354 this->runAfterPass();
1355 },
1356 true);
1358 [this](StringRef P, const PreservedAnalyses &) { this->runAfterPass(); },
1359 true);
1361 [this](StringRef P, Any IR) { this->runBeforePass(P, IR); });
1363 [this](StringRef P, Any IR) { this->runAfterPass(); }, true);
1364}
1365
1366void TimeProfilingPassesHandler::runBeforePass(StringRef PassID, Any IR) {
1367 timeTraceProfilerBegin(PassID, getIRName(IR));
1368}
1369
1370void TimeProfilingPassesHandler::runAfterPass() { timeTraceProfilerEnd(); }
1371
1372namespace {
1373
1374class DisplayNode;
1375class DotCfgDiffDisplayGraph;
1376
1377// Base class for a node or edge in the dot-cfg-changes graph.
1378class DisplayElement {
1379public:
1380 // Is this in before, after, or both?
1381 StringRef getColour() const { return Colour; }
1382
1383protected:
1384 DisplayElement(StringRef Colour) : Colour(Colour) {}
1385 const StringRef Colour;
1386};
1387
1388// An edge representing a transition between basic blocks in the
1389// dot-cfg-changes graph.
1390class DisplayEdge : public DisplayElement {
1391public:
1392 DisplayEdge(std::string Value, DisplayNode &Node, StringRef Colour)
1393 : DisplayElement(Colour), Value(Value), Node(Node) {}
1394 // The value on which the transition is made.
1395 std::string getValue() const { return Value; }
1396 // The node (representing a basic block) reached by this transition.
1397 const DisplayNode &getDestinationNode() const { return Node; }
1398
1399protected:
1400 std::string Value;
1401 const DisplayNode &Node;
1402};
1403
1404// A node in the dot-cfg-changes graph which represents a basic block.
1405class DisplayNode : public DisplayElement {
1406public:
1407 // \p C is the content for the node, \p T indicates the colour for the
1408 // outline of the node
1409 DisplayNode(std::string Content, StringRef Colour)
1410 : DisplayElement(Colour), Content(Content) {}
1411
1412 // Iterator to the child nodes. Required by GraphWriter.
1413 using ChildIterator = std::unordered_set<DisplayNode *>::const_iterator;
1414 ChildIterator children_begin() const { return Children.cbegin(); }
1415 ChildIterator children_end() const { return Children.cend(); }
1416
1417 // Iterator for the edges. Required by GraphWriter.
1418 using EdgeIterator = std::vector<DisplayEdge *>::const_iterator;
1419 EdgeIterator edges_begin() const { return EdgePtrs.cbegin(); }
1420 EdgeIterator edges_end() const { return EdgePtrs.cend(); }
1421
1422 // Create an edge to \p Node on value \p Value, with colour \p Colour.
1423 void createEdge(StringRef Value, DisplayNode &Node, StringRef Colour);
1424
1425 // Return the content of this node.
1426 std::string getContent() const { return Content; }
1427
1428 // Return the edge to node \p S.
1429 const DisplayEdge &getEdge(const DisplayNode &To) const {
1430 assert(EdgeMap.find(&To) != EdgeMap.end() && "Expected to find edge.");
1431 return *EdgeMap.find(&To)->second;
1432 }
1433
1434 // Return the value for the transition to basic block \p S.
1435 // Required by GraphWriter.
1436 std::string getEdgeSourceLabel(const DisplayNode &Sink) const {
1437 return getEdge(Sink).getValue();
1438 }
1439
1440 void createEdgeMap();
1441
1442protected:
1443 const std::string Content;
1444
1445 // Place to collect all of the edges. Once they are all in the vector,
1446 // the vector will not reallocate so then we can use pointers to them,
1447 // which are required by the graph writing routines.
1448 std::vector<DisplayEdge> Edges;
1449
1450 std::vector<DisplayEdge *> EdgePtrs;
1451 std::unordered_set<DisplayNode *> Children;
1452 std::unordered_map<const DisplayNode *, const DisplayEdge *> EdgeMap;
1453
1454 // Safeguard adding of edges.
1455 bool AllEdgesCreated = false;
1456};
1457
1458// Class representing a difference display (corresponds to a pdf file).
1459class DotCfgDiffDisplayGraph {
1460public:
1461 DotCfgDiffDisplayGraph(std::string Name) : GraphName(Name) {}
1462
1463 // Generate the file into \p DotFile.
1464 void generateDotFile(StringRef DotFile);
1465
1466 // Iterator to the nodes. Required by GraphWriter.
1467 using NodeIterator = std::vector<DisplayNode *>::const_iterator;
1468 NodeIterator nodes_begin() const {
1469 assert(NodeGenerationComplete && "Unexpected children iterator creation");
1470 return NodePtrs.cbegin();
1471 }
1472 NodeIterator nodes_end() const {
1473 assert(NodeGenerationComplete && "Unexpected children iterator creation");
1474 return NodePtrs.cend();
1475 }
1476
1477 // Record the index of the entry node. At this point, we can build up
1478 // vectors of pointers that are required by the graph routines.
1479 void setEntryNode(unsigned N) {
1480 // At this point, there will be no new nodes.
1481 assert(!NodeGenerationComplete && "Unexpected node creation");
1482 NodeGenerationComplete = true;
1483 for (auto &N : Nodes)
1484 NodePtrs.emplace_back(&N);
1485
1486 EntryNode = NodePtrs[N];
1487 }
1488
1489 // Create a node.
1490 void createNode(std::string C, StringRef Colour) {
1491 assert(!NodeGenerationComplete && "Unexpected node creation");
1492 Nodes.emplace_back(C, Colour);
1493 }
1494 // Return the node at index \p N to avoid problems with vectors reallocating.
1495 DisplayNode &getNode(unsigned N) {
1496 assert(N < Nodes.size() && "Node is out of bounds");
1497 return Nodes[N];
1498 }
1499 unsigned size() const {
1500 assert(NodeGenerationComplete && "Unexpected children iterator creation");
1501 return Nodes.size();
1502 }
1503
1504 // Return the name of the graph. Required by GraphWriter.
1505 std::string getGraphName() const { return GraphName; }
1506
1507 // Return the string representing the differences for basic block \p Node.
1508 // Required by GraphWriter.
1509 std::string getNodeLabel(const DisplayNode &Node) const {
1510 return Node.getContent();
1511 }
1512
1513 // Return a string with colour information for Dot. Required by GraphWriter.
1514 std::string getNodeAttributes(const DisplayNode &Node) const {
1515 return attribute(Node.getColour());
1516 }
1517
1518 // Return a string with colour information for Dot. Required by GraphWriter.
1519 std::string getEdgeColorAttr(const DisplayNode &From,
1520 const DisplayNode &To) const {
1521 return attribute(From.getEdge(To).getColour());
1522 }
1523
1524 // Get the starting basic block. Required by GraphWriter.
1525 DisplayNode *getEntryNode() const {
1526 assert(NodeGenerationComplete && "Unexpected children iterator creation");
1527 return EntryNode;
1528 }
1529
1530protected:
1531 // Return the string containing the colour to use as a Dot attribute.
1532 std::string attribute(StringRef Colour) const {
1533 return "color=" + Colour.str();
1534 }
1535
1536 bool NodeGenerationComplete = false;
1537 const std::string GraphName;
1538 std::vector<DisplayNode> Nodes;
1539 std::vector<DisplayNode *> NodePtrs;
1540 DisplayNode *EntryNode = nullptr;
1541};
1542
1543void DisplayNode::createEdge(StringRef Value, DisplayNode &Node,
1544 StringRef Colour) {
1545 assert(!AllEdgesCreated && "Expected to be able to still create edges.");
1546 Edges.emplace_back(Value.str(), Node, Colour);
1547 Children.insert(&Node);
1548}
1549
1550void DisplayNode::createEdgeMap() {
1551 // No more edges will be added so we can now use pointers to the edges
1552 // as the vector will not grow and reallocate.
1553 AllEdgesCreated = true;
1554 for (auto &E : Edges)
1555 EdgeMap.insert({&E.getDestinationNode(), &E});
1556}
1557
1558class DotCfgDiffNode;
1559class DotCfgDiff;
1560
1561// A class representing a basic block in the Dot difference graph.
1562class DotCfgDiffNode {
1563public:
1564 DotCfgDiffNode() = delete;
1565
1566 // Create a node in Dot difference graph \p G representing the basic block
1567 // represented by \p BD with colour \p Colour (where it exists).
1568 DotCfgDiffNode(DotCfgDiff &G, unsigned N, const BlockDataT<DCData> &BD,
1569 StringRef Colour)
1570 : Graph(G), N(N), Data{&BD, nullptr}, Colour(Colour) {}
1571 DotCfgDiffNode(const DotCfgDiffNode &DN)
1572 : Graph(DN.Graph), N(DN.N), Data{DN.Data[0], DN.Data[1]},
1573 Colour(DN.Colour), EdgesMap(DN.EdgesMap), Children(DN.Children),
1574 Edges(DN.Edges) {}
1575
1576 unsigned getIndex() const { return N; }
1577
1578 // The label of the basic block
1579 StringRef getLabel() const {
1580 assert(Data[0] && "Expected Data[0] to be set.");
1581 return Data[0]->getLabel();
1582 }
1583 // Return the colour for this block
1584 StringRef getColour() const { return Colour; }
1585 // Change this basic block from being only in before to being common.
1586 // Save the pointer to \p Other.
1587 void setCommon(const BlockDataT<DCData> &Other) {
1588 assert(!Data[1] && "Expected only one block datum");
1589 Data[1] = &Other;
1590 Colour = CommonColour;
1591 }
1592 // Add an edge to \p E of colour {\p Value, \p Colour}.
1593 void addEdge(unsigned E, StringRef Value, StringRef Colour) {
1594 // This is a new edge or it is an edge being made common.
1595 assert((EdgesMap.count(E) == 0 || Colour == CommonColour) &&
1596 "Unexpected edge count and color.");
1597 EdgesMap[E] = {Value.str(), Colour};
1598 }
1599 // Record the children and create edges.
1600 void finalize(DotCfgDiff &G);
1601
1602 // Return the colour of the edge to node \p S.
1603 StringRef getEdgeColour(const unsigned S) const {
1604 assert(EdgesMap.count(S) == 1 && "Expected to find edge.");
1605 return EdgesMap.at(S).second;
1606 }
1607
1608 // Return the string representing the basic block.
1609 std::string getBodyContent() const;
1610
1611 void createDisplayEdges(DotCfgDiffDisplayGraph &Graph, unsigned DisplayNode,
1612 std::map<const unsigned, unsigned> &NodeMap) const;
1613
1614protected:
1615 DotCfgDiff &Graph;
1616 const unsigned N;
1617 const BlockDataT<DCData> *Data[2];
1618 StringRef Colour;
1619 std::map<const unsigned, std::pair<std::string, StringRef>> EdgesMap;
1620 std::vector<unsigned> Children;
1621 std::vector<unsigned> Edges;
1622};
1623
1624// Class representing the difference graph between two functions.
1625class DotCfgDiff {
1626public:
1627 // \p Title is the title given to the graph. \p EntryNodeName is the
1628 // entry node for the function. \p Before and \p After are the before
1629 // after versions of the function, respectively. \p Dir is the directory
1630 // in which to store the results.
1631 DotCfgDiff(StringRef Title, const FuncDataT<DCData> &Before,
1632 const FuncDataT<DCData> &After);
1633
1634 DotCfgDiff(const DotCfgDiff &) = delete;
1635 DotCfgDiff &operator=(const DotCfgDiff &) = delete;
1636
1637 DotCfgDiffDisplayGraph createDisplayGraph(StringRef Title,
1638 StringRef EntryNodeName);
1639
1640 // Return a string consisting of the labels for the \p Source and \p Sink.
1641 // The combination allows distinguishing changing transitions on the
1642 // same value (ie, a transition went to X before and goes to Y after).
1643 // Required by GraphWriter.
1644 StringRef getEdgeSourceLabel(const unsigned &Source,
1645 const unsigned &Sink) const {
1646 std::string S =
1647 getNode(Source).getLabel().str() + " " + getNode(Sink).getLabel().str();
1648 assert(EdgeLabels.count(S) == 1 && "Expected to find edge label.");
1649 return EdgeLabels.find(S)->getValue();
1650 }
1651
1652 // Return the number of basic blocks (nodes). Required by GraphWriter.
1653 unsigned size() const { return Nodes.size(); }
1654
1655 const DotCfgDiffNode &getNode(unsigned N) const {
1656 assert(N < Nodes.size() && "Unexpected index for node reference");
1657 return Nodes[N];
1658 }
1659
1660protected:
1661 // Return the string surrounded by HTML to make it the appropriate colour.
1662 std::string colourize(std::string S, StringRef Colour) const;
1663
1664 void createNode(StringRef Label, const BlockDataT<DCData> &BD, StringRef C) {
1665 unsigned Pos = Nodes.size();
1666 Nodes.emplace_back(*this, Pos, BD, C);
1667 NodePosition.insert({Label, Pos});
1668 }
1669
1670 // TODO Nodes should probably be a StringMap<DotCfgDiffNode> after the
1671 // display graph is separated out, which would remove the need for
1672 // NodePosition.
1673 std::vector<DotCfgDiffNode> Nodes;
1674 StringMap<unsigned> NodePosition;
1675 const std::string GraphName;
1676
1677 StringMap<std::string> EdgeLabels;
1678};
1679
1680std::string DotCfgDiffNode::getBodyContent() const {
1681 if (Colour == CommonColour) {
1682 assert(Data[1] && "Expected Data[1] to be set.");
1683
1684 StringRef SR[2];
1685 for (unsigned I = 0; I < 2; ++I) {
1686 SR[I] = Data[I]->getBody();
1687 // drop initial '\n' if present
1688 if (SR[I][0] == '\n')
1689 SR[I] = SR[I].drop_front();
1690 // drop predecessors as they can be big and are redundant
1691 SR[I] = SR[I].drop_until([](char C) { return C == '\n'; }).drop_front();
1692 }
1693
1694 SmallString<80> OldLineFormat = formatv(
1695 "<FONT COLOR=\"{0}\">%l</FONT><BR align=\"left\"/>", BeforeColour);
1696 SmallString<80> NewLineFormat = formatv(
1697 "<FONT COLOR=\"{0}\">%l</FONT><BR align=\"left\"/>", AfterColour);
1698 SmallString<80> UnchangedLineFormat = formatv(
1699 "<FONT COLOR=\"{0}\">%l</FONT><BR align=\"left\"/>", CommonColour);
1700 std::string Diff = Data[0]->getLabel().str();
1701 Diff += ":\n<BR align=\"left\"/>" +
1702 doSystemDiff(makeHTMLReady(SR[0]), makeHTMLReady(SR[1]),
1703 OldLineFormat, NewLineFormat, UnchangedLineFormat);
1704
1705 // Diff adds in some empty colour changes which are not valid HTML
1706 // so remove them. Colours are all lowercase alpha characters (as
1707 // listed in https://graphviz.org/pdf/dotguide.pdf).
1708 Regex R("<FONT COLOR=\"\\w+\"></FONT>");
1709 while (true) {
1710 std::string Error;
1711 std::string S = R.sub("", Diff, &Error);
1712 if (Error != "")
1713 return Error;
1714 if (S == Diff)
1715 return Diff;
1716 Diff = S;
1717 }
1718 llvm_unreachable("Should not get here");
1719 }
1720
1721 // Put node out in the appropriate colour.
1722 assert(!Data[1] && "Data[1] is set unexpectedly.");
1723 std::string Body = makeHTMLReady(Data[0]->getBody());
1724 const StringRef BS = Body;
1725 StringRef BS1 = BS;
1726 // Drop leading newline, if present.
1727 if (BS.front() == '\n')
1728 BS1 = BS1.drop_front(1);
1729 // Get label.
1730 StringRef Label = BS1.take_until([](char C) { return C == ':'; });
1731 // drop predecessors as they can be big and are redundant
1732 BS1 = BS1.drop_until([](char C) { return C == '\n'; }).drop_front();
1733
1734 std::string S = "<FONT COLOR=\"" + Colour.str() + "\">" + Label.str() + ":";
1735
1736 // align each line to the left.
1737 while (BS1.size()) {
1738 S.append("<BR align=\"left\"/>");
1739 StringRef Line = BS1.take_until([](char C) { return C == '\n'; });
1740 S.append(Line.str());
1741 BS1 = BS1.drop_front(Line.size() + 1);
1742 }
1743 S.append("<BR align=\"left\"/></FONT>");
1744 return S;
1745}
1746
1747std::string DotCfgDiff::colourize(std::string S, StringRef Colour) const {
1748 if (S.length() == 0)
1749 return S;
1750 return "<FONT COLOR=\"" + Colour.str() + "\">" + S + "</FONT>";
1751}
1752
1753DotCfgDiff::DotCfgDiff(StringRef Title, const FuncDataT<DCData> &Before,
1754 const FuncDataT<DCData> &After)
1755 : GraphName(Title.str()) {
1756 StringMap<StringRef> EdgesMap;
1757
1758 // Handle each basic block in the before IR.
1759 for (auto &B : Before.getData()) {
1760 StringRef Label = B.getKey();
1761 const BlockDataT<DCData> &BD = B.getValue();
1762 createNode(Label, BD, BeforeColour);
1763
1764 // Create transitions with names made up of the from block label, the value
1765 // on which the transition is made and the to block label.
1766 for (StringMap<std::string>::const_iterator Sink = BD.getData().begin(),
1767 E = BD.getData().end();
1768 Sink != E; ++Sink) {
1769 std::string Key = (Label + " " + Sink->getKey().str()).str() + " " +
1770 BD.getData().getSuccessorLabel(Sink->getKey()).str();
1771 EdgesMap.insert({Key, BeforeColour});
1772 }
1773 }
1774
1775 // Handle each basic block in the after IR
1776 for (auto &A : After.getData()) {
1777 StringRef Label = A.getKey();
1778 const BlockDataT<DCData> &BD = A.getValue();
1779 unsigned C = NodePosition.count(Label);
1780 if (C == 0)
1781 // This only exists in the after IR. Create the node.
1782 createNode(Label, BD, AfterColour);
1783 else {
1784 assert(C == 1 && "Unexpected multiple nodes.");
1785 Nodes[NodePosition[Label]].setCommon(BD);
1786 }
1787 // Add in the edges between the nodes (as common or only in after).
1788 for (StringMap<std::string>::const_iterator Sink = BD.getData().begin(),
1789 E = BD.getData().end();
1790 Sink != E; ++Sink) {
1791 std::string Key = (Label + " " + Sink->getKey().str()).str() + " " +
1792 BD.getData().getSuccessorLabel(Sink->getKey()).str();
1793 unsigned C = EdgesMap.count(Key);
1794 if (C == 0)
1795 EdgesMap.insert({Key, AfterColour});
1796 else {
1797 EdgesMap[Key] = CommonColour;
1798 }
1799 }
1800 }
1801
1802 // Now go through the map of edges and add them to the node.
1803 for (auto &E : EdgesMap) {
1804 // Extract the source, sink and value from the edge key.
1805 StringRef S = E.getKey();
1806 auto SP1 = S.rsplit(' ');
1807 auto &SourceSink = SP1.first;
1808 auto SP2 = SourceSink.split(' ');
1809 StringRef Source = SP2.first;
1810 StringRef Sink = SP2.second;
1811 StringRef Value = SP1.second;
1812
1813 assert(NodePosition.count(Source) == 1 && "Expected to find node.");
1814 DotCfgDiffNode &SourceNode = Nodes[NodePosition[Source]];
1815 assert(NodePosition.count(Sink) == 1 && "Expected to find node.");
1816 unsigned SinkNode = NodePosition[Sink];
1817 StringRef Colour = E.second;
1818
1819 // Look for an edge from Source to Sink
1820 if (EdgeLabels.count(SourceSink) == 0)
1821 EdgeLabels.insert({SourceSink, colourize(Value.str(), Colour)});
1822 else {
1823 StringRef V = EdgeLabels.find(SourceSink)->getValue();
1824 std::string NV = colourize(V.str() + " " + Value.str(), Colour);
1825 Colour = CommonColour;
1826 EdgeLabels[SourceSink] = NV;
1827 }
1828 SourceNode.addEdge(SinkNode, Value, Colour);
1829 }
1830 for (auto &I : Nodes)
1831 I.finalize(*this);
1832}
1833
1834DotCfgDiffDisplayGraph DotCfgDiff::createDisplayGraph(StringRef Title,
1835 StringRef EntryNodeName) {
1836 assert(NodePosition.count(EntryNodeName) == 1 &&
1837 "Expected to find entry block in map.");
1838 unsigned Entry = NodePosition[EntryNodeName];
1839 assert(Entry < Nodes.size() && "Expected to find entry node");
1840 DotCfgDiffDisplayGraph G(Title.str());
1841
1842 std::map<const unsigned, unsigned> NodeMap;
1843
1844 int EntryIndex = -1;
1845 unsigned Index = 0;
1846 for (auto &I : Nodes) {
1847 if (I.getIndex() == Entry)
1848 EntryIndex = Index;
1849 G.createNode(I.getBodyContent(), I.getColour());
1850 NodeMap.insert({I.getIndex(), Index++});
1851 }
1852 assert(EntryIndex >= 0 && "Expected entry node index to be set.");
1853 G.setEntryNode(EntryIndex);
1854
1855 for (auto &I : NodeMap) {
1856 unsigned SourceNode = I.first;
1857 unsigned DisplayNode = I.second;
1858 getNode(SourceNode).createDisplayEdges(G, DisplayNode, NodeMap);
1859 }
1860 return G;
1861}
1862
1863void DotCfgDiffNode::createDisplayEdges(
1864 DotCfgDiffDisplayGraph &DisplayGraph, unsigned DisplayNodeIndex,
1865 std::map<const unsigned, unsigned> &NodeMap) const {
1866
1867 DisplayNode &SourceDisplayNode = DisplayGraph.getNode(DisplayNodeIndex);
1868
1869 for (auto I : Edges) {
1870 unsigned SinkNodeIndex = I;
1871 StringRef Colour = getEdgeColour(SinkNodeIndex);
1872 const DotCfgDiffNode *SinkNode = &Graph.getNode(SinkNodeIndex);
1873
1874 StringRef Label = Graph.getEdgeSourceLabel(getIndex(), SinkNodeIndex);
1875 DisplayNode &SinkDisplayNode = DisplayGraph.getNode(SinkNode->getIndex());
1876 SourceDisplayNode.createEdge(Label, SinkDisplayNode, Colour);
1877 }
1878 SourceDisplayNode.createEdgeMap();
1879}
1880
1881void DotCfgDiffNode::finalize(DotCfgDiff &G) {
1882 for (auto E : EdgesMap) {
1883 Children.emplace_back(E.first);
1884 Edges.emplace_back(E.first);
1885 }
1886}
1887
1888} // namespace
1889
1890namespace llvm {
1891
1892template <> struct GraphTraits<DotCfgDiffDisplayGraph *> {
1893 using NodeRef = const DisplayNode *;
1894 using ChildIteratorType = DisplayNode::ChildIterator;
1895 using nodes_iterator = DotCfgDiffDisplayGraph::NodeIterator;
1896 using EdgeRef = const DisplayEdge *;
1897 using ChildEdgeIterator = DisplayNode::EdgeIterator;
1898
1899 static NodeRef getEntryNode(const DotCfgDiffDisplayGraph *G) {
1900 return G->getEntryNode();
1901 }
1903 return N->children_begin();
1904 }
1905 static ChildIteratorType child_end(NodeRef N) { return N->children_end(); }
1906 static nodes_iterator nodes_begin(const DotCfgDiffDisplayGraph *G) {
1907 return G->nodes_begin();
1908 }
1909 static nodes_iterator nodes_end(const DotCfgDiffDisplayGraph *G) {
1910 return G->nodes_end();
1911 }
1913 return N->edges_begin();
1914 }
1915 static ChildEdgeIterator child_edge_end(NodeRef N) { return N->edges_end(); }
1916 static NodeRef edge_dest(EdgeRef E) { return &E->getDestinationNode(); }
1917 static unsigned size(const DotCfgDiffDisplayGraph *G) { return G->size(); }
1918};
1919
1920template <>
1921struct DOTGraphTraits<DotCfgDiffDisplayGraph *> : public DefaultDOTGraphTraits {
1922 explicit DOTGraphTraits(bool Simple = false)
1924
1925 static bool renderNodesUsingHTML() { return true; }
1926 static std::string getGraphName(const DotCfgDiffDisplayGraph *DiffData) {
1927 return DiffData->getGraphName();
1928 }
1929 static std::string
1930 getGraphProperties(const DotCfgDiffDisplayGraph *DiffData) {
1931 return "\tsize=\"190, 190\";\n";
1932 }
1933 static std::string getNodeLabel(const DisplayNode *Node,
1934 const DotCfgDiffDisplayGraph *DiffData) {
1935 return DiffData->getNodeLabel(*Node);
1936 }
1937 static std::string getNodeAttributes(const DisplayNode *Node,
1938 const DotCfgDiffDisplayGraph *DiffData) {
1939 return DiffData->getNodeAttributes(*Node);
1940 }
1941 static std::string getEdgeSourceLabel(const DisplayNode *From,
1942 DisplayNode::ChildIterator &To) {
1943 return From->getEdgeSourceLabel(**To);
1944 }
1945 static std::string getEdgeAttributes(const DisplayNode *From,
1946 DisplayNode::ChildIterator &To,
1947 const DotCfgDiffDisplayGraph *DiffData) {
1948 return DiffData->getEdgeColorAttr(*From, **To);
1949 }
1950};
1951
1952} // namespace llvm
1953
1954namespace {
1955
1956void DotCfgDiffDisplayGraph::generateDotFile(StringRef DotFile) {
1957 std::error_code EC;
1958 raw_fd_ostream OutStream(DotFile, EC);
1959 if (EC) {
1960 errs() << "Error: " << EC.message() << "\n";
1961 return;
1962 }
1963 WriteGraph(OutStream, this, false);
1964 OutStream.flush();
1965 OutStream.close();
1966}
1967
1968} // namespace
1969
1970namespace llvm {
1971
1973 // Build up transition labels.
1974 const Instruction *Term = B.getTerminator();
1975 if (const BranchInst *Br = dyn_cast<const BranchInst>(Term))
1976 if (Br->isUnconditional())
1977 addSuccessorLabel(Br->getSuccessor(0)->getName().str(), "");
1978 else {
1979 addSuccessorLabel(Br->getSuccessor(0)->getName().str(), "true");
1980 addSuccessorLabel(Br->getSuccessor(1)->getName().str(), "false");
1981 }
1982 else if (const SwitchInst *Sw = dyn_cast<const SwitchInst>(Term)) {
1983 addSuccessorLabel(Sw->case_default()->getCaseSuccessor()->getName().str(),
1984 "default");
1985 for (auto &C : Sw->cases()) {
1986 assert(C.getCaseValue() && "Expected to find case value.");
1987 SmallString<20> Value = formatv("{0}", C.getCaseValue()->getSExtValue());
1988 addSuccessorLabel(C.getCaseSuccessor()->getName().str(), Value);
1989 }
1990 } else
1991 for (const_succ_iterator I = succ_begin(&B), E = succ_end(&B); I != E; ++I)
1992 addSuccessorLabel((*I)->getName().str(), "");
1993}
1994
1997
1999 StringRef Name, StringRef Prefix, StringRef PassID, StringRef Divider,
2000 bool InModule, unsigned Minor, const FuncDataT<DCData> &Before,
2001 const FuncDataT<DCData> &After) {
2002 assert(HTML && "Expected outstream to be set");
2003 SmallString<8> Extender;
2005 // Handle numbering and file names.
2006 if (InModule) {
2007 Extender = formatv("{0}_{1}", N, Minor);
2008 Number = formatv("{0}.{1}", N, Minor);
2009 } else {
2010 Extender = formatv("{0}", N);
2011 Number = formatv("{0}", N);
2012 }
2013 // Create a temporary file name for the dot file.
2015 sys::fs::createUniquePath("cfgdot-%%%%%%.dot", SV, true);
2016 std::string DotFile = Twine(SV).str();
2017
2018 SmallString<20> PDFFileName = formatv("diff_{0}.pdf", Extender);
2020
2021 Text = formatv("{0}.{1}{2}{3}{4}", Number, Prefix, makeHTMLReady(PassID),
2022 Divider, Name);
2023
2024 DotCfgDiff Diff(Text, Before, After);
2025 std::string EntryBlockName = After.getEntryBlockName();
2026 // Use the before entry block if the after entry block was removed.
2027 if (EntryBlockName == "")
2028 EntryBlockName = Before.getEntryBlockName();
2029 assert(EntryBlockName != "" && "Expected to find entry block");
2030
2031 DotCfgDiffDisplayGraph DG = Diff.createDisplayGraph(Text, EntryBlockName);
2032 DG.generateDotFile(DotFile);
2033
2034 *HTML << genHTML(Text, DotFile, PDFFileName);
2035 std::error_code EC = sys::fs::remove(DotFile);
2036 if (EC)
2037 errs() << "Error: " << EC.message() << "\n";
2038}
2039
2041 StringRef PDFFileName) {
2042 SmallString<20> PDFFile = formatv("{0}/{1}", DotCfgDir, PDFFileName);
2043 // Create the PDF file.
2045 if (!DotExe)
2046 return "Unable to find dot executable.";
2047
2048 StringRef Args[] = {DotBinary, "-Tpdf", "-o", PDFFile, DotFile};
2049 int Result = sys::ExecuteAndWait(*DotExe, Args, std::nullopt);
2050 if (Result < 0)
2051 return "Error executing system dot.";
2052
2053 // Create the HTML tag refering to the PDF file.
2055 " <a href=\"{0}\" target=\"_blank\">{1}</a><br/>\n", PDFFileName, Text);
2056 return S.c_str();
2057}
2058
2060 assert(HTML && "Expected outstream to be set");
2061 *HTML << "<button type=\"button\" class=\"collapsible\">0. "
2062 << "Initial IR (by function)</button>\n"
2063 << "<div class=\"content\">\n"
2064 << " <p>\n";
2065 // Create representation of IR
2068 // Now compare it against itself, which will have everything the
2069 // same and will generate the files.
2071 .compare(getModuleForComparison(IR),
2072 [&](bool InModule, unsigned Minor,
2073 const FuncDataT<DCData> &Before,
2074 const FuncDataT<DCData> &After) -> void {
2075 handleFunctionCompare("", " ", "Initial IR", "", InModule,
2076 Minor, Before, After);
2077 });
2078 *HTML << " </p>\n"
2079 << "</div><br/>\n";
2080 ++N;
2081}
2082
2086}
2087
2089 assert(HTML && "Expected outstream to be set");
2090 SmallString<20> Banner =
2091 formatv(" <a>{0}. Pass {1} on {2} omitted because no change</a><br/>\n",
2092 N, makeHTMLReady(PassID), Name);
2093 *HTML << Banner;
2094 ++N;
2095}
2096
2098 const IRDataT<DCData> &Before,
2099 const IRDataT<DCData> &After, Any IR) {
2100 assert(HTML && "Expected outstream to be set");
2101 IRComparer<DCData>(Before, After)
2102 .compare(getModuleForComparison(IR),
2103 [&](bool InModule, unsigned Minor,
2104 const FuncDataT<DCData> &Before,
2105 const FuncDataT<DCData> &After) -> void {
2106 handleFunctionCompare(Name, " Pass ", PassID, " on ", InModule,
2107 Minor, Before, After);
2108 });
2109 *HTML << " </p></div>\n";
2110 ++N;
2111}
2112
2114 assert(HTML && "Expected outstream to be set");
2115 SmallString<20> Banner =
2116 formatv(" <a>{0}. {1} invalidated</a><br/>\n", N, makeHTMLReady(PassID));
2117 *HTML << Banner;
2118 ++N;
2119}
2120
2122 assert(HTML && "Expected outstream to be set");
2123 SmallString<20> Banner =
2124 formatv(" <a>{0}. Pass {1} on {2} filtered out</a><br/>\n", N,
2125 makeHTMLReady(PassID), Name);
2126 *HTML << Banner;
2127 ++N;
2128}
2129
2131 assert(HTML && "Expected outstream to be set");
2132 SmallString<20> Banner = formatv(" <a>{0}. {1} on {2} ignored</a><br/>\n", N,
2133 makeHTMLReady(PassID), Name);
2134 *HTML << Banner;
2135 ++N;
2136}
2137
2139 std::error_code EC;
2140 HTML = std::make_unique<raw_fd_ostream>(DotCfgDir + "/passes.html", EC);
2141 if (EC) {
2142 HTML = nullptr;
2143 return false;
2144 }
2145
2146 *HTML << "<!doctype html>"
2147 << "<html>"
2148 << "<head>"
2149 << "<style>.collapsible { "
2150 << "background-color: #777;"
2151 << " color: white;"
2152 << " cursor: pointer;"
2153 << " padding: 18px;"
2154 << " width: 100%;"
2155 << " border: none;"
2156 << " text-align: left;"
2157 << " outline: none;"
2158 << " font-size: 15px;"
2159 << "} .active, .collapsible:hover {"
2160 << " background-color: #555;"
2161 << "} .content {"
2162 << " padding: 0 18px;"
2163 << " display: none;"
2164 << " overflow: hidden;"
2165 << " background-color: #f1f1f1;"
2166 << "}"
2167 << "</style>"
2168 << "<title>passes.html</title>"
2169 << "</head>\n"
2170 << "<body>";
2171 return true;
2172}
2173
2175 if (!HTML)
2176 return;
2177 *HTML
2178 << "<script>var coll = document.getElementsByClassName(\"collapsible\");"
2179 << "var i;"
2180 << "for (i = 0; i < coll.length; i++) {"
2181 << "coll[i].addEventListener(\"click\", function() {"
2182 << " this.classList.toggle(\"active\");"
2183 << " var content = this.nextElementSibling;"
2184 << " if (content.style.display === \"block\"){"
2185 << " content.style.display = \"none\";"
2186 << " }"
2187 << " else {"
2188 << " content.style.display= \"block\";"
2189 << " }"
2190 << " });"
2191 << " }"
2192 << "</script>"
2193 << "</body>"
2194 << "</html>\n";
2195 HTML->flush();
2196 HTML->close();
2197}
2198
2203 SmallString<128> OutputDir;
2204 sys::fs::expand_tilde(DotCfgDir, OutputDir);
2205 sys::fs::make_absolute(OutputDir);
2206 assert(!OutputDir.empty() && "expected output dir to be non-empty");
2207 DotCfgDir = OutputDir.c_str();
2208 if (initializeHTML()) {
2210 return;
2211 }
2212 dbgs() << "Unable to open output stream for -cfg-dot-changed\n";
2213 }
2214}
2215
2217 LLVMContext &Context, bool DebugLogging, bool VerifyEach,
2218 PrintPassOptions PrintPassOpts)
2219 : PrintPass(DebugLogging, PrintPassOpts),
2220 OptNone(DebugLogging),
2222 PrintChangedIR(PrintChanged == ChangePrinter::Verbose),
2223 PrintChangedDiff(PrintChanged == ChangePrinter::DiffVerbose ||
2227 WebsiteChangeReporter(PrintChanged == ChangePrinter::DotCfgVerbose),
2228 Verify(DebugLogging), VerifyEach(VerifyEach) {}
2229
2230PrintCrashIRInstrumentation *PrintCrashIRInstrumentation::CrashReporter =
2231 nullptr;
2232
2234 if (!PrintOnCrashPath.empty()) {
2235 std::error_code EC;
2237 if (EC)
2239 Out << SavedIR;
2240 } else {
2241 dbgs() << SavedIR;
2242 }
2243}
2244
2245void PrintCrashIRInstrumentation::SignalHandler(void *) {
2246 // Called by signal handlers so do not lock here
2247 // Is the PrintCrashIRInstrumentation still alive?
2248 if (!CrashReporter)
2249 return;
2250
2251 assert((PrintOnCrash || !PrintOnCrashPath.empty()) &&
2252 "Did not expect to get here without option set.");
2253 CrashReporter->reportCrashIR();
2254}
2255
2257 if (!CrashReporter)
2258 return;
2259
2260 assert((PrintOnCrash || !PrintOnCrashPath.empty()) &&
2261 "Did not expect to get here without option set.");
2262 CrashReporter = nullptr;
2263}
2264
2267 if ((!PrintOnCrash && PrintOnCrashPath.empty()) || CrashReporter)
2268 return;
2269
2270 sys::AddSignalHandler(SignalHandler, nullptr);
2271 CrashReporter = this;
2272
2274 [&PIC, this](StringRef PassID, Any IR) {
2275 SavedIR.clear();
2277 OS << formatv("*** Dump of {0}IR Before Last Pass {1}",
2278 llvm::forcePrintModuleIR() ? "Module " : "", PassID);
2279 if (!isInteresting(IR, PassID, PIC.getPassNameForClassName(PassID))) {
2280 OS << " Filtered Out ***\n";
2281 return;
2282 }
2283 OS << " Started ***\n";
2284 unwrapAndPrint(OS, IR);
2285 });
2286}
2287
2290 PrintIR.registerCallbacks(PIC);
2291 PrintPass.registerCallbacks(PIC);
2292 TimePasses.registerCallbacks(PIC);
2293 OptNone.registerCallbacks(PIC);
2294 OptPassGate.registerCallbacks(PIC);
2295 PrintChangedIR.registerCallbacks(PIC);
2296 PseudoProbeVerification.registerCallbacks(PIC);
2297 if (VerifyEach)
2298 Verify.registerCallbacks(PIC);
2299 PrintChangedDiff.registerCallbacks(PIC);
2300 WebsiteChangeReporter.registerCallbacks(PIC);
2301 ChangeTester.registerCallbacks(PIC);
2302 PrintCrashIR.registerCallbacks(PIC);
2303 if (MAM)
2304 PreservedCFGChecker.registerCallbacks(PIC, *MAM);
2305
2306 // TimeProfiling records the pass running time cost.
2307 // Its 'BeforePassCallback' can be appended at the tail of all the
2308 // BeforeCallbacks by calling `registerCallbacks` in the end.
2309 // Its 'AfterPassCallback' is put at the front of all the
2310 // AfterCallbacks by its `registerCallbacks`. This is necessary
2311 // to ensure that other callbacks are not included in the timings.
2312 TimeProfilingPasses.registerCallbacks(PIC);
2313}
2314
2315template class ChangeReporter<std::string>;
2316template class TextChangeReporter<std::string>;
2317
2318template class BlockDataT<EmptyData>;
2319template class FuncDataT<EmptyData>;
2320template class IRDataT<EmptyData>;
2321template class ChangeReporter<IRDataT<EmptyData>>;
2323template class IRComparer<EmptyData>;
2324
2325} // 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:1269
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.
Legalize the Machine IR a function s Machine IR
Definition: Legalizer.cpp:81
#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
#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< unsigned > PrintAtPassNumber("print-at-pass-number", cl::init(0), cl::Hidden, cl::desc("Print IR at pass with this number as " "reported by print-passes-names"))
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 > PrintOnCrash("print-on-crash", cl::desc("Print the last form of the IR before crash (use -print-on-crash-path to dump to a file)"), cl::Hidden)
static cl::opt< bool > PrintPassNumbers("print-pass-numbers", cl::init(false), cl::Hidden, cl::desc("Print pass names and their ordinals"))
static cl::opt< std::string > PrintOnCrashPath("print-on-crash-path", cl::desc("Print the last form of the IR before crash to a file"), 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:404
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:47
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:94
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:607
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:627
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:601
std::pair< StringRef, StringRef > rsplit(StringRef Separator) const
Split into two substrings around the last occurrence of a separator string.
Definition: StringRef.h:731
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:309
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:907
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:797
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)
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
Definition: STLExtras.h:1777
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:6511
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:1826
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:1976
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:976
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:6522
#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.