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