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