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