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