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