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