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