LLVM: lib/Passes/StandardInstrumentations.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
48#include <unordered_map>
49#include <unordered_set>
50#include
51#include
52
53using namespace llvm;
54
57#ifdef EXPENSIVE_CHECKS
59#else
61#endif
62);
63
64
65
66
69 cl::desc("Print before passes that change them"),
71
72
73
76 cl::desc("system dot used by change reporters"));
77
78
79
80
85
86
87
92
93
94
99
100
101
103 "dot-cfg-dir",
104 cl::desc("Generate dot files into specified directory for changed IRs"),
106
107
109 "print-on-crash-path",
110 cl::desc("Print the last form of the IR before crash to a file"),
112
114 "print-on-crash",
115 cl::desc("Print the last form of the IR before crash (use -print-on-crash-path to dump to a file)"),
117
119 "opt-bisect-print-ir-path",
120 cl::desc("Print IR to path when opt-bisect-limit is reached"), cl::Hidden);
121
124 cl::desc("Print pass names and their ordinals"));
125
128 cl::desc("Print IR before the pass with this number as "
129 "reported by print-pass-numbers"));
130
133 cl::desc("Print IR after the pass with this number as "
134 "reported by print-pass-numbers"));
135
137 "ir-dump-directory",
138 cl::desc("If specified, IR printed using the "
139 "-print-[before|after]{-all} options will be dumped into "
140 "files in this directory rather than written to stderr"),
142
145 cl::desc("Dump dropped debug variables stats"),
147
148template static const IRUnitT *unwrapIR(Any IR) {
149 const IRUnitT **IRPtr = llvm::any_cast<const IRUnitT *>(&IR);
150 return IRPtr ? *IRPtr : nullptr;
151}
152
153namespace {
154
155
156
157
158
159
160
161
164 cl::desc("exe called with module IR after each pass that "
165 "changes it"));
166
167
168
169const Module *unwrapModule(Any IR, bool Force = false) {
170 if (const auto *M = unwrapIR(IR))
171 return M;
172
173 if (const auto *F = unwrapIR(IR)) {
175 return nullptr;
176
177 return F->getParent();
178 }
179
180 if (const auto *C = unwrapIRLazyCallGraph::SCC(IR)) {
184 return F.getParent();
185 }
186 }
187 assert(!Force && "Expected a module");
188 return nullptr;
189 }
190
191 if (const auto *L = unwrapIR(IR)) {
192 const Function *F = L->getHeader()->getParent();
194 return nullptr;
195 return F->getParent();
196 }
197
198 if (const auto *MF = unwrapIR(IR)) {
200 return nullptr;
201 return MF->getFunction().getParent();
202 }
203
205}
206
209 return;
211}
215 M->print(OS, nullptr);
217 for (const auto &F : M->functions()) {
219 }
220 }
221}
222
228 }
229 }
230}
231
233 const Function *F = L->getHeader()->getParent();
235 return;
237}
238
241 return;
243}
244
245std::string getIRName(Any IR) {
246 if (unwrapIR(IR))
247 return "[module]";
248
249 if (const auto *F = unwrapIR(IR))
250 return F->getName().str();
251
252 if (const auto *C = unwrapIRLazyCallGraph::SCC(IR))
254
255 if (const auto *L = unwrapIR(IR))
256 return "loop %" + L->getName().str() + " in function " +
257 L->getHeader()->getParent()->getName().str();
258
259 if (const auto *MF = unwrapIR(IR))
263}
264
265bool moduleContainsFilterPrintFunc(const Module &M) {
266 return any_of(M.functions(),
268 return isFunctionInPrintList(F.getName());
269 }) ||
271}
272
277 }) ||
279}
280
281bool shouldPrintIR(Any IR) {
282 if (const auto *M = unwrapIR(IR))
283 return moduleContainsFilterPrintFunc(*M);
284
285 if (const auto *F = unwrapIR(IR))
287
288 if (const auto *C = unwrapIRLazyCallGraph::SCC(IR))
289 return sccContainsFilterPrintFunc(*C);
290
291 if (const auto *L = unwrapIR(IR))
293
294 if (const auto *MF = unwrapIR(IR))
297}
298
299
300
302 if (!shouldPrintIR(IR))
303 return;
304
306 auto *M = unwrapModule(IR);
307 assert(M && "should have unwrapped module");
308 printIR(OS, M);
309 return;
310 }
311
312 if (const auto *M = unwrapIR(IR)) {
313 printIR(OS, M);
314 return;
315 }
316
317 if (const auto *F = unwrapIR(IR)) {
319 return;
320 }
321
322 if (const auto *C = unwrapIRLazyCallGraph::SCC(IR)) {
324 return;
325 }
326
327 if (const auto *L = unwrapIR(IR)) {
328 printIR(OS, L);
329 return;
330 }
331
332 if (const auto *MF = unwrapIR(IR)) {
333 printIR(OS, MF);
334 return;
335 }
337}
338
339
340bool isIgnored(StringRef PassID) {
342 {"PassManager", "PassAdaptor", "AnalysisManagerProxy",
343 "DevirtSCCRepeatedPass", "ModuleInlinerWrapperPass",
344 "VerifierPass", "PrintModulePass", "PrintMIRPass",
345 "PrintMIRPreparePass"});
346}
347
348std::string makeHTMLReady(StringRef SR) {
349 std::string S;
350 while (true) {
352 SR.take_until([](char C) { return C == '<' || C == '>'; });
353 S.append(Clean.str());
355 if (SR.size() == 0)
356 return S;
357 S.append(SR[0] == '<' ? "<" : ">");
359 }
361}
362
363
364const Module *getModuleForComparison(Any IR) {
365 if (const auto *M = unwrapIR(IR))
366 return M;
367 if (const auto *C = unwrapIRLazyCallGraph::SCC(IR))
368 return C->begin()->getFunction().getParent();
369 return nullptr;
370}
371
372bool isInterestingFunction(const Function &F) {
374}
375
376
377
380 return false;
381 if (const auto *F = unwrapIR(IR))
382 return isInterestingFunction(*F);
383 return true;
384}
385
386}
387
389 assert(BeforeStack.empty() && "Problem with Change Printer stack.");
390}
391
392template
395
396 if (InitialIR) {
397 InitialIR = false;
398 if (VerboseMode)
399 handleInitialIR(IR);
400 }
401
402
403
404
405 BeforeStack.emplace_back();
406
408 return;
409
410
411 T &Data = BeforeStack.back();
412 generateIRRepresentation(IR, PassID, Data);
413}
414
415template
418 assert(!BeforeStack.empty() && "Unexpected empty stack encountered.");
419
420 std::string Name = getIRName(IR);
421
422 if (isIgnored(PassID)) {
423 if (VerboseMode)
424 handleIgnored(PassID, Name);
426 if (VerboseMode)
427 handleFiltered(PassID, Name);
428 } else {
429
430 T &Before = BeforeStack.back();
431
433 generateIRRepresentation(IR, PassID, After);
434
435
437 if (VerboseMode)
438 omitAfter(PassID, Name);
439 } else
441 }
442 BeforeStack.pop_back();
443}
444
445template
447 assert(!BeforeStack.empty() && "Unexpected empty stack encountered.");
448
449
450
451
452
453 if (VerboseMode)
454 handleInvalidated(PassID);
455 BeforeStack.pop_back();
456}
457
458template
463 });
464
468 });
471 handleInvalidatedPass(P);
472 });
473}
474
475template
478
480
481
482 auto *M = unwrapModule(IR, true);
483 assert(M && "Expected module to be unwrapped when forced.");
484 Out << "*** IR Dump At Start ***\n";
485 M->print(Out, nullptr);
486}
487
488template
490 Out << formatv("*** IR Dump After {0} on {1} omitted because no change ***\n",
491 PassID, Name);
492}
493
494template
496 Out << formatv("*** IR Pass {0} invalidated ***\n", PassID);
497}
498
499template
501 std::string &Name) {
503 formatv("*** IR Dump After {0} on {1} filtered out ***\n", PassID, Name);
504 Out << Banner;
505}
506
507template
509 Out << formatv("*** IR Pass {0} on {1} ignored ***\n", PassID, Name);
510}
511
513
518}
519
521 std::string &Output) {
524 OS.str();
525}
526
528 const std::string &Before,
529 const std::string &After, Any) {
530
532 Out << "*** IR Dump Before " << PassID << " on " << Name << " ***\n"
534
535
536
537 if (After.empty()) {
538 Out << "*** IR Deleted After " << PassID << " on " << Name << " ***\n";
539 return;
540 }
541
542 Out << "*** IR Dump After " << PassID << " on " << Name << " ***\n" << After;
543}
544
546
548 if (TestChanged != "")
550}
551
553
558 dbgs() << "Unable to create temporary file.";
559 return;
560 }
562 if (!Exe) {
563 dbgs() << "Unable to find test-changed executable.";
564 return;
565 }
566
567 StringRef Args[] = {TestChanged, FileName[0], PassID};
569 if (Result < 0) {
570 dbgs() << "Error executing test-changed executable.";
571 return;
572 }
573
575 dbgs() << "Unable to remove temporary file.";
576}
577
579
580
581 std::string S;
584}
585
591 const std::string &Before,
592 const std::string &After, Any) {
594}
595
596template
599 function_ref<void(const T *, const T *)> HandlePair) {
600 const auto &BFD = Before.getData();
601 const auto &AFD = After.getData();
602 std::vectorstd::string::const_iterator BI = Before.getOrder().begin();
603 std::vectorstd::string::const_iterator BE = Before.getOrder().end();
604 std::vectorstd::string::const_iterator AI = After.getOrder().begin();
605 std::vectorstd::string::const_iterator AE = After.getOrder().end();
606
607 auto HandlePotentiallyRemovedData = [&](std::string S) {
608
609 if (!AFD.count(S)) {
610
611 HandlePair(&BFD.find(*BI)->getValue(), nullptr);
612 }
613 };
614 auto HandleNewData = [&](std::vector<const T *> &Q) {
615
616 for (const T *NBI : Q)
617 HandlePair(nullptr, NBI);
618 Q.clear();
619 };
620
621
622
623
624
625
626
627
628
629
630 std::vector<const T *> NewDataQueue;
631 while (AI != AE) {
632 if (!BFD.count(*AI)) {
633
634
635 NewDataQueue.emplace_back(&AFD.find(*AI)->getValue());
636 ++AI;
637 continue;
638 }
639
640
641
642
643
644 while (BI != BE && *BI != *AI) {
645 HandlePotentiallyRemovedData(*BI);
646 ++BI;
647 }
648
649 HandleNewData(NewDataQueue);
650
651 const T &AData = AFD.find(*AI)->getValue();
652 const T &BData = BFD.find(*AI)->getValue();
653 HandlePair(&BData, &AData);
654 if (BI != BE)
655 ++BI;
656 ++AI;
657 }
658
659
660 while (BI != BE) {
661 HandlePotentiallyRemovedData(*BI);
662 ++BI;
663 }
664
665 HandleNewData(NewDataQueue);
666}
667
668template
670 bool CompareModule,
671 std::function<void(bool InModule, unsigned Minor,
673 CompareFunc) {
674 if (!CompareModule) {
675
676 assert(Before.getData().size() == 1 && After.getData().size() == 1 &&
677 "Expected only one function.");
678 CompareFunc(false, 0, Before.getData().begin()->getValue(),
679 After.getData().begin()->getValue());
680 return;
681 }
682
683 unsigned Minor = 0;
687 assert((B || A) && "Both functions cannot be missing.");
688 if ()
689 B = &Missing;
690 else if ()
691 A = &Missing;
692 CompareFunc(true, Minor++, *B, *A);
693 });
694}
695
697 if (const Module *M = getModuleForComparison(IR)) {
698
700 generateFunctionData(Data, F);
701 return;
702 }
703
704 if (const auto *F = unwrapIR(IR)) {
705 generateFunctionData(Data, *F);
706 return;
707 }
708
709 if (const auto *L = unwrapIR(IR)) {
710 auto *F = L->getHeader()->getParent();
711 generateFunctionData(Data, *F);
712 return;
713 }
714
715 if (const auto *MF = unwrapIR(IR)) {
716 generateFunctionData(Data, *MF);
717 return;
718 }
719
721}
722
725}
726
729}
730
731template
732template
736 int I = 0;
738 std::string BBName = B.getName().str();
739 if (BBName.empty()) {
741 ++I;
742 }
743 FD.getOrder().emplace_back(BBName);
745 }
746 Data.getOrder().emplace_back(F.getName());
747 Data.getData().insert({F.getName(), FD});
748 return true;
749 }
750 return false;
751}
752
755 "PassRunDescriptorStack is not empty at exit");
756}
757
761 const Module *M = unwrapModule(IR, true);
762 assert(M && "should have unwrapped module");
764 unsigned MaxHashWidth = sizeof(uint64_t) * 2;
766 if (unwrapIR(IR)) {
767 ResultStream << "-module";
768 } else if (const auto *F = unwrapIR(IR)) {
769 ResultStream << "-function-";
770 auto FunctionNameHash = xxh3_64bits(F->getName());
772 MaxHashWidth);
773 } else if (const auto *C = unwrapIRLazyCallGraph::SCC(IR)) {
774 ResultStream << "-scc-";
775 auto SCCNameHash = xxh3_64bits(C->getName());
777 } else if (const auto *L = unwrapIR(IR)) {
778 ResultStream << "-loop-";
779 auto LoopNameHash = xxh3_64bits(L->getName());
781 } else if (const auto *MF = unwrapIR(IR)) {
782 ResultStream << "-machine-function-";
785 MaxHashWidth);
786 } else {
788 }
789 return Result;
790}
791
792std::string PrintIRInstrumentation::fetchDumpFilename(StringRef PassName,
796 "The flag -ir-dump-directory must be passed to dump IR to files");
798 ResultPath += RootDirectory;
801 FilenameStream << CurrentPassNumber;
802 FilenameStream << "-";
804 FilenameStream << "-";
807 return std::string(ResultPath);
808}
809
814};
815
817 static constexpr std::array FileSuffixes = {"-before.ll", "-after.ll",
818 "-invalidated.ll"};
819 return FileSuffixes[static_cast<size_t>(Type)];
820}
821
822void PrintIRInstrumentation::pushPassRunDescriptor(
823 StringRef PassID, Any IR, std::string &DumpIRFilename) {
824 const Module *M = unwrapModule(IR);
826 PassRunDescriptor(M, DumpIRFilename, getIRName(IR), PassID));
827}
828
829PrintIRInstrumentation::PassRunDescriptor
830PrintIRInstrumentation::popPassRunDescriptor(StringRef PassID) {
831 assert(!PassRunDescriptorStack.empty() && "empty PassRunDescriptorStack");
832 PassRunDescriptor Descriptor = PassRunDescriptorStack.pop_back_val();
833 assert(Descriptor.PassID == PassID && "malformed PassRunDescriptorStack");
834 return Descriptor;
835}
836
837
839 std::error_code EC;
841 if (!ParentPath.empty()) {
843 if (EC)
845 " to support -ir-dump-directory: " + EC.message());
846 }
847 int Result = 0;
850 if (EC)
852 " to support -ir-dump-directory: " + EC.message());
853 return Result;
854}
855
856void PrintIRInstrumentation::printBeforePass(StringRef PassID, Any IR) {
857 if (isIgnored(PassID))
858 return;
859
860 std::string DumpIRFilename;
862 (shouldPrintBeforePass(PassID) || shouldPrintAfterPass(PassID) ||
863 shouldPrintBeforeCurrentPassNumber() ||
864 shouldPrintAfterCurrentPassNumber()))
865 DumpIRFilename = fetchDumpFilename(PassID, IR);
866
867
868
869
870
871 if (shouldPrintAfterPass(PassID))
872 pushPassRunDescriptor(PassID, IR, DumpIRFilename);
873
874 if (!shouldPrintIR(IR))
875 return;
876
877 ++CurrentPassNumber;
878
879 if (shouldPrintPassNumbers())
880 dbgs() << " Running pass " << CurrentPassNumber << " " << PassID
881 << " on " << getIRName(IR) << "\n";
882
883 if (shouldPrintAfterCurrentPassNumber())
884 pushPassRunDescriptor(PassID, IR, DumpIRFilename);
885
886 if (!shouldPrintBeforePass(PassID) && !shouldPrintBeforeCurrentPassNumber())
887 return;
888
889 auto WriteIRToStream = [&](raw_ostream &Stream) {
890 Stream << "; *** IR Dump Before ";
891 if (shouldPrintBeforeSomePassNumber())
892 Stream << CurrentPassNumber << "-";
893 Stream << PassID << " on " << getIRName(IR) << " ***\n";
894 unwrapAndPrint(Stream, IR);
895 };
896
897 if (!DumpIRFilename.empty()) {
898 DumpIRFilename += getFileSuffix(IRDumpFileSuffixType::Before);
901 WriteIRToStream(DumpIRFileStream);
902 } else {
903 WriteIRToStream(dbgs());
904 }
905}
906
907void PrintIRInstrumentation::printAfterPass(StringRef PassID, Any IR) {
908 if (isIgnored(PassID))
909 return;
910
911 if (!shouldPrintAfterPass(PassID) && !shouldPrintAfterCurrentPassNumber())
912 return;
913
914 auto [M, DumpIRFilename, IRName, StoredPassID] = popPassRunDescriptor(PassID);
915 assert(StoredPassID == PassID && "mismatched PassID");
916
917 if (!shouldPrintIR(IR) ||
918 (!shouldPrintAfterPass(PassID) && !shouldPrintAfterCurrentPassNumber()))
919 return;
920
922 Stream << "; *** IR Dump After ";
923 if (shouldPrintAfterSomePassNumber())
924 Stream << CurrentPassNumber << "-";
925 Stream << StringRef(formatv("{0}", PassID)) << " on " << IRName << " ***\n";
926 unwrapAndPrint(Stream, IR);
927 };
928
930 assert(!DumpIRFilename.empty() && "DumpIRFilename must not be empty and "
931 "should be set in printBeforePass");
932 const std::string DumpIRFilenameWithSuffix =
933 DumpIRFilename + getFileSuffix(IRDumpFileSuffixType::After).str();
936 true};
937 WriteIRToStream(DumpIRFileStream, IRName);
938 } else {
939 WriteIRToStream(dbgs(), IRName);
940 }
941}
942
943void PrintIRInstrumentation::printAfterPassInvalidated(StringRef PassID) {
944 if (isIgnored(PassID))
945 return;
946
947 if (!shouldPrintAfterPass(PassID) && !shouldPrintAfterCurrentPassNumber())
948 return;
949
950 auto [M, DumpIRFilename, IRName, StoredPassID] = popPassRunDescriptor(PassID);
951 assert(StoredPassID == PassID && "mismatched PassID");
952
953
954 if (!M ||
955 (!shouldPrintAfterPass(PassID) && !shouldPrintAfterCurrentPassNumber()))
956 return;
957
961 Banner = formatv("; *** IR Dump After {0} on {1} (invalidated) ***", PassID,
962 IRName);
963 Stream << Banner << "\n";
964 printIR(Stream, M);
965 };
966
968 assert(!DumpIRFilename.empty() && "DumpIRFilename must not be empty and "
969 "should be set in printBeforePass");
970 const std::string DumpIRFilenameWithSuffix =
971 DumpIRFilename + getFileSuffix(IRDumpFileSuffixType::Invalidated).str();
974 true};
975 WriteIRToStream(DumpIRFileStream, M, IRName);
976 } else {
977 WriteIRToStream(dbgs(), M, IRName);
978 }
979}
980
981bool PrintIRInstrumentation::shouldPrintBeforePass(StringRef PassID) {
983 return true;
984
987}
988
989bool PrintIRInstrumentation::shouldPrintAfterPass(StringRef PassID) {
991 return true;
992
995}
996
997bool PrintIRInstrumentation::shouldPrintBeforeCurrentPassNumber() {
998 return shouldPrintBeforeSomePassNumber() &&
1000}
1001
1002bool PrintIRInstrumentation::shouldPrintAfterCurrentPassNumber() {
1003 return shouldPrintAfterSomePassNumber() &&
1005}
1006
1007bool PrintIRInstrumentation::shouldPrintPassNumbers() {
1009}
1010
1011bool PrintIRInstrumentation::shouldPrintBeforeSomePassNumber() {
1013}
1014
1015bool PrintIRInstrumentation::shouldPrintAfterSomePassNumber() {
1017}
1018
1021 this->PIC = &PIC;
1022
1023
1024
1025
1026 if (shouldPrintPassNumbers() || shouldPrintBeforeSomePassNumber() ||
1031
1035 this->printAfterPass(P, IR);
1036 });
1039 this->printAfterPassInvalidated(P);
1040 });
1041 }
1042}
1043
1048}
1049
1050bool OptNoneInstrumentation::shouldRun(StringRef PassID, Any IR) {
1051 bool ShouldRun = true;
1052 if (const auto *F = unwrapIR(IR))
1053 ShouldRun = ->hasOptNone();
1054 else if (const auto *L = unwrapIR(IR))
1055 ShouldRun = !L->getHeader()->getParent()->hasOptNone();
1056 else if (const auto *MF = unwrapIR(IR))
1058
1059 if (!ShouldRun && DebugLogging) {
1060 errs() << "Skipping pass " << PassID << " on " << getIRName(IR)
1061 << " due to optnone attribute\n";
1062 }
1063 return ShouldRun;
1064}
1065
1068 return true;
1069
1070 bool ShouldRun =
1073
1074
1075 this->HasWrittenIR = true;
1076 const Module *M = unwrapModule(IR, true);
1077 assert((M && &M->getContext() == &Context) && "Missing/Mismatching Module");
1078 std::error_code EC;
1080 if (EC)
1082 M->print(OS, nullptr);
1083 }
1084 return ShouldRun;
1085}
1086
1091 return;
1092
1095 });
1096}
1097
1098raw_ostream &PrintPassInstrumentation::print() {
1100 assert(Indent >= 0);
1102 }
1103 return dbgs();
1104}
1105
1108 if (!Enabled)
1109 return;
1110
1111 std::vector SpecialPasses;
1113 SpecialPasses.emplace_back("PassManager");
1114 SpecialPasses.emplace_back("PassAdaptor");
1115 }
1116
1120 "Unexpectedly skipping special pass");
1121
1122 print() << "Skipping pass: " << PassID << " on " << getIRName(IR) << "\n";
1123 });
1127 return;
1128
1129 auto &OS = print();
1130 OS << "Running pass: " << PassID << " on " << getIRName(IR);
1131 if (const auto *F = unwrapIR(IR)) {
1132 unsigned Count = F->getInstructionCount();
1133 OS << " (" << Count << " instruction";
1134 if (Count != 1)
1135 OS << 's';
1136 OS << ')';
1137 } else if (const auto *C = unwrapIRLazyCallGraph::SCC(IR)) {
1138 int Count = C->size();
1139 OS << " (" << Count << " node";
1140 if (Count != 1)
1141 OS << 's';
1142 OS << ')';
1143 }
1144 OS << "\n";
1145 Indent += 2;
1146 });
1151 return;
1152
1153 Indent -= 2;
1154 });
1158 return;
1159
1160 Indent -= 2;
1161 });
1162
1165 print() << "Running analysis: " << PassID << " on " << getIRName(IR)
1166 << "\n";
1167 Indent += 2;
1168 });
1172 print() << "Invalidating analysis: " << PassID << " on " << getIRName(IR)
1173 << "\n";
1174 });
1176 print() << "Clearing all analysis results for: " << IRName << "\n";
1177 });
1178 }
1179}
1180
1182 bool TrackBBLifetime) {
1183 if (TrackBBLifetime)
1185 for (const auto &BB : *F) {
1187 BBGuards->try_emplace(intptr_t(&BB), &BB);
1188 for (const auto *Succ : successors(&BB)) {
1189 Graph[&BB][Succ]++;
1191 BBGuards->try_emplace(intptr_t(Succ), Succ);
1192 }
1193 }
1194}
1195
1198 out << BB->getName() << "<" << BB << ">";
1199 return;
1200 }
1201
1203 out << "unnamed_removed<" << BB << ">";
1204 return;
1205 }
1206
1208 out << "entry"
1209 << "<" << BB << ">";
1210 return;
1211 }
1212
1213 unsigned FuncOrderBlockNum = 0;
1214 for (auto &FuncBB : *BB->getParent()) {
1215 if (&FuncBB == BB)
1216 break;
1217 FuncOrderBlockNum++;
1218 }
1219 out << "unnamed_" << FuncOrderBlockNum << "<" << BB << ">";
1220}
1221
1226 if (Before.isPoisoned()) {
1227 out << "Some blocks were deleted\n";
1228 return;
1229 }
1230
1231
1232 if (Before.Graph.size() != After.Graph.size())
1233 out << "Different number of non-leaf basic blocks: before="
1234 << Before.Graph.size() << ", after=" << After.Graph.size() << "\n";
1235
1236 for (auto &BB : Before.Graph) {
1237 auto BA = After.Graph.find(BB.first);
1238 if (BA == After.Graph.end()) {
1239 out << "Non-leaf block ";
1241 out << " is removed (" << BB.second.size() << " successors)\n";
1242 }
1243 }
1244
1245 for (auto &BA : After.Graph) {
1246 auto BB = Before.Graph.find(BA.first);
1247 if (BB == Before.Graph.end()) {
1248 out << "Non-leaf block ";
1250 out << " is added (" << BA.second.size() << " successors)\n";
1251 continue;
1252 }
1253
1254 if (BB->second == BA.second)
1255 continue;
1256
1257 out << "Different successors of block ";
1259 out << " (unordered):\n";
1260 out << "- before (" << BB->second.size() << "): ";
1261 for (auto &SuccB : BB->second) {
1263 if (SuccB.second != 1)
1264 out << "(" << SuccB.second << "), ";
1265 else
1266 out << ", ";
1267 }
1268 out << "\n";
1269 out << "- after (" << BA.second.size() << "): ";
1270 for (auto &SuccA : BA.second) {
1272 if (SuccA.second != 1)
1273 out << "(" << SuccA.second << "), ";
1274 else
1275 out << ", ";
1276 }
1277 out << "\n";
1278 }
1279}
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1293
1295
1296public:
1297
1299
1300
1303 }
1304};
1305
1307
1311
1314 };
1315
1317
1320 }
1321};
1322
1324
1328
1331 };
1332
1334
1337 }
1338};
1339
1341
1348}
1349
1352
1353 if (const auto *MaybeF = unwrapIR(IR)) {
1355 } else if (const auto *MaybeM = unwrapIR(IR)) {
1358 }
1359 return Functions;
1360}
1361
1365 return;
1366
1367 bool Registered = false;
1370#if LLVM_ENABLE_ABI_BREAKING_CHECKS
1371 assert(&PassStack.emplace_back(P));
1372#endif
1373 (void)this;
1374
1376 *const_cast<Module *>(unwrapModule(IR, true)))
1377 .getManager();
1378 if (!Registered) {
1382 Registered = true;
1383 }
1384
1386
1389 }
1390
1391 if (const auto *MPtr = unwrapIR(IR)) {
1392 auto &M = *const_cast<Module *>(MPtr);
1394 }
1395 });
1396
1399#if LLVM_ENABLE_ABI_BREAKING_CHECKS
1400 assert(PassStack.pop_back_val() == P &&
1401 "Before and After callbacks must correspond");
1402#endif
1403 (void)this;
1404 });
1405
1408#if LLVM_ENABLE_ABI_BREAKING_CHECKS
1409 assert(PassStack.pop_back_val() == P &&
1410 "Before and After callbacks must correspond");
1411#endif
1412 (void)this;
1413
1414
1415
1416
1418 *const_cast<Module *>(unwrapModule(IR, true)))
1419 .getManager();
1420
1422 if (auto *HashBefore =
1426 "Function @{0} changed by {1} without invalidating analyses",
1428 }
1429 }
1430
1432 const CFG &GraphBefore, const CFG &GraphAfter) {
1433 if (GraphAfter == GraphBefore)
1434 return;
1435
1437 << "Error: " << Pass
1438 << " does not invalidate CFG analyses but CFG changes detected in "
1439 "function @"
1440 << FuncName << ":\n";
1443 };
1444
1445 if (auto *GraphBefore =
1447 CheckCFG(P, F->getName(), *GraphBefore,
1449 }
1450 if (const auto *MPtr = unwrapIR(IR)) {
1451 auto &M = *const_cast<Module *>(MPtr);
1452 if (auto *HashBefore =
1456 "Module changed by {0} without invalidating analyses", P));
1457 }
1458 }
1459 }
1460 });
1461}
1462
1467 if (isIgnored(P) || P == "VerifierPass")
1468 return;
1469 const auto *F = unwrapIR(IR);
1470 if () {
1471 if (const auto *L = unwrapIR(IR))
1472 F = L->getHeader()->getParent();
1473 }
1474
1475 if (F) {
1476 if (DebugLogging)
1477 dbgs() << "Verifying function " << F->getName() << "\n";
1478
1481 "\"{0}\", compilation aborted!",
1482 P));
1483 } else {
1484 const auto *M = unwrapIR(IR);
1485 if (!M) {
1486 if (const auto *C = unwrapIRLazyCallGraph::SCC(IR))
1487 M = C->begin()->getFunction().getParent();
1488 }
1489
1490 if (M) {
1491 if (DebugLogging)
1492 dbgs() << "Verifying module " << M->getName() << "\n";
1493
1496 "\"{0}\", compilation aborted!",
1497 P));
1498 }
1499
1500 if (auto *MF = unwrapIR(IR)) {
1501 if (DebugLogging)
1502 dbgs() << "Verifying machine function " << MF->getName() << '\n';
1503 std::string Banner =
1504 formatv("Broken machine function found after pass "
1505 "\"{0}\", compilation aborted!",
1506 P);
1507 if (MAM) {
1509 auto &MFAM =
1511 .getManager();
1514 } else {
1516 }
1517 }
1518 }
1519 });
1520}
1521
1523
1528}
1529
1535 formatv("*** IR Dump After {0} on {1} ***\n", PassID, Name);
1536 Out << Banner;
1538 .compare(getModuleForComparison(IR),
1539 [&](bool InModule, unsigned Minor,
1542 handleFunctionCompare(Name, "", PassID, " on ", InModule,
1544 });
1545 Out << "\n";
1546}
1547
1552
1553 if (InModule)
1554 Out << "\n*** IR for function " << Name << " ***\n";
1555
1559 StringRef BStr = B ? B->getBody() : "\n";
1560 StringRef AStr = A ? A->getBody() : "\n";
1561 const std::string Removed =
1562 UseColour ? "\033[31m-%l\033[0m\n" : "-%l\n";
1563 const std::string Added = UseColour ? "\033[32m+%l\033[0m\n" : "+%l\n";
1564 const std::string NoChange = " %l\n";
1565 Out << doSystemDiff(BStr, AStr, Removed, Added, NoChange);
1566 });
1567}
1568
1575}
1576
1578
1582 return;
1587 this->runAfterPass();
1588 },
1589 true);
1592 true);
1596 [this](StringRef P, Any IR) { this->runAfterPass(); }, true);
1597}
1598
1599void TimeProfilingPassesHandler::runBeforePass(StringRef PassID, Any IR) {
1601}
1602
1604
1605namespace {
1606
1607class DisplayNode;
1608class DotCfgDiffDisplayGraph;
1609
1610
1611class DisplayElement {
1612public:
1613
1614 StringRef getColour() const { return Colour; }
1615
1616protected:
1617 DisplayElement(StringRef Colour) : Colour(Colour) {}
1619};
1620
1621
1622
1623class DisplayEdge : public DisplayElement {
1624public:
1627
1628 std::string getValue() const { return Value; }
1629
1630 const DisplayNode &getDestinationNode() const { return Node; }
1631
1632protected:
1633 std::string Value;
1634 const DisplayNode &Node;
1635};
1636
1637
1638class DisplayNode : public DisplayElement {
1639public:
1640
1641
1644
1645
1646 using ChildIterator = std::unordered_set<DisplayNode *>::const_iterator;
1647 ChildIterator children_begin() const { return Children.cbegin(); }
1648 ChildIterator children_end() const { return Children.cend(); }
1649
1650
1651 using EdgeIterator = std::vector<DisplayEdge *>::const_iterator;
1652 EdgeIterator edges_begin() const { return EdgePtrs.cbegin(); }
1653 EdgeIterator edges_end() const { return EdgePtrs.cend(); }
1654
1655
1657
1658
1659 std::string getContent() const { return Content; }
1660
1661
1662 const DisplayEdge &getEdge(const DisplayNode &To) const {
1663 assert(EdgeMap.find(&To) != EdgeMap.end() && "Expected to find edge.");
1664 return *EdgeMap.find(&To)->second;
1665 }
1666
1667
1668
1669 std::string getEdgeSourceLabel(const DisplayNode &Sink) const {
1670 return getEdge(Sink).getValue();
1671 }
1672
1673 void createEdgeMap();
1674
1675protected:
1676 const std::string Content;
1677
1678
1679
1680
1681 std::vector Edges;
1682
1683 std::vector<DisplayEdge *> EdgePtrs;
1684 std::unordered_set<DisplayNode *> Children;
1685 std::unordered_map<const DisplayNode *, const DisplayEdge *> EdgeMap;
1686
1687
1688 bool AllEdgesCreated = false;
1689};
1690
1691
1692class DotCfgDiffDisplayGraph {
1693public:
1694 DotCfgDiffDisplayGraph(std::string Name) : GraphName(Name) {}
1695
1696
1697 void generateDotFile(StringRef DotFile);
1698
1699
1700 using NodeIterator = std::vector<DisplayNode *>::const_iterator;
1701 NodeIterator nodes_begin() const {
1702 assert(NodeGenerationComplete && "Unexpected children iterator creation");
1703 return NodePtrs.cbegin();
1704 }
1705 NodeIterator nodes_end() const {
1706 assert(NodeGenerationComplete && "Unexpected children iterator creation");
1707 return NodePtrs.cend();
1708 }
1709
1710
1711
1712 void setEntryNode(unsigned N) {
1713
1714 assert(!NodeGenerationComplete && "Unexpected node creation");
1715 NodeGenerationComplete = true;
1716 for (auto &N : Nodes)
1717 NodePtrs.emplace_back(&N);
1718
1719 EntryNode = NodePtrs[N];
1720 }
1721
1722
1723 void createNode(std::string C, StringRef Colour) {
1724 assert(!NodeGenerationComplete && "Unexpected node creation");
1725 Nodes.emplace_back(C, Colour);
1726 }
1727
1728 DisplayNode &getNode(unsigned N) {
1729 assert(N < Nodes.size() && "Node is out of bounds");
1730 return Nodes[N];
1731 }
1732 unsigned size() const {
1733 assert(NodeGenerationComplete && "Unexpected children iterator creation");
1734 return Nodes.size();
1735 }
1736
1737
1738 std::string getGraphName() const { return GraphName; }
1739
1740
1741
1743 return Node.getContent();
1744 }
1745
1746
1747 std::string getNodeAttributes(const DisplayNode &Node) const {
1748 return attribute(Node.getColour());
1749 }
1750
1751
1752 std::string getEdgeColorAttr(const DisplayNode &From,
1753 const DisplayNode &To) const {
1754 return attribute(From.getEdge(To).getColour());
1755 }
1756
1757
1758 DisplayNode *getEntryNode() const {
1759 assert(NodeGenerationComplete && "Unexpected children iterator creation");
1760 return EntryNode;
1761 }
1762
1763protected:
1764
1765 std::string attribute(StringRef Colour) const {
1766 return "color=" + Colour.str();
1767 }
1768
1769 bool NodeGenerationComplete = false;
1770 const std::string GraphName;
1771 std::vector Nodes;
1772 std::vector<DisplayNode *> NodePtrs;
1773 DisplayNode *EntryNode = nullptr;
1774};
1775
1778 assert(!AllEdgesCreated && "Expected to be able to still create edges.");
1779 Edges.emplace_back(Value.str(), Node, Colour);
1781}
1782
1783void DisplayNode::createEdgeMap() {
1784
1785
1786 AllEdgesCreated = true;
1787 for (auto &E : Edges)
1788 EdgeMap.insert({&E.getDestinationNode(), &E});
1789}
1790
1791class DotCfgDiffNode;
1792class DotCfgDiff;
1793
1794
1795class DotCfgDiffNode {
1796public:
1797 DotCfgDiffNode() = delete;
1798
1799
1800
1803 : Graph(G), N(N), Data{&BD, nullptr}, Colour(Colour) {}
1804 DotCfgDiffNode(const DotCfgDiffNode &DN)
1805 : Graph(DN.Graph), N(DN.N), Data{DN.Data[0], DN.Data[1]},
1806 Colour(DN.Colour), EdgesMap(DN.EdgesMap), Children(DN.Children),
1807 Edges(DN.Edges) {}
1808
1809 unsigned getIndex() const { return N; }
1810
1811
1813 assert(Data[0] && "Expected Data[0] to be set.");
1814 return Data[0]->getLabel();
1815 }
1816
1817 StringRef getColour() const { return Colour; }
1818
1819
1821 assert(!Data[1] && "Expected only one block datum");
1822 Data[1] = &Other;
1824 }
1825
1827
1829 "Unexpected edge count and color.");
1830 EdgesMap[E] = {Value.str(), Colour};
1831 }
1832
1834
1835
1836 StringRef getEdgeColour(const unsigned S) const {
1837 assert(EdgesMap.count(S) == 1 && "Expected to find edge.");
1838 return EdgesMap.at(S).second;
1839 }
1840
1841
1842 std::string getBodyContent() const;
1843
1844 void createDisplayEdges(DotCfgDiffDisplayGraph &Graph, unsigned DisplayNode,
1845 std::map<const unsigned, unsigned> &NodeMap) const;
1846
1847protected:
1848 DotCfgDiff &Graph;
1849 const unsigned N;
1852 std::map<const unsigned, std::pair<std::string, StringRef>> EdgesMap;
1853 std::vector Children;
1854 std::vector Edges;
1855};
1856
1857
1858class DotCfgDiff {
1859public:
1860
1861
1862
1863
1866
1867 DotCfgDiff(const DotCfgDiff &) = delete;
1868 DotCfgDiff &operator=(const DotCfgDiff &) = delete;
1869
1870 DotCfgDiffDisplayGraph createDisplayGraph(StringRef Title,
1872
1873
1874
1875
1876
1877 StringRef getEdgeSourceLabel(const unsigned &Source,
1878 const unsigned &Sink) const {
1879 std::string S =
1880 getNode(Source).getLabel().str() + " " + getNode(Sink).getLabel().str();
1881 assert(EdgeLabels.count(S) == 1 && "Expected to find edge label.");
1882 return EdgeLabels.find(S)->getValue();
1883 }
1884
1885
1886 unsigned size() const { return Nodes.size(); }
1887
1888 const DotCfgDiffNode &getNode(unsigned N) const {
1889 assert(N < Nodes.size() && "Unexpected index for node reference");
1890 return Nodes[N];
1891 }
1892
1893protected:
1894
1895 std::string colourize(std::string S, StringRef Colour) const;
1896
1898 unsigned Pos = Nodes.size();
1899 Nodes.emplace_back(*this, Pos, BD, C);
1900 NodePosition.insert({Label, Pos});
1901 }
1902
1903
1904
1905
1906 std::vector Nodes;
1908 const std::string GraphName;
1909
1911};
1912
1913std::string DotCfgDiffNode::getBodyContent() const {
1915 assert(Data[1] && "Expected Data[1] to be set.");
1916
1918 for (unsigned I = 0; I < 2; ++I) {
1919 SR[I] = Data[I]->getBody();
1920
1922
1923 SR[I] = SR[I].drop_until([](char C) { return C == '\n'; }).drop_front();
1924 }
1925
1927 "<FONT COLOR=\"{0}\">%l<BR align=\"left\"/>", BeforeColour);
1929 "<FONT COLOR=\"{0}\">%l<BR align=\"left\"/>", AfterColour);
1931 "<FONT COLOR=\"{0}\">%l<BR align=\"left\"/>", CommonColour);
1932 std::string Diff = Data[0]->getLabel().str();
1933 Diff += ":\n<BR align=\"left\"/>" +
1934 doSystemDiff(makeHTMLReady(SR[0]), makeHTMLReady(SR[1]),
1935 OldLineFormat, NewLineFormat, UnchangedLineFormat);
1936
1937
1938
1939
1940 Regex R("<FONT COLOR=\"\\w+\">");
1941 while (true) {
1942 std::string Error;
1943 std::string S = R.sub("", Diff, &Error);
1944 if (Error != "")
1946 if (S == Diff)
1947 return Diff;
1948 Diff = S;
1949 }
1951 }
1952
1953
1954 assert([1] && "Data[1] is set unexpectedly.");
1955 std::string Body = makeHTMLReady(Data[0]->getBody());
1958
1959 if (BS.front() == '\n')
1961
1963
1964 BS1 = BS1.drop_until([](char C) { return C == '\n'; }).drop_front();
1965
1966 std::string S = "<FONT COLOR=\"" + Colour.str() + "\">" + Label.str() + ":";
1967
1968
1969 while (BS1.size()) {
1970 S.append("<BR align=\"left\"/>");
1972 S.append(Line.str());
1974 }
1975 S.append("<BR align=\"left\"/>");
1976 return S;
1977}
1978
1979std::string DotCfgDiff::colourize(std::string S, StringRef Colour) const {
1980 if (S.length() == 0)
1981 return S;
1982 return "<FONT COLOR=\"" + Colour.str() + "\">" + S + "";
1983}
1984
1987 : GraphName(Title.str()) {
1989
1990
1991 for (auto &B : Before.getData()) {
1995
1996
1997
2000 Sink != E; ++Sink) {
2001 std::string Key = (Label + " " + Sink->getKey().str()).str() + " " +
2002 BD.getData().getSuccessorLabel(Sink->getKey()).str();
2004 }
2005 }
2006
2007
2008 for (auto &A : After.getData()) {
2011 unsigned C = NodePosition.count(Label);
2012 if (C == 0)
2013
2015 else {
2016 assert(C == 1 && "Unexpected multiple nodes.");
2017 Nodes[NodePosition[Label]].setCommon(BD);
2018 }
2019
2022 Sink != E; ++Sink) {
2023 std::string Key = (Label + " " + Sink->getKey().str()).str() + " " +
2024 BD.getData().getSuccessorLabel(Sink->getKey()).str();
2025 unsigned C = EdgesMap.count(Key);
2026 if (C == 0)
2028 else {
2030 }
2031 }
2032 }
2033
2034
2035 for (auto &E : EdgesMap) {
2036
2038 auto SP1 = S.rsplit(' ');
2039 auto &SourceSink = SP1.first;
2040 auto SP2 = SourceSink.split(' ');
2044
2045 assert(NodePosition.count(Source) == 1 && "Expected to find node.");
2046 DotCfgDiffNode &SourceNode = Nodes[NodePosition[Source]];
2047 assert(NodePosition.count(Sink) == 1 && "Expected to find node.");
2048 unsigned SinkNode = NodePosition[Sink];
2050
2051
2052 auto [It, Inserted] = EdgeLabels.try_emplace(SourceSink);
2053 if (Inserted)
2054 It->getValue() = colourize(Value.str(), Colour);
2055 else {
2057 std::string NV = colourize(V.str() + " " + Value.str(), Colour);
2059 It->getValue() = NV;
2060 }
2061 SourceNode.addEdge(SinkNode, Value, Colour);
2062 }
2063 for (auto &I : Nodes)
2064 I.finalize(*this);
2065}
2066
2067DotCfgDiffDisplayGraph DotCfgDiff::createDisplayGraph(StringRef Title,
2069 assert(NodePosition.count(EntryNodeName) == 1 &&
2070 "Expected to find entry block in map.");
2071 unsigned Entry = NodePosition[EntryNodeName];
2072 assert(Entry < Nodes.size() && "Expected to find entry node");
2073 DotCfgDiffDisplayGraph G(Title.str());
2074
2075 std::map<const unsigned, unsigned> NodeMap;
2076
2077 int EntryIndex = -1;
2078 unsigned Index = 0;
2079 for (auto &I : Nodes) {
2080 if (I.getIndex() == Entry)
2081 EntryIndex = Index;
2082 G.createNode(I.getBodyContent(), I.getColour());
2083 NodeMap.insert({I.getIndex(), Index++});
2084 }
2085 assert(EntryIndex >= 0 && "Expected entry node index to be set.");
2086 G.setEntryNode(EntryIndex);
2087
2088 for (auto &I : NodeMap) {
2089 unsigned SourceNode = I.first;
2090 unsigned DisplayNode = I.second;
2091 getNode(SourceNode).createDisplayEdges(G, DisplayNode, NodeMap);
2092 }
2093 return G;
2094}
2095
2096void DotCfgDiffNode::createDisplayEdges(
2097 DotCfgDiffDisplayGraph &DisplayGraph, unsigned DisplayNodeIndex,
2098 std::map<const unsigned, unsigned> &NodeMap) const {
2099
2100 DisplayNode &SourceDisplayNode = DisplayGraph.getNode(DisplayNodeIndex);
2101
2102 for (auto I : Edges) {
2103 unsigned SinkNodeIndex = I;
2104 StringRef Colour = getEdgeColour(SinkNodeIndex);
2105 const DotCfgDiffNode *SinkNode = &Graph.getNode(SinkNodeIndex);
2106
2107 StringRef Label = Graph.getEdgeSourceLabel(getIndex(), SinkNodeIndex);
2108 DisplayNode &SinkDisplayNode = DisplayGraph.getNode(SinkNode->getIndex());
2109 SourceDisplayNode.createEdge(Label, SinkDisplayNode, Colour);
2110 }
2111 SourceDisplayNode.createEdgeMap();
2112}
2113
2114void DotCfgDiffNode::finalize(DotCfgDiff &G) {
2115 for (auto E : EdgesMap) {
2116 Children.emplace_back(E.first);
2117 Edges.emplace_back(E.first);
2118 }
2119}
2120
2121}
2122
2123namespace llvm {
2124
2125template <> struct GraphTraits<DotCfgDiffDisplayGraph *> {
2131
2133 return G->getEntryNode();
2134 }
2136 return N->children_begin();
2137 }
2140 return G->nodes_begin();
2141 }
2143 return G->nodes_end();
2144 }
2146 return N->edges_begin();
2147 }
2150 static unsigned size(const DotCfgDiffDisplayGraph *G) { return G->size(); }
2151};
2152
2153template <>
2157
2159 static std::string getGraphName(const DotCfgDiffDisplayGraph *DiffData) {
2160 return DiffData->getGraphName();
2161 }
2162 static std::string
2164 return "\tsize=\"190, 190\";\n";
2165 }
2167 const DotCfgDiffDisplayGraph *DiffData) {
2168 return DiffData->getNodeLabel(*Node);
2169 }
2171 const DotCfgDiffDisplayGraph *DiffData) {
2172 return DiffData->getNodeAttributes(*Node);
2173 }
2175 DisplayNode::ChildIterator &To) {
2176 return From->getEdgeSourceLabel(**To);
2177 }
2179 DisplayNode::ChildIterator &To,
2180 const DotCfgDiffDisplayGraph *DiffData) {
2181 return DiffData->getEdgeColorAttr(*From, **To);
2182 }
2183};
2184
2185}
2186
2187namespace {
2188
2189void DotCfgDiffDisplayGraph::generateDotFile(StringRef DotFile) {
2190 std::error_code EC;
2192 if (EC) {
2193 errs() << "Error: " << EC.message() << "\n";
2194 return;
2195 }
2197 OutStream.flush();
2198 OutStream.close();
2199}
2200
2201}
2202
2203namespace llvm {
2204
2206
2207 const Instruction *Term = B.getTerminator();
2208 if (const BranchInst *Br = dyn_cast(Term))
2209 if (Br->isUnconditional())
2211 else {
2212 addSuccessorLabel(Br->getSuccessor(0)->getName().str(), "true");
2213 addSuccessorLabel(Br->getSuccessor(1)->getName().str(), "false");
2214 }
2215 else if (const SwitchInst *Sw = dyn_cast(Term)) {
2216 addSuccessorLabel(Sw->case_default()->getCaseSuccessor()->getName().str(),
2217 "default");
2218 for (auto &C : Sw->cases()) {
2219 assert(C.getCaseValue() && "Expected to find case value.");
2222 }
2223 } else
2226}
2227
2231}
2232
2235
2240 assert(HTML && "Expected outstream to be set");
2243
2244 if (InModule) {
2245 Extender = formatv("{0}_{1}", N, Minor);
2247 } else {
2248 Extender = formatv("{0}", N);
2250 }
2251
2254 std::string DotFile = Twine(SV).str();
2255
2258
2259 Text = formatv("{0}.{1}{2}{3}{4}", Number, Prefix, makeHTMLReady(PassID),
2260 Divider, Name);
2261
2263 std::string EntryBlockName = After.getEntryBlockName();
2264
2265 if (EntryBlockName == "")
2266 EntryBlockName = Before.getEntryBlockName();
2267 assert(EntryBlockName != "" && "Expected to find entry block");
2268
2269 DotCfgDiffDisplayGraph DG = Diff.createDisplayGraph(Text, EntryBlockName);
2270 DG.generateDotFile(DotFile);
2271
2272 *HTML << genHTML(Text, DotFile, PDFFileName);
2274 if (EC)
2275 errs() << "Error: " << EC.message() << "\n";
2276}
2277
2281
2283 if (!DotExe)
2284 return "Unable to find dot executable.";
2285
2288 if (Result < 0)
2289 return "Error executing system dot.";
2290
2291
2293 " <a href=\"{0}\" target=\"_blank\">{1}
\n", PDFFileName, Text);
2294 return S.c_str();
2295}
2296
2298 assert(HTML && "Expected outstream to be set");
2299 *HTML << "<button type=\"button\" class=\"collapsible\">0. "
2300 << "Initial IR (by function)\n"
2301 << "<div class=\"content\">\n"
2302 << "
\n";
2303
2306
2307
2309 .compare(getModuleForComparison(IR),
2310 [&](bool InModule, unsigned Minor,
2315 });
2316 *HTML << "
\n" 2317 << "
\n";
2318 ++N;
2319}
2320
2324}
2325
2327 assert(HTML && "Expected outstream to be set");
2329 formatv(" {0}. Pass {1} on {2} omitted because no change
\n",
2330 N, makeHTMLReady(PassID), Name);
2331 *HTML << Banner;
2332 ++N;
2333}
2334
2338 assert(HTML && "Expected outstream to be set");
2340 .compare(getModuleForComparison(IR),
2341 [&](bool InModule, unsigned Minor,
2346 });
2347 *HTML << "
\n";2348 ++N;
2349}
2350
2352 assert(HTML && "Expected outstream to be set");
2354 formatv(" {0}. {1} invalidated
\n", N, makeHTMLReady(PassID));
2355 *HTML << Banner;
2356 ++N;
2357}
2358
2360 assert(HTML && "Expected outstream to be set");
2362 formatv(" {0}. Pass {1} on {2} filtered out
\n", N,
2363 makeHTMLReady(PassID), Name);
2364 *HTML << Banner;
2365 ++N;
2366}
2367
2369 assert(HTML && "Expected outstream to be set");
2371 makeHTMLReady(PassID), Name);
2372 *HTML << Banner;
2373 ++N;
2374}
2375
2377 std::error_code EC;
2378 HTML = std::make_unique<raw_fd_ostream>(DotCfgDir + "/passes.html", EC);
2379 if (EC) {
2380 HTML = nullptr;
2381 return false;
2382 }
2383
2384 *HTML << ""
2385 << ""
2386 << ""
2387 << ""
2406 << "passes.html"
2407 << "\n"
2408 << "";
2409 return true;
2410}
2411
2414 return;
2416 << ""
2431 << ""
2432 << "\n";
2433 HTML->flush();
2434 HTML->close();
2435}
2436
2444 assert(!OutputDir.empty() && "expected output dir to be non-empty");
2448 return;
2449 }
2450 dbgs() << "Unable to open output stream for -cfg-dot-changed\n";
2451 }
2452}
2453
2457 : PrintPass(DebugLogging, PrintPassOpts), OptNone(DebugLogging),
2467
2469 nullptr;
2470
2473 std::error_code EC;
2475 if (EC)
2478 } else {
2480 }
2481}
2482
2483void PrintCrashIRInstrumentation::SignalHandler(void *) {
2484
2485
2486 if (!CrashReporter)
2487 return;
2488
2490 "Did not expect to get here without option set.");
2492}
2493
2495 if (!CrashReporter)
2496 return;
2497
2499 "Did not expect to get here without option set.");
2500 CrashReporter = nullptr;
2501}
2502
2506 return;
2507
2509 CrashReporter = this;
2510
2515 OS << formatv("*** Dump of {0}IR Before Last Pass {1}",
2518 OS << " Filtered Out ***\n";
2519 return;
2520 }
2521 OS << " Started ***\n";
2523 });
2524}
2525
2535 if (VerifyEach)
2542 if (MAM)
2544
2545
2546
2547
2548
2549
2550
2552}
2553
2556
2563
2564}
static msgpack::DocNode getNode(msgpack::DocNode DN, msgpack::Type Type, MCValue Val)
This file provides Any, a non-template class modeled in the spirit of std::any.
BlockVerifier::State From
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
std::optional< std::vector< StOtherPiece > > Other
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,...
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
static std::string getNodeLabel(const ValueInfo &VI, GlobalValueSummary *GVS)
ppc ctr loops PowerPC CTR Loops Verify
FunctionAnalysisManager FAM
ModuleAnalysisManager MAM
PassInstrumentationCallbacks PIC
This file defines the Pass Instrumentation classes that provide instrumentation points into the pass ...
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
verify safepoint Safepoint IR Verifier
static cl::opt< std::string > BeforeColour("dot-cfg-before-color", cl::desc("Color for dot-cfg before elements"), cl::Hidden, cl::init("red"))
static cl::opt< std::string > IRDumpDirectory("ir-dump-directory", cl::desc("If specified, IR printed using the " "-print-[before|after]{-all} options will be dumped into " "files in this directory rather than written to stderr"), cl::Hidden, cl::value_desc("filename"))
static cl::opt< bool > DroppedVarStats("dropped-variable-stats", cl::Hidden, cl::desc("Dump dropped debug variables stats"), cl::init(false))
static cl::opt< unsigned > PrintAfterPassNumber("print-after-pass-number", cl::init(0), cl::Hidden, cl::desc("Print IR after the pass with this number as " "reported by print-pass-numbers"))
static cl::opt< std::string > OptBisectPrintIRPath("opt-bisect-print-ir-path", cl::desc("Print IR to path when opt-bisect-limit is reached"), cl::Hidden)
static cl::opt< bool > PrintChangedBefore("print-before-changed", cl::desc("Print before passes that change them"), cl::init(false), cl::Hidden)
static cl::opt< std::string > DotCfgDir("dot-cfg-dir", cl::desc("Generate dot files into specified directory for changed IRs"), cl::Hidden, cl::init("./"))
static cl::opt< bool > VerifyAnalysisInvalidation("verify-analysis-invalidation", cl::Hidden, cl::init(false))
static cl::opt< unsigned > PrintBeforePassNumber("print-before-pass-number", cl::init(0), cl::Hidden, cl::desc("Print IR before the pass with this number as " "reported by print-pass-numbers"))
static cl::opt< std::string > CommonColour("dot-cfg-common-color", cl::desc("Color for dot-cfg common elements"), cl::Hidden, cl::init("black"))
static StringRef getFileSuffix(IRDumpFileSuffixType Type)
static SmallString< 32 > getIRFileDisplayName(Any IR)
static SmallVector< Function *, 1 > GetFunctions(Any IR)
static void printBBName(raw_ostream &out, const BasicBlock *BB)
static cl::opt< std::string > DotBinary("print-changed-dot-path", cl::Hidden, cl::init("dot"), cl::desc("system dot used by change reporters"))
static bool shouldGenerateData(const Function &F)
static int prepareDumpIRFileDescriptor(const StringRef DumpIRFilename)
static const IRUnitT * unwrapIR(Any IR)
static cl::opt< std::string > AfterColour("dot-cfg-after-color", cl::desc("Color for dot-cfg after elements"), cl::Hidden, cl::init("forestgreen"))
static cl::opt< bool > PrintOnCrash("print-on-crash", cl::desc("Print the last form of the IR before crash (use -print-on-crash-path to dump to a file)"), cl::Hidden)
static cl::opt< bool > PrintPassNumbers("print-pass-numbers", cl::init(false), cl::Hidden, cl::desc("Print pass names and their ordinals"))
static cl::opt< std::string > PrintOnCrashPath("print-on-crash-path", cl::desc("Print the last form of the IR before crash to a file"), cl::Hidden)
This header defines a class that provides bookkeeping for all standard (i.e in-tree) pass instrumenta...
static const char PassName[]
This templated class represents "all analyses that operate over " (e....
API to communicate dependencies between analyses during invalidation.
A container for analyses that lazily runs them and caches their results.
PassT::Result * getCachedResult(IRUnitT &IR) const
Get the cached result of an analysis pass for a given IR unit.
bool registerPass(PassBuilderT &&PassBuilder)
Register an analysis pass with the manager.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
LLVM Basic Block Representation.
bool isEntryBlock() const
Return true if this is the entry block of the containing function.
const Function * getParent() const
Return the enclosing method, or null if none.
const T & getData() const
Conditional or Unconditional Branch instruction.
Represents analyses that only rely on functions' control flow.
void saveIRBeforePass(Any IR, StringRef PassID, StringRef PassName)
void handleIRAfterPass(Any IR, StringRef PassID, StringRef PassName)
void registerRequiredCallbacks(PassInstrumentationCallbacks &PIC)
void handleInvalidatedPass(StringRef PassID)
virtual ~ChangeReporter()
void addSuccessorLabel(StringRef Succ, StringRef Label)
DCData(const BasicBlock &B)
std::unique_ptr< raw_fd_ostream > HTML
void handleInvalidated(StringRef PassID) override
void generateIRRepresentation(Any IR, StringRef PassID, IRDataT< DCData > &Output) override
static std::string genHTML(StringRef Text, StringRef DotFile, StringRef PDFFileName)
void handleInitialIR(Any IR) 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)
DotCfgChangeReporter(bool Verbose)
void handleIgnored(StringRef PassID, std::string &Name) override
~DotCfgChangeReporter() override
void handleAfter(StringRef PassID, std::string &Name, const IRDataT< DCData > &Before, const IRDataT< DCData > &After, Any) override
void handleFiltered(StringRef PassID, std::string &Name) override
void omitAfter(StringRef PassID, std::string &Name) override
void registerCallbacks(PassInstrumentationCallbacks &PIC)
Represents either an error or a value T.
Lightweight error class with error context and mandatory checking.
bool hasOptNone() const
Do not optimize this function (-O0).
Module * getParent()
Get the module that this global value is contained inside of...
~IRChangedPrinter() override
void handleAfter(StringRef PassID, std::string &Name, const std::string &Before, const std::string &After, Any) override
void registerCallbacks(PassInstrumentationCallbacks &PIC)
void generateIRRepresentation(Any IR, StringRef PassID, std::string &Output) override
void handleIgnored(StringRef PassID, std::string &Name) override
void handleAfter(StringRef PassID, std::string &Name, const std::string &Before, const std::string &After, Any) override
void omitAfter(StringRef PassID, std::string &Name) override
void handleInvalidated(StringRef PassID) override
void handleIR(const std::string &IR, StringRef PassID)
void handleInitialIR(Any IR) override
void registerCallbacks(PassInstrumentationCallbacks &PIC)
void handleFiltered(StringRef PassID, std::string &Name) override
~IRChangedTester() override
static bool generateFunctionData(IRDataT< T > &Data, const FunctionT &F)
static void analyzeIR(Any IR, IRDataT< T > &Data)
void compare(bool CompareModule, std::function< void(bool InModule, unsigned Minor, const FuncDataT< T > &Before, const FuncDataT< T > &After)> CompareFunc)
void registerCallbacks(PassInstrumentationCallbacks &PIC)
~InLineChangePrinter() override
void handleAfter(StringRef PassID, std::string &Name, const IRDataT< EmptyData > &Before, const IRDataT< EmptyData > &After, Any) override
void generateIRRepresentation(Any IR, StringRef PassID, IRDataT< EmptyData > &Output) override
void handleFunctionCompare(StringRef Name, StringRef Prefix, StringRef PassID, StringRef Divider, bool InModule, unsigned Minor, const FuncDataT< EmptyData > &Before, const FuncDataT< EmptyData > &After)
An analysis over an "outer" IR unit that provides access to an analysis manager over an "inner" IR un...
This is an important class for using LLVM in a threaded context.
OptPassGate & getOptPassGate() const
Access the object which can disable optional passes and individual optimizations at compile time.
A node in the call graph.
An SCC of the call graph.
Represents a single loop in the control flow graph.
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.
A Module instance is used to store all the information related to an LLVM module.
void registerCallbacks(PassInstrumentationCallbacks &PIC)
void registerCallbacks(PassInstrumentationCallbacks &PIC)
bool shouldRun(StringRef PassName, Any IR)
Extensions to this class implement mechanisms to disable passes and individual optimizations at compi...
virtual bool isEnabled() const
isEnabled() should return true before calling shouldRunPass().
virtual bool shouldRunPass(const StringRef PassName, StringRef IRDescription)
IRDescription is a textual description of the IR unit the pass is running over.
static void report(const OrderedChangedData &Before, const OrderedChangedData &After, function_ref< void(const T *, const T *)> HandlePair)
StringMap< T > & getData()
std::vector< std::string > & getOrder()
Pass interface - Implemented by all 'passes'.
A set of analyses that are preserved following a run of a transformation pass.
PreservedAnalysisChecker getChecker() const
Build a checker for this PreservedAnalyses and the specified analysis type.
void registerCallbacks(PassInstrumentationCallbacks &PIC, ModuleAnalysisManager &MAM)
~PrintCrashIRInstrumentation()
void registerCallbacks(PassInstrumentationCallbacks &PIC)
~PrintIRInstrumentation()
void registerCallbacks(PassInstrumentationCallbacks &PIC)
void registerCallbacks(PassInstrumentationCallbacks &PIC)
void registerCallbacks(PassInstrumentationCallbacks &PIC)
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
void registerCallbacks(PassInstrumentationCallbacks &PIC, ModuleAnalysisManager *MAM=nullptr)
StandardInstrumentations(LLVMContext &Context, bool DebugLogging, bool VerifyEach=false, PrintPassOptions PrintPassOpts=PrintPassOptions())
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
size_type count(StringRef Key) const
count - Return 1 if the element is in the map, 0 otherwise.
bool insert(MapEntryTy *KeyValue)
insert - Insert the specified key/value pair into the map.
StringRef - Represent a constant reference to a string, i.e.
std::string str() const
str - Get the contents as an std::string.
constexpr bool empty() const
empty - Check if the string is empty.
StringRef drop_front(size_t N=1) const
Return a StringRef equal to 'this' but with the first N elements dropped.
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...
constexpr size_t size() const
size - Get the string size.
char front() const
front - Get the first character in the string.
bool consume_front(StringRef Prefix)
Returns true if this StringRef has the given prefix and removes that prefix.
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...
std::pair< StringRef, StringRef > rsplit(StringRef Separator) const
Split into two substrings around the last occurrence of a separator string.
void handleInitialIR(Any IR) override
void handleInvalidated(StringRef PassID) override
TextChangeReporter(bool Verbose)
void omitAfter(StringRef PassID, std::string &Name) override
void handleIgnored(StringRef PassID, std::string &Name) override
void handleFiltered(StringRef PassID, std::string &Name) override
void registerCallbacks(PassInstrumentationCallbacks &PIC)
void registerCallbacks(PassInstrumentationCallbacks &PIC)
TimeProfilingPassesHandler()
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
std::string str() const
Return the twine contents as a std::string.
The instances of the Type class are immutable: once they are created, they are never changed.
LLVM Value Representation.
StringRef getName() const
Return a constant reference to the value's name.
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.
raw_ostream & indent(unsigned NumSpaces)
indent - Insert 'NumSpaces' spaces.
A raw_ostream that writes to an std::string.
A raw_ostream that writes to an SmallVector or SmallString.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ C
The default llvm calling convention, compatible with C.
initializer< Ty > init(const Ty &Val)
DiagnosticInfoOptimizationBase::Argument NV
void make_absolute(const Twine ¤t_directory, SmallVectorImpl< char > &path)
Make path an absolute path.
std::error_code openFile(const Twine &Name, int &ResultFD, CreationDisposition Disp, FileAccess Access, OpenFlags Flags, unsigned Mode=0666)
Opens a file with the specified creation disposition, access mode, and flags and returns a file descr...
void expand_tilde(const Twine &path, SmallVectorImpl< char > &output)
Expands ~ expressions to the user's home directory.
@ OF_Text
The file should be opened in text mode on platforms like z/OS that make this distinction.
std::error_code remove(const Twine &path, bool IgnoreNonExisting=true)
Remove path.
@ CD_OpenAlways
CD_OpenAlways - When opening a file:
void createUniquePath(const Twine &Model, SmallVectorImpl< char > &ResultPath, bool MakeAbsolute)
Create a potentially unique file name but does not create it.
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.
StringRef parent_path(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Get parent path.
void append(SmallVectorImpl< char > &path, const Twine &a, const Twine &b="", const Twine &c="", const Twine &d="")
Append to path.
void AddSignalHandler(SignalHandlerCallback FnPtr, void *Cookie)
Add a function to be called when an abort/kill signal is delivered to the process.
int ExecuteAndWait(StringRef Program, ArrayRef< StringRef > Args, std::optional< ArrayRef< StringRef > > Env=std::nullopt, ArrayRef< std::optional< StringRef > > Redirects={}, unsigned SecondsToWait=0, unsigned MemoryLimit=0, std::string *ErrMsg=nullptr, bool *ExecutionFailed=nullptr, std::optional< ProcessStatistics > *ProcStat=nullptr, BitVector *AffinityMask=nullptr)
This function executes the program using the arguments provided.
ErrorOr< std::string > findProgramByName(StringRef Name, ArrayRef< StringRef > Paths={})
Find the first executable file Name in Paths.
This is an optimization pass for GlobalISel generic memory operations.
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.
bool forcePrintModuleIR()
std::vector< std::string > printAfterPasses()
uint64_t xxh3_64bits(ArrayRef< uint8_t > data)
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)
bool DisplayGraph(StringRef Filename, bool wait=true, GraphProgram::Name program=GraphProgram::DOT)
bool shouldPrintBeforeAll()
raw_ostream & WriteGraph(raw_ostream &O, const GraphType &G, bool ShortNames=false, const Twine &Title="")
bool shouldPrintAfterAll()
cl::opt< ChangePrinter > PrintChanged
TimeTraceProfiler * getTimeTraceProfilerInstance()
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
std::vector< std::string > printBeforePasses()
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)
bool shouldPrintAfterSomePass()
void verifyMachineFunction(const std::string &Banner, const MachineFunction &MF)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
bool isFunctionInPrintList(StringRef FunctionName)
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
bool isPassInPrintList(StringRef PassName)
bool isSpecialPass(StringRef PassID, const std::vector< StringRef > &Specials)
void timeTraceProfilerEnd()
Manually end the last time section.
std::error_code cleanUpTempFiles(ArrayRef< std::string > FileName)
raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
void write_hex(raw_ostream &S, uint64_t N, HexPrintStyle Style, std::optional< size_t > Width=std::nullopt)
std::string doSystemDiff(StringRef Before, StringRef After, StringRef OldLineFormat, StringRef NewLineFormat, StringRef UnchangedLineFormat)
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
std::array< uint32_t, 5 > ModuleHash
160 bits SHA1
stable_hash StructuralHash(const Function &F, bool DetailedHash=false)
Returns a hash of the function F.
void printLoop(Loop &L, raw_ostream &OS, const std::string &Banner="")
Function to print a loop's contents as LLVM's text IR assembly.
bool verifyModule(const Module &M, raw_ostream *OS=nullptr, bool *BrokenDebugInfo=nullptr)
Check a module for errors.
TimeTraceProfilerEntry * timeTraceProfilerBegin(StringRef Name, StringRef Detail)
Manually begin a time section, with the given Name and Detail.
Result run(Function &F, FunctionAnalysisManager &FAM)
Run the analysis pass over a function and produce CFG.
Result run(Function &F, FunctionAnalysisManager &FAM)
Result run(Module &F, ModuleAnalysisManager &FAM)
A CRTP mix-in that provides informational APIs needed for analysis passes.
A special type used by analysis passes to provide an address that identifies that particular analysis...
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 bool renderNodesUsingHTML()
static std::string getGraphProperties(const DotCfgDiffDisplayGraph *DiffData)
DOTGraphTraits(bool Simple=false)
DOTGraphTraits - Template class that can be specialized to customize how graphs are converted to 'dot...
DefaultDOTGraphTraits - This class provides the default implementations of all of the DOTGraphTraits ...
static ChildEdgeIterator child_edge_end(NodeRef N)
static unsigned size(const DotCfgDiffDisplayGraph *G)
static NodeRef getEntryNode(const DotCfgDiffDisplayGraph *G)
DisplayNode::EdgeIterator ChildEdgeIterator
static ChildIteratorType child_begin(NodeRef N)
const DisplayEdge * EdgeRef
static ChildIteratorType child_end(NodeRef N)
const DisplayNode * NodeRef
static NodeRef edge_dest(EdgeRef E)
DotCfgDiffDisplayGraph::NodeIterator nodes_iterator
DisplayNode::ChildIterator ChildIteratorType
static nodes_iterator nodes_begin(const DotCfgDiffDisplayGraph *G)
static ChildEdgeIterator child_edge_begin(NodeRef N)
static nodes_iterator nodes_end(const DotCfgDiffDisplayGraph *G)
This class manages callbacks registration, as well as provides a way for PassInstrumentation to pass ...
void registerAnalysesClearedCallback(CallableT C)
void registerBeforeAnalysisCallback(CallableT C)
void registerAfterPassInvalidatedCallback(CallableT C, bool ToFront=false)
void registerAnalysisInvalidatedCallback(CallableT C)
StringRef getPassNameForClassName(StringRef ClassName)
Get the pass name for a given pass class name.
void registerAfterAnalysisCallback(CallableT C, bool ToFront=false)
void registerBeforeNonSkippedPassCallback(CallableT C)
void registerBeforeSkippedPassCallback(CallableT C)
void registerShouldRunOptionalPassCallback(CallableT C)
void registerAfterPassCallback(CallableT C, bool ToFront=false)
std::optional< DenseMap< intptr_t, BBGuard > > BBGuards
static void printDiff(raw_ostream &out, const CFG &Before, const CFG &After)
CFG(const Function *F, bool TrackBBLifetime)
bool invalidate(Function &F, const PreservedAnalyses &PA, FunctionAnalysisManager::Invalidator &)
DenseMap< const BasicBlock *, DenseMap< const BasicBlock *, unsigned > > Graph
bool SkipAnalyses
Don't print information for analyses.
bool Verbose
Print adaptors and pass managers.
bool Indent
Indent based on hierarchy.