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