10b57cec5SDimitry Andric //===- Standard pass instrumentations handling ----------------*- C++ -*--===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric /// \file
90b57cec5SDimitry Andric ///
100b57cec5SDimitry Andric /// This file defines IR-printing pass instrumentation callbacks as well as
110b57cec5SDimitry Andric /// StandardInstrumentations class that manages standard pass instrumentations.
120b57cec5SDimitry Andric ///
130b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
140b57cec5SDimitry Andric 
150b57cec5SDimitry Andric #include "llvm/Passes/StandardInstrumentations.h"
16e8d8bef9SDimitry Andric #include "llvm/ADT/Any.h"
175f757f3fSDimitry Andric #include "llvm/ADT/StableHashing.h"
18e8d8bef9SDimitry Andric #include "llvm/ADT/StringRef.h"
190b57cec5SDimitry Andric #include "llvm/Analysis/CallGraphSCCPass.h"
200b57cec5SDimitry Andric #include "llvm/Analysis/LazyCallGraph.h"
210b57cec5SDimitry Andric #include "llvm/Analysis/LoopInfo.h"
225f757f3fSDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
2381ad6265SDimitry Andric #include "llvm/IR/Constants.h"
240b57cec5SDimitry Andric #include "llvm/IR/Function.h"
250b57cec5SDimitry Andric #include "llvm/IR/Module.h"
260b57cec5SDimitry Andric #include "llvm/IR/PassInstrumentation.h"
27fe6060f1SDimitry Andric #include "llvm/IR/PassManager.h"
28e8d8bef9SDimitry Andric #include "llvm/IR/PrintPasses.h"
2906c3fb27SDimitry Andric #include "llvm/IR/StructuralHash.h"
30e8d8bef9SDimitry Andric #include "llvm/IR/Verifier.h"
31e8d8bef9SDimitry Andric #include "llvm/Support/CommandLine.h"
3281ad6265SDimitry Andric #include "llvm/Support/CrashRecoveryContext.h"
330b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
34bdd1243dSDimitry Andric #include "llvm/Support/Error.h"
350b57cec5SDimitry Andric #include "llvm/Support/FormatVariadic.h"
36349cc55cSDimitry Andric #include "llvm/Support/GraphWriter.h"
37fe6060f1SDimitry Andric #include "llvm/Support/MemoryBuffer.h"
385f757f3fSDimitry Andric #include "llvm/Support/Path.h"
39fe6060f1SDimitry Andric #include "llvm/Support/Program.h"
40349cc55cSDimitry Andric #include "llvm/Support/Regex.h"
4181ad6265SDimitry Andric #include "llvm/Support/Signals.h"
420b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
43349cc55cSDimitry Andric #include <unordered_map>
44e8d8bef9SDimitry Andric #include <unordered_set>
45349cc55cSDimitry Andric #include <utility>
46e8d8bef9SDimitry Andric #include <vector>
470b57cec5SDimitry Andric 
480b57cec5SDimitry Andric using namespace llvm;
490b57cec5SDimitry Andric 
5006c3fb27SDimitry Andric static cl::opt<bool> VerifyAnalysisInvalidation("verify-analysis-invalidation",
5106c3fb27SDimitry Andric                                                 cl::Hidden,
5206c3fb27SDimitry Andric #ifdef EXPENSIVE_CHECKS
53349cc55cSDimitry Andric                                                 cl::init(true)
5406c3fb27SDimitry Andric #else
5506c3fb27SDimitry Andric                                                 cl::init(false)
56e8d8bef9SDimitry Andric #endif
57349cc55cSDimitry Andric );
58e8d8bef9SDimitry Andric 
59e8d8bef9SDimitry Andric // An option that supports the -print-changed option.  See
60e8d8bef9SDimitry Andric // the description for -print-changed for an explanation of the use
61e8d8bef9SDimitry Andric // of this option.  Note that this option has no effect without -print-changed.
62e8d8bef9SDimitry Andric static cl::opt<bool>
63e8d8bef9SDimitry Andric     PrintChangedBefore("print-before-changed",
64e8d8bef9SDimitry Andric                        cl::desc("Print before passes that change them"),
65e8d8bef9SDimitry Andric                        cl::init(false), cl::Hidden);
66e8d8bef9SDimitry Andric 
67349cc55cSDimitry Andric // An option for specifying the dot used by
68349cc55cSDimitry Andric // print-changed=[dot-cfg | dot-cfg-quiet]
69349cc55cSDimitry Andric static cl::opt<std::string>
70349cc55cSDimitry Andric     DotBinary("print-changed-dot-path", cl::Hidden, cl::init("dot"),
71349cc55cSDimitry Andric               cl::desc("system dot used by change reporters"));
72349cc55cSDimitry Andric 
73349cc55cSDimitry Andric // An option that determines the colour used for elements that are only
74349cc55cSDimitry Andric // in the before part.  Must be a colour named in appendix J of
75349cc55cSDimitry Andric // https://graphviz.org/pdf/dotguide.pdf
76bdd1243dSDimitry Andric static cl::opt<std::string>
77349cc55cSDimitry Andric     BeforeColour("dot-cfg-before-color",
78bdd1243dSDimitry Andric                  cl::desc("Color for dot-cfg before elements"), cl::Hidden,
79349cc55cSDimitry Andric                  cl::init("red"));
80349cc55cSDimitry Andric // An option that determines the colour used for elements that are only
81349cc55cSDimitry Andric // in the after part.  Must be a colour named in appendix J of
82349cc55cSDimitry Andric // https://graphviz.org/pdf/dotguide.pdf
83bdd1243dSDimitry Andric static cl::opt<std::string>
84bdd1243dSDimitry Andric     AfterColour("dot-cfg-after-color",
85bdd1243dSDimitry Andric                 cl::desc("Color for dot-cfg after elements"), cl::Hidden,
86bdd1243dSDimitry Andric                 cl::init("forestgreen"));
87349cc55cSDimitry Andric // An option that determines the colour used for elements that are in both
88349cc55cSDimitry Andric // the before and after parts.  Must be a colour named in appendix J of
89349cc55cSDimitry Andric // https://graphviz.org/pdf/dotguide.pdf
90bdd1243dSDimitry Andric static cl::opt<std::string>
91349cc55cSDimitry Andric     CommonColour("dot-cfg-common-color",
92bdd1243dSDimitry Andric                  cl::desc("Color for dot-cfg common elements"), cl::Hidden,
93349cc55cSDimitry Andric                  cl::init("black"));
94349cc55cSDimitry Andric 
95349cc55cSDimitry Andric // An option that determines where the generated website file (named
96349cc55cSDimitry Andric // passes.html) and the associated pdf files (named diff_*.pdf) are saved.
97349cc55cSDimitry Andric static cl::opt<std::string> DotCfgDir(
98349cc55cSDimitry Andric     "dot-cfg-dir",
99349cc55cSDimitry Andric     cl::desc("Generate dot files into specified directory for changed IRs"),
100349cc55cSDimitry Andric     cl::Hidden, cl::init("./"));
101349cc55cSDimitry Andric 
10206c3fb27SDimitry Andric // Options to print the IR that was being processed when a pass crashes.
10306c3fb27SDimitry Andric static cl::opt<std::string> PrintOnCrashPath(
10406c3fb27SDimitry Andric     "print-on-crash-path",
10506c3fb27SDimitry Andric     cl::desc("Print the last form of the IR before crash to a file"),
10606c3fb27SDimitry Andric     cl::Hidden);
10706c3fb27SDimitry Andric 
10806c3fb27SDimitry Andric static cl::opt<bool> PrintOnCrash(
10906c3fb27SDimitry Andric     "print-on-crash",
11006c3fb27SDimitry Andric     cl::desc("Print the last form of the IR before crash (use -print-on-crash-path to dump to a file)"),
111bdd1243dSDimitry Andric     cl::Hidden);
112bdd1243dSDimitry Andric 
113bdd1243dSDimitry Andric static cl::opt<std::string> OptBisectPrintIRPath(
114bdd1243dSDimitry Andric     "opt-bisect-print-ir-path",
115bdd1243dSDimitry Andric     cl::desc("Print IR to path when opt-bisect-limit is reached"), cl::Hidden);
11681ad6265SDimitry Andric 
11706c3fb27SDimitry Andric static cl::opt<bool> PrintPassNumbers(
11806c3fb27SDimitry Andric     "print-pass-numbers", cl::init(false), cl::Hidden,
11906c3fb27SDimitry Andric     cl::desc("Print pass names and their ordinals"));
12006c3fb27SDimitry Andric 
1211db9f3b2SDimitry Andric static cl::opt<unsigned> PrintBeforePassNumber(
1221db9f3b2SDimitry Andric     "print-before-pass-number", cl::init(0), cl::Hidden,
1231db9f3b2SDimitry Andric     cl::desc("Print IR before the pass with this number as "
1241db9f3b2SDimitry Andric              "reported by print-pass-numbers"));
12506c3fb27SDimitry Andric 
1265f757f3fSDimitry Andric static cl::opt<std::string> IRDumpDirectory(
1275f757f3fSDimitry Andric     "ir-dump-directory",
1285f757f3fSDimitry Andric     cl::desc("If specified, IR printed using the "
1295f757f3fSDimitry Andric              "-print-[before|after]{-all} options will be dumped into "
1305f757f3fSDimitry Andric              "files in this directory rather than written to stderr"),
1315f757f3fSDimitry Andric     cl::Hidden, cl::value_desc("filename"));
1325f757f3fSDimitry Andric 
unwrapIR(Any IR)1335f757f3fSDimitry Andric template <typename IRUnitT> static const IRUnitT *unwrapIR(Any IR) {
1345f757f3fSDimitry Andric   const IRUnitT **IRPtr = llvm::any_cast<const IRUnitT *>(&IR);
1355f757f3fSDimitry Andric   return IRPtr ? *IRPtr : nullptr;
1365f757f3fSDimitry Andric }
1375f757f3fSDimitry Andric 
1380b57cec5SDimitry Andric namespace {
1390b57cec5SDimitry Andric 
140bdd1243dSDimitry Andric // An option for specifying an executable that will be called with the IR
141bdd1243dSDimitry Andric // everytime it changes in the opt pipeline.  It will also be called on
142bdd1243dSDimitry Andric // the initial IR as it enters the pipeline.  The executable will be passed
143bdd1243dSDimitry Andric // the name of a temporary file containing the IR and the PassID.  This may
144bdd1243dSDimitry Andric // be used, for example, to call llc on the IR and run a test to determine
145bdd1243dSDimitry Andric // which pass makes a change that changes the functioning of the IR.
146bdd1243dSDimitry Andric // The usual modifier options work as expected.
147bdd1243dSDimitry Andric static cl::opt<std::string>
148bdd1243dSDimitry Andric     TestChanged("exec-on-ir-change", cl::Hidden, cl::init(""),
149bdd1243dSDimitry Andric                 cl::desc("exe called with module IR after each pass that "
150bdd1243dSDimitry Andric                          "changes it"));
151fe6060f1SDimitry Andric 
152fe6060f1SDimitry Andric /// Extract Module out of \p IR unit. May return nullptr if \p IR does not match
153fe6060f1SDimitry Andric /// certain global filters. Will never return nullptr if \p Force is true.
unwrapModule(Any IR,bool Force=false)154fe6060f1SDimitry Andric const Module *unwrapModule(Any IR, bool Force = false) {
1555f757f3fSDimitry Andric   if (const auto *M = unwrapIR<Module>(IR))
1565f757f3fSDimitry Andric     return M;
1570b57cec5SDimitry Andric 
1585f757f3fSDimitry Andric   if (const auto *F = unwrapIR<Function>(IR)) {
1595f757f3fSDimitry Andric     if (!Force && !isFunctionInPrintList(F->getName()))
160fe6060f1SDimitry Andric       return nullptr;
161e8d8bef9SDimitry Andric 
1625f757f3fSDimitry Andric     return F->getParent();
1630b57cec5SDimitry Andric   }
1640b57cec5SDimitry Andric 
1655f757f3fSDimitry Andric   if (const auto *C = unwrapIR<LazyCallGraph::SCC>(IR)) {
1665f757f3fSDimitry Andric     for (const LazyCallGraph::Node &N : *C) {
1670b57cec5SDimitry Andric       const Function &F = N.getFunction();
168e8d8bef9SDimitry Andric       if (Force || (!F.isDeclaration() && isFunctionInPrintList(F.getName()))) {
169fe6060f1SDimitry Andric         return F.getParent();
1700b57cec5SDimitry Andric       }
1710b57cec5SDimitry Andric     }
172fe6060f1SDimitry Andric     assert(!Force && "Expected a module");
173fe6060f1SDimitry Andric     return nullptr;
1740b57cec5SDimitry Andric   }
1750b57cec5SDimitry Andric 
1765f757f3fSDimitry Andric   if (const auto *L = unwrapIR<Loop>(IR)) {
1775f757f3fSDimitry Andric     const Function *F = L->getHeader()->getParent();
178e8d8bef9SDimitry Andric     if (!Force && !isFunctionInPrintList(F->getName()))
179fe6060f1SDimitry Andric       return nullptr;
180fe6060f1SDimitry Andric     return F->getParent();
1810b57cec5SDimitry Andric   }
1820b57cec5SDimitry Andric 
1830b57cec5SDimitry Andric   llvm_unreachable("Unknown IR unit");
1840b57cec5SDimitry Andric }
1850b57cec5SDimitry Andric 
printIR(raw_ostream & OS,const Function * F)186fe6060f1SDimitry Andric void printIR(raw_ostream &OS, const Function *F) {
187e8d8bef9SDimitry Andric   if (!isFunctionInPrintList(F->getName()))
188e8d8bef9SDimitry Andric     return;
189fe6060f1SDimitry Andric   OS << *F;
190e8d8bef9SDimitry Andric }
191e8d8bef9SDimitry Andric 
printIR(raw_ostream & OS,const Module * M)192349cc55cSDimitry Andric void printIR(raw_ostream &OS, const Module *M) {
193e8d8bef9SDimitry Andric   if (isFunctionInPrintList("*") || forcePrintModuleIR()) {
194349cc55cSDimitry Andric     M->print(OS, nullptr);
1955ffd83dbSDimitry Andric   } else {
1965ffd83dbSDimitry Andric     for (const auto &F : M->functions()) {
197fe6060f1SDimitry Andric       printIR(OS, &F);
1985ffd83dbSDimitry Andric     }
1995ffd83dbSDimitry Andric   }
2005ffd83dbSDimitry Andric }
2015ffd83dbSDimitry Andric 
printIR(raw_ostream & OS,const LazyCallGraph::SCC * C)202fe6060f1SDimitry Andric void printIR(raw_ostream &OS, const LazyCallGraph::SCC *C) {
2030b57cec5SDimitry Andric   for (const LazyCallGraph::Node &N : *C) {
2040b57cec5SDimitry Andric     const Function &F = N.getFunction();
205e8d8bef9SDimitry Andric     if (!F.isDeclaration() && isFunctionInPrintList(F.getName())) {
206e8d8bef9SDimitry Andric       F.print(OS);
2070b57cec5SDimitry Andric     }
2080b57cec5SDimitry Andric   }
2090b57cec5SDimitry Andric }
210e8d8bef9SDimitry Andric 
printIR(raw_ostream & OS,const Loop * L)211fe6060f1SDimitry Andric void printIR(raw_ostream &OS, const Loop *L) {
212e8d8bef9SDimitry Andric   const Function *F = L->getHeader()->getParent();
213e8d8bef9SDimitry Andric   if (!isFunctionInPrintList(F->getName()))
214e8d8bef9SDimitry Andric     return;
215fe6060f1SDimitry Andric   printLoop(const_cast<Loop &>(*L), OS);
216fe6060f1SDimitry Andric }
217fe6060f1SDimitry Andric 
getIRName(Any IR)218fe6060f1SDimitry Andric std::string getIRName(Any IR) {
2195f757f3fSDimitry Andric   if (unwrapIR<Module>(IR))
220fe6060f1SDimitry Andric     return "[module]";
221fe6060f1SDimitry Andric 
2225f757f3fSDimitry Andric   if (const auto *F = unwrapIR<Function>(IR))
2235f757f3fSDimitry Andric     return F->getName().str();
224fe6060f1SDimitry Andric 
2255f757f3fSDimitry Andric   if (const auto *C = unwrapIR<LazyCallGraph::SCC>(IR))
2265f757f3fSDimitry Andric     return C->getName();
227fe6060f1SDimitry Andric 
2285f757f3fSDimitry Andric   if (const auto *L = unwrapIR<Loop>(IR))
2295f757f3fSDimitry Andric     return L->getName().str();
2305f757f3fSDimitry Andric 
2315f757f3fSDimitry Andric   if (const auto *MF = unwrapIR<MachineFunction>(IR))
2325f757f3fSDimitry Andric     return MF->getName().str();
233fe6060f1SDimitry Andric 
234fe6060f1SDimitry Andric   llvm_unreachable("Unknown wrapped IR type");
235fe6060f1SDimitry Andric }
236fe6060f1SDimitry Andric 
moduleContainsFilterPrintFunc(const Module & M)237fe6060f1SDimitry Andric bool moduleContainsFilterPrintFunc(const Module &M) {
238fe6060f1SDimitry Andric   return any_of(M.functions(),
239fe6060f1SDimitry Andric                 [](const Function &F) {
240fe6060f1SDimitry Andric                   return isFunctionInPrintList(F.getName());
241fe6060f1SDimitry Andric                 }) ||
242fe6060f1SDimitry Andric          isFunctionInPrintList("*");
243fe6060f1SDimitry Andric }
244fe6060f1SDimitry Andric 
sccContainsFilterPrintFunc(const LazyCallGraph::SCC & C)245fe6060f1SDimitry Andric bool sccContainsFilterPrintFunc(const LazyCallGraph::SCC &C) {
246fe6060f1SDimitry Andric   return any_of(C,
247fe6060f1SDimitry Andric                 [](const LazyCallGraph::Node &N) {
248fe6060f1SDimitry Andric                   return isFunctionInPrintList(N.getName());
249fe6060f1SDimitry Andric                 }) ||
250fe6060f1SDimitry Andric          isFunctionInPrintList("*");
251fe6060f1SDimitry Andric }
252fe6060f1SDimitry Andric 
shouldPrintIR(Any IR)253fe6060f1SDimitry Andric bool shouldPrintIR(Any IR) {
2545f757f3fSDimitry Andric   if (const auto *M = unwrapIR<Module>(IR))
2555f757f3fSDimitry Andric     return moduleContainsFilterPrintFunc(*M);
256fe6060f1SDimitry Andric 
2575f757f3fSDimitry Andric   if (const auto *F = unwrapIR<Function>(IR))
2585f757f3fSDimitry Andric     return isFunctionInPrintList(F->getName());
259fe6060f1SDimitry Andric 
2605f757f3fSDimitry Andric   if (const auto *C = unwrapIR<LazyCallGraph::SCC>(IR))
2615f757f3fSDimitry Andric     return sccContainsFilterPrintFunc(*C);
262fe6060f1SDimitry Andric 
2635f757f3fSDimitry Andric   if (const auto *L = unwrapIR<Loop>(IR))
2645f757f3fSDimitry Andric     return isFunctionInPrintList(L->getHeader()->getParent()->getName());
265fe6060f1SDimitry Andric   llvm_unreachable("Unknown wrapped IR type");
2660b57cec5SDimitry Andric }
2670b57cec5SDimitry Andric 
2680b57cec5SDimitry Andric /// Generic IR-printing helper that unpacks a pointer to IRUnit wrapped into
269bdd1243dSDimitry Andric /// Any and does actual print job.
unwrapAndPrint(raw_ostream & OS,Any IR)270349cc55cSDimitry Andric void unwrapAndPrint(raw_ostream &OS, Any IR) {
271fe6060f1SDimitry Andric   if (!shouldPrintIR(IR))
272fe6060f1SDimitry Andric     return;
273fe6060f1SDimitry Andric 
274fe6060f1SDimitry Andric   if (forcePrintModuleIR()) {
275fe6060f1SDimitry Andric     auto *M = unwrapModule(IR);
276fe6060f1SDimitry Andric     assert(M && "should have unwrapped module");
277349cc55cSDimitry Andric     printIR(OS, M);
2780b57cec5SDimitry Andric     return;
2790b57cec5SDimitry Andric   }
2800b57cec5SDimitry Andric 
2815f757f3fSDimitry Andric   if (const auto *M = unwrapIR<Module>(IR)) {
2825f757f3fSDimitry Andric     printIR(OS, M);
2830b57cec5SDimitry Andric     return;
2840b57cec5SDimitry Andric   }
2850b57cec5SDimitry Andric 
2865f757f3fSDimitry Andric   if (const auto *F = unwrapIR<Function>(IR)) {
2875f757f3fSDimitry Andric     printIR(OS, F);
2880b57cec5SDimitry Andric     return;
2890b57cec5SDimitry Andric   }
2900b57cec5SDimitry Andric 
2915f757f3fSDimitry Andric   if (const auto *C = unwrapIR<LazyCallGraph::SCC>(IR)) {
2925f757f3fSDimitry Andric     printIR(OS, C);
2930b57cec5SDimitry Andric     return;
2940b57cec5SDimitry Andric   }
2950b57cec5SDimitry Andric 
2965f757f3fSDimitry Andric   if (const auto *L = unwrapIR<Loop>(IR)) {
2975f757f3fSDimitry Andric     printIR(OS, L);
2980b57cec5SDimitry Andric     return;
2990b57cec5SDimitry Andric   }
3000b57cec5SDimitry Andric   llvm_unreachable("Unknown wrapped IR type");
3010b57cec5SDimitry Andric }
3020b57cec5SDimitry Andric 
303e8d8bef9SDimitry Andric // Return true when this is a pass for which changes should be ignored
isIgnored(StringRef PassID)304e8d8bef9SDimitry Andric bool isIgnored(StringRef PassID) {
305e8d8bef9SDimitry Andric   return isSpecialPass(PassID,
306fe6060f1SDimitry Andric                        {"PassManager", "PassAdaptor", "AnalysisManagerProxy",
3075f757f3fSDimitry Andric                         "DevirtSCCRepeatedPass", "ModuleInlinerWrapperPass",
3085f757f3fSDimitry Andric                         "VerifierPass", "PrintModulePass"});
309e8d8bef9SDimitry Andric }
310e8d8bef9SDimitry Andric 
makeHTMLReady(StringRef SR)311349cc55cSDimitry Andric std::string makeHTMLReady(StringRef SR) {
312349cc55cSDimitry Andric   std::string S;
313349cc55cSDimitry Andric   while (true) {
314349cc55cSDimitry Andric     StringRef Clean =
315349cc55cSDimitry Andric         SR.take_until([](char C) { return C == '<' || C == '>'; });
316349cc55cSDimitry Andric     S.append(Clean.str());
317349cc55cSDimitry Andric     SR = SR.drop_front(Clean.size());
318349cc55cSDimitry Andric     if (SR.size() == 0)
319349cc55cSDimitry Andric       return S;
320349cc55cSDimitry Andric     S.append(SR[0] == '<' ? "&lt;" : "&gt;");
321349cc55cSDimitry Andric     SR = SR.drop_front();
322349cc55cSDimitry Andric   }
323349cc55cSDimitry Andric   llvm_unreachable("problems converting string to HTML");
324349cc55cSDimitry Andric }
325349cc55cSDimitry Andric 
326349cc55cSDimitry Andric // Return the module when that is the appropriate level of comparison for \p IR.
getModuleForComparison(Any IR)327349cc55cSDimitry Andric const Module *getModuleForComparison(Any IR) {
3285f757f3fSDimitry Andric   if (const auto *M = unwrapIR<Module>(IR))
3295f757f3fSDimitry Andric     return M;
3305f757f3fSDimitry Andric   if (const auto *C = unwrapIR<LazyCallGraph::SCC>(IR))
3315f757f3fSDimitry Andric     return C->begin()->getFunction().getParent();
332349cc55cSDimitry Andric   return nullptr;
333349cc55cSDimitry Andric }
334349cc55cSDimitry Andric 
isInterestingFunction(const Function & F)33581ad6265SDimitry Andric bool isInterestingFunction(const Function &F) {
336e8d8bef9SDimitry Andric   return isFunctionInPrintList(F.getName());
337e8d8bef9SDimitry Andric }
338e8d8bef9SDimitry Andric 
339e8d8bef9SDimitry Andric // Return true when this is a pass on IR for which printing
340e8d8bef9SDimitry Andric // of changes is desired.
isInteresting(Any IR,StringRef PassID,StringRef PassName)341bdd1243dSDimitry Andric bool isInteresting(Any IR, StringRef PassID, StringRef PassName) {
342bdd1243dSDimitry Andric   if (isIgnored(PassID) || !isPassInPrintList(PassName))
343e8d8bef9SDimitry Andric     return false;
3445f757f3fSDimitry Andric   if (const auto *F = unwrapIR<Function>(IR))
3455f757f3fSDimitry Andric     return isInterestingFunction(*F);
346e8d8bef9SDimitry Andric   return true;
347e8d8bef9SDimitry Andric }
348e8d8bef9SDimitry Andric 
34981ad6265SDimitry Andric } // namespace
35081ad6265SDimitry Andric 
~ChangeReporter()35181ad6265SDimitry Andric template <typename T> ChangeReporter<T>::~ChangeReporter() {
35281ad6265SDimitry Andric   assert(BeforeStack.empty() && "Problem with Change Printer stack.");
35381ad6265SDimitry Andric }
35481ad6265SDimitry Andric 
355349cc55cSDimitry Andric template <typename T>
saveIRBeforePass(Any IR,StringRef PassID,StringRef PassName)356bdd1243dSDimitry Andric void ChangeReporter<T>::saveIRBeforePass(Any IR, StringRef PassID,
357bdd1243dSDimitry Andric                                          StringRef PassName) {
358e8d8bef9SDimitry Andric   // Is this the initial IR?
359e8d8bef9SDimitry Andric   if (InitialIR) {
360e8d8bef9SDimitry Andric     InitialIR = false;
361e8d8bef9SDimitry Andric     if (VerboseMode)
362e8d8bef9SDimitry Andric       handleInitialIR(IR);
363e8d8bef9SDimitry Andric   }
364e8d8bef9SDimitry Andric 
365bdd1243dSDimitry Andric   // Always need to place something on the stack because invalidated passes
366bdd1243dSDimitry Andric   // are not given the IR so it cannot be determined whether the pass was for
367bdd1243dSDimitry Andric   // something that was filtered out.
368bdd1243dSDimitry Andric   BeforeStack.emplace_back();
369bdd1243dSDimitry Andric 
370bdd1243dSDimitry Andric   if (!isInteresting(IR, PassID, PassName))
371bdd1243dSDimitry Andric     return;
372bdd1243dSDimitry Andric 
373e8d8bef9SDimitry Andric   // Save the IR representation on the stack.
374349cc55cSDimitry Andric   T &Data = BeforeStack.back();
375e8d8bef9SDimitry Andric   generateIRRepresentation(IR, PassID, Data);
376e8d8bef9SDimitry Andric }
377e8d8bef9SDimitry Andric 
378349cc55cSDimitry Andric template <typename T>
handleIRAfterPass(Any IR,StringRef PassID,StringRef PassName)379bdd1243dSDimitry Andric void ChangeReporter<T>::handleIRAfterPass(Any IR, StringRef PassID,
380bdd1243dSDimitry Andric                                           StringRef PassName) {
381e8d8bef9SDimitry Andric   assert(!BeforeStack.empty() && "Unexpected empty stack encountered.");
382e8d8bef9SDimitry Andric 
383fe6060f1SDimitry Andric   std::string Name = getIRName(IR);
384e8d8bef9SDimitry Andric 
385e8d8bef9SDimitry Andric   if (isIgnored(PassID)) {
386e8d8bef9SDimitry Andric     if (VerboseMode)
387e8d8bef9SDimitry Andric       handleIgnored(PassID, Name);
388bdd1243dSDimitry Andric   } else if (!isInteresting(IR, PassID, PassName)) {
389e8d8bef9SDimitry Andric     if (VerboseMode)
390e8d8bef9SDimitry Andric       handleFiltered(PassID, Name);
391e8d8bef9SDimitry Andric   } else {
392e8d8bef9SDimitry Andric     // Get the before rep from the stack
393349cc55cSDimitry Andric     T &Before = BeforeStack.back();
394e8d8bef9SDimitry Andric     // Create the after rep
395349cc55cSDimitry Andric     T After;
396e8d8bef9SDimitry Andric     generateIRRepresentation(IR, PassID, After);
397e8d8bef9SDimitry Andric 
398e8d8bef9SDimitry Andric     // Was there a change in IR?
399349cc55cSDimitry Andric     if (Before == After) {
400e8d8bef9SDimitry Andric       if (VerboseMode)
401e8d8bef9SDimitry Andric         omitAfter(PassID, Name);
402e8d8bef9SDimitry Andric     } else
403e8d8bef9SDimitry Andric       handleAfter(PassID, Name, Before, After, IR);
404e8d8bef9SDimitry Andric   }
405e8d8bef9SDimitry Andric   BeforeStack.pop_back();
406e8d8bef9SDimitry Andric }
407e8d8bef9SDimitry Andric 
408349cc55cSDimitry Andric template <typename T>
handleInvalidatedPass(StringRef PassID)409349cc55cSDimitry Andric void ChangeReporter<T>::handleInvalidatedPass(StringRef PassID) {
410e8d8bef9SDimitry Andric   assert(!BeforeStack.empty() && "Unexpected empty stack encountered.");
411e8d8bef9SDimitry Andric 
412e8d8bef9SDimitry Andric   // Always flag it as invalidated as we cannot determine when
413e8d8bef9SDimitry Andric   // a pass for a filtered function is invalidated since we do not
414e8d8bef9SDimitry Andric   // get the IR in the call.  Also, the output is just alternate
415e8d8bef9SDimitry Andric   // forms of the banner anyway.
416e8d8bef9SDimitry Andric   if (VerboseMode)
417e8d8bef9SDimitry Andric     handleInvalidated(PassID);
418e8d8bef9SDimitry Andric   BeforeStack.pop_back();
419e8d8bef9SDimitry Andric }
420e8d8bef9SDimitry Andric 
421349cc55cSDimitry Andric template <typename T>
registerRequiredCallbacks(PassInstrumentationCallbacks & PIC)422349cc55cSDimitry Andric void ChangeReporter<T>::registerRequiredCallbacks(
423e8d8bef9SDimitry Andric     PassInstrumentationCallbacks &PIC) {
424bdd1243dSDimitry Andric   PIC.registerBeforeNonSkippedPassCallback([&PIC, this](StringRef P, Any IR) {
425bdd1243dSDimitry Andric     saveIRBeforePass(IR, P, PIC.getPassNameForClassName(P));
426bdd1243dSDimitry Andric   });
427e8d8bef9SDimitry Andric 
428e8d8bef9SDimitry Andric   PIC.registerAfterPassCallback(
429bdd1243dSDimitry Andric       [&PIC, this](StringRef P, Any IR, const PreservedAnalyses &) {
430bdd1243dSDimitry Andric         handleIRAfterPass(IR, P, PIC.getPassNameForClassName(P));
431e8d8bef9SDimitry Andric       });
432e8d8bef9SDimitry Andric   PIC.registerAfterPassInvalidatedCallback(
433e8d8bef9SDimitry Andric       [this](StringRef P, const PreservedAnalyses &) {
434e8d8bef9SDimitry Andric         handleInvalidatedPass(P);
435e8d8bef9SDimitry Andric       });
436e8d8bef9SDimitry Andric }
437e8d8bef9SDimitry Andric 
438349cc55cSDimitry Andric template <typename T>
TextChangeReporter(bool Verbose)439349cc55cSDimitry Andric TextChangeReporter<T>::TextChangeReporter(bool Verbose)
440349cc55cSDimitry Andric     : ChangeReporter<T>(Verbose), Out(dbgs()) {}
441fe6060f1SDimitry Andric 
handleInitialIR(Any IR)442349cc55cSDimitry Andric template <typename T> void TextChangeReporter<T>::handleInitialIR(Any IR) {
443e8d8bef9SDimitry Andric   // Always print the module.
444e8d8bef9SDimitry Andric   // Unwrap and print directly to avoid filtering problems in general routines.
445fe6060f1SDimitry Andric   auto *M = unwrapModule(IR, /*Force=*/true);
446fe6060f1SDimitry Andric   assert(M && "Expected module to be unwrapped when forced.");
447fe6060f1SDimitry Andric   Out << "*** IR Dump At Start ***\n";
448349cc55cSDimitry Andric   M->print(Out, nullptr);
449e8d8bef9SDimitry Andric }
450e8d8bef9SDimitry Andric 
451349cc55cSDimitry Andric template <typename T>
omitAfter(StringRef PassID,std::string & Name)452349cc55cSDimitry Andric void TextChangeReporter<T>::omitAfter(StringRef PassID, std::string &Name) {
453fe6060f1SDimitry Andric   Out << formatv("*** IR Dump After {0} on {1} omitted because no change ***\n",
454e8d8bef9SDimitry Andric                  PassID, Name);
455e8d8bef9SDimitry Andric }
456e8d8bef9SDimitry Andric 
457349cc55cSDimitry Andric template <typename T>
handleInvalidated(StringRef PassID)458349cc55cSDimitry Andric void TextChangeReporter<T>::handleInvalidated(StringRef PassID) {
459e8d8bef9SDimitry Andric   Out << formatv("*** IR Pass {0} invalidated ***\n", PassID);
460e8d8bef9SDimitry Andric }
461e8d8bef9SDimitry Andric 
462349cc55cSDimitry Andric template <typename T>
handleFiltered(StringRef PassID,std::string & Name)463349cc55cSDimitry Andric void TextChangeReporter<T>::handleFiltered(StringRef PassID,
464e8d8bef9SDimitry Andric                                            std::string &Name) {
465e8d8bef9SDimitry Andric   SmallString<20> Banner =
466fe6060f1SDimitry Andric       formatv("*** IR Dump After {0} on {1} filtered out ***\n", PassID, Name);
467e8d8bef9SDimitry Andric   Out << Banner;
468e8d8bef9SDimitry Andric }
469e8d8bef9SDimitry Andric 
470349cc55cSDimitry Andric template <typename T>
handleIgnored(StringRef PassID,std::string & Name)471349cc55cSDimitry Andric void TextChangeReporter<T>::handleIgnored(StringRef PassID, std::string &Name) {
472fe6060f1SDimitry Andric   Out << formatv("*** IR Pass {0} on {1} ignored ***\n", PassID, Name);
473e8d8bef9SDimitry Andric }
474e8d8bef9SDimitry Andric 
47581ad6265SDimitry Andric IRChangedPrinter::~IRChangedPrinter() = default;
476e8d8bef9SDimitry Andric 
registerCallbacks(PassInstrumentationCallbacks & PIC)477e8d8bef9SDimitry Andric void IRChangedPrinter::registerCallbacks(PassInstrumentationCallbacks &PIC) {
478fcaf7f86SDimitry Andric   if (PrintChanged == ChangePrinter::Verbose ||
479fcaf7f86SDimitry Andric       PrintChanged == ChangePrinter::Quiet)
480e8d8bef9SDimitry Andric     TextChangeReporter<std::string>::registerRequiredCallbacks(PIC);
481e8d8bef9SDimitry Andric }
482e8d8bef9SDimitry Andric 
generateIRRepresentation(Any IR,StringRef PassID,std::string & Output)483e8d8bef9SDimitry Andric void IRChangedPrinter::generateIRRepresentation(Any IR, StringRef PassID,
484e8d8bef9SDimitry Andric                                                 std::string &Output) {
485e8d8bef9SDimitry Andric   raw_string_ostream OS(Output);
486349cc55cSDimitry Andric   unwrapAndPrint(OS, IR);
487e8d8bef9SDimitry Andric   OS.str();
488e8d8bef9SDimitry Andric }
489e8d8bef9SDimitry Andric 
handleAfter(StringRef PassID,std::string & Name,const std::string & Before,const std::string & After,Any)490e8d8bef9SDimitry Andric void IRChangedPrinter::handleAfter(StringRef PassID, std::string &Name,
491e8d8bef9SDimitry Andric                                    const std::string &Before,
492e8d8bef9SDimitry Andric                                    const std::string &After, Any) {
493e8d8bef9SDimitry Andric   // Report the IR before the changes when requested.
494fe6060f1SDimitry Andric   if (PrintChangedBefore)
495fe6060f1SDimitry Andric     Out << "*** IR Dump Before " << PassID << " on " << Name << " ***\n"
496fe6060f1SDimitry Andric         << Before;
497e8d8bef9SDimitry Andric 
498fe6060f1SDimitry Andric   // We might not get anything to print if we only want to print a specific
499fe6060f1SDimitry Andric   // function but it gets deleted.
500fe6060f1SDimitry Andric   if (After.empty()) {
501fe6060f1SDimitry Andric     Out << "*** IR Deleted After " << PassID << " on " << Name << " ***\n";
502fe6060f1SDimitry Andric     return;
503e8d8bef9SDimitry Andric   }
504e8d8bef9SDimitry Andric 
505fe6060f1SDimitry Andric   Out << "*** IR Dump After " << PassID << " on " << Name << " ***\n" << After;
506e8d8bef9SDimitry Andric }
507e8d8bef9SDimitry Andric 
~IRChangedTester()508bdd1243dSDimitry Andric IRChangedTester::~IRChangedTester() {}
509bdd1243dSDimitry Andric 
registerCallbacks(PassInstrumentationCallbacks & PIC)510bdd1243dSDimitry Andric void IRChangedTester::registerCallbacks(PassInstrumentationCallbacks &PIC) {
511bdd1243dSDimitry Andric   if (TestChanged != "")
512bdd1243dSDimitry Andric     TextChangeReporter<std::string>::registerRequiredCallbacks(PIC);
513bdd1243dSDimitry Andric }
514bdd1243dSDimitry Andric 
handleIR(const std::string & S,StringRef PassID)515bdd1243dSDimitry Andric void IRChangedTester::handleIR(const std::string &S, StringRef PassID) {
516bdd1243dSDimitry Andric   // Store the body into a temporary file
517bdd1243dSDimitry Andric   static SmallVector<int> FD{-1};
518bdd1243dSDimitry Andric   SmallVector<StringRef> SR{S};
519bdd1243dSDimitry Andric   static SmallVector<std::string> FileName{""};
5205f757f3fSDimitry Andric   if (prepareTempFiles(FD, SR, FileName)) {
521bdd1243dSDimitry Andric     dbgs() << "Unable to create temporary file.";
522bdd1243dSDimitry Andric     return;
523bdd1243dSDimitry Andric   }
524bdd1243dSDimitry Andric   static ErrorOr<std::string> Exe = sys::findProgramByName(TestChanged);
525bdd1243dSDimitry Andric   if (!Exe) {
526bdd1243dSDimitry Andric     dbgs() << "Unable to find test-changed executable.";
527bdd1243dSDimitry Andric     return;
528bdd1243dSDimitry Andric   }
529bdd1243dSDimitry Andric 
530bdd1243dSDimitry Andric   StringRef Args[] = {TestChanged, FileName[0], PassID};
531bdd1243dSDimitry Andric   int Result = sys::ExecuteAndWait(*Exe, Args);
532bdd1243dSDimitry Andric   if (Result < 0) {
533bdd1243dSDimitry Andric     dbgs() << "Error executing test-changed executable.";
534bdd1243dSDimitry Andric     return;
535bdd1243dSDimitry Andric   }
536bdd1243dSDimitry Andric 
5375f757f3fSDimitry Andric   if (cleanUpTempFiles(FileName))
538bdd1243dSDimitry Andric     dbgs() << "Unable to remove temporary file.";
539bdd1243dSDimitry Andric }
540bdd1243dSDimitry Andric 
handleInitialIR(Any IR)541bdd1243dSDimitry Andric void IRChangedTester::handleInitialIR(Any IR) {
542bdd1243dSDimitry Andric   // Always test the initial module.
543bdd1243dSDimitry Andric   // Unwrap and print directly to avoid filtering problems in general routines.
544bdd1243dSDimitry Andric   std::string S;
545bdd1243dSDimitry Andric   generateIRRepresentation(IR, "Initial IR", S);
546bdd1243dSDimitry Andric   handleIR(S, "Initial IR");
547bdd1243dSDimitry Andric }
548bdd1243dSDimitry Andric 
omitAfter(StringRef PassID,std::string & Name)549bdd1243dSDimitry Andric void IRChangedTester::omitAfter(StringRef PassID, std::string &Name) {}
handleInvalidated(StringRef PassID)550bdd1243dSDimitry Andric void IRChangedTester::handleInvalidated(StringRef PassID) {}
handleFiltered(StringRef PassID,std::string & Name)551bdd1243dSDimitry Andric void IRChangedTester::handleFiltered(StringRef PassID, std::string &Name) {}
handleIgnored(StringRef PassID,std::string & Name)552bdd1243dSDimitry Andric void IRChangedTester::handleIgnored(StringRef PassID, std::string &Name) {}
handleAfter(StringRef PassID,std::string & Name,const std::string & Before,const std::string & After,Any)553bdd1243dSDimitry Andric void IRChangedTester::handleAfter(StringRef PassID, std::string &Name,
554bdd1243dSDimitry Andric                                   const std::string &Before,
555bdd1243dSDimitry Andric                                   const std::string &After, Any) {
556bdd1243dSDimitry Andric   handleIR(After, PassID);
557bdd1243dSDimitry Andric }
558bdd1243dSDimitry Andric 
559349cc55cSDimitry Andric template <typename T>
report(const OrderedChangedData & Before,const OrderedChangedData & After,function_ref<void (const T *,const T *)> HandlePair)560349cc55cSDimitry Andric void OrderedChangedData<T>::report(
561fe6060f1SDimitry Andric     const OrderedChangedData &Before, const OrderedChangedData &After,
562349cc55cSDimitry Andric     function_ref<void(const T *, const T *)> HandlePair) {
563fe6060f1SDimitry Andric   const auto &BFD = Before.getData();
564fe6060f1SDimitry Andric   const auto &AFD = After.getData();
565fe6060f1SDimitry Andric   std::vector<std::string>::const_iterator BI = Before.getOrder().begin();
566fe6060f1SDimitry Andric   std::vector<std::string>::const_iterator BE = Before.getOrder().end();
567fe6060f1SDimitry Andric   std::vector<std::string>::const_iterator AI = After.getOrder().begin();
568fe6060f1SDimitry Andric   std::vector<std::string>::const_iterator AE = After.getOrder().end();
569fe6060f1SDimitry Andric 
570349cc55cSDimitry Andric   auto HandlePotentiallyRemovedData = [&](std::string S) {
571fe6060f1SDimitry Andric     // The order in LLVM may have changed so check if still exists.
572fe6060f1SDimitry Andric     if (!AFD.count(S)) {
573fe6060f1SDimitry Andric       // This has been removed.
574fe6060f1SDimitry Andric       HandlePair(&BFD.find(*BI)->getValue(), nullptr);
575fe6060f1SDimitry Andric     }
576fe6060f1SDimitry Andric   };
577349cc55cSDimitry Andric   auto HandleNewData = [&](std::vector<const T *> &Q) {
578fe6060f1SDimitry Andric     // Print out any queued up new sections
579349cc55cSDimitry Andric     for (const T *NBI : Q)
580fe6060f1SDimitry Andric       HandlePair(nullptr, NBI);
581fe6060f1SDimitry Andric     Q.clear();
582fe6060f1SDimitry Andric   };
583fe6060f1SDimitry Andric 
584349cc55cSDimitry Andric   // Print out the data in the after order, with before ones interspersed
585fe6060f1SDimitry Andric   // appropriately (ie, somewhere near where they were in the before list).
586fe6060f1SDimitry Andric   // Start at the beginning of both lists.  Loop through the
587fe6060f1SDimitry Andric   // after list.  If an element is common, then advance in the before list
588fe6060f1SDimitry Andric   // reporting the removed ones until the common one is reached.  Report any
589fe6060f1SDimitry Andric   // queued up new ones and then report the common one.  If an element is not
590fe6060f1SDimitry Andric   // common, then enqueue it for reporting.  When the after list is exhausted,
591fe6060f1SDimitry Andric   // loop through the before list, reporting any removed ones.  Finally,
592fe6060f1SDimitry Andric   // report the rest of the enqueued new ones.
593349cc55cSDimitry Andric   std::vector<const T *> NewDataQueue;
594fe6060f1SDimitry Andric   while (AI != AE) {
595fe6060f1SDimitry Andric     if (!BFD.count(*AI)) {
596fe6060f1SDimitry Andric       // This section is new so place it in the queue.  This will cause it
597fe6060f1SDimitry Andric       // to be reported after deleted sections.
598349cc55cSDimitry Andric       NewDataQueue.emplace_back(&AFD.find(*AI)->getValue());
599fe6060f1SDimitry Andric       ++AI;
600fe6060f1SDimitry Andric       continue;
601fe6060f1SDimitry Andric     }
602fe6060f1SDimitry Andric     // This section is in both; advance and print out any before-only
603fe6060f1SDimitry Andric     // until we get to it.
604bdd1243dSDimitry Andric     // It's possible that this section has moved to be later than before. This
605bdd1243dSDimitry Andric     // will mess up printing most blocks side by side, but it's a rare case and
606bdd1243dSDimitry Andric     // it's better than crashing.
607bdd1243dSDimitry Andric     while (BI != BE && *BI != *AI) {
608349cc55cSDimitry Andric       HandlePotentiallyRemovedData(*BI);
609fe6060f1SDimitry Andric       ++BI;
610fe6060f1SDimitry Andric     }
611fe6060f1SDimitry Andric     // Report any new sections that were queued up and waiting.
612349cc55cSDimitry Andric     HandleNewData(NewDataQueue);
613fe6060f1SDimitry Andric 
614349cc55cSDimitry Andric     const T &AData = AFD.find(*AI)->getValue();
615349cc55cSDimitry Andric     const T &BData = BFD.find(*AI)->getValue();
616fe6060f1SDimitry Andric     HandlePair(&BData, &AData);
617bdd1243dSDimitry Andric     if (BI != BE)
618fe6060f1SDimitry Andric       ++BI;
619fe6060f1SDimitry Andric     ++AI;
620fe6060f1SDimitry Andric   }
621fe6060f1SDimitry Andric 
622fe6060f1SDimitry Andric   // Check any remaining before sections to see if they have been removed
623fe6060f1SDimitry Andric   while (BI != BE) {
624349cc55cSDimitry Andric     HandlePotentiallyRemovedData(*BI);
625fe6060f1SDimitry Andric     ++BI;
626fe6060f1SDimitry Andric   }
627fe6060f1SDimitry Andric 
628349cc55cSDimitry Andric   HandleNewData(NewDataQueue);
629fe6060f1SDimitry Andric }
630fe6060f1SDimitry Andric 
631349cc55cSDimitry Andric template <typename T>
compare(bool CompareModule,std::function<void (bool InModule,unsigned Minor,const FuncDataT<T> & Before,const FuncDataT<T> & After)> CompareFunc)632349cc55cSDimitry Andric void IRComparer<T>::compare(
633349cc55cSDimitry Andric     bool CompareModule,
634349cc55cSDimitry Andric     std::function<void(bool InModule, unsigned Minor,
635349cc55cSDimitry Andric                        const FuncDataT<T> &Before, const FuncDataT<T> &After)>
636349cc55cSDimitry Andric         CompareFunc) {
637349cc55cSDimitry Andric   if (!CompareModule) {
638349cc55cSDimitry Andric     // Just handle the single function.
639349cc55cSDimitry Andric     assert(Before.getData().size() == 1 && After.getData().size() == 1 &&
640349cc55cSDimitry Andric            "Expected only one function.");
641349cc55cSDimitry Andric     CompareFunc(false, 0, Before.getData().begin()->getValue(),
642fe6060f1SDimitry Andric                 After.getData().begin()->getValue());
643fe6060f1SDimitry Andric     return;
644fe6060f1SDimitry Andric   }
645fe6060f1SDimitry Andric 
646349cc55cSDimitry Andric   unsigned Minor = 0;
647349cc55cSDimitry Andric   FuncDataT<T> Missing("");
648349cc55cSDimitry Andric   IRDataT<T>::report(Before, After,
649349cc55cSDimitry Andric                      [&](const FuncDataT<T> *B, const FuncDataT<T> *A) {
650349cc55cSDimitry Andric                        assert((B || A) && "Both functions cannot be missing.");
651fe6060f1SDimitry Andric                        if (!B)
652fe6060f1SDimitry Andric                          B = &Missing;
653fe6060f1SDimitry Andric                        else if (!A)
654fe6060f1SDimitry Andric                          A = &Missing;
655349cc55cSDimitry Andric                        CompareFunc(true, Minor++, *B, *A);
656fe6060f1SDimitry Andric                      });
657fe6060f1SDimitry Andric }
658fe6060f1SDimitry Andric 
analyzeIR(Any IR,IRDataT<T> & Data)659349cc55cSDimitry Andric template <typename T> void IRComparer<T>::analyzeIR(Any IR, IRDataT<T> &Data) {
660fe6060f1SDimitry Andric   if (const Module *M = getModuleForComparison(IR)) {
661fe6060f1SDimitry Andric     // Create data for each existing/interesting function in the module.
662fe6060f1SDimitry Andric     for (const Function &F : *M)
663fe6060f1SDimitry Andric       generateFunctionData(Data, F);
664fe6060f1SDimitry Andric     return;
665fe6060f1SDimitry Andric   }
666fe6060f1SDimitry Andric 
6675f757f3fSDimitry Andric   const auto *F = unwrapIR<Function>(IR);
668bdd1243dSDimitry Andric   if (!F) {
6695f757f3fSDimitry Andric     const auto *L = unwrapIR<Loop>(IR);
670bdd1243dSDimitry Andric     assert(L && "Unknown IR unit.");
6715f757f3fSDimitry Andric     F = L->getHeader()->getParent();
672fe6060f1SDimitry Andric   }
673fe6060f1SDimitry Andric   assert(F && "Unknown IR unit.");
674fe6060f1SDimitry Andric   generateFunctionData(Data, *F);
675fe6060f1SDimitry Andric }
676fe6060f1SDimitry Andric 
677349cc55cSDimitry Andric template <typename T>
generateFunctionData(IRDataT<T> & Data,const Function & F)678349cc55cSDimitry Andric bool IRComparer<T>::generateFunctionData(IRDataT<T> &Data, const Function &F) {
679fe6060f1SDimitry Andric   if (!F.isDeclaration() && isFunctionInPrintList(F.getName())) {
680349cc55cSDimitry Andric     FuncDataT<T> FD(F.getEntryBlock().getName().str());
681bdd1243dSDimitry Andric     int I = 0;
682fe6060f1SDimitry Andric     for (const auto &B : F) {
683bdd1243dSDimitry Andric       std::string BBName = B.getName().str();
684bdd1243dSDimitry Andric       if (BBName.empty()) {
685bdd1243dSDimitry Andric         BBName = formatv("{0}", I);
686bdd1243dSDimitry Andric         ++I;
687bdd1243dSDimitry Andric       }
688bdd1243dSDimitry Andric       FD.getOrder().emplace_back(BBName);
689bdd1243dSDimitry Andric       FD.getData().insert({BBName, B});
690fe6060f1SDimitry Andric     }
691fe6060f1SDimitry Andric     Data.getOrder().emplace_back(F.getName());
692349cc55cSDimitry Andric     Data.getData().insert({F.getName(), FD});
693fe6060f1SDimitry Andric     return true;
694fe6060f1SDimitry Andric   }
695fe6060f1SDimitry Andric   return false;
696fe6060f1SDimitry Andric }
697fe6060f1SDimitry Andric 
~PrintIRInstrumentation()6980b57cec5SDimitry Andric PrintIRInstrumentation::~PrintIRInstrumentation() {
6995f757f3fSDimitry Andric   assert(PassRunDescriptorStack.empty() &&
7005f757f3fSDimitry Andric          "PassRunDescriptorStack is not empty at exit");
7010b57cec5SDimitry Andric }
7020b57cec5SDimitry Andric 
getIRFileDisplayName(Any IR)7035f757f3fSDimitry Andric static SmallString<32> getIRFileDisplayName(Any IR) {
7045f757f3fSDimitry Andric   SmallString<32> Result;
7055f757f3fSDimitry Andric   raw_svector_ostream ResultStream(Result);
706fe6060f1SDimitry Andric   const Module *M = unwrapModule(IR);
7075f757f3fSDimitry Andric   stable_hash NameHash = stable_hash_combine_string(M->getName());
7085f757f3fSDimitry Andric   unsigned int MaxHashWidth = sizeof(stable_hash) * 8 / 4;
7095f757f3fSDimitry Andric   write_hex(ResultStream, NameHash, HexPrintStyle::Lower, MaxHashWidth);
7105f757f3fSDimitry Andric   if (unwrapIR<Module>(IR)) {
7115f757f3fSDimitry Andric     ResultStream << "-module";
7125f757f3fSDimitry Andric   } else if (const auto *F = unwrapIR<Function>(IR)) {
7135f757f3fSDimitry Andric     ResultStream << "-function-";
7145f757f3fSDimitry Andric     stable_hash FunctionNameHash = stable_hash_combine_string(F->getName());
7155f757f3fSDimitry Andric     write_hex(ResultStream, FunctionNameHash, HexPrintStyle::Lower,
7165f757f3fSDimitry Andric               MaxHashWidth);
7175f757f3fSDimitry Andric   } else if (const auto *C = unwrapIR<LazyCallGraph::SCC>(IR)) {
7185f757f3fSDimitry Andric     ResultStream << "-scc-";
7195f757f3fSDimitry Andric     stable_hash SCCNameHash = stable_hash_combine_string(C->getName());
7205f757f3fSDimitry Andric     write_hex(ResultStream, SCCNameHash, HexPrintStyle::Lower, MaxHashWidth);
7215f757f3fSDimitry Andric   } else if (const auto *L = unwrapIR<Loop>(IR)) {
7225f757f3fSDimitry Andric     ResultStream << "-loop-";
7235f757f3fSDimitry Andric     stable_hash LoopNameHash = stable_hash_combine_string(L->getName());
7245f757f3fSDimitry Andric     write_hex(ResultStream, LoopNameHash, HexPrintStyle::Lower, MaxHashWidth);
7255f757f3fSDimitry Andric   } else {
7265f757f3fSDimitry Andric     llvm_unreachable("Unknown wrapped IR type");
7275f757f3fSDimitry Andric   }
7285f757f3fSDimitry Andric   return Result;
7290b57cec5SDimitry Andric }
7300b57cec5SDimitry Andric 
fetchDumpFilename(StringRef PassName,Any IR)7315f757f3fSDimitry Andric std::string PrintIRInstrumentation::fetchDumpFilename(StringRef PassName,
7325f757f3fSDimitry Andric                                                       Any IR) {
7335f757f3fSDimitry Andric   const StringRef RootDirectory = IRDumpDirectory;
7345f757f3fSDimitry Andric   assert(!RootDirectory.empty() &&
7355f757f3fSDimitry Andric          "The flag -ir-dump-directory must be passed to dump IR to files");
7365f757f3fSDimitry Andric   SmallString<128> ResultPath;
7375f757f3fSDimitry Andric   ResultPath += RootDirectory;
7385f757f3fSDimitry Andric   SmallString<64> Filename;
7395f757f3fSDimitry Andric   raw_svector_ostream FilenameStream(Filename);
7405f757f3fSDimitry Andric   FilenameStream << CurrentPassNumber;
7415f757f3fSDimitry Andric   FilenameStream << "-";
7425f757f3fSDimitry Andric   FilenameStream << getIRFileDisplayName(IR);
7435f757f3fSDimitry Andric   FilenameStream << "-";
7445f757f3fSDimitry Andric   FilenameStream << PassName;
7455f757f3fSDimitry Andric   sys::path::append(ResultPath, Filename);
7465f757f3fSDimitry Andric   return std::string(ResultPath);
7475f757f3fSDimitry Andric }
7485f757f3fSDimitry Andric 
7495f757f3fSDimitry Andric enum class IRDumpFileSuffixType {
7505f757f3fSDimitry Andric   Before,
7515f757f3fSDimitry Andric   After,
7525f757f3fSDimitry Andric   Invalidated,
7535f757f3fSDimitry Andric };
7545f757f3fSDimitry Andric 
getFileSuffix(IRDumpFileSuffixType Type)7555f757f3fSDimitry Andric static StringRef getFileSuffix(IRDumpFileSuffixType Type) {
7565f757f3fSDimitry Andric   static constexpr std::array FileSuffixes = {"-before.ll", "-after.ll",
7575f757f3fSDimitry Andric                                               "-invalidated.ll"};
7585f757f3fSDimitry Andric   return FileSuffixes[static_cast<size_t>(Type)];
7595f757f3fSDimitry Andric }
7605f757f3fSDimitry Andric 
pushPassRunDescriptor(StringRef PassID,Any IR,std::string & DumpIRFilename)7615f757f3fSDimitry Andric void PrintIRInstrumentation::pushPassRunDescriptor(
7625f757f3fSDimitry Andric     StringRef PassID, Any IR, std::string &DumpIRFilename) {
7635f757f3fSDimitry Andric   const Module *M = unwrapModule(IR);
7645f757f3fSDimitry Andric   PassRunDescriptorStack.emplace_back(
7655f757f3fSDimitry Andric       PassRunDescriptor(M, DumpIRFilename, getIRName(IR), PassID));
7665f757f3fSDimitry Andric }
7675f757f3fSDimitry Andric 
7685f757f3fSDimitry Andric PrintIRInstrumentation::PassRunDescriptor
popPassRunDescriptor(StringRef PassID)7695f757f3fSDimitry Andric PrintIRInstrumentation::popPassRunDescriptor(StringRef PassID) {
7705f757f3fSDimitry Andric   assert(!PassRunDescriptorStack.empty() && "empty PassRunDescriptorStack");
7715f757f3fSDimitry Andric   PassRunDescriptor Descriptor = PassRunDescriptorStack.pop_back_val();
7725f757f3fSDimitry Andric   assert(Descriptor.PassID.equals(PassID) &&
7735f757f3fSDimitry Andric          "malformed PassRunDescriptorStack");
7745f757f3fSDimitry Andric   return Descriptor;
7755f757f3fSDimitry Andric }
7765f757f3fSDimitry Andric 
7775f757f3fSDimitry Andric // Callers are responsible for closing the returned file descriptor
prepareDumpIRFileDescriptor(const StringRef DumpIRFilename)7785f757f3fSDimitry Andric static int prepareDumpIRFileDescriptor(const StringRef DumpIRFilename) {
7795f757f3fSDimitry Andric   std::error_code EC;
7805f757f3fSDimitry Andric   auto ParentPath = llvm::sys::path::parent_path(DumpIRFilename);
7815f757f3fSDimitry Andric   if (!ParentPath.empty()) {
7825f757f3fSDimitry Andric     std::error_code EC = llvm::sys::fs::create_directories(ParentPath);
7835f757f3fSDimitry Andric     if (EC)
7845f757f3fSDimitry Andric       report_fatal_error(Twine("Failed to create directory ") + ParentPath +
7855f757f3fSDimitry Andric                          " to support -ir-dump-directory: " + EC.message());
7865f757f3fSDimitry Andric   }
7875f757f3fSDimitry Andric   int Result = 0;
7885f757f3fSDimitry Andric   EC = sys::fs::openFile(DumpIRFilename, Result, sys::fs::CD_OpenAlways,
7895f757f3fSDimitry Andric                          sys::fs::FA_Write, sys::fs::OF_None);
7905f757f3fSDimitry Andric   if (EC)
7915f757f3fSDimitry Andric     report_fatal_error(Twine("Failed to open ") + DumpIRFilename +
7925f757f3fSDimitry Andric                        " to support -ir-dump-directory: " + EC.message());
7935f757f3fSDimitry Andric   return Result;
7940b57cec5SDimitry Andric }
7950b57cec5SDimitry Andric 
printBeforePass(StringRef PassID,Any IR)796e8d8bef9SDimitry Andric void PrintIRInstrumentation::printBeforePass(StringRef PassID, Any IR) {
797e8d8bef9SDimitry Andric   if (isIgnored(PassID))
798e8d8bef9SDimitry Andric     return;
7990b57cec5SDimitry Andric 
8005f757f3fSDimitry Andric   std::string DumpIRFilename;
8015f757f3fSDimitry Andric   if (!IRDumpDirectory.empty() &&
8025f757f3fSDimitry Andric       (shouldPrintBeforePass(PassID) || shouldPrintAfterPass(PassID)))
8035f757f3fSDimitry Andric     DumpIRFilename = fetchDumpFilename(PassID, IR);
8045f757f3fSDimitry Andric 
8050b57cec5SDimitry Andric   // Saving Module for AfterPassInvalidated operations.
8060b57cec5SDimitry Andric   // Note: here we rely on a fact that we do not change modules while
8070b57cec5SDimitry Andric   // traversing the pipeline, so the latest captured module is good
8080b57cec5SDimitry Andric   // for all print operations that has not happen yet.
8091db9f3b2SDimitry Andric   if (shouldPrintAfterPass(PassID))
8105f757f3fSDimitry Andric     pushPassRunDescriptor(PassID, IR, DumpIRFilename);
8110b57cec5SDimitry Andric 
81206c3fb27SDimitry Andric   if (!shouldPrintIR(IR))
813e8d8bef9SDimitry Andric     return;
8140b57cec5SDimitry Andric 
81506c3fb27SDimitry Andric   ++CurrentPassNumber;
81606c3fb27SDimitry Andric 
81706c3fb27SDimitry Andric   if (shouldPrintPassNumbers())
8185f757f3fSDimitry Andric     dbgs() << " Running pass " << CurrentPassNumber << " " << PassID
8195f757f3fSDimitry Andric            << " on " << getIRName(IR) << "\n";
82006c3fb27SDimitry Andric 
82106c3fb27SDimitry Andric   if (!shouldPrintBeforePass(PassID))
822fe6060f1SDimitry Andric     return;
823fe6060f1SDimitry Andric 
8245f757f3fSDimitry Andric   auto WriteIRToStream = [&](raw_ostream &Stream) {
8251db9f3b2SDimitry Andric     Stream << "; *** IR Dump Before ";
8261db9f3b2SDimitry Andric     if (shouldPrintBeforePassNumber())
8271db9f3b2SDimitry Andric       Stream << CurrentPassNumber << "-";
8281db9f3b2SDimitry Andric     Stream << PassID << " on " << getIRName(IR) << " ***\n";
8295f757f3fSDimitry Andric     unwrapAndPrint(Stream, IR);
8305f757f3fSDimitry Andric   };
8315f757f3fSDimitry Andric 
8325f757f3fSDimitry Andric   if (!DumpIRFilename.empty()) {
8335f757f3fSDimitry Andric     DumpIRFilename += getFileSuffix(IRDumpFileSuffixType::Before);
8345f757f3fSDimitry Andric     llvm::raw_fd_ostream DumpIRFileStream{
8355f757f3fSDimitry Andric         prepareDumpIRFileDescriptor(DumpIRFilename), /* shouldClose */ true};
8365f757f3fSDimitry Andric     WriteIRToStream(DumpIRFileStream);
8375f757f3fSDimitry Andric   } else {
8385f757f3fSDimitry Andric     WriteIRToStream(dbgs());
8395f757f3fSDimitry Andric   }
8400b57cec5SDimitry Andric }
8410b57cec5SDimitry Andric 
printAfterPass(StringRef PassID,Any IR)8420b57cec5SDimitry Andric void PrintIRInstrumentation::printAfterPass(StringRef PassID, Any IR) {
843e8d8bef9SDimitry Andric   if (isIgnored(PassID))
8440b57cec5SDimitry Andric     return;
8450b57cec5SDimitry Andric 
8461db9f3b2SDimitry Andric   if (!shouldPrintAfterPass(PassID))
8470b57cec5SDimitry Andric     return;
8480b57cec5SDimitry Andric 
8495f757f3fSDimitry Andric   auto [M, DumpIRFilename, IRName, StoredPassID] = popPassRunDescriptor(PassID);
850fe6060f1SDimitry Andric   assert(StoredPassID == PassID && "mismatched PassID");
8510b57cec5SDimitry Andric 
85206c3fb27SDimitry Andric   if (!shouldPrintIR(IR) || !shouldPrintAfterPass(PassID))
853fe6060f1SDimitry Andric     return;
854fe6060f1SDimitry Andric 
8555f757f3fSDimitry Andric   auto WriteIRToStream = [&](raw_ostream &Stream, const StringRef IRName) {
8561db9f3b2SDimitry Andric     Stream << "; *** IR Dump " << StringRef(formatv("After {0}", PassID))
85706c3fb27SDimitry Andric            << " on " << IRName << " ***\n";
8585f757f3fSDimitry Andric     unwrapAndPrint(Stream, IR);
8595f757f3fSDimitry Andric   };
8605f757f3fSDimitry Andric 
8615f757f3fSDimitry Andric   if (!IRDumpDirectory.empty()) {
8625f757f3fSDimitry Andric     assert(!DumpIRFilename.empty() && "DumpIRFilename must not be empty and "
8635f757f3fSDimitry Andric                                       "should be set in printBeforePass");
8645f757f3fSDimitry Andric     const std::string DumpIRFilenameWithSuffix =
8655f757f3fSDimitry Andric         DumpIRFilename + getFileSuffix(IRDumpFileSuffixType::After).str();
8665f757f3fSDimitry Andric     llvm::raw_fd_ostream DumpIRFileStream{
8675f757f3fSDimitry Andric         prepareDumpIRFileDescriptor(DumpIRFilenameWithSuffix),
8685f757f3fSDimitry Andric         /* shouldClose */ true};
8695f757f3fSDimitry Andric     WriteIRToStream(DumpIRFileStream, IRName);
8705f757f3fSDimitry Andric   } else {
8715f757f3fSDimitry Andric     WriteIRToStream(dbgs(), IRName);
8725f757f3fSDimitry Andric   }
8730b57cec5SDimitry Andric }
8740b57cec5SDimitry Andric 
printAfterPassInvalidated(StringRef PassID)8750b57cec5SDimitry Andric void PrintIRInstrumentation::printAfterPassInvalidated(StringRef PassID) {
87606c3fb27SDimitry Andric   if (isIgnored(PassID))
8770b57cec5SDimitry Andric     return;
8780b57cec5SDimitry Andric 
8791db9f3b2SDimitry Andric   if (!shouldPrintAfterPass(PassID))
8800b57cec5SDimitry Andric     return;
8810b57cec5SDimitry Andric 
8825f757f3fSDimitry Andric   auto [M, DumpIRFilename, IRName, StoredPassID] = popPassRunDescriptor(PassID);
883fe6060f1SDimitry Andric   assert(StoredPassID == PassID && "mismatched PassID");
8840b57cec5SDimitry Andric   // Additional filtering (e.g. -filter-print-func) can lead to module
8850b57cec5SDimitry Andric   // printing being skipped.
88606c3fb27SDimitry Andric   if (!M || !shouldPrintAfterPass(PassID))
8870b57cec5SDimitry Andric     return;
8880b57cec5SDimitry Andric 
8895f757f3fSDimitry Andric   auto WriteIRToStream = [&](raw_ostream &Stream, const Module *M,
8905f757f3fSDimitry Andric                              const StringRef IRName) {
89106c3fb27SDimitry Andric     SmallString<20> Banner;
8921db9f3b2SDimitry Andric     Banner = formatv("; *** IR Dump After {0} on {1} (invalidated) ***", PassID,
8931db9f3b2SDimitry Andric                      IRName);
8945f757f3fSDimitry Andric     Stream << Banner << "\n";
8955f757f3fSDimitry Andric     printIR(Stream, M);
8965f757f3fSDimitry Andric   };
8975f757f3fSDimitry Andric 
8985f757f3fSDimitry Andric   if (!IRDumpDirectory.empty()) {
8995f757f3fSDimitry Andric     assert(!DumpIRFilename.empty() && "DumpIRFilename must not be empty and "
9005f757f3fSDimitry Andric                                       "should be set in printBeforePass");
9015f757f3fSDimitry Andric     const std::string DumpIRFilenameWithSuffix =
9025f757f3fSDimitry Andric         DumpIRFilename + getFileSuffix(IRDumpFileSuffixType::Invalidated).str();
9035f757f3fSDimitry Andric     llvm::raw_fd_ostream DumpIRFileStream{
9045f757f3fSDimitry Andric         prepareDumpIRFileDescriptor(DumpIRFilenameWithSuffix),
9055f757f3fSDimitry Andric         /* shouldClose */ true};
9065f757f3fSDimitry Andric     WriteIRToStream(DumpIRFileStream, M, IRName);
9075f757f3fSDimitry Andric   } else {
9085f757f3fSDimitry Andric     WriteIRToStream(dbgs(), M, IRName);
9095f757f3fSDimitry Andric   }
910e8d8bef9SDimitry Andric }
911e8d8bef9SDimitry Andric 
shouldPrintBeforePass(StringRef PassID)912e8d8bef9SDimitry Andric bool PrintIRInstrumentation::shouldPrintBeforePass(StringRef PassID) {
913e8d8bef9SDimitry Andric   if (shouldPrintBeforeAll())
914e8d8bef9SDimitry Andric     return true;
915e8d8bef9SDimitry Andric 
9161db9f3b2SDimitry Andric   if (shouldPrintBeforePassNumber() &&
9171db9f3b2SDimitry Andric       CurrentPassNumber == PrintBeforePassNumber)
9181db9f3b2SDimitry Andric     return true;
9191db9f3b2SDimitry Andric 
920e8d8bef9SDimitry Andric   StringRef PassName = PIC->getPassNameForClassName(PassID);
921349cc55cSDimitry Andric   return is_contained(printBeforePasses(), PassName);
922e8d8bef9SDimitry Andric }
923e8d8bef9SDimitry Andric 
shouldPrintAfterPass(StringRef PassID)924e8d8bef9SDimitry Andric bool PrintIRInstrumentation::shouldPrintAfterPass(StringRef PassID) {
925e8d8bef9SDimitry Andric   if (shouldPrintAfterAll())
926e8d8bef9SDimitry Andric     return true;
927e8d8bef9SDimitry Andric 
928e8d8bef9SDimitry Andric   StringRef PassName = PIC->getPassNameForClassName(PassID);
929349cc55cSDimitry Andric   return is_contained(printAfterPasses(), PassName);
9300b57cec5SDimitry Andric }
9310b57cec5SDimitry Andric 
shouldPrintPassNumbers()93206c3fb27SDimitry Andric bool PrintIRInstrumentation::shouldPrintPassNumbers() {
93306c3fb27SDimitry Andric   return PrintPassNumbers;
93406c3fb27SDimitry Andric }
93506c3fb27SDimitry Andric 
shouldPrintBeforePassNumber()9361db9f3b2SDimitry Andric bool PrintIRInstrumentation::shouldPrintBeforePassNumber() {
9371db9f3b2SDimitry Andric   return PrintBeforePassNumber > 0;
93806c3fb27SDimitry Andric }
93906c3fb27SDimitry Andric 
registerCallbacks(PassInstrumentationCallbacks & PIC)9400b57cec5SDimitry Andric void PrintIRInstrumentation::registerCallbacks(
9410b57cec5SDimitry Andric     PassInstrumentationCallbacks &PIC) {
942e8d8bef9SDimitry Andric   this->PIC = &PIC;
943e8d8bef9SDimitry Andric 
9440b57cec5SDimitry Andric   // BeforePass callback is not just for printing, it also saves a Module
9450b57cec5SDimitry Andric   // for later use in AfterPassInvalidated.
9461db9f3b2SDimitry Andric   if (shouldPrintPassNumbers() || shouldPrintBeforePassNumber() ||
94706c3fb27SDimitry Andric       shouldPrintBeforeSomePass() || shouldPrintAfterSomePass())
948e8d8bef9SDimitry Andric     PIC.registerBeforeNonSkippedPassCallback(
949e8d8bef9SDimitry Andric         [this](StringRef P, Any IR) { this->printBeforePass(P, IR); });
9500b57cec5SDimitry Andric 
9511db9f3b2SDimitry Andric   if (shouldPrintAfterSomePass()) {
9520b57cec5SDimitry Andric     PIC.registerAfterPassCallback(
953e8d8bef9SDimitry Andric         [this](StringRef P, Any IR, const PreservedAnalyses &) {
954e8d8bef9SDimitry Andric           this->printAfterPass(P, IR);
955e8d8bef9SDimitry Andric         });
9560b57cec5SDimitry Andric     PIC.registerAfterPassInvalidatedCallback(
957e8d8bef9SDimitry Andric         [this](StringRef P, const PreservedAnalyses &) {
958e8d8bef9SDimitry Andric           this->printAfterPassInvalidated(P);
959e8d8bef9SDimitry Andric         });
9600b57cec5SDimitry Andric   }
9610b57cec5SDimitry Andric }
9620b57cec5SDimitry Andric 
registerCallbacks(PassInstrumentationCallbacks & PIC)963e8d8bef9SDimitry Andric void OptNoneInstrumentation::registerCallbacks(
964e8d8bef9SDimitry Andric     PassInstrumentationCallbacks &PIC) {
965e8d8bef9SDimitry Andric   PIC.registerShouldRunOptionalPassCallback(
966e8d8bef9SDimitry Andric       [this](StringRef P, Any IR) { return this->shouldRun(P, IR); });
967e8d8bef9SDimitry Andric }
968e8d8bef9SDimitry Andric 
shouldRun(StringRef PassID,Any IR)969e8d8bef9SDimitry Andric bool OptNoneInstrumentation::shouldRun(StringRef PassID, Any IR) {
9705f757f3fSDimitry Andric   const auto *F = unwrapIR<Function>(IR);
971bdd1243dSDimitry Andric   if (!F) {
9725f757f3fSDimitry Andric     if (const auto *L = unwrapIR<Loop>(IR))
9735f757f3fSDimitry Andric       F = L->getHeader()->getParent();
974e8d8bef9SDimitry Andric   }
975e8d8bef9SDimitry Andric   bool ShouldRun = !(F && F->hasOptNone());
976e8d8bef9SDimitry Andric   if (!ShouldRun && DebugLogging) {
977e8d8bef9SDimitry Andric     errs() << "Skipping pass " << PassID << " on " << F->getName()
978e8d8bef9SDimitry Andric            << " due to optnone attribute\n";
979e8d8bef9SDimitry Andric   }
980e8d8bef9SDimitry Andric   return ShouldRun;
981e8d8bef9SDimitry Andric }
982e8d8bef9SDimitry Andric 
shouldRun(StringRef PassName,Any IR)983bdd1243dSDimitry Andric bool OptPassGateInstrumentation::shouldRun(StringRef PassName, Any IR) {
984bdd1243dSDimitry Andric   if (isIgnored(PassName))
985bdd1243dSDimitry Andric     return true;
986bdd1243dSDimitry Andric 
987bdd1243dSDimitry Andric   bool ShouldRun =
988bdd1243dSDimitry Andric       Context.getOptPassGate().shouldRunPass(PassName, getIRName(IR));
989bdd1243dSDimitry Andric   if (!ShouldRun && !this->HasWrittenIR && !OptBisectPrintIRPath.empty()) {
990bdd1243dSDimitry Andric     // FIXME: print IR if limit is higher than number of opt-bisect
991bdd1243dSDimitry Andric     // invocations
992bdd1243dSDimitry Andric     this->HasWrittenIR = true;
993bdd1243dSDimitry Andric     const Module *M = unwrapModule(IR, /*Force=*/true);
994bdd1243dSDimitry Andric     assert((M && &M->getContext() == &Context) && "Missing/Mismatching Module");
995bdd1243dSDimitry Andric     std::error_code EC;
996bdd1243dSDimitry Andric     raw_fd_ostream OS(OptBisectPrintIRPath, EC);
997bdd1243dSDimitry Andric     if (EC)
998bdd1243dSDimitry Andric       report_fatal_error(errorCodeToError(EC));
999bdd1243dSDimitry Andric     M->print(OS, nullptr);
1000bdd1243dSDimitry Andric   }
1001bdd1243dSDimitry Andric   return ShouldRun;
1002bdd1243dSDimitry Andric }
1003bdd1243dSDimitry Andric 
registerCallbacks(PassInstrumentationCallbacks & PIC)1004bdd1243dSDimitry Andric void OptPassGateInstrumentation::registerCallbacks(
1005e8d8bef9SDimitry Andric     PassInstrumentationCallbacks &PIC) {
1006bdd1243dSDimitry Andric   OptPassGate &PassGate = Context.getOptPassGate();
1007bdd1243dSDimitry Andric   if (!PassGate.isEnabled())
1008e8d8bef9SDimitry Andric     return;
1009bdd1243dSDimitry Andric 
1010bdd1243dSDimitry Andric   PIC.registerShouldRunOptionalPassCallback([this](StringRef PassName, Any IR) {
1011bdd1243dSDimitry Andric     return this->shouldRun(PassName, IR);
1012e8d8bef9SDimitry Andric   });
1013e8d8bef9SDimitry Andric }
1014e8d8bef9SDimitry Andric 
print()1015fe6060f1SDimitry Andric raw_ostream &PrintPassInstrumentation::print() {
1016fe6060f1SDimitry Andric   if (Opts.Indent) {
1017fe6060f1SDimitry Andric     assert(Indent >= 0);
1018fe6060f1SDimitry Andric     dbgs().indent(Indent);
1019fe6060f1SDimitry Andric   }
1020fe6060f1SDimitry Andric   return dbgs();
1021fe6060f1SDimitry Andric }
1022fe6060f1SDimitry Andric 
registerCallbacks(PassInstrumentationCallbacks & PIC)1023e8d8bef9SDimitry Andric void PrintPassInstrumentation::registerCallbacks(
1024e8d8bef9SDimitry Andric     PassInstrumentationCallbacks &PIC) {
1025fe6060f1SDimitry Andric   if (!Enabled)
1026e8d8bef9SDimitry Andric     return;
1027e8d8bef9SDimitry Andric 
1028fe6060f1SDimitry Andric   std::vector<StringRef> SpecialPasses;
1029fe6060f1SDimitry Andric   if (!Opts.Verbose) {
1030fe6060f1SDimitry Andric     SpecialPasses.emplace_back("PassManager");
1031e8d8bef9SDimitry Andric     SpecialPasses.emplace_back("PassAdaptor");
1032fe6060f1SDimitry Andric   }
1033e8d8bef9SDimitry Andric 
1034349cc55cSDimitry Andric   PIC.registerBeforeSkippedPassCallback([this, SpecialPasses](StringRef PassID,
1035349cc55cSDimitry Andric                                                               Any IR) {
1036e8d8bef9SDimitry Andric     assert(!isSpecialPass(PassID, SpecialPasses) &&
1037e8d8bef9SDimitry Andric            "Unexpectedly skipping special pass");
1038e8d8bef9SDimitry Andric 
1039349cc55cSDimitry Andric     print() << "Skipping pass: " << PassID << " on " << getIRName(IR) << "\n";
1040e8d8bef9SDimitry Andric   });
1041fe6060f1SDimitry Andric   PIC.registerBeforeNonSkippedPassCallback([this, SpecialPasses](
1042fe6060f1SDimitry Andric                                                StringRef PassID, Any IR) {
1043e8d8bef9SDimitry Andric     if (isSpecialPass(PassID, SpecialPasses))
1044e8d8bef9SDimitry Andric       return;
1045e8d8bef9SDimitry Andric 
1046fcaf7f86SDimitry Andric     auto &OS = print();
1047fcaf7f86SDimitry Andric     OS << "Running pass: " << PassID << " on " << getIRName(IR);
10485f757f3fSDimitry Andric     if (const auto *F = unwrapIR<Function>(IR)) {
10495f757f3fSDimitry Andric       unsigned Count = F->getInstructionCount();
1050fcaf7f86SDimitry Andric       OS << " (" << Count << " instruction";
1051fcaf7f86SDimitry Andric       if (Count != 1)
1052fcaf7f86SDimitry Andric         OS << 's';
1053fcaf7f86SDimitry Andric       OS << ')';
10545f757f3fSDimitry Andric     } else if (const auto *C = unwrapIR<LazyCallGraph::SCC>(IR)) {
10555f757f3fSDimitry Andric       int Count = C->size();
1056fcaf7f86SDimitry Andric       OS << " (" << Count << " node";
1057fcaf7f86SDimitry Andric       if (Count != 1)
1058fcaf7f86SDimitry Andric         OS << 's';
1059fcaf7f86SDimitry Andric       OS << ')';
1060fcaf7f86SDimitry Andric     }
1061fcaf7f86SDimitry Andric     OS << "\n";
1062fe6060f1SDimitry Andric     Indent += 2;
1063fe6060f1SDimitry Andric   });
1064fe6060f1SDimitry Andric   PIC.registerAfterPassCallback(
1065fe6060f1SDimitry Andric       [this, SpecialPasses](StringRef PassID, Any IR,
1066fe6060f1SDimitry Andric                             const PreservedAnalyses &) {
1067fe6060f1SDimitry Andric         if (isSpecialPass(PassID, SpecialPasses))
1068fe6060f1SDimitry Andric           return;
1069fe6060f1SDimitry Andric 
1070fe6060f1SDimitry Andric         Indent -= 2;
1071fe6060f1SDimitry Andric       });
1072fe6060f1SDimitry Andric   PIC.registerAfterPassInvalidatedCallback(
1073fe6060f1SDimitry Andric       [this, SpecialPasses](StringRef PassID, Any IR) {
1074fe6060f1SDimitry Andric         if (isSpecialPass(PassID, SpecialPasses))
1075fe6060f1SDimitry Andric           return;
1076fe6060f1SDimitry Andric 
1077fe6060f1SDimitry Andric         Indent -= 2;
1078e8d8bef9SDimitry Andric       });
1079e8d8bef9SDimitry Andric 
1080fe6060f1SDimitry Andric   if (!Opts.SkipAnalyses) {
1081fe6060f1SDimitry Andric     PIC.registerBeforeAnalysisCallback([this](StringRef PassID, Any IR) {
1082fe6060f1SDimitry Andric       print() << "Running analysis: " << PassID << " on " << getIRName(IR)
1083fe6060f1SDimitry Andric               << "\n";
1084fe6060f1SDimitry Andric       Indent += 2;
1085e8d8bef9SDimitry Andric     });
1086fe6060f1SDimitry Andric     PIC.registerAfterAnalysisCallback(
1087fe6060f1SDimitry Andric         [this](StringRef PassID, Any IR) { Indent -= 2; });
1088fe6060f1SDimitry Andric     PIC.registerAnalysisInvalidatedCallback([this](StringRef PassID, Any IR) {
1089fe6060f1SDimitry Andric       print() << "Invalidating analysis: " << PassID << " on " << getIRName(IR)
1090fe6060f1SDimitry Andric               << "\n";
1091fe6060f1SDimitry Andric     });
1092fe6060f1SDimitry Andric     PIC.registerAnalysesClearedCallback([this](StringRef IRName) {
1093fe6060f1SDimitry Andric       print() << "Clearing all analysis results for: " << IRName << "\n";
1094fe6060f1SDimitry Andric     });
1095fe6060f1SDimitry Andric   }
1096e8d8bef9SDimitry Andric }
1097e8d8bef9SDimitry Andric 
CFG(const Function * F,bool TrackBBLifetime)1098e8d8bef9SDimitry Andric PreservedCFGCheckerInstrumentation::CFG::CFG(const Function *F,
1099e8d8bef9SDimitry Andric                                              bool TrackBBLifetime) {
1100e8d8bef9SDimitry Andric   if (TrackBBLifetime)
1101e8d8bef9SDimitry Andric     BBGuards = DenseMap<intptr_t, BBGuard>(F->size());
1102e8d8bef9SDimitry Andric   for (const auto &BB : *F) {
1103e8d8bef9SDimitry Andric     if (BBGuards)
1104e8d8bef9SDimitry Andric       BBGuards->try_emplace(intptr_t(&BB), &BB);
1105bdd1243dSDimitry Andric     for (const auto *Succ : successors(&BB)) {
1106e8d8bef9SDimitry Andric       Graph[&BB][Succ]++;
1107e8d8bef9SDimitry Andric       if (BBGuards)
1108e8d8bef9SDimitry Andric         BBGuards->try_emplace(intptr_t(Succ), Succ);
1109e8d8bef9SDimitry Andric     }
1110e8d8bef9SDimitry Andric   }
1111e8d8bef9SDimitry Andric }
1112e8d8bef9SDimitry Andric 
printBBName(raw_ostream & out,const BasicBlock * BB)1113e8d8bef9SDimitry Andric static void printBBName(raw_ostream &out, const BasicBlock *BB) {
1114e8d8bef9SDimitry Andric   if (BB->hasName()) {
1115e8d8bef9SDimitry Andric     out << BB->getName() << "<" << BB << ">";
1116e8d8bef9SDimitry Andric     return;
1117e8d8bef9SDimitry Andric   }
1118e8d8bef9SDimitry Andric 
1119e8d8bef9SDimitry Andric   if (!BB->getParent()) {
1120e8d8bef9SDimitry Andric     out << "unnamed_removed<" << BB << ">";
1121e8d8bef9SDimitry Andric     return;
1122e8d8bef9SDimitry Andric   }
1123e8d8bef9SDimitry Andric 
1124fe6060f1SDimitry Andric   if (BB->isEntryBlock()) {
1125e8d8bef9SDimitry Andric     out << "entry"
1126e8d8bef9SDimitry Andric         << "<" << BB << ">";
1127e8d8bef9SDimitry Andric     return;
1128e8d8bef9SDimitry Andric   }
1129e8d8bef9SDimitry Andric 
1130e8d8bef9SDimitry Andric   unsigned FuncOrderBlockNum = 0;
1131e8d8bef9SDimitry Andric   for (auto &FuncBB : *BB->getParent()) {
1132e8d8bef9SDimitry Andric     if (&FuncBB == BB)
1133e8d8bef9SDimitry Andric       break;
1134e8d8bef9SDimitry Andric     FuncOrderBlockNum++;
1135e8d8bef9SDimitry Andric   }
1136e8d8bef9SDimitry Andric   out << "unnamed_" << FuncOrderBlockNum << "<" << BB << ">";
1137e8d8bef9SDimitry Andric }
1138e8d8bef9SDimitry Andric 
printDiff(raw_ostream & out,const CFG & Before,const CFG & After)1139e8d8bef9SDimitry Andric void PreservedCFGCheckerInstrumentation::CFG::printDiff(raw_ostream &out,
1140e8d8bef9SDimitry Andric                                                         const CFG &Before,
1141e8d8bef9SDimitry Andric                                                         const CFG &After) {
1142e8d8bef9SDimitry Andric   assert(!After.isPoisoned());
1143e8d8bef9SDimitry Andric   if (Before.isPoisoned()) {
1144e8d8bef9SDimitry Andric     out << "Some blocks were deleted\n";
1145e8d8bef9SDimitry Andric     return;
1146e8d8bef9SDimitry Andric   }
1147e8d8bef9SDimitry Andric 
1148e8d8bef9SDimitry Andric   // Find and print graph differences.
1149e8d8bef9SDimitry Andric   if (Before.Graph.size() != After.Graph.size())
1150e8d8bef9SDimitry Andric     out << "Different number of non-leaf basic blocks: before="
1151e8d8bef9SDimitry Andric         << Before.Graph.size() << ", after=" << After.Graph.size() << "\n";
1152e8d8bef9SDimitry Andric 
1153e8d8bef9SDimitry Andric   for (auto &BB : Before.Graph) {
1154e8d8bef9SDimitry Andric     auto BA = After.Graph.find(BB.first);
1155e8d8bef9SDimitry Andric     if (BA == After.Graph.end()) {
1156e8d8bef9SDimitry Andric       out << "Non-leaf block ";
1157e8d8bef9SDimitry Andric       printBBName(out, BB.first);
1158e8d8bef9SDimitry Andric       out << " is removed (" << BB.second.size() << " successors)\n";
1159e8d8bef9SDimitry Andric     }
1160e8d8bef9SDimitry Andric   }
1161e8d8bef9SDimitry Andric 
1162e8d8bef9SDimitry Andric   for (auto &BA : After.Graph) {
1163e8d8bef9SDimitry Andric     auto BB = Before.Graph.find(BA.first);
1164e8d8bef9SDimitry Andric     if (BB == Before.Graph.end()) {
1165e8d8bef9SDimitry Andric       out << "Non-leaf block ";
1166e8d8bef9SDimitry Andric       printBBName(out, BA.first);
1167e8d8bef9SDimitry Andric       out << " is added (" << BA.second.size() << " successors)\n";
1168e8d8bef9SDimitry Andric       continue;
1169e8d8bef9SDimitry Andric     }
1170e8d8bef9SDimitry Andric 
1171e8d8bef9SDimitry Andric     if (BB->second == BA.second)
1172e8d8bef9SDimitry Andric       continue;
1173e8d8bef9SDimitry Andric 
1174e8d8bef9SDimitry Andric     out << "Different successors of block ";
1175e8d8bef9SDimitry Andric     printBBName(out, BA.first);
1176e8d8bef9SDimitry Andric     out << " (unordered):\n";
1177e8d8bef9SDimitry Andric     out << "- before (" << BB->second.size() << "): ";
1178e8d8bef9SDimitry Andric     for (auto &SuccB : BB->second) {
1179e8d8bef9SDimitry Andric       printBBName(out, SuccB.first);
1180e8d8bef9SDimitry Andric       if (SuccB.second != 1)
1181e8d8bef9SDimitry Andric         out << "(" << SuccB.second << "), ";
1182e8d8bef9SDimitry Andric       else
1183e8d8bef9SDimitry Andric         out << ", ";
1184e8d8bef9SDimitry Andric     }
1185e8d8bef9SDimitry Andric     out << "\n";
1186e8d8bef9SDimitry Andric     out << "- after (" << BA.second.size() << "): ";
1187e8d8bef9SDimitry Andric     for (auto &SuccA : BA.second) {
1188e8d8bef9SDimitry Andric       printBBName(out, SuccA.first);
1189e8d8bef9SDimitry Andric       if (SuccA.second != 1)
1190e8d8bef9SDimitry Andric         out << "(" << SuccA.second << "), ";
1191e8d8bef9SDimitry Andric       else
1192e8d8bef9SDimitry Andric         out << ", ";
1193e8d8bef9SDimitry Andric     }
1194e8d8bef9SDimitry Andric     out << "\n";
1195e8d8bef9SDimitry Andric   }
1196e8d8bef9SDimitry Andric }
1197e8d8bef9SDimitry Andric 
1198fe6060f1SDimitry Andric // PreservedCFGCheckerInstrumentation uses PreservedCFGCheckerAnalysis to check
1199fe6060f1SDimitry Andric // passes, that reported they kept CFG analyses up-to-date, did not actually
1200fe6060f1SDimitry Andric // change CFG. This check is done as follows. Before every functional pass in
1201fe6060f1SDimitry Andric // BeforeNonSkippedPassCallback a CFG snapshot (an instance of
1202fe6060f1SDimitry Andric // PreservedCFGCheckerInstrumentation::CFG) is requested from
1203fe6060f1SDimitry Andric // FunctionAnalysisManager as a result of PreservedCFGCheckerAnalysis. When the
1204fe6060f1SDimitry Andric // functional pass finishes and reports that CFGAnalyses or AllAnalyses are
1205fe6060f1SDimitry Andric // up-to-date then the cached result of PreservedCFGCheckerAnalysis (if
1206fe6060f1SDimitry Andric // available) is checked to be equal to a freshly created CFG snapshot.
1207fe6060f1SDimitry Andric struct PreservedCFGCheckerAnalysis
1208fe6060f1SDimitry Andric     : public AnalysisInfoMixin<PreservedCFGCheckerAnalysis> {
1209fe6060f1SDimitry Andric   friend AnalysisInfoMixin<PreservedCFGCheckerAnalysis>;
1210fe6060f1SDimitry Andric 
1211fe6060f1SDimitry Andric   static AnalysisKey Key;
1212fe6060f1SDimitry Andric 
1213fe6060f1SDimitry Andric public:
1214fe6060f1SDimitry Andric   /// Provide the result type for this analysis pass.
1215fe6060f1SDimitry Andric   using Result = PreservedCFGCheckerInstrumentation::CFG;
1216fe6060f1SDimitry Andric 
1217fe6060f1SDimitry Andric   /// Run the analysis pass over a function and produce CFG.
runPreservedCFGCheckerAnalysis1218fe6060f1SDimitry Andric   Result run(Function &F, FunctionAnalysisManager &FAM) {
1219fe6060f1SDimitry Andric     return Result(&F, /* TrackBBLifetime */ true);
1220fe6060f1SDimitry Andric   }
1221fe6060f1SDimitry Andric };
1222fe6060f1SDimitry Andric 
1223fe6060f1SDimitry Andric AnalysisKey PreservedCFGCheckerAnalysis::Key;
1224fe6060f1SDimitry Andric 
122506c3fb27SDimitry Andric struct PreservedFunctionHashAnalysis
122606c3fb27SDimitry Andric     : public AnalysisInfoMixin<PreservedFunctionHashAnalysis> {
122706c3fb27SDimitry Andric   static AnalysisKey Key;
122806c3fb27SDimitry Andric 
122906c3fb27SDimitry Andric   struct FunctionHash {
123006c3fb27SDimitry Andric     uint64_t Hash;
123106c3fb27SDimitry Andric   };
123206c3fb27SDimitry Andric 
123306c3fb27SDimitry Andric   using Result = FunctionHash;
123406c3fb27SDimitry Andric 
runPreservedFunctionHashAnalysis123506c3fb27SDimitry Andric   Result run(Function &F, FunctionAnalysisManager &FAM) {
123606c3fb27SDimitry Andric     return Result{StructuralHash(F)};
123706c3fb27SDimitry Andric   }
123806c3fb27SDimitry Andric };
123906c3fb27SDimitry Andric 
124006c3fb27SDimitry Andric AnalysisKey PreservedFunctionHashAnalysis::Key;
124106c3fb27SDimitry Andric 
124206c3fb27SDimitry Andric struct PreservedModuleHashAnalysis
124306c3fb27SDimitry Andric     : public AnalysisInfoMixin<PreservedModuleHashAnalysis> {
124406c3fb27SDimitry Andric   static AnalysisKey Key;
124506c3fb27SDimitry Andric 
124606c3fb27SDimitry Andric   struct ModuleHash {
124706c3fb27SDimitry Andric     uint64_t Hash;
124806c3fb27SDimitry Andric   };
124906c3fb27SDimitry Andric 
125006c3fb27SDimitry Andric   using Result = ModuleHash;
125106c3fb27SDimitry Andric 
runPreservedModuleHashAnalysis125206c3fb27SDimitry Andric   Result run(Module &F, ModuleAnalysisManager &FAM) {
125306c3fb27SDimitry Andric     return Result{StructuralHash(F)};
125406c3fb27SDimitry Andric   }
125506c3fb27SDimitry Andric };
125606c3fb27SDimitry Andric 
125706c3fb27SDimitry Andric AnalysisKey PreservedModuleHashAnalysis::Key;
125806c3fb27SDimitry Andric 
invalidate(Function & F,const PreservedAnalyses & PA,FunctionAnalysisManager::Invalidator &)1259fe6060f1SDimitry Andric bool PreservedCFGCheckerInstrumentation::CFG::invalidate(
1260fe6060f1SDimitry Andric     Function &F, const PreservedAnalyses &PA,
1261fe6060f1SDimitry Andric     FunctionAnalysisManager::Invalidator &) {
1262fe6060f1SDimitry Andric   auto PAC = PA.getChecker<PreservedCFGCheckerAnalysis>();
1263fe6060f1SDimitry Andric   return !(PAC.preserved() || PAC.preservedSet<AllAnalysesOn<Function>>() ||
1264fe6060f1SDimitry Andric            PAC.preservedSet<CFGAnalyses>());
1265fe6060f1SDimitry Andric }
1266fe6060f1SDimitry Andric 
GetFunctions(Any IR)126706c3fb27SDimitry Andric static SmallVector<Function *, 1> GetFunctions(Any IR) {
126806c3fb27SDimitry Andric   SmallVector<Function *, 1> Functions;
126906c3fb27SDimitry Andric 
12705f757f3fSDimitry Andric   if (const auto *MaybeF = unwrapIR<Function>(IR)) {
12715f757f3fSDimitry Andric     Functions.push_back(const_cast<Function *>(MaybeF));
12725f757f3fSDimitry Andric   } else if (const auto *MaybeM = unwrapIR<Module>(IR)) {
12735f757f3fSDimitry Andric     for (Function &F : *const_cast<Module *>(MaybeM))
127406c3fb27SDimitry Andric       Functions.push_back(&F);
127506c3fb27SDimitry Andric   }
127606c3fb27SDimitry Andric   return Functions;
127706c3fb27SDimitry Andric }
127806c3fb27SDimitry Andric 
registerCallbacks(PassInstrumentationCallbacks & PIC,ModuleAnalysisManager & MAM)1279e8d8bef9SDimitry Andric void PreservedCFGCheckerInstrumentation::registerCallbacks(
128006c3fb27SDimitry Andric     PassInstrumentationCallbacks &PIC, ModuleAnalysisManager &MAM) {
128106c3fb27SDimitry Andric   if (!VerifyAnalysisInvalidation)
1282e8d8bef9SDimitry Andric     return;
1283e8d8bef9SDimitry Andric 
128406c3fb27SDimitry Andric   bool Registered = false;
128506c3fb27SDimitry Andric   PIC.registerBeforeNonSkippedPassCallback([this, &MAM, Registered](
128606c3fb27SDimitry Andric                                                StringRef P, Any IR) mutable {
1287fe6060f1SDimitry Andric #ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
1288fe6060f1SDimitry Andric     assert(&PassStack.emplace_back(P));
1289fe6060f1SDimitry Andric #endif
1290fe6060f1SDimitry Andric     (void)this;
1291fe6060f1SDimitry Andric 
129206c3fb27SDimitry Andric     auto &FAM = MAM.getResult<FunctionAnalysisManagerModuleProxy>(
129306c3fb27SDimitry Andric                        *const_cast<Module *>(unwrapModule(IR, /*Force=*/true)))
129406c3fb27SDimitry Andric                     .getManager();
129506c3fb27SDimitry Andric     if (!Registered) {
129606c3fb27SDimitry Andric       FAM.registerPass([&] { return PreservedCFGCheckerAnalysis(); });
129706c3fb27SDimitry Andric       FAM.registerPass([&] { return PreservedFunctionHashAnalysis(); });
129806c3fb27SDimitry Andric       MAM.registerPass([&] { return PreservedModuleHashAnalysis(); });
129906c3fb27SDimitry Andric       Registered = true;
130006c3fb27SDimitry Andric     }
130106c3fb27SDimitry Andric 
130206c3fb27SDimitry Andric     for (Function *F : GetFunctions(IR)) {
1303fe6060f1SDimitry Andric       // Make sure a fresh CFG snapshot is available before the pass.
130406c3fb27SDimitry Andric       FAM.getResult<PreservedCFGCheckerAnalysis>(*F);
130506c3fb27SDimitry Andric       FAM.getResult<PreservedFunctionHashAnalysis>(*F);
130606c3fb27SDimitry Andric     }
130706c3fb27SDimitry Andric 
13085f757f3fSDimitry Andric     if (const auto *MPtr = unwrapIR<Module>(IR)) {
13095f757f3fSDimitry Andric       auto &M = *const_cast<Module *>(MPtr);
131006c3fb27SDimitry Andric       MAM.getResult<PreservedModuleHashAnalysis>(M);
131106c3fb27SDimitry Andric     }
1312e8d8bef9SDimitry Andric   });
1313e8d8bef9SDimitry Andric 
1314e8d8bef9SDimitry Andric   PIC.registerAfterPassInvalidatedCallback(
1315e8d8bef9SDimitry Andric       [this](StringRef P, const PreservedAnalyses &PassPA) {
1316fe6060f1SDimitry Andric #ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
1317fe6060f1SDimitry Andric         assert(PassStack.pop_back_val() == P &&
1318e8d8bef9SDimitry Andric                "Before and After callbacks must correspond");
1319fe6060f1SDimitry Andric #endif
1320fe6060f1SDimitry Andric         (void)this;
1321e8d8bef9SDimitry Andric       });
1322e8d8bef9SDimitry Andric 
132306c3fb27SDimitry Andric   PIC.registerAfterPassCallback([this, &MAM](StringRef P, Any IR,
1324e8d8bef9SDimitry Andric                                              const PreservedAnalyses &PassPA) {
1325fe6060f1SDimitry Andric #ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
1326fe6060f1SDimitry Andric     assert(PassStack.pop_back_val() == P &&
1327fe6060f1SDimitry Andric            "Before and After callbacks must correspond");
1328fe6060f1SDimitry Andric #endif
1329fe6060f1SDimitry Andric     (void)this;
1330e8d8bef9SDimitry Andric 
133106c3fb27SDimitry Andric     // We have to get the FAM via the MAM, rather than directly use a passed in
133206c3fb27SDimitry Andric     // FAM because if MAM has not cached the FAM, it won't invalidate function
133306c3fb27SDimitry Andric     // analyses in FAM.
133406c3fb27SDimitry Andric     auto &FAM = MAM.getResult<FunctionAnalysisManagerModuleProxy>(
133506c3fb27SDimitry Andric                        *const_cast<Module *>(unwrapModule(IR, /*Force=*/true)))
133606c3fb27SDimitry Andric                     .getManager();
133706c3fb27SDimitry Andric 
133806c3fb27SDimitry Andric     for (Function *F : GetFunctions(IR)) {
133906c3fb27SDimitry Andric       if (auto *HashBefore =
134006c3fb27SDimitry Andric               FAM.getCachedResult<PreservedFunctionHashAnalysis>(*F)) {
134106c3fb27SDimitry Andric         if (HashBefore->Hash != StructuralHash(*F)) {
134206c3fb27SDimitry Andric           report_fatal_error(formatv(
134306c3fb27SDimitry Andric               "Function @{0} changed by {1} without invalidating analyses",
134406c3fb27SDimitry Andric               F->getName(), P));
134506c3fb27SDimitry Andric         }
134606c3fb27SDimitry Andric       }
134706c3fb27SDimitry Andric 
134806c3fb27SDimitry Andric       auto CheckCFG = [](StringRef Pass, StringRef FuncName,
134906c3fb27SDimitry Andric                          const CFG &GraphBefore, const CFG &GraphAfter) {
135006c3fb27SDimitry Andric         if (GraphAfter == GraphBefore)
1351e8d8bef9SDimitry Andric           return;
1352e8d8bef9SDimitry Andric 
135306c3fb27SDimitry Andric         dbgs()
135406c3fb27SDimitry Andric             << "Error: " << Pass
135506c3fb27SDimitry Andric             << " does not invalidate CFG analyses but CFG changes detected in "
135606c3fb27SDimitry Andric                "function @"
135706c3fb27SDimitry Andric             << FuncName << ":\n";
135806c3fb27SDimitry Andric         CFG::printDiff(dbgs(), GraphBefore, GraphAfter);
135906c3fb27SDimitry Andric         report_fatal_error(Twine("CFG unexpectedly changed by ", Pass));
136006c3fb27SDimitry Andric       };
1361e8d8bef9SDimitry Andric 
136206c3fb27SDimitry Andric       if (auto *GraphBefore =
136306c3fb27SDimitry Andric               FAM.getCachedResult<PreservedCFGCheckerAnalysis>(*F))
136406c3fb27SDimitry Andric         CheckCFG(P, F->getName(), *GraphBefore,
136506c3fb27SDimitry Andric                  CFG(F, /* TrackBBLifetime */ false));
136606c3fb27SDimitry Andric     }
13675f757f3fSDimitry Andric     if (const auto *MPtr = unwrapIR<Module>(IR)) {
13685f757f3fSDimitry Andric       auto &M = *const_cast<Module *>(MPtr);
136906c3fb27SDimitry Andric       if (auto *HashBefore =
137006c3fb27SDimitry Andric               MAM.getCachedResult<PreservedModuleHashAnalysis>(M)) {
137106c3fb27SDimitry Andric         if (HashBefore->Hash != StructuralHash(M)) {
137206c3fb27SDimitry Andric           report_fatal_error(formatv(
137306c3fb27SDimitry Andric               "Module changed by {0} without invalidating analyses", P));
137406c3fb27SDimitry Andric         }
137506c3fb27SDimitry Andric       }
137606c3fb27SDimitry Andric     }
1377e8d8bef9SDimitry Andric   });
1378e8d8bef9SDimitry Andric }
1379e8d8bef9SDimitry Andric 
registerCallbacks(PassInstrumentationCallbacks & PIC)1380e8d8bef9SDimitry Andric void VerifyInstrumentation::registerCallbacks(
1381e8d8bef9SDimitry Andric     PassInstrumentationCallbacks &PIC) {
1382e8d8bef9SDimitry Andric   PIC.registerAfterPassCallback(
1383e8d8bef9SDimitry Andric       [this](StringRef P, Any IR, const PreservedAnalyses &PassPA) {
1384e8d8bef9SDimitry Andric         if (isIgnored(P) || P == "VerifierPass")
1385e8d8bef9SDimitry Andric           return;
13865f757f3fSDimitry Andric         const auto *F = unwrapIR<Function>(IR);
1387bdd1243dSDimitry Andric         if (!F) {
13885f757f3fSDimitry Andric           if (const auto *L = unwrapIR<Loop>(IR))
13895f757f3fSDimitry Andric             F = L->getHeader()->getParent();
1390bdd1243dSDimitry Andric         }
1391bdd1243dSDimitry Andric 
1392bdd1243dSDimitry Andric         if (F) {
1393e8d8bef9SDimitry Andric           if (DebugLogging)
1394e8d8bef9SDimitry Andric             dbgs() << "Verifying function " << F->getName() << "\n";
1395e8d8bef9SDimitry Andric 
139681ad6265SDimitry Andric           if (verifyFunction(*F, &errs()))
13975f757f3fSDimitry Andric             report_fatal_error(formatv("Broken function found after pass "
13985f757f3fSDimitry Andric                                        "\"{0}\", compilation aborted!",
13995f757f3fSDimitry Andric                                        P));
1400bdd1243dSDimitry Andric         } else {
14015f757f3fSDimitry Andric           const auto *M = unwrapIR<Module>(IR);
1402bdd1243dSDimitry Andric           if (!M) {
14035f757f3fSDimitry Andric             if (const auto *C = unwrapIR<LazyCallGraph::SCC>(IR))
14045f757f3fSDimitry Andric               M = C->begin()->getFunction().getParent();
1405bdd1243dSDimitry Andric           }
1406bdd1243dSDimitry Andric 
1407bdd1243dSDimitry Andric           if (M) {
1408e8d8bef9SDimitry Andric             if (DebugLogging)
1409e8d8bef9SDimitry Andric               dbgs() << "Verifying module " << M->getName() << "\n";
1410e8d8bef9SDimitry Andric 
141181ad6265SDimitry Andric             if (verifyModule(*M, &errs()))
14125f757f3fSDimitry Andric               report_fatal_error(formatv("Broken module found after pass "
14135f757f3fSDimitry Andric                                          "\"{0}\", compilation aborted!",
14145f757f3fSDimitry Andric                                          P));
1415e8d8bef9SDimitry Andric           }
1416bdd1243dSDimitry Andric         }
1417e8d8bef9SDimitry Andric       });
1418e8d8bef9SDimitry Andric }
1419e8d8bef9SDimitry Andric 
142081ad6265SDimitry Andric InLineChangePrinter::~InLineChangePrinter() = default;
1421fe6060f1SDimitry Andric 
generateIRRepresentation(Any IR,StringRef PassID,IRDataT<EmptyData> & D)1422bdd1243dSDimitry Andric void InLineChangePrinter::generateIRRepresentation(Any IR,
1423bdd1243dSDimitry Andric                                                    StringRef PassID,
1424349cc55cSDimitry Andric                                                    IRDataT<EmptyData> &D) {
1425349cc55cSDimitry Andric   IRComparer<EmptyData>::analyzeIR(IR, D);
1426fe6060f1SDimitry Andric }
1427fe6060f1SDimitry Andric 
handleAfter(StringRef PassID,std::string & Name,const IRDataT<EmptyData> & Before,const IRDataT<EmptyData> & After,Any IR)1428fe6060f1SDimitry Andric void InLineChangePrinter::handleAfter(StringRef PassID, std::string &Name,
1429349cc55cSDimitry Andric                                       const IRDataT<EmptyData> &Before,
1430bdd1243dSDimitry Andric                                       const IRDataT<EmptyData> &After,
1431bdd1243dSDimitry Andric                                       Any IR) {
1432fe6060f1SDimitry Andric   SmallString<20> Banner =
1433fe6060f1SDimitry Andric       formatv("*** IR Dump After {0} on {1} ***\n", PassID, Name);
1434fe6060f1SDimitry Andric   Out << Banner;
1435349cc55cSDimitry Andric   IRComparer<EmptyData>(Before, After)
1436349cc55cSDimitry Andric       .compare(getModuleForComparison(IR),
1437349cc55cSDimitry Andric                [&](bool InModule, unsigned Minor,
1438349cc55cSDimitry Andric                    const FuncDataT<EmptyData> &Before,
1439349cc55cSDimitry Andric                    const FuncDataT<EmptyData> &After) -> void {
1440349cc55cSDimitry Andric                  handleFunctionCompare(Name, "", PassID, " on ", InModule,
1441349cc55cSDimitry Andric                                        Minor, Before, After);
1442349cc55cSDimitry Andric                });
1443fe6060f1SDimitry Andric   Out << "\n";
1444fe6060f1SDimitry Andric }
1445fe6060f1SDimitry Andric 
handleFunctionCompare(StringRef Name,StringRef Prefix,StringRef PassID,StringRef Divider,bool InModule,unsigned Minor,const FuncDataT<EmptyData> & Before,const FuncDataT<EmptyData> & After)1446349cc55cSDimitry Andric void InLineChangePrinter::handleFunctionCompare(
1447349cc55cSDimitry Andric     StringRef Name, StringRef Prefix, StringRef PassID, StringRef Divider,
1448349cc55cSDimitry Andric     bool InModule, unsigned Minor, const FuncDataT<EmptyData> &Before,
1449349cc55cSDimitry Andric     const FuncDataT<EmptyData> &After) {
1450fe6060f1SDimitry Andric   // Print a banner when this is being shown in the context of a module
1451fe6060f1SDimitry Andric   if (InModule)
1452fe6060f1SDimitry Andric     Out << "\n*** IR for function " << Name << " ***\n";
1453fe6060f1SDimitry Andric 
1454349cc55cSDimitry Andric   FuncDataT<EmptyData>::report(
1455349cc55cSDimitry Andric       Before, After,
1456349cc55cSDimitry Andric       [&](const BlockDataT<EmptyData> *B, const BlockDataT<EmptyData> *A) {
1457fe6060f1SDimitry Andric         StringRef BStr = B ? B->getBody() : "\n";
1458fe6060f1SDimitry Andric         StringRef AStr = A ? A->getBody() : "\n";
1459fe6060f1SDimitry Andric         const std::string Removed =
1460fe6060f1SDimitry Andric             UseColour ? "\033[31m-%l\033[0m\n" : "-%l\n";
1461fe6060f1SDimitry Andric         const std::string Added = UseColour ? "\033[32m+%l\033[0m\n" : "+%l\n";
1462fe6060f1SDimitry Andric         const std::string NoChange = " %l\n";
1463fe6060f1SDimitry Andric         Out << doSystemDiff(BStr, AStr, Removed, Added, NoChange);
1464fe6060f1SDimitry Andric       });
1465fe6060f1SDimitry Andric }
1466fe6060f1SDimitry Andric 
registerCallbacks(PassInstrumentationCallbacks & PIC)1467fe6060f1SDimitry Andric void InLineChangePrinter::registerCallbacks(PassInstrumentationCallbacks &PIC) {
1468fcaf7f86SDimitry Andric   if (PrintChanged == ChangePrinter::DiffVerbose ||
1469fcaf7f86SDimitry Andric       PrintChanged == ChangePrinter::DiffQuiet ||
1470fcaf7f86SDimitry Andric       PrintChanged == ChangePrinter::ColourDiffVerbose ||
1471fcaf7f86SDimitry Andric       PrintChanged == ChangePrinter::ColourDiffQuiet)
1472349cc55cSDimitry Andric     TextChangeReporter<IRDataT<EmptyData>>::registerRequiredCallbacks(PIC);
1473349cc55cSDimitry Andric }
1474349cc55cSDimitry Andric 
TimeProfilingPassesHandler()1475bdd1243dSDimitry Andric TimeProfilingPassesHandler::TimeProfilingPassesHandler() {}
1476bdd1243dSDimitry Andric 
registerCallbacks(PassInstrumentationCallbacks & PIC)1477bdd1243dSDimitry Andric void TimeProfilingPassesHandler::registerCallbacks(
1478bdd1243dSDimitry Andric     PassInstrumentationCallbacks &PIC) {
1479bdd1243dSDimitry Andric   if (!getTimeTraceProfilerInstance())
1480bdd1243dSDimitry Andric     return;
1481bdd1243dSDimitry Andric   PIC.registerBeforeNonSkippedPassCallback(
1482bdd1243dSDimitry Andric       [this](StringRef P, Any IR) { this->runBeforePass(P, IR); });
1483bdd1243dSDimitry Andric   PIC.registerAfterPassCallback(
1484bdd1243dSDimitry Andric       [this](StringRef P, Any IR, const PreservedAnalyses &) {
1485bdd1243dSDimitry Andric         this->runAfterPass();
1486bdd1243dSDimitry Andric       },
1487bdd1243dSDimitry Andric       true);
1488bdd1243dSDimitry Andric   PIC.registerAfterPassInvalidatedCallback(
1489bdd1243dSDimitry Andric       [this](StringRef P, const PreservedAnalyses &) { this->runAfterPass(); },
1490bdd1243dSDimitry Andric       true);
1491bdd1243dSDimitry Andric   PIC.registerBeforeAnalysisCallback(
1492bdd1243dSDimitry Andric       [this](StringRef P, Any IR) { this->runBeforePass(P, IR); });
1493bdd1243dSDimitry Andric   PIC.registerAfterAnalysisCallback(
1494bdd1243dSDimitry Andric       [this](StringRef P, Any IR) { this->runAfterPass(); }, true);
1495bdd1243dSDimitry Andric }
1496bdd1243dSDimitry Andric 
runBeforePass(StringRef PassID,Any IR)1497bdd1243dSDimitry Andric void TimeProfilingPassesHandler::runBeforePass(StringRef PassID, Any IR) {
1498bdd1243dSDimitry Andric   timeTraceProfilerBegin(PassID, getIRName(IR));
1499bdd1243dSDimitry Andric }
1500bdd1243dSDimitry Andric 
runAfterPass()1501bdd1243dSDimitry Andric void TimeProfilingPassesHandler::runAfterPass() { timeTraceProfilerEnd(); }
1502bdd1243dSDimitry Andric 
1503349cc55cSDimitry Andric namespace {
1504349cc55cSDimitry Andric 
1505349cc55cSDimitry Andric class DisplayNode;
1506349cc55cSDimitry Andric class DotCfgDiffDisplayGraph;
1507349cc55cSDimitry Andric 
1508349cc55cSDimitry Andric // Base class for a node or edge in the dot-cfg-changes graph.
1509349cc55cSDimitry Andric class DisplayElement {
1510349cc55cSDimitry Andric public:
1511349cc55cSDimitry Andric   // Is this in before, after, or both?
getColour() const15120eae32dcSDimitry Andric   StringRef getColour() const { return Colour; }
1513349cc55cSDimitry Andric 
1514349cc55cSDimitry Andric protected:
DisplayElement(StringRef Colour)15150eae32dcSDimitry Andric   DisplayElement(StringRef Colour) : Colour(Colour) {}
15160eae32dcSDimitry Andric   const StringRef Colour;
1517349cc55cSDimitry Andric };
1518349cc55cSDimitry Andric 
1519349cc55cSDimitry Andric // An edge representing a transition between basic blocks in the
1520349cc55cSDimitry Andric // dot-cfg-changes graph.
1521349cc55cSDimitry Andric class DisplayEdge : public DisplayElement {
1522349cc55cSDimitry Andric public:
DisplayEdge(std::string Value,DisplayNode & Node,StringRef Colour)15230eae32dcSDimitry Andric   DisplayEdge(std::string Value, DisplayNode &Node, StringRef Colour)
15240eae32dcSDimitry Andric       : DisplayElement(Colour), Value(Value), Node(Node) {}
1525349cc55cSDimitry Andric   // The value on which the transition is made.
getValue() const1526349cc55cSDimitry Andric   std::string getValue() const { return Value; }
1527349cc55cSDimitry Andric   // The node (representing a basic block) reached by this transition.
getDestinationNode() const1528349cc55cSDimitry Andric   const DisplayNode &getDestinationNode() const { return Node; }
1529349cc55cSDimitry Andric 
1530349cc55cSDimitry Andric protected:
1531349cc55cSDimitry Andric   std::string Value;
1532349cc55cSDimitry Andric   const DisplayNode &Node;
1533349cc55cSDimitry Andric };
1534349cc55cSDimitry Andric 
1535349cc55cSDimitry Andric // A node in the dot-cfg-changes graph which represents a basic block.
1536349cc55cSDimitry Andric class DisplayNode : public DisplayElement {
1537349cc55cSDimitry Andric public:
1538349cc55cSDimitry Andric   // \p C is the content for the node, \p T indicates the colour for the
1539349cc55cSDimitry Andric   // outline of the node
DisplayNode(std::string Content,StringRef Colour)15400eae32dcSDimitry Andric   DisplayNode(std::string Content, StringRef Colour)
15410eae32dcSDimitry Andric       : DisplayElement(Colour), Content(Content) {}
1542349cc55cSDimitry Andric 
1543349cc55cSDimitry Andric   // Iterator to the child nodes.  Required by GraphWriter.
1544349cc55cSDimitry Andric   using ChildIterator = std::unordered_set<DisplayNode *>::const_iterator;
children_begin() const1545349cc55cSDimitry Andric   ChildIterator children_begin() const { return Children.cbegin(); }
children_end() const1546349cc55cSDimitry Andric   ChildIterator children_end() const { return Children.cend(); }
1547349cc55cSDimitry Andric 
1548349cc55cSDimitry Andric   // Iterator for the edges.  Required by GraphWriter.
1549349cc55cSDimitry Andric   using EdgeIterator = std::vector<DisplayEdge *>::const_iterator;
edges_begin() const1550349cc55cSDimitry Andric   EdgeIterator edges_begin() const { return EdgePtrs.cbegin(); }
edges_end() const1551349cc55cSDimitry Andric   EdgeIterator edges_end() const { return EdgePtrs.cend(); }
1552349cc55cSDimitry Andric 
15530eae32dcSDimitry Andric   // Create an edge to \p Node on value \p Value, with colour \p Colour.
15540eae32dcSDimitry Andric   void createEdge(StringRef Value, DisplayNode &Node, StringRef Colour);
1555349cc55cSDimitry Andric 
1556349cc55cSDimitry Andric   // Return the content of this node.
getContent() const1557349cc55cSDimitry Andric   std::string getContent() const { return Content; }
1558349cc55cSDimitry Andric 
15590eae32dcSDimitry Andric   // Return the edge to node \p S.
getEdge(const DisplayNode & To) const1560349cc55cSDimitry Andric   const DisplayEdge &getEdge(const DisplayNode &To) const {
1561349cc55cSDimitry Andric     assert(EdgeMap.find(&To) != EdgeMap.end() && "Expected to find edge.");
1562349cc55cSDimitry Andric     return *EdgeMap.find(&To)->second;
1563349cc55cSDimitry Andric   }
1564349cc55cSDimitry Andric 
1565349cc55cSDimitry Andric   // Return the value for the transition to basic block \p S.
1566349cc55cSDimitry Andric   // Required by GraphWriter.
getEdgeSourceLabel(const DisplayNode & Sink) const1567349cc55cSDimitry Andric   std::string getEdgeSourceLabel(const DisplayNode &Sink) const {
1568349cc55cSDimitry Andric     return getEdge(Sink).getValue();
1569349cc55cSDimitry Andric   }
1570349cc55cSDimitry Andric 
1571349cc55cSDimitry Andric   void createEdgeMap();
1572349cc55cSDimitry Andric 
1573349cc55cSDimitry Andric protected:
1574349cc55cSDimitry Andric   const std::string Content;
1575349cc55cSDimitry Andric 
1576349cc55cSDimitry Andric   // Place to collect all of the edges.  Once they are all in the vector,
1577349cc55cSDimitry Andric   // the vector will not reallocate so then we can use pointers to them,
1578349cc55cSDimitry Andric   // which are required by the graph writing routines.
1579349cc55cSDimitry Andric   std::vector<DisplayEdge> Edges;
1580349cc55cSDimitry Andric 
1581349cc55cSDimitry Andric   std::vector<DisplayEdge *> EdgePtrs;
1582349cc55cSDimitry Andric   std::unordered_set<DisplayNode *> Children;
1583349cc55cSDimitry Andric   std::unordered_map<const DisplayNode *, const DisplayEdge *> EdgeMap;
1584349cc55cSDimitry Andric 
1585349cc55cSDimitry Andric   // Safeguard adding of edges.
1586349cc55cSDimitry Andric   bool AllEdgesCreated = false;
1587349cc55cSDimitry Andric };
1588349cc55cSDimitry Andric 
1589349cc55cSDimitry Andric // Class representing a difference display (corresponds to a pdf file).
1590349cc55cSDimitry Andric class DotCfgDiffDisplayGraph {
1591349cc55cSDimitry Andric public:
DotCfgDiffDisplayGraph(std::string Name)1592349cc55cSDimitry Andric   DotCfgDiffDisplayGraph(std::string Name) : GraphName(Name) {}
1593349cc55cSDimitry Andric 
1594349cc55cSDimitry Andric   // Generate the file into \p DotFile.
1595349cc55cSDimitry Andric   void generateDotFile(StringRef DotFile);
1596349cc55cSDimitry Andric 
1597349cc55cSDimitry Andric   // Iterator to the nodes.  Required by GraphWriter.
1598349cc55cSDimitry Andric   using NodeIterator = std::vector<DisplayNode *>::const_iterator;
nodes_begin() const1599349cc55cSDimitry Andric   NodeIterator nodes_begin() const {
1600349cc55cSDimitry Andric     assert(NodeGenerationComplete && "Unexpected children iterator creation");
1601349cc55cSDimitry Andric     return NodePtrs.cbegin();
1602349cc55cSDimitry Andric   }
nodes_end() const1603349cc55cSDimitry Andric   NodeIterator nodes_end() const {
1604349cc55cSDimitry Andric     assert(NodeGenerationComplete && "Unexpected children iterator creation");
1605349cc55cSDimitry Andric     return NodePtrs.cend();
1606349cc55cSDimitry Andric   }
1607349cc55cSDimitry Andric 
1608349cc55cSDimitry Andric   // Record the index of the entry node.  At this point, we can build up
1609349cc55cSDimitry Andric   // vectors of pointers that are required by the graph routines.
setEntryNode(unsigned N)1610349cc55cSDimitry Andric   void setEntryNode(unsigned N) {
1611349cc55cSDimitry Andric     // At this point, there will be no new nodes.
1612349cc55cSDimitry Andric     assert(!NodeGenerationComplete && "Unexpected node creation");
1613349cc55cSDimitry Andric     NodeGenerationComplete = true;
1614349cc55cSDimitry Andric     for (auto &N : Nodes)
1615349cc55cSDimitry Andric       NodePtrs.emplace_back(&N);
1616349cc55cSDimitry Andric 
1617349cc55cSDimitry Andric     EntryNode = NodePtrs[N];
1618349cc55cSDimitry Andric   }
1619349cc55cSDimitry Andric 
1620349cc55cSDimitry Andric   // Create a node.
createNode(std::string C,StringRef Colour)16210eae32dcSDimitry Andric   void createNode(std::string C, StringRef Colour) {
1622349cc55cSDimitry Andric     assert(!NodeGenerationComplete && "Unexpected node creation");
16230eae32dcSDimitry Andric     Nodes.emplace_back(C, Colour);
1624349cc55cSDimitry Andric   }
1625349cc55cSDimitry Andric   // Return the node at index \p N to avoid problems with vectors reallocating.
getNode(unsigned N)1626349cc55cSDimitry Andric   DisplayNode &getNode(unsigned N) {
1627349cc55cSDimitry Andric     assert(N < Nodes.size() && "Node is out of bounds");
1628349cc55cSDimitry Andric     return Nodes[N];
1629349cc55cSDimitry Andric   }
size() const1630349cc55cSDimitry Andric   unsigned size() const {
1631349cc55cSDimitry Andric     assert(NodeGenerationComplete && "Unexpected children iterator creation");
1632349cc55cSDimitry Andric     return Nodes.size();
1633349cc55cSDimitry Andric   }
1634349cc55cSDimitry Andric 
1635349cc55cSDimitry Andric   // Return the name of the graph.  Required by GraphWriter.
getGraphName() const1636349cc55cSDimitry Andric   std::string getGraphName() const { return GraphName; }
1637349cc55cSDimitry Andric 
1638349cc55cSDimitry Andric   // Return the string representing the differences for basic block \p Node.
1639349cc55cSDimitry Andric   // Required by GraphWriter.
getNodeLabel(const DisplayNode & Node) const1640349cc55cSDimitry Andric   std::string getNodeLabel(const DisplayNode &Node) const {
1641349cc55cSDimitry Andric     return Node.getContent();
1642349cc55cSDimitry Andric   }
1643349cc55cSDimitry Andric 
1644349cc55cSDimitry Andric   // Return a string with colour information for Dot.  Required by GraphWriter.
getNodeAttributes(const DisplayNode & Node) const1645349cc55cSDimitry Andric   std::string getNodeAttributes(const DisplayNode &Node) const {
16460eae32dcSDimitry Andric     return attribute(Node.getColour());
1647349cc55cSDimitry Andric   }
1648349cc55cSDimitry Andric 
1649349cc55cSDimitry Andric   // Return a string with colour information for Dot.  Required by GraphWriter.
getEdgeColorAttr(const DisplayNode & From,const DisplayNode & To) const1650349cc55cSDimitry Andric   std::string getEdgeColorAttr(const DisplayNode &From,
1651349cc55cSDimitry Andric                                const DisplayNode &To) const {
16520eae32dcSDimitry Andric     return attribute(From.getEdge(To).getColour());
1653349cc55cSDimitry Andric   }
1654349cc55cSDimitry Andric 
1655349cc55cSDimitry Andric   // Get the starting basic block.  Required by GraphWriter.
getEntryNode() const1656349cc55cSDimitry Andric   DisplayNode *getEntryNode() const {
1657349cc55cSDimitry Andric     assert(NodeGenerationComplete && "Unexpected children iterator creation");
1658349cc55cSDimitry Andric     return EntryNode;
1659349cc55cSDimitry Andric   }
1660349cc55cSDimitry Andric 
1661349cc55cSDimitry Andric protected:
1662349cc55cSDimitry Andric   // Return the string containing the colour to use as a Dot attribute.
attribute(StringRef Colour) const16630eae32dcSDimitry Andric   std::string attribute(StringRef Colour) const {
16640eae32dcSDimitry Andric     return "color=" + Colour.str();
16650eae32dcSDimitry Andric   }
1666349cc55cSDimitry Andric 
1667349cc55cSDimitry Andric   bool NodeGenerationComplete = false;
1668349cc55cSDimitry Andric   const std::string GraphName;
1669349cc55cSDimitry Andric   std::vector<DisplayNode> Nodes;
1670349cc55cSDimitry Andric   std::vector<DisplayNode *> NodePtrs;
1671349cc55cSDimitry Andric   DisplayNode *EntryNode = nullptr;
1672349cc55cSDimitry Andric };
1673349cc55cSDimitry Andric 
createEdge(StringRef Value,DisplayNode & Node,StringRef Colour)16740eae32dcSDimitry Andric void DisplayNode::createEdge(StringRef Value, DisplayNode &Node,
16750eae32dcSDimitry Andric                              StringRef Colour) {
1676349cc55cSDimitry Andric   assert(!AllEdgesCreated && "Expected to be able to still create edges.");
16770eae32dcSDimitry Andric   Edges.emplace_back(Value.str(), Node, Colour);
1678349cc55cSDimitry Andric   Children.insert(&Node);
1679349cc55cSDimitry Andric }
1680349cc55cSDimitry Andric 
createEdgeMap()1681349cc55cSDimitry Andric void DisplayNode::createEdgeMap() {
1682349cc55cSDimitry Andric   // No more edges will be added so we can now use pointers to the edges
1683349cc55cSDimitry Andric   // as the vector will not grow and reallocate.
1684349cc55cSDimitry Andric   AllEdgesCreated = true;
1685349cc55cSDimitry Andric   for (auto &E : Edges)
1686349cc55cSDimitry Andric     EdgeMap.insert({&E.getDestinationNode(), &E});
1687349cc55cSDimitry Andric }
1688349cc55cSDimitry Andric 
1689349cc55cSDimitry Andric class DotCfgDiffNode;
1690349cc55cSDimitry Andric class DotCfgDiff;
1691349cc55cSDimitry Andric 
1692349cc55cSDimitry Andric // A class representing a basic block in the Dot difference graph.
1693349cc55cSDimitry Andric class DotCfgDiffNode {
1694349cc55cSDimitry Andric public:
1695349cc55cSDimitry Andric   DotCfgDiffNode() = delete;
1696349cc55cSDimitry Andric 
1697349cc55cSDimitry Andric   // Create a node in Dot difference graph \p G representing the basic block
16980eae32dcSDimitry Andric   // represented by \p BD with colour \p Colour (where it exists).
DotCfgDiffNode(DotCfgDiff & G,unsigned N,const BlockDataT<DCData> & BD,StringRef Colour)1699349cc55cSDimitry Andric   DotCfgDiffNode(DotCfgDiff &G, unsigned N, const BlockDataT<DCData> &BD,
17000eae32dcSDimitry Andric                  StringRef Colour)
17010eae32dcSDimitry Andric       : Graph(G), N(N), Data{&BD, nullptr}, Colour(Colour) {}
DotCfgDiffNode(const DotCfgDiffNode & DN)1702349cc55cSDimitry Andric   DotCfgDiffNode(const DotCfgDiffNode &DN)
17030eae32dcSDimitry Andric       : Graph(DN.Graph), N(DN.N), Data{DN.Data[0], DN.Data[1]},
17040eae32dcSDimitry Andric         Colour(DN.Colour), EdgesMap(DN.EdgesMap), Children(DN.Children),
17050eae32dcSDimitry Andric         Edges(DN.Edges) {}
1706349cc55cSDimitry Andric 
getIndex() const1707349cc55cSDimitry Andric   unsigned getIndex() const { return N; }
1708349cc55cSDimitry Andric 
1709349cc55cSDimitry Andric   // The label of the basic block
getLabel() const1710349cc55cSDimitry Andric   StringRef getLabel() const {
1711349cc55cSDimitry Andric     assert(Data[0] && "Expected Data[0] to be set.");
1712349cc55cSDimitry Andric     return Data[0]->getLabel();
1713349cc55cSDimitry Andric   }
17140eae32dcSDimitry Andric   // Return the colour for this block
getColour() const17150eae32dcSDimitry Andric   StringRef getColour() const { return Colour; }
1716349cc55cSDimitry Andric   // Change this basic block from being only in before to being common.
1717349cc55cSDimitry Andric   // Save the pointer to \p Other.
setCommon(const BlockDataT<DCData> & Other)1718349cc55cSDimitry Andric   void setCommon(const BlockDataT<DCData> &Other) {
1719349cc55cSDimitry Andric     assert(!Data[1] && "Expected only one block datum");
1720349cc55cSDimitry Andric     Data[1] = &Other;
17210eae32dcSDimitry Andric     Colour = CommonColour;
1722349cc55cSDimitry Andric   }
17230eae32dcSDimitry Andric   // Add an edge to \p E of colour {\p Value, \p Colour}.
addEdge(unsigned E,StringRef Value,StringRef Colour)17240eae32dcSDimitry Andric   void addEdge(unsigned E, StringRef Value, StringRef Colour) {
1725349cc55cSDimitry Andric     // This is a new edge or it is an edge being made common.
17260eae32dcSDimitry Andric     assert((EdgesMap.count(E) == 0 || Colour == CommonColour) &&
17270eae32dcSDimitry Andric            "Unexpected edge count and color.");
17280eae32dcSDimitry Andric     EdgesMap[E] = {Value.str(), Colour};
1729349cc55cSDimitry Andric   }
1730349cc55cSDimitry Andric   // Record the children and create edges.
1731349cc55cSDimitry Andric   void finalize(DotCfgDiff &G);
1732349cc55cSDimitry Andric 
17330eae32dcSDimitry Andric   // Return the colour of the edge to node \p S.
getEdgeColour(const unsigned S) const17340eae32dcSDimitry Andric   StringRef getEdgeColour(const unsigned S) const {
1735349cc55cSDimitry Andric     assert(EdgesMap.count(S) == 1 && "Expected to find edge.");
17360eae32dcSDimitry Andric     return EdgesMap.at(S).second;
1737349cc55cSDimitry Andric   }
1738349cc55cSDimitry Andric 
1739349cc55cSDimitry Andric   // Return the string representing the basic block.
1740349cc55cSDimitry Andric   std::string getBodyContent() const;
1741349cc55cSDimitry Andric 
1742349cc55cSDimitry Andric   void createDisplayEdges(DotCfgDiffDisplayGraph &Graph, unsigned DisplayNode,
1743349cc55cSDimitry Andric                           std::map<const unsigned, unsigned> &NodeMap) const;
1744349cc55cSDimitry Andric 
1745349cc55cSDimitry Andric protected:
1746349cc55cSDimitry Andric   DotCfgDiff &Graph;
1747349cc55cSDimitry Andric   const unsigned N;
1748349cc55cSDimitry Andric   const BlockDataT<DCData> *Data[2];
17490eae32dcSDimitry Andric   StringRef Colour;
17500eae32dcSDimitry Andric   std::map<const unsigned, std::pair<std::string, StringRef>> EdgesMap;
1751349cc55cSDimitry Andric   std::vector<unsigned> Children;
1752349cc55cSDimitry Andric   std::vector<unsigned> Edges;
1753349cc55cSDimitry Andric };
1754349cc55cSDimitry Andric 
1755349cc55cSDimitry Andric // Class representing the difference graph between two functions.
1756349cc55cSDimitry Andric class DotCfgDiff {
1757349cc55cSDimitry Andric public:
1758349cc55cSDimitry Andric   // \p Title is the title given to the graph.  \p EntryNodeName is the
1759349cc55cSDimitry Andric   // entry node for the function.  \p Before and \p After are the before
1760349cc55cSDimitry Andric   // after versions of the function, respectively.  \p Dir is the directory
1761349cc55cSDimitry Andric   // in which to store the results.
1762349cc55cSDimitry Andric   DotCfgDiff(StringRef Title, const FuncDataT<DCData> &Before,
1763349cc55cSDimitry Andric              const FuncDataT<DCData> &After);
1764349cc55cSDimitry Andric 
1765349cc55cSDimitry Andric   DotCfgDiff(const DotCfgDiff &) = delete;
1766349cc55cSDimitry Andric   DotCfgDiff &operator=(const DotCfgDiff &) = delete;
1767349cc55cSDimitry Andric 
1768349cc55cSDimitry Andric   DotCfgDiffDisplayGraph createDisplayGraph(StringRef Title,
1769349cc55cSDimitry Andric                                             StringRef EntryNodeName);
1770349cc55cSDimitry Andric 
1771349cc55cSDimitry Andric   // Return a string consisting of the labels for the \p Source and \p Sink.
1772349cc55cSDimitry Andric   // The combination allows distinguishing changing transitions on the
1773349cc55cSDimitry Andric   // same value (ie, a transition went to X before and goes to Y after).
1774349cc55cSDimitry Andric   // Required by GraphWriter.
getEdgeSourceLabel(const unsigned & Source,const unsigned & Sink) const1775349cc55cSDimitry Andric   StringRef getEdgeSourceLabel(const unsigned &Source,
1776349cc55cSDimitry Andric                                const unsigned &Sink) const {
1777349cc55cSDimitry Andric     std::string S =
1778349cc55cSDimitry Andric         getNode(Source).getLabel().str() + " " + getNode(Sink).getLabel().str();
1779349cc55cSDimitry Andric     assert(EdgeLabels.count(S) == 1 && "Expected to find edge label.");
1780349cc55cSDimitry Andric     return EdgeLabels.find(S)->getValue();
1781349cc55cSDimitry Andric   }
1782349cc55cSDimitry Andric 
1783349cc55cSDimitry Andric   // Return the number of basic blocks (nodes).  Required by GraphWriter.
size() const1784349cc55cSDimitry Andric   unsigned size() const { return Nodes.size(); }
1785349cc55cSDimitry Andric 
getNode(unsigned N) const1786349cc55cSDimitry Andric   const DotCfgDiffNode &getNode(unsigned N) const {
1787349cc55cSDimitry Andric     assert(N < Nodes.size() && "Unexpected index for node reference");
1788349cc55cSDimitry Andric     return Nodes[N];
1789349cc55cSDimitry Andric   }
1790349cc55cSDimitry Andric 
1791349cc55cSDimitry Andric protected:
1792349cc55cSDimitry Andric   // Return the string surrounded by HTML to make it the appropriate colour.
17930eae32dcSDimitry Andric   std::string colourize(std::string S, StringRef Colour) const;
1794349cc55cSDimitry Andric 
createNode(StringRef Label,const BlockDataT<DCData> & BD,StringRef C)17950eae32dcSDimitry Andric   void createNode(StringRef Label, const BlockDataT<DCData> &BD, StringRef C) {
1796349cc55cSDimitry Andric     unsigned Pos = Nodes.size();
17970eae32dcSDimitry Andric     Nodes.emplace_back(*this, Pos, BD, C);
1798349cc55cSDimitry Andric     NodePosition.insert({Label, Pos});
1799349cc55cSDimitry Andric   }
1800349cc55cSDimitry Andric 
1801349cc55cSDimitry Andric   // TODO Nodes should probably be a StringMap<DotCfgDiffNode> after the
1802349cc55cSDimitry Andric   // display graph is separated out, which would remove the need for
1803349cc55cSDimitry Andric   // NodePosition.
1804349cc55cSDimitry Andric   std::vector<DotCfgDiffNode> Nodes;
1805349cc55cSDimitry Andric   StringMap<unsigned> NodePosition;
1806349cc55cSDimitry Andric   const std::string GraphName;
1807349cc55cSDimitry Andric 
1808349cc55cSDimitry Andric   StringMap<std::string> EdgeLabels;
1809349cc55cSDimitry Andric };
1810349cc55cSDimitry Andric 
getBodyContent() const1811349cc55cSDimitry Andric std::string DotCfgDiffNode::getBodyContent() const {
18120eae32dcSDimitry Andric   if (Colour == CommonColour) {
1813349cc55cSDimitry Andric     assert(Data[1] && "Expected Data[1] to be set.");
1814349cc55cSDimitry Andric 
1815349cc55cSDimitry Andric     StringRef SR[2];
1816349cc55cSDimitry Andric     for (unsigned I = 0; I < 2; ++I) {
1817349cc55cSDimitry Andric       SR[I] = Data[I]->getBody();
1818349cc55cSDimitry Andric       // drop initial '\n' if present
1819349cc55cSDimitry Andric       if (SR[I][0] == '\n')
1820349cc55cSDimitry Andric         SR[I] = SR[I].drop_front();
1821349cc55cSDimitry Andric       // drop predecessors as they can be big and are redundant
1822349cc55cSDimitry Andric       SR[I] = SR[I].drop_until([](char C) { return C == '\n'; }).drop_front();
1823349cc55cSDimitry Andric     }
1824349cc55cSDimitry Andric 
1825349cc55cSDimitry Andric     SmallString<80> OldLineFormat = formatv(
18260eae32dcSDimitry Andric         "<FONT COLOR=\"{0}\">%l</FONT><BR align=\"left\"/>", BeforeColour);
1827349cc55cSDimitry Andric     SmallString<80> NewLineFormat = formatv(
18280eae32dcSDimitry Andric         "<FONT COLOR=\"{0}\">%l</FONT><BR align=\"left\"/>", AfterColour);
1829349cc55cSDimitry Andric     SmallString<80> UnchangedLineFormat = formatv(
18300eae32dcSDimitry Andric         "<FONT COLOR=\"{0}\">%l</FONT><BR align=\"left\"/>", CommonColour);
1831349cc55cSDimitry Andric     std::string Diff = Data[0]->getLabel().str();
1832349cc55cSDimitry Andric     Diff += ":\n<BR align=\"left\"/>" +
1833349cc55cSDimitry Andric             doSystemDiff(makeHTMLReady(SR[0]), makeHTMLReady(SR[1]),
1834349cc55cSDimitry Andric                          OldLineFormat, NewLineFormat, UnchangedLineFormat);
1835349cc55cSDimitry Andric 
1836349cc55cSDimitry Andric     // Diff adds in some empty colour changes which are not valid HTML
1837349cc55cSDimitry Andric     // so remove them.  Colours are all lowercase alpha characters (as
1838349cc55cSDimitry Andric     // listed in https://graphviz.org/pdf/dotguide.pdf).
1839349cc55cSDimitry Andric     Regex R("<FONT COLOR=\"\\w+\"></FONT>");
1840349cc55cSDimitry Andric     while (true) {
1841349cc55cSDimitry Andric       std::string Error;
1842349cc55cSDimitry Andric       std::string S = R.sub("", Diff, &Error);
1843349cc55cSDimitry Andric       if (Error != "")
1844349cc55cSDimitry Andric         return Error;
1845349cc55cSDimitry Andric       if (S == Diff)
1846349cc55cSDimitry Andric         return Diff;
1847349cc55cSDimitry Andric       Diff = S;
1848349cc55cSDimitry Andric     }
1849349cc55cSDimitry Andric     llvm_unreachable("Should not get here");
1850349cc55cSDimitry Andric   }
1851349cc55cSDimitry Andric 
1852349cc55cSDimitry Andric   // Put node out in the appropriate colour.
1853349cc55cSDimitry Andric   assert(!Data[1] && "Data[1] is set unexpectedly.");
1854349cc55cSDimitry Andric   std::string Body = makeHTMLReady(Data[0]->getBody());
1855349cc55cSDimitry Andric   const StringRef BS = Body;
1856349cc55cSDimitry Andric   StringRef BS1 = BS;
1857349cc55cSDimitry Andric   // Drop leading newline, if present.
1858349cc55cSDimitry Andric   if (BS.front() == '\n')
1859349cc55cSDimitry Andric     BS1 = BS1.drop_front(1);
1860349cc55cSDimitry Andric   // Get label.
1861349cc55cSDimitry Andric   StringRef Label = BS1.take_until([](char C) { return C == ':'; });
1862349cc55cSDimitry Andric   // drop predecessors as they can be big and are redundant
1863349cc55cSDimitry Andric   BS1 = BS1.drop_until([](char C) { return C == '\n'; }).drop_front();
1864349cc55cSDimitry Andric 
18650eae32dcSDimitry Andric   std::string S = "<FONT COLOR=\"" + Colour.str() + "\">" + Label.str() + ":";
1866349cc55cSDimitry Andric 
1867349cc55cSDimitry Andric   // align each line to the left.
1868349cc55cSDimitry Andric   while (BS1.size()) {
1869349cc55cSDimitry Andric     S.append("<BR align=\"left\"/>");
1870349cc55cSDimitry Andric     StringRef Line = BS1.take_until([](char C) { return C == '\n'; });
1871349cc55cSDimitry Andric     S.append(Line.str());
1872349cc55cSDimitry Andric     BS1 = BS1.drop_front(Line.size() + 1);
1873349cc55cSDimitry Andric   }
1874349cc55cSDimitry Andric   S.append("<BR align=\"left\"/></FONT>");
1875349cc55cSDimitry Andric   return S;
1876349cc55cSDimitry Andric }
1877349cc55cSDimitry Andric 
colourize(std::string S,StringRef Colour) const18780eae32dcSDimitry Andric std::string DotCfgDiff::colourize(std::string S, StringRef Colour) const {
1879349cc55cSDimitry Andric   if (S.length() == 0)
1880349cc55cSDimitry Andric     return S;
18810eae32dcSDimitry Andric   return "<FONT COLOR=\"" + Colour.str() + "\">" + S + "</FONT>";
1882349cc55cSDimitry Andric }
1883349cc55cSDimitry Andric 
DotCfgDiff(StringRef Title,const FuncDataT<DCData> & Before,const FuncDataT<DCData> & After)1884349cc55cSDimitry Andric DotCfgDiff::DotCfgDiff(StringRef Title, const FuncDataT<DCData> &Before,
1885349cc55cSDimitry Andric                        const FuncDataT<DCData> &After)
1886349cc55cSDimitry Andric     : GraphName(Title.str()) {
18870eae32dcSDimitry Andric   StringMap<StringRef> EdgesMap;
1888349cc55cSDimitry Andric 
1889349cc55cSDimitry Andric   // Handle each basic block in the before IR.
1890349cc55cSDimitry Andric   for (auto &B : Before.getData()) {
1891349cc55cSDimitry Andric     StringRef Label = B.getKey();
1892349cc55cSDimitry Andric     const BlockDataT<DCData> &BD = B.getValue();
18930eae32dcSDimitry Andric     createNode(Label, BD, BeforeColour);
1894349cc55cSDimitry Andric 
1895349cc55cSDimitry Andric     // Create transitions with names made up of the from block label, the value
1896349cc55cSDimitry Andric     // on which the transition is made and the to block label.
1897349cc55cSDimitry Andric     for (StringMap<std::string>::const_iterator Sink = BD.getData().begin(),
1898349cc55cSDimitry Andric                                                 E = BD.getData().end();
1899349cc55cSDimitry Andric          Sink != E; ++Sink) {
1900349cc55cSDimitry Andric       std::string Key = (Label + " " + Sink->getKey().str()).str() + " " +
1901349cc55cSDimitry Andric                         BD.getData().getSuccessorLabel(Sink->getKey()).str();
19020eae32dcSDimitry Andric       EdgesMap.insert({Key, BeforeColour});
1903349cc55cSDimitry Andric     }
1904349cc55cSDimitry Andric   }
1905349cc55cSDimitry Andric 
1906349cc55cSDimitry Andric   // Handle each basic block in the after IR
1907349cc55cSDimitry Andric   for (auto &A : After.getData()) {
1908349cc55cSDimitry Andric     StringRef Label = A.getKey();
1909349cc55cSDimitry Andric     const BlockDataT<DCData> &BD = A.getValue();
1910349cc55cSDimitry Andric     unsigned C = NodePosition.count(Label);
1911349cc55cSDimitry Andric     if (C == 0)
1912349cc55cSDimitry Andric       // This only exists in the after IR.  Create the node.
19130eae32dcSDimitry Andric       createNode(Label, BD, AfterColour);
1914349cc55cSDimitry Andric     else {
1915349cc55cSDimitry Andric       assert(C == 1 && "Unexpected multiple nodes.");
1916349cc55cSDimitry Andric       Nodes[NodePosition[Label]].setCommon(BD);
1917349cc55cSDimitry Andric     }
1918349cc55cSDimitry Andric     // Add in the edges between the nodes (as common or only in after).
1919349cc55cSDimitry Andric     for (StringMap<std::string>::const_iterator Sink = BD.getData().begin(),
1920349cc55cSDimitry Andric                                                 E = BD.getData().end();
1921349cc55cSDimitry Andric          Sink != E; ++Sink) {
1922349cc55cSDimitry Andric       std::string Key = (Label + " " + Sink->getKey().str()).str() + " " +
1923349cc55cSDimitry Andric                         BD.getData().getSuccessorLabel(Sink->getKey()).str();
1924349cc55cSDimitry Andric       unsigned C = EdgesMap.count(Key);
1925349cc55cSDimitry Andric       if (C == 0)
19260eae32dcSDimitry Andric         EdgesMap.insert({Key, AfterColour});
1927349cc55cSDimitry Andric       else {
19280eae32dcSDimitry Andric         EdgesMap[Key] = CommonColour;
1929349cc55cSDimitry Andric       }
1930349cc55cSDimitry Andric     }
1931349cc55cSDimitry Andric   }
1932349cc55cSDimitry Andric 
1933349cc55cSDimitry Andric   // Now go through the map of edges and add them to the node.
1934349cc55cSDimitry Andric   for (auto &E : EdgesMap) {
1935349cc55cSDimitry Andric     // Extract the source, sink and value from the edge key.
1936349cc55cSDimitry Andric     StringRef S = E.getKey();
1937349cc55cSDimitry Andric     auto SP1 = S.rsplit(' ');
1938349cc55cSDimitry Andric     auto &SourceSink = SP1.first;
1939349cc55cSDimitry Andric     auto SP2 = SourceSink.split(' ');
1940349cc55cSDimitry Andric     StringRef Source = SP2.first;
1941349cc55cSDimitry Andric     StringRef Sink = SP2.second;
1942349cc55cSDimitry Andric     StringRef Value = SP1.second;
1943349cc55cSDimitry Andric 
1944349cc55cSDimitry Andric     assert(NodePosition.count(Source) == 1 && "Expected to find node.");
1945349cc55cSDimitry Andric     DotCfgDiffNode &SourceNode = Nodes[NodePosition[Source]];
1946349cc55cSDimitry Andric     assert(NodePosition.count(Sink) == 1 && "Expected to find node.");
1947349cc55cSDimitry Andric     unsigned SinkNode = NodePosition[Sink];
19480eae32dcSDimitry Andric     StringRef Colour = E.second;
1949349cc55cSDimitry Andric 
1950349cc55cSDimitry Andric     // Look for an edge from Source to Sink
1951349cc55cSDimitry Andric     if (EdgeLabels.count(SourceSink) == 0)
19520eae32dcSDimitry Andric       EdgeLabels.insert({SourceSink, colourize(Value.str(), Colour)});
1953349cc55cSDimitry Andric     else {
1954349cc55cSDimitry Andric       StringRef V = EdgeLabels.find(SourceSink)->getValue();
19550eae32dcSDimitry Andric       std::string NV = colourize(V.str() + " " + Value.str(), Colour);
19560eae32dcSDimitry Andric       Colour = CommonColour;
1957349cc55cSDimitry Andric       EdgeLabels[SourceSink] = NV;
1958349cc55cSDimitry Andric     }
19590eae32dcSDimitry Andric     SourceNode.addEdge(SinkNode, Value, Colour);
1960349cc55cSDimitry Andric   }
1961349cc55cSDimitry Andric   for (auto &I : Nodes)
1962349cc55cSDimitry Andric     I.finalize(*this);
1963349cc55cSDimitry Andric }
1964349cc55cSDimitry Andric 
createDisplayGraph(StringRef Title,StringRef EntryNodeName)1965349cc55cSDimitry Andric DotCfgDiffDisplayGraph DotCfgDiff::createDisplayGraph(StringRef Title,
1966349cc55cSDimitry Andric                                                       StringRef EntryNodeName) {
1967349cc55cSDimitry Andric   assert(NodePosition.count(EntryNodeName) == 1 &&
1968349cc55cSDimitry Andric          "Expected to find entry block in map.");
1969349cc55cSDimitry Andric   unsigned Entry = NodePosition[EntryNodeName];
1970349cc55cSDimitry Andric   assert(Entry < Nodes.size() && "Expected to find entry node");
1971349cc55cSDimitry Andric   DotCfgDiffDisplayGraph G(Title.str());
1972349cc55cSDimitry Andric 
1973349cc55cSDimitry Andric   std::map<const unsigned, unsigned> NodeMap;
1974349cc55cSDimitry Andric 
1975349cc55cSDimitry Andric   int EntryIndex = -1;
1976349cc55cSDimitry Andric   unsigned Index = 0;
1977349cc55cSDimitry Andric   for (auto &I : Nodes) {
1978349cc55cSDimitry Andric     if (I.getIndex() == Entry)
1979349cc55cSDimitry Andric       EntryIndex = Index;
19800eae32dcSDimitry Andric     G.createNode(I.getBodyContent(), I.getColour());
1981349cc55cSDimitry Andric     NodeMap.insert({I.getIndex(), Index++});
1982349cc55cSDimitry Andric   }
1983349cc55cSDimitry Andric   assert(EntryIndex >= 0 && "Expected entry node index to be set.");
1984349cc55cSDimitry Andric   G.setEntryNode(EntryIndex);
1985349cc55cSDimitry Andric 
1986349cc55cSDimitry Andric   for (auto &I : NodeMap) {
1987349cc55cSDimitry Andric     unsigned SourceNode = I.first;
1988349cc55cSDimitry Andric     unsigned DisplayNode = I.second;
1989349cc55cSDimitry Andric     getNode(SourceNode).createDisplayEdges(G, DisplayNode, NodeMap);
1990349cc55cSDimitry Andric   }
1991349cc55cSDimitry Andric   return G;
1992349cc55cSDimitry Andric }
1993349cc55cSDimitry Andric 
createDisplayEdges(DotCfgDiffDisplayGraph & DisplayGraph,unsigned DisplayNodeIndex,std::map<const unsigned,unsigned> & NodeMap) const1994349cc55cSDimitry Andric void DotCfgDiffNode::createDisplayEdges(
1995349cc55cSDimitry Andric     DotCfgDiffDisplayGraph &DisplayGraph, unsigned DisplayNodeIndex,
1996349cc55cSDimitry Andric     std::map<const unsigned, unsigned> &NodeMap) const {
1997349cc55cSDimitry Andric 
1998349cc55cSDimitry Andric   DisplayNode &SourceDisplayNode = DisplayGraph.getNode(DisplayNodeIndex);
1999349cc55cSDimitry Andric 
2000349cc55cSDimitry Andric   for (auto I : Edges) {
2001349cc55cSDimitry Andric     unsigned SinkNodeIndex = I;
20020eae32dcSDimitry Andric     StringRef Colour = getEdgeColour(SinkNodeIndex);
2003349cc55cSDimitry Andric     const DotCfgDiffNode *SinkNode = &Graph.getNode(SinkNodeIndex);
2004349cc55cSDimitry Andric 
2005349cc55cSDimitry Andric     StringRef Label = Graph.getEdgeSourceLabel(getIndex(), SinkNodeIndex);
2006349cc55cSDimitry Andric     DisplayNode &SinkDisplayNode = DisplayGraph.getNode(SinkNode->getIndex());
20070eae32dcSDimitry Andric     SourceDisplayNode.createEdge(Label, SinkDisplayNode, Colour);
2008349cc55cSDimitry Andric   }
2009349cc55cSDimitry Andric   SourceDisplayNode.createEdgeMap();
2010349cc55cSDimitry Andric }
2011349cc55cSDimitry Andric 
finalize(DotCfgDiff & G)2012349cc55cSDimitry Andric void DotCfgDiffNode::finalize(DotCfgDiff &G) {
2013349cc55cSDimitry Andric   for (auto E : EdgesMap) {
2014349cc55cSDimitry Andric     Children.emplace_back(E.first);
2015349cc55cSDimitry Andric     Edges.emplace_back(E.first);
2016349cc55cSDimitry Andric   }
2017349cc55cSDimitry Andric }
2018349cc55cSDimitry Andric 
2019349cc55cSDimitry Andric } // namespace
2020349cc55cSDimitry Andric 
2021349cc55cSDimitry Andric namespace llvm {
2022349cc55cSDimitry Andric 
2023349cc55cSDimitry Andric template <> struct GraphTraits<DotCfgDiffDisplayGraph *> {
2024349cc55cSDimitry Andric   using NodeRef = const DisplayNode *;
2025349cc55cSDimitry Andric   using ChildIteratorType = DisplayNode::ChildIterator;
2026349cc55cSDimitry Andric   using nodes_iterator = DotCfgDiffDisplayGraph::NodeIterator;
2027349cc55cSDimitry Andric   using EdgeRef = const DisplayEdge *;
2028349cc55cSDimitry Andric   using ChildEdgeIterator = DisplayNode::EdgeIterator;
2029349cc55cSDimitry Andric 
getEntryNodellvm::GraphTraits2030349cc55cSDimitry Andric   static NodeRef getEntryNode(const DotCfgDiffDisplayGraph *G) {
2031349cc55cSDimitry Andric     return G->getEntryNode();
2032349cc55cSDimitry Andric   }
child_beginllvm::GraphTraits2033349cc55cSDimitry Andric   static ChildIteratorType child_begin(NodeRef N) {
2034349cc55cSDimitry Andric     return N->children_begin();
2035349cc55cSDimitry Andric   }
child_endllvm::GraphTraits2036349cc55cSDimitry Andric   static ChildIteratorType child_end(NodeRef N) { return N->children_end(); }
nodes_beginllvm::GraphTraits2037349cc55cSDimitry Andric   static nodes_iterator nodes_begin(const DotCfgDiffDisplayGraph *G) {
2038349cc55cSDimitry Andric     return G->nodes_begin();
2039349cc55cSDimitry Andric   }
nodes_endllvm::GraphTraits2040349cc55cSDimitry Andric   static nodes_iterator nodes_end(const DotCfgDiffDisplayGraph *G) {
2041349cc55cSDimitry Andric     return G->nodes_end();
2042349cc55cSDimitry Andric   }
child_edge_beginllvm::GraphTraits2043349cc55cSDimitry Andric   static ChildEdgeIterator child_edge_begin(NodeRef N) {
2044349cc55cSDimitry Andric     return N->edges_begin();
2045349cc55cSDimitry Andric   }
child_edge_endllvm::GraphTraits2046349cc55cSDimitry Andric   static ChildEdgeIterator child_edge_end(NodeRef N) { return N->edges_end(); }
edge_destllvm::GraphTraits2047349cc55cSDimitry Andric   static NodeRef edge_dest(EdgeRef E) { return &E->getDestinationNode(); }
sizellvm::GraphTraits2048349cc55cSDimitry Andric   static unsigned size(const DotCfgDiffDisplayGraph *G) { return G->size(); }
2049349cc55cSDimitry Andric };
2050349cc55cSDimitry Andric 
2051349cc55cSDimitry Andric template <>
2052349cc55cSDimitry Andric struct DOTGraphTraits<DotCfgDiffDisplayGraph *> : public DefaultDOTGraphTraits {
DOTGraphTraitsllvm::DOTGraphTraits2053349cc55cSDimitry Andric   explicit DOTGraphTraits(bool Simple = false)
2054349cc55cSDimitry Andric       : DefaultDOTGraphTraits(Simple) {}
2055349cc55cSDimitry Andric 
renderNodesUsingHTMLllvm::DOTGraphTraits2056349cc55cSDimitry Andric   static bool renderNodesUsingHTML() { return true; }
getGraphNamellvm::DOTGraphTraits2057349cc55cSDimitry Andric   static std::string getGraphName(const DotCfgDiffDisplayGraph *DiffData) {
2058349cc55cSDimitry Andric     return DiffData->getGraphName();
2059349cc55cSDimitry Andric   }
2060349cc55cSDimitry Andric   static std::string
getGraphPropertiesllvm::DOTGraphTraits2061349cc55cSDimitry Andric   getGraphProperties(const DotCfgDiffDisplayGraph *DiffData) {
2062349cc55cSDimitry Andric     return "\tsize=\"190, 190\";\n";
2063349cc55cSDimitry Andric   }
getNodeLabelllvm::DOTGraphTraits2064349cc55cSDimitry Andric   static std::string getNodeLabel(const DisplayNode *Node,
2065349cc55cSDimitry Andric                                   const DotCfgDiffDisplayGraph *DiffData) {
2066349cc55cSDimitry Andric     return DiffData->getNodeLabel(*Node);
2067349cc55cSDimitry Andric   }
getNodeAttributesllvm::DOTGraphTraits2068349cc55cSDimitry Andric   static std::string getNodeAttributes(const DisplayNode *Node,
2069349cc55cSDimitry Andric                                        const DotCfgDiffDisplayGraph *DiffData) {
2070349cc55cSDimitry Andric     return DiffData->getNodeAttributes(*Node);
2071349cc55cSDimitry Andric   }
getEdgeSourceLabelllvm::DOTGraphTraits2072349cc55cSDimitry Andric   static std::string getEdgeSourceLabel(const DisplayNode *From,
2073349cc55cSDimitry Andric                                         DisplayNode::ChildIterator &To) {
2074349cc55cSDimitry Andric     return From->getEdgeSourceLabel(**To);
2075349cc55cSDimitry Andric   }
getEdgeAttributesllvm::DOTGraphTraits2076349cc55cSDimitry Andric   static std::string getEdgeAttributes(const DisplayNode *From,
2077349cc55cSDimitry Andric                                        DisplayNode::ChildIterator &To,
2078349cc55cSDimitry Andric                                        const DotCfgDiffDisplayGraph *DiffData) {
2079349cc55cSDimitry Andric     return DiffData->getEdgeColorAttr(*From, **To);
2080349cc55cSDimitry Andric   }
2081349cc55cSDimitry Andric };
2082349cc55cSDimitry Andric 
2083349cc55cSDimitry Andric } // namespace llvm
2084349cc55cSDimitry Andric 
2085349cc55cSDimitry Andric namespace {
2086349cc55cSDimitry Andric 
generateDotFile(StringRef DotFile)2087349cc55cSDimitry Andric void DotCfgDiffDisplayGraph::generateDotFile(StringRef DotFile) {
2088349cc55cSDimitry Andric   std::error_code EC;
2089349cc55cSDimitry Andric   raw_fd_ostream OutStream(DotFile, EC);
2090349cc55cSDimitry Andric   if (EC) {
2091349cc55cSDimitry Andric     errs() << "Error: " << EC.message() << "\n";
2092349cc55cSDimitry Andric     return;
2093349cc55cSDimitry Andric   }
2094349cc55cSDimitry Andric   WriteGraph(OutStream, this, false);
2095349cc55cSDimitry Andric   OutStream.flush();
2096349cc55cSDimitry Andric   OutStream.close();
2097349cc55cSDimitry Andric }
2098349cc55cSDimitry Andric 
2099349cc55cSDimitry Andric } // namespace
2100349cc55cSDimitry Andric 
2101349cc55cSDimitry Andric namespace llvm {
2102349cc55cSDimitry Andric 
DCData(const BasicBlock & B)2103349cc55cSDimitry Andric DCData::DCData(const BasicBlock &B) {
2104349cc55cSDimitry Andric   // Build up transition labels.
2105349cc55cSDimitry Andric   const Instruction *Term = B.getTerminator();
2106349cc55cSDimitry Andric   if (const BranchInst *Br = dyn_cast<const BranchInst>(Term))
2107349cc55cSDimitry Andric     if (Br->isUnconditional())
2108349cc55cSDimitry Andric       addSuccessorLabel(Br->getSuccessor(0)->getName().str(), "");
2109349cc55cSDimitry Andric     else {
2110349cc55cSDimitry Andric       addSuccessorLabel(Br->getSuccessor(0)->getName().str(), "true");
2111349cc55cSDimitry Andric       addSuccessorLabel(Br->getSuccessor(1)->getName().str(), "false");
2112349cc55cSDimitry Andric     }
2113349cc55cSDimitry Andric   else if (const SwitchInst *Sw = dyn_cast<const SwitchInst>(Term)) {
2114349cc55cSDimitry Andric     addSuccessorLabel(Sw->case_default()->getCaseSuccessor()->getName().str(),
2115349cc55cSDimitry Andric                       "default");
2116349cc55cSDimitry Andric     for (auto &C : Sw->cases()) {
2117349cc55cSDimitry Andric       assert(C.getCaseValue() && "Expected to find case value.");
2118349cc55cSDimitry Andric       SmallString<20> Value = formatv("{0}", C.getCaseValue()->getSExtValue());
2119349cc55cSDimitry Andric       addSuccessorLabel(C.getCaseSuccessor()->getName().str(), Value);
2120349cc55cSDimitry Andric     }
2121349cc55cSDimitry Andric   } else
21227a6dacacSDimitry Andric     for (const BasicBlock *Succ : successors(&B))
21237a6dacacSDimitry Andric       addSuccessorLabel(Succ->getName().str(), "");
2124349cc55cSDimitry Andric }
2125349cc55cSDimitry Andric 
DotCfgChangeReporter(bool Verbose)2126349cc55cSDimitry Andric DotCfgChangeReporter::DotCfgChangeReporter(bool Verbose)
21270eae32dcSDimitry Andric     : ChangeReporter<IRDataT<DCData>>(Verbose) {}
2128349cc55cSDimitry Andric 
handleFunctionCompare(StringRef Name,StringRef Prefix,StringRef PassID,StringRef Divider,bool InModule,unsigned Minor,const FuncDataT<DCData> & Before,const FuncDataT<DCData> & After)2129349cc55cSDimitry Andric void DotCfgChangeReporter::handleFunctionCompare(
2130349cc55cSDimitry Andric     StringRef Name, StringRef Prefix, StringRef PassID, StringRef Divider,
2131349cc55cSDimitry Andric     bool InModule, unsigned Minor, const FuncDataT<DCData> &Before,
2132349cc55cSDimitry Andric     const FuncDataT<DCData> &After) {
2133349cc55cSDimitry Andric   assert(HTML && "Expected outstream to be set");
2134349cc55cSDimitry Andric   SmallString<8> Extender;
2135349cc55cSDimitry Andric   SmallString<8> Number;
2136349cc55cSDimitry Andric   // Handle numbering and file names.
2137349cc55cSDimitry Andric   if (InModule) {
2138349cc55cSDimitry Andric     Extender = formatv("{0}_{1}", N, Minor);
2139349cc55cSDimitry Andric     Number = formatv("{0}.{1}", N, Minor);
2140349cc55cSDimitry Andric   } else {
2141349cc55cSDimitry Andric     Extender = formatv("{0}", N);
2142349cc55cSDimitry Andric     Number = formatv("{0}", N);
2143349cc55cSDimitry Andric   }
2144349cc55cSDimitry Andric   // Create a temporary file name for the dot file.
2145349cc55cSDimitry Andric   SmallVector<char, 128> SV;
2146349cc55cSDimitry Andric   sys::fs::createUniquePath("cfgdot-%%%%%%.dot", SV, true);
2147349cc55cSDimitry Andric   std::string DotFile = Twine(SV).str();
2148349cc55cSDimitry Andric 
2149349cc55cSDimitry Andric   SmallString<20> PDFFileName = formatv("diff_{0}.pdf", Extender);
2150349cc55cSDimitry Andric   SmallString<200> Text;
2151349cc55cSDimitry Andric 
2152349cc55cSDimitry Andric   Text = formatv("{0}.{1}{2}{3}{4}", Number, Prefix, makeHTMLReady(PassID),
2153349cc55cSDimitry Andric                  Divider, Name);
2154349cc55cSDimitry Andric 
2155349cc55cSDimitry Andric   DotCfgDiff Diff(Text, Before, After);
2156349cc55cSDimitry Andric   std::string EntryBlockName = After.getEntryBlockName();
2157349cc55cSDimitry Andric   // Use the before entry block if the after entry block was removed.
2158349cc55cSDimitry Andric   if (EntryBlockName == "")
2159349cc55cSDimitry Andric     EntryBlockName = Before.getEntryBlockName();
2160349cc55cSDimitry Andric   assert(EntryBlockName != "" && "Expected to find entry block");
2161349cc55cSDimitry Andric 
2162349cc55cSDimitry Andric   DotCfgDiffDisplayGraph DG = Diff.createDisplayGraph(Text, EntryBlockName);
2163349cc55cSDimitry Andric   DG.generateDotFile(DotFile);
2164349cc55cSDimitry Andric 
2165349cc55cSDimitry Andric   *HTML << genHTML(Text, DotFile, PDFFileName);
2166349cc55cSDimitry Andric   std::error_code EC = sys::fs::remove(DotFile);
2167349cc55cSDimitry Andric   if (EC)
2168349cc55cSDimitry Andric     errs() << "Error: " << EC.message() << "\n";
2169349cc55cSDimitry Andric }
2170349cc55cSDimitry Andric 
genHTML(StringRef Text,StringRef DotFile,StringRef PDFFileName)2171349cc55cSDimitry Andric std::string DotCfgChangeReporter::genHTML(StringRef Text, StringRef DotFile,
2172349cc55cSDimitry Andric                                           StringRef PDFFileName) {
2173349cc55cSDimitry Andric   SmallString<20> PDFFile = formatv("{0}/{1}", DotCfgDir, PDFFileName);
2174349cc55cSDimitry Andric   // Create the PDF file.
2175349cc55cSDimitry Andric   static ErrorOr<std::string> DotExe = sys::findProgramByName(DotBinary);
2176349cc55cSDimitry Andric   if (!DotExe)
2177349cc55cSDimitry Andric     return "Unable to find dot executable.";
2178349cc55cSDimitry Andric 
2179349cc55cSDimitry Andric   StringRef Args[] = {DotBinary, "-Tpdf", "-o", PDFFile, DotFile};
2180bdd1243dSDimitry Andric   int Result = sys::ExecuteAndWait(*DotExe, Args, std::nullopt);
2181349cc55cSDimitry Andric   if (Result < 0)
2182349cc55cSDimitry Andric     return "Error executing system dot.";
2183349cc55cSDimitry Andric 
2184349cc55cSDimitry Andric   // Create the HTML tag refering to the PDF file.
2185349cc55cSDimitry Andric   SmallString<200> S = formatv(
2186349cc55cSDimitry Andric       "  <a href=\"{0}\" target=\"_blank\">{1}</a><br/>\n", PDFFileName, Text);
2187349cc55cSDimitry Andric   return S.c_str();
2188349cc55cSDimitry Andric }
2189349cc55cSDimitry Andric 
handleInitialIR(Any IR)2190349cc55cSDimitry Andric void DotCfgChangeReporter::handleInitialIR(Any IR) {
2191349cc55cSDimitry Andric   assert(HTML && "Expected outstream to be set");
2192349cc55cSDimitry Andric   *HTML << "<button type=\"button\" class=\"collapsible\">0. "
2193349cc55cSDimitry Andric         << "Initial IR (by function)</button>\n"
2194349cc55cSDimitry Andric         << "<div class=\"content\">\n"
2195349cc55cSDimitry Andric         << "  <p>\n";
2196349cc55cSDimitry Andric   // Create representation of IR
2197349cc55cSDimitry Andric   IRDataT<DCData> Data;
2198349cc55cSDimitry Andric   IRComparer<DCData>::analyzeIR(IR, Data);
2199349cc55cSDimitry Andric   // Now compare it against itself, which will have everything the
2200349cc55cSDimitry Andric   // same and will generate the files.
2201349cc55cSDimitry Andric   IRComparer<DCData>(Data, Data)
2202349cc55cSDimitry Andric       .compare(getModuleForComparison(IR),
2203349cc55cSDimitry Andric                [&](bool InModule, unsigned Minor,
2204349cc55cSDimitry Andric                    const FuncDataT<DCData> &Before,
2205349cc55cSDimitry Andric                    const FuncDataT<DCData> &After) -> void {
2206349cc55cSDimitry Andric                  handleFunctionCompare("", " ", "Initial IR", "", InModule,
2207349cc55cSDimitry Andric                                        Minor, Before, After);
2208349cc55cSDimitry Andric                });
2209349cc55cSDimitry Andric   *HTML << "  </p>\n"
2210349cc55cSDimitry Andric         << "</div><br/>\n";
2211349cc55cSDimitry Andric   ++N;
2212349cc55cSDimitry Andric }
2213349cc55cSDimitry Andric 
generateIRRepresentation(Any IR,StringRef PassID,IRDataT<DCData> & Data)2214349cc55cSDimitry Andric void DotCfgChangeReporter::generateIRRepresentation(Any IR, StringRef PassID,
2215349cc55cSDimitry Andric                                                     IRDataT<DCData> &Data) {
2216349cc55cSDimitry Andric   IRComparer<DCData>::analyzeIR(IR, Data);
2217349cc55cSDimitry Andric }
2218349cc55cSDimitry Andric 
omitAfter(StringRef PassID,std::string & Name)2219349cc55cSDimitry Andric void DotCfgChangeReporter::omitAfter(StringRef PassID, std::string &Name) {
2220349cc55cSDimitry Andric   assert(HTML && "Expected outstream to be set");
2221349cc55cSDimitry Andric   SmallString<20> Banner =
2222349cc55cSDimitry Andric       formatv("  <a>{0}. Pass {1} on {2} omitted because no change</a><br/>\n",
2223349cc55cSDimitry Andric               N, makeHTMLReady(PassID), Name);
2224349cc55cSDimitry Andric   *HTML << Banner;
2225349cc55cSDimitry Andric   ++N;
2226349cc55cSDimitry Andric }
2227349cc55cSDimitry Andric 
handleAfter(StringRef PassID,std::string & Name,const IRDataT<DCData> & Before,const IRDataT<DCData> & After,Any IR)2228349cc55cSDimitry Andric void DotCfgChangeReporter::handleAfter(StringRef PassID, std::string &Name,
2229349cc55cSDimitry Andric                                        const IRDataT<DCData> &Before,
2230349cc55cSDimitry Andric                                        const IRDataT<DCData> &After, Any IR) {
2231349cc55cSDimitry Andric   assert(HTML && "Expected outstream to be set");
2232349cc55cSDimitry Andric   IRComparer<DCData>(Before, After)
2233349cc55cSDimitry Andric       .compare(getModuleForComparison(IR),
2234349cc55cSDimitry Andric                [&](bool InModule, unsigned Minor,
2235349cc55cSDimitry Andric                    const FuncDataT<DCData> &Before,
2236349cc55cSDimitry Andric                    const FuncDataT<DCData> &After) -> void {
2237349cc55cSDimitry Andric                  handleFunctionCompare(Name, " Pass ", PassID, " on ", InModule,
2238349cc55cSDimitry Andric                                        Minor, Before, After);
2239349cc55cSDimitry Andric                });
2240349cc55cSDimitry Andric   *HTML << "    </p></div>\n";
2241349cc55cSDimitry Andric   ++N;
2242349cc55cSDimitry Andric }
2243349cc55cSDimitry Andric 
handleInvalidated(StringRef PassID)2244349cc55cSDimitry Andric void DotCfgChangeReporter::handleInvalidated(StringRef PassID) {
2245349cc55cSDimitry Andric   assert(HTML && "Expected outstream to be set");
2246349cc55cSDimitry Andric   SmallString<20> Banner =
2247349cc55cSDimitry Andric       formatv("  <a>{0}. {1} invalidated</a><br/>\n", N, makeHTMLReady(PassID));
2248349cc55cSDimitry Andric   *HTML << Banner;
2249349cc55cSDimitry Andric   ++N;
2250349cc55cSDimitry Andric }
2251349cc55cSDimitry Andric 
handleFiltered(StringRef PassID,std::string & Name)2252349cc55cSDimitry Andric void DotCfgChangeReporter::handleFiltered(StringRef PassID, std::string &Name) {
2253349cc55cSDimitry Andric   assert(HTML && "Expected outstream to be set");
2254349cc55cSDimitry Andric   SmallString<20> Banner =
2255349cc55cSDimitry Andric       formatv("  <a>{0}. Pass {1} on {2} filtered out</a><br/>\n", N,
2256349cc55cSDimitry Andric               makeHTMLReady(PassID), Name);
2257349cc55cSDimitry Andric   *HTML << Banner;
2258349cc55cSDimitry Andric   ++N;
2259349cc55cSDimitry Andric }
2260349cc55cSDimitry Andric 
handleIgnored(StringRef PassID,std::string & Name)2261349cc55cSDimitry Andric void DotCfgChangeReporter::handleIgnored(StringRef PassID, std::string &Name) {
2262349cc55cSDimitry Andric   assert(HTML && "Expected outstream to be set");
2263349cc55cSDimitry Andric   SmallString<20> Banner = formatv("  <a>{0}. {1} on {2} ignored</a><br/>\n", N,
2264349cc55cSDimitry Andric                                    makeHTMLReady(PassID), Name);
2265349cc55cSDimitry Andric   *HTML << Banner;
2266349cc55cSDimitry Andric   ++N;
2267349cc55cSDimitry Andric }
2268349cc55cSDimitry Andric 
initializeHTML()2269349cc55cSDimitry Andric bool DotCfgChangeReporter::initializeHTML() {
2270349cc55cSDimitry Andric   std::error_code EC;
2271349cc55cSDimitry Andric   HTML = std::make_unique<raw_fd_ostream>(DotCfgDir + "/passes.html", EC);
2272349cc55cSDimitry Andric   if (EC) {
2273349cc55cSDimitry Andric     HTML = nullptr;
2274349cc55cSDimitry Andric     return false;
2275349cc55cSDimitry Andric   }
2276349cc55cSDimitry Andric 
2277349cc55cSDimitry Andric   *HTML << "<!doctype html>"
2278349cc55cSDimitry Andric         << "<html>"
2279349cc55cSDimitry Andric         << "<head>"
2280349cc55cSDimitry Andric         << "<style>.collapsible { "
2281349cc55cSDimitry Andric         << "background-color: #777;"
2282349cc55cSDimitry Andric         << " color: white;"
2283349cc55cSDimitry Andric         << " cursor: pointer;"
2284349cc55cSDimitry Andric         << " padding: 18px;"
2285349cc55cSDimitry Andric         << " width: 100%;"
2286349cc55cSDimitry Andric         << " border: none;"
2287349cc55cSDimitry Andric         << " text-align: left;"
2288349cc55cSDimitry Andric         << " outline: none;"
2289349cc55cSDimitry Andric         << " font-size: 15px;"
2290349cc55cSDimitry Andric         << "} .active, .collapsible:hover {"
2291349cc55cSDimitry Andric         << " background-color: #555;"
2292349cc55cSDimitry Andric         << "} .content {"
2293349cc55cSDimitry Andric         << " padding: 0 18px;"
2294349cc55cSDimitry Andric         << " display: none;"
2295349cc55cSDimitry Andric         << " overflow: hidden;"
2296349cc55cSDimitry Andric         << " background-color: #f1f1f1;"
2297349cc55cSDimitry Andric         << "}"
2298349cc55cSDimitry Andric         << "</style>"
2299349cc55cSDimitry Andric         << "<title>passes.html</title>"
2300349cc55cSDimitry Andric         << "</head>\n"
2301349cc55cSDimitry Andric         << "<body>";
2302349cc55cSDimitry Andric   return true;
2303349cc55cSDimitry Andric }
2304349cc55cSDimitry Andric 
~DotCfgChangeReporter()2305349cc55cSDimitry Andric DotCfgChangeReporter::~DotCfgChangeReporter() {
2306349cc55cSDimitry Andric   if (!HTML)
2307349cc55cSDimitry Andric     return;
2308349cc55cSDimitry Andric   *HTML
2309349cc55cSDimitry Andric       << "<script>var coll = document.getElementsByClassName(\"collapsible\");"
2310349cc55cSDimitry Andric       << "var i;"
2311349cc55cSDimitry Andric       << "for (i = 0; i < coll.length; i++) {"
2312349cc55cSDimitry Andric       << "coll[i].addEventListener(\"click\", function() {"
2313349cc55cSDimitry Andric       << " this.classList.toggle(\"active\");"
2314349cc55cSDimitry Andric       << " var content = this.nextElementSibling;"
2315349cc55cSDimitry Andric       << " if (content.style.display === \"block\"){"
2316349cc55cSDimitry Andric       << " content.style.display = \"none\";"
2317349cc55cSDimitry Andric       << " }"
2318349cc55cSDimitry Andric       << " else {"
2319349cc55cSDimitry Andric       << " content.style.display= \"block\";"
2320349cc55cSDimitry Andric       << " }"
2321349cc55cSDimitry Andric       << " });"
2322349cc55cSDimitry Andric       << " }"
2323349cc55cSDimitry Andric       << "</script>"
2324349cc55cSDimitry Andric       << "</body>"
2325349cc55cSDimitry Andric       << "</html>\n";
2326349cc55cSDimitry Andric   HTML->flush();
2327349cc55cSDimitry Andric   HTML->close();
2328349cc55cSDimitry Andric }
2329349cc55cSDimitry Andric 
registerCallbacks(PassInstrumentationCallbacks & PIC)2330349cc55cSDimitry Andric void DotCfgChangeReporter::registerCallbacks(
2331349cc55cSDimitry Andric     PassInstrumentationCallbacks &PIC) {
2332fcaf7f86SDimitry Andric   if (PrintChanged == ChangePrinter::DotCfgVerbose ||
2333fcaf7f86SDimitry Andric        PrintChanged == ChangePrinter::DotCfgQuiet) {
2334349cc55cSDimitry Andric     SmallString<128> OutputDir;
2335349cc55cSDimitry Andric     sys::fs::expand_tilde(DotCfgDir, OutputDir);
2336349cc55cSDimitry Andric     sys::fs::make_absolute(OutputDir);
2337349cc55cSDimitry Andric     assert(!OutputDir.empty() && "expected output dir to be non-empty");
2338349cc55cSDimitry Andric     DotCfgDir = OutputDir.c_str();
2339349cc55cSDimitry Andric     if (initializeHTML()) {
2340349cc55cSDimitry Andric       ChangeReporter<IRDataT<DCData>>::registerRequiredCallbacks(PIC);
2341349cc55cSDimitry Andric       return;
2342349cc55cSDimitry Andric     }
2343349cc55cSDimitry Andric     dbgs() << "Unable to open output stream for -cfg-dot-changed\n";
2344349cc55cSDimitry Andric   }
2345fe6060f1SDimitry Andric }
2346fe6060f1SDimitry Andric 
StandardInstrumentations(LLVMContext & Context,bool DebugLogging,bool VerifyEach,PrintPassOptions PrintPassOpts)2347fe6060f1SDimitry Andric StandardInstrumentations::StandardInstrumentations(
2348bdd1243dSDimitry Andric     LLVMContext &Context, bool DebugLogging, bool VerifyEach,
2349bdd1243dSDimitry Andric     PrintPassOptions PrintPassOpts)
2350bdd1243dSDimitry Andric     : PrintPass(DebugLogging, PrintPassOpts),
2351bdd1243dSDimitry Andric       OptNone(DebugLogging),
2352bdd1243dSDimitry Andric       OptPassGate(Context),
2353fcaf7f86SDimitry Andric       PrintChangedIR(PrintChanged == ChangePrinter::Verbose),
2354fcaf7f86SDimitry Andric       PrintChangedDiff(PrintChanged == ChangePrinter::DiffVerbose ||
2355fcaf7f86SDimitry Andric                            PrintChanged == ChangePrinter::ColourDiffVerbose,
2356fcaf7f86SDimitry Andric                        PrintChanged == ChangePrinter::ColourDiffVerbose ||
2357fcaf7f86SDimitry Andric                            PrintChanged == ChangePrinter::ColourDiffQuiet),
2358fcaf7f86SDimitry Andric       WebsiteChangeReporter(PrintChanged == ChangePrinter::DotCfgVerbose),
2359fe6060f1SDimitry Andric       Verify(DebugLogging), VerifyEach(VerifyEach) {}
2360e8d8bef9SDimitry Andric 
236181ad6265SDimitry Andric PrintCrashIRInstrumentation *PrintCrashIRInstrumentation::CrashReporter =
236281ad6265SDimitry Andric     nullptr;
236381ad6265SDimitry Andric 
reportCrashIR()236406c3fb27SDimitry Andric void PrintCrashIRInstrumentation::reportCrashIR() {
236506c3fb27SDimitry Andric   if (!PrintOnCrashPath.empty()) {
236606c3fb27SDimitry Andric     std::error_code EC;
236706c3fb27SDimitry Andric     raw_fd_ostream Out(PrintOnCrashPath, EC);
236806c3fb27SDimitry Andric     if (EC)
236906c3fb27SDimitry Andric       report_fatal_error(errorCodeToError(EC));
237006c3fb27SDimitry Andric     Out << SavedIR;
237106c3fb27SDimitry Andric   } else {
237206c3fb27SDimitry Andric     dbgs() << SavedIR;
237306c3fb27SDimitry Andric   }
237406c3fb27SDimitry Andric }
237581ad6265SDimitry Andric 
SignalHandler(void *)237681ad6265SDimitry Andric void PrintCrashIRInstrumentation::SignalHandler(void *) {
237781ad6265SDimitry Andric   // Called by signal handlers so do not lock here
237881ad6265SDimitry Andric   // Is the PrintCrashIRInstrumentation still alive?
237981ad6265SDimitry Andric   if (!CrashReporter)
238081ad6265SDimitry Andric     return;
238181ad6265SDimitry Andric 
238206c3fb27SDimitry Andric   assert((PrintOnCrash || !PrintOnCrashPath.empty()) &&
238306c3fb27SDimitry Andric          "Did not expect to get here without option set.");
238481ad6265SDimitry Andric   CrashReporter->reportCrashIR();
238581ad6265SDimitry Andric }
238681ad6265SDimitry Andric 
~PrintCrashIRInstrumentation()238781ad6265SDimitry Andric PrintCrashIRInstrumentation::~PrintCrashIRInstrumentation() {
238881ad6265SDimitry Andric   if (!CrashReporter)
238981ad6265SDimitry Andric     return;
239081ad6265SDimitry Andric 
239106c3fb27SDimitry Andric   assert((PrintOnCrash || !PrintOnCrashPath.empty()) &&
239206c3fb27SDimitry Andric          "Did not expect to get here without option set.");
239381ad6265SDimitry Andric   CrashReporter = nullptr;
239481ad6265SDimitry Andric }
239581ad6265SDimitry Andric 
registerCallbacks(PassInstrumentationCallbacks & PIC)239681ad6265SDimitry Andric void PrintCrashIRInstrumentation::registerCallbacks(
239781ad6265SDimitry Andric     PassInstrumentationCallbacks &PIC) {
239806c3fb27SDimitry Andric   if ((!PrintOnCrash && PrintOnCrashPath.empty()) || CrashReporter)
239981ad6265SDimitry Andric     return;
240081ad6265SDimitry Andric 
240181ad6265SDimitry Andric   sys::AddSignalHandler(SignalHandler, nullptr);
240281ad6265SDimitry Andric   CrashReporter = this;
240381ad6265SDimitry Andric 
240406c3fb27SDimitry Andric   PIC.registerBeforeNonSkippedPassCallback(
240506c3fb27SDimitry Andric       [&PIC, this](StringRef PassID, Any IR) {
240681ad6265SDimitry Andric         SavedIR.clear();
240781ad6265SDimitry Andric         raw_string_ostream OS(SavedIR);
240881ad6265SDimitry Andric         OS << formatv("*** Dump of {0}IR Before Last Pass {1}",
240981ad6265SDimitry Andric                       llvm::forcePrintModuleIR() ? "Module " : "", PassID);
2410bdd1243dSDimitry Andric         if (!isInteresting(IR, PassID, PIC.getPassNameForClassName(PassID))) {
241181ad6265SDimitry Andric           OS << " Filtered Out ***\n";
241281ad6265SDimitry Andric           return;
241381ad6265SDimitry Andric         }
241481ad6265SDimitry Andric         OS << " Started ***\n";
241581ad6265SDimitry Andric         unwrapAndPrint(OS, IR);
241681ad6265SDimitry Andric       });
241781ad6265SDimitry Andric }
241881ad6265SDimitry Andric 
registerCallbacks(PassInstrumentationCallbacks & PIC,ModuleAnalysisManager * MAM)24190b57cec5SDimitry Andric void StandardInstrumentations::registerCallbacks(
242006c3fb27SDimitry Andric     PassInstrumentationCallbacks &PIC, ModuleAnalysisManager *MAM) {
24210b57cec5SDimitry Andric   PrintIR.registerCallbacks(PIC);
2422e8d8bef9SDimitry Andric   PrintPass.registerCallbacks(PIC);
24230b57cec5SDimitry Andric   TimePasses.registerCallbacks(PIC);
2424e8d8bef9SDimitry Andric   OptNone.registerCallbacks(PIC);
2425bdd1243dSDimitry Andric   OptPassGate.registerCallbacks(PIC);
2426e8d8bef9SDimitry Andric   PrintChangedIR.registerCallbacks(PIC);
2427d409305fSDimitry Andric   PseudoProbeVerification.registerCallbacks(PIC);
2428e8d8bef9SDimitry Andric   if (VerifyEach)
2429e8d8bef9SDimitry Andric     Verify.registerCallbacks(PIC);
2430fe6060f1SDimitry Andric   PrintChangedDiff.registerCallbacks(PIC);
2431349cc55cSDimitry Andric   WebsiteChangeReporter.registerCallbacks(PIC);
2432bdd1243dSDimitry Andric   ChangeTester.registerCallbacks(PIC);
243381ad6265SDimitry Andric   PrintCrashIR.registerCallbacks(PIC);
243406c3fb27SDimitry Andric   if (MAM)
243506c3fb27SDimitry Andric     PreservedCFGChecker.registerCallbacks(PIC, *MAM);
243606c3fb27SDimitry Andric 
2437bdd1243dSDimitry Andric   // TimeProfiling records the pass running time cost.
2438bdd1243dSDimitry Andric   // Its 'BeforePassCallback' can be appended at the tail of all the
2439bdd1243dSDimitry Andric   // BeforeCallbacks by calling `registerCallbacks` in the end.
2440bdd1243dSDimitry Andric   // Its 'AfterPassCallback' is put at the front of all the
2441bdd1243dSDimitry Andric   // AfterCallbacks by its `registerCallbacks`. This is necessary
2442bdd1243dSDimitry Andric   // to ensure that other callbacks are not included in the timings.
2443bdd1243dSDimitry Andric   TimeProfilingPasses.registerCallbacks(PIC);
24440b57cec5SDimitry Andric }
2445e8d8bef9SDimitry Andric 
2446e8d8bef9SDimitry Andric template class ChangeReporter<std::string>;
2447e8d8bef9SDimitry Andric template class TextChangeReporter<std::string>;
2448e8d8bef9SDimitry Andric 
2449349cc55cSDimitry Andric template class BlockDataT<EmptyData>;
2450349cc55cSDimitry Andric template class FuncDataT<EmptyData>;
2451349cc55cSDimitry Andric template class IRDataT<EmptyData>;
2452349cc55cSDimitry Andric template class ChangeReporter<IRDataT<EmptyData>>;
2453349cc55cSDimitry Andric template class TextChangeReporter<IRDataT<EmptyData>>;
2454349cc55cSDimitry Andric template class IRComparer<EmptyData>;
2455fe6060f1SDimitry Andric 
2456e8d8bef9SDimitry Andric } // namespace llvm
2457