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