brintos

brintos / llvm-project-archived public Read only

0
0
Text · 87.0 KiB · 6b7e980 Raw
2552 lines · cpp
1//===- Standard pass instrumentations handling ----------------*- C++ -*--===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8/// \file9///10/// This file defines IR-printing pass instrumentation callbacks as well as11/// StandardInstrumentations class that manages standard pass instrumentations.12///13//===----------------------------------------------------------------------===//14 15#include "llvm/Passes/StandardInstrumentations.h"16#include "llvm/ADT/Any.h"17#include "llvm/ADT/StringRef.h"18#include "llvm/Analysis/LazyCallGraph.h"19#include "llvm/Analysis/LoopInfo.h"20#include "llvm/CodeGen/MIRPrinter.h"21#include "llvm/CodeGen/MachineFunction.h"22#include "llvm/CodeGen/MachineModuleInfo.h"23#include "llvm/CodeGen/MachineVerifier.h"24#include "llvm/IR/Constants.h"25#include "llvm/IR/Function.h"26#include "llvm/IR/Module.h"27#include "llvm/IR/PassInstrumentation.h"28#include "llvm/IR/PassManager.h"29#include "llvm/IR/PrintPasses.h"30#include "llvm/IR/StructuralHash.h"31#include "llvm/IR/Verifier.h"32#include "llvm/Support/CommandLine.h"33#include "llvm/Support/Debug.h"34#include "llvm/Support/Error.h"35#include "llvm/Support/FormatVariadic.h"36#include "llvm/Support/GraphWriter.h"37#include "llvm/Support/Path.h"38#include "llvm/Support/Program.h"39#include "llvm/Support/Regex.h"40#include "llvm/Support/Signals.h"41#include "llvm/Support/raw_ostream.h"42#include "llvm/Support/xxhash.h"43#include <unordered_map>44#include <unordered_set>45#include <utility>46#include <vector>47 48using namespace llvm;49 50static cl::opt<bool> VerifyAnalysisInvalidation("verify-analysis-invalidation",51                                                cl::Hidden,52#ifdef EXPENSIVE_CHECKS53                                                cl::init(true)54#else55                                                cl::init(false)56#endif57);58 59// An option that supports the -print-changed option.  See60// the description for -print-changed for an explanation of the use61// of this option.  Note that this option has no effect without -print-changed.62static cl::opt<bool>63    PrintChangedBefore("print-before-changed",64                       cl::desc("Print before passes that change them"),65                       cl::init(false), cl::Hidden);66 67// An option for specifying the dot used by68// print-changed=[dot-cfg | dot-cfg-quiet]69static cl::opt<std::string>70    DotBinary("print-changed-dot-path", cl::Hidden, cl::init("dot"),71              cl::desc("system dot used by change reporters"));72 73// An option that determines the colour used for elements that are only74// in the before part.  Must be a colour named in appendix J of75// https://graphviz.org/pdf/dotguide.pdf76static cl::opt<std::string>77    BeforeColour("dot-cfg-before-color",78                 cl::desc("Color for dot-cfg before elements"), cl::Hidden,79                 cl::init("red"));80// An option that determines the colour used for elements that are only81// in the after part.  Must be a colour named in appendix J of82// https://graphviz.org/pdf/dotguide.pdf83static cl::opt<std::string>84    AfterColour("dot-cfg-after-color",85                cl::desc("Color for dot-cfg after elements"), cl::Hidden,86                cl::init("forestgreen"));87// An option that determines the colour used for elements that are in both88// the before and after parts.  Must be a colour named in appendix J of89// https://graphviz.org/pdf/dotguide.pdf90static cl::opt<std::string>91    CommonColour("dot-cfg-common-color",92                 cl::desc("Color for dot-cfg common elements"), cl::Hidden,93                 cl::init("black"));94 95// An option that determines where the generated website file (named96// passes.html) and the associated pdf files (named diff_*.pdf) are saved.97static cl::opt<std::string> DotCfgDir(98    "dot-cfg-dir",99    cl::desc("Generate dot files into specified directory for changed IRs"),100    cl::Hidden, cl::init("./"));101 102// Options to print the IR that was being processed when a pass crashes.103static cl::opt<std::string> PrintOnCrashPath(104    "print-on-crash-path",105    cl::desc("Print the last form of the IR before crash to a file"),106    cl::Hidden);107 108static cl::opt<bool> PrintOnCrash(109    "print-on-crash",110    cl::desc("Print the last form of the IR before crash (use -print-on-crash-path to dump to a file)"),111    cl::Hidden);112 113static cl::opt<std::string> OptBisectPrintIRPath(114    "opt-bisect-print-ir-path",115    cl::desc("Print IR to path when opt-bisect-limit is reached"), cl::Hidden);116 117static cl::opt<bool> PrintPassNumbers(118    "print-pass-numbers", cl::init(false), cl::Hidden,119    cl::desc("Print pass names and their ordinals"));120 121static cl::list<unsigned> PrintBeforePassNumber(122    "print-before-pass-number", cl::CommaSeparated, cl::Hidden,123    cl::desc("Print IR before the passes with specified numbers as "124             "reported by print-pass-numbers"));125 126static cl::list<unsigned> PrintAfterPassNumber(127    "print-after-pass-number", cl::CommaSeparated, cl::Hidden,128    cl::desc("Print IR after the passes with specified numbers as "129             "reported by print-pass-numbers"));130 131static cl::opt<std::string> IRDumpDirectory(132    "ir-dump-directory",133    cl::desc("If specified, IR printed using the "134             "-print-[before|after]{-all} options will be dumped into "135             "files in this directory rather than written to stderr"),136    cl::Hidden, cl::value_desc("filename"));137 138static cl::opt<bool>139    DroppedVarStats("dropped-variable-stats", cl::Hidden,140                    cl::desc("Dump dropped debug variables stats"),141                    cl::init(false));142 143template <typename IRUnitT> static const IRUnitT *unwrapIR(Any IR) {144  const IRUnitT **IRPtr = llvm::any_cast<const IRUnitT *>(&IR);145  return IRPtr ? *IRPtr : nullptr;146}147 148namespace {149 150// An option for specifying an executable that will be called with the IR151// everytime it changes in the opt pipeline.  It will also be called on152// the initial IR as it enters the pipeline.  The executable will be passed153// the name of a temporary file containing the IR and the PassID.  This may154// be used, for example, to call llc on the IR and run a test to determine155// which pass makes a change that changes the functioning of the IR.156// The usual modifier options work as expected.157static cl::opt<std::string>158    TestChanged("exec-on-ir-change", cl::Hidden, cl::init(""),159                cl::desc("exe called with module IR after each pass that "160                         "changes it"));161 162/// Extract Module out of \p IR unit. May return nullptr if \p IR does not match163/// certain global filters. Will never return nullptr if \p Force is true.164const Module *unwrapModule(Any IR, bool Force = false) {165  if (const auto *M = unwrapIR<Module>(IR))166    return M;167 168  if (const auto *F = unwrapIR<Function>(IR)) {169    if (!Force && !isFunctionInPrintList(F->getName()))170      return nullptr;171 172    return F->getParent();173  }174 175  if (const auto *C = unwrapIR<LazyCallGraph::SCC>(IR)) {176    for (const LazyCallGraph::Node &N : *C) {177      const Function &F = N.getFunction();178      if (Force || (!F.isDeclaration() && isFunctionInPrintList(F.getName()))) {179        return F.getParent();180      }181    }182    assert(!Force && "Expected a module");183    return nullptr;184  }185 186  if (const auto *L = unwrapIR<Loop>(IR)) {187    const Function *F = L->getHeader()->getParent();188    if (!Force && !isFunctionInPrintList(F->getName()))189      return nullptr;190    return F->getParent();191  }192 193  if (const auto *MF = unwrapIR<MachineFunction>(IR)) {194    if (!Force && !isFunctionInPrintList(MF->getName()))195      return nullptr;196    return MF->getFunction().getParent();197  }198 199  llvm_unreachable("Unknown IR unit");200}201 202void printIR(raw_ostream &OS, const Function *F) {203  if (!isFunctionInPrintList(F->getName()))204    return;205  OS << *F;206}207 208void printIR(raw_ostream &OS, const Module *M) {209  if (isFunctionInPrintList("*") || forcePrintModuleIR()) {210    M->print(OS, nullptr);211  } else {212    for (const auto &F : M->functions()) {213      printIR(OS, &F);214    }215  }216}217 218void printIR(raw_ostream &OS, const LazyCallGraph::SCC *C) {219  for (const LazyCallGraph::Node &N : *C) {220    const Function &F = N.getFunction();221    if (!F.isDeclaration() && isFunctionInPrintList(F.getName())) {222      F.print(OS);223    }224  }225}226 227void printIR(raw_ostream &OS, const Loop *L) {228  const Function *F = L->getHeader()->getParent();229  if (!isFunctionInPrintList(F->getName()))230    return;231  printLoop(const_cast<Loop &>(*L), OS);232}233 234void printIR(raw_ostream &OS, const MachineFunction *MF) {235  if (!isFunctionInPrintList(MF->getName()))236    return;237  MF->print(OS);238}239 240std::string getIRName(Any IR) {241  if (unwrapIR<Module>(IR))242    return "[module]";243 244  if (const auto *F = unwrapIR<Function>(IR))245    return F->getName().str();246 247  if (const auto *C = unwrapIR<LazyCallGraph::SCC>(IR))248    return C->getName();249 250  if (const auto *L = unwrapIR<Loop>(IR))251    return "loop %" + L->getName().str() + " in function " +252           L->getHeader()->getParent()->getName().str();253 254  if (const auto *MF = unwrapIR<MachineFunction>(IR))255    return MF->getName().str();256 257  llvm_unreachable("Unknown wrapped IR type");258}259 260bool moduleContainsFilterPrintFunc(const Module &M) {261  return any_of(M.functions(),262                [](const Function &F) {263                  return isFunctionInPrintList(F.getName());264                }) ||265         isFunctionInPrintList("*");266}267 268bool sccContainsFilterPrintFunc(const LazyCallGraph::SCC &C) {269  return any_of(C,270                [](const LazyCallGraph::Node &N) {271                  return isFunctionInPrintList(N.getName());272                }) ||273         isFunctionInPrintList("*");274}275 276bool shouldPrintIR(Any IR) {277  if (const auto *M = unwrapIR<Module>(IR))278    return moduleContainsFilterPrintFunc(*M);279 280  if (const auto *F = unwrapIR<Function>(IR))281    return isFunctionInPrintList(F->getName());282 283  if (const auto *C = unwrapIR<LazyCallGraph::SCC>(IR))284    return sccContainsFilterPrintFunc(*C);285 286  if (const auto *L = unwrapIR<Loop>(IR))287    return isFunctionInPrintList(L->getHeader()->getParent()->getName());288 289  if (const auto *MF = unwrapIR<MachineFunction>(IR))290    return isFunctionInPrintList(MF->getName());291  llvm_unreachable("Unknown wrapped IR type");292}293 294/// Generic IR-printing helper that unpacks a pointer to IRUnit wrapped into295/// Any and does actual print job.296void unwrapAndPrint(raw_ostream &OS, Any IR) {297  if (!shouldPrintIR(IR))298    return;299 300  if (forcePrintModuleIR()) {301    auto *M = unwrapModule(IR);302    assert(M && "should have unwrapped module");303    printIR(OS, M);304    return;305  }306 307  if (const auto *M = unwrapIR<Module>(IR)) {308    printIR(OS, M);309    return;310  }311 312  if (const auto *F = unwrapIR<Function>(IR)) {313    printIR(OS, F);314    return;315  }316 317  if (const auto *C = unwrapIR<LazyCallGraph::SCC>(IR)) {318    printIR(OS, C);319    return;320  }321 322  if (const auto *L = unwrapIR<Loop>(IR)) {323    printIR(OS, L);324    return;325  }326 327  if (const auto *MF = unwrapIR<MachineFunction>(IR)) {328    printIR(OS, MF);329    return;330  }331  llvm_unreachable("Unknown wrapped IR type");332}333 334// Return true when this is a pass for which changes should be ignored335bool isIgnored(StringRef PassID) {336  return isSpecialPass(PassID,337                       {"PassManager", "PassAdaptor", "AnalysisManagerProxy",338                        "DevirtSCCRepeatedPass", "ModuleInlinerWrapperPass",339                        "VerifierPass", "PrintModulePass", "PrintMIRPass",340                        "PrintMIRPreparePass"});341}342 343std::string makeHTMLReady(StringRef SR) {344  std::string S;345  while (true) {346    StringRef Clean =347        SR.take_until([](char C) { return C == '<' || C == '>'; });348    S.append(Clean.str());349    SR = SR.drop_front(Clean.size());350    if (SR.size() == 0)351      return S;352    S.append(SR[0] == '<' ? "&lt;" : "&gt;");353    SR = SR.drop_front();354  }355  llvm_unreachable("problems converting string to HTML");356}357 358// Return the module when that is the appropriate level of comparison for \p IR.359const Module *getModuleForComparison(Any IR) {360  if (const auto *M = unwrapIR<Module>(IR))361    return M;362  if (const auto *C = unwrapIR<LazyCallGraph::SCC>(IR))363    return C->begin()->getFunction().getParent();364  return nullptr;365}366 367bool isInterestingFunction(const Function &F) {368  return isFunctionInPrintList(F.getName());369}370 371// Return true when this is a pass on IR for which printing372// of changes is desired.373bool isInteresting(Any IR, StringRef PassID, StringRef PassName) {374  if (isIgnored(PassID) || !isPassInPrintList(PassName))375    return false;376  if (const auto *F = unwrapIR<Function>(IR))377    return isInterestingFunction(*F);378  return true;379}380 381} // namespace382 383template <typename T> ChangeReporter<T>::~ChangeReporter() {384  assert(BeforeStack.empty() && "Problem with Change Printer stack.");385}386 387template <typename T>388void ChangeReporter<T>::saveIRBeforePass(Any IR, StringRef PassID,389                                         StringRef PassName) {390  // Is this the initial IR?391  if (InitialIR) {392    InitialIR = false;393    if (VerboseMode)394      handleInitialIR(IR);395  }396 397  // Always need to place something on the stack because invalidated passes398  // are not given the IR so it cannot be determined whether the pass was for399  // something that was filtered out.400  BeforeStack.emplace_back();401 402  if (!isInteresting(IR, PassID, PassName))403    return;404 405  // Save the IR representation on the stack.406  T &Data = BeforeStack.back();407  generateIRRepresentation(IR, PassID, Data);408}409 410template <typename T>411void ChangeReporter<T>::handleIRAfterPass(Any IR, StringRef PassID,412                                          StringRef PassName) {413  assert(!BeforeStack.empty() && "Unexpected empty stack encountered.");414 415  std::string Name = getIRName(IR);416 417  if (isIgnored(PassID)) {418    if (VerboseMode)419      handleIgnored(PassID, Name);420  } else if (!isInteresting(IR, PassID, PassName)) {421    if (VerboseMode)422      handleFiltered(PassID, Name);423  } else {424    // Get the before rep from the stack425    T &Before = BeforeStack.back();426    // Create the after rep427    T After;428    generateIRRepresentation(IR, PassID, After);429 430    // Was there a change in IR?431    if (Before == After) {432      if (VerboseMode)433        omitAfter(PassID, Name);434    } else435      handleAfter(PassID, Name, Before, After, IR);436  }437  BeforeStack.pop_back();438}439 440template <typename T>441void ChangeReporter<T>::handleInvalidatedPass(StringRef PassID) {442  assert(!BeforeStack.empty() && "Unexpected empty stack encountered.");443 444  // Always flag it as invalidated as we cannot determine when445  // a pass for a filtered function is invalidated since we do not446  // get the IR in the call.  Also, the output is just alternate447  // forms of the banner anyway.448  if (VerboseMode)449    handleInvalidated(PassID);450  BeforeStack.pop_back();451}452 453template <typename T>454void ChangeReporter<T>::registerRequiredCallbacks(455    PassInstrumentationCallbacks &PIC) {456  PIC.registerBeforeNonSkippedPassCallback([&PIC, this](StringRef P, Any IR) {457    saveIRBeforePass(IR, P, PIC.getPassNameForClassName(P));458  });459 460  PIC.registerAfterPassCallback(461      [&PIC, this](StringRef P, Any IR, const PreservedAnalyses &) {462        handleIRAfterPass(IR, P, PIC.getPassNameForClassName(P));463      });464  PIC.registerAfterPassInvalidatedCallback(465      [this](StringRef P, const PreservedAnalyses &) {466        handleInvalidatedPass(P);467      });468}469 470template <typename T>471TextChangeReporter<T>::TextChangeReporter(bool Verbose)472    : ChangeReporter<T>(Verbose), Out(dbgs()) {}473 474template <typename T> void TextChangeReporter<T>::handleInitialIR(Any IR) {475  // Always print the module.476  // Unwrap and print directly to avoid filtering problems in general routines.477  auto *M = unwrapModule(IR, /*Force=*/true);478  assert(M && "Expected module to be unwrapped when forced.");479  Out << "*** IR Dump At Start ***\n";480  M->print(Out, nullptr);481}482 483template <typename T>484void TextChangeReporter<T>::omitAfter(StringRef PassID, std::string &Name) {485  Out << formatv("*** IR Dump After {0} on {1} omitted because no change ***\n",486                 PassID, Name);487}488 489template <typename T>490void TextChangeReporter<T>::handleInvalidated(StringRef PassID) {491  Out << formatv("*** IR Pass {0} invalidated ***\n", PassID);492}493 494template <typename T>495void TextChangeReporter<T>::handleFiltered(StringRef PassID,496                                           std::string &Name) {497  SmallString<20> Banner =498      formatv("*** IR Dump After {0} on {1} filtered out ***\n", PassID, Name);499  Out << Banner;500}501 502template <typename T>503void TextChangeReporter<T>::handleIgnored(StringRef PassID, std::string &Name) {504  Out << formatv("*** IR Pass {0} on {1} ignored ***\n", PassID, Name);505}506 507IRChangedPrinter::~IRChangedPrinter() = default;508 509void IRChangedPrinter::registerCallbacks(PassInstrumentationCallbacks &PIC) {510  if (PrintChanged == ChangePrinter::Verbose ||511      PrintChanged == ChangePrinter::Quiet)512    TextChangeReporter<std::string>::registerRequiredCallbacks(PIC);513}514 515void IRChangedPrinter::generateIRRepresentation(Any IR, StringRef PassID,516                                                std::string &Output) {517  raw_string_ostream OS(Output);518  unwrapAndPrint(OS, IR);519  OS.str();520}521 522void IRChangedPrinter::handleAfter(StringRef PassID, std::string &Name,523                                   const std::string &Before,524                                   const std::string &After, Any) {525  // Report the IR before the changes when requested.526  if (PrintChangedBefore)527    Out << "*** IR Dump Before " << PassID << " on " << Name << " ***\n"528        << Before;529 530  // We might not get anything to print if we only want to print a specific531  // function but it gets deleted.532  if (After.empty()) {533    Out << "*** IR Deleted After " << PassID << " on " << Name << " ***\n";534    return;535  }536 537  Out << "*** IR Dump After " << PassID << " on " << Name << " ***\n" << After;538}539 540IRChangedTester::~IRChangedTester() = default;541 542void IRChangedTester::registerCallbacks(PassInstrumentationCallbacks &PIC) {543  if (TestChanged != "")544    TextChangeReporter<std::string>::registerRequiredCallbacks(PIC);545}546 547void IRChangedTester::handleIR(const std::string &S, StringRef PassID) {548  // Store the body into a temporary file549  static SmallVector<int> FD{-1};550  SmallVector<StringRef> SR{S};551  static SmallVector<std::string> FileName{""};552  if (prepareTempFiles(FD, SR, FileName)) {553    dbgs() << "Unable to create temporary file.";554    return;555  }556  static ErrorOr<std::string> Exe = sys::findProgramByName(TestChanged);557  if (!Exe) {558    dbgs() << "Unable to find test-changed executable.";559    return;560  }561 562  StringRef Args[] = {TestChanged, FileName[0], PassID};563  int Result = sys::ExecuteAndWait(*Exe, Args);564  if (Result < 0) {565    dbgs() << "Error executing test-changed executable.";566    return;567  }568 569  if (cleanUpTempFiles(FileName))570    dbgs() << "Unable to remove temporary file.";571}572 573void IRChangedTester::handleInitialIR(Any IR) {574  // Always test the initial module.575  // Unwrap and print directly to avoid filtering problems in general routines.576  std::string S;577  generateIRRepresentation(IR, "Initial IR", S);578  handleIR(S, "Initial IR");579}580 581void IRChangedTester::omitAfter(StringRef PassID, std::string &Name) {}582void IRChangedTester::handleInvalidated(StringRef PassID) {}583void IRChangedTester::handleFiltered(StringRef PassID, std::string &Name) {}584void IRChangedTester::handleIgnored(StringRef PassID, std::string &Name) {}585void IRChangedTester::handleAfter(StringRef PassID, std::string &Name,586                                  const std::string &Before,587                                  const std::string &After, Any) {588  handleIR(After, PassID);589}590 591template <typename T>592void OrderedChangedData<T>::report(593    const OrderedChangedData &Before, const OrderedChangedData &After,594    function_ref<void(const T *, const T *)> HandlePair) {595  const auto &BFD = Before.getData();596  const auto &AFD = After.getData();597  std::vector<std::string>::const_iterator BI = Before.getOrder().begin();598  std::vector<std::string>::const_iterator BE = Before.getOrder().end();599  std::vector<std::string>::const_iterator AI = After.getOrder().begin();600  std::vector<std::string>::const_iterator AE = After.getOrder().end();601 602  auto HandlePotentiallyRemovedData = [&](std::string S) {603    // The order in LLVM may have changed so check if still exists.604    if (!AFD.count(S)) {605      // This has been removed.606      HandlePair(&BFD.find(*BI)->getValue(), nullptr);607    }608  };609  auto HandleNewData = [&](std::vector<const T *> &Q) {610    // Print out any queued up new sections611    for (const T *NBI : Q)612      HandlePair(nullptr, NBI);613    Q.clear();614  };615 616  // Print out the data in the after order, with before ones interspersed617  // appropriately (ie, somewhere near where they were in the before list).618  // Start at the beginning of both lists.  Loop through the619  // after list.  If an element is common, then advance in the before list620  // reporting the removed ones until the common one is reached.  Report any621  // queued up new ones and then report the common one.  If an element is not622  // common, then enqueue it for reporting.  When the after list is exhausted,623  // loop through the before list, reporting any removed ones.  Finally,624  // report the rest of the enqueued new ones.625  std::vector<const T *> NewDataQueue;626  while (AI != AE) {627    if (!BFD.count(*AI)) {628      // This section is new so place it in the queue.  This will cause it629      // to be reported after deleted sections.630      NewDataQueue.emplace_back(&AFD.find(*AI)->getValue());631      ++AI;632      continue;633    }634    // This section is in both; advance and print out any before-only635    // until we get to it.636    // It's possible that this section has moved to be later than before. This637    // will mess up printing most blocks side by side, but it's a rare case and638    // it's better than crashing.639    while (BI != BE && *BI != *AI) {640      HandlePotentiallyRemovedData(*BI);641      ++BI;642    }643    // Report any new sections that were queued up and waiting.644    HandleNewData(NewDataQueue);645 646    const T &AData = AFD.find(*AI)->getValue();647    const T &BData = BFD.find(*AI)->getValue();648    HandlePair(&BData, &AData);649    if (BI != BE)650      ++BI;651    ++AI;652  }653 654  // Check any remaining before sections to see if they have been removed655  while (BI != BE) {656    HandlePotentiallyRemovedData(*BI);657    ++BI;658  }659 660  HandleNewData(NewDataQueue);661}662 663template <typename T>664void IRComparer<T>::compare(665    bool CompareModule,666    std::function<void(bool InModule, unsigned Minor,667                       const FuncDataT<T> &Before, const FuncDataT<T> &After)>668        CompareFunc) {669  if (!CompareModule) {670    // Just handle the single function.671    assert(Before.getData().size() == 1 && After.getData().size() == 1 &&672           "Expected only one function.");673    CompareFunc(false, 0, Before.getData().begin()->getValue(),674                After.getData().begin()->getValue());675    return;676  }677 678  unsigned Minor = 0;679  FuncDataT<T> Missing("");680  IRDataT<T>::report(Before, After,681                     [&](const FuncDataT<T> *B, const FuncDataT<T> *A) {682                       assert((B || A) && "Both functions cannot be missing.");683                       if (!B)684                         B = &Missing;685                       else if (!A)686                         A = &Missing;687                       CompareFunc(true, Minor++, *B, *A);688                     });689}690 691template <typename T> void IRComparer<T>::analyzeIR(Any IR, IRDataT<T> &Data) {692  if (const Module *M = getModuleForComparison(IR)) {693    // Create data for each existing/interesting function in the module.694    for (const Function &F : *M)695      generateFunctionData(Data, F);696    return;697  }698 699  if (const auto *F = unwrapIR<Function>(IR)) {700    generateFunctionData(Data, *F);701    return;702  }703 704  if (const auto *L = unwrapIR<Loop>(IR)) {705    auto *F = L->getHeader()->getParent();706    generateFunctionData(Data, *F);707    return;708  }709 710  if (const auto *MF = unwrapIR<MachineFunction>(IR)) {711    generateFunctionData(Data, *MF);712    return;713  }714 715  llvm_unreachable("Unknown IR unit");716}717 718static bool shouldGenerateData(const Function &F) {719  return !F.isDeclaration() && isFunctionInPrintList(F.getName());720}721 722static bool shouldGenerateData(const MachineFunction &MF) {723  return isFunctionInPrintList(MF.getName());724}725 726template <typename T>727template <typename FunctionT>728bool IRComparer<T>::generateFunctionData(IRDataT<T> &Data, const FunctionT &F) {729  if (shouldGenerateData(F)) {730    FuncDataT<T> FD(F.front().getName().str());731    int I = 0;732    for (const auto &B : F) {733      std::string BBName = B.getName().str();734      if (BBName.empty()) {735        BBName = formatv("{0}", I);736        ++I;737      }738      FD.getOrder().emplace_back(BBName);739      FD.getData().insert({BBName, B});740    }741    Data.getOrder().emplace_back(F.getName());742    Data.getData().insert({F.getName(), FD});743    return true;744  }745  return false;746}747 748PrintIRInstrumentation::~PrintIRInstrumentation() {749  assert(PassRunDescriptorStack.empty() &&750         "PassRunDescriptorStack is not empty at exit");751}752 753static void writeIRFileDisplayName(raw_ostream &ResultStream, Any IR) {754  const Module *M = unwrapModule(IR, /*Force=*/true);755  assert(M && "should have unwrapped module");756  uint64_t NameHash = xxh3_64bits(M->getName());757  unsigned MaxHashWidth = sizeof(uint64_t) * 2;758  write_hex(ResultStream, NameHash, HexPrintStyle::Lower, MaxHashWidth);759  if (unwrapIR<Module>(IR)) {760    ResultStream << "-module";761  } else if (const auto *F = unwrapIR<Function>(IR)) {762    ResultStream << "-function-";763    auto FunctionNameHash = xxh3_64bits(F->getName());764    write_hex(ResultStream, FunctionNameHash, HexPrintStyle::Lower,765              MaxHashWidth);766  } else if (const auto *C = unwrapIR<LazyCallGraph::SCC>(IR)) {767    ResultStream << "-scc-";768    auto SCCNameHash = xxh3_64bits(C->getName());769    write_hex(ResultStream, SCCNameHash, HexPrintStyle::Lower, MaxHashWidth);770  } else if (const auto *L = unwrapIR<Loop>(IR)) {771    ResultStream << "-loop-";772    auto LoopNameHash = xxh3_64bits(L->getName());773    write_hex(ResultStream, LoopNameHash, HexPrintStyle::Lower, MaxHashWidth);774  } else if (const auto *MF = unwrapIR<MachineFunction>(IR)) {775    ResultStream << "-machine-function-";776    auto MachineFunctionNameHash = xxh3_64bits(MF->getName());777    write_hex(ResultStream, MachineFunctionNameHash, HexPrintStyle::Lower,778              MaxHashWidth);779  } else {780    llvm_unreachable("Unknown wrapped IR type");781  }782}783 784static std::string getIRFileDisplayName(Any IR) {785  std::string Result;786  raw_string_ostream ResultStream(Result);787  writeIRFileDisplayName(ResultStream, IR);788  return Result;789}790 791StringRef PrintIRInstrumentation::getFileSuffix(IRDumpFileSuffixType Type) {792  static constexpr std::array FileSuffixes = {"-before.ll", "-after.ll",793                                              "-invalidated.ll"};794  return FileSuffixes[static_cast<size_t>(Type)];795}796 797std::string PrintIRInstrumentation::fetchDumpFilename(798    StringRef PassName, StringRef IRFileDisplayName, unsigned PassNumber,799    IRDumpFileSuffixType SuffixType) {800  assert(!IRDumpDirectory.empty() &&801         "The flag -ir-dump-directory must be passed to dump IR to files");802 803  SmallString<64> Filename;804  raw_svector_ostream FilenameStream(Filename);805  FilenameStream << PassNumber;806  FilenameStream << '-' << IRFileDisplayName << '-';807  FilenameStream << PassName;808  FilenameStream << getFileSuffix(SuffixType);809 810  SmallString<128> ResultPath;811  sys::path::append(ResultPath, IRDumpDirectory, Filename);812  return std::string(ResultPath);813}814 815void PrintIRInstrumentation::pushPassRunDescriptor(StringRef PassID, Any IR,816                                                   unsigned PassNumber) {817  const Module *M = unwrapModule(IR);818  PassRunDescriptorStack.emplace_back(M, PassNumber, getIRFileDisplayName(IR),819                                      getIRName(IR), PassID);820}821 822PrintIRInstrumentation::PassRunDescriptor823PrintIRInstrumentation::popPassRunDescriptor(StringRef PassID) {824  assert(!PassRunDescriptorStack.empty() && "empty PassRunDescriptorStack");825  PassRunDescriptor Descriptor = PassRunDescriptorStack.pop_back_val();826  assert(Descriptor.PassID == PassID && "malformed PassRunDescriptorStack");827  return Descriptor;828}829 830// Callers are responsible for closing the returned file descriptor831static int prepareDumpIRFileDescriptor(const StringRef DumpIRFilename) {832  std::error_code EC;833  auto ParentPath = llvm::sys::path::parent_path(DumpIRFilename);834  if (!ParentPath.empty()) {835    std::error_code EC = llvm::sys::fs::create_directories(ParentPath);836    if (EC)837      report_fatal_error(Twine("Failed to create directory ") + ParentPath +838                         " to support -ir-dump-directory: " + EC.message());839  }840  int Result = 0;841  EC = sys::fs::openFile(DumpIRFilename, Result, sys::fs::CD_OpenAlways,842                         sys::fs::FA_Write, sys::fs::OF_Text);843  if (EC)844    report_fatal_error(Twine("Failed to open ") + DumpIRFilename +845                       " to support -ir-dump-directory: " + EC.message());846  return Result;847}848 849void PrintIRInstrumentation::printBeforePass(StringRef PassID, Any IR) {850  if (isIgnored(PassID))851    return;852 853  // Saving Module for AfterPassInvalidated operations.854  // Note: here we rely on a fact that we do not change modules while855  // traversing the pipeline, so the latest captured module is good856  // for all print operations that has not happen yet.857  if (shouldPrintAfterPass(PassID))858    pushPassRunDescriptor(PassID, IR, CurrentPassNumber);859 860  if (!shouldPrintIR(IR))861    return;862 863  ++CurrentPassNumber;864 865  if (shouldPrintPassNumbers())866    dbgs() << " Running pass " << CurrentPassNumber << " " << PassID867           << " on " << getIRName(IR) << "\n";868 869  if (shouldPrintAfterCurrentPassNumber())870    pushPassRunDescriptor(PassID, IR, CurrentPassNumber);871 872  if (!shouldPrintBeforePass(PassID) && !shouldPrintBeforeCurrentPassNumber())873    return;874 875  auto WriteIRToStream = [&](raw_ostream &Stream) {876    Stream << "; *** IR Dump Before ";877    if (shouldPrintBeforeSomePassNumber())878      Stream << CurrentPassNumber << "-";879    Stream << PassID << " on " << getIRName(IR) << " ***\n";880    unwrapAndPrint(Stream, IR);881  };882 883  if (!IRDumpDirectory.empty()) {884    std::string DumpIRFilename =885        fetchDumpFilename(PassID, getIRFileDisplayName(IR), CurrentPassNumber,886                          IRDumpFileSuffixType::Before);887    llvm::raw_fd_ostream DumpIRFileStream{888        prepareDumpIRFileDescriptor(DumpIRFilename), /* shouldClose */ true};889    WriteIRToStream(DumpIRFileStream);890  } else {891    WriteIRToStream(dbgs());892  }893}894 895void PrintIRInstrumentation::printAfterPass(StringRef PassID, Any IR) {896  if (isIgnored(PassID))897    return;898 899  if (!shouldPrintAfterPass(PassID) && !shouldPrintAfterCurrentPassNumber())900    return;901 902  auto [M, PassNumber, IRFileDisplayName, IRName, StoredPassID] =903      popPassRunDescriptor(PassID);904  assert(StoredPassID == PassID && "mismatched PassID");905 906  if (!shouldPrintIR(IR) ||907      (!shouldPrintAfterPass(PassID) && !shouldPrintAfterCurrentPassNumber()))908    return;909 910  auto WriteIRToStream = [&](raw_ostream &Stream, const StringRef IRName) {911    Stream << "; *** IR Dump After ";912    if (shouldPrintAfterSomePassNumber())913      Stream << CurrentPassNumber << "-";914    Stream << StringRef(formatv("{0}", PassID)) << " on " << IRName << " ***\n";915    unwrapAndPrint(Stream, IR);916  };917 918  if (!IRDumpDirectory.empty()) {919    std::string DumpIRFilename =920        fetchDumpFilename(PassID, getIRFileDisplayName(IR), CurrentPassNumber,921                          IRDumpFileSuffixType::After);922    llvm::raw_fd_ostream DumpIRFileStream{923        prepareDumpIRFileDescriptor(DumpIRFilename),924        /* shouldClose */ true};925    WriteIRToStream(DumpIRFileStream, IRName);926  } else {927    WriteIRToStream(dbgs(), IRName);928  }929}930 931void PrintIRInstrumentation::printAfterPassInvalidated(StringRef PassID) {932  if (isIgnored(PassID))933    return;934 935  if (!shouldPrintAfterPass(PassID) && !shouldPrintAfterCurrentPassNumber())936    return;937 938  auto [M, PassNumber, IRFileDisplayName, IRName, StoredPassID] =939      popPassRunDescriptor(PassID);940  assert(StoredPassID == PassID && "mismatched PassID");941  // Additional filtering (e.g. -filter-print-func) can lead to module942  // printing being skipped.943  if (!M ||944      (!shouldPrintAfterPass(PassID) && !shouldPrintAfterCurrentPassNumber()))945    return;946 947  auto WriteIRToStream = [&](raw_ostream &Stream, const Module *M,948                             const StringRef IRName) {949    SmallString<20> Banner;950    Banner = formatv("; *** IR Dump After {0} on {1} (invalidated) ***", PassID,951                     IRName);952    Stream << Banner << "\n";953    printIR(Stream, M);954  };955 956  if (!IRDumpDirectory.empty()) {957    std::string DumpIRFilename =958        fetchDumpFilename(PassID, IRFileDisplayName, PassNumber,959                          IRDumpFileSuffixType::Invalidated);960    llvm::raw_fd_ostream DumpIRFileStream{961        prepareDumpIRFileDescriptor(DumpIRFilename),962        /*shouldClose=*/true};963    WriteIRToStream(DumpIRFileStream, M, IRName);964  } else {965    WriteIRToStream(dbgs(), M, IRName);966  }967}968 969bool PrintIRInstrumentation::shouldPrintBeforePass(StringRef PassID) {970  if (shouldPrintBeforeAll())971    return true;972 973  StringRef PassName = PIC->getPassNameForClassName(PassID);974  return is_contained(printBeforePasses(), PassName);975}976 977bool PrintIRInstrumentation::shouldPrintAfterPass(StringRef PassID) {978  if (shouldPrintAfterAll())979    return true;980 981  StringRef PassName = PIC->getPassNameForClassName(PassID);982  return is_contained(printAfterPasses(), PassName);983}984 985bool PrintIRInstrumentation::shouldPrintBeforeCurrentPassNumber() {986  return shouldPrintBeforeSomePassNumber() &&987         (is_contained(PrintBeforePassNumber, CurrentPassNumber));988}989 990bool PrintIRInstrumentation::shouldPrintAfterCurrentPassNumber() {991  return shouldPrintAfterSomePassNumber() &&992         (is_contained(PrintAfterPassNumber, CurrentPassNumber));993}994 995bool PrintIRInstrumentation::shouldPrintPassNumbers() {996  return PrintPassNumbers;997}998 999bool PrintIRInstrumentation::shouldPrintBeforeSomePassNumber() {1000  return !PrintBeforePassNumber.empty();1001}1002 1003bool PrintIRInstrumentation::shouldPrintAfterSomePassNumber() {1004  return !PrintAfterPassNumber.empty();1005}1006 1007void PrintIRInstrumentation::registerCallbacks(1008    PassInstrumentationCallbacks &PIC) {1009  this->PIC = &PIC;1010 1011  // BeforePass callback is not just for printing, it also saves a Module1012  // for later use in AfterPassInvalidated and keeps tracks of the1013  // CurrentPassNumber.1014  if (shouldPrintPassNumbers() || shouldPrintBeforeSomePassNumber() ||1015      shouldPrintAfterSomePassNumber() || shouldPrintBeforeSomePass() ||1016      shouldPrintAfterSomePass())1017    PIC.registerBeforeNonSkippedPassCallback(1018        [this](StringRef P, Any IR) { this->printBeforePass(P, IR); });1019 1020  if (shouldPrintAfterSomePass() || shouldPrintAfterSomePassNumber()) {1021    PIC.registerAfterPassCallback(1022        [this](StringRef P, Any IR, const PreservedAnalyses &) {1023          this->printAfterPass(P, IR);1024        });1025    PIC.registerAfterPassInvalidatedCallback(1026        [this](StringRef P, const PreservedAnalyses &) {1027          this->printAfterPassInvalidated(P);1028        });1029  }1030}1031 1032void OptNoneInstrumentation::registerCallbacks(1033    PassInstrumentationCallbacks &PIC) {1034  PIC.registerShouldRunOptionalPassCallback(1035      [this](StringRef P, Any IR) { return this->shouldRun(P, IR); });1036}1037 1038bool OptNoneInstrumentation::shouldRun(StringRef PassID, Any IR) {1039  bool ShouldRun = true;1040  if (const auto *F = unwrapIR<Function>(IR))1041    ShouldRun = !F->hasOptNone();1042  else if (const auto *L = unwrapIR<Loop>(IR))1043    ShouldRun = !L->getHeader()->getParent()->hasOptNone();1044  else if (const auto *MF = unwrapIR<MachineFunction>(IR))1045    ShouldRun = !MF->getFunction().hasOptNone();1046 1047  if (!ShouldRun && DebugLogging) {1048    errs() << "Skipping pass " << PassID << " on " << getIRName(IR)1049           << " due to optnone attribute\n";1050  }1051  return ShouldRun;1052}1053 1054bool OptPassGateInstrumentation::shouldRun(StringRef PassName, Any IR) {1055  if (isIgnored(PassName))1056    return true;1057 1058  bool ShouldRun =1059      Context.getOptPassGate().shouldRunPass(PassName, getIRName(IR));1060  if (!ShouldRun && !this->HasWrittenIR && !OptBisectPrintIRPath.empty()) {1061    // FIXME: print IR if limit is higher than number of opt-bisect1062    // invocations1063    this->HasWrittenIR = true;1064    const Module *M = unwrapModule(IR, /*Force=*/true);1065    assert((M && &M->getContext() == &Context) && "Missing/Mismatching Module");1066    std::error_code EC;1067    raw_fd_ostream OS(OptBisectPrintIRPath, EC);1068    if (EC)1069      report_fatal_error(errorCodeToError(EC));1070    M->print(OS, nullptr);1071  }1072  return ShouldRun;1073}1074 1075void OptPassGateInstrumentation::registerCallbacks(1076    PassInstrumentationCallbacks &PIC) {1077  const OptPassGate &PassGate = Context.getOptPassGate();1078  if (!PassGate.isEnabled())1079    return;1080 1081  PIC.registerShouldRunOptionalPassCallback(1082      [this, &PIC](StringRef ClassName, Any IR) {1083        StringRef PassName = PIC.getPassNameForClassName(ClassName);1084        if (PassName.empty())1085          return this->shouldRun(ClassName, IR);1086        return this->shouldRun(PassName, IR);1087      });1088}1089 1090raw_ostream &PrintPassInstrumentation::print() {1091  if (Opts.Indent) {1092    assert(Indent >= 0);1093    dbgs().indent(Indent);1094  }1095  return dbgs();1096}1097 1098void PrintPassInstrumentation::registerCallbacks(1099    PassInstrumentationCallbacks &PIC) {1100  if (!Enabled)1101    return;1102 1103  std::vector<StringRef> SpecialPasses;1104  if (!Opts.Verbose) {1105    SpecialPasses.emplace_back("PassManager");1106    SpecialPasses.emplace_back("PassAdaptor");1107  }1108 1109  PIC.registerBeforeSkippedPassCallback([this, SpecialPasses](StringRef PassID,1110                                                              Any IR) {1111    assert(!isSpecialPass(PassID, SpecialPasses) &&1112           "Unexpectedly skipping special pass");1113 1114    print() << "Skipping pass: " << PassID << " on " << getIRName(IR) << "\n";1115  });1116  PIC.registerBeforeNonSkippedPassCallback([this, SpecialPasses](1117                                               StringRef PassID, Any IR) {1118    if (isSpecialPass(PassID, SpecialPasses))1119      return;1120 1121    auto &OS = print();1122    OS << "Running pass: " << PassID << " on " << getIRName(IR);1123    if (const auto *F = unwrapIR<Function>(IR)) {1124      unsigned Count = F->getInstructionCount();1125      OS << " (" << Count << " instruction";1126      if (Count != 1)1127        OS << 's';1128      OS << ')';1129    } else if (const auto *C = unwrapIR<LazyCallGraph::SCC>(IR)) {1130      int Count = C->size();1131      OS << " (" << Count << " node";1132      if (Count != 1)1133        OS << 's';1134      OS << ')';1135    }1136    OS << "\n";1137    Indent += 2;1138  });1139  PIC.registerAfterPassCallback(1140      [this, SpecialPasses](StringRef PassID, Any IR,1141                            const PreservedAnalyses &) {1142        if (isSpecialPass(PassID, SpecialPasses))1143          return;1144 1145        Indent -= 2;1146      });1147  PIC.registerAfterPassInvalidatedCallback(1148      [this, SpecialPasses](StringRef PassID, Any IR) {1149        if (isSpecialPass(PassID, SpecialPasses))1150          return;1151 1152        Indent -= 2;1153      });1154 1155  if (!Opts.SkipAnalyses) {1156    PIC.registerBeforeAnalysisCallback([this](StringRef PassID, Any IR) {1157      print() << "Running analysis: " << PassID << " on " << getIRName(IR)1158              << "\n";1159      Indent += 2;1160    });1161    PIC.registerAfterAnalysisCallback(1162        [this](StringRef PassID, Any IR) { Indent -= 2; });1163    PIC.registerAnalysisInvalidatedCallback([this](StringRef PassID, Any IR) {1164      print() << "Invalidating analysis: " << PassID << " on " << getIRName(IR)1165              << "\n";1166    });1167    PIC.registerAnalysesClearedCallback([this](StringRef IRName) {1168      print() << "Clearing all analysis results for: " << IRName << "\n";1169    });1170  }1171}1172 1173PreservedCFGCheckerInstrumentation::CFG::CFG(const Function *F,1174                                             bool TrackBBLifetime) {1175  if (TrackBBLifetime)1176    BBGuards = DenseMap<intptr_t, BBGuard>(F->size());1177  for (const auto &BB : *F) {1178    if (BBGuards)1179      BBGuards->try_emplace(intptr_t(&BB), &BB);1180    for (const auto *Succ : successors(&BB)) {1181      Graph[&BB][Succ]++;1182      if (BBGuards)1183        BBGuards->try_emplace(intptr_t(Succ), Succ);1184    }1185  }1186}1187 1188static void printBBName(raw_ostream &out, const BasicBlock *BB) {1189  if (BB->hasName()) {1190    out << BB->getName() << "<" << BB << ">";1191    return;1192  }1193 1194  if (!BB->getParent()) {1195    out << "unnamed_removed<" << BB << ">";1196    return;1197  }1198 1199  if (BB->isEntryBlock()) {1200    out << "entry"1201        << "<" << BB << ">";1202    return;1203  }1204 1205  unsigned FuncOrderBlockNum = 0;1206  for (auto &FuncBB : *BB->getParent()) {1207    if (&FuncBB == BB)1208      break;1209    FuncOrderBlockNum++;1210  }1211  out << "unnamed_" << FuncOrderBlockNum << "<" << BB << ">";1212}1213 1214void PreservedCFGCheckerInstrumentation::CFG::printDiff(raw_ostream &out,1215                                                        const CFG &Before,1216                                                        const CFG &After) {1217  assert(!After.isPoisoned());1218  if (Before.isPoisoned()) {1219    out << "Some blocks were deleted\n";1220    return;1221  }1222 1223  // Find and print graph differences.1224  if (Before.Graph.size() != After.Graph.size())1225    out << "Different number of non-leaf basic blocks: before="1226        << Before.Graph.size() << ", after=" << After.Graph.size() << "\n";1227 1228  for (auto &BB : Before.Graph) {1229    auto BA = After.Graph.find(BB.first);1230    if (BA == After.Graph.end()) {1231      out << "Non-leaf block ";1232      printBBName(out, BB.first);1233      out << " is removed (" << BB.second.size() << " successors)\n";1234    }1235  }1236 1237  for (auto &BA : After.Graph) {1238    auto BB = Before.Graph.find(BA.first);1239    if (BB == Before.Graph.end()) {1240      out << "Non-leaf block ";1241      printBBName(out, BA.first);1242      out << " is added (" << BA.second.size() << " successors)\n";1243      continue;1244    }1245 1246    if (BB->second == BA.second)1247      continue;1248 1249    out << "Different successors of block ";1250    printBBName(out, BA.first);1251    out << " (unordered):\n";1252    out << "- before (" << BB->second.size() << "): ";1253    for (auto &SuccB : BB->second) {1254      printBBName(out, SuccB.first);1255      if (SuccB.second != 1)1256        out << "(" << SuccB.second << "), ";1257      else1258        out << ", ";1259    }1260    out << "\n";1261    out << "- after (" << BA.second.size() << "): ";1262    for (auto &SuccA : BA.second) {1263      printBBName(out, SuccA.first);1264      if (SuccA.second != 1)1265        out << "(" << SuccA.second << "), ";1266      else1267        out << ", ";1268    }1269    out << "\n";1270  }1271}1272 1273// PreservedCFGCheckerInstrumentation uses PreservedCFGCheckerAnalysis to check1274// passes, that reported they kept CFG analyses up-to-date, did not actually1275// change CFG. This check is done as follows. Before every functional pass in1276// BeforeNonSkippedPassCallback a CFG snapshot (an instance of1277// PreservedCFGCheckerInstrumentation::CFG) is requested from1278// FunctionAnalysisManager as a result of PreservedCFGCheckerAnalysis. When the1279// functional pass finishes and reports that CFGAnalyses or AllAnalyses are1280// up-to-date then the cached result of PreservedCFGCheckerAnalysis (if1281// available) is checked to be equal to a freshly created CFG snapshot.1282struct PreservedCFGCheckerAnalysis1283    : public AnalysisInfoMixin<PreservedCFGCheckerAnalysis> {1284  friend AnalysisInfoMixin<PreservedCFGCheckerAnalysis>;1285 1286  static AnalysisKey Key;1287 1288public:1289  /// Provide the result type for this analysis pass.1290  using Result = PreservedCFGCheckerInstrumentation::CFG;1291 1292  /// Run the analysis pass over a function and produce CFG.1293  Result run(Function &F, FunctionAnalysisManager &FAM) {1294    return Result(&F, /* TrackBBLifetime */ true);1295  }1296};1297 1298AnalysisKey PreservedCFGCheckerAnalysis::Key;1299 1300struct PreservedFunctionHashAnalysis1301    : public AnalysisInfoMixin<PreservedFunctionHashAnalysis> {1302  static AnalysisKey Key;1303 1304  struct FunctionHash {1305    uint64_t Hash;1306  };1307 1308  using Result = FunctionHash;1309 1310  Result run(Function &F, FunctionAnalysisManager &FAM) {1311    return Result{StructuralHash(F)};1312  }1313};1314 1315AnalysisKey PreservedFunctionHashAnalysis::Key;1316 1317struct PreservedModuleHashAnalysis1318    : public AnalysisInfoMixin<PreservedModuleHashAnalysis> {1319  static AnalysisKey Key;1320 1321  struct ModuleHash {1322    uint64_t Hash;1323  };1324 1325  using Result = ModuleHash;1326 1327  Result run(Module &F, ModuleAnalysisManager &FAM) {1328    return Result{StructuralHash(F)};1329  }1330};1331 1332AnalysisKey PreservedModuleHashAnalysis::Key;1333 1334bool PreservedCFGCheckerInstrumentation::CFG::invalidate(1335    Function &F, const PreservedAnalyses &PA,1336    FunctionAnalysisManager::Invalidator &) {1337  auto PAC = PA.getChecker<PreservedCFGCheckerAnalysis>();1338  return !(PAC.preserved() || PAC.preservedSet<AllAnalysesOn<Function>>() ||1339           PAC.preservedSet<CFGAnalyses>());1340}1341 1342static SmallVector<Function *, 1> GetFunctions(Any IR) {1343  SmallVector<Function *, 1> Functions;1344 1345  if (const auto *MaybeF = unwrapIR<Function>(IR)) {1346    Functions.push_back(const_cast<Function *>(MaybeF));1347  } else if (const auto *MaybeM = unwrapIR<Module>(IR)) {1348    for (Function &F : *const_cast<Module *>(MaybeM))1349      Functions.push_back(&F);1350  }1351  return Functions;1352}1353 1354void PreservedCFGCheckerInstrumentation::registerCallbacks(1355    PassInstrumentationCallbacks &PIC, ModuleAnalysisManager &MAM) {1356  if (!VerifyAnalysisInvalidation)1357    return;1358 1359  bool Registered = false;1360  PIC.registerBeforeNonSkippedPassCallback([this, &MAM, Registered](1361                                               StringRef P, Any IR) mutable {1362#if LLVM_ENABLE_ABI_BREAKING_CHECKS1363    assert(&PassStack.emplace_back(P));1364#endif1365    (void)this;1366 1367    auto &FAM = MAM.getResult<FunctionAnalysisManagerModuleProxy>(1368                       *const_cast<Module *>(unwrapModule(IR, /*Force=*/true)))1369                    .getManager();1370    if (!Registered) {1371      FAM.registerPass([&] { return PreservedCFGCheckerAnalysis(); });1372      FAM.registerPass([&] { return PreservedFunctionHashAnalysis(); });1373      MAM.registerPass([&] { return PreservedModuleHashAnalysis(); });1374      Registered = true;1375    }1376 1377    for (Function *F : GetFunctions(IR)) {1378      // Make sure a fresh CFG snapshot is available before the pass.1379      FAM.getResult<PreservedCFGCheckerAnalysis>(*F);1380      FAM.getResult<PreservedFunctionHashAnalysis>(*F);1381    }1382 1383    if (const auto *MPtr = unwrapIR<Module>(IR)) {1384      auto &M = *const_cast<Module *>(MPtr);1385      MAM.getResult<PreservedModuleHashAnalysis>(M);1386    }1387  });1388 1389  PIC.registerAfterPassInvalidatedCallback(1390      [this](StringRef P, const PreservedAnalyses &PassPA) {1391#if LLVM_ENABLE_ABI_BREAKING_CHECKS1392        assert(PassStack.pop_back_val() == P &&1393               "Before and After callbacks must correspond");1394#endif1395        (void)this;1396      });1397 1398  PIC.registerAfterPassCallback([this, &MAM](StringRef P, Any IR,1399                                             const PreservedAnalyses &PassPA) {1400#if LLVM_ENABLE_ABI_BREAKING_CHECKS1401    assert(PassStack.pop_back_val() == P &&1402           "Before and After callbacks must correspond");1403#endif1404    (void)this;1405 1406    // We have to get the FAM via the MAM, rather than directly use a passed in1407    // FAM because if MAM has not cached the FAM, it won't invalidate function1408    // analyses in FAM.1409    auto &FAM = MAM.getResult<FunctionAnalysisManagerModuleProxy>(1410                       *const_cast<Module *>(unwrapModule(IR, /*Force=*/true)))1411                    .getManager();1412 1413    for (Function *F : GetFunctions(IR)) {1414      if (auto *HashBefore =1415              FAM.getCachedResult<PreservedFunctionHashAnalysis>(*F)) {1416        if (HashBefore->Hash != StructuralHash(*F)) {1417          report_fatal_error(formatv(1418              "Function @{0} changed by {1} without invalidating analyses",1419              F->getName(), P));1420        }1421      }1422 1423      auto CheckCFG = [](StringRef Pass, StringRef FuncName,1424                         const CFG &GraphBefore, const CFG &GraphAfter) {1425        if (GraphAfter == GraphBefore)1426          return;1427 1428        dbgs()1429            << "Error: " << Pass1430            << " does not invalidate CFG analyses but CFG changes detected in "1431               "function @"1432            << FuncName << ":\n";1433        CFG::printDiff(dbgs(), GraphBefore, GraphAfter);1434        report_fatal_error(Twine("CFG unexpectedly changed by ", Pass));1435      };1436 1437      if (auto *GraphBefore =1438              FAM.getCachedResult<PreservedCFGCheckerAnalysis>(*F))1439        CheckCFG(P, F->getName(), *GraphBefore,1440                 CFG(F, /* TrackBBLifetime */ false));1441    }1442    if (const auto *MPtr = unwrapIR<Module>(IR)) {1443      auto &M = *const_cast<Module *>(MPtr);1444      if (auto *HashBefore =1445              MAM.getCachedResult<PreservedModuleHashAnalysis>(M)) {1446        if (HashBefore->Hash != StructuralHash(M)) {1447          report_fatal_error(formatv(1448              "Module changed by {0} without invalidating analyses", P));1449        }1450      }1451    }1452  });1453}1454 1455void VerifyInstrumentation::registerCallbacks(PassInstrumentationCallbacks &PIC,1456                                              ModuleAnalysisManager *MAM) {1457  PIC.registerAfterPassCallback(1458      [this, MAM](StringRef P, Any IR, const PreservedAnalyses &PassPA) {1459        if (isIgnored(P) || P == "VerifierPass")1460          return;1461        const auto *F = unwrapIR<Function>(IR);1462        if (!F) {1463          if (const auto *L = unwrapIR<Loop>(IR))1464            F = L->getHeader()->getParent();1465        }1466 1467        if (F) {1468          if (DebugLogging)1469            dbgs() << "Verifying function " << F->getName() << "\n";1470 1471          if (verifyFunction(*F, &errs()))1472            report_fatal_error(formatv("Broken function found after pass "1473                                       "\"{0}\", compilation aborted!",1474                                       P));1475        } else {1476          const auto *M = unwrapIR<Module>(IR);1477          if (!M) {1478            if (const auto *C = unwrapIR<LazyCallGraph::SCC>(IR))1479              M = C->begin()->getFunction().getParent();1480          }1481 1482          if (M) {1483            if (DebugLogging)1484              dbgs() << "Verifying module " << M->getName() << "\n";1485 1486            if (verifyModule(*M, &errs()))1487              report_fatal_error(formatv("Broken module found after pass "1488                                         "\"{0}\", compilation aborted!",1489                                         P));1490          }1491 1492          if (auto *MF = unwrapIR<MachineFunction>(IR)) {1493            if (DebugLogging)1494              dbgs() << "Verifying machine function " << MF->getName() << '\n';1495            std::string Banner =1496                formatv("Broken machine function found after pass "1497                        "\"{0}\", compilation aborted!",1498                        P);1499            if (MAM) {1500              Module &M = const_cast<Module &>(*MF->getFunction().getParent());1501              auto &MFAM =1502                  MAM->getResult<MachineFunctionAnalysisManagerModuleProxy>(M)1503                      .getManager();1504              MachineVerifierPass Verifier(Banner);1505              Verifier.run(const_cast<MachineFunction &>(*MF), MFAM);1506            } else {1507              verifyMachineFunction(Banner, *MF);1508            }1509          }1510        }1511      });1512}1513 1514InLineChangePrinter::~InLineChangePrinter() = default;1515 1516void InLineChangePrinter::generateIRRepresentation(Any IR,1517                                                   StringRef PassID,1518                                                   IRDataT<EmptyData> &D) {1519  IRComparer<EmptyData>::analyzeIR(IR, D);1520}1521 1522void InLineChangePrinter::handleAfter(StringRef PassID, std::string &Name,1523                                      const IRDataT<EmptyData> &Before,1524                                      const IRDataT<EmptyData> &After,1525                                      Any IR) {1526  SmallString<20> Banner =1527      formatv("*** IR Dump After {0} on {1} ***\n", PassID, Name);1528  Out << Banner;1529  IRComparer<EmptyData>(Before, After)1530      .compare(getModuleForComparison(IR),1531               [&](bool InModule, unsigned Minor,1532                   const FuncDataT<EmptyData> &Before,1533                   const FuncDataT<EmptyData> &After) -> void {1534                 handleFunctionCompare(Name, "", PassID, " on ", InModule,1535                                       Minor, Before, After);1536               });1537  Out << "\n";1538}1539 1540void InLineChangePrinter::handleFunctionCompare(1541    StringRef Name, StringRef Prefix, StringRef PassID, StringRef Divider,1542    bool InModule, unsigned Minor, const FuncDataT<EmptyData> &Before,1543    const FuncDataT<EmptyData> &After) {1544  // Print a banner when this is being shown in the context of a module1545  if (InModule)1546    Out << "\n*** IR for function " << Name << " ***\n";1547 1548  FuncDataT<EmptyData>::report(1549      Before, After,1550      [&](const BlockDataT<EmptyData> *B, const BlockDataT<EmptyData> *A) {1551        StringRef BStr = B ? B->getBody() : "\n";1552        StringRef AStr = A ? A->getBody() : "\n";1553        const std::string Removed =1554            UseColour ? "\033[31m-%l\033[0m\n" : "-%l\n";1555        const std::string Added = UseColour ? "\033[32m+%l\033[0m\n" : "+%l\n";1556        const std::string NoChange = " %l\n";1557        Out << doSystemDiff(BStr, AStr, Removed, Added, NoChange);1558      });1559}1560 1561void InLineChangePrinter::registerCallbacks(PassInstrumentationCallbacks &PIC) {1562  if (PrintChanged == ChangePrinter::DiffVerbose ||1563      PrintChanged == ChangePrinter::DiffQuiet ||1564      PrintChanged == ChangePrinter::ColourDiffVerbose ||1565      PrintChanged == ChangePrinter::ColourDiffQuiet)1566    TextChangeReporter<IRDataT<EmptyData>>::registerRequiredCallbacks(PIC);1567}1568 1569TimeProfilingPassesHandler::TimeProfilingPassesHandler() = default;1570 1571void TimeProfilingPassesHandler::registerCallbacks(1572    PassInstrumentationCallbacks &PIC) {1573  if (!getTimeTraceProfilerInstance())1574    return;1575  PIC.registerBeforeNonSkippedPassCallback(1576      [this](StringRef P, Any IR) { this->runBeforePass(P, IR); });1577  PIC.registerAfterPassCallback(1578      [this](StringRef P, Any IR, const PreservedAnalyses &) {1579        this->runAfterPass();1580      },1581      true);1582  PIC.registerAfterPassInvalidatedCallback(1583      [this](StringRef P, const PreservedAnalyses &) { this->runAfterPass(); },1584      true);1585  PIC.registerBeforeAnalysisCallback(1586      [this](StringRef P, Any IR) { this->runBeforePass(P, IR); });1587  PIC.registerAfterAnalysisCallback(1588      [this](StringRef P, Any IR) { this->runAfterPass(); }, true);1589}1590 1591void TimeProfilingPassesHandler::runBeforePass(StringRef PassID, Any IR) {1592  timeTraceProfilerBegin(PassID, getIRName(IR));1593}1594 1595void TimeProfilingPassesHandler::runAfterPass() { timeTraceProfilerEnd(); }1596 1597namespace {1598 1599class DisplayNode;1600class DotCfgDiffDisplayGraph;1601 1602// Base class for a node or edge in the dot-cfg-changes graph.1603class DisplayElement {1604public:1605  // Is this in before, after, or both?1606  StringRef getColour() const { return Colour; }1607 1608protected:1609  DisplayElement(StringRef Colour) : Colour(Colour) {}1610  const StringRef Colour;1611};1612 1613// An edge representing a transition between basic blocks in the1614// dot-cfg-changes graph.1615class DisplayEdge : public DisplayElement {1616public:1617  DisplayEdge(std::string Value, DisplayNode &Node, StringRef Colour)1618      : DisplayElement(Colour), Value(Value), Node(Node) {}1619  // The value on which the transition is made.1620  std::string getValue() const { return Value; }1621  // The node (representing a basic block) reached by this transition.1622  const DisplayNode &getDestinationNode() const { return Node; }1623 1624protected:1625  std::string Value;1626  const DisplayNode &Node;1627};1628 1629// A node in the dot-cfg-changes graph which represents a basic block.1630class DisplayNode : public DisplayElement {1631public:1632  // \p C is the content for the node, \p T indicates the colour for the1633  // outline of the node1634  DisplayNode(std::string Content, StringRef Colour)1635      : DisplayElement(Colour), Content(Content) {}1636 1637  // Iterator to the child nodes.  Required by GraphWriter.1638  using ChildIterator = std::unordered_set<DisplayNode *>::const_iterator;1639  ChildIterator children_begin() const { return Children.cbegin(); }1640  ChildIterator children_end() const { return Children.cend(); }1641 1642  // Iterator for the edges.  Required by GraphWriter.1643  using EdgeIterator = std::vector<DisplayEdge *>::const_iterator;1644  EdgeIterator edges_begin() const { return EdgePtrs.cbegin(); }1645  EdgeIterator edges_end() const { return EdgePtrs.cend(); }1646 1647  // Create an edge to \p Node on value \p Value, with colour \p Colour.1648  void createEdge(StringRef Value, DisplayNode &Node, StringRef Colour);1649 1650  // Return the content of this node.1651  std::string getContent() const { return Content; }1652 1653  // Return the edge to node \p S.1654  const DisplayEdge &getEdge(const DisplayNode &To) const {1655    assert(EdgeMap.find(&To) != EdgeMap.end() && "Expected to find edge.");1656    return *EdgeMap.find(&To)->second;1657  }1658 1659  // Return the value for the transition to basic block \p S.1660  // Required by GraphWriter.1661  std::string getEdgeSourceLabel(const DisplayNode &Sink) const {1662    return getEdge(Sink).getValue();1663  }1664 1665  void createEdgeMap();1666 1667protected:1668  const std::string Content;1669 1670  // Place to collect all of the edges.  Once they are all in the vector,1671  // the vector will not reallocate so then we can use pointers to them,1672  // which are required by the graph writing routines.1673  std::vector<DisplayEdge> Edges;1674 1675  std::vector<DisplayEdge *> EdgePtrs;1676  std::unordered_set<DisplayNode *> Children;1677  std::unordered_map<const DisplayNode *, const DisplayEdge *> EdgeMap;1678 1679  // Safeguard adding of edges.1680  bool AllEdgesCreated = false;1681};1682 1683// Class representing a difference display (corresponds to a pdf file).1684class DotCfgDiffDisplayGraph {1685public:1686  DotCfgDiffDisplayGraph(std::string Name) : GraphName(Name) {}1687 1688  // Generate the file into \p DotFile.1689  void generateDotFile(StringRef DotFile);1690 1691  // Iterator to the nodes.  Required by GraphWriter.1692  using NodeIterator = std::vector<DisplayNode *>::const_iterator;1693  NodeIterator nodes_begin() const {1694    assert(NodeGenerationComplete && "Unexpected children iterator creation");1695    return NodePtrs.cbegin();1696  }1697  NodeIterator nodes_end() const {1698    assert(NodeGenerationComplete && "Unexpected children iterator creation");1699    return NodePtrs.cend();1700  }1701 1702  // Record the index of the entry node.  At this point, we can build up1703  // vectors of pointers that are required by the graph routines.1704  void setEntryNode(unsigned N) {1705    // At this point, there will be no new nodes.1706    assert(!NodeGenerationComplete && "Unexpected node creation");1707    NodeGenerationComplete = true;1708    for (auto &N : Nodes)1709      NodePtrs.emplace_back(&N);1710 1711    EntryNode = NodePtrs[N];1712  }1713 1714  // Create a node.1715  void createNode(std::string C, StringRef Colour) {1716    assert(!NodeGenerationComplete && "Unexpected node creation");1717    Nodes.emplace_back(C, Colour);1718  }1719  // Return the node at index \p N to avoid problems with vectors reallocating.1720  DisplayNode &getNode(unsigned N) {1721    assert(N < Nodes.size() && "Node is out of bounds");1722    return Nodes[N];1723  }1724  unsigned size() const {1725    assert(NodeGenerationComplete && "Unexpected children iterator creation");1726    return Nodes.size();1727  }1728 1729  // Return the name of the graph.  Required by GraphWriter.1730  std::string getGraphName() const { return GraphName; }1731 1732  // Return the string representing the differences for basic block \p Node.1733  // Required by GraphWriter.1734  std::string getNodeLabel(const DisplayNode &Node) const {1735    return Node.getContent();1736  }1737 1738  // Return a string with colour information for Dot.  Required by GraphWriter.1739  std::string getNodeAttributes(const DisplayNode &Node) const {1740    return attribute(Node.getColour());1741  }1742 1743  // Return a string with colour information for Dot.  Required by GraphWriter.1744  std::string getEdgeColorAttr(const DisplayNode &From,1745                               const DisplayNode &To) const {1746    return attribute(From.getEdge(To).getColour());1747  }1748 1749  // Get the starting basic block.  Required by GraphWriter.1750  DisplayNode *getEntryNode() const {1751    assert(NodeGenerationComplete && "Unexpected children iterator creation");1752    return EntryNode;1753  }1754 1755protected:1756  // Return the string containing the colour to use as a Dot attribute.1757  std::string attribute(StringRef Colour) const {1758    return "color=" + Colour.str();1759  }1760 1761  bool NodeGenerationComplete = false;1762  const std::string GraphName;1763  std::vector<DisplayNode> Nodes;1764  std::vector<DisplayNode *> NodePtrs;1765  DisplayNode *EntryNode = nullptr;1766};1767 1768void DisplayNode::createEdge(StringRef Value, DisplayNode &Node,1769                             StringRef Colour) {1770  assert(!AllEdgesCreated && "Expected to be able to still create edges.");1771  Edges.emplace_back(Value.str(), Node, Colour);1772  Children.insert(&Node);1773}1774 1775void DisplayNode::createEdgeMap() {1776  // No more edges will be added so we can now use pointers to the edges1777  // as the vector will not grow and reallocate.1778  AllEdgesCreated = true;1779  for (auto &E : Edges)1780    EdgeMap.insert({&E.getDestinationNode(), &E});1781}1782 1783class DotCfgDiffNode;1784class DotCfgDiff;1785 1786// A class representing a basic block in the Dot difference graph.1787class DotCfgDiffNode {1788public:1789  DotCfgDiffNode() = delete;1790 1791  // Create a node in Dot difference graph \p G representing the basic block1792  // represented by \p BD with colour \p Colour (where it exists).1793  DotCfgDiffNode(DotCfgDiff &G, unsigned N, const BlockDataT<DCData> &BD,1794                 StringRef Colour)1795      : Graph(G), N(N), Data{&BD, nullptr}, Colour(Colour) {}1796  DotCfgDiffNode(const DotCfgDiffNode &DN)1797      : Graph(DN.Graph), N(DN.N), Data{DN.Data[0], DN.Data[1]},1798        Colour(DN.Colour), EdgesMap(DN.EdgesMap), Children(DN.Children),1799        Edges(DN.Edges) {}1800 1801  unsigned getIndex() const { return N; }1802 1803  // The label of the basic block1804  StringRef getLabel() const {1805    assert(Data[0] && "Expected Data[0] to be set.");1806    return Data[0]->getLabel();1807  }1808  // Return the colour for this block1809  StringRef getColour() const { return Colour; }1810  // Change this basic block from being only in before to being common.1811  // Save the pointer to \p Other.1812  void setCommon(const BlockDataT<DCData> &Other) {1813    assert(!Data[1] && "Expected only one block datum");1814    Data[1] = &Other;1815    Colour = CommonColour;1816  }1817  // Add an edge to \p E of colour {\p Value, \p Colour}.1818  void addEdge(unsigned E, StringRef Value, StringRef Colour) {1819    // This is a new edge or it is an edge being made common.1820    assert((EdgesMap.count(E) == 0 || Colour == CommonColour) &&1821           "Unexpected edge count and color.");1822    EdgesMap[E] = {Value.str(), Colour};1823  }1824  // Record the children and create edges.1825  void finalize(DotCfgDiff &G);1826 1827  // Return the colour of the edge to node \p S.1828  StringRef getEdgeColour(const unsigned S) const {1829    assert(EdgesMap.count(S) == 1 && "Expected to find edge.");1830    return EdgesMap.at(S).second;1831  }1832 1833  // Return the string representing the basic block.1834  std::string getBodyContent() const;1835 1836  void createDisplayEdges(DotCfgDiffDisplayGraph &Graph, unsigned DisplayNode,1837                          std::map<const unsigned, unsigned> &NodeMap) const;1838 1839protected:1840  DotCfgDiff &Graph;1841  const unsigned N;1842  const BlockDataT<DCData> *Data[2];1843  StringRef Colour;1844  std::map<const unsigned, std::pair<std::string, StringRef>> EdgesMap;1845  std::vector<unsigned> Children;1846  std::vector<unsigned> Edges;1847};1848 1849// Class representing the difference graph between two functions.1850class DotCfgDiff {1851public:1852  // \p Title is the title given to the graph.  \p EntryNodeName is the1853  // entry node for the function.  \p Before and \p After are the before1854  // after versions of the function, respectively.  \p Dir is the directory1855  // in which to store the results.1856  DotCfgDiff(StringRef Title, const FuncDataT<DCData> &Before,1857             const FuncDataT<DCData> &After);1858 1859  DotCfgDiff(const DotCfgDiff &) = delete;1860  DotCfgDiff &operator=(const DotCfgDiff &) = delete;1861 1862  DotCfgDiffDisplayGraph createDisplayGraph(StringRef Title,1863                                            StringRef EntryNodeName);1864 1865  // Return a string consisting of the labels for the \p Source and \p Sink.1866  // The combination allows distinguishing changing transitions on the1867  // same value (ie, a transition went to X before and goes to Y after).1868  // Required by GraphWriter.1869  StringRef getEdgeSourceLabel(const unsigned &Source,1870                               const unsigned &Sink) const {1871    std::string S =1872        getNode(Source).getLabel().str() + " " + getNode(Sink).getLabel().str();1873    assert(EdgeLabels.count(S) == 1 && "Expected to find edge label.");1874    return EdgeLabels.find(S)->getValue();1875  }1876 1877  // Return the number of basic blocks (nodes).  Required by GraphWriter.1878  unsigned size() const { return Nodes.size(); }1879 1880  const DotCfgDiffNode &getNode(unsigned N) const {1881    assert(N < Nodes.size() && "Unexpected index for node reference");1882    return Nodes[N];1883  }1884 1885protected:1886  // Return the string surrounded by HTML to make it the appropriate colour.1887  std::string colourize(std::string S, StringRef Colour) const;1888 1889  void createNode(StringRef Label, const BlockDataT<DCData> &BD, StringRef C) {1890    unsigned Pos = Nodes.size();1891    Nodes.emplace_back(*this, Pos, BD, C);1892    NodePosition.insert({Label, Pos});1893  }1894 1895  // TODO Nodes should probably be a StringMap<DotCfgDiffNode> after the1896  // display graph is separated out, which would remove the need for1897  // NodePosition.1898  std::vector<DotCfgDiffNode> Nodes;1899  StringMap<unsigned> NodePosition;1900  const std::string GraphName;1901 1902  StringMap<std::string> EdgeLabels;1903};1904 1905std::string DotCfgDiffNode::getBodyContent() const {1906  if (Colour == CommonColour) {1907    assert(Data[1] && "Expected Data[1] to be set.");1908 1909    StringRef SR[2];1910    for (unsigned I = 0; I < 2; ++I) {1911      SR[I] = Data[I]->getBody();1912      // drop initial '\n' if present1913      SR[I].consume_front("\n");1914      // drop predecessors as they can be big and are redundant1915      SR[I] = SR[I].drop_until([](char C) { return C == '\n'; }).drop_front();1916    }1917 1918    SmallString<80> OldLineFormat = formatv(1919        "<FONT COLOR=\"{0}\">%l</FONT><BR align=\"left\"/>", BeforeColour);1920    SmallString<80> NewLineFormat = formatv(1921        "<FONT COLOR=\"{0}\">%l</FONT><BR align=\"left\"/>", AfterColour);1922    SmallString<80> UnchangedLineFormat = formatv(1923        "<FONT COLOR=\"{0}\">%l</FONT><BR align=\"left\"/>", CommonColour);1924    std::string Diff = Data[0]->getLabel().str();1925    Diff += ":\n<BR align=\"left\"/>" +1926            doSystemDiff(makeHTMLReady(SR[0]), makeHTMLReady(SR[1]),1927                         OldLineFormat, NewLineFormat, UnchangedLineFormat);1928 1929    // Diff adds in some empty colour changes which are not valid HTML1930    // so remove them.  Colours are all lowercase alpha characters (as1931    // listed in https://graphviz.org/pdf/dotguide.pdf).1932    Regex R("<FONT COLOR=\"\\w+\"></FONT>");1933    while (true) {1934      std::string Error;1935      std::string S = R.sub("", Diff, &Error);1936      if (Error != "")1937        return Error;1938      if (S == Diff)1939        return Diff;1940      Diff = S;1941    }1942    llvm_unreachable("Should not get here");1943  }1944 1945  // Put node out in the appropriate colour.1946  assert(!Data[1] && "Data[1] is set unexpectedly.");1947  std::string Body = makeHTMLReady(Data[0]->getBody());1948  const StringRef BS = Body;1949  StringRef BS1 = BS;1950  // Drop leading newline, if present.1951  if (BS.front() == '\n')1952    BS1 = BS1.drop_front(1);1953  // Get label.1954  StringRef Label = BS1.take_until([](char C) { return C == ':'; });1955  // drop predecessors as they can be big and are redundant1956  BS1 = BS1.drop_until([](char C) { return C == '\n'; }).drop_front();1957 1958  std::string S = "<FONT COLOR=\"" + Colour.str() + "\">" + Label.str() + ":";1959 1960  // align each line to the left.1961  while (BS1.size()) {1962    S.append("<BR align=\"left\"/>");1963    StringRef Line = BS1.take_until([](char C) { return C == '\n'; });1964    S.append(Line.str());1965    BS1 = BS1.drop_front(Line.size() + 1);1966  }1967  S.append("<BR align=\"left\"/></FONT>");1968  return S;1969}1970 1971std::string DotCfgDiff::colourize(std::string S, StringRef Colour) const {1972  if (S.length() == 0)1973    return S;1974  return "<FONT COLOR=\"" + Colour.str() + "\">" + S + "</FONT>";1975}1976 1977DotCfgDiff::DotCfgDiff(StringRef Title, const FuncDataT<DCData> &Before,1978                       const FuncDataT<DCData> &After)1979    : GraphName(Title.str()) {1980  StringMap<StringRef> EdgesMap;1981 1982  // Handle each basic block in the before IR.1983  for (auto &B : Before.getData()) {1984    StringRef Label = B.getKey();1985    const BlockDataT<DCData> &BD = B.getValue();1986    createNode(Label, BD, BeforeColour);1987 1988    // Create transitions with names made up of the from block label, the value1989    // on which the transition is made and the to block label.1990    for (StringMap<std::string>::const_iterator Sink = BD.getData().begin(),1991                                                E = BD.getData().end();1992         Sink != E; ++Sink) {1993      std::string Key = (Label + " " + Sink->getKey().str()).str() + " " +1994                        BD.getData().getSuccessorLabel(Sink->getKey()).str();1995      EdgesMap.insert({Key, BeforeColour});1996    }1997  }1998 1999  // Handle each basic block in the after IR2000  for (auto &A : After.getData()) {2001    StringRef Label = A.getKey();2002    const BlockDataT<DCData> &BD = A.getValue();2003    auto It = NodePosition.find(Label);2004    if (It == NodePosition.end())2005      // This only exists in the after IR.  Create the node.2006      createNode(Label, BD, AfterColour);2007    else2008      Nodes[It->second].setCommon(BD);2009    // Add in the edges between the nodes (as common or only in after).2010    for (StringMap<std::string>::const_iterator Sink = BD.getData().begin(),2011                                                E = BD.getData().end();2012         Sink != E; ++Sink) {2013      std::string Key = (Label + " " + Sink->getKey().str()).str() + " " +2014                        BD.getData().getSuccessorLabel(Sink->getKey()).str();2015      auto [It, Inserted] = EdgesMap.try_emplace(Key, AfterColour);2016      if (!Inserted)2017        It->second = CommonColour;2018    }2019  }2020 2021  // Now go through the map of edges and add them to the node.2022  for (auto &E : EdgesMap) {2023    // Extract the source, sink and value from the edge key.2024    StringRef S = E.getKey();2025    auto SP1 = S.rsplit(' ');2026    auto &SourceSink = SP1.first;2027    auto SP2 = SourceSink.split(' ');2028    StringRef Source = SP2.first;2029    StringRef Sink = SP2.second;2030    StringRef Value = SP1.second;2031 2032    assert(NodePosition.count(Source) == 1 && "Expected to find node.");2033    DotCfgDiffNode &SourceNode = Nodes[NodePosition[Source]];2034    assert(NodePosition.count(Sink) == 1 && "Expected to find node.");2035    unsigned SinkNode = NodePosition[Sink];2036    StringRef Colour = E.second;2037 2038    // Look for an edge from Source to Sink2039    auto [It, Inserted] = EdgeLabels.try_emplace(SourceSink);2040    if (Inserted)2041      It->getValue() = colourize(Value.str(), Colour);2042    else {2043      StringRef V = It->getValue();2044      std::string NV = colourize(V.str() + " " + Value.str(), Colour);2045      Colour = CommonColour;2046      It->getValue() = NV;2047    }2048    SourceNode.addEdge(SinkNode, Value, Colour);2049  }2050  for (auto &I : Nodes)2051    I.finalize(*this);2052}2053 2054DotCfgDiffDisplayGraph DotCfgDiff::createDisplayGraph(StringRef Title,2055                                                      StringRef EntryNodeName) {2056  assert(NodePosition.count(EntryNodeName) == 1 &&2057         "Expected to find entry block in map.");2058  unsigned Entry = NodePosition[EntryNodeName];2059  assert(Entry < Nodes.size() && "Expected to find entry node");2060  DotCfgDiffDisplayGraph G(Title.str());2061 2062  std::map<const unsigned, unsigned> NodeMap;2063 2064  int EntryIndex = -1;2065  unsigned Index = 0;2066  for (auto &I : Nodes) {2067    if (I.getIndex() == Entry)2068      EntryIndex = Index;2069    G.createNode(I.getBodyContent(), I.getColour());2070    NodeMap.insert({I.getIndex(), Index++});2071  }2072  assert(EntryIndex >= 0 && "Expected entry node index to be set.");2073  G.setEntryNode(EntryIndex);2074 2075  for (auto &I : NodeMap) {2076    unsigned SourceNode = I.first;2077    unsigned DisplayNode = I.second;2078    getNode(SourceNode).createDisplayEdges(G, DisplayNode, NodeMap);2079  }2080  return G;2081}2082 2083void DotCfgDiffNode::createDisplayEdges(2084    DotCfgDiffDisplayGraph &DisplayGraph, unsigned DisplayNodeIndex,2085    std::map<const unsigned, unsigned> &NodeMap) const {2086 2087  DisplayNode &SourceDisplayNode = DisplayGraph.getNode(DisplayNodeIndex);2088 2089  for (auto I : Edges) {2090    unsigned SinkNodeIndex = I;2091    StringRef Colour = getEdgeColour(SinkNodeIndex);2092    const DotCfgDiffNode *SinkNode = &Graph.getNode(SinkNodeIndex);2093 2094    StringRef Label = Graph.getEdgeSourceLabel(getIndex(), SinkNodeIndex);2095    DisplayNode &SinkDisplayNode = DisplayGraph.getNode(SinkNode->getIndex());2096    SourceDisplayNode.createEdge(Label, SinkDisplayNode, Colour);2097  }2098  SourceDisplayNode.createEdgeMap();2099}2100 2101void DotCfgDiffNode::finalize(DotCfgDiff &G) {2102  for (auto E : EdgesMap) {2103    Children.emplace_back(E.first);2104    Edges.emplace_back(E.first);2105  }2106}2107 2108} // namespace2109 2110namespace llvm {2111 2112template <> struct GraphTraits<DotCfgDiffDisplayGraph *> {2113  using NodeRef = const DisplayNode *;2114  using ChildIteratorType = DisplayNode::ChildIterator;2115  using nodes_iterator = DotCfgDiffDisplayGraph::NodeIterator;2116  using EdgeRef = const DisplayEdge *;2117  using ChildEdgeIterator = DisplayNode::EdgeIterator;2118 2119  static NodeRef getEntryNode(const DotCfgDiffDisplayGraph *G) {2120    return G->getEntryNode();2121  }2122  static ChildIteratorType child_begin(NodeRef N) {2123    return N->children_begin();2124  }2125  static ChildIteratorType child_end(NodeRef N) { return N->children_end(); }2126  static nodes_iterator nodes_begin(const DotCfgDiffDisplayGraph *G) {2127    return G->nodes_begin();2128  }2129  static nodes_iterator nodes_end(const DotCfgDiffDisplayGraph *G) {2130    return G->nodes_end();2131  }2132  static ChildEdgeIterator child_edge_begin(NodeRef N) {2133    return N->edges_begin();2134  }2135  static ChildEdgeIterator child_edge_end(NodeRef N) { return N->edges_end(); }2136  static NodeRef edge_dest(EdgeRef E) { return &E->getDestinationNode(); }2137  static unsigned size(const DotCfgDiffDisplayGraph *G) { return G->size(); }2138};2139 2140template <>2141struct DOTGraphTraits<DotCfgDiffDisplayGraph *> : public DefaultDOTGraphTraits {2142  explicit DOTGraphTraits(bool Simple = false)2143      : DefaultDOTGraphTraits(Simple) {}2144 2145  static bool renderNodesUsingHTML() { return true; }2146  static std::string getGraphName(const DotCfgDiffDisplayGraph *DiffData) {2147    return DiffData->getGraphName();2148  }2149  static std::string2150  getGraphProperties(const DotCfgDiffDisplayGraph *DiffData) {2151    return "\tsize=\"190, 190\";\n";2152  }2153  static std::string getNodeLabel(const DisplayNode *Node,2154                                  const DotCfgDiffDisplayGraph *DiffData) {2155    return DiffData->getNodeLabel(*Node);2156  }2157  static std::string getNodeAttributes(const DisplayNode *Node,2158                                       const DotCfgDiffDisplayGraph *DiffData) {2159    return DiffData->getNodeAttributes(*Node);2160  }2161  static std::string getEdgeSourceLabel(const DisplayNode *From,2162                                        DisplayNode::ChildIterator &To) {2163    return From->getEdgeSourceLabel(**To);2164  }2165  static std::string getEdgeAttributes(const DisplayNode *From,2166                                       DisplayNode::ChildIterator &To,2167                                       const DotCfgDiffDisplayGraph *DiffData) {2168    return DiffData->getEdgeColorAttr(*From, **To);2169  }2170};2171 2172} // namespace llvm2173 2174namespace {2175 2176void DotCfgDiffDisplayGraph::generateDotFile(StringRef DotFile) {2177  std::error_code EC;2178  raw_fd_ostream OutStream(DotFile, EC);2179  if (EC) {2180    errs() << "Error: " << EC.message() << "\n";2181    return;2182  }2183  WriteGraph(OutStream, this, false);2184  OutStream.flush();2185  OutStream.close();2186}2187 2188} // namespace2189 2190namespace llvm {2191 2192DCData::DCData(const BasicBlock &B) {2193  // Build up transition labels.2194  const Instruction *Term = B.getTerminator();2195  if (const BranchInst *Br = dyn_cast<const BranchInst>(Term))2196    if (Br->isUnconditional())2197      addSuccessorLabel(Br->getSuccessor(0)->getName().str(), "");2198    else {2199      addSuccessorLabel(Br->getSuccessor(0)->getName().str(), "true");2200      addSuccessorLabel(Br->getSuccessor(1)->getName().str(), "false");2201    }2202  else if (const SwitchInst *Sw = dyn_cast<const SwitchInst>(Term)) {2203    addSuccessorLabel(Sw->case_default()->getCaseSuccessor()->getName().str(),2204                      "default");2205    for (auto &C : Sw->cases()) {2206      assert(C.getCaseValue() && "Expected to find case value.");2207      SmallString<20> Value = formatv("{0}", C.getCaseValue()->getSExtValue());2208      addSuccessorLabel(C.getCaseSuccessor()->getName().str(), Value);2209    }2210  } else2211    for (const BasicBlock *Succ : successors(&B))2212      addSuccessorLabel(Succ->getName().str(), "");2213}2214 2215DCData::DCData(const MachineBasicBlock &B) {2216  for (const MachineBasicBlock *Succ : successors(&B))2217    addSuccessorLabel(Succ->getName().str(), "");2218}2219 2220DotCfgChangeReporter::DotCfgChangeReporter(bool Verbose)2221    : ChangeReporter<IRDataT<DCData>>(Verbose) {}2222 2223void DotCfgChangeReporter::handleFunctionCompare(2224    StringRef Name, StringRef Prefix, StringRef PassID, StringRef Divider,2225    bool InModule, unsigned Minor, const FuncDataT<DCData> &Before,2226    const FuncDataT<DCData> &After) {2227  assert(HTML && "Expected outstream to be set");2228  SmallString<8> Extender;2229  SmallString<8> Number;2230  // Handle numbering and file names.2231  if (InModule) {2232    Extender = formatv("{0}_{1}", N, Minor);2233    Number = formatv("{0}.{1}", N, Minor);2234  } else {2235    Extender = formatv("{0}", N);2236    Number = formatv("{0}", N);2237  }2238  // Create a temporary file name for the dot file.2239  SmallVector<char, 128> SV;2240  sys::fs::createUniquePath("cfgdot-%%%%%%.dot", SV, true);2241  std::string DotFile = Twine(SV).str();2242 2243  SmallString<20> PDFFileName = formatv("diff_{0}.pdf", Extender);2244  SmallString<200> Text;2245 2246  Text = formatv("{0}.{1}{2}{3}{4}", Number, Prefix, makeHTMLReady(PassID),2247                 Divider, Name);2248 2249  DotCfgDiff Diff(Text, Before, After);2250  std::string EntryBlockName = After.getEntryBlockName();2251  // Use the before entry block if the after entry block was removed.2252  if (EntryBlockName == "")2253    EntryBlockName = Before.getEntryBlockName();2254  assert(EntryBlockName != "" && "Expected to find entry block");2255 2256  DotCfgDiffDisplayGraph DG = Diff.createDisplayGraph(Text, EntryBlockName);2257  DG.generateDotFile(DotFile);2258 2259  *HTML << genHTML(Text, DotFile, PDFFileName);2260  std::error_code EC = sys::fs::remove(DotFile);2261  if (EC)2262    errs() << "Error: " << EC.message() << "\n";2263}2264 2265std::string DotCfgChangeReporter::genHTML(StringRef Text, StringRef DotFile,2266                                          StringRef PDFFileName) {2267  SmallString<20> PDFFile = formatv("{0}/{1}", DotCfgDir, PDFFileName);2268  // Create the PDF file.2269  static ErrorOr<std::string> DotExe = sys::findProgramByName(DotBinary);2270  if (!DotExe)2271    return "Unable to find dot executable.";2272 2273  StringRef Args[] = {DotBinary, "-Tpdf", "-o", PDFFile, DotFile};2274  int Result = sys::ExecuteAndWait(*DotExe, Args, std::nullopt);2275  if (Result < 0)2276    return "Error executing system dot.";2277 2278  // Create the HTML tag refering to the PDF file.2279  SmallString<200> S = formatv(2280      "  <a href=\"{0}\" target=\"_blank\">{1}</a><br/>\n", PDFFileName, Text);2281  return S.c_str();2282}2283 2284void DotCfgChangeReporter::handleInitialIR(Any IR) {2285  assert(HTML && "Expected outstream to be set");2286  *HTML << "<button type=\"button\" class=\"collapsible\">0. "2287        << "Initial IR (by function)</button>\n"2288        << "<div class=\"content\">\n"2289        << "  <p>\n";2290  // Create representation of IR2291  IRDataT<DCData> Data;2292  IRComparer<DCData>::analyzeIR(IR, Data);2293  // Now compare it against itself, which will have everything the2294  // same and will generate the files.2295  IRComparer<DCData>(Data, Data)2296      .compare(getModuleForComparison(IR),2297               [&](bool InModule, unsigned Minor,2298                   const FuncDataT<DCData> &Before,2299                   const FuncDataT<DCData> &After) -> void {2300                 handleFunctionCompare("", " ", "Initial IR", "", InModule,2301                                       Minor, Before, After);2302               });2303  *HTML << "  </p>\n"2304        << "</div><br/>\n";2305  ++N;2306}2307 2308void DotCfgChangeReporter::generateIRRepresentation(Any IR, StringRef PassID,2309                                                    IRDataT<DCData> &Data) {2310  IRComparer<DCData>::analyzeIR(IR, Data);2311}2312 2313void DotCfgChangeReporter::omitAfter(StringRef PassID, std::string &Name) {2314  assert(HTML && "Expected outstream to be set");2315  SmallString<20> Banner =2316      formatv("  <a>{0}. Pass {1} on {2} omitted because no change</a><br/>\n",2317              N, makeHTMLReady(PassID), Name);2318  *HTML << Banner;2319  ++N;2320}2321 2322void DotCfgChangeReporter::handleAfter(StringRef PassID, std::string &Name,2323                                       const IRDataT<DCData> &Before,2324                                       const IRDataT<DCData> &After, Any IR) {2325  assert(HTML && "Expected outstream to be set");2326  IRComparer<DCData>(Before, After)2327      .compare(getModuleForComparison(IR),2328               [&](bool InModule, unsigned Minor,2329                   const FuncDataT<DCData> &Before,2330                   const FuncDataT<DCData> &After) -> void {2331                 handleFunctionCompare(Name, " Pass ", PassID, " on ", InModule,2332                                       Minor, Before, After);2333               });2334  *HTML << "    </p></div>\n";2335  ++N;2336}2337 2338void DotCfgChangeReporter::handleInvalidated(StringRef PassID) {2339  assert(HTML && "Expected outstream to be set");2340  SmallString<20> Banner =2341      formatv("  <a>{0}. {1} invalidated</a><br/>\n", N, makeHTMLReady(PassID));2342  *HTML << Banner;2343  ++N;2344}2345 2346void DotCfgChangeReporter::handleFiltered(StringRef PassID, std::string &Name) {2347  assert(HTML && "Expected outstream to be set");2348  SmallString<20> Banner =2349      formatv("  <a>{0}. Pass {1} on {2} filtered out</a><br/>\n", N,2350              makeHTMLReady(PassID), Name);2351  *HTML << Banner;2352  ++N;2353}2354 2355void DotCfgChangeReporter::handleIgnored(StringRef PassID, std::string &Name) {2356  assert(HTML && "Expected outstream to be set");2357  SmallString<20> Banner = formatv("  <a>{0}. {1} on {2} ignored</a><br/>\n", N,2358                                   makeHTMLReady(PassID), Name);2359  *HTML << Banner;2360  ++N;2361}2362 2363bool DotCfgChangeReporter::initializeHTML() {2364  std::error_code EC;2365  HTML = std::make_unique<raw_fd_ostream>(DotCfgDir + "/passes.html", EC);2366  if (EC) {2367    HTML = nullptr;2368    return false;2369  }2370 2371  *HTML << "<!doctype html>"2372        << "<html>"2373        << "<head>"2374        << "<style>.collapsible { "2375        << "background-color: #777;"2376        << " color: white;"2377        << " cursor: pointer;"2378        << " padding: 18px;"2379        << " width: 100%;"2380        << " border: none;"2381        << " text-align: left;"2382        << " outline: none;"2383        << " font-size: 15px;"2384        << "} .active, .collapsible:hover {"2385        << " background-color: #555;"2386        << "} .content {"2387        << " padding: 0 18px;"2388        << " display: none;"2389        << " overflow: hidden;"2390        << " background-color: #f1f1f1;"2391        << "}"2392        << "</style>"2393        << "<title>passes.html</title>"2394        << "</head>\n"2395        << "<body>";2396  return true;2397}2398 2399DotCfgChangeReporter::~DotCfgChangeReporter() {2400  if (!HTML)2401    return;2402  *HTML2403      << "<script>var coll = document.getElementsByClassName(\"collapsible\");"2404      << "var i;"2405      << "for (i = 0; i < coll.length; i++) {"2406      << "coll[i].addEventListener(\"click\", function() {"2407      << " this.classList.toggle(\"active\");"2408      << " var content = this.nextElementSibling;"2409      << " if (content.style.display === \"block\"){"2410      << " content.style.display = \"none\";"2411      << " }"2412      << " else {"2413      << " content.style.display= \"block\";"2414      << " }"2415      << " });"2416      << " }"2417      << "</script>"2418      << "</body>"2419      << "</html>\n";2420  HTML->flush();2421  HTML->close();2422}2423 2424void DotCfgChangeReporter::registerCallbacks(2425    PassInstrumentationCallbacks &PIC) {2426  if (PrintChanged == ChangePrinter::DotCfgVerbose ||2427       PrintChanged == ChangePrinter::DotCfgQuiet) {2428    SmallString<128> OutputDir;2429    sys::fs::expand_tilde(DotCfgDir, OutputDir);2430    sys::fs::make_absolute(OutputDir);2431    assert(!OutputDir.empty() && "expected output dir to be non-empty");2432    DotCfgDir = OutputDir.c_str();2433    if (initializeHTML()) {2434      ChangeReporter<IRDataT<DCData>>::registerRequiredCallbacks(PIC);2435      return;2436    }2437    dbgs() << "Unable to open output stream for -cfg-dot-changed\n";2438  }2439}2440 2441StandardInstrumentations::StandardInstrumentations(2442    LLVMContext &Context, bool DebugLogging, bool VerifyEach,2443    PrintPassOptions PrintPassOpts)2444    : PrintPass(DebugLogging, PrintPassOpts), OptNone(DebugLogging),2445      OptPassGate(Context),2446      PrintChangedIR(PrintChanged == ChangePrinter::Verbose),2447      PrintChangedDiff(PrintChanged == ChangePrinter::DiffVerbose ||2448                           PrintChanged == ChangePrinter::ColourDiffVerbose,2449                       PrintChanged == ChangePrinter::ColourDiffVerbose ||2450                           PrintChanged == ChangePrinter::ColourDiffQuiet),2451      WebsiteChangeReporter(PrintChanged == ChangePrinter::DotCfgVerbose),2452      Verify(DebugLogging), DroppedStatsIR(DroppedVarStats),2453      VerifyEach(VerifyEach) {}2454 2455PrintCrashIRInstrumentation *PrintCrashIRInstrumentation::CrashReporter =2456    nullptr;2457 2458void PrintCrashIRInstrumentation::reportCrashIR() {2459  if (!PrintOnCrashPath.empty()) {2460    std::error_code EC;2461    raw_fd_ostream Out(PrintOnCrashPath, EC);2462    if (EC)2463      report_fatal_error(errorCodeToError(EC));2464    Out << SavedIR;2465  } else {2466    dbgs() << SavedIR;2467  }2468}2469 2470void PrintCrashIRInstrumentation::SignalHandler(void *) {2471  // Called by signal handlers so do not lock here2472  // Is the PrintCrashIRInstrumentation still alive?2473  if (!CrashReporter)2474    return;2475 2476  assert((PrintOnCrash || !PrintOnCrashPath.empty()) &&2477         "Did not expect to get here without option set.");2478  CrashReporter->reportCrashIR();2479}2480 2481PrintCrashIRInstrumentation::~PrintCrashIRInstrumentation() {2482  if (!CrashReporter)2483    return;2484 2485  assert((PrintOnCrash || !PrintOnCrashPath.empty()) &&2486         "Did not expect to get here without option set.");2487  CrashReporter = nullptr;2488}2489 2490void PrintCrashIRInstrumentation::registerCallbacks(2491    PassInstrumentationCallbacks &PIC) {2492  if ((!PrintOnCrash && PrintOnCrashPath.empty()) || CrashReporter)2493    return;2494 2495  sys::AddSignalHandler(SignalHandler, nullptr);2496  CrashReporter = this;2497 2498  PIC.registerBeforeNonSkippedPassCallback(2499      [&PIC, this](StringRef PassID, Any IR) {2500        SavedIR.clear();2501        raw_string_ostream OS(SavedIR);2502        OS << formatv("; *** Dump of {0}IR Before Last Pass {1}",2503                      llvm::forcePrintModuleIR() ? "Module " : "", PassID);2504        if (!isInteresting(IR, PassID, PIC.getPassNameForClassName(PassID))) {2505          OS << " Filtered Out ***\n";2506          return;2507        }2508        OS << " Started ***\n";2509        unwrapAndPrint(OS, IR);2510      });2511}2512 2513void StandardInstrumentations::registerCallbacks(2514    PassInstrumentationCallbacks &PIC, ModuleAnalysisManager *MAM) {2515  PrintIR.registerCallbacks(PIC);2516  PrintPass.registerCallbacks(PIC);2517  TimePasses.registerCallbacks(PIC);2518  OptNone.registerCallbacks(PIC);2519  OptPassGate.registerCallbacks(PIC);2520  PrintChangedIR.registerCallbacks(PIC);2521  PseudoProbeVerification.registerCallbacks(PIC);2522  if (VerifyEach)2523    Verify.registerCallbacks(PIC, MAM);2524  PrintChangedDiff.registerCallbacks(PIC);2525  WebsiteChangeReporter.registerCallbacks(PIC);2526  ChangeTester.registerCallbacks(PIC);2527  PrintCrashIR.registerCallbacks(PIC);2528  DroppedStatsIR.registerCallbacks(PIC);2529  if (MAM)2530    PreservedCFGChecker.registerCallbacks(PIC, *MAM);2531 2532  // TimeProfiling records the pass running time cost.2533  // Its 'BeforePassCallback' can be appended at the tail of all the2534  // BeforeCallbacks by calling `registerCallbacks` in the end.2535  // Its 'AfterPassCallback' is put at the front of all the2536  // AfterCallbacks by its `registerCallbacks`. This is necessary2537  // to ensure that other callbacks are not included in the timings.2538  TimeProfilingPasses.registerCallbacks(PIC);2539}2540 2541template class ChangeReporter<std::string>;2542template class TextChangeReporter<std::string>;2543 2544template class BlockDataT<EmptyData>;2545template class FuncDataT<EmptyData>;2546template class IRDataT<EmptyData>;2547template class ChangeReporter<IRDataT<EmptyData>>;2548template class TextChangeReporter<IRDataT<EmptyData>>;2549template class IRComparer<EmptyData>;2550 2551} // namespace llvm2552