LLVM 23.0.0git
StandardInstrumentations.cpp
Go to the documentation of this file.
1//===- Standard pass instrumentations handling ----------------*- C++ -*--===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8/// \file
9///
10/// This file defines IR-printing pass instrumentation callbacks as well as
11/// StandardInstrumentations class that manages standard pass instrumentations.
12///
13//===----------------------------------------------------------------------===//
14
16#include "llvm/ADT/Any.h"
17#include "llvm/ADT/StringRef.h"
24#include "llvm/IR/Constants.h"
25#include "llvm/IR/Function.h"
26#include "llvm/IR/Module.h"
28#include "llvm/IR/PassManager.h"
29#include "llvm/IR/PrintPasses.h"
31#include "llvm/IR/Verifier.h"
33#include "llvm/Support/Debug.h"
34#include "llvm/Support/Error.h"
37#include "llvm/Support/Path.h"
39#include "llvm/Support/Regex.h"
42#include "llvm/Support/xxhash.h"
43#include <unordered_map>
44#include <unordered_set>
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(Any IR) {
144 const IRUnitT **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(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}
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);
224 }
226
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(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 }) ||
267
268bool sccContainsFilterPrintFunc(const LazyCallGraph::SCC &C) {
269 return any_of(C,
271 return isFunctionInPrintList(N.getName());
272 }) ||
275
276bool shouldPrintIR(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, 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(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.
375 if (isIgnored(PassID) || !isPassInPrintList(PassName))
376 return false;
377 if (const auto *F = unwrapIR<Function>(IR))
378 return isInterestingFunction(*F);
379 return true;
381
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([&PIC, this](StringRef P, Any IR) {
458 saveIRBeforePass(IR, P, PIC.getPassNameForClassName(P));
459 });
460
461 PIC.registerAfterPassCallback(
462 [&PIC, this](StringRef P, Any IR, const PreservedAnalyses &) {
463 handleIRAfterPass(IR, P, PIC.getPassNameForClassName(P));
464 });
465 PIC.registerAfterPassInvalidatedCallback(
466 [this](StringRef P, const PreservedAnalyses &) {
468 });
469}
470
471template <typename T>
474
475template <typename T> void TextChangeReporter<T>::handleInitialIR(Any IR) {
476 // Always print the module.
477 // Unwrap and print directly to avoid filtering problems in general routines.
478 auto *M = unwrapModule(IR, /*Force=*/true);
479 assert(M && "Expected module to be unwrapped when forced.");
480 Out << "*** IR Dump At Start ***\n";
481 M->print(Out, nullptr);
482}
483
484template <typename T>
485void TextChangeReporter<T>::omitAfter(StringRef PassID, std::string &Name) {
486 Out << formatv("*** IR Dump After {0} on {1} omitted because no change ***\n",
487 PassID, Name);
488}
489
490template <typename T>
492 Out << formatv("*** IR Pass {0} invalidated ***\n", PassID);
493}
494
495template <typename T>
497 std::string &Name) {
498 SmallString<20> Banner =
499 formatv("*** IR Dump After {0} on {1} filtered out ***\n", PassID, Name);
500 Out << Banner;
501}
502
503template <typename T>
504void TextChangeReporter<T>::handleIgnored(StringRef PassID, std::string &Name) {
505 Out << formatv("*** IR Pass {0} on {1} ignored ***\n", PassID, Name);
506}
507
509
515
517 std::string &Output) {
518 raw_string_ostream OS(Output);
519 unwrapAndPrint(OS, IR);
520 OS.str();
521}
522
523void IRChangedPrinter::handleAfter(StringRef PassID, std::string &Name,
524 const std::string &Before,
525 const std::string &After, Any) {
526 // Report the IR before the changes when requested.
528 Out << "*** IR Dump Before " << PassID << " on " << Name << " ***\n"
529 << Before;
530
531 // We might not get anything to print if we only want to print a specific
532 // function but it gets deleted.
533 if (After.empty()) {
534 Out << "*** IR Deleted After " << PassID << " on " << Name << " ***\n";
535 return;
536 }
537
538 Out << "*** IR Dump After " << PassID << " on " << Name << " ***\n" << After;
539}
540
542
547
548void IRChangedTester::handleIR(const std::string &S, StringRef PassID) {
549 // Store the body into a temporary file
550 static SmallVector<int> FD{-1};
552 static SmallVector<std::string> FileName{""};
553 if (prepareTempFiles(FD, SR, FileName)) {
554 dbgs() << "Unable to create temporary file.";
555 return;
556 }
557 static ErrorOr<std::string> Exe = sys::findProgramByName(TestChanged);
558 if (!Exe) {
559 dbgs() << "Unable to find test-changed executable.";
560 return;
561 }
562
563 StringRef Args[] = {TestChanged, FileName[0], PassID};
564 int Result = sys::ExecuteAndWait(*Exe, Args);
565 if (Result < 0) {
566 dbgs() << "Error executing test-changed executable.";
567 return;
568 }
569
570 if (cleanUpTempFiles(FileName))
571 dbgs() << "Unable to remove temporary file.";
572}
573
575 // Always test the initial module.
576 // Unwrap and print directly to avoid filtering problems in general routines.
577 std::string S;
578 generateIRRepresentation(IR, "Initial IR", S);
579 handleIR(S, "Initial IR");
580}
581
582void IRChangedTester::omitAfter(StringRef PassID, std::string &Name) {}
584void IRChangedTester::handleFiltered(StringRef PassID, std::string &Name) {}
585void IRChangedTester::handleIgnored(StringRef PassID, std::string &Name) {}
586void IRChangedTester::handleAfter(StringRef PassID, std::string &Name,
587 const std::string &Before,
588 const std::string &After, Any) {
589 handleIR(After, PassID);
590}
591
592template <typename T>
594 const OrderedChangedData &Before, const OrderedChangedData &After,
595 function_ref<void(const T *, const T *)> HandlePair) {
596 const auto &BFD = Before.getData();
597 const auto &AFD = After.getData();
598 std::vector<std::string>::const_iterator BI = Before.getOrder().begin();
599 std::vector<std::string>::const_iterator BE = Before.getOrder().end();
600 std::vector<std::string>::const_iterator AI = After.getOrder().begin();
601 std::vector<std::string>::const_iterator AE = After.getOrder().end();
602
603 auto HandlePotentiallyRemovedData = [&](std::string S) {
604 // The order in LLVM may have changed so check if still exists.
605 if (!AFD.count(S)) {
606 // This has been removed.
607 HandlePair(&BFD.find(*BI)->getValue(), nullptr);
608 }
609 };
610 auto HandleNewData = [&](std::vector<const T *> &Q) {
611 // Print out any queued up new sections
612 for (const T *NBI : Q)
613 HandlePair(nullptr, NBI);
614 Q.clear();
615 };
616
617 // Print out the data in the after order, with before ones interspersed
618 // appropriately (ie, somewhere near where they were in the before list).
619 // Start at the beginning of both lists. Loop through the
620 // after list. If an element is common, then advance in the before list
621 // reporting the removed ones until the common one is reached. Report any
622 // queued up new ones and then report the common one. If an element is not
623 // common, then enqueue it for reporting. When the after list is exhausted,
624 // loop through the before list, reporting any removed ones. Finally,
625 // report the rest of the enqueued new ones.
626 std::vector<const T *> NewDataQueue;
627 while (AI != AE) {
628 if (!BFD.count(*AI)) {
629 // This section is new so place it in the queue. This will cause it
630 // to be reported after deleted sections.
631 NewDataQueue.emplace_back(&AFD.find(*AI)->getValue());
632 ++AI;
633 continue;
634 }
635 // This section is in both; advance and print out any before-only
636 // until we get to it.
637 // It's possible that this section has moved to be later than before. This
638 // will mess up printing most blocks side by side, but it's a rare case and
639 // it's better than crashing.
640 while (BI != BE && *BI != *AI) {
641 HandlePotentiallyRemovedData(*BI);
642 ++BI;
643 }
644 // Report any new sections that were queued up and waiting.
645 HandleNewData(NewDataQueue);
646
647 const T &AData = AFD.find(*AI)->getValue();
648 const T &BData = BFD.find(*AI)->getValue();
649 HandlePair(&BData, &AData);
650 if (BI != BE)
651 ++BI;
652 ++AI;
653 }
654
655 // Check any remaining before sections to see if they have been removed
656 while (BI != BE) {
657 HandlePotentiallyRemovedData(*BI);
658 ++BI;
659 }
660
661 HandleNewData(NewDataQueue);
662}
663
664template <typename T>
666 bool CompareModule,
667 std::function<void(bool InModule, unsigned Minor,
668 const FuncDataT<T> &Before, const FuncDataT<T> &After)>
669 CompareFunc) {
670 if (!CompareModule) {
671 // Just handle the single function.
672 assert(Before.getData().size() == 1 && After.getData().size() == 1 &&
673 "Expected only one function.");
674 CompareFunc(false, 0, Before.getData().begin()->getValue(),
675 After.getData().begin()->getValue());
676 return;
677 }
678
679 unsigned Minor = 0;
680 FuncDataT<T> Missing("");
682 [&](const FuncDataT<T> *B, const FuncDataT<T> *A) {
683 assert((B || A) && "Both functions cannot be missing.");
684 if (!B)
685 B = &Missing;
686 else if (!A)
687 A = &Missing;
688 CompareFunc(true, Minor++, *B, *A);
689 });
690}
691
692template <typename T> void IRComparer<T>::analyzeIR(Any IR, IRDataT<T> &Data) {
693 if (const Module *M = getModuleForComparison(IR)) {
694 // Create data for each existing/interesting function in the module.
695 for (const Function &F : *M)
697 return;
698 }
699
700 if (const auto *F = unwrapIR<Function>(IR)) {
702 return;
703 }
704
705 if (const auto *L = unwrapIR<Loop>(IR)) {
706 auto *F = L->getHeader()->getParent();
708 return;
709 }
710
711 if (const auto *MF = unwrapIR<MachineFunction>(IR)) {
713 return;
714 }
715
716 llvm_unreachable("Unknown IR unit");
717}
718
719static bool shouldGenerateData(const Function &F) {
720 return !F.isDeclaration() && isFunctionInPrintList(F.getName());
721}
722
723static bool shouldGenerateData(const MachineFunction &MF) {
724 return isFunctionInPrintList(MF.getName());
725}
726
727template <typename T>
728template <typename FunctionT>
730 if (shouldGenerateData(F)) {
731 FuncDataT<T> FD(F.front().getName().str());
732 int I = 0;
733 for (const auto &B : F) {
734 std::string BBName = B.getName().str();
735 if (BBName.empty()) {
736 BBName = formatv("{0}", I);
737 ++I;
738 }
739 FD.getOrder().emplace_back(BBName);
740 FD.getData().insert({BBName, B});
741 }
742 Data.getOrder().emplace_back(F.getName());
743 Data.getData().insert({F.getName(), FD});
744 return true;
745 }
746 return false;
747}
748
750 assert(PassRunDescriptorStack.empty() &&
751 "PassRunDescriptorStack is not empty at exit");
752}
753
754static void writeIRFileDisplayName(raw_ostream &ResultStream, Any IR) {
755 const Module *M = unwrapModule(IR, /*Force=*/true);
756 assert(M && "should have unwrapped module");
757 uint64_t NameHash = xxh3_64bits(M->getName());
758 unsigned MaxHashWidth = sizeof(uint64_t) * 2;
759 write_hex(ResultStream, NameHash, HexPrintStyle::Lower, MaxHashWidth);
760 if (unwrapIR<Module>(IR)) {
761 ResultStream << "-module";
762 } else if (const auto *F = unwrapIR<Function>(IR)) {
763 ResultStream << "-function-";
764 auto FunctionNameHash = xxh3_64bits(F->getName());
765 write_hex(ResultStream, FunctionNameHash, HexPrintStyle::Lower,
766 MaxHashWidth);
767 } else if (const auto *C = unwrapIR<LazyCallGraph::SCC>(IR)) {
768 ResultStream << "-scc-";
769 auto SCCNameHash = xxh3_64bits(C->getName());
770 write_hex(ResultStream, SCCNameHash, HexPrintStyle::Lower, MaxHashWidth);
771 } else if (const auto *L = unwrapIR<Loop>(IR)) {
772 ResultStream << "-loop-";
773 auto LoopNameHash = xxh3_64bits(L->getName());
774 write_hex(ResultStream, LoopNameHash, HexPrintStyle::Lower, MaxHashWidth);
775 } else if (const auto *MF = unwrapIR<MachineFunction>(IR)) {
776 ResultStream << "-machine-function-";
777 auto MachineFunctionNameHash = xxh3_64bits(MF->getName());
778 write_hex(ResultStream, MachineFunctionNameHash, HexPrintStyle::Lower,
779 MaxHashWidth);
780 } else {
781 llvm_unreachable("Unknown wrapped IR type");
782 }
783}
784
785static std::string getIRFileDisplayName(Any IR) {
786 std::string Result;
787 raw_string_ostream ResultStream(Result);
788 writeIRFileDisplayName(ResultStream, IR);
789 return Result;
790}
791
792StringRef PrintIRInstrumentation::getFileSuffix(IRDumpFileSuffixType Type) {
793 static constexpr std::array FileSuffixes = {"-before.ll", "-after.ll",
794 "-invalidated.ll"};
795 return FileSuffixes[static_cast<size_t>(Type)];
796}
797
798std::string PrintIRInstrumentation::fetchDumpFilename(
799 StringRef PassName, StringRef IRFileDisplayName, unsigned PassNumber,
800 IRDumpFileSuffixType SuffixType) {
801 assert(!IRDumpDirectory.empty() &&
802 "The flag -ir-dump-directory must be passed to dump IR to files");
803
804 SmallString<64> Filename;
805 raw_svector_ostream FilenameStream(Filename);
806 FilenameStream << PassNumber;
807 FilenameStream << '-' << IRFileDisplayName << '-';
808 FilenameStream << PassName;
809 FilenameStream << getFileSuffix(SuffixType);
810
811 SmallString<128> ResultPath;
813 return std::string(ResultPath);
814}
815
816void PrintIRInstrumentation::pushPassRunDescriptor(StringRef PassID, Any IR,
817 unsigned PassNumber) {
818 const Module *M = unwrapModule(IR);
819 PassRunDescriptorStack.emplace_back(M, PassNumber, getIRFileDisplayName(IR),
820 getIRName(IR), PassID);
821}
822
823PrintIRInstrumentation::PassRunDescriptor
824PrintIRInstrumentation::popPassRunDescriptor(StringRef PassID) {
825 assert(!PassRunDescriptorStack.empty() && "empty PassRunDescriptorStack");
826 PassRunDescriptor Descriptor = PassRunDescriptorStack.pop_back_val();
827 assert(Descriptor.PassID == PassID && "malformed PassRunDescriptorStack");
828 return Descriptor;
829}
830
831// Callers are responsible for closing the returned file descriptor
832static int prepareDumpIRFileDescriptor(const StringRef DumpIRFilename) {
833 std::error_code EC;
834 auto ParentPath = llvm::sys::path::parent_path(DumpIRFilename);
835 if (!ParentPath.empty()) {
836 std::error_code EC = llvm::sys::fs::create_directories(ParentPath);
837 if (EC)
838 report_fatal_error(Twine("Failed to create directory ") + ParentPath +
839 " to support -ir-dump-directory: " + EC.message());
840 }
841 int Result = 0;
842 EC = sys::fs::openFile(DumpIRFilename, Result, sys::fs::CD_OpenAlways,
844 if (EC)
845 report_fatal_error(Twine("Failed to open ") + DumpIRFilename +
846 " to support -ir-dump-directory: " + EC.message());
847 return Result;
848}
849
850void PrintIRInstrumentation::printBeforePass(StringRef PassID, Any IR) {
851 if (isIgnored(PassID))
852 return;
853
854 // Saving Module for AfterPassInvalidated operations.
855 // Note: here we rely on a fact that we do not change modules while
856 // traversing the pipeline, so the latest captured module is good
857 // for all print operations that has not happen yet.
858 if (shouldPrintAfterPass(PassID))
859 pushPassRunDescriptor(PassID, IR, CurrentPassNumber);
860
861 if (!shouldPrintIR(IR))
862 return;
863
864 ++CurrentPassNumber;
865
866 if (shouldPrintPassNumbers())
867 dbgs() << " Running pass " << CurrentPassNumber << " " << PassID
868 << " on " << getIRName(IR) << "\n";
869
870 if (shouldPrintAfterCurrentPassNumber())
871 pushPassRunDescriptor(PassID, IR, CurrentPassNumber);
872
873 if (!shouldPrintBeforePass(PassID) && !shouldPrintBeforeCurrentPassNumber())
874 return;
875
876 auto WriteIRToStream = [&](raw_ostream &Stream) {
877 Stream << "; *** IR Dump Before ";
878 if (shouldPrintBeforeSomePassNumber())
879 Stream << CurrentPassNumber << "-";
880 Stream << PassID << " on " << getIRName(IR) << " ***\n";
881 unwrapAndPrint(Stream, IR);
882 };
883
884 if (!IRDumpDirectory.empty()) {
885 std::string DumpIRFilename =
886 fetchDumpFilename(PassID, getIRFileDisplayName(IR), CurrentPassNumber,
887 IRDumpFileSuffixType::Before);
888 llvm::raw_fd_ostream DumpIRFileStream{
889 prepareDumpIRFileDescriptor(DumpIRFilename), /* shouldClose */ true};
890 WriteIRToStream(DumpIRFileStream);
891 } else {
892 WriteIRToStream(dbgs());
893 }
894}
895
896void PrintIRInstrumentation::printAfterPass(StringRef PassID, Any IR) {
897 if (isIgnored(PassID))
898 return;
899
900 if (!shouldPrintAfterPass(PassID) && !shouldPrintAfterCurrentPassNumber())
901 return;
902
903 auto [M, PassNumber, IRFileDisplayName, IRName, StoredPassID] =
904 popPassRunDescriptor(PassID);
905 assert(StoredPassID == PassID && "mismatched PassID");
906
907 if (!shouldPrintIR(IR) ||
908 (!shouldPrintAfterPass(PassID) && !shouldPrintAfterCurrentPassNumber()))
909 return;
910
911 auto WriteIRToStream = [&](raw_ostream &Stream, const StringRef IRName) {
912 Stream << "; *** IR Dump After ";
913 if (shouldPrintAfterSomePassNumber())
914 Stream << CurrentPassNumber << "-";
915 Stream << StringRef(formatv("{0}", PassID)) << " on " << IRName << " ***\n";
916 unwrapAndPrint(Stream, IR);
917 };
918
919 if (!IRDumpDirectory.empty()) {
920 std::string DumpIRFilename =
921 fetchDumpFilename(PassID, getIRFileDisplayName(IR), CurrentPassNumber,
922 IRDumpFileSuffixType::After);
923 llvm::raw_fd_ostream DumpIRFileStream{
924 prepareDumpIRFileDescriptor(DumpIRFilename),
925 /* shouldClose */ true};
926 WriteIRToStream(DumpIRFileStream, IRName);
927 } else {
928 WriteIRToStream(dbgs(), IRName);
929 }
930}
931
932void PrintIRInstrumentation::printAfterPassInvalidated(StringRef PassID) {
933 if (isIgnored(PassID))
934 return;
935
936 if (!shouldPrintAfterPass(PassID) && !shouldPrintAfterCurrentPassNumber())
937 return;
938
939 auto [M, PassNumber, IRFileDisplayName, IRName, StoredPassID] =
940 popPassRunDescriptor(PassID);
941 assert(StoredPassID == PassID && "mismatched PassID");
942 // Additional filtering (e.g. -filter-print-func) can lead to module
943 // printing being skipped.
944 if (!M ||
945 (!shouldPrintAfterPass(PassID) && !shouldPrintAfterCurrentPassNumber()))
946 return;
947
948 auto WriteIRToStream = [&](raw_ostream &Stream, const Module *M,
949 const StringRef IRName) {
950 SmallString<20> Banner;
951 Banner = formatv("; *** IR Dump After {0} on {1} (invalidated) ***", PassID,
952 IRName);
953 Stream << Banner << "\n";
954 printIR(Stream, M);
955 };
956
957 if (!IRDumpDirectory.empty()) {
958 std::string DumpIRFilename =
959 fetchDumpFilename(PassID, IRFileDisplayName, PassNumber,
960 IRDumpFileSuffixType::Invalidated);
961 llvm::raw_fd_ostream DumpIRFileStream{
962 prepareDumpIRFileDescriptor(DumpIRFilename),
963 /*shouldClose=*/true};
964 WriteIRToStream(DumpIRFileStream, M, IRName);
965 } else {
966 WriteIRToStream(dbgs(), M, IRName);
967 }
968}
969
970bool PrintIRInstrumentation::shouldPrintBeforePass(StringRef PassID) {
972 return true;
973
974 StringRef PassName = PIC->getPassNameForClassName(PassID);
976}
977
978bool PrintIRInstrumentation::shouldPrintAfterPass(StringRef PassID) {
980 return true;
981
982 StringRef PassName = PIC->getPassNameForClassName(PassID);
984}
985
986bool PrintIRInstrumentation::shouldPrintBeforeCurrentPassNumber() {
987 return shouldPrintBeforeSomePassNumber() &&
988 (is_contained(PrintBeforePassNumber, CurrentPassNumber));
989}
990
991bool PrintIRInstrumentation::shouldPrintAfterCurrentPassNumber() {
992 return shouldPrintAfterSomePassNumber() &&
993 (is_contained(PrintAfterPassNumber, CurrentPassNumber));
994}
995
996bool PrintIRInstrumentation::shouldPrintPassNumbers() {
997 return PrintPassNumbers;
998}
999
1000bool PrintIRInstrumentation::shouldPrintBeforeSomePassNumber() {
1001 return !PrintBeforePassNumber.empty();
1002}
1003
1004bool PrintIRInstrumentation::shouldPrintAfterSomePassNumber() {
1005 return !PrintAfterPassNumber.empty();
1006}
1007
1010 this->PIC = &PIC;
1011
1012 // BeforePass callback is not just for printing, it also saves a Module
1013 // for later use in AfterPassInvalidated and keeps tracks of the
1014 // CurrentPassNumber.
1015 if (shouldPrintPassNumbers() || shouldPrintBeforeSomePassNumber() ||
1016 shouldPrintAfterSomePassNumber() || shouldPrintBeforeSomePass() ||
1019 [this](StringRef P, Any IR) { this->printBeforePass(P, IR); });
1020
1021 if (shouldPrintAfterSomePass() || shouldPrintAfterSomePassNumber()) {
1022 PIC.registerAfterPassCallback(
1023 [this](StringRef P, Any IR, const PreservedAnalyses &) {
1024 this->printAfterPass(P, IR);
1025 });
1026 PIC.registerAfterPassInvalidatedCallback(
1027 [this](StringRef P, const PreservedAnalyses &) {
1028 this->printAfterPassInvalidated(P);
1029 });
1030 }
1031}
1032
1035 PIC.registerShouldRunOptionalPassCallback(
1036 [this](StringRef P, Any IR) { return this->shouldRun(P, IR); });
1037}
1038
1039bool OptNoneInstrumentation::shouldRun(StringRef PassID, Any IR) {
1040 bool ShouldRun = true;
1041 if (const auto *F = unwrapIR<Function>(IR))
1042 ShouldRun = !F->hasOptNone();
1043 else if (const auto *L = unwrapIR<Loop>(IR))
1044 ShouldRun = !L->getHeader()->getParent()->hasOptNone();
1045 else if (const auto *MF = unwrapIR<MachineFunction>(IR))
1046 ShouldRun = !MF->getFunction().hasOptNone();
1047
1048 if (!ShouldRun && DebugLogging) {
1049 errs() << "Skipping pass " << PassID << " on " << getIRName(IR)
1050 << " due to optnone attribute\n";
1051 }
1052 return ShouldRun;
1053}
1054
1056 if (isIgnored(PassName))
1057 return true;
1058
1059 bool ShouldRun =
1060 Context.getOptPassGate().shouldRunPass(PassName, getIRName(IR));
1061 if (!ShouldRun && !this->HasWrittenIR && !OptBisectPrintIRPath.empty()) {
1062 // FIXME: print IR if limit is higher than number of opt-bisect
1063 // invocations
1064 this->HasWrittenIR = true;
1065 const Module *M = unwrapModule(IR, /*Force=*/true);
1066 assert((M && &M->getContext() == &Context) && "Missing/Mismatching Module");
1067 std::error_code EC;
1069 if (EC)
1071 M->print(OS, nullptr);
1072 }
1073 return ShouldRun;
1074}
1075
1078 const OptPassGate &PassGate = Context.getOptPassGate();
1079 if (!PassGate.isEnabled())
1080 return;
1081
1082 PIC.registerShouldRunOptionalPassCallback(
1083 [this, &PIC](StringRef ClassName, Any IR) {
1084 StringRef PassName = PIC.getPassNameForClassName(ClassName);
1085 if (PassName.empty())
1086 return this->shouldRun(ClassName, IR);
1087 return this->shouldRun(PassName, IR);
1088 });
1089}
1090
1091raw_ostream &PrintPassInstrumentation::print() {
1092 if (Opts.Indent) {
1093 assert(Indent >= 0);
1094 dbgs().indent(Indent);
1095 }
1096 return dbgs();
1097}
1098
1101 if (!Enabled)
1102 return;
1103
1104 std::vector<StringRef> SpecialPasses;
1105 if (!Opts.Verbose) {
1106 SpecialPasses.emplace_back("PassManager");
1107 SpecialPasses.emplace_back("PassAdaptor");
1108 }
1109
1110 PIC.registerBeforeSkippedPassCallback([this, SpecialPasses](StringRef PassID,
1111 Any IR) {
1112 assert(!isSpecialPass(PassID, SpecialPasses) &&
1113 "Unexpectedly skipping special pass");
1114
1115 print() << "Skipping pass: " << PassID << " on " << getIRName(IR) << "\n";
1116 });
1117 PIC.registerBeforeNonSkippedPassCallback([this, SpecialPasses](
1118 StringRef PassID, Any IR) {
1119 if (isSpecialPass(PassID, SpecialPasses))
1120 return;
1121
1122 auto &OS = print();
1123 OS << "Running pass: " << PassID << " on " << getIRName(IR);
1124 if (const auto *F = unwrapIR<Function>(IR)) {
1125 unsigned Count = F->getInstructionCount();
1126 OS << " (" << Count << " instruction";
1127 if (Count != 1)
1128 OS << 's';
1129 OS << ')';
1130 } else if (const auto *C = unwrapIR<LazyCallGraph::SCC>(IR)) {
1131 int Count = C->size();
1132 OS << " (" << Count << " node";
1133 if (Count != 1)
1134 OS << 's';
1135 OS << ')';
1136 }
1137 OS << "\n";
1138 Indent += 2;
1139 });
1140 PIC.registerAfterPassCallback(
1141 [this, SpecialPasses](StringRef PassID, Any IR,
1142 const PreservedAnalyses &) {
1143 if (isSpecialPass(PassID, SpecialPasses))
1144 return;
1145
1146 Indent -= 2;
1147 });
1148 PIC.registerAfterPassInvalidatedCallback(
1149 [this, SpecialPasses](StringRef PassID, Any IR) {
1150 if (isSpecialPass(PassID, SpecialPasses))
1151 return;
1152
1153 Indent -= 2;
1154 });
1155
1156 if (!Opts.SkipAnalyses) {
1157 PIC.registerBeforeAnalysisCallback([this](StringRef PassID, Any IR) {
1158 print() << "Running analysis: " << PassID << " on " << getIRName(IR)
1159 << "\n";
1160 Indent += 2;
1161 });
1162 PIC.registerAfterAnalysisCallback(
1163 [this](StringRef PassID, Any IR) { Indent -= 2; });
1164 PIC.registerAnalysisInvalidatedCallback([this](StringRef PassID, Any IR) {
1165 print() << "Invalidating analysis: " << PassID << " on " << getIRName(IR)
1166 << "\n";
1167 });
1168 PIC.registerAnalysesClearedCallback([this](StringRef IRName) {
1169 print() << "Clearing all analysis results for: " << IRName << "\n";
1170 });
1171 }
1172}
1173
1175 bool TrackBBLifetime) {
1176 if (TrackBBLifetime)
1178 for (const auto &BB : *F) {
1179 if (BBGuards)
1180 BBGuards->try_emplace(intptr_t(&BB), &BB);
1181 for (const auto *Succ : successors(&BB)) {
1182 Graph[&BB][Succ]++;
1183 if (BBGuards)
1184 BBGuards->try_emplace(intptr_t(Succ), Succ);
1185 }
1186 }
1187}
1188
1189static void printBBName(raw_ostream &out, const BasicBlock *BB) {
1190 if (BB->hasName()) {
1191 out << BB->getName() << "<" << BB << ">";
1192 return;
1193 }
1194
1195 if (!BB->getParent()) {
1196 out << "unnamed_removed<" << BB << ">";
1197 return;
1198 }
1199
1200 if (BB->isEntryBlock()) {
1201 out << "entry"
1202 << "<" << BB << ">";
1203 return;
1204 }
1205
1206 unsigned FuncOrderBlockNum = 0;
1207 for (auto &FuncBB : *BB->getParent()) {
1208 if (&FuncBB == BB)
1209 break;
1210 FuncOrderBlockNum++;
1211 }
1212 out << "unnamed_" << FuncOrderBlockNum << "<" << BB << ">";
1213}
1214
1216 const CFG &Before,
1217 const CFG &After) {
1218 assert(!After.isPoisoned());
1219 if (Before.isPoisoned()) {
1220 out << "Some blocks were deleted\n";
1221 return;
1222 }
1223
1224 // Find and print graph differences.
1225 if (Before.Graph.size() != After.Graph.size())
1226 out << "Different number of non-leaf basic blocks: before="
1227 << Before.Graph.size() << ", after=" << After.Graph.size() << "\n";
1228
1229 for (auto &BB : Before.Graph) {
1230 auto BA = After.Graph.find(BB.first);
1231 if (BA == After.Graph.end()) {
1232 out << "Non-leaf block ";
1233 printBBName(out, BB.first);
1234 out << " is removed (" << BB.second.size() << " successors)\n";
1235 }
1236 }
1237
1238 for (auto &BA : After.Graph) {
1239 auto BB = Before.Graph.find(BA.first);
1240 if (BB == Before.Graph.end()) {
1241 out << "Non-leaf block ";
1242 printBBName(out, BA.first);
1243 out << " is added (" << BA.second.size() << " successors)\n";
1244 continue;
1245 }
1246
1247 if (BB->second == BA.second)
1248 continue;
1249
1250 out << "Different successors of block ";
1251 printBBName(out, BA.first);
1252 out << " (unordered):\n";
1253 out << "- before (" << BB->second.size() << "): ";
1254 for (auto &SuccB : BB->second) {
1255 printBBName(out, SuccB.first);
1256 if (SuccB.second != 1)
1257 out << "(" << SuccB.second << "), ";
1258 else
1259 out << ", ";
1260 }
1261 out << "\n";
1262 out << "- after (" << BA.second.size() << "): ";
1263 for (auto &SuccA : BA.second) {
1264 printBBName(out, SuccA.first);
1265 if (SuccA.second != 1)
1266 out << "(" << SuccA.second << "), ";
1267 else
1268 out << ", ";
1269 }
1270 out << "\n";
1271 }
1272}
1273
1274// PreservedCFGCheckerInstrumentation uses PreservedCFGCheckerAnalysis to check
1275// passes, that reported they kept CFG analyses up-to-date, did not actually
1276// change CFG. This check is done as follows. Before every functional pass in
1277// BeforeNonSkippedPassCallback a CFG snapshot (an instance of
1278// PreservedCFGCheckerInstrumentation::CFG) is requested from
1279// FunctionAnalysisManager as a result of PreservedCFGCheckerAnalysis. When the
1280// functional pass finishes and reports that CFGAnalyses or AllAnalyses are
1281// up-to-date then the cached result of PreservedCFGCheckerAnalysis (if
1282// available) is checked to be equal to a freshly created CFG snapshot.
1284 : public AnalysisInfoMixin<PreservedCFGCheckerAnalysis> {
1286
1288
1289public:
1290 /// Provide the result type for this analysis pass.
1292
1293 /// Run the analysis pass over a function and produce CFG.
1295 return Result(&F, /* TrackBBLifetime */ true);
1296 }
1297};
1298
1300
1302 : public AnalysisInfoMixin<PreservedFunctionHashAnalysis> {
1304
1308
1310
1314};
1315
1317
1319 : public AnalysisInfoMixin<PreservedModuleHashAnalysis> {
1321
1322 struct ModuleHash {
1324 };
1325
1327
1331};
1332
1334
1336 Function &F, const PreservedAnalyses &PA,
1337 FunctionAnalysisManager::Invalidator &) {
1338 auto PAC = PA.getChecker<PreservedCFGCheckerAnalysis>();
1339 return !(PAC.preserved() || PAC.preservedSet<AllAnalysesOn<Function>>() ||
1340 PAC.preservedSet<CFGAnalyses>());
1341}
1342
1345
1346 if (const auto *MaybeF = unwrapIR<Function>(IR)) {
1347 Functions.push_back(const_cast<Function *>(MaybeF));
1348 } else if (const auto *MaybeM = unwrapIR<Module>(IR)) {
1349 for (Function &F : *const_cast<Module *>(MaybeM))
1350 Functions.push_back(&F);
1351 }
1352 return Functions;
1353}
1354
1358 return;
1359
1360 bool Registered = false;
1361 PIC.registerBeforeNonSkippedPassCallback([this, &MAM, Registered](
1362 StringRef P, Any IR) mutable {
1363#if LLVM_ENABLE_ABI_BREAKING_CHECKS
1364 assert(&PassStack.emplace_back(P));
1365#endif
1366 (void)this;
1367
1368 auto &FAM = MAM.getResult<FunctionAnalysisManagerModuleProxy>(
1369 *const_cast<Module *>(unwrapModule(IR, /*Force=*/true)))
1370 .getManager();
1371 if (!Registered) {
1372 FAM.registerPass([&] { return PreservedCFGCheckerAnalysis(); });
1373 FAM.registerPass([&] { return PreservedFunctionHashAnalysis(); });
1374 MAM.registerPass([&] { return PreservedModuleHashAnalysis(); });
1375 Registered = true;
1376 }
1377
1378 for (Function *F : GetFunctions(IR)) {
1379 // Make sure a fresh CFG snapshot is available before the pass.
1380 FAM.getResult<PreservedCFGCheckerAnalysis>(*F);
1381 FAM.getResult<PreservedFunctionHashAnalysis>(*F);
1382 }
1383
1384 if (const auto *MPtr = unwrapIR<Module>(IR)) {
1385 auto &M = *const_cast<Module *>(MPtr);
1386 MAM.getResult<PreservedModuleHashAnalysis>(M);
1387 }
1388 });
1389
1390 PIC.registerAfterPassInvalidatedCallback(
1391 [this](StringRef P, const PreservedAnalyses &PassPA) {
1392#if LLVM_ENABLE_ABI_BREAKING_CHECKS
1393 assert(PassStack.pop_back_val() == P &&
1394 "Before and After callbacks must correspond");
1395#endif
1396 (void)this;
1397 });
1398
1399 PIC.registerAfterPassCallback([this, &MAM](StringRef P, Any IR,
1400 const PreservedAnalyses &PassPA) {
1401#if LLVM_ENABLE_ABI_BREAKING_CHECKS
1402 assert(PassStack.pop_back_val() == P &&
1403 "Before and After callbacks must correspond");
1404#endif
1405 (void)this;
1406
1407 // We have to get the FAM via the MAM, rather than directly use a passed in
1408 // FAM because if MAM has not cached the FAM, it won't invalidate function
1409 // analyses in FAM.
1410 auto &FAM = MAM.getResult<FunctionAnalysisManagerModuleProxy>(
1411 *const_cast<Module *>(unwrapModule(IR, /*Force=*/true)))
1412 .getManager();
1413
1414 for (Function *F : GetFunctions(IR)) {
1415 if (auto *HashBefore =
1416 FAM.getCachedResult<PreservedFunctionHashAnalysis>(*F)) {
1417 if (HashBefore->Hash != StructuralHash(*F)) {
1419 "Function @{0} changed by {1} without invalidating analyses",
1420 F->getName(), P));
1421 }
1422 }
1423
1424 auto CheckCFG = [](StringRef Pass, StringRef FuncName,
1425 const CFG &GraphBefore, const CFG &GraphAfter) {
1426 if (GraphAfter == GraphBefore)
1427 return;
1428
1429 dbgs()
1430 << "Error: " << Pass
1431 << " does not invalidate CFG analyses but CFG changes detected in "
1432 "function @"
1433 << FuncName << ":\n";
1434 CFG::printDiff(dbgs(), GraphBefore, GraphAfter);
1435 report_fatal_error(Twine("CFG unexpectedly changed by ", Pass));
1436 };
1437
1438 if (auto *GraphBefore =
1439 FAM.getCachedResult<PreservedCFGCheckerAnalysis>(*F))
1440 CheckCFG(P, F->getName(), *GraphBefore,
1441 CFG(F, /* TrackBBLifetime */ false));
1442 }
1443 if (const auto *MPtr = unwrapIR<Module>(IR)) {
1444 auto &M = *const_cast<Module *>(MPtr);
1445 if (auto *HashBefore =
1446 MAM.getCachedResult<PreservedModuleHashAnalysis>(M)) {
1447 if (HashBefore->Hash != StructuralHash(M)) {
1449 "Module changed by {0} without invalidating analyses", P));
1450 }
1451 }
1452 }
1453 });
1454}
1455
1458 PIC.registerAfterPassCallback(
1459 [this, MAM](StringRef P, Any IR, const PreservedAnalyses &PassPA) {
1460 if (isIgnored(P) || P == "VerifierPass")
1461 return;
1462 const auto *F = unwrapIR<Function>(IR);
1463 if (!F) {
1464 if (const auto *L = unwrapIR<Loop>(IR))
1465 F = L->getHeader()->getParent();
1466 }
1467
1468 if (F) {
1469 if (DebugLogging)
1470 dbgs() << "Verifying function " << F->getName() << "\n";
1471
1472 if (verifyFunction(*F, &errs()))
1473 report_fatal_error(formatv("Broken function found after pass "
1474 "\"{0}\", compilation aborted!",
1475 P));
1476 } else {
1477 const auto *M = unwrapIR<Module>(IR);
1478 if (!M) {
1479 if (const auto *C = unwrapIR<LazyCallGraph::SCC>(IR))
1480 M = C->begin()->getFunction().getParent();
1481 }
1482
1483 if (M) {
1484 if (DebugLogging)
1485 dbgs() << "Verifying module " << M->getName() << "\n";
1486
1487 if (verifyModule(*M, &errs()))
1488 report_fatal_error(formatv("Broken module found after pass "
1489 "\"{0}\", compilation aborted!",
1490 P));
1491 }
1492
1493 if (auto *MF = unwrapIR<MachineFunction>(IR)) {
1494 if (DebugLogging)
1495 dbgs() << "Verifying machine function " << MF->getName() << '\n';
1496 std::string Banner =
1497 formatv("Broken machine function found after pass "
1498 "\"{0}\", compilation aborted!",
1499 P);
1500 if (MAM) {
1501 Module &M = const_cast<Module &>(*MF->getFunction().getParent());
1502 auto &MFAM =
1504 .getManager();
1506 Verifier.run(const_cast<MachineFunction &>(*MF), MFAM);
1507 } else {
1508 verifyMachineFunction(Banner, *MF);
1509 }
1510 }
1511 }
1512 });
1513}
1514
1516
1522
1523void InLineChangePrinter::handleAfter(StringRef PassID, std::string &Name,
1524 const IRDataT<EmptyData> &Before,
1525 const IRDataT<EmptyData> &After,
1526 Any IR) {
1527 SmallString<20> Banner =
1528 formatv("*** IR Dump After {0} on {1} ***\n", PassID, Name);
1529 Out << Banner;
1530 IRComparer<EmptyData>(Before, After)
1531 .compare(getModuleForComparison(IR),
1532 [&](bool InModule, unsigned Minor,
1533 const FuncDataT<EmptyData> &Before,
1534 const FuncDataT<EmptyData> &After) -> void {
1535 handleFunctionCompare(Name, "", PassID, " on ", InModule,
1536 Minor, Before, After);
1537 });
1538 Out << "\n";
1539}
1540
1542 StringRef Name, StringRef Prefix, StringRef PassID, StringRef Divider,
1543 bool InModule, unsigned Minor, const FuncDataT<EmptyData> &Before,
1544 const FuncDataT<EmptyData> &After) {
1545 // Print a banner when this is being shown in the context of a module
1546 if (InModule)
1547 Out << "\n*** IR for function " << Name << " ***\n";
1548
1550 Before, After,
1551 [&](const BlockDataT<EmptyData> *B, const BlockDataT<EmptyData> *A) {
1552 StringRef BStr = B ? B->getBody() : "\n";
1553 StringRef AStr = A ? A->getBody() : "\n";
1554 const std::string Removed =
1555 UseColour ? "\033[31m-%l\033[0m\n" : "-%l\n";
1556 const std::string Added = UseColour ? "\033[32m+%l\033[0m\n" : "+%l\n";
1557 const std::string NoChange = " %l\n";
1558 Out << doSystemDiff(BStr, AStr, Removed, Added, NoChange);
1559 });
1560}
1561
1569
1571
1575 return;
1576 PIC.registerBeforeNonSkippedPassCallback(
1577 [this](StringRef P, Any IR) { this->runBeforePass(P, IR); });
1578 PIC.registerAfterPassCallback(
1579 [this](StringRef P, Any IR, const PreservedAnalyses &) {
1580 this->runAfterPass();
1581 },
1582 true);
1583 PIC.registerAfterPassInvalidatedCallback(
1584 [this](StringRef P, const PreservedAnalyses &) { this->runAfterPass(); },
1585 true);
1586 PIC.registerBeforeAnalysisCallback(
1587 [this](StringRef P, Any IR) { this->runBeforePass(P, IR); });
1588 PIC.registerAfterAnalysisCallback(
1589 [this](StringRef P, Any IR) { this->runAfterPass(); }, true);
1590}
1591
1592void TimeProfilingPassesHandler::runBeforePass(StringRef PassID, Any IR) {
1593 timeTraceProfilerBegin(PassID, getIRName(IR));
1594}
1595
1596void TimeProfilingPassesHandler::runAfterPass() { timeTraceProfilerEnd(); }
1597
1598namespace {
1599
1600class DisplayNode;
1601class DotCfgDiffDisplayGraph;
1602
1603// Base class for a node or edge in the dot-cfg-changes graph.
1604class DisplayElement {
1605public:
1606 // Is this in before, after, or both?
1607 StringRef getColour() const { return Colour; }
1608
1609protected:
1610 DisplayElement(StringRef Colour) : Colour(Colour) {}
1611 const StringRef Colour;
1612};
1613
1614// An edge representing a transition between basic blocks in the
1615// dot-cfg-changes graph.
1616class DisplayEdge : public DisplayElement {
1617public:
1618 DisplayEdge(std::string Value, DisplayNode &Node, StringRef Colour)
1619 : DisplayElement(Colour), Value(Value), Node(Node) {}
1620 // The value on which the transition is made.
1621 std::string getValue() const { return Value; }
1622 // The node (representing a basic block) reached by this transition.
1623 const DisplayNode &getDestinationNode() const { return Node; }
1624
1625protected:
1626 std::string Value;
1627 const DisplayNode &Node;
1628};
1629
1630// A node in the dot-cfg-changes graph which represents a basic block.
1631class DisplayNode : public DisplayElement {
1632public:
1633 // \p C is the content for the node, \p T indicates the colour for the
1634 // outline of the node
1635 DisplayNode(std::string Content, StringRef Colour)
1636 : DisplayElement(Colour), Content(Content) {}
1637
1638 // Iterator to the child nodes. Required by GraphWriter.
1639 using ChildIterator = std::unordered_set<DisplayNode *>::const_iterator;
1640 ChildIterator children_begin() const { return Children.cbegin(); }
1641 ChildIterator children_end() const { return Children.cend(); }
1642
1643 // Iterator for the edges. Required by GraphWriter.
1644 using EdgeIterator = std::vector<DisplayEdge *>::const_iterator;
1645 EdgeIterator edges_begin() const { return EdgePtrs.cbegin(); }
1646 EdgeIterator edges_end() const { return EdgePtrs.cend(); }
1647
1648 // Create an edge to \p Node on value \p Value, with colour \p Colour.
1649 void createEdge(StringRef Value, DisplayNode &Node, StringRef Colour);
1650
1651 // Return the content of this node.
1652 std::string getContent() const { return Content; }
1653
1654 // Return the edge to node \p S.
1655 const DisplayEdge &getEdge(const DisplayNode &To) const {
1656 assert(EdgeMap.find(&To) != EdgeMap.end() && "Expected to find edge.");
1657 return *EdgeMap.find(&To)->second;
1658 }
1659
1660 // Return the value for the transition to basic block \p S.
1661 // Required by GraphWriter.
1662 std::string getEdgeSourceLabel(const DisplayNode &Sink) const {
1663 return getEdge(Sink).getValue();
1664 }
1665
1666 void createEdgeMap();
1667
1668protected:
1669 const std::string Content;
1670
1671 // Place to collect all of the edges. Once they are all in the vector,
1672 // the vector will not reallocate so then we can use pointers to them,
1673 // which are required by the graph writing routines.
1674 std::vector<DisplayEdge> Edges;
1675
1676 std::vector<DisplayEdge *> EdgePtrs;
1677 std::unordered_set<DisplayNode *> Children;
1678 std::unordered_map<const DisplayNode *, const DisplayEdge *> EdgeMap;
1679
1680 // Safeguard adding of edges.
1681 bool AllEdgesCreated = false;
1682};
1683
1684// Class representing a difference display (corresponds to a pdf file).
1685class DotCfgDiffDisplayGraph {
1686public:
1687 DotCfgDiffDisplayGraph(std::string Name) : GraphName(Name) {}
1688
1689 // Generate the file into \p DotFile.
1690 void generateDotFile(StringRef DotFile);
1691
1692 // Iterator to the nodes. Required by GraphWriter.
1693 using NodeIterator = std::vector<DisplayNode *>::const_iterator;
1694 NodeIterator nodes_begin() const {
1695 assert(NodeGenerationComplete && "Unexpected children iterator creation");
1696 return NodePtrs.cbegin();
1697 }
1698 NodeIterator nodes_end() const {
1699 assert(NodeGenerationComplete && "Unexpected children iterator creation");
1700 return NodePtrs.cend();
1701 }
1702
1703 // Record the index of the entry node. At this point, we can build up
1704 // vectors of pointers that are required by the graph routines.
1705 void setEntryNode(unsigned N) {
1706 // At this point, there will be no new nodes.
1707 assert(!NodeGenerationComplete && "Unexpected node creation");
1708 NodeGenerationComplete = true;
1709 for (auto &N : Nodes)
1710 NodePtrs.emplace_back(&N);
1711
1712 EntryNode = NodePtrs[N];
1713 }
1714
1715 // Create a node.
1716 void createNode(std::string C, StringRef Colour) {
1717 assert(!NodeGenerationComplete && "Unexpected node creation");
1718 Nodes.emplace_back(C, Colour);
1719 }
1720 // Return the node at index \p N to avoid problems with vectors reallocating.
1721 DisplayNode &getNode(unsigned N) {
1722 assert(N < Nodes.size() && "Node is out of bounds");
1723 return Nodes[N];
1724 }
1725 unsigned size() const {
1726 assert(NodeGenerationComplete && "Unexpected children iterator creation");
1727 return Nodes.size();
1728 }
1729
1730 // Return the name of the graph. Required by GraphWriter.
1731 std::string getGraphName() const { return GraphName; }
1732
1733 // Return the string representing the differences for basic block \p Node.
1734 // Required by GraphWriter.
1735 std::string getNodeLabel(const DisplayNode &Node) const {
1736 return Node.getContent();
1737 }
1738
1739 // Return a string with colour information for Dot. Required by GraphWriter.
1740 std::string getNodeAttributes(const DisplayNode &Node) const {
1741 return attribute(Node.getColour());
1742 }
1743
1744 // Return a string with colour information for Dot. Required by GraphWriter.
1745 std::string getEdgeColorAttr(const DisplayNode &From,
1746 const DisplayNode &To) const {
1747 return attribute(From.getEdge(To).getColour());
1748 }
1749
1750 // Get the starting basic block. Required by GraphWriter.
1751 DisplayNode *getEntryNode() const {
1752 assert(NodeGenerationComplete && "Unexpected children iterator creation");
1753 return EntryNode;
1754 }
1755
1756protected:
1757 // Return the string containing the colour to use as a Dot attribute.
1758 std::string attribute(StringRef Colour) const {
1759 return "color=" + Colour.str();
1760 }
1761
1762 bool NodeGenerationComplete = false;
1763 const std::string GraphName;
1764 std::vector<DisplayNode> Nodes;
1765 std::vector<DisplayNode *> NodePtrs;
1766 DisplayNode *EntryNode = nullptr;
1767};
1768
1769void DisplayNode::createEdge(StringRef Value, DisplayNode &Node,
1770 StringRef Colour) {
1771 assert(!AllEdgesCreated && "Expected to be able to still create edges.");
1772 Edges.emplace_back(Value.str(), Node, Colour);
1773 Children.insert(&Node);
1774}
1775
1776void DisplayNode::createEdgeMap() {
1777 // No more edges will be added so we can now use pointers to the edges
1778 // as the vector will not grow and reallocate.
1779 AllEdgesCreated = true;
1780 for (auto &E : Edges)
1781 EdgeMap.insert({&E.getDestinationNode(), &E});
1782}
1783
1784class DotCfgDiffNode;
1785class DotCfgDiff;
1786
1787// A class representing a basic block in the Dot difference graph.
1788class DotCfgDiffNode {
1789public:
1790 DotCfgDiffNode() = delete;
1791
1792 // Create a node in Dot difference graph \p G representing the basic block
1793 // represented by \p BD with colour \p Colour (where it exists).
1794 DotCfgDiffNode(DotCfgDiff &G, unsigned N, const BlockDataT<DCData> &BD,
1795 StringRef Colour)
1796 : Graph(G), N(N), Data{&BD, nullptr}, Colour(Colour) {}
1797 DotCfgDiffNode(const DotCfgDiffNode &DN)
1798 : Graph(DN.Graph), N(DN.N), Data{DN.Data[0], DN.Data[1]},
1799 Colour(DN.Colour), EdgesMap(DN.EdgesMap), Children(DN.Children),
1800 Edges(DN.Edges) {}
1801
1802 unsigned getIndex() const { return N; }
1803
1804 // The label of the basic block
1805 StringRef getLabel() const {
1806 assert(Data[0] && "Expected Data[0] to be set.");
1807 return Data[0]->getLabel();
1808 }
1809 // Return the colour for this block
1810 StringRef getColour() const { return Colour; }
1811 // Change this basic block from being only in before to being common.
1812 // Save the pointer to \p Other.
1813 void setCommon(const BlockDataT<DCData> &Other) {
1814 assert(!Data[1] && "Expected only one block datum");
1815 Data[1] = &Other;
1816 Colour = CommonColour;
1817 }
1818 // Add an edge to \p E of colour {\p Value, \p Colour}.
1819 void addEdge(unsigned E, StringRef Value, StringRef Colour) {
1820 // This is a new edge or it is an edge being made common.
1821 assert((EdgesMap.count(E) == 0 || Colour == CommonColour) &&
1822 "Unexpected edge count and color.");
1823 EdgesMap[E] = {Value.str(), Colour};
1824 }
1825 // Record the children and create edges.
1826 void finalize(DotCfgDiff &G);
1827
1828 // Return the colour of the edge to node \p S.
1829 StringRef getEdgeColour(const unsigned S) const {
1830 assert(EdgesMap.count(S) == 1 && "Expected to find edge.");
1831 return EdgesMap.at(S).second;
1832 }
1833
1834 // Return the string representing the basic block.
1835 std::string getBodyContent() const;
1836
1837 void createDisplayEdges(DotCfgDiffDisplayGraph &Graph, unsigned DisplayNode,
1838 std::map<const unsigned, unsigned> &NodeMap) const;
1839
1840protected:
1841 DotCfgDiff &Graph;
1842 const unsigned N;
1843 const BlockDataT<DCData> *Data[2];
1844 StringRef Colour;
1845 std::map<const unsigned, std::pair<std::string, StringRef>> EdgesMap;
1846 std::vector<unsigned> Children;
1847 std::vector<unsigned> Edges;
1848};
1849
1850// Class representing the difference graph between two functions.
1851class DotCfgDiff {
1852public:
1853 // \p Title is the title given to the graph. \p EntryNodeName is the
1854 // entry node for the function. \p Before and \p After are the before
1855 // after versions of the function, respectively. \p Dir is the directory
1856 // in which to store the results.
1857 DotCfgDiff(StringRef Title, const FuncDataT<DCData> &Before,
1858 const FuncDataT<DCData> &After);
1859
1860 DotCfgDiff(const DotCfgDiff &) = delete;
1861 DotCfgDiff &operator=(const DotCfgDiff &) = delete;
1862
1863 DotCfgDiffDisplayGraph createDisplayGraph(StringRef Title,
1864 StringRef EntryNodeName);
1865
1866 // Return a string consisting of the labels for the \p Source and \p Sink.
1867 // The combination allows distinguishing changing transitions on the
1868 // same value (ie, a transition went to X before and goes to Y after).
1869 // Required by GraphWriter.
1870 StringRef getEdgeSourceLabel(const unsigned &Source,
1871 const unsigned &Sink) const {
1872 std::string S =
1873 getNode(Source).getLabel().str() + " " + getNode(Sink).getLabel().str();
1874 assert(EdgeLabels.count(S) == 1 && "Expected to find edge label.");
1875 return EdgeLabels.find(S)->getValue();
1876 }
1877
1878 // Return the number of basic blocks (nodes). Required by GraphWriter.
1879 unsigned size() const { return Nodes.size(); }
1880
1881 const DotCfgDiffNode &getNode(unsigned N) const {
1882 assert(N < Nodes.size() && "Unexpected index for node reference");
1883 return Nodes[N];
1884 }
1885
1886protected:
1887 // Return the string surrounded by HTML to make it the appropriate colour.
1888 std::string colourize(std::string S, StringRef Colour) const;
1889
1890 void createNode(StringRef Label, const BlockDataT<DCData> &BD, StringRef C) {
1891 unsigned Pos = Nodes.size();
1892 Nodes.emplace_back(*this, Pos, BD, C);
1893 NodePosition.insert({Label, Pos});
1894 }
1895
1896 // TODO Nodes should probably be a StringMap<DotCfgDiffNode> after the
1897 // display graph is separated out, which would remove the need for
1898 // NodePosition.
1899 std::vector<DotCfgDiffNode> Nodes;
1900 StringMap<unsigned> NodePosition;
1901 const std::string GraphName;
1902
1903 StringMap<std::string> EdgeLabels;
1904};
1905
1906std::string DotCfgDiffNode::getBodyContent() const {
1907 if (Colour == CommonColour) {
1908 assert(Data[1] && "Expected Data[1] to be set.");
1909
1910 StringRef SR[2];
1911 for (unsigned I = 0; I < 2; ++I) {
1912 SR[I] = Data[I]->getBody();
1913 // drop initial '\n' if present
1914 SR[I].consume_front("\n");
1915 // drop predecessors as they can be big and are redundant
1916 SR[I] = SR[I].drop_until([](char C) { return C == '\n'; }).drop_front();
1917 }
1918
1919 SmallString<80> OldLineFormat = formatv(
1920 "<FONT COLOR=\"{0}\">%l</FONT><BR align=\"left\"/>", BeforeColour);
1921 SmallString<80> NewLineFormat = formatv(
1922 "<FONT COLOR=\"{0}\">%l</FONT><BR align=\"left\"/>", AfterColour);
1923 SmallString<80> UnchangedLineFormat = formatv(
1924 "<FONT COLOR=\"{0}\">%l</FONT><BR align=\"left\"/>", CommonColour);
1925 std::string Diff = Data[0]->getLabel().str();
1926 Diff += ":\n<BR align=\"left\"/>" +
1927 doSystemDiff(makeHTMLReady(SR[0]), makeHTMLReady(SR[1]),
1928 OldLineFormat, NewLineFormat, UnchangedLineFormat);
1929
1930 // Diff adds in some empty colour changes which are not valid HTML
1931 // so remove them. Colours are all lowercase alpha characters (as
1932 // listed in https://graphviz.org/pdf/dotguide.pdf).
1933 Regex R("<FONT COLOR=\"\\w+\"></FONT>");
1934 while (true) {
1935 std::string Error;
1936 std::string S = R.sub("", Diff, &Error);
1937 if (Error != "")
1938 return Error;
1939 if (S == Diff)
1940 return Diff;
1941 Diff = S;
1942 }
1943 llvm_unreachable("Should not get here");
1944 }
1945
1946 // Put node out in the appropriate colour.
1947 assert(!Data[1] && "Data[1] is set unexpectedly.");
1948 std::string Body = makeHTMLReady(Data[0]->getBody());
1949 const StringRef BS = Body;
1950 StringRef BS1 = BS;
1951 // Drop leading newline, if present.
1952 if (BS.front() == '\n')
1953 BS1 = BS1.drop_front(1);
1954 // Get label.
1955 StringRef Label = BS1.take_until([](char C) { return C == ':'; });
1956 // drop predecessors as they can be big and are redundant
1957 BS1 = BS1.drop_until([](char C) { return C == '\n'; }).drop_front();
1958
1959 std::string S = "<FONT COLOR=\"" + Colour.str() + "\">" + Label.str() + ":";
1960
1961 // align each line to the left.
1962 while (BS1.size()) {
1963 S.append("<BR align=\"left\"/>");
1964 StringRef Line = BS1.take_until([](char C) { return C == '\n'; });
1965 S.append(Line.str());
1966 BS1 = BS1.drop_front(Line.size() + 1);
1967 }
1968 S.append("<BR align=\"left\"/></FONT>");
1969 return S;
1970}
1971
1972std::string DotCfgDiff::colourize(std::string S, StringRef Colour) const {
1973 if (S.length() == 0)
1974 return S;
1975 return "<FONT COLOR=\"" + Colour.str() + "\">" + S + "</FONT>";
1976}
1977
1978DotCfgDiff::DotCfgDiff(StringRef Title, const FuncDataT<DCData> &Before,
1979 const FuncDataT<DCData> &After)
1980 : GraphName(Title.str()) {
1981 StringMap<StringRef> EdgesMap;
1982
1983 // Handle each basic block in the before IR.
1984 for (auto &B : Before.getData()) {
1985 StringRef Label = B.getKey();
1986 const BlockDataT<DCData> &BD = B.getValue();
1987 createNode(Label, BD, BeforeColour);
1988
1989 // Create transitions with names made up of the from block label, the value
1990 // on which the transition is made and the to block label.
1991 for (StringMap<std::string>::const_iterator Sink = BD.getData().begin(),
1992 E = BD.getData().end();
1993 Sink != E; ++Sink) {
1994 std::string Key = (Label + " " + Sink->getKey().str()).str() + " " +
1995 BD.getData().getSuccessorLabel(Sink->getKey()).str();
1996 EdgesMap.insert({Key, BeforeColour});
1997 }
1998 }
1999
2000 // Handle each basic block in the after IR
2001 for (auto &A : After.getData()) {
2002 StringRef Label = A.getKey();
2003 const BlockDataT<DCData> &BD = A.getValue();
2004 auto It = NodePosition.find(Label);
2005 if (It == NodePosition.end())
2006 // This only exists in the after IR. Create the node.
2007 createNode(Label, BD, AfterColour);
2008 else
2009 Nodes[It->second].setCommon(BD);
2010 // Add in the edges between the nodes (as common or only in after).
2011 for (StringMap<std::string>::const_iterator Sink = BD.getData().begin(),
2012 E = BD.getData().end();
2013 Sink != E; ++Sink) {
2014 std::string Key = (Label + " " + Sink->getKey().str()).str() + " " +
2015 BD.getData().getSuccessorLabel(Sink->getKey()).str();
2016 auto [It, Inserted] = EdgesMap.try_emplace(Key, AfterColour);
2017 if (!Inserted)
2018 It->second = CommonColour;
2019 }
2020 }
2021
2022 // Now go through the map of edges and add them to the node.
2023 for (auto &E : EdgesMap) {
2024 // Extract the source, sink and value from the edge key.
2025 StringRef S = E.getKey();
2026 auto SP1 = S.rsplit(' ');
2027 auto &SourceSink = SP1.first;
2028 auto SP2 = SourceSink.split(' ');
2029 StringRef Source = SP2.first;
2030 StringRef Sink = SP2.second;
2031 StringRef Value = SP1.second;
2032
2033 assert(NodePosition.count(Source) == 1 && "Expected to find node.");
2034 DotCfgDiffNode &SourceNode = Nodes[NodePosition[Source]];
2035 assert(NodePosition.count(Sink) == 1 && "Expected to find node.");
2036 unsigned SinkNode = NodePosition[Sink];
2037 StringRef Colour = E.second;
2038
2039 // Look for an edge from Source to Sink
2040 auto [It, Inserted] = EdgeLabels.try_emplace(SourceSink);
2041 if (Inserted)
2042 It->getValue() = colourize(Value.str(), Colour);
2043 else {
2044 StringRef V = It->getValue();
2045 std::string NV = colourize(V.str() + " " + Value.str(), Colour);
2046 Colour = CommonColour;
2047 It->getValue() = NV;
2048 }
2049 SourceNode.addEdge(SinkNode, Value, Colour);
2050 }
2051 for (auto &I : Nodes)
2052 I.finalize(*this);
2053}
2054
2055DotCfgDiffDisplayGraph DotCfgDiff::createDisplayGraph(StringRef Title,
2056 StringRef EntryNodeName) {
2057 assert(NodePosition.count(EntryNodeName) == 1 &&
2058 "Expected to find entry block in map.");
2059 unsigned Entry = NodePosition[EntryNodeName];
2060 assert(Entry < Nodes.size() && "Expected to find entry node");
2061 DotCfgDiffDisplayGraph G(Title.str());
2062
2063 std::map<const unsigned, unsigned> NodeMap;
2064
2065 int EntryIndex = -1;
2066 unsigned Index = 0;
2067 for (auto &I : Nodes) {
2068 if (I.getIndex() == Entry)
2069 EntryIndex = Index;
2070 G.createNode(I.getBodyContent(), I.getColour());
2071 NodeMap.insert({I.getIndex(), Index++});
2072 }
2073 assert(EntryIndex >= 0 && "Expected entry node index to be set.");
2074 G.setEntryNode(EntryIndex);
2075
2076 for (auto &I : NodeMap) {
2077 unsigned SourceNode = I.first;
2078 unsigned DisplayNode = I.second;
2079 getNode(SourceNode).createDisplayEdges(G, DisplayNode, NodeMap);
2080 }
2081 return G;
2082}
2083
2084void DotCfgDiffNode::createDisplayEdges(
2085 DotCfgDiffDisplayGraph &DisplayGraph, unsigned DisplayNodeIndex,
2086 std::map<const unsigned, unsigned> &NodeMap) const {
2087
2088 DisplayNode &SourceDisplayNode = DisplayGraph.getNode(DisplayNodeIndex);
2089
2090 for (auto I : Edges) {
2091 unsigned SinkNodeIndex = I;
2092 StringRef Colour = getEdgeColour(SinkNodeIndex);
2093 const DotCfgDiffNode *SinkNode = &Graph.getNode(SinkNodeIndex);
2094
2095 StringRef Label = Graph.getEdgeSourceLabel(getIndex(), SinkNodeIndex);
2096 DisplayNode &SinkDisplayNode = DisplayGraph.getNode(SinkNode->getIndex());
2097 SourceDisplayNode.createEdge(Label, SinkDisplayNode, Colour);
2098 }
2099 SourceDisplayNode.createEdgeMap();
2100}
2101
2102void DotCfgDiffNode::finalize(DotCfgDiff &G) {
2103 for (auto E : EdgesMap) {
2104 Children.emplace_back(E.first);
2105 Edges.emplace_back(E.first);
2106 }
2107}
2108
2109} // namespace
2110
2111namespace llvm {
2112
2113template <> struct GraphTraits<DotCfgDiffDisplayGraph *> {
2114 using NodeRef = const DisplayNode *;
2115 using ChildIteratorType = DisplayNode::ChildIterator;
2116 using nodes_iterator = DotCfgDiffDisplayGraph::NodeIterator;
2117 using EdgeRef = const DisplayEdge *;
2118 using ChildEdgeIterator = DisplayNode::EdgeIterator;
2119
2120 static NodeRef getEntryNode(const DotCfgDiffDisplayGraph *G) {
2121 return G->getEntryNode();
2122 }
2124 return N->children_begin();
2125 }
2126 static ChildIteratorType child_end(NodeRef N) { return N->children_end(); }
2127 static nodes_iterator nodes_begin(const DotCfgDiffDisplayGraph *G) {
2128 return G->nodes_begin();
2129 }
2130 static nodes_iterator nodes_end(const DotCfgDiffDisplayGraph *G) {
2131 return G->nodes_end();
2132 }
2134 return N->edges_begin();
2135 }
2136 static ChildEdgeIterator child_edge_end(NodeRef N) { return N->edges_end(); }
2137 static NodeRef edge_dest(EdgeRef E) { return &E->getDestinationNode(); }
2138 static unsigned size(const DotCfgDiffDisplayGraph *G) { return G->size(); }
2139};
2140
2141template <>
2142struct DOTGraphTraits<DotCfgDiffDisplayGraph *> : public DefaultDOTGraphTraits {
2143 explicit DOTGraphTraits(bool Simple = false)
2145
2146 static bool renderNodesUsingHTML() { return true; }
2147 static std::string getGraphName(const DotCfgDiffDisplayGraph *DiffData) {
2148 return DiffData->getGraphName();
2149 }
2150 static std::string
2151 getGraphProperties(const DotCfgDiffDisplayGraph *DiffData) {
2152 return "\tsize=\"190, 190\";\n";
2153 }
2154 static std::string getNodeLabel(const DisplayNode *Node,
2155 const DotCfgDiffDisplayGraph *DiffData) {
2156 return DiffData->getNodeLabel(*Node);
2157 }
2158 static std::string getNodeAttributes(const DisplayNode *Node,
2159 const DotCfgDiffDisplayGraph *DiffData) {
2160 return DiffData->getNodeAttributes(*Node);
2161 }
2162 static std::string getEdgeSourceLabel(const DisplayNode *From,
2163 DisplayNode::ChildIterator &To) {
2164 return From->getEdgeSourceLabel(**To);
2165 }
2166 static std::string getEdgeAttributes(const DisplayNode *From,
2167 DisplayNode::ChildIterator &To,
2168 const DotCfgDiffDisplayGraph *DiffData) {
2169 return DiffData->getEdgeColorAttr(*From, **To);
2170 }
2171};
2172
2173} // namespace llvm
2174
2175namespace {
2176
2177void DotCfgDiffDisplayGraph::generateDotFile(StringRef DotFile) {
2178 std::error_code EC;
2179 raw_fd_ostream OutStream(DotFile, EC);
2180 if (EC) {
2181 errs() << "Error: " << EC.message() << "\n";
2182 return;
2183 }
2184 WriteGraph(OutStream, this, false);
2185 OutStream.flush();
2186 OutStream.close();
2187}
2188
2189} // namespace
2190
2191namespace llvm {
2192
2194 // Build up transition labels.
2195 const Instruction *Term = B.getTerminator();
2196 if (const CondBrInst *Br = dyn_cast<const CondBrInst>(Term)) {
2197 addSuccessorLabel(Br->getSuccessor(0)->getName().str(), "true");
2198 addSuccessorLabel(Br->getSuccessor(1)->getName().str(), "false");
2199 } else if (const SwitchInst *Sw = dyn_cast<const SwitchInst>(Term)) {
2200 addSuccessorLabel(Sw->case_default()->getCaseSuccessor()->getName().str(),
2201 "default");
2202 for (auto &C : Sw->cases()) {
2203 assert(C.getCaseValue() && "Expected to find case value.");
2204 SmallString<20> Value = formatv("{0}", C.getCaseValue()->getSExtValue());
2205 addSuccessorLabel(C.getCaseSuccessor()->getName().str(), Value);
2206 }
2207 } else
2208 for (const BasicBlock *Succ : successors(&B))
2209 addSuccessorLabel(Succ->getName().str(), "");
2210}
2211
2213 for (const MachineBasicBlock *Succ : successors(&B))
2214 addSuccessorLabel(Succ->getName().str(), "");
2215}
2216
2219
2221 StringRef Name, StringRef Prefix, StringRef PassID, StringRef Divider,
2222 bool InModule, unsigned Minor, const FuncDataT<DCData> &Before,
2223 const FuncDataT<DCData> &After) {
2224 assert(HTML && "Expected outstream to be set");
2225 SmallString<8> Extender;
2227 // Handle numbering and file names.
2228 if (InModule) {
2229 Extender = formatv("{0}_{1}", N, Minor);
2230 Number = formatv("{0}.{1}", N, Minor);
2231 } else {
2232 Extender = formatv("{0}", N);
2233 Number = formatv("{0}", N);
2234 }
2235 // Create a temporary file name for the dot file.
2237 sys::fs::createUniquePath("cfgdot-%%%%%%.dot", SV, true);
2238 std::string DotFile = Twine(SV).str();
2239
2240 SmallString<20> PDFFileName = formatv("diff_{0}.pdf", Extender);
2242
2243 Text = formatv("{0}.{1}{2}{3}{4}", Number, Prefix, makeHTMLReady(PassID),
2244 Divider, Name);
2245
2246 DotCfgDiff Diff(Text, Before, After);
2247 std::string EntryBlockName = After.getEntryBlockName();
2248 // Use the before entry block if the after entry block was removed.
2249 if (EntryBlockName == "")
2250 EntryBlockName = Before.getEntryBlockName();
2251 assert(EntryBlockName != "" && "Expected to find entry block");
2252
2253 DotCfgDiffDisplayGraph DG = Diff.createDisplayGraph(Text, EntryBlockName);
2254 DG.generateDotFile(DotFile);
2255
2256 *HTML << genHTML(Text, DotFile, PDFFileName);
2257 std::error_code EC = sys::fs::remove(DotFile);
2258 if (EC)
2259 errs() << "Error: " << EC.message() << "\n";
2260}
2261
2263 StringRef PDFFileName) {
2264 SmallString<20> PDFFile = formatv("{0}/{1}", DotCfgDir, PDFFileName);
2265 // Create the PDF file.
2267 if (!DotExe)
2268 return "Unable to find dot executable.";
2269
2270 StringRef Args[] = {DotBinary, "-Tpdf", "-o", PDFFile, DotFile};
2271 int Result = sys::ExecuteAndWait(*DotExe, Args, std::nullopt);
2272 if (Result < 0)
2273 return "Error executing system dot.";
2274
2275 // Create the HTML tag refering to the PDF file.
2277 " <a href=\"{0}\" target=\"_blank\">{1}</a><br/>\n", PDFFileName, Text);
2278 return S.c_str();
2279}
2280
2282 assert(HTML && "Expected outstream to be set");
2283 *HTML << "<button type=\"button\" class=\"collapsible\">0. "
2284 << "Initial IR (by function)</button>\n"
2285 << "<div class=\"content\">\n"
2286 << " <p>\n";
2287 // Create representation of IR
2290 // Now compare it against itself, which will have everything the
2291 // same and will generate the files.
2293 .compare(getModuleForComparison(IR),
2294 [&](bool InModule, unsigned Minor,
2295 const FuncDataT<DCData> &Before,
2296 const FuncDataT<DCData> &After) -> void {
2297 handleFunctionCompare("", " ", "Initial IR", "", InModule,
2298 Minor, Before, After);
2299 });
2300 *HTML << " </p>\n"
2301 << "</div><br/>\n";
2302 ++N;
2303}
2304
2309
2310void DotCfgChangeReporter::omitAfter(StringRef PassID, std::string &Name) {
2311 assert(HTML && "Expected outstream to be set");
2312 SmallString<20> Banner =
2313 formatv(" <a>{0}. Pass {1} on {2} omitted because no change</a><br/>\n",
2314 N, makeHTMLReady(PassID), Name);
2315 *HTML << Banner;
2316 ++N;
2317}
2318
2319void DotCfgChangeReporter::handleAfter(StringRef PassID, std::string &Name,
2320 const IRDataT<DCData> &Before,
2321 const IRDataT<DCData> &After, Any IR) {
2322 assert(HTML && "Expected outstream to be set");
2323 IRComparer<DCData>(Before, After)
2324 .compare(getModuleForComparison(IR),
2325 [&](bool InModule, unsigned Minor,
2326 const FuncDataT<DCData> &Before,
2327 const FuncDataT<DCData> &After) -> void {
2328 handleFunctionCompare(Name, " Pass ", PassID, " on ", InModule,
2329 Minor, Before, After);
2330 });
2331 *HTML << " </p></div>\n";
2332 ++N;
2333}
2334
2336 assert(HTML && "Expected outstream to be set");
2337 SmallString<20> Banner =
2338 formatv(" <a>{0}. {1} invalidated</a><br/>\n", N, makeHTMLReady(PassID));
2339 *HTML << Banner;
2340 ++N;
2341}
2342
2343void DotCfgChangeReporter::handleFiltered(StringRef PassID, std::string &Name) {
2344 assert(HTML && "Expected outstream to be set");
2345 SmallString<20> Banner =
2346 formatv(" <a>{0}. Pass {1} on {2} filtered out</a><br/>\n", N,
2347 makeHTMLReady(PassID), Name);
2348 *HTML << Banner;
2349 ++N;
2350}
2351
2352void DotCfgChangeReporter::handleIgnored(StringRef PassID, std::string &Name) {
2353 assert(HTML && "Expected outstream to be set");
2354 SmallString<20> Banner = formatv(" <a>{0}. {1} on {2} ignored</a><br/>\n", N,
2355 makeHTMLReady(PassID), Name);
2356 *HTML << Banner;
2357 ++N;
2358}
2359
2361 std::error_code EC;
2362 HTML = std::make_unique<raw_fd_ostream>(DotCfgDir + "/passes.html", EC);
2363 if (EC) {
2364 HTML = nullptr;
2365 return false;
2366 }
2367
2368 *HTML << "<!doctype html>"
2369 << "<html>"
2370 << "<head>"
2371 << "<style>.collapsible { "
2372 << "background-color: #777;"
2373 << " color: white;"
2374 << " cursor: pointer;"
2375 << " padding: 18px;"
2376 << " width: 100%;"
2377 << " border: none;"
2378 << " text-align: left;"
2379 << " outline: none;"
2380 << " font-size: 15px;"
2381 << "} .active, .collapsible:hover {"
2382 << " background-color: #555;"
2383 << "} .content {"
2384 << " padding: 0 18px;"
2385 << " display: none;"
2386 << " overflow: hidden;"
2387 << " background-color: #f1f1f1;"
2388 << "}"
2389 << "</style>"
2390 << "<title>passes.html</title>"
2391 << "</head>\n"
2392 << "<body>";
2393 return true;
2394}
2395
2397 if (!HTML)
2398 return;
2399 *HTML
2400 << "<script>var coll = document.getElementsByClassName(\"collapsible\");"
2401 << "var i;"
2402 << "for (i = 0; i < coll.length; i++) {"
2403 << "coll[i].addEventListener(\"click\", function() {"
2404 << " this.classList.toggle(\"active\");"
2405 << " var content = this.nextElementSibling;"
2406 << " if (content.style.display === \"block\"){"
2407 << " content.style.display = \"none\";"
2408 << " }"
2409 << " else {"
2410 << " content.style.display= \"block\";"
2411 << " }"
2412 << " });"
2413 << " }"
2414 << "</script>"
2415 << "</body>"
2416 << "</html>\n";
2417 HTML->flush();
2418 HTML->close();
2419}
2420
2425 SmallString<128> OutputDir;
2426 sys::fs::expand_tilde(DotCfgDir, OutputDir);
2427 sys::fs::make_absolute(OutputDir);
2428 assert(!OutputDir.empty() && "expected output dir to be non-empty");
2429 DotCfgDir = OutputDir.c_str();
2430 if (initializeHTML()) {
2432 return;
2433 }
2434 dbgs() << "Unable to open output stream for -cfg-dot-changed\n";
2435 }
2436}
2437
2439 LLVMContext &Context, bool DebugLogging, bool VerifyEach,
2440 PrintPassOptions PrintPassOpts)
2441 : PrintPass(DebugLogging, PrintPassOpts), OptNone(DebugLogging),
2442 OptPassGate(Context),
2443 PrintChangedIR(PrintChanged == ChangePrinter::Verbose),
2444 PrintChangedDiff(PrintChanged == ChangePrinter::DiffVerbose ||
2448 WebsiteChangeReporter(PrintChanged == ChangePrinter::DotCfgVerbose),
2449 Verify(DebugLogging), DroppedStatsIR(DroppedVarStats),
2450 VerifyEach(VerifyEach) {}
2451
2452PrintCrashIRInstrumentation *PrintCrashIRInstrumentation::CrashReporter =
2453 nullptr;
2454
2456 if (!PrintOnCrashPath.empty()) {
2457 std::error_code EC;
2459 if (EC)
2461 Out << SavedIR;
2462 } else {
2463 dbgs() << SavedIR;
2464 }
2465}
2466
2467void PrintCrashIRInstrumentation::SignalHandler(void *) {
2468 // Called by signal handlers so do not lock here
2469 // Is the PrintCrashIRInstrumentation still alive?
2470 if (!CrashReporter)
2471 return;
2472
2473 assert((PrintOnCrash || !PrintOnCrashPath.empty()) &&
2474 "Did not expect to get here without option set.");
2475 CrashReporter->reportCrashIR();
2476}
2477
2479 if (!CrashReporter)
2480 return;
2481
2482 assert((PrintOnCrash || !PrintOnCrashPath.empty()) &&
2483 "Did not expect to get here without option set.");
2484 CrashReporter = nullptr;
2485}
2486
2489 if ((!PrintOnCrash && PrintOnCrashPath.empty()) || CrashReporter)
2490 return;
2491
2492 sys::AddSignalHandler(SignalHandler, nullptr);
2493 CrashReporter = this;
2494
2495 PIC.registerBeforeNonSkippedPassCallback(
2496 [&PIC, this](StringRef PassID, Any IR) {
2497 SavedIR.clear();
2499 OS << formatv("; *** Dump of {0}IR Before Last Pass {1}",
2500 llvm::forcePrintModuleIR() ? "Module " : "", PassID);
2501 if (!isInteresting(IR, PassID, PIC.getPassNameForClassName(PassID))) {
2502 OS << " Filtered Out ***\n";
2503 return;
2504 }
2505 OS << " Started ***\n";
2506 unwrapAndPrint(OS, IR);
2507 });
2508}
2509
2512 PrintIR.registerCallbacks(PIC);
2513 PrintPass.registerCallbacks(PIC);
2514 TimePasses.registerCallbacks(PIC);
2515 OptNone.registerCallbacks(PIC);
2516 OptPassGate.registerCallbacks(PIC);
2517 PrintChangedIR.registerCallbacks(PIC);
2518 PseudoProbeVerification.registerCallbacks(PIC);
2519 if (VerifyEach)
2520 Verify.registerCallbacks(PIC, MAM);
2521 PrintChangedDiff.registerCallbacks(PIC);
2522 WebsiteChangeReporter.registerCallbacks(PIC);
2523 ChangeTester.registerCallbacks(PIC);
2524 PrintCrashIR.registerCallbacks(PIC);
2525 DroppedStatsIR.registerCallbacks(PIC);
2526 if (MAM)
2527 PreservedCFGChecker.registerCallbacks(PIC, *MAM);
2528
2529 // TimeProfiling records the pass running time cost.
2530 // Its 'BeforePassCallback' can be appended at the tail of all the
2531 // BeforeCallbacks by calling `registerCallbacks` in the end.
2532 // Its 'AfterPassCallback' is put at the front of all the
2533 // AfterCallbacks by its `registerCallbacks`. This is necessary
2534 // to ensure that other callbacks are not included in the timings.
2535 TimeProfilingPasses.registerCallbacks(PIC);
2536}
2537
2538template class ChangeReporter<std::string>;
2539template class TextChangeReporter<std::string>;
2540
2541template class BlockDataT<EmptyData>;
2542template class FuncDataT<EmptyData>;
2543template class IRDataT<EmptyData>;
2544template class ChangeReporter<IRDataT<EmptyData>>;
2546template class IRComparer<EmptyData>;
2547
2548} // 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< 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...
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
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 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 std::string getIRFileDisplayName(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 SmallVector< Function *, 1 > GetFunctions(Any IR)
static void printBBName(raw_ostream &out, const BasicBlock *BB)
static cl::opt< std::string > DotBinary("print-changed-dot-path", cl::Hidden, cl::init("dot"), cl::desc("system dot used by change reporters"))
static bool shouldGenerateData(const Function &F)
static 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 const IRUnitT * unwrapIR(Any IR)
static cl::opt< std::string > AfterColour("dot-cfg-after-color", cl::desc("Color for dot-cfg after elements"), cl::Hidden, cl::init("forestgreen"))
static cl::opt< bool > PrintOnCrash("print-on-crash", cl::desc("Print the last form of the IR before crash (use -print-on-crash-path to dump to a file)"), cl::Hidden)
static cl::opt< bool > PrintPassNumbers("print-pass-numbers", cl::init(false), cl::Hidden, cl::desc("Print pass names and their ordinals"))
static cl::opt< std::string > PrintOnCrashPath("print-on-crash-path", cl::desc("Print the last form of the IR before crash to a file"), cl::Hidden)
static void writeIRFileDisplayName(raw_ostream &ResultStream, Any IR)
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
void saveIRBeforePass(Any IR, StringRef PassID, StringRef PassName)
virtual void handleFiltered(StringRef PassID, std::string &Name)=0
virtual void handleAfter(StringRef PassID, std::string &Name, const IRUnitT &Before, const IRUnitT &After, Any)=0
virtual void handleIgnored(StringRef PassID, std::string &Name)=0
virtual void generateIRRepresentation(Any IR, StringRef PassID, IRUnitT &Output)=0
virtual void handleInitialIR(Any IR)=0
void handleIRAfterPass(Any IR, StringRef PassID, StringRef PassName)
virtual void handleInvalidated(StringRef PassID)=0
void registerRequiredCallbacks(PassInstrumentationCallbacks &PIC)
std::vector< IRUnitT > BeforeStack
virtual void omitAfter(StringRef PassID, std::string &Name)=0
void handleInvalidatedPass(StringRef PassID)
ChangeReporter(bool RunInVerboseMode)
Conditional Branch instruction.
void addSuccessorLabel(StringRef Succ, StringRef Label)
LLVM_ABI DCData(const BasicBlock &B)
std::unique_ptr< raw_fd_ostream > HTML
void handleInvalidated(StringRef PassID) override
void generateIRRepresentation(Any IR, StringRef PassID, IRDataT< DCData > &Output) override
static std::string genHTML(StringRef Text, StringRef DotFile, StringRef PDFFileName)
void handleFunctionCompare(StringRef Name, StringRef Prefix, StringRef PassID, StringRef Divider, bool InModule, unsigned Minor, const FuncDataT< DCData > &Before, const FuncDataT< DCData > &After)
void registerCallbacks(PassInstrumentationCallbacks &PIC)
void handleIgnored(StringRef PassID, std::string &Name) override
void handleAfter(StringRef PassID, std::string &Name, const IRDataT< DCData > &Before, const IRDataT< DCData > &After, Any) override
void handleFiltered(StringRef PassID, std::string &Name) override
void omitAfter(StringRef PassID, std::string &Name) override
Represents either an error or a value T.
Definition ErrorOr.h:56
std::string getEntryBlockName() const
bool hasOptNone() const
Do not optimize this function (-O0).
Definition Function.h:708
~IRChangedPrinter() override
void handleAfter(StringRef PassID, std::string &Name, const std::string &Before, const std::string &After, Any) override
void registerCallbacks(PassInstrumentationCallbacks &PIC)
void generateIRRepresentation(Any IR, StringRef PassID, std::string &Output) override
void handleIgnored(StringRef PassID, std::string &Name) override
void handleAfter(StringRef PassID, std::string &Name, const std::string &Before, const std::string &After, Any) override
void omitAfter(StringRef PassID, std::string &Name) override
void handleInvalidated(StringRef PassID) override
void handleIR(const std::string &IR, StringRef PassID)
void handleInitialIR(Any IR) override
void registerCallbacks(PassInstrumentationCallbacks &PIC)
void handleFiltered(StringRef PassID, std::string &Name) override
~IRChangedTester() override
const IRDataT< T > & Before
static bool generateFunctionData(IRDataT< T > &Data, const FunctionT &F)
const IRDataT< T > & After
static void analyzeIR(Any IR, IRDataT< T > &Data)
void compare(bool CompareModule, std::function< void(bool InModule, unsigned Minor, const FuncDataT< T > &Before, const FuncDataT< T > &After)> CompareFunc)
void registerCallbacks(PassInstrumentationCallbacks &PIC)
void handleAfter(StringRef PassID, std::string &Name, const IRDataT< EmptyData > &Before, const IRDataT< EmptyData > &After, Any) override
void generateIRRepresentation(Any IR, StringRef PassID, IRDataT< EmptyData > &Output) override
void handleFunctionCompare(StringRef Name, StringRef Prefix, StringRef PassID, StringRef Divider, bool InModule, unsigned Minor, const FuncDataT< EmptyData > &Before, const FuncDataT< EmptyData > &After)
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, 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:629
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:649
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:623
std::pair< StringRef, StringRef > rsplit(StringRef Separator) const
Split into two substrings around the last occurrence of a separator string.
Definition StringRef.h:763
bool consume_front(char Prefix)
Returns true if this StringRef has the given prefix and removes that prefix.
Definition StringRef.h:655
Multiway switch.
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
@ C
The default llvm calling convention, compatible with C.
Definition CallingConv.h:34
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.
FunctionAddr VTableAddr Value
Definition InstrProf.h:137
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:1668
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
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:1745
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)
FunctionAddr VTableAddr Count
Definition InstrProf.h:139
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
FunctionAddr VTableAddr uintptr_t uintptr_t Data
Definition InstrProf.h:221
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.
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:1946
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.