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