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