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 bool ShouldRun = Context.getOptPassGate().shouldRunPass(
1012 PassName, getIRName(IR, IRContext));
1013 if (!ShouldRun && !this->HasWrittenIR &&
1014 !Opts.opt_bisect_print_ir_path.empty()) {
1015 // FIXME: print IR if limit is higher than number of opt-bisect
1016 // invocations
1017 this->HasWrittenIR = true;
1018 const Module *M = unwrapModule(IR, /*Force=*/true);
1019 assert((M && &M->getContext() == &Context) && "Missing/Mismatching Module");
1020 std::error_code EC;
1021 raw_fd_ostream OS(Opts.opt_bisect_print_ir_path, EC);
1022 if (EC)
1024 M->print(OS, nullptr);
1025 }
1026 return ShouldRun;
1027}
1028
1031 this->IRContext = IRContext;
1032 const OptPassGate &PassGate = Context.getOptPassGate();
1033 if (!PassGate.isEnabled())
1034 return;
1035
1036 PIC.registerShouldRunOptionalPassCallback(
1037 [this, &PIC](StringRef ClassName, IRUnitRef IR) {
1038 StringRef PassName = PIC.getPassNameForClassName(ClassName);
1039 if (PassName.empty())
1040 return this->shouldRun(ClassName, IR);
1041 return this->shouldRun(PassName, IR);
1042 });
1043}
1044
1045raw_ostream &PrintPassInstrumentation::print() {
1046 if (Opts.Indent) {
1047 assert(Indent >= 0);
1048 dbgs().indent(Indent);
1049 }
1050 return dbgs();
1051}
1052
1055 this->IRContext = IRContext;
1056 if (!Enabled)
1057 return;
1058
1059 std::vector<StringRef> SpecialPasses;
1060 if (!Opts.Verbose) {
1061 SpecialPasses.emplace_back("PassManager");
1062 SpecialPasses.emplace_back("PassAdaptor");
1063 }
1064
1065 PIC.registerBeforeSkippedPassCallback([this, SpecialPasses](StringRef PassID,
1066 IRUnitRef IR) {
1067 assert(!isSpecialPass(PassID, SpecialPasses) &&
1068 "Unexpectedly skipping special pass");
1069
1070 print() << "Skipping pass: " << PassID << " on "
1071 << getIRName(IR, this->IRContext) << "\n";
1072 });
1073 PIC.registerBeforeNonSkippedPassCallback(
1074 [this, SpecialPasses](StringRef PassID, IRUnitRef IR) {
1075 if (isSpecialPass(PassID, SpecialPasses))
1076 return;
1077
1078 auto &OS = print();
1079 OS << "Running pass: " << PassID << " on "
1080 << getIRName(IR, this->IRContext);
1081 if (const auto *F = dyn_cast<Function>(IR)) {
1082 unsigned Count = F->getInstructionCount();
1083 OS << " (" << Count << " instruction";
1084 if (Count != 1)
1085 OS << 's';
1086 OS << ')';
1087 } else if (const auto *C = dyn_cast<LazyCallGraph::SCC>(IR)) {
1088 int Count = C->size();
1089 OS << " (" << Count << " node";
1090 if (Count != 1)
1091 OS << 's';
1092 OS << ')';
1093 }
1094 OS << "\n";
1095 Indent += 2;
1096 });
1097 PIC.registerAfterPassCallback(
1098 [this, SpecialPasses](StringRef PassID, IRUnitRef IR,
1099 const PreservedAnalyses &) {
1100 if (isSpecialPass(PassID, SpecialPasses))
1101 return;
1102
1103 Indent -= 2;
1104 });
1105 PIC.registerAfterPassInvalidatedCallback(
1106 [this, SpecialPasses](StringRef PassID, const PreservedAnalyses &) {
1107 if (isSpecialPass(PassID, SpecialPasses))
1108 return;
1109
1110 Indent -= 2;
1111 });
1112
1113 if (!Opts.SkipAnalyses) {
1114 PIC.registerBeforeAnalysisCallback([this](StringRef PassID, IRUnitRef IR) {
1115 print() << "Running analysis: " << PassID << " on "
1116 << getIRName(IR, this->IRContext) << "\n";
1117 Indent += 2;
1118 });
1119 PIC.registerAfterAnalysisCallback(
1120 [this](StringRef PassID, IRUnitRef IR) { Indent -= 2; });
1121 PIC.registerAnalysisInvalidatedCallback(
1122 [this](StringRef PassID, IRUnitRef IR) {
1123 print() << "Invalidating analysis: " << PassID << " on "
1124 << getIRName(IR, this->IRContext) << "\n";
1125 });
1126 PIC.registerAnalysesClearedCallback([this](StringRef IRName) {
1127 print() << "Clearing all analysis results for: " << IRName << "\n";
1128 });
1129 }
1130}
1131
1133 bool TrackBBLifetime) {
1134 if (TrackBBLifetime)
1136 for (const auto &BB : *F) {
1137 if (BBGuards)
1138 BBGuards->try_emplace(intptr_t(&BB), &BB);
1139 for (const auto *Succ : successors(&BB)) {
1140 Graph[&BB][Succ]++;
1141 if (BBGuards)
1142 BBGuards->try_emplace(intptr_t(Succ), Succ);
1143 }
1144 }
1145}
1146
1147static void printBBName(raw_ostream &out, const BasicBlock *BB) {
1148 if (BB->hasName()) {
1149 out << BB->getName() << "<" << BB << ">";
1150 return;
1151 }
1152
1153 if (!BB->getParent()) {
1154 out << "unnamed_removed<" << BB << ">";
1155 return;
1156 }
1157
1158 if (BB->isEntryBlock()) {
1159 out << "entry"
1160 << "<" << BB << ">";
1161 return;
1162 }
1163
1164 unsigned FuncOrderBlockNum = 0;
1165 for (auto &FuncBB : *BB->getParent()) {
1166 if (&FuncBB == BB)
1167 break;
1168 FuncOrderBlockNum++;
1169 }
1170 out << "unnamed_" << FuncOrderBlockNum << "<" << BB << ">";
1171}
1172
1174 const CFG &Before,
1175 const CFG &After) {
1176 assert(!After.isPoisoned());
1177 if (Before.isPoisoned()) {
1178 out << "Some blocks were deleted\n";
1179 return;
1180 }
1181
1182 // Find and print graph differences.
1183 if (Before.Graph.size() != After.Graph.size())
1184 out << "Different number of non-leaf basic blocks: before="
1185 << Before.Graph.size() << ", after=" << After.Graph.size() << "\n";
1186
1187 for (auto &BB : Before.Graph) {
1188 auto BA = After.Graph.find(BB.first);
1189 if (BA == After.Graph.end()) {
1190 out << "Non-leaf block ";
1191 printBBName(out, BB.first);
1192 out << " is removed (" << BB.second.size() << " successors)\n";
1193 }
1194 }
1195
1196 for (auto &BA : After.Graph) {
1197 auto BB = Before.Graph.find(BA.first);
1198 if (BB == Before.Graph.end()) {
1199 out << "Non-leaf block ";
1200 printBBName(out, BA.first);
1201 out << " is added (" << BA.second.size() << " successors)\n";
1202 continue;
1203 }
1204
1205 if (BB->second == BA.second)
1206 continue;
1207
1208 out << "Different successors of block ";
1209 printBBName(out, BA.first);
1210 out << " (unordered):\n";
1211 out << "- before (" << BB->second.size() << "): ";
1212 for (auto &SuccB : BB->second) {
1213 printBBName(out, SuccB.first);
1214 if (SuccB.second != 1)
1215 out << "(" << SuccB.second << "), ";
1216 else
1217 out << ", ";
1218 }
1219 out << "\n";
1220 out << "- after (" << BA.second.size() << "): ";
1221 for (auto &SuccA : BA.second) {
1222 printBBName(out, SuccA.first);
1223 if (SuccA.second != 1)
1224 out << "(" << SuccA.second << "), ";
1225 else
1226 out << ", ";
1227 }
1228 out << "\n";
1229 }
1230}
1231
1232// PreservedCFGCheckerInstrumentation uses PreservedCFGCheckerAnalysis to check
1233// passes, that reported they kept CFG analyses up-to-date, did not actually
1234// change CFG. This check is done as follows. Before every functional pass in
1235// BeforeNonSkippedPassCallback a CFG snapshot (an instance of
1236// PreservedCFGCheckerInstrumentation::CFG) is requested from
1237// FunctionAnalysisManager as a result of PreservedCFGCheckerAnalysis. When the
1238// functional pass finishes and reports that CFGAnalyses or AllAnalyses are
1239// up-to-date then the cached result of PreservedCFGCheckerAnalysis (if
1240// available) is checked to be equal to a freshly created CFG snapshot.
1242 : public AnalysisInfoMixin<PreservedCFGCheckerAnalysis> {
1244
1246
1247public:
1248 /// Provide the result type for this analysis pass.
1250
1251 /// Run the analysis pass over a function and produce CFG.
1253 return Result(&F, /* TrackBBLifetime */ true);
1254 }
1255};
1256
1258
1260 : public AnalysisInfoMixin<PreservedFunctionHashAnalysis> {
1262
1264 uint64_t Hash;
1265 };
1266
1268
1272};
1273
1275
1277 : public AnalysisInfoMixin<PreservedModuleHashAnalysis> {
1279
1280 struct ModuleHash {
1281 uint64_t Hash;
1282 };
1283
1285
1289};
1290
1292
1294 Function &F, const PreservedAnalyses &PA,
1295 FunctionAnalysisManager::Invalidator &) {
1296 auto PAC = PA.getChecker<PreservedCFGCheckerAnalysis>();
1297 return !(PAC.preserved() || PAC.preservedSet<AllAnalysesOn<Function>>() ||
1298 PAC.preservedSet<CFGAnalyses>());
1299}
1300
1303
1304 if (const auto *MaybeF = dyn_cast<Function>(IR)) {
1305 Functions.push_back(const_cast<Function *>(MaybeF));
1306 } else if (const auto *MaybeM = dyn_cast<Module>(IR)) {
1307 for (Function &F : *const_cast<Module *>(MaybeM))
1308 Functions.push_back(&F);
1309 }
1310 return Functions;
1311}
1312
1315#ifdef EXPENSIVE_CHECKS
1316 constexpr bool VerifyByDefault = true;
1317#else
1318 constexpr bool VerifyByDefault = false;
1319#endif
1320 if (!valueOr(Opts.verify_analysis_invalidation, VerifyByDefault))
1321 return;
1322
1323 bool Registered = false;
1324 PIC.registerBeforeNonSkippedPassCallback([this, &MAM,
1325 Registered](StringRef P,
1326 IRUnitRef IR) mutable {
1327#if LLVM_ENABLE_ABI_BREAKING_CHECKS
1328 assert(&PassStack.emplace_back(P));
1329#endif
1330 (void)this;
1331
1332 auto &FAM = MAM.getResult<FunctionAnalysisManagerModuleProxy>(
1333 *const_cast<Module *>(unwrapModule(IR, /*Force=*/true)))
1334 .getManager();
1335 if (!Registered) {
1336 FAM.registerPass([&] { return PreservedCFGCheckerAnalysis(); });
1337 FAM.registerPass([&] { return PreservedFunctionHashAnalysis(); });
1338 MAM.registerPass([&] { return PreservedModuleHashAnalysis(); });
1339 Registered = true;
1340 }
1341
1342 for (Function *F : GetFunctions(IR)) {
1343 // Make sure a fresh CFG snapshot is available before the pass.
1344 FAM.getResult<PreservedCFGCheckerAnalysis>(*F);
1345 FAM.getResult<PreservedFunctionHashAnalysis>(*F);
1346 }
1347
1348 if (const auto *MPtr = dyn_cast<Module>(IR)) {
1349 auto &M = *const_cast<Module *>(MPtr);
1350 MAM.getResult<PreservedModuleHashAnalysis>(M);
1351 }
1352 });
1353
1354 PIC.registerAfterPassInvalidatedCallback(
1355 [this](StringRef P, const PreservedAnalyses &PassPA) {
1356#if LLVM_ENABLE_ABI_BREAKING_CHECKS
1357 assert(PassStack.pop_back_val() == P &&
1358 "Before and After callbacks must correspond");
1359#endif
1360 (void)this;
1361 });
1362
1363 PIC.registerAfterPassCallback([this, &MAM](StringRef P, IRUnitRef IR,
1364 const PreservedAnalyses &PassPA) {
1365#if LLVM_ENABLE_ABI_BREAKING_CHECKS
1366 assert(PassStack.pop_back_val() == P &&
1367 "Before and After callbacks must correspond");
1368#endif
1369 (void)this;
1370
1371 // We have to get the FAM via the MAM, rather than directly use a passed in
1372 // FAM because if MAM has not cached the FAM, it won't invalidate function
1373 // analyses in FAM.
1374 auto &FAM = MAM.getResult<FunctionAnalysisManagerModuleProxy>(
1375 *const_cast<Module *>(unwrapModule(IR, /*Force=*/true)))
1376 .getManager();
1377
1378 for (Function *F : GetFunctions(IR)) {
1379 if (auto *HashBefore =
1380 FAM.getCachedResult<PreservedFunctionHashAnalysis>(*F)) {
1381 if (HashBefore->Hash != StructuralHash(*F)) {
1383 "Function @{0} changed by {1} without invalidating analyses",
1384 F->getName(), P));
1385 }
1386 }
1387
1388 auto CheckCFG = [](StringRef Pass, StringRef FuncName,
1389 const CFG &GraphBefore, const CFG &GraphAfter) {
1390 if (GraphAfter == GraphBefore)
1391 return;
1392
1393 dbgs()
1394 << "Error: " << Pass
1395 << " does not invalidate CFG analyses but CFG changes detected in "
1396 "function @"
1397 << FuncName << ":\n";
1398 CFG::printDiff(dbgs(), GraphBefore, GraphAfter);
1399 report_fatal_error(Twine("CFG unexpectedly changed by ", Pass));
1400 };
1401
1402 if (auto *GraphBefore =
1403 FAM.getCachedResult<PreservedCFGCheckerAnalysis>(*F))
1404 CheckCFG(P, F->getName(), *GraphBefore,
1405 CFG(F, /* TrackBBLifetime */ false));
1406 }
1407 if (const auto *MPtr = dyn_cast<Module>(IR)) {
1408 auto &M = *const_cast<Module *>(MPtr);
1409 if (auto *HashBefore =
1410 MAM.getCachedResult<PreservedModuleHashAnalysis>(M)) {
1411 if (HashBefore->Hash != StructuralHash(M)) {
1413 "Module changed by {0} without invalidating analyses", P));
1414 }
1415 }
1416 }
1417 });
1418}
1419
1422 PIC.registerAfterPassCallback(
1423 [this, MAM](StringRef P, IRUnitRef IR, const PreservedAnalyses &PassPA) {
1424 if (isIgnored(P) || P == "VerifierPass")
1425 return;
1426 const auto *F = dyn_cast<Function>(IR);
1427 if (!F) {
1428 if (const auto *L = dyn_cast<Loop>(IR))
1429 F = L->getHeader()->getParent();
1430 }
1431
1432 if (F) {
1433 if (DebugLogging)
1434 dbgs() << "Verifying function " << F->getName() << "\n";
1435
1436 if (verifyFunction(*F, &errs()))
1437 report_fatal_error(formatv("Broken function found after pass "
1438 "\"{0}\", compilation aborted!",
1439 P));
1440 } else {
1441 const auto *M = dyn_cast<Module>(IR);
1442 if (!M) {
1443 if (const auto *C = dyn_cast<LazyCallGraph::SCC>(IR))
1444 M = C->begin()->getFunction().getParent();
1445 }
1446
1447 if (M) {
1448 if (DebugLogging)
1449 dbgs() << "Verifying module " << M->getName() << "\n";
1450
1451 if (verifyModule(*M, &errs()))
1452 report_fatal_error(formatv("Broken module found after pass "
1453 "\"{0}\", compilation aborted!",
1454 P));
1455 }
1456
1457 if (auto *MF = dyn_cast<MachineFunction>(IR)) {
1458 if (DebugLogging)
1459 dbgs() << "Verifying machine function " << MF->getName() << '\n';
1460 std::string Banner =
1461 formatv("Broken machine function found after pass "
1462 "\"{0}\", compilation aborted!",
1463 P);
1464 if (MAM) {
1465 Module &M = const_cast<Module &>(*MF->getFunction().getParent());
1466 auto &MFAM =
1468 .getManager();
1470 Verifier.run(const_cast<MachineFunction &>(*MF), MFAM);
1471 } else {
1472 verifyMachineFunction(Banner, *MF);
1473 }
1474 }
1475 }
1476 });
1477}
1478
1480
1486
1488 const IRDataT<EmptyData> &Before,
1489 const IRDataT<EmptyData> &After,
1490 IRUnitRef IR) {
1491 SmallString<20> Banner =
1492 formatv("*** IR Dump After {0} on {1} ***\n", PassID, Name);
1493 Out << Banner;
1494 IRComparer<EmptyData>(Before, After)
1495 .compare(getModuleForComparison(IR),
1496 [&](bool InModule, unsigned Minor,
1497 const FuncDataT<EmptyData> &Before,
1498 const FuncDataT<EmptyData> &After) -> void {
1499 handleFunctionCompare(Name, "", PassID, " on ", InModule,
1500 Minor, Before, After);
1501 });
1502 Out << "\n";
1503}
1504
1506 StringRef Name, StringRef Prefix, StringRef PassID, StringRef Divider,
1507 bool InModule, unsigned Minor, const FuncDataT<EmptyData> &Before,
1508 const FuncDataT<EmptyData> &After) {
1509 // Print a banner when this is being shown in the context of a module
1510 if (InModule)
1511 Out << "\n*** IR for function " << Name << " ***\n";
1512
1514 Before, After,
1515 [&](const BlockDataT<EmptyData> *B, const BlockDataT<EmptyData> *A) {
1516 StringRef BStr = B ? B->getBody() : "\n";
1517 StringRef AStr = A ? A->getBody() : "\n";
1518 const std::string Removed =
1519 UseColour ? "\033[31m-%l\033[0m\n" : "-%l\n";
1520 const std::string Added = UseColour ? "\033[32m+%l\033[0m\n" : "+%l\n";
1521 const std::string NoChange = " %l\n";
1522 Out << doSystemDiff(BStr, AStr, Removed, Added, NoChange);
1523 });
1524}
1525
1533
1535
1538 this->IRContext = IRContext;
1540 return;
1541 PIC.registerBeforeNonSkippedPassCallback(
1542 [this](StringRef P, IRUnitRef IR) { this->runBeforePass(P, IR); });
1543 PIC.registerAfterPassCallback(
1544 [this](StringRef P, IRUnitRef IR, const PreservedAnalyses &) {
1545 this->runAfterPass();
1546 },
1547 true);
1548 PIC.registerAfterPassInvalidatedCallback(
1549 [this](StringRef P, const PreservedAnalyses &) { this->runAfterPass(); },
1550 true);
1551 PIC.registerBeforeAnalysisCallback(
1552 [this](StringRef P, IRUnitRef IR) { this->runBeforePass(P, IR); });
1553 PIC.registerAfterAnalysisCallback(
1554 [this](StringRef P, IRUnitRef IR) { this->runAfterPass(); }, true);
1555}
1556
1557void TimeProfilingPassesHandler::runBeforePass(StringRef PassID, IRUnitRef IR) {
1558 timeTraceProfilerBegin(PassID, getIRName(IR, IRContext));
1559}
1560
1561void TimeProfilingPassesHandler::runAfterPass() { timeTraceProfilerEnd(); }
1562
1563namespace {
1564
1565class DisplayNode;
1566class DotCfgDiffDisplayGraph;
1567
1568// Base class for a node or edge in the dot-cfg-changes graph.
1569class DisplayElement {
1570public:
1571 // Is this in before, after, or both?
1572 StringRef getColour() const { return Colour; }
1573
1574protected:
1575 DisplayElement(StringRef Colour) : Colour(Colour) {}
1576 const StringRef Colour;
1577};
1578
1579// An edge representing a transition between basic blocks in the
1580// dot-cfg-changes graph.
1581class DisplayEdge : public DisplayElement {
1582public:
1583 DisplayEdge(std::string Value, DisplayNode &Node, StringRef Colour)
1584 : DisplayElement(Colour), Value(Value), Node(Node) {}
1585 // The value on which the transition is made.
1586 std::string getValue() const { return Value; }
1587 // The node (representing a basic block) reached by this transition.
1588 const DisplayNode &getDestinationNode() const { return Node; }
1589
1590protected:
1591 std::string Value;
1592 const DisplayNode &Node;
1593};
1594
1595// A node in the dot-cfg-changes graph which represents a basic block.
1596class DisplayNode : public DisplayElement {
1597public:
1598 // \p C is the content for the node, \p T indicates the colour for the
1599 // outline of the node
1600 DisplayNode(std::string Content, StringRef Colour)
1601 : DisplayElement(Colour), Content(Content) {}
1602
1603 // Iterator to the child nodes. Required by GraphWriter.
1604 using ChildIterator = SmallPtrSet<DisplayNode *, 0>::const_iterator;
1605 ChildIterator children_begin() const { return Children.begin(); }
1606 ChildIterator children_end() const { return Children.end(); }
1607
1608 // Iterator for the edges. Required by GraphWriter.
1609 using EdgeIterator = std::vector<DisplayEdge *>::const_iterator;
1610 EdgeIterator edges_begin() const { return EdgePtrs.cbegin(); }
1611 EdgeIterator edges_end() const { return EdgePtrs.cend(); }
1612
1613 // Create an edge to \p Node on value \p Value, with colour \p Colour.
1614 void createEdge(StringRef Value, DisplayNode &Node, StringRef Colour);
1615
1616 // Return the content of this node.
1617 std::string getContent() const { return Content; }
1618
1619 // Return the edge to node \p S.
1620 const DisplayEdge &getEdge(const DisplayNode &To) const {
1621 assert(EdgeMap.find(&To) != EdgeMap.end() && "Expected to find edge.");
1622 return *EdgeMap.find(&To)->second;
1623 }
1624
1625 // Return the value for the transition to basic block \p S.
1626 // Required by GraphWriter.
1627 std::string getEdgeSourceLabel(const DisplayNode &Sink) const {
1628 return getEdge(Sink).getValue();
1629 }
1630
1631 void createEdgeMap();
1632
1633protected:
1634 const std::string Content;
1635
1636 // Place to collect all of the edges. Once they are all in the vector,
1637 // the vector will not reallocate so then we can use pointers to them,
1638 // which are required by the graph writing routines.
1639 std::vector<DisplayEdge> Edges;
1640
1641 std::vector<DisplayEdge *> EdgePtrs;
1642 SmallPtrSet<DisplayNode *, 0> Children;
1643 DenseMap<const DisplayNode *, const DisplayEdge *> EdgeMap;
1644
1645 // Safeguard adding of edges.
1646 bool AllEdgesCreated = false;
1647};
1648
1649// Class representing a difference display (corresponds to a pdf file).
1650class DotCfgDiffDisplayGraph {
1651public:
1652 DotCfgDiffDisplayGraph(std::string Name) : GraphName(Name) {}
1653
1654 // Generate the file into \p DotFile.
1655 void generateDotFile(StringRef DotFile);
1656
1657 // Iterator to the nodes. Required by GraphWriter.
1658 using NodeIterator = std::vector<DisplayNode *>::const_iterator;
1659 NodeIterator nodes_begin() const {
1660 assert(NodeGenerationComplete && "Unexpected children iterator creation");
1661 return NodePtrs.cbegin();
1662 }
1663 NodeIterator nodes_end() const {
1664 assert(NodeGenerationComplete && "Unexpected children iterator creation");
1665 return NodePtrs.cend();
1666 }
1667
1668 // Record the index of the entry node. At this point, we can build up
1669 // vectors of pointers that are required by the graph routines.
1670 void setEntryNode(unsigned N) {
1671 // At this point, there will be no new nodes.
1672 assert(!NodeGenerationComplete && "Unexpected node creation");
1673 NodeGenerationComplete = true;
1674 for (auto &N : Nodes)
1675 NodePtrs.emplace_back(&N);
1676
1677 EntryNode = NodePtrs[N];
1678 }
1679
1680 // Create a node.
1681 void createNode(std::string C, StringRef Colour) {
1682 assert(!NodeGenerationComplete && "Unexpected node creation");
1683 Nodes.emplace_back(C, Colour);
1684 }
1685 // Return the node at index \p N to avoid problems with vectors reallocating.
1686 DisplayNode &getNode(unsigned N) {
1687 assert(N < Nodes.size() && "Node is out of bounds");
1688 return Nodes[N];
1689 }
1690 unsigned size() const {
1691 assert(NodeGenerationComplete && "Unexpected children iterator creation");
1692 return Nodes.size();
1693 }
1694
1695 // Return the name of the graph. Required by GraphWriter.
1696 std::string getGraphName() const { return GraphName; }
1697
1698 // Return the string representing the differences for basic block \p Node.
1699 // Required by GraphWriter.
1700 std::string getNodeLabel(const DisplayNode &Node) const {
1701 return Node.getContent();
1702 }
1703
1704 // Return a string with colour information for Dot. Required by GraphWriter.
1705 std::string getNodeAttributes(const DisplayNode &Node) const {
1706 return attribute(Node.getColour());
1707 }
1708
1709 // Return a string with colour information for Dot. Required by GraphWriter.
1710 std::string getEdgeColorAttr(const DisplayNode &From,
1711 const DisplayNode &To) const {
1712 return attribute(From.getEdge(To).getColour());
1713 }
1714
1715 // Get the starting basic block. Required by GraphWriter.
1716 DisplayNode *getEntryNode() const {
1717 assert(NodeGenerationComplete && "Unexpected children iterator creation");
1718 return EntryNode;
1719 }
1720
1721protected:
1722 // Return the string containing the colour to use as a Dot attribute.
1723 std::string attribute(StringRef Colour) const {
1724 return "color=" + Colour.str();
1725 }
1726
1727 bool NodeGenerationComplete = false;
1728 const std::string GraphName;
1729 std::vector<DisplayNode> Nodes;
1730 std::vector<DisplayNode *> NodePtrs;
1731 DisplayNode *EntryNode = nullptr;
1732};
1733
1734void DisplayNode::createEdge(StringRef Value, DisplayNode &Node,
1735 StringRef Colour) {
1736 assert(!AllEdgesCreated && "Expected to be able to still create edges.");
1737 Edges.emplace_back(Value.str(), Node, Colour);
1738 Children.insert(&Node);
1739}
1740
1741void DisplayNode::createEdgeMap() {
1742 // No more edges will be added so we can now use pointers to the edges
1743 // as the vector will not grow and reallocate.
1744 AllEdgesCreated = true;
1745 for (auto &E : Edges)
1746 EdgeMap.insert({&E.getDestinationNode(), &E});
1747}
1748
1749class DotCfgDiffNode;
1750class DotCfgDiff;
1751
1752// A class representing a basic block in the Dot difference graph.
1753class DotCfgDiffNode {
1754public:
1755 DotCfgDiffNode() = delete;
1756
1757 // Create a node in Dot difference graph \p G representing the basic block
1758 // represented by \p BD with colour \p Colour (where it exists).
1759 DotCfgDiffNode(const PassesOptions &Opts, DotCfgDiff &G, unsigned N,
1760 const BlockDataT<DCData> &BD, StringRef Colour)
1761 : Opts(Opts), Graph(G), N(N), Data{&BD, nullptr}, Colour(Colour) {}
1762 DotCfgDiffNode(const DotCfgDiffNode &DN)
1763 : Opts(DN.Opts), Graph(DN.Graph), N(DN.N), Data{DN.Data[0], DN.Data[1]},
1764 Colour(DN.Colour), EdgesMap(DN.EdgesMap), Children(DN.Children),
1765 Edges(DN.Edges) {}
1766
1767 unsigned getIndex() const { return N; }
1768
1769 // The label of the basic block
1770 StringRef getLabel() const {
1771 assert(Data[0] && "Expected Data[0] to be set.");
1772 return Data[0]->getLabel();
1773 }
1774 // Return the colour for this block
1775 StringRef getColour() const { return Colour; }
1776 // Change this basic block from being only in before to being common.
1777 // Save the pointer to \p Other.
1778 void setCommon(const BlockDataT<DCData> &Other) {
1779 assert(!Data[1] && "Expected only one block datum");
1780 Data[1] = &Other;
1781 Colour = Opts.dot_cfg_common_color;
1782 }
1783 // Add an edge to \p E of colour {\p Value, \p Colour}.
1784 void addEdge(unsigned E, StringRef Value, StringRef Colour) {
1785 // This is a new edge or it is an edge being made common.
1786 assert((EdgesMap.count(E) == 0 || Colour == Opts.dot_cfg_common_color) &&
1787 "Unexpected edge count and color.");
1788 EdgesMap[E] = {Value.str(), Colour};
1789 }
1790 // Record the children and create edges.
1791 void finalize(DotCfgDiff &G);
1792
1793 // Return the colour of the edge to node \p S.
1794 StringRef getEdgeColour(const unsigned S) const {
1795 assert(EdgesMap.count(S) == 1 && "Expected to find edge.");
1796 return EdgesMap.at(S).second;
1797 }
1798
1799 // Return the string representing the basic block.
1800 std::string getBodyContent() const;
1801
1802 void createDisplayEdges(DotCfgDiffDisplayGraph &Graph, unsigned DisplayNode,
1803 std::map<const unsigned, unsigned> &NodeMap) const;
1804
1805protected:
1806 const PassesOptions &Opts;
1807 DotCfgDiff &Graph;
1808 const unsigned N;
1809 const BlockDataT<DCData> *Data[2];
1810 StringRef Colour;
1811 std::map<const unsigned, std::pair<std::string, StringRef>> EdgesMap;
1812 std::vector<unsigned> Children;
1813 std::vector<unsigned> Edges;
1814};
1815
1816// Class representing the difference graph between two functions.
1817class DotCfgDiff {
1818public:
1819 // \p Title is the title given to the graph. \p EntryNodeName is the
1820 // entry node for the function. \p Before and \p After are the before
1821 // after versions of the function, respectively. \p Dir is the directory
1822 // in which to store the results.
1823 DotCfgDiff(const PassesOptions &Opts, StringRef Title,
1824 const FuncDataT<DCData> &Before, const FuncDataT<DCData> &After);
1825
1826 DotCfgDiff(const DotCfgDiff &) = delete;
1827 DotCfgDiff &operator=(const DotCfgDiff &) = delete;
1828
1829 DotCfgDiffDisplayGraph createDisplayGraph(StringRef Title,
1830 StringRef EntryNodeName);
1831
1832 // Return a string consisting of the labels for the \p Source and \p Sink.
1833 // The combination allows distinguishing changing transitions on the
1834 // same value (ie, a transition went to X before and goes to Y after).
1835 // Required by GraphWriter.
1836 StringRef getEdgeSourceLabel(const unsigned &Source,
1837 const unsigned &Sink) const {
1838 std::string S =
1839 getNode(Source).getLabel().str() + " " + getNode(Sink).getLabel().str();
1840 assert(EdgeLabels.count(S) == 1 && "Expected to find edge label.");
1841 return EdgeLabels.find(S)->getValue();
1842 }
1843
1844 // Return the number of basic blocks (nodes). Required by GraphWriter.
1845 unsigned size() const { return Nodes.size(); }
1846
1847 const DotCfgDiffNode &getNode(unsigned N) const {
1848 assert(N < Nodes.size() && "Unexpected index for node reference");
1849 return Nodes[N];
1850 }
1851
1852protected:
1853 // Return the string surrounded by HTML to make it the appropriate colour.
1854 std::string colourize(std::string S, StringRef Colour) const;
1855
1856 void createNode(StringRef Label, const BlockDataT<DCData> &BD, StringRef C) {
1857 unsigned Pos = Nodes.size();
1858 Nodes.emplace_back(Opts, *this, Pos, BD, C);
1859 NodePosition.insert({Label, Pos});
1860 }
1861
1862 const PassesOptions &Opts;
1863 // TODO Nodes should probably be a StringMap<DotCfgDiffNode> after the
1864 // display graph is separated out, which would remove the need for
1865 // NodePosition.
1866 std::vector<DotCfgDiffNode> Nodes;
1867 StringMap<unsigned> NodePosition;
1868 const std::string GraphName;
1869
1870 StringMap<std::string> EdgeLabels;
1871};
1872
1873std::string DotCfgDiffNode::getBodyContent() const {
1874 if (Colour == Opts.dot_cfg_common_color) {
1875 assert(Data[1] && "Expected Data[1] to be set.");
1876
1877 StringRef SR[2];
1878 for (unsigned I = 0; I < 2; ++I) {
1879 SR[I] = Data[I]->getBody();
1880 // drop initial '\n' if present
1881 SR[I].consume_front("\n");
1882 // drop predecessors as they can be big and are redundant
1883 SR[I] = SR[I].drop_until([](char C) { return C == '\n'; }).drop_front();
1884 }
1885
1886 SmallString<80> OldLineFormat =
1887 formatv("<FONT COLOR=\"{0}\">%l</FONT><BR align=\"left\"/>",
1888 Opts.dot_cfg_before_color);
1889 SmallString<80> NewLineFormat =
1890 formatv("<FONT COLOR=\"{0}\">%l</FONT><BR align=\"left\"/>",
1891 Opts.dot_cfg_after_color);
1892 SmallString<80> UnchangedLineFormat =
1893 formatv("<FONT COLOR=\"{0}\">%l</FONT><BR align=\"left\"/>",
1894 Opts.dot_cfg_common_color);
1895 std::string Diff = Data[0]->getLabel().str();
1896 Diff += ":\n<BR align=\"left\"/>" +
1897 doSystemDiff(makeHTMLReady(SR[0]), makeHTMLReady(SR[1]),
1898 OldLineFormat, NewLineFormat, UnchangedLineFormat);
1899
1900 // Diff adds in some empty colour changes which are not valid HTML
1901 // so remove them. Colours are all lowercase alpha characters (as
1902 // listed in https://graphviz.org/pdf/dotguide.pdf).
1903 Regex R("<FONT COLOR=\"\\w+\"></FONT>");
1904 while (true) {
1905 std::string Error;
1906 std::string S = R.sub("", Diff, &Error);
1907 if (Error != "")
1908 return Error;
1909 if (S == Diff)
1910 return Diff;
1911 Diff = S;
1912 }
1913 llvm_unreachable("Should not get here");
1914 }
1915
1916 // Put node out in the appropriate colour.
1917 assert(!Data[1] && "Data[1] is set unexpectedly.");
1918 std::string Body = makeHTMLReady(Data[0]->getBody());
1919 const StringRef BS = Body;
1920 StringRef BS1 = BS;
1921 // Drop leading newline, if present.
1922 if (BS.front() == '\n')
1923 BS1 = BS1.drop_front(1);
1924 // Get label.
1925 StringRef Label = BS1.take_until([](char C) { return C == ':'; });
1926 // drop predecessors as they can be big and are redundant
1927 BS1 = BS1.drop_until([](char C) { return C == '\n'; }).drop_front();
1928
1929 std::string S = "<FONT COLOR=\"" + Colour.str() + "\">" + Label.str() + ":";
1930
1931 // align each line to the left.
1932 while (BS1.size()) {
1933 S.append("<BR align=\"left\"/>");
1934 StringRef Line = BS1.take_until([](char C) { return C == '\n'; });
1935 S.append(Line.str());
1936 BS1 = BS1.drop_front(Line.size() + 1);
1937 }
1938 S.append("<BR align=\"left\"/></FONT>");
1939 return S;
1940}
1941
1942std::string DotCfgDiff::colourize(std::string S, StringRef Colour) const {
1943 if (S.length() == 0)
1944 return S;
1945 return "<FONT COLOR=\"" + Colour.str() + "\">" + S + "</FONT>";
1946}
1947
1948DotCfgDiff::DotCfgDiff(const PassesOptions &Opts, StringRef Title,
1949 const FuncDataT<DCData> &Before,
1950 const FuncDataT<DCData> &After)
1951 : Opts(Opts), GraphName(Title.str()) {
1952 StringMap<StringRef> EdgesMap;
1953
1954 // Handle each basic block in the before IR.
1955 for (auto &B : Before.getData()) {
1956 StringRef Label = B.getKey();
1957 const BlockDataT<DCData> &BD = B.getValue();
1958 createNode(Label, BD, Opts.dot_cfg_before_color);
1959
1960 // Create transitions with names made up of the from block label, the value
1961 // on which the transition is made and the to block label.
1962 for (StringMap<std::string>::const_iterator Sink = BD.getData().begin(),
1963 E = BD.getData().end();
1964 Sink != E; ++Sink) {
1965 std::string Key = (Label + " " + Sink->getKey().str()).str() + " " +
1966 BD.getData().getSuccessorLabel(Sink->getKey()).str();
1967 EdgesMap.insert({Key, Opts.dot_cfg_before_color});
1968 }
1969 }
1970
1971 // Handle each basic block in the after IR
1972 for (auto &A : After.getData()) {
1973 StringRef Label = A.getKey();
1974 const BlockDataT<DCData> &BD = A.getValue();
1975 auto It = NodePosition.find(Label);
1976 if (It == NodePosition.end())
1977 // This only exists in the after IR. Create the node.
1978 createNode(Label, BD, Opts.dot_cfg_after_color);
1979 else
1980 Nodes[It->second].setCommon(BD);
1981 // Add in the edges between the nodes (as common or only in after).
1982 for (StringMap<std::string>::const_iterator Sink = BD.getData().begin(),
1983 E = BD.getData().end();
1984 Sink != E; ++Sink) {
1985 std::string Key = (Label + " " + Sink->getKey().str()).str() + " " +
1986 BD.getData().getSuccessorLabel(Sink->getKey()).str();
1987 auto [It, Inserted] = EdgesMap.try_emplace(Key, Opts.dot_cfg_after_color);
1988 if (!Inserted)
1989 It->second = Opts.dot_cfg_common_color;
1990 }
1991 }
1992
1993 // Now go through the map of edges and add them to the node.
1994 for (auto &E : EdgesMap) {
1995 // Extract the source, sink and value from the edge key.
1996 StringRef S = E.getKey();
1997 auto SP1 = S.rsplit(' ');
1998 auto &SourceSink = SP1.first;
1999 auto SP2 = SourceSink.split(' ');
2000 StringRef Source = SP2.first;
2001 StringRef Sink = SP2.second;
2002 StringRef Value = SP1.second;
2003
2004 assert(NodePosition.count(Source) == 1 && "Expected to find node.");
2005 DotCfgDiffNode &SourceNode = Nodes[NodePosition[Source]];
2006 assert(NodePosition.count(Sink) == 1 && "Expected to find node.");
2007 unsigned SinkNode = NodePosition[Sink];
2008 StringRef Colour = E.second;
2009
2010 // Look for an edge from Source to Sink
2011 auto [It, Inserted] = EdgeLabels.try_emplace(SourceSink);
2012 if (Inserted)
2013 It->getValue() = colourize(Value.str(), Colour);
2014 else {
2015 StringRef V = It->getValue();
2016 std::string NV = colourize(V.str() + " " + Value.str(), Colour);
2017 Colour = Opts.dot_cfg_common_color;
2018 It->getValue() = NV;
2019 }
2020 SourceNode.addEdge(SinkNode, Value, Colour);
2021 }
2022 for (auto &I : Nodes)
2023 I.finalize(*this);
2024}
2025
2026DotCfgDiffDisplayGraph DotCfgDiff::createDisplayGraph(StringRef Title,
2027 StringRef EntryNodeName) {
2028 assert(NodePosition.count(EntryNodeName) == 1 &&
2029 "Expected to find entry block in map.");
2030 unsigned Entry = NodePosition[EntryNodeName];
2031 assert(Entry < Nodes.size() && "Expected to find entry node");
2032 DotCfgDiffDisplayGraph G(Title.str());
2033
2034 std::map<const unsigned, unsigned> NodeMap;
2035
2036 int EntryIndex = -1;
2037 unsigned Index = 0;
2038 for (auto &I : Nodes) {
2039 if (I.getIndex() == Entry)
2040 EntryIndex = Index;
2041 G.createNode(I.getBodyContent(), I.getColour());
2042 NodeMap.insert({I.getIndex(), Index++});
2043 }
2044 assert(EntryIndex >= 0 && "Expected entry node index to be set.");
2045 G.setEntryNode(EntryIndex);
2046
2047 for (auto &I : NodeMap) {
2048 unsigned SourceNode = I.first;
2049 unsigned DisplayNode = I.second;
2050 getNode(SourceNode).createDisplayEdges(G, DisplayNode, NodeMap);
2051 }
2052 return G;
2053}
2054
2055void DotCfgDiffNode::createDisplayEdges(
2056 DotCfgDiffDisplayGraph &DisplayGraph, unsigned DisplayNodeIndex,
2057 std::map<const unsigned, unsigned> &NodeMap) const {
2058
2059 DisplayNode &SourceDisplayNode = DisplayGraph.getNode(DisplayNodeIndex);
2060
2061 for (auto I : Edges) {
2062 unsigned SinkNodeIndex = I;
2063 StringRef Colour = getEdgeColour(SinkNodeIndex);
2064 const DotCfgDiffNode *SinkNode = &Graph.getNode(SinkNodeIndex);
2065
2066 StringRef Label = Graph.getEdgeSourceLabel(getIndex(), SinkNodeIndex);
2067 DisplayNode &SinkDisplayNode = DisplayGraph.getNode(SinkNode->getIndex());
2068 SourceDisplayNode.createEdge(Label, SinkDisplayNode, Colour);
2069 }
2070 SourceDisplayNode.createEdgeMap();
2071}
2072
2073void DotCfgDiffNode::finalize(DotCfgDiff &G) {
2074 for (auto E : EdgesMap) {
2075 Children.emplace_back(E.first);
2076 Edges.emplace_back(E.first);
2077 }
2078}
2079
2080} // namespace
2081
2082namespace llvm {
2083
2084template <> struct GraphTraits<DotCfgDiffDisplayGraph *> {
2085 using NodeRef = const DisplayNode *;
2086 using ChildIteratorType = DisplayNode::ChildIterator;
2087 using nodes_iterator = DotCfgDiffDisplayGraph::NodeIterator;
2088 using EdgeRef = const DisplayEdge *;
2089 using ChildEdgeIterator = DisplayNode::EdgeIterator;
2090
2091 static NodeRef getEntryNode(const DotCfgDiffDisplayGraph *G) {
2092 return G->getEntryNode();
2093 }
2095 return N->children_begin();
2096 }
2097 static ChildIteratorType child_end(NodeRef N) { return N->children_end(); }
2098 static nodes_iterator nodes_begin(const DotCfgDiffDisplayGraph *G) {
2099 return G->nodes_begin();
2100 }
2101 static nodes_iterator nodes_end(const DotCfgDiffDisplayGraph *G) {
2102 return G->nodes_end();
2103 }
2105 return N->edges_begin();
2106 }
2107 static ChildEdgeIterator child_edge_end(NodeRef N) { return N->edges_end(); }
2108 static NodeRef edge_dest(EdgeRef E) { return &E->getDestinationNode(); }
2109 static unsigned size(const DotCfgDiffDisplayGraph *G) { return G->size(); }
2110};
2111
2112template <>
2113struct DOTGraphTraits<DotCfgDiffDisplayGraph *> : public DefaultDOTGraphTraits {
2114 explicit DOTGraphTraits(bool Simple = false)
2116
2117 static bool renderNodesUsingHTML() { return true; }
2118 static std::string getGraphName(const DotCfgDiffDisplayGraph *DiffData) {
2119 return DiffData->getGraphName();
2120 }
2121 static std::string
2122 getGraphProperties(const DotCfgDiffDisplayGraph *DiffData) {
2123 return "\tsize=\"190, 190\";\n";
2124 }
2125 static std::string getNodeLabel(const DisplayNode *Node,
2126 const DotCfgDiffDisplayGraph *DiffData) {
2127 return DiffData->getNodeLabel(*Node);
2128 }
2129 static std::string getNodeAttributes(const DisplayNode *Node,
2130 const DotCfgDiffDisplayGraph *DiffData) {
2131 return DiffData->getNodeAttributes(*Node);
2132 }
2133 static std::string getEdgeSourceLabel(const DisplayNode *From,
2134 DisplayNode::ChildIterator &To) {
2135 return From->getEdgeSourceLabel(**To);
2136 }
2137 static std::string getEdgeAttributes(const DisplayNode *From,
2138 DisplayNode::ChildIterator &To,
2139 const DotCfgDiffDisplayGraph *DiffData) {
2140 return DiffData->getEdgeColorAttr(*From, **To);
2141 }
2142};
2143
2144} // namespace llvm
2145
2146namespace {
2147
2148void DotCfgDiffDisplayGraph::generateDotFile(StringRef DotFile) {
2149 std::error_code EC;
2150 raw_fd_ostream OutStream(DotFile, EC);
2151 if (EC) {
2152 errs() << "Error: " << EC.message() << "\n";
2153 return;
2154 }
2155 WriteGraph(OutStream, this, false);
2156 OutStream.flush();
2157 OutStream.close();
2158}
2159
2160} // namespace
2161
2162namespace llvm {
2163
2165 // Build up transition labels.
2166 const Instruction *Term = B.getTerminator();
2167 if (const CondBrInst *Br = dyn_cast<const CondBrInst>(Term)) {
2168 addSuccessorLabel(Br->getSuccessor(0)->getName().str(), "true");
2169 addSuccessorLabel(Br->getSuccessor(1)->getName().str(), "false");
2170 } else if (const SwitchInst *Sw = dyn_cast<const SwitchInst>(Term)) {
2171 addSuccessorLabel(Sw->case_default()->getCaseSuccessor()->getName().str(),
2172 "default");
2173 for (auto &C : Sw->cases()) {
2174 assert(C.getCaseValue() && "Expected to find case value.");
2175 SmallString<20> Value = formatv("{0}", C.getCaseValue()->getSExtValue());
2176 addSuccessorLabel(C.getCaseSuccessor()->getName().str(), Value);
2177 }
2178 } else
2179 for (const BasicBlock *Succ : successors(&B))
2180 addSuccessorLabel(Succ->getName().str(), "");
2181}
2182
2184 for (const MachineBasicBlock *Succ : successors(&B))
2185 addSuccessorLabel(Succ->getName().str(), "");
2186}
2187
2191
2193 StringRef Name, StringRef Prefix, StringRef PassID, StringRef Divider,
2194 bool InModule, unsigned Minor, const FuncDataT<DCData> &Before,
2195 const FuncDataT<DCData> &After) {
2196 assert(HTML && "Expected outstream to be set");
2197 SmallString<8> Extender;
2199 // Handle numbering and file names.
2200 if (InModule) {
2201 Extender = formatv("{0}_{1}", N, Minor);
2202 Number = formatv("{0}.{1}", N, Minor);
2203 } else {
2204 Extender = formatv("{0}", N);
2205 Number = formatv("{0}", N);
2206 }
2207 // Create a temporary file name for the dot file.
2209 sys::fs::createUniquePath("cfgdot-%%%%%%.dot", SV, true);
2210 std::string DotFile = Twine(SV).str();
2211
2212 SmallString<20> PDFFileName = formatv("diff_{0}.pdf", Extender);
2214
2215 Text = formatv("{0}.{1}{2}{3}{4}", Number, Prefix, makeHTMLReady(PassID),
2216 Divider, Name);
2217
2218 DotCfgDiff Diff(Opts, Text, Before, After);
2219 std::string EntryBlockName = After.getEntryBlockName();
2220 // Use the before entry block if the after entry block was removed.
2221 if (EntryBlockName == "")
2222 EntryBlockName = Before.getEntryBlockName();
2223 assert(EntryBlockName != "" && "Expected to find entry block");
2224
2225 DotCfgDiffDisplayGraph DG = Diff.createDisplayGraph(Text, EntryBlockName);
2226 DG.generateDotFile(DotFile);
2227
2228 *HTML << genHTML(Text, DotFile, PDFFileName);
2229 std::error_code EC = sys::fs::remove(DotFile);
2230 if (EC)
2231 errs() << "Error: " << EC.message() << "\n";
2232}
2233
2235 StringRef PDFFileName) const {
2236 SmallString<20> PDFFile = formatv("{0}/{1}", OutputDir, PDFFileName);
2237 // Create the PDF file.
2238 static ErrorOr<std::string> DotExe =
2239 sys::findProgramByName(Opts.print_changed_dot_path);
2240 if (!DotExe)
2241 return "Unable to find dot executable.";
2242
2243 StringRef Args[] = {Opts.print_changed_dot_path, "-Tpdf", "-o", PDFFile,
2244 DotFile};
2245 int Result = sys::ExecuteAndWait(*DotExe, Args, std::nullopt);
2246 if (Result < 0)
2247 return "Error executing system dot.";
2248
2249 // Create the HTML tag refering to the PDF file.
2251 " <a href=\"{0}\" target=\"_blank\">{1}</a><br/>\n", PDFFileName, Text);
2252 return S.c_str();
2253}
2254
2256 assert(HTML && "Expected outstream to be set");
2257 *HTML << "<button type=\"button\" class=\"collapsible\">0. "
2258 << "Initial IR (by function)</button>\n"
2259 << "<div class=\"content\">\n"
2260 << " <p>\n";
2261 // Create representation of IR
2264 // Now compare it against itself, which will have everything the
2265 // same and will generate the files.
2267 .compare(getModuleForComparison(IR),
2268 [&](bool InModule, unsigned Minor,
2269 const FuncDataT<DCData> &Before,
2270 const FuncDataT<DCData> &After) -> void {
2271 handleFunctionCompare("", " ", "Initial IR", "", InModule,
2272 Minor, Before, After);
2273 });
2274 *HTML << " </p>\n"
2275 << "</div><br/>\n";
2276 ++N;
2277}
2278
2284
2286 assert(HTML && "Expected outstream to be set");
2287 SmallString<20> Banner =
2288 formatv(" <a>{0}. Pass {1} on {2} omitted because no change</a><br/>\n",
2289 N, makeHTMLReady(PassID), Name);
2290 *HTML << Banner;
2291 ++N;
2292}
2293
2295 const IRDataT<DCData> &Before,
2296 const IRDataT<DCData> &After,
2297 IRUnitRef IR) {
2298 assert(HTML && "Expected outstream to be set");
2299 IRComparer<DCData>(Before, After)
2300 .compare(getModuleForComparison(IR),
2301 [&](bool InModule, unsigned Minor,
2302 const FuncDataT<DCData> &Before,
2303 const FuncDataT<DCData> &After) -> void {
2304 handleFunctionCompare(Name, " Pass ", PassID, " on ", InModule,
2305 Minor, Before, After);
2306 });
2307 *HTML << " </p></div>\n";
2308 ++N;
2309}
2310
2312 assert(HTML && "Expected outstream to be set");
2313 SmallString<20> Banner =
2314 formatv(" <a>{0}. {1} invalidated</a><br/>\n", N, makeHTMLReady(PassID));
2315 *HTML << Banner;
2316 ++N;
2317}
2318
2320 assert(HTML && "Expected outstream to be set");
2321 SmallString<20> Banner =
2322 formatv(" <a>{0}. Pass {1} on {2} filtered out</a><br/>\n", N,
2323 makeHTMLReady(PassID), Name);
2324 *HTML << Banner;
2325 ++N;
2326}
2327
2329 assert(HTML && "Expected outstream to be set");
2330 SmallString<20> Banner = formatv(" <a>{0}. {1} on {2} ignored</a><br/>\n", N,
2331 makeHTMLReady(PassID), Name);
2332 *HTML << Banner;
2333 ++N;
2334}
2335
2337 std::error_code EC;
2338 HTML = std::make_unique<raw_fd_ostream>(OutputDir + "/passes.html", EC);
2339 if (EC) {
2340 HTML = nullptr;
2341 return false;
2342 }
2343
2344 *HTML << "<!doctype html>"
2345 << "<html>"
2346 << "<head>"
2347 << "<style>.collapsible { "
2348 << "background-color: #777;"
2349 << " color: white;"
2350 << " cursor: pointer;"
2351 << " padding: 18px;"
2352 << " width: 100%;"
2353 << " border: none;"
2354 << " text-align: left;"
2355 << " outline: none;"
2356 << " font-size: 15px;"
2357 << "} .active, .collapsible:hover {"
2358 << " background-color: #555;"
2359 << "} .content {"
2360 << " padding: 0 18px;"
2361 << " display: none;"
2362 << " overflow: hidden;"
2363 << " background-color: #f1f1f1;"
2364 << "}"
2365 << "</style>"
2366 << "<title>passes.html</title>"
2367 << "</head>\n"
2368 << "<body>";
2369 return true;
2370}
2371
2373 if (!HTML)
2374 return;
2375 *HTML
2376 << "<script>var coll = document.getElementsByClassName(\"collapsible\");"
2377 << "var i;"
2378 << "for (i = 0; i < coll.length; i++) {"
2379 << "coll[i].addEventListener(\"click\", function() {"
2380 << " this.classList.toggle(\"active\");"
2381 << " var content = this.nextElementSibling;"
2382 << " if (content.style.display === \"block\"){"
2383 << " content.style.display = \"none\";"
2384 << " }"
2385 << " else {"
2386 << " content.style.display= \"block\";"
2387 << " }"
2388 << " });"
2389 << " }"
2390 << "</script>"
2391 << "</body>"
2392 << "</html>\n";
2393 HTML->flush();
2394 HTML->close();
2395}
2396
2401 SmallString<128> Dir;
2402 sys::fs::expand_tilde(Opts.dot_cfg_dir, Dir);
2404 assert(!Dir.empty() && "expected output dir to be non-empty");
2405 OutputDir = Dir.str();
2406 if (initializeHTML()) {
2408 return;
2409 }
2410 dbgs() << "Unable to open output stream for -cfg-dot-changed\n";
2411 }
2412}
2413
2415 LLVMContext &Context, bool DebugLogging, bool VerifyEach,
2416 PrintPassOptions PrintPassOpts)
2417 : Opts(Context.getLibraryOptions().get<PassesOptions>()), PrintIR(Opts),
2418 PrintPass(DebugLogging, PrintPassOpts), OptNone(DebugLogging),
2419 OptPassGate(Opts, Context), PreservedCFGChecker(Opts),
2420 PrintChangedIR(Opts, PrintChanged == ChangePrinter::Verbose),
2421 PrintChangedDiff(PrintChanged == ChangePrinter::DiffVerbose ||
2425 WebsiteChangeReporter(Opts, PrintChanged == ChangePrinter::DotCfgVerbose),
2426 PrintCrashIR(Opts), ChangeTester(Opts), Verify(DebugLogging),
2427 DroppedStatsIR(Opts.dropped_variable_stats), VerifyEach(VerifyEach) {}
2428
2429PrintCrashIRInstrumentation *PrintCrashIRInstrumentation::CrashReporter =
2430 nullptr;
2431
2433 if (!Opts.print_on_crash_path.empty()) {
2434 std::error_code EC;
2435 raw_fd_ostream Out(Opts.print_on_crash_path, EC);
2436 if (EC)
2438 Out << SavedIR;
2439 } else {
2440 dbgs() << SavedIR;
2441 }
2442}
2443
2444void PrintCrashIRInstrumentation::SignalHandler(void *) {
2445 // Called by signal handlers so do not lock here
2446 // Is the PrintCrashIRInstrumentation still alive?
2447 if (!CrashReporter)
2448 return;
2449
2450 assert((CrashReporter->Opts.print_on_crash ||
2451 !CrashReporter->Opts.print_on_crash_path.empty()) &&
2452 "Did not expect to get here without option set.");
2453 CrashReporter->reportCrashIR();
2454}
2455
2457 if (!CrashReporter)
2458 return;
2459
2460 assert((CrashReporter->Opts.print_on_crash ||
2461 !CrashReporter->Opts.print_on_crash_path.empty()) &&
2462 "Did not expect to get here without option set.");
2463 CrashReporter = nullptr;
2464}
2465
2468 if ((!Opts.print_on_crash && Opts.print_on_crash_path.empty()) ||
2469 CrashReporter)
2470 return;
2471
2472 sys::AddSignalHandler(SignalHandler, nullptr);
2473 CrashReporter = this;
2474
2475 PIC.registerBeforeNonSkippedPassCallback(
2476 [&PIC, this](StringRef PassID, IRUnitRef IR) {
2477 SavedIR.clear();
2479 OS << formatv("; *** Dump of {0}IR Before Last Pass {1}",
2480 llvm::forcePrintModuleIR() ? "Module " : "", PassID);
2481 if (!isInteresting(IR, PassID, PIC.getPassNameForClassName(PassID))) {
2482 OS << " Filtered Out ***\n";
2483 return;
2484 }
2485 OS << " Started ***\n";
2486 unwrapAndPrint(OS, IR);
2487 });
2488}
2489
2492 ExtendedIRContext *IRContext) {
2493 if (Opts.instnamer_after_each_pass)
2495 PrintIR.registerCallbacks(PIC, IRContext);
2496 PrintPass.registerCallbacks(PIC, IRContext);
2497 TimePasses.registerCallbacks(PIC);
2498 OptNone.registerCallbacks(PIC, IRContext);
2499 OptPassGate.registerCallbacks(PIC, IRContext);
2500 PrintChangedIR.registerCallbacks(PIC);
2501 PseudoProbeVerification.registerCallbacks(PIC);
2502 if (VerifyEach)
2503 Verify.registerCallbacks(PIC, MAM);
2504 PrintChangedDiff.registerCallbacks(PIC);
2505 WebsiteChangeReporter.registerCallbacks(PIC);
2506 ChangeTester.registerCallbacks(PIC);
2507 PrintCrashIR.registerCallbacks(PIC);
2508 DroppedStatsIR.registerCallbacks(PIC);
2509 if (MAM)
2510 PreservedCFGChecker.registerCallbacks(PIC, *MAM);
2511
2512 // TimeProfiling records the pass running time cost.
2513 // Its 'BeforePassCallback' can be appended at the tail of all the
2514 // BeforeCallbacks by calling `registerCallbacks` in the end.
2515 // Its 'AfterPassCallback' is put at the front of all the
2516 // AfterCallbacks by its `registerCallbacks`. This is necessary
2517 // to ensure that other callbacks are not included in the timings.
2518 TimeProfilingPasses.registerCallbacks(PIC, IRContext);
2519}
2520
2521template class ChangeReporter<std::string>;
2522template class TextChangeReporter<std::string>;
2523
2524template class BlockDataT<EmptyData>;
2525template class FuncDataT<EmptyData>;
2526template class IRDataT<EmptyData>;
2527template class ChangeReporter<IRDataT<EmptyData>>;
2529template class IRComparer<EmptyData>;
2530
2531} // 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:38
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:777
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:764
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.