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