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