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