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