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