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 == PassID && "malformed PassRunDescriptorStack");
826 return Descriptor;
827}
828
829// Callers are responsible for closing the returned file descriptor
830static int prepareDumpIRFileDescriptor(const StringRef DumpIRFilename) {
831 std::error_code EC;
832 auto ParentPath = llvm::sys::path::parent_path(DumpIRFilename);
833 if (!ParentPath.empty()) {
834 std::error_code EC = llvm::sys::fs::create_directories(ParentPath);
835 if (EC)
836 report_fatal_error(Twine("Failed to create directory ") + ParentPath +
837 " to support -ir-dump-directory: " + EC.message());
838 }
839 int Result = 0;
840 EC = sys::fs::openFile(DumpIRFilename, Result, sys::fs::CD_OpenAlways,
842 if (EC)
843 report_fatal_error(Twine("Failed to open ") + DumpIRFilename +
844 " to support -ir-dump-directory: " + EC.message());
845 return Result;
846}
847
848void PrintIRInstrumentation::printBeforePass(StringRef PassID, Any IR) {
849 if (isIgnored(PassID))
850 return;
851
852 std::string DumpIRFilename;
853 if (!IRDumpDirectory.empty() &&
854 (shouldPrintBeforePass(PassID) || shouldPrintAfterPass(PassID) ||
855 shouldPrintBeforeCurrentPassNumber() ||
856 shouldPrintAfterCurrentPassNumber()))
857 DumpIRFilename = fetchDumpFilename(PassID, IR);
858
859 // Saving Module for AfterPassInvalidated operations.
860 // Note: here we rely on a fact that we do not change modules while
861 // traversing the pipeline, so the latest captured module is good
862 // for all print operations that has not happen yet.
863 if (shouldPrintAfterPass(PassID))
864 pushPassRunDescriptor(PassID, IR, DumpIRFilename);
865
866 if (!shouldPrintIR(IR))
867 return;
868
869 ++CurrentPassNumber;
870
871 if (shouldPrintPassNumbers())
872 dbgs() << " Running pass " << CurrentPassNumber << " " << PassID
873 << " on " << getIRName(IR) << "\n";
874
875 if (shouldPrintAfterCurrentPassNumber())
876 pushPassRunDescriptor(PassID, IR, DumpIRFilename);
877
878 if (!shouldPrintBeforePass(PassID) && !shouldPrintBeforeCurrentPassNumber())
879 return;
880
881 auto WriteIRToStream = [&](raw_ostream &Stream) {
882 Stream << "; *** IR Dump Before ";
883 if (shouldPrintBeforeSomePassNumber())
884 Stream << CurrentPassNumber << "-";
885 Stream << PassID << " on " << getIRName(IR) << " ***\n";
886 unwrapAndPrint(Stream, IR);
887 };
888
889 if (!DumpIRFilename.empty()) {
890 DumpIRFilename += getFileSuffix(IRDumpFileSuffixType::Before);
891 llvm::raw_fd_ostream DumpIRFileStream{
892 prepareDumpIRFileDescriptor(DumpIRFilename), /* shouldClose */ true};
893 WriteIRToStream(DumpIRFileStream);
894 } else {
895 WriteIRToStream(dbgs());
896 }
897}
898
899void PrintIRInstrumentation::printAfterPass(StringRef PassID, Any IR) {
900 if (isIgnored(PassID))
901 return;
902
903 if (!shouldPrintAfterPass(PassID) && !shouldPrintAfterCurrentPassNumber())
904 return;
905
906 auto [M, DumpIRFilename, IRName, StoredPassID] = popPassRunDescriptor(PassID);
907 assert(StoredPassID == PassID && "mismatched PassID");
908
909 if (!shouldPrintIR(IR) ||
910 (!shouldPrintAfterPass(PassID) && !shouldPrintAfterCurrentPassNumber()))
911 return;
912
913 auto WriteIRToStream = [&](raw_ostream &Stream, const StringRef IRName) {
914 Stream << "; *** IR Dump After ";
915 if (shouldPrintAfterSomePassNumber())
916 Stream << CurrentPassNumber << "-";
917 Stream << StringRef(formatv("{0}", PassID)) << " on " << IRName << " ***\n";
918 unwrapAndPrint(Stream, IR);
919 };
920
921 if (!IRDumpDirectory.empty()) {
922 assert(!DumpIRFilename.empty() && "DumpIRFilename must not be empty and "
923 "should be set in printBeforePass");
924 const std::string DumpIRFilenameWithSuffix =
925 DumpIRFilename + getFileSuffix(IRDumpFileSuffixType::After).str();
926 llvm::raw_fd_ostream DumpIRFileStream{
927 prepareDumpIRFileDescriptor(DumpIRFilenameWithSuffix),
928 /* shouldClose */ true};
929 WriteIRToStream(DumpIRFileStream, IRName);
930 } else {
931 WriteIRToStream(dbgs(), IRName);
932 }
933}
934
935void PrintIRInstrumentation::printAfterPassInvalidated(StringRef PassID) {
936 if (isIgnored(PassID))
937 return;
938
939 if (!shouldPrintAfterPass(PassID) && !shouldPrintAfterCurrentPassNumber())
940 return;
941
942 auto [M, DumpIRFilename, IRName, StoredPassID] = popPassRunDescriptor(PassID);
943 assert(StoredPassID == PassID && "mismatched PassID");
944 // Additional filtering (e.g. -filter-print-func) can lead to module
945 // printing being skipped.
946 if (!M ||
947 (!shouldPrintAfterPass(PassID) && !shouldPrintAfterCurrentPassNumber()))
948 return;
949
950 auto WriteIRToStream = [&](raw_ostream &Stream, const Module *M,
951 const StringRef IRName) {
952 SmallString<20> Banner;
953 Banner = formatv("; *** IR Dump After {0} on {1} (invalidated) ***", PassID,
954 IRName);
955 Stream << Banner << "\n";
956 printIR(Stream, M);
957 };
958
959 if (!IRDumpDirectory.empty()) {
960 assert(!DumpIRFilename.empty() && "DumpIRFilename must not be empty and "
961 "should be set in printBeforePass");
962 const std::string DumpIRFilenameWithSuffix =
963 DumpIRFilename + getFileSuffix(IRDumpFileSuffixType::Invalidated).str();
964 llvm::raw_fd_ostream DumpIRFileStream{
965 prepareDumpIRFileDescriptor(DumpIRFilenameWithSuffix),
966 /* shouldClose */ true};
967 WriteIRToStream(DumpIRFileStream, M, IRName);
968 } else {
969 WriteIRToStream(dbgs(), M, IRName);
970 }
971}
972
973bool PrintIRInstrumentation::shouldPrintBeforePass(StringRef PassID) {
975 return true;
976
979}
980
981bool PrintIRInstrumentation::shouldPrintAfterPass(StringRef PassID) {
983 return true;
984
987}
988
989bool PrintIRInstrumentation::shouldPrintBeforeCurrentPassNumber() {
990 return shouldPrintBeforeSomePassNumber() &&
991 (CurrentPassNumber == PrintBeforePassNumber);
992}
993
994bool PrintIRInstrumentation::shouldPrintAfterCurrentPassNumber() {
995 return shouldPrintAfterSomePassNumber() &&
996 (CurrentPassNumber == PrintAfterPassNumber);
997}
998
999bool PrintIRInstrumentation::shouldPrintPassNumbers() {
1000 return PrintPassNumbers;
1001}
1002
1003bool PrintIRInstrumentation::shouldPrintBeforeSomePassNumber() {
1004 return PrintBeforePassNumber > 0;
1005}
1006
1007bool PrintIRInstrumentation::shouldPrintAfterSomePassNumber() {
1008 return PrintAfterPassNumber > 0;
1009}
1010
1013 this->PIC = &PIC;
1014
1015 // BeforePass callback is not just for printing, it also saves a Module
1016 // for later use in AfterPassInvalidated and keeps tracks of the
1017 // CurrentPassNumber.
1018 if (shouldPrintPassNumbers() || shouldPrintBeforeSomePassNumber() ||
1019 shouldPrintAfterSomePassNumber() || shouldPrintBeforeSomePass() ||
1022 [this](StringRef P, Any IR) { this->printBeforePass(P, IR); });
1023
1024 if (shouldPrintAfterSomePass() || shouldPrintAfterSomePassNumber()) {
1026 [this](StringRef P, Any IR, const PreservedAnalyses &) {
1027 this->printAfterPass(P, IR);
1028 });
1030 [this](StringRef P, const PreservedAnalyses &) {
1031 this->printAfterPassInvalidated(P);
1032 });
1033 }
1034}
1035
1039 [this](StringRef P, Any IR) { return this->shouldRun(P, IR); });
1040}
1041
1042bool OptNoneInstrumentation::shouldRun(StringRef PassID, Any IR) {
1043 const auto *F = unwrapIR<Function>(IR);
1044 if (!F) {
1045 if (const auto *L = unwrapIR<Loop>(IR))
1046 F = L->getHeader()->getParent();
1047 }
1048 bool ShouldRun = !(F && F->hasOptNone());
1049 if (!ShouldRun && DebugLogging) {
1050 errs() << "Skipping pass " << PassID << " on " << F->getName()
1051 << " due to optnone attribute\n";
1052 }
1053 return ShouldRun;
1054}
1055
1057 if (isIgnored(PassName))
1058 return true;
1059
1060 bool ShouldRun =
1061 Context.getOptPassGate().shouldRunPass(PassName, getIRName(IR));
1062 if (!ShouldRun && !this->HasWrittenIR && !OptBisectPrintIRPath.empty()) {
1063 // FIXME: print IR if limit is higher than number of opt-bisect
1064 // invocations
1065 this->HasWrittenIR = true;
1066 const Module *M = unwrapModule(IR, /*Force=*/true);
1067 assert((M && &M->getContext() == &Context) && "Missing/Mismatching Module");
1068 std::error_code EC;
1070 if (EC)
1072 M->print(OS, nullptr);
1073 }
1074 return ShouldRun;
1075}
1076
1079 OptPassGate &PassGate = Context.getOptPassGate();
1080 if (!PassGate.isEnabled())
1081 return;
1082
1084 return this->shouldRun(PassName, IR);
1085 });
1086}
1087
1088raw_ostream &PrintPassInstrumentation::print() {
1089 if (Opts.Indent) {
1090 assert(Indent >= 0);
1091 dbgs().indent(Indent);
1092 }
1093 return dbgs();
1094}
1095
1098 if (!Enabled)
1099 return;
1100
1101 std::vector<StringRef> SpecialPasses;
1102 if (!Opts.Verbose) {
1103 SpecialPasses.emplace_back("PassManager");
1104 SpecialPasses.emplace_back("PassAdaptor");
1105 }
1106
1107 PIC.registerBeforeSkippedPassCallback([this, SpecialPasses](StringRef PassID,
1108 Any IR) {
1109 assert(!isSpecialPass(PassID, SpecialPasses) &&
1110 "Unexpectedly skipping special pass");
1111
1112 print() << "Skipping pass: " << PassID << " on " << getIRName(IR) << "\n";
1113 });
1114 PIC.registerBeforeNonSkippedPassCallback([this, SpecialPasses](
1115 StringRef PassID, Any IR) {
1116 if (isSpecialPass(PassID, SpecialPasses))
1117 return;
1118
1119 auto &OS = print();
1120 OS << "Running pass: " << PassID << " on " << getIRName(IR);
1121 if (const auto *F = unwrapIR<Function>(IR)) {
1122 unsigned Count = F->getInstructionCount();
1123 OS << " (" << Count << " instruction";
1124 if (Count != 1)
1125 OS << 's';
1126 OS << ')';
1127 } else if (const auto *C = unwrapIR<LazyCallGraph::SCC>(IR)) {
1128 int Count = C->size();
1129 OS << " (" << Count << " node";
1130 if (Count != 1)
1131 OS << 's';
1132 OS << ')';
1133 }
1134 OS << "\n";
1135 Indent += 2;
1136 });
1138 [this, SpecialPasses](StringRef PassID, Any IR,
1139 const PreservedAnalyses &) {
1140 if (isSpecialPass(PassID, SpecialPasses))
1141 return;
1142
1143 Indent -= 2;
1144 });
1146 [this, SpecialPasses](StringRef PassID, Any IR) {
1147 if (isSpecialPass(PassID, SpecialPasses))
1148 return;
1149
1150 Indent -= 2;
1151 });
1152
1153 if (!Opts.SkipAnalyses) {
1155 print() << "Running analysis: " << PassID << " on " << getIRName(IR)
1156 << "\n";
1157 Indent += 2;
1158 });
1160 [this](StringRef PassID, Any IR) { Indent -= 2; });
1162 print() << "Invalidating analysis: " << PassID << " on " << getIRName(IR)
1163 << "\n";
1164 });
1166 print() << "Clearing all analysis results for: " << IRName << "\n";
1167 });
1168 }
1169}
1170
1172 bool TrackBBLifetime) {
1173 if (TrackBBLifetime)
1175 for (const auto &BB : *F) {
1176 if (BBGuards)
1177 BBGuards->try_emplace(intptr_t(&BB), &BB);
1178 for (const auto *Succ : successors(&BB)) {
1179 Graph[&BB][Succ]++;
1180 if (BBGuards)
1181 BBGuards->try_emplace(intptr_t(Succ), Succ);
1182 }
1183 }
1184}
1185
1186static void printBBName(raw_ostream &out, const BasicBlock *BB) {
1187 if (BB->hasName()) {
1188 out << BB->getName() << "<" << BB << ">";
1189 return;
1190 }
1191
1192 if (!BB->getParent()) {
1193 out << "unnamed_removed<" << BB << ">";
1194 return;
1195 }
1196
1197 if (BB->isEntryBlock()) {
1198 out << "entry"
1199 << "<" << BB << ">";
1200 return;
1201 }
1202
1203 unsigned FuncOrderBlockNum = 0;
1204 for (auto &FuncBB : *BB->getParent()) {
1205 if (&FuncBB == BB)
1206 break;
1207 FuncOrderBlockNum++;
1208 }
1209 out << "unnamed_" << FuncOrderBlockNum << "<" << BB << ">";
1210}
1211
1213 const CFG &Before,
1214 const CFG &After) {
1215 assert(!After.isPoisoned());
1216 if (Before.isPoisoned()) {
1217 out << "Some blocks were deleted\n";
1218 return;
1219 }
1220
1221 // Find and print graph differences.
1222 if (Before.Graph.size() != After.Graph.size())
1223 out << "Different number of non-leaf basic blocks: before="
1224 << Before.Graph.size() << ", after=" << After.Graph.size() << "\n";
1225
1226 for (auto &BB : Before.Graph) {
1227 auto BA = After.Graph.find(BB.first);
1228 if (BA == After.Graph.end()) {
1229 out << "Non-leaf block ";
1230 printBBName(out, BB.first);
1231 out << " is removed (" << BB.second.size() << " successors)\n";
1232 }
1233 }
1234
1235 for (auto &BA : After.Graph) {
1236 auto BB = Before.Graph.find(BA.first);
1237 if (BB == Before.Graph.end()) {
1238 out << "Non-leaf block ";
1239 printBBName(out, BA.first);
1240 out << " is added (" << BA.second.size() << " successors)\n";
1241 continue;
1242 }
1243
1244 if (BB->second == BA.second)
1245 continue;
1246
1247 out << "Different successors of block ";
1248 printBBName(out, BA.first);
1249 out << " (unordered):\n";
1250 out << "- before (" << BB->second.size() << "): ";
1251 for (auto &SuccB : BB->second) {
1252 printBBName(out, SuccB.first);
1253 if (SuccB.second != 1)
1254 out << "(" << SuccB.second << "), ";
1255 else
1256 out << ", ";
1257 }
1258 out << "\n";
1259 out << "- after (" << BA.second.size() << "): ";
1260 for (auto &SuccA : BA.second) {
1261 printBBName(out, SuccA.first);
1262 if (SuccA.second != 1)
1263 out << "(" << SuccA.second << "), ";
1264 else
1265 out << ", ";
1266 }
1267 out << "\n";
1268 }
1269}
1270
1271// PreservedCFGCheckerInstrumentation uses PreservedCFGCheckerAnalysis to check
1272// passes, that reported they kept CFG analyses up-to-date, did not actually
1273// change CFG. This check is done as follows. Before every functional pass in
1274// BeforeNonSkippedPassCallback a CFG snapshot (an instance of
1275// PreservedCFGCheckerInstrumentation::CFG) is requested from
1276// FunctionAnalysisManager as a result of PreservedCFGCheckerAnalysis. When the
1277// functional pass finishes and reports that CFGAnalyses or AllAnalyses are
1278// up-to-date then the cached result of PreservedCFGCheckerAnalysis (if
1279// available) is checked to be equal to a freshly created CFG snapshot.
1281 : public AnalysisInfoMixin<PreservedCFGCheckerAnalysis> {
1283
1285
1286public:
1287 /// Provide the result type for this analysis pass.
1289
1290 /// Run the analysis pass over a function and produce CFG.
1292 return Result(&F, /* TrackBBLifetime */ true);
1293 }
1294};
1295
1297
1299 : public AnalysisInfoMixin<PreservedFunctionHashAnalysis> {
1301
1304 };
1305
1307
1309 return Result{StructuralHash(F)};
1310 }
1311};
1312
1314
1316 : public AnalysisInfoMixin<PreservedModuleHashAnalysis> {
1318
1319 struct ModuleHash {
1321 };
1322
1324
1326 return Result{StructuralHash(F)};
1327 }
1328};
1329
1331
1333 Function &F, const PreservedAnalyses &PA,
1335 auto PAC = PA.getChecker<PreservedCFGCheckerAnalysis>();
1336 return !(PAC.preserved() || PAC.preservedSet<AllAnalysesOn<Function>>() ||
1337 PAC.preservedSet<CFGAnalyses>());
1338}
1339
1342
1343 if (const auto *MaybeF = unwrapIR<Function>(IR)) {
1344 Functions.push_back(const_cast<Function *>(MaybeF));
1345 } else if (const auto *MaybeM = unwrapIR<Module>(IR)) {
1346 for (Function &F : *const_cast<Module *>(MaybeM))
1347 Functions.push_back(&F);
1348 }
1349 return Functions;
1350}
1351
1355 return;
1356
1357 bool Registered = false;
1358 PIC.registerBeforeNonSkippedPassCallback([this, &MAM, Registered](
1359 StringRef P, Any IR) mutable {
1360#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
1361 assert(&PassStack.emplace_back(P));
1362#endif
1363 (void)this;
1364
1366 *const_cast<Module *>(unwrapModule(IR, /*Force=*/true)))
1367 .getManager();
1368 if (!Registered) {
1369 FAM.registerPass([&] { return PreservedCFGCheckerAnalysis(); });
1371 MAM.registerPass([&] { return PreservedModuleHashAnalysis(); });
1372 Registered = true;
1373 }
1374
1375 for (Function *F : GetFunctions(IR)) {
1376 // Make sure a fresh CFG snapshot is available before the pass.
1379 }
1380
1381 if (const auto *MPtr = unwrapIR<Module>(IR)) {
1382 auto &M = *const_cast<Module *>(MPtr);
1384 }
1385 });
1386
1388 [this](StringRef P, const PreservedAnalyses &PassPA) {
1389#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
1390 assert(PassStack.pop_back_val() == P &&
1391 "Before and After callbacks must correspond");
1392#endif
1393 (void)this;
1394 });
1395
1397 const PreservedAnalyses &PassPA) {
1398#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
1399 assert(PassStack.pop_back_val() == P &&
1400 "Before and After callbacks must correspond");
1401#endif
1402 (void)this;
1403
1404 // We have to get the FAM via the MAM, rather than directly use a passed in
1405 // FAM because if MAM has not cached the FAM, it won't invalidate function
1406 // analyses in FAM.
1408 *const_cast<Module *>(unwrapModule(IR, /*Force=*/true)))
1409 .getManager();
1410
1411 for (Function *F : GetFunctions(IR)) {
1412 if (auto *HashBefore =
1414 if (HashBefore->Hash != StructuralHash(*F)) {
1416 "Function @{0} changed by {1} without invalidating analyses",
1417 F->getName(), P));
1418 }
1419 }
1420
1421 auto CheckCFG = [](StringRef Pass, StringRef FuncName,
1422 const CFG &GraphBefore, const CFG &GraphAfter) {
1423 if (GraphAfter == GraphBefore)
1424 return;
1425
1426 dbgs()
1427 << "Error: " << Pass
1428 << " does not invalidate CFG analyses but CFG changes detected in "
1429 "function @"
1430 << FuncName << ":\n";
1431 CFG::printDiff(dbgs(), GraphBefore, GraphAfter);
1432 report_fatal_error(Twine("CFG unexpectedly changed by ", Pass));
1433 };
1434
1435 if (auto *GraphBefore =
1437 CheckCFG(P, F->getName(), *GraphBefore,
1438 CFG(F, /* TrackBBLifetime */ false));
1439 }
1440 if (const auto *MPtr = unwrapIR<Module>(IR)) {
1441 auto &M = *const_cast<Module *>(MPtr);
1442 if (auto *HashBefore =
1444 if (HashBefore->Hash != StructuralHash(M)) {
1446 "Module changed by {0} without invalidating analyses", P));
1447 }
1448 }
1449 }
1450 });
1451}
1452
1456 [this](StringRef P, Any IR, const PreservedAnalyses &PassPA) {
1457 if (isIgnored(P) || P == "VerifierPass")
1458 return;
1459 const auto *F = unwrapIR<Function>(IR);
1460 if (!F) {
1461 if (const auto *L = unwrapIR<Loop>(IR))
1462 F = L->getHeader()->getParent();
1463 }
1464
1465 if (F) {
1466 if (DebugLogging)
1467 dbgs() << "Verifying function " << F->getName() << "\n";
1468
1469 if (verifyFunction(*F, &errs()))
1470 report_fatal_error(formatv("Broken function found after pass "
1471 "\"{0}\", compilation aborted!",
1472 P));
1473 } else {
1474 const auto *M = unwrapIR<Module>(IR);
1475 if (!M) {
1476 if (const auto *C = unwrapIR<LazyCallGraph::SCC>(IR))
1477 M = C->begin()->getFunction().getParent();
1478 }
1479
1480 if (M) {
1481 if (DebugLogging)
1482 dbgs() << "Verifying module " << M->getName() << "\n";
1483
1484 if (verifyModule(*M, &errs()))
1485 report_fatal_error(formatv("Broken module found after pass "
1486 "\"{0}\", compilation aborted!",
1487 P));
1488 }
1489
1490 // TODO: Use complete MachineVerifierPass.
1491 if (auto *MF = unwrapIR<MachineFunction>(IR)) {
1492 if (DebugLogging)
1493 dbgs() << "Verifying machine function " << MF->getName() << '\n';
1495 formatv("Broken machine function found after pass "
1496 "\"{0}\", compilation aborted!",
1497 P),
1498 *MF);
1499 }
1500 }
1501 });
1502}
1503
1505
1507 StringRef PassID,
1510}
1511
1515 Any IR) {
1516 SmallString<20> Banner =
1517 formatv("*** IR Dump After {0} on {1} ***\n", PassID, Name);
1518 Out << Banner;
1520 .compare(getModuleForComparison(IR),
1521 [&](bool InModule, unsigned Minor,
1523 const FuncDataT<EmptyData> &After) -> void {
1524 handleFunctionCompare(Name, "", PassID, " on ", InModule,
1525 Minor, Before, After);
1526 });
1527 Out << "\n";
1528}
1529
1531 StringRef Name, StringRef Prefix, StringRef PassID, StringRef Divider,
1532 bool InModule, unsigned Minor, const FuncDataT<EmptyData> &Before,
1533 const FuncDataT<EmptyData> &After) {
1534 // Print a banner when this is being shown in the context of a module
1535 if (InModule)
1536 Out << "\n*** IR for function " << Name << " ***\n";
1537
1539 Before, After,
1540 [&](const BlockDataT<EmptyData> *B, const BlockDataT<EmptyData> *A) {
1541 StringRef BStr = B ? B->getBody() : "\n";
1542 StringRef AStr = A ? A->getBody() : "\n";
1543 const std::string Removed =
1544 UseColour ? "\033[31m-%l\033[0m\n" : "-%l\n";
1545 const std::string Added = UseColour ? "\033[32m+%l\033[0m\n" : "+%l\n";
1546 const std::string NoChange = " %l\n";
1547 Out << doSystemDiff(BStr, AStr, Removed, Added, NoChange);
1548 });
1549}
1550
1556 TextChangeReporter<IRDataT<EmptyData>>::registerRequiredCallbacks(PIC);
1557}
1558
1560
1564 return;
1566 [this](StringRef P, Any IR) { this->runBeforePass(P, IR); });
1568 [this](StringRef P, Any IR, const PreservedAnalyses &) {
1569 this->runAfterPass();
1570 },
1571 true);
1573 [this](StringRef P, const PreservedAnalyses &) { this->runAfterPass(); },
1574 true);
1576 [this](StringRef P, Any IR) { this->runBeforePass(P, IR); });
1578 [this](StringRef P, Any IR) { this->runAfterPass(); }, true);
1579}
1580
1581void TimeProfilingPassesHandler::runBeforePass(StringRef PassID, Any IR) {
1582 timeTraceProfilerBegin(PassID, getIRName(IR));
1583}
1584
1585void TimeProfilingPassesHandler::runAfterPass() { timeTraceProfilerEnd(); }
1586
1587namespace {
1588
1589class DisplayNode;
1590class DotCfgDiffDisplayGraph;
1591
1592// Base class for a node or edge in the dot-cfg-changes graph.
1593class DisplayElement {
1594public:
1595 // Is this in before, after, or both?
1596 StringRef getColour() const { return Colour; }
1597
1598protected:
1599 DisplayElement(StringRef Colour) : Colour(Colour) {}
1600 const StringRef Colour;
1601};
1602
1603// An edge representing a transition between basic blocks in the
1604// dot-cfg-changes graph.
1605class DisplayEdge : public DisplayElement {
1606public:
1607 DisplayEdge(std::string Value, DisplayNode &Node, StringRef Colour)
1608 : DisplayElement(Colour), Value(Value), Node(Node) {}
1609 // The value on which the transition is made.
1610 std::string getValue() const { return Value; }
1611 // The node (representing a basic block) reached by this transition.
1612 const DisplayNode &getDestinationNode() const { return Node; }
1613
1614protected:
1615 std::string Value;
1616 const DisplayNode &Node;
1617};
1618
1619// A node in the dot-cfg-changes graph which represents a basic block.
1620class DisplayNode : public DisplayElement {
1621public:
1622 // \p C is the content for the node, \p T indicates the colour for the
1623 // outline of the node
1624 DisplayNode(std::string Content, StringRef Colour)
1625 : DisplayElement(Colour), Content(Content) {}
1626
1627 // Iterator to the child nodes. Required by GraphWriter.
1628 using ChildIterator = std::unordered_set<DisplayNode *>::const_iterator;
1629 ChildIterator children_begin() const { return Children.cbegin(); }
1630 ChildIterator children_end() const { return Children.cend(); }
1631
1632 // Iterator for the edges. Required by GraphWriter.
1633 using EdgeIterator = std::vector<DisplayEdge *>::const_iterator;
1634 EdgeIterator edges_begin() const { return EdgePtrs.cbegin(); }
1635 EdgeIterator edges_end() const { return EdgePtrs.cend(); }
1636
1637 // Create an edge to \p Node on value \p Value, with colour \p Colour.
1638 void createEdge(StringRef Value, DisplayNode &Node, StringRef Colour);
1639
1640 // Return the content of this node.
1641 std::string getContent() const { return Content; }
1642
1643 // Return the edge to node \p S.
1644 const DisplayEdge &getEdge(const DisplayNode &To) const {
1645 assert(EdgeMap.find(&To) != EdgeMap.end() && "Expected to find edge.");
1646 return *EdgeMap.find(&To)->second;
1647 }
1648
1649 // Return the value for the transition to basic block \p S.
1650 // Required by GraphWriter.
1651 std::string getEdgeSourceLabel(const DisplayNode &Sink) const {
1652 return getEdge(Sink).getValue();
1653 }
1654
1655 void createEdgeMap();
1656
1657protected:
1658 const std::string Content;
1659
1660 // Place to collect all of the edges. Once they are all in the vector,
1661 // the vector will not reallocate so then we can use pointers to them,
1662 // which are required by the graph writing routines.
1663 std::vector<DisplayEdge> Edges;
1664
1665 std::vector<DisplayEdge *> EdgePtrs;
1666 std::unordered_set<DisplayNode *> Children;
1667 std::unordered_map<const DisplayNode *, const DisplayEdge *> EdgeMap;
1668
1669 // Safeguard adding of edges.
1670 bool AllEdgesCreated = false;
1671};
1672
1673// Class representing a difference display (corresponds to a pdf file).
1674class DotCfgDiffDisplayGraph {
1675public:
1676 DotCfgDiffDisplayGraph(std::string Name) : GraphName(Name) {}
1677
1678 // Generate the file into \p DotFile.
1679 void generateDotFile(StringRef DotFile);
1680
1681 // Iterator to the nodes. Required by GraphWriter.
1682 using NodeIterator = std::vector<DisplayNode *>::const_iterator;
1683 NodeIterator nodes_begin() const {
1684 assert(NodeGenerationComplete && "Unexpected children iterator creation");
1685 return NodePtrs.cbegin();
1686 }
1687 NodeIterator nodes_end() const {
1688 assert(NodeGenerationComplete && "Unexpected children iterator creation");
1689 return NodePtrs.cend();
1690 }
1691
1692 // Record the index of the entry node. At this point, we can build up
1693 // vectors of pointers that are required by the graph routines.
1694 void setEntryNode(unsigned N) {
1695 // At this point, there will be no new nodes.
1696 assert(!NodeGenerationComplete && "Unexpected node creation");
1697 NodeGenerationComplete = true;
1698 for (auto &N : Nodes)
1699 NodePtrs.emplace_back(&N);
1700
1701 EntryNode = NodePtrs[N];
1702 }
1703
1704 // Create a node.
1705 void createNode(std::string C, StringRef Colour) {
1706 assert(!NodeGenerationComplete && "Unexpected node creation");
1707 Nodes.emplace_back(C, Colour);
1708 }
1709 // Return the node at index \p N to avoid problems with vectors reallocating.
1710 DisplayNode &getNode(unsigned N) {
1711 assert(N < Nodes.size() && "Node is out of bounds");
1712 return Nodes[N];
1713 }
1714 unsigned size() const {
1715 assert(NodeGenerationComplete && "Unexpected children iterator creation");
1716 return Nodes.size();
1717 }
1718
1719 // Return the name of the graph. Required by GraphWriter.
1720 std::string getGraphName() const { return GraphName; }
1721
1722 // Return the string representing the differences for basic block \p Node.
1723 // Required by GraphWriter.
1724 std::string getNodeLabel(const DisplayNode &Node) const {
1725 return Node.getContent();
1726 }
1727
1728 // Return a string with colour information for Dot. Required by GraphWriter.
1729 std::string getNodeAttributes(const DisplayNode &Node) const {
1730 return attribute(Node.getColour());
1731 }
1732
1733 // Return a string with colour information for Dot. Required by GraphWriter.
1734 std::string getEdgeColorAttr(const DisplayNode &From,
1735 const DisplayNode &To) const {
1736 return attribute(From.getEdge(To).getColour());
1737 }
1738
1739 // Get the starting basic block. Required by GraphWriter.
1740 DisplayNode *getEntryNode() const {
1741 assert(NodeGenerationComplete && "Unexpected children iterator creation");
1742 return EntryNode;
1743 }
1744
1745protected:
1746 // Return the string containing the colour to use as a Dot attribute.
1747 std::string attribute(StringRef Colour) const {
1748 return "color=" + Colour.str();
1749 }
1750
1751 bool NodeGenerationComplete = false;
1752 const std::string GraphName;
1753 std::vector<DisplayNode> Nodes;
1754 std::vector<DisplayNode *> NodePtrs;
1755 DisplayNode *EntryNode = nullptr;
1756};
1757
1758void DisplayNode::createEdge(StringRef Value, DisplayNode &Node,
1759 StringRef Colour) {
1760 assert(!AllEdgesCreated && "Expected to be able to still create edges.");
1761 Edges.emplace_back(Value.str(), Node, Colour);
1762 Children.insert(&Node);
1763}
1764
1765void DisplayNode::createEdgeMap() {
1766 // No more edges will be added so we can now use pointers to the edges
1767 // as the vector will not grow and reallocate.
1768 AllEdgesCreated = true;
1769 for (auto &E : Edges)
1770 EdgeMap.insert({&E.getDestinationNode(), &E});
1771}
1772
1773class DotCfgDiffNode;
1774class DotCfgDiff;
1775
1776// A class representing a basic block in the Dot difference graph.
1777class DotCfgDiffNode {
1778public:
1779 DotCfgDiffNode() = delete;
1780
1781 // Create a node in Dot difference graph \p G representing the basic block
1782 // represented by \p BD with colour \p Colour (where it exists).
1783 DotCfgDiffNode(DotCfgDiff &G, unsigned N, const BlockDataT<DCData> &BD,
1784 StringRef Colour)
1785 : Graph(G), N(N), Data{&BD, nullptr}, Colour(Colour) {}
1786 DotCfgDiffNode(const DotCfgDiffNode &DN)
1787 : Graph(DN.Graph), N(DN.N), Data{DN.Data[0], DN.Data[1]},
1788 Colour(DN.Colour), EdgesMap(DN.EdgesMap), Children(DN.Children),
1789 Edges(DN.Edges) {}
1790
1791 unsigned getIndex() const { return N; }
1792
1793 // The label of the basic block
1794 StringRef getLabel() const {
1795 assert(Data[0] && "Expected Data[0] to be set.");
1796 return Data[0]->getLabel();
1797 }
1798 // Return the colour for this block
1799 StringRef getColour() const { return Colour; }
1800 // Change this basic block from being only in before to being common.
1801 // Save the pointer to \p Other.
1802 void setCommon(const BlockDataT<DCData> &Other) {
1803 assert(!Data[1] && "Expected only one block datum");
1804 Data[1] = &Other;
1805 Colour = CommonColour;
1806 }
1807 // Add an edge to \p E of colour {\p Value, \p Colour}.
1808 void addEdge(unsigned E, StringRef Value, StringRef Colour) {
1809 // This is a new edge or it is an edge being made common.
1810 assert((EdgesMap.count(E) == 0 || Colour == CommonColour) &&
1811 "Unexpected edge count and color.");
1812 EdgesMap[E] = {Value.str(), Colour};
1813 }
1814 // Record the children and create edges.
1815 void finalize(DotCfgDiff &G);
1816
1817 // Return the colour of the edge to node \p S.
1818 StringRef getEdgeColour(const unsigned S) const {
1819 assert(EdgesMap.count(S) == 1 && "Expected to find edge.");
1820 return EdgesMap.at(S).second;
1821 }
1822
1823 // Return the string representing the basic block.
1824 std::string getBodyContent() const;
1825
1826 void createDisplayEdges(DotCfgDiffDisplayGraph &Graph, unsigned DisplayNode,
1827 std::map<const unsigned, unsigned> &NodeMap) const;
1828
1829protected:
1830 DotCfgDiff &Graph;
1831 const unsigned N;
1832 const BlockDataT<DCData> *Data[2];
1833 StringRef Colour;
1834 std::map<const unsigned, std::pair<std::string, StringRef>> EdgesMap;
1835 std::vector<unsigned> Children;
1836 std::vector<unsigned> Edges;
1837};
1838
1839// Class representing the difference graph between two functions.
1840class DotCfgDiff {
1841public:
1842 // \p Title is the title given to the graph. \p EntryNodeName is the
1843 // entry node for the function. \p Before and \p After are the before
1844 // after versions of the function, respectively. \p Dir is the directory
1845 // in which to store the results.
1846 DotCfgDiff(StringRef Title, const FuncDataT<DCData> &Before,
1847 const FuncDataT<DCData> &After);
1848
1849 DotCfgDiff(const DotCfgDiff &) = delete;
1850 DotCfgDiff &operator=(const DotCfgDiff &) = delete;
1851
1852 DotCfgDiffDisplayGraph createDisplayGraph(StringRef Title,
1853 StringRef EntryNodeName);
1854
1855 // Return a string consisting of the labels for the \p Source and \p Sink.
1856 // The combination allows distinguishing changing transitions on the
1857 // same value (ie, a transition went to X before and goes to Y after).
1858 // Required by GraphWriter.
1859 StringRef getEdgeSourceLabel(const unsigned &Source,
1860 const unsigned &Sink) const {
1861 std::string S =
1862 getNode(Source).getLabel().str() + " " + getNode(Sink).getLabel().str();
1863 assert(EdgeLabels.count(S) == 1 && "Expected to find edge label.");
1864 return EdgeLabels.find(S)->getValue();
1865 }
1866
1867 // Return the number of basic blocks (nodes). Required by GraphWriter.
1868 unsigned size() const { return Nodes.size(); }
1869
1870 const DotCfgDiffNode &getNode(unsigned N) const {
1871 assert(N < Nodes.size() && "Unexpected index for node reference");
1872 return Nodes[N];
1873 }
1874
1875protected:
1876 // Return the string surrounded by HTML to make it the appropriate colour.
1877 std::string colourize(std::string S, StringRef Colour) const;
1878
1879 void createNode(StringRef Label, const BlockDataT<DCData> &BD, StringRef C) {
1880 unsigned Pos = Nodes.size();
1881 Nodes.emplace_back(*this, Pos, BD, C);
1882 NodePosition.insert({Label, Pos});
1883 }
1884
1885 // TODO Nodes should probably be a StringMap<DotCfgDiffNode> after the
1886 // display graph is separated out, which would remove the need for
1887 // NodePosition.
1888 std::vector<DotCfgDiffNode> Nodes;
1889 StringMap<unsigned> NodePosition;
1890 const std::string GraphName;
1891
1892 StringMap<std::string> EdgeLabels;
1893};
1894
1895std::string DotCfgDiffNode::getBodyContent() const {
1896 if (Colour == CommonColour) {
1897 assert(Data[1] && "Expected Data[1] to be set.");
1898
1899 StringRef SR[2];
1900 for (unsigned I = 0; I < 2; ++I) {
1901 SR[I] = Data[I]->getBody();
1902 // drop initial '\n' if present
1903 SR[I].consume_front("\n");
1904 // drop predecessors as they can be big and are redundant
1905 SR[I] = SR[I].drop_until([](char C) { return C == '\n'; }).drop_front();
1906 }
1907
1908 SmallString<80> OldLineFormat = formatv(
1909 "<FONT COLOR=\"{0}\">%l</FONT><BR align=\"left\"/>", BeforeColour);
1910 SmallString<80> NewLineFormat = formatv(
1911 "<FONT COLOR=\"{0}\">%l</FONT><BR align=\"left\"/>", AfterColour);
1912 SmallString<80> UnchangedLineFormat = formatv(
1913 "<FONT COLOR=\"{0}\">%l</FONT><BR align=\"left\"/>", CommonColour);
1914 std::string Diff = Data[0]->getLabel().str();
1915 Diff += ":\n<BR align=\"left\"/>" +
1916 doSystemDiff(makeHTMLReady(SR[0]), makeHTMLReady(SR[1]),
1917 OldLineFormat, NewLineFormat, UnchangedLineFormat);
1918
1919 // Diff adds in some empty colour changes which are not valid HTML
1920 // so remove them. Colours are all lowercase alpha characters (as
1921 // listed in https://graphviz.org/pdf/dotguide.pdf).
1922 Regex R("<FONT COLOR=\"\\w+\"></FONT>");
1923 while (true) {
1924 std::string Error;
1925 std::string S = R.sub("", Diff, &Error);
1926 if (Error != "")
1927 return Error;
1928 if (S == Diff)
1929 return Diff;
1930 Diff = S;
1931 }
1932 llvm_unreachable("Should not get here");
1933 }
1934
1935 // Put node out in the appropriate colour.
1936 assert(!Data[1] && "Data[1] is set unexpectedly.");
1937 std::string Body = makeHTMLReady(Data[0]->getBody());
1938 const StringRef BS = Body;
1939 StringRef BS1 = BS;
1940 // Drop leading newline, if present.
1941 if (BS.front() == '\n')
1942 BS1 = BS1.drop_front(1);
1943 // Get label.
1944 StringRef Label = BS1.take_until([](char C) { return C == ':'; });
1945 // drop predecessors as they can be big and are redundant
1946 BS1 = BS1.drop_until([](char C) { return C == '\n'; }).drop_front();
1947
1948 std::string S = "<FONT COLOR=\"" + Colour.str() + "\">" + Label.str() + ":";
1949
1950 // align each line to the left.
1951 while (BS1.size()) {
1952 S.append("<BR align=\"left\"/>");
1953 StringRef Line = BS1.take_until([](char C) { return C == '\n'; });
1954 S.append(Line.str());
1955 BS1 = BS1.drop_front(Line.size() + 1);
1956 }
1957 S.append("<BR align=\"left\"/></FONT>");
1958 return S;
1959}
1960
1961std::string DotCfgDiff::colourize(std::string S, StringRef Colour) const {
1962 if (S.length() == 0)
1963 return S;
1964 return "<FONT COLOR=\"" + Colour.str() + "\">" + S + "</FONT>";
1965}
1966
1967DotCfgDiff::DotCfgDiff(StringRef Title, const FuncDataT<DCData> &Before,
1968 const FuncDataT<DCData> &After)
1969 : GraphName(Title.str()) {
1970 StringMap<StringRef> EdgesMap;
1971
1972 // Handle each basic block in the before IR.
1973 for (auto &B : Before.getData()) {
1974 StringRef Label = B.getKey();
1975 const BlockDataT<DCData> &BD = B.getValue();
1976 createNode(Label, BD, BeforeColour);
1977
1978 // Create transitions with names made up of the from block label, the value
1979 // on which the transition is made and the to block label.
1980 for (StringMap<std::string>::const_iterator Sink = BD.getData().begin(),
1981 E = BD.getData().end();
1982 Sink != E; ++Sink) {
1983 std::string Key = (Label + " " + Sink->getKey().str()).str() + " " +
1984 BD.getData().getSuccessorLabel(Sink->getKey()).str();
1985 EdgesMap.insert({Key, BeforeColour});
1986 }
1987 }
1988
1989 // Handle each basic block in the after IR
1990 for (auto &A : After.getData()) {
1991 StringRef Label = A.getKey();
1992 const BlockDataT<DCData> &BD = A.getValue();
1993 unsigned C = NodePosition.count(Label);
1994 if (C == 0)
1995 // This only exists in the after IR. Create the node.
1996 createNode(Label, BD, AfterColour);
1997 else {
1998 assert(C == 1 && "Unexpected multiple nodes.");
1999 Nodes[NodePosition[Label]].setCommon(BD);
2000 }
2001 // Add in the edges between the nodes (as common or only in after).
2002 for (StringMap<std::string>::const_iterator Sink = BD.getData().begin(),
2003 E = BD.getData().end();
2004 Sink != E; ++Sink) {
2005 std::string Key = (Label + " " + Sink->getKey().str()).str() + " " +
2006 BD.getData().getSuccessorLabel(Sink->getKey()).str();
2007 unsigned C = EdgesMap.count(Key);
2008 if (C == 0)
2009 EdgesMap.insert({Key, AfterColour});
2010 else {
2011 EdgesMap[Key] = CommonColour;
2012 }
2013 }
2014 }
2015
2016 // Now go through the map of edges and add them to the node.
2017 for (auto &E : EdgesMap) {
2018 // Extract the source, sink and value from the edge key.
2019 StringRef S = E.getKey();
2020 auto SP1 = S.rsplit(' ');
2021 auto &SourceSink = SP1.first;
2022 auto SP2 = SourceSink.split(' ');
2023 StringRef Source = SP2.first;
2024 StringRef Sink = SP2.second;
2025 StringRef Value = SP1.second;
2026
2027 assert(NodePosition.count(Source) == 1 && "Expected to find node.");
2028 DotCfgDiffNode &SourceNode = Nodes[NodePosition[Source]];
2029 assert(NodePosition.count(Sink) == 1 && "Expected to find node.");
2030 unsigned SinkNode = NodePosition[Sink];
2031 StringRef Colour = E.second;
2032
2033 // Look for an edge from Source to Sink
2034 if (EdgeLabels.count(SourceSink) == 0)
2035 EdgeLabels.insert({SourceSink, colourize(Value.str(), Colour)});
2036 else {
2037 StringRef V = EdgeLabels.find(SourceSink)->getValue();
2038 std::string NV = colourize(V.str() + " " + Value.str(), Colour);
2039 Colour = CommonColour;
2040 EdgeLabels[SourceSink] = NV;
2041 }
2042 SourceNode.addEdge(SinkNode, Value, Colour);
2043 }
2044 for (auto &I : Nodes)
2045 I.finalize(*this);
2046}
2047
2048DotCfgDiffDisplayGraph DotCfgDiff::createDisplayGraph(StringRef Title,
2049 StringRef EntryNodeName) {
2050 assert(NodePosition.count(EntryNodeName) == 1 &&
2051 "Expected to find entry block in map.");
2052 unsigned Entry = NodePosition[EntryNodeName];
2053 assert(Entry < Nodes.size() && "Expected to find entry node");
2054 DotCfgDiffDisplayGraph G(Title.str());
2055
2056 std::map<const unsigned, unsigned> NodeMap;
2057
2058 int EntryIndex = -1;
2059 unsigned Index = 0;
2060 for (auto &I : Nodes) {
2061 if (I.getIndex() == Entry)
2062 EntryIndex = Index;
2063 G.createNode(I.getBodyContent(), I.getColour());
2064 NodeMap.insert({I.getIndex(), Index++});
2065 }
2066 assert(EntryIndex >= 0 && "Expected entry node index to be set.");
2067 G.setEntryNode(EntryIndex);
2068
2069 for (auto &I : NodeMap) {
2070 unsigned SourceNode = I.first;
2071 unsigned DisplayNode = I.second;
2072 getNode(SourceNode).createDisplayEdges(G, DisplayNode, NodeMap);
2073 }
2074 return G;
2075}
2076
2077void DotCfgDiffNode::createDisplayEdges(
2078 DotCfgDiffDisplayGraph &DisplayGraph, unsigned DisplayNodeIndex,
2079 std::map<const unsigned, unsigned> &NodeMap) const {
2080
2081 DisplayNode &SourceDisplayNode = DisplayGraph.getNode(DisplayNodeIndex);
2082
2083 for (auto I : Edges) {
2084 unsigned SinkNodeIndex = I;
2085 StringRef Colour = getEdgeColour(SinkNodeIndex);
2086 const DotCfgDiffNode *SinkNode = &Graph.getNode(SinkNodeIndex);
2087
2088 StringRef Label = Graph.getEdgeSourceLabel(getIndex(), SinkNodeIndex);
2089 DisplayNode &SinkDisplayNode = DisplayGraph.getNode(SinkNode->getIndex());
2090 SourceDisplayNode.createEdge(Label, SinkDisplayNode, Colour);
2091 }
2092 SourceDisplayNode.createEdgeMap();
2093}
2094
2095void DotCfgDiffNode::finalize(DotCfgDiff &G) {
2096 for (auto E : EdgesMap) {
2097 Children.emplace_back(E.first);
2098 Edges.emplace_back(E.first);
2099 }
2100}
2101
2102} // namespace
2103
2104namespace llvm {
2105
2106template <> struct GraphTraits<DotCfgDiffDisplayGraph *> {
2107 using NodeRef = const DisplayNode *;
2108 using ChildIteratorType = DisplayNode::ChildIterator;
2109 using nodes_iterator = DotCfgDiffDisplayGraph::NodeIterator;
2110 using EdgeRef = const DisplayEdge *;
2111 using ChildEdgeIterator = DisplayNode::EdgeIterator;
2112
2113 static NodeRef getEntryNode(const DotCfgDiffDisplayGraph *G) {
2114 return G->getEntryNode();
2115 }
2117 return N->children_begin();
2118 }
2119 static ChildIteratorType child_end(NodeRef N) { return N->children_end(); }
2120 static nodes_iterator nodes_begin(const DotCfgDiffDisplayGraph *G) {
2121 return G->nodes_begin();
2122 }
2123 static nodes_iterator nodes_end(const DotCfgDiffDisplayGraph *G) {
2124 return G->nodes_end();
2125 }
2127 return N->edges_begin();
2128 }
2129 static ChildEdgeIterator child_edge_end(NodeRef N) { return N->edges_end(); }
2130 static NodeRef edge_dest(EdgeRef E) { return &E->getDestinationNode(); }
2131 static unsigned size(const DotCfgDiffDisplayGraph *G) { return G->size(); }
2132};
2133
2134template <>
2135struct DOTGraphTraits<DotCfgDiffDisplayGraph *> : public DefaultDOTGraphTraits {
2136 explicit DOTGraphTraits(bool Simple = false)
2138
2139 static bool renderNodesUsingHTML() { return true; }
2140 static std::string getGraphName(const DotCfgDiffDisplayGraph *DiffData) {
2141 return DiffData->getGraphName();
2142 }
2143 static std::string
2144 getGraphProperties(const DotCfgDiffDisplayGraph *DiffData) {
2145 return "\tsize=\"190, 190\";\n";
2146 }
2147 static std::string getNodeLabel(const DisplayNode *Node,
2148 const DotCfgDiffDisplayGraph *DiffData) {
2149 return DiffData->getNodeLabel(*Node);
2150 }
2151 static std::string getNodeAttributes(const DisplayNode *Node,
2152 const DotCfgDiffDisplayGraph *DiffData) {
2153 return DiffData->getNodeAttributes(*Node);
2154 }
2155 static std::string getEdgeSourceLabel(const DisplayNode *From,
2156 DisplayNode::ChildIterator &To) {
2157 return From->getEdgeSourceLabel(**To);
2158 }
2159 static std::string getEdgeAttributes(const DisplayNode *From,
2160 DisplayNode::ChildIterator &To,
2161 const DotCfgDiffDisplayGraph *DiffData) {
2162 return DiffData->getEdgeColorAttr(*From, **To);
2163 }
2164};
2165
2166} // namespace llvm
2167
2168namespace {
2169
2170void DotCfgDiffDisplayGraph::generateDotFile(StringRef DotFile) {
2171 std::error_code EC;
2172 raw_fd_ostream OutStream(DotFile, EC);
2173 if (EC) {
2174 errs() << "Error: " << EC.message() << "\n";
2175 return;
2176 }
2177 WriteGraph(OutStream, this, false);
2178 OutStream.flush();
2179 OutStream.close();
2180}
2181
2182} // namespace
2183
2184namespace llvm {
2185
2187 // Build up transition labels.
2188 const Instruction *Term = B.getTerminator();
2189 if (const BranchInst *Br = dyn_cast<const BranchInst>(Term))
2190 if (Br->isUnconditional())
2191 addSuccessorLabel(Br->getSuccessor(0)->getName().str(), "");
2192 else {
2193 addSuccessorLabel(Br->getSuccessor(0)->getName().str(), "true");
2194 addSuccessorLabel(Br->getSuccessor(1)->getName().str(), "false");
2195 }
2196 else if (const SwitchInst *Sw = dyn_cast<const SwitchInst>(Term)) {
2197 addSuccessorLabel(Sw->case_default()->getCaseSuccessor()->getName().str(),
2198 "default");
2199 for (auto &C : Sw->cases()) {
2200 assert(C.getCaseValue() && "Expected to find case value.");
2201 SmallString<20> Value = formatv("{0}", C.getCaseValue()->getSExtValue());
2202 addSuccessorLabel(C.getCaseSuccessor()->getName().str(), Value);
2203 }
2204 } else
2205 for (const BasicBlock *Succ : successors(&B))
2206 addSuccessorLabel(Succ->getName().str(), "");
2207}
2208
2210 for (const MachineBasicBlock *Succ : successors(&B))
2211 addSuccessorLabel(Succ->getName().str(), "");
2212}
2213
2216
2218 StringRef Name, StringRef Prefix, StringRef PassID, StringRef Divider,
2219 bool InModule, unsigned Minor, const FuncDataT<DCData> &Before,
2220 const FuncDataT<DCData> &After) {
2221 assert(HTML && "Expected outstream to be set");
2222 SmallString<8> Extender;
2224 // Handle numbering and file names.
2225 if (InModule) {
2226 Extender = formatv("{0}_{1}", N, Minor);
2227 Number = formatv("{0}.{1}", N, Minor);
2228 } else {
2229 Extender = formatv("{0}", N);
2230 Number = formatv("{0}", N);
2231 }
2232 // Create a temporary file name for the dot file.
2234 sys::fs::createUniquePath("cfgdot-%%%%%%.dot", SV, true);
2235 std::string DotFile = Twine(SV).str();
2236
2237 SmallString<20> PDFFileName = formatv("diff_{0}.pdf", Extender);
2238 SmallString<200> Text;
2239
2240 Text = formatv("{0}.{1}{2}{3}{4}", Number, Prefix, makeHTMLReady(PassID),
2241 Divider, Name);
2242
2243 DotCfgDiff Diff(Text, Before, After);
2244 std::string EntryBlockName = After.getEntryBlockName();
2245 // Use the before entry block if the after entry block was removed.
2246 if (EntryBlockName == "")
2247 EntryBlockName = Before.getEntryBlockName();
2248 assert(EntryBlockName != "" && "Expected to find entry block");
2249
2250 DotCfgDiffDisplayGraph DG = Diff.createDisplayGraph(Text, EntryBlockName);
2251 DG.generateDotFile(DotFile);
2252
2253 *HTML << genHTML(Text, DotFile, PDFFileName);
2254 std::error_code EC = sys::fs::remove(DotFile);
2255 if (EC)
2256 errs() << "Error: " << EC.message() << "\n";
2257}
2258
2260 StringRef PDFFileName) {
2261 SmallString<20> PDFFile = formatv("{0}/{1}", DotCfgDir, PDFFileName);
2262 // Create the PDF file.
2264 if (!DotExe)
2265 return "Unable to find dot executable.";
2266
2267 StringRef Args[] = {DotBinary, "-Tpdf", "-o", PDFFile, DotFile};
2268 int Result = sys::ExecuteAndWait(*DotExe, Args, std::nullopt);
2269 if (Result < 0)
2270 return "Error executing system dot.";
2271
2272 // Create the HTML tag refering to the PDF file.
2274 " <a href=\"{0}\" target=\"_blank\">{1}</a><br/>\n", PDFFileName, Text);
2275 return S.c_str();
2276}
2277
2279 assert(HTML && "Expected outstream to be set");
2280 *HTML << "<button type=\"button\" class=\"collapsible\">0. "
2281 << "Initial IR (by function)</button>\n"
2282 << "<div class=\"content\">\n"
2283 << " <p>\n";
2284 // Create representation of IR
2287 // Now compare it against itself, which will have everything the
2288 // same and will generate the files.
2290 .compare(getModuleForComparison(IR),
2291 [&](bool InModule, unsigned Minor,
2293 const FuncDataT<DCData> &After) -> void {
2294 handleFunctionCompare("", " ", "Initial IR", "", InModule,
2295 Minor, Before, After);
2296 });
2297 *HTML << " </p>\n"
2298 << "</div><br/>\n";
2299 ++N;
2300}
2301
2305}
2306
2308 assert(HTML && "Expected outstream to be set");
2309 SmallString<20> Banner =
2310 formatv(" <a>{0}. Pass {1} on {2} omitted because no change</a><br/>\n",
2311 N, makeHTMLReady(PassID), Name);
2312 *HTML << Banner;
2313 ++N;
2314}
2315
2317 const IRDataT<DCData> &Before,
2318 const IRDataT<DCData> &After, Any IR) {
2319 assert(HTML && "Expected outstream to be set");
2321 .compare(getModuleForComparison(IR),
2322 [&](bool InModule, unsigned Minor,
2324 const FuncDataT<DCData> &After) -> void {
2325 handleFunctionCompare(Name, " Pass ", PassID, " on ", InModule,
2326 Minor, Before, After);
2327 });
2328 *HTML << " </p></div>\n";
2329 ++N;
2330}
2331
2333 assert(HTML && "Expected outstream to be set");
2334 SmallString<20> Banner =
2335 formatv(" <a>{0}. {1} invalidated</a><br/>\n", N, makeHTMLReady(PassID));
2336 *HTML << Banner;
2337 ++N;
2338}
2339
2341 assert(HTML && "Expected outstream to be set");
2342 SmallString<20> Banner =
2343 formatv(" <a>{0}. Pass {1} on {2} filtered out</a><br/>\n", N,
2344 makeHTMLReady(PassID), Name);
2345 *HTML << Banner;
2346 ++N;
2347}
2348
2350 assert(HTML && "Expected outstream to be set");
2351 SmallString<20> Banner = formatv(" <a>{0}. {1} on {2} ignored</a><br/>\n", N,
2352 makeHTMLReady(PassID), Name);
2353 *HTML << Banner;
2354 ++N;
2355}
2356
2358 std::error_code EC;
2359 HTML = std::make_unique<raw_fd_ostream>(DotCfgDir + "/passes.html", EC);
2360 if (EC) {
2361 HTML = nullptr;
2362 return false;
2363 }
2364
2365 *HTML << "<!doctype html>"
2366 << "<html>"
2367 << "<head>"
2368 << "<style>.collapsible { "
2369 << "background-color: #777;"
2370 << " color: white;"
2371 << " cursor: pointer;"
2372 << " padding: 18px;"
2373 << " width: 100%;"
2374 << " border: none;"
2375 << " text-align: left;"
2376 << " outline: none;"
2377 << " font-size: 15px;"
2378 << "} .active, .collapsible:hover {"
2379 << " background-color: #555;"
2380 << "} .content {"
2381 << " padding: 0 18px;"
2382 << " display: none;"
2383 << " overflow: hidden;"
2384 << " background-color: #f1f1f1;"
2385 << "}"
2386 << "</style>"
2387 << "<title>passes.html</title>"
2388 << "</head>\n"
2389 << "<body>";
2390 return true;
2391}
2392
2394 if (!HTML)
2395 return;
2396 *HTML
2397 << "<script>var coll = document.getElementsByClassName(\"collapsible\");"
2398 << "var i;"
2399 << "for (i = 0; i < coll.length; i++) {"
2400 << "coll[i].addEventListener(\"click\", function() {"
2401 << " this.classList.toggle(\"active\");"
2402 << " var content = this.nextElementSibling;"
2403 << " if (content.style.display === \"block\"){"
2404 << " content.style.display = \"none\";"
2405 << " }"
2406 << " else {"
2407 << " content.style.display= \"block\";"
2408 << " }"
2409 << " });"
2410 << " }"
2411 << "</script>"
2412 << "</body>"
2413 << "</html>\n";
2414 HTML->flush();
2415 HTML->close();
2416}
2417
2422 SmallString<128> OutputDir;
2423 sys::fs::expand_tilde(DotCfgDir, OutputDir);
2424 sys::fs::make_absolute(OutputDir);
2425 assert(!OutputDir.empty() && "expected output dir to be non-empty");
2426 DotCfgDir = OutputDir.c_str();
2427 if (initializeHTML()) {
2429 return;
2430 }
2431 dbgs() << "Unable to open output stream for -cfg-dot-changed\n";
2432 }
2433}
2434
2436 LLVMContext &Context, bool DebugLogging, bool VerifyEach,
2437 PrintPassOptions PrintPassOpts)
2438 : PrintPass(DebugLogging, PrintPassOpts),
2439 OptNone(DebugLogging),
2441 PrintChangedIR(PrintChanged == ChangePrinter::Verbose),
2442 PrintChangedDiff(PrintChanged == ChangePrinter::DiffVerbose ||
2446 WebsiteChangeReporter(PrintChanged == ChangePrinter::DotCfgVerbose),
2447 Verify(DebugLogging), VerifyEach(VerifyEach) {}
2448
2449PrintCrashIRInstrumentation *PrintCrashIRInstrumentation::CrashReporter =
2450 nullptr;
2451
2453 if (!PrintOnCrashPath.empty()) {
2454 std::error_code EC;
2456 if (EC)
2458 Out << SavedIR;
2459 } else {
2460 dbgs() << SavedIR;
2461 }
2462}
2463
2464void PrintCrashIRInstrumentation::SignalHandler(void *) {
2465 // Called by signal handlers so do not lock here
2466 // Is the PrintCrashIRInstrumentation still alive?
2467 if (!CrashReporter)
2468 return;
2469
2470 assert((PrintOnCrash || !PrintOnCrashPath.empty()) &&
2471 "Did not expect to get here without option set.");
2472 CrashReporter->reportCrashIR();
2473}
2474
2476 if (!CrashReporter)
2477 return;
2478
2479 assert((PrintOnCrash || !PrintOnCrashPath.empty()) &&
2480 "Did not expect to get here without option set.");
2481 CrashReporter = nullptr;
2482}
2483
2486 if ((!PrintOnCrash && PrintOnCrashPath.empty()) || CrashReporter)
2487 return;
2488
2489 sys::AddSignalHandler(SignalHandler, nullptr);
2490 CrashReporter = this;
2491
2493 [&PIC, this](StringRef PassID, Any IR) {
2494 SavedIR.clear();
2496 OS << formatv("*** Dump of {0}IR Before Last Pass {1}",
2497 llvm::forcePrintModuleIR() ? "Module " : "", PassID);
2498 if (!isInteresting(IR, PassID, PIC.getPassNameForClassName(PassID))) {
2499 OS << " Filtered Out ***\n";
2500 return;
2501 }
2502 OS << " Started ***\n";
2503 unwrapAndPrint(OS, IR);
2504 });
2505}
2506
2509 PrintIR.registerCallbacks(PIC);
2510 PrintPass.registerCallbacks(PIC);
2511 TimePasses.registerCallbacks(PIC);
2512 OptNone.registerCallbacks(PIC);
2513 OptPassGate.registerCallbacks(PIC);
2514 PrintChangedIR.registerCallbacks(PIC);
2515 PseudoProbeVerification.registerCallbacks(PIC);
2516 if (VerifyEach)
2517 Verify.registerCallbacks(PIC);
2518 PrintChangedDiff.registerCallbacks(PIC);
2519 WebsiteChangeReporter.registerCallbacks(PIC);
2520 ChangeTester.registerCallbacks(PIC);
2521 PrintCrashIR.registerCallbacks(PIC);
2522 if (MAM)
2523 PreservedCFGChecker.registerCallbacks(PIC, *MAM);
2524
2525 // TimeProfiling records the pass running time cost.
2526 // Its 'BeforePassCallback' can be appended at the tail of all the
2527 // BeforeCallbacks by calling `registerCallbacks` in the end.
2528 // Its 'AfterPassCallback' is put at the front of all the
2529 // AfterCallbacks by its `registerCallbacks`. This is necessary
2530 // to ensure that other callbacks are not included in the timings.
2531 TimeProfilingPasses.registerCallbacks(PIC);
2532}
2533
2534template class ChangeReporter<std::string>;
2535template class TextChangeReporter<std::string>;
2536
2537template class BlockDataT<EmptyData>;
2538template class FuncDataT<EmptyData>;
2539template class IRDataT<EmptyData>;
2540template class ChangeReporter<IRDataT<EmptyData>>;
2542template class IRComparer<EmptyData>;
2543
2544} // 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:308
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:7060
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:7071
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.