Changes to print-changed classes in preparation for DotCfg change printer
authorJamie Schmeiser <schmeise@ca.ibm.com>
Tue, 19 Oct 2021 14:57:54 +0000 (10:57 -0400)
committerJamie Schmeiser <schmeise@ca.ibm.com>
Tue, 19 Oct 2021 14:58:40 +0000 (10:58 -0400)
Summary:
Break out non-functional changes to the print-changed classes that are needed
for reuse with the DotCfg change printer in https://reviews.llvm.org/D87202.

Various changes to the change printers to facilitate reuse with the
upcoming DotCfg change printer. This includes changing several of
the classes and their support classes to being templates. Also,
some template parameter names were simplified to avoid confusion
with planned identifiers in the DotCfg change printer to come. A
virtual function in the class for comparing functions was changed
to a lambda. The virtual function same was replaced with calls to
operator==. The only intentional functional change was to add the exe name
as the first parameter to llvm::sys::ExecuteAndWait

Author: Jamie Schmeiser <schmeise@ca.ibm.com>
Reviewed By: aeubanks (Arthur Eubanks)
Differential Revision: https://reviews.llvm.org/D110737

llvm/include/llvm/Passes/StandardInstrumentations.h
llvm/lib/Passes/StandardInstrumentations.cpp

index 2f57358..b89a151 100644 (file)
@@ -215,8 +215,6 @@ protected:
   virtual void handleFiltered(StringRef PassID, std::string &Name) = 0;
   // Called when an ignored pass is encountered.
   virtual void handleIgnored(StringRef PassID, std::string &Name) = 0;
-  // Called to compare the before and after representations of the IR.
-  virtual bool same(const IRUnitT &Before, const IRUnitT &After) = 0;
 
   // Stack of IRs before passes.
   std::vector<IRUnitT> BeforeStack;
@@ -269,50 +267,47 @@ protected:
   void handleAfter(StringRef PassID, std::string &Name,
                    const std::string &Before, const std::string &After,
                    Any) override;
-  // Called to compare the before and after representations of the IR.
-  bool same(const std::string &Before, const std::string &After) override;
 };
 
-// The following classes hold a representation of the IR for a change
-// reporter that uses string comparisons of the basic blocks
-// that are created using print (ie, similar to dump()).
-// These classes respect the filtering of passes and functions using
-// -filter-passes and -filter-print-funcs.
-//
 // Information that needs to be saved for a basic block in order to compare
 // before and after the pass to determine if it was changed by a pass.
-class ChangedBlockData {
+template <typename T> class BlockDataT {
 public:
-  ChangedBlockData(const BasicBlock &B);
-
-  bool operator==(const ChangedBlockData &That) const {
-    return Body == That.Body;
-  }
-  bool operator!=(const ChangedBlockData &That) const {
-    return Body != That.Body;
+  BlockDataT(const BasicBlock &B) : Label(B.getName().str()), Data(B) {
+    raw_string_ostream SS(Body);
+    B.print(SS, nullptr, true, true);
   }
 
+  bool operator==(const BlockDataT &That) const { return Body == That.Body; }
+  bool operator!=(const BlockDataT &That) const { return Body != That.Body; }
+
   // Return the label of the represented basic block.
   StringRef getLabel() const { return Label; }
   // Return the string representation of the basic block.
   StringRef getBody() const { return Body; }
 
+  // Return the associated data
+  const T &getData() const { return Data; }
+
 protected:
   std::string Label;
   std::string Body;
+
+  // Extra data associated with a basic block
+  T Data;
 };
 
-template <typename IRData> class OrderedChangedData {
+template <typename T> class OrderedChangedData {
 public:
   // Return the names in the order they were saved
   std::vector<std::string> &getOrder() { return Order; }
   const std::vector<std::string> &getOrder() const { return Order; }
 
   // Return a map of names to saved representations
-  StringMap<IRData> &getData() { return Data; }
-  const StringMap<IRData> &getData() const { return Data; }
+  StringMap<T> &getData() { return Data; }
+  const StringMap<T> &getData() const { return Data; }
 
-  bool operator==(const OrderedChangedData<IRData> &That) const {
+  bool operator==(const OrderedChangedData<T> &That) const {
     return Data == That.getData();
   }
 
@@ -321,55 +316,56 @@ public:
   // with ones that are only in \p Before interspersed based on where they
   // occur in \p Before.  This is used to present the output in an order
   // based on how the data is ordered in LLVM.
-  static void
-  report(const OrderedChangedData &Before, const OrderedChangedData &After,
-         function_ref<void(const IRData *, const IRData *)> HandlePair);
+  static void report(const OrderedChangedData &Before,
+                     const OrderedChangedData &After,
+                     function_ref<void(const T *, const T *)> HandlePair);
 
 protected:
   std::vector<std::string> Order;
-  StringMap<IRData> Data;
+  StringMap<T> Data;
+};
+
+// Do not need extra information for patch-style change reporter.
+class EmptyData {
+public:
+  EmptyData(const BasicBlock &) {}
 };
 
 // The data saved for comparing functions.
-using ChangedFuncData = OrderedChangedData<ChangedBlockData>;
+template <typename T>
+class FuncDataT : public OrderedChangedData<BlockDataT<T>> {};
 
-// A map of names to the saved data.
-using ChangedIRData = OrderedChangedData<ChangedFuncData>;
+// The data saved for comparing IRs.
+template <typename T>
+class IRDataT : public OrderedChangedData<FuncDataT<T>> {};
 
-// A class that compares two IRs and does a diff between them.  The
-// added lines are prefixed with a '+', the removed lines are prefixed
-// with a '-' and unchanged lines are prefixed with a space (to have
-// things line up).
-class ChangedIRComparer {
+// Abstract template base class for a class that compares two IRs.  The
+// class is created with the 2 IRs to compare and then compare is called.
+// The static function analyzeIR is used to build up the IR representation.
+template <typename T> class IRComparer {
 public:
-  ChangedIRComparer(raw_ostream &OS, const ChangedIRData &Before,
-                    const ChangedIRData &After, bool ColourMode)
-      : Before(Before), After(After), Out(OS), UseColour(ColourMode) {}
+  IRComparer(const IRDataT<T> &Before, const IRDataT<T> &After)
+      : Before(Before), After(After) {}
 
-  // Compare the 2 IRs.
-  void compare(Any IR, StringRef Prefix, StringRef PassID, StringRef Name);
+  // Compare the 2 IRs. \p handleFunctionCompare is called to handle the
+  // compare of a function. When \p InModule is set,
+  // this function is being handled as part of comparing a module.
+
+  void compare(
+      bool CompareModule,
+      std::function<void(bool InModule, unsigned Minor,
+                         const FuncDataT<T> &Before, const FuncDataT<T> &After)>
+          CompareFunc);
 
   // Analyze \p IR and build the IR representation in \p Data.
-  static void analyzeIR(Any IR, ChangedIRData &Data);
+  static void analyzeIR(Any IR, IRDataT<T> &Data);
 
 protected:
-  // Return the module when that is the appropriate level of
-  // comparison for \p IR.
-  static const Module *getModuleForComparison(Any IR);
-
   // Generate the data for \p F into \p Data.
-  static bool generateFunctionData(ChangedIRData &Data, const Function &F);
-
-  // Called to handle the compare of a function. When \p InModule is set,
-  // this function is being handled as part of comparing a module.
-  void handleFunctionCompare(StringRef Name, StringRef Prefix, StringRef PassID,
-                             bool InModule, const ChangedFuncData &Before,
-                             const ChangedFuncData &After);
+  static bool generateFunctionData(IRDataT<T> &Data, const Function &F);
 
-  const ChangedIRData &Before;
-  const ChangedIRData &After;
-  raw_ostream &Out;
-  bool UseColour;
+  const IRDataT<T> &Before;
+  const IRDataT<T> &After;
 };
 
 // A change printer that prints out in-line differences in the basic
@@ -378,25 +374,28 @@ protected:
 // and added, respectively.  Changes to the IR that do not affect basic
 // blocks are not reported as having changed the IR.  The option
 // -print-module-scope does not affect this change reporter.
-class InLineChangePrinter : public TextChangeReporter<ChangedIRData> {
+class InLineChangePrinter : public TextChangeReporter<IRDataT<EmptyData>> {
 public:
   InLineChangePrinter(bool VerboseMode, bool ColourMode)
-      : TextChangeReporter<ChangedIRData>(VerboseMode), UseColour(ColourMode) {}
+      : TextChangeReporter<IRDataT<EmptyData>>(VerboseMode),
+        UseColour(ColourMode) {}
   ~InLineChangePrinter() override;
   void registerCallbacks(PassInstrumentationCallbacks &PIC);
 
 protected:
   // Create a representation of the IR.
   virtual void generateIRRepresentation(Any IR, StringRef PassID,
-                                        ChangedIRData &Output) override;
+                                        IRDataT<EmptyData> &Output) override;
 
   // Called when an interesting IR has changed.
   virtual void handleAfter(StringRef PassID, std::string &Name,
-                           const ChangedIRData &Before,
-                           const ChangedIRData &After, Any) override;
-  // Called to compare the before and after representations of the IR.
-  virtual bool same(const ChangedIRData &Before,
-                    const ChangedIRData &After) override;
+                           const IRDataT<EmptyData> &Before,
+                           const IRDataT<EmptyData> &After, Any) override;
+
+  void handleFunctionCompare(StringRef Name, StringRef Prefix, StringRef PassID,
+                             StringRef Divider, bool InModule, unsigned Minor,
+                             const FuncDataT<EmptyData> &Before,
+                             const FuncDataT<EmptyData> &After);
 
   bool UseColour;
 };
@@ -440,8 +439,12 @@ public:
 extern template class ChangeReporter<std::string>;
 extern template class TextChangeReporter<std::string>;
 
-extern template class ChangeReporter<ChangedIRData>;
-extern template class TextChangeReporter<ChangedIRData>;
+extern template class BlockDataT<EmptyData>;
+extern template class FuncDataT<EmptyData>;
+extern template class IRDataT<EmptyData>;
+extern template class ChangeReporter<IRDataT<EmptyData>>;
+extern template class TextChangeReporter<IRDataT<EmptyData>>;
+extern template class IRComparer<EmptyData>;
 
 } // namespace llvm
 
index 28d2ca2..727d02a 100644 (file)
@@ -166,7 +166,8 @@ std::string doSystemDiff(StringRef Before, StringRef After,
   SmallString<128> ULF =
       formatv("--unchanged-line-format={0}", UnchangedLineFormat);
 
-  StringRef Args[] = {"-w", "-d", OLF, NLF, ULF, FileName[0], FileName[1]};
+  StringRef Args[] = {DiffBinary, "-w", "-d",        OLF,
+                      NLF,        ULF,  FileName[0], FileName[1]};
   Optional<StringRef> Redirects[] = {None, StringRef(FileName[2]), None};
   int Result = sys::ExecuteAndWait(*DiffExe, Args, None, Redirects);
   if (Result < 0)
@@ -366,20 +367,31 @@ bool isIgnored(StringRef PassID) {
                         "DevirtSCCRepeatedPass", "ModuleInlinerWrapperPass"});
 }
 
+// Return the module when that is the appropriate level of comparison for \p IR.
+const Module *getModuleForComparison(Any IR) {
+  if (any_isa<const Module *>(IR))
+    return any_cast<const Module *>(IR);
+  if (any_isa<const LazyCallGraph::SCC *>(IR))
+    return any_cast<const LazyCallGraph::SCC *>(IR)
+        ->begin()
+        ->getFunction()
+        .getParent();
+  return nullptr;
+}
+
 } // namespace
 
-template <typename IRUnitT>
-ChangeReporter<IRUnitT>::~ChangeReporter<IRUnitT>() {
+template <typename T> ChangeReporter<T>::~ChangeReporter<T>() {
   assert(BeforeStack.empty() && "Problem with Change Printer stack.");
 }
 
-template <typename IRUnitT>
-bool ChangeReporter<IRUnitT>::isInterestingFunction(const Function &F) {
+template <typename T>
+bool ChangeReporter<T>::isInterestingFunction(const Function &F) {
   return isFunctionInPrintList(F.getName());
 }
 
-template <typename IRUnitT>
-bool ChangeReporter<IRUnitT>::isInterestingPass(StringRef PassID) {
+template <typename T>
+bool ChangeReporter<T>::isInterestingPass(StringRef PassID) {
   if (isIgnored(PassID))
     return false;
 
@@ -390,8 +402,8 @@ bool ChangeReporter<IRUnitT>::isInterestingPass(StringRef PassID) {
 
 // Return true when this is a pass on IR for which printing
 // of changes is desired.
-template <typename IRUnitT>
-bool ChangeReporter<IRUnitT>::isInteresting(Any IR, StringRef PassID) {
+template <typename T>
+bool ChangeReporter<T>::isInteresting(Any IR, StringRef PassID) {
   if (!isInterestingPass(PassID))
     return false;
   if (any_isa<const Function *>(IR))
@@ -399,8 +411,8 @@ bool ChangeReporter<IRUnitT>::isInteresting(Any IR, StringRef PassID) {
   return true;
 }
 
-template <typename IRUnitT>
-void ChangeReporter<IRUnitT>::saveIRBeforePass(Any IR, StringRef PassID) {
+template <typename T>
+void ChangeReporter<T>::saveIRBeforePass(Any IR, StringRef PassID) {
   // Always need to place something on the stack because invalidated passes
   // are not given the IR so it cannot be determined whether the pass was for
   // something that was filtered out.
@@ -416,12 +428,12 @@ void ChangeReporter<IRUnitT>::saveIRBeforePass(Any IR, StringRef PassID) {
   }
 
   // Save the IR representation on the stack.
-  IRUnitT &Data = BeforeStack.back();
+  T &Data = BeforeStack.back();
   generateIRRepresentation(IR, PassID, Data);
 }
 
-template <typename IRUnitT>
-void ChangeReporter<IRUnitT>::handleIRAfterPass(Any IR, StringRef PassID) {
+template <typename T>
+void ChangeReporter<T>::handleIRAfterPass(Any IR, StringRef PassID) {
   assert(!BeforeStack.empty() && "Unexpected empty stack encountered.");
 
   std::string Name = getIRName(IR);
@@ -434,13 +446,13 @@ void ChangeReporter<IRUnitT>::handleIRAfterPass(Any IR, StringRef PassID) {
       handleFiltered(PassID, Name);
   } else {
     // Get the before rep from the stack
-    IRUnitT &Before = BeforeStack.back();
+    T &Before = BeforeStack.back();
     // Create the after rep
-    IRUnitT After;
+    T After;
     generateIRRepresentation(IR, PassID, After);
 
     // Was there a change in IR?
-    if (same(Before, After)) {
+    if (Before == After) {
       if (VerboseMode)
         omitAfter(PassID, Name);
     } else
@@ -449,8 +461,8 @@ void ChangeReporter<IRUnitT>::handleIRAfterPass(Any IR, StringRef PassID) {
   BeforeStack.pop_back();
 }
 
-template <typename IRUnitT>
-void ChangeReporter<IRUnitT>::handleInvalidatedPass(StringRef PassID) {
+template <typename T>
+void ChangeReporter<T>::handleInvalidatedPass(StringRef PassID) {
   assert(!BeforeStack.empty() && "Unexpected empty stack encountered.");
 
   // Always flag it as invalidated as we cannot determine when
@@ -462,8 +474,8 @@ void ChangeReporter<IRUnitT>::handleInvalidatedPass(StringRef PassID) {
   BeforeStack.pop_back();
 }
 
-template <typename IRUnitT>
-void ChangeReporter<IRUnitT>::registerRequiredCallbacks(
+template <typename T>
+void ChangeReporter<T>::registerRequiredCallbacks(
     PassInstrumentationCallbacks &PIC) {
   PIC.registerBeforeNonSkippedPassCallback(
       [this](StringRef P, Any IR) { saveIRBeforePass(IR, P); });
@@ -478,18 +490,11 @@ void ChangeReporter<IRUnitT>::registerRequiredCallbacks(
       });
 }
 
-ChangedBlockData::ChangedBlockData(const BasicBlock &B)
-    : Label(B.getName().str()) {
-  raw_string_ostream SS(Body);
-  B.print(SS, nullptr, true, true);
-}
-
-template <typename IRUnitT>
-TextChangeReporter<IRUnitT>::TextChangeReporter(bool Verbose)
-    : ChangeReporter<IRUnitT>(Verbose), Out(dbgs()) {}
+template <typename T>
+TextChangeReporter<T>::TextChangeReporter(bool Verbose)
+    : ChangeReporter<T>(Verbose), Out(dbgs()) {}
 
-template <typename IRUnitT>
-void TextChangeReporter<IRUnitT>::handleInitialIR(Any IR) {
+template <typename T> void TextChangeReporter<T>::handleInitialIR(Any IR) {
   // Always print the module.
   // Unwrap and print directly to avoid filtering problems in general routines.
   auto *M = unwrapModule(IR, /*Force=*/true);
@@ -498,29 +503,27 @@ void TextChangeReporter<IRUnitT>::handleInitialIR(Any IR) {
   M->print(Out, nullptr);
 }
 
-template <typename IRUnitT>
-void TextChangeReporter<IRUnitT>::omitAfter(StringRef PassID,
-                                            std::string &Name) {
+template <typename T>
+void TextChangeReporter<T>::omitAfter(StringRef PassID, std::string &Name) {
   Out << formatv("*** IR Dump After {0} on {1} omitted because no change ***\n",
                  PassID, Name);
 }
 
-template <typename IRUnitT>
-void TextChangeReporter<IRUnitT>::handleInvalidated(StringRef PassID) {
+template <typename T>
+void TextChangeReporter<T>::handleInvalidated(StringRef PassID) {
   Out << formatv("*** IR Pass {0} invalidated ***\n", PassID);
 }
 
-template <typename IRUnitT>
-void TextChangeReporter<IRUnitT>::handleFiltered(StringRef PassID,
-                                                 std::string &Name) {
+template <typename T>
+void TextChangeReporter<T>::handleFiltered(StringRef PassID,
+                                           std::string &Name) {
   SmallString<20> Banner =
       formatv("*** IR Dump After {0} on {1} filtered out ***\n", PassID, Name);
   Out << Banner;
 }
 
-template <typename IRUnitT>
-void TextChangeReporter<IRUnitT>::handleIgnored(StringRef PassID,
-                                                std::string &Name) {
+template <typename T>
+void TextChangeReporter<T>::handleIgnored(StringRef PassID, std::string &Name) {
   Out << formatv("*** IR Pass {0} on {1} ignored ***\n", PassID, Name);
 }
 
@@ -557,14 +560,10 @@ void IRChangedPrinter::handleAfter(StringRef PassID, std::string &Name,
   Out << "*** IR Dump After " << PassID << " on " << Name << " ***\n" << After;
 }
 
-bool IRChangedPrinter::same(const std::string &S1, const std::string &S2) {
-  return S1 == S2;
-}
-
-template <typename IRData>
-void OrderedChangedData<IRData>::report(
+template <typename T>
+void OrderedChangedData<T>::report(
     const OrderedChangedData &Before, const OrderedChangedData &After,
-    function_ref<void(const IRData *, const IRData *)> HandlePair) {
+    function_ref<void(const T *, const T *)> HandlePair) {
   const auto &BFD = Before.getData();
   const auto &AFD = After.getData();
   std::vector<std::string>::const_iterator BI = Before.getOrder().begin();
@@ -572,21 +571,21 @@ void OrderedChangedData<IRData>::report(
   std::vector<std::string>::const_iterator AI = After.getOrder().begin();
   std::vector<std::string>::const_iterator AE = After.getOrder().end();
 
-  auto handlePotentiallyRemovedIRData = [&](std::string S) {
+  auto HandlePotentiallyRemovedData = [&](std::string S) {
     // The order in LLVM may have changed so check if still exists.
     if (!AFD.count(S)) {
       // This has been removed.
       HandlePair(&BFD.find(*BI)->getValue(), nullptr);
     }
   };
-  auto handleNewIRData = [&](std::vector<const IRData *> &Q) {
+  auto HandleNewData = [&](std::vector<const T *> &Q) {
     // Print out any queued up new sections
-    for (const IRData *NBI : Q)
+    for (const T *NBI : Q)
       HandlePair(nullptr, NBI);
     Q.clear();
   };
 
-  // Print out the IRData in the after order, with before ones interspersed
+  // Print out the data in the after order, with before ones interspersed
   // appropriately (ie, somewhere near where they were in the before list).
   // Start at the beginning of both lists.  Loop through the
   // after list.  If an element is common, then advance in the before list
@@ -595,26 +594,26 @@ void OrderedChangedData<IRData>::report(
   // common, then enqueue it for reporting.  When the after list is exhausted,
   // loop through the before list, reporting any removed ones.  Finally,
   // report the rest of the enqueued new ones.
-  std::vector<const IRData *> NewIRDataQueue;
+  std::vector<const T *> NewDataQueue;
   while (AI != AE) {
     if (!BFD.count(*AI)) {
       // This section is new so place it in the queue.  This will cause it
       // to be reported after deleted sections.
-      NewIRDataQueue.emplace_back(&AFD.find(*AI)->getValue());
+      NewDataQueue.emplace_back(&AFD.find(*AI)->getValue());
       ++AI;
       continue;
     }
     // This section is in both; advance and print out any before-only
     // until we get to it.
     while (*BI != *AI) {
-      handlePotentiallyRemovedIRData(*BI);
+      HandlePotentiallyRemovedData(*BI);
       ++BI;
     }
     // Report any new sections that were queued up and waiting.
-    handleNewIRData(NewIRDataQueue);
+    HandleNewData(NewDataQueue);
 
-    const IRData &AData = AFD.find(*AI)->getValue();
-    const IRData &BData = BFD.find(*AI)->getValue();
+    const T &AData = AFD.find(*AI)->getValue();
+    const T &BData = BFD.find(*AI)->getValue();
     HandlePair(&BData, &AData);
     ++BI;
     ++AI;
@@ -622,38 +621,42 @@ void OrderedChangedData<IRData>::report(
 
   // Check any remaining before sections to see if they have been removed
   while (BI != BE) {
-    handlePotentiallyRemovedIRData(*BI);
+    HandlePotentiallyRemovedData(*BI);
     ++BI;
   }
 
-  handleNewIRData(NewIRDataQueue);
+  HandleNewData(NewDataQueue);
 }
 
-void ChangedIRComparer::compare(Any IR, StringRef Prefix, StringRef PassID,
-                                StringRef Name) {
-  if (!getModuleForComparison(IR)) {
-    // Not a module so just handle the single function.
-    assert(Before.getData().size() == 1 && "Expected only one function.");
-    assert(After.getData().size() == 1 && "Expected only one function.");
-    handleFunctionCompare(Name, Prefix, PassID, false,
-                          Before.getData().begin()->getValue(),
-                          After.getData().begin()->getValue());
+template <typename T>
+void IRComparer<T>::compare(
+    bool CompareModule,
+    std::function<void(bool InModule, unsigned Minor,
+                       const FuncDataT<T> &Before, const FuncDataT<T> &After)>
+        CompareFunc) {
+  if (!CompareModule) {
+    // Just handle the single function.
+    assert(Before.getData().size() == 1 && After.getData().size() == 1 &&
+           "Expected only one function.");
+    CompareFunc(false, 0, Before.getData().begin()->getValue(),
+                After.getData().begin()->getValue());
     return;
   }
 
-  ChangedIRData::report(
-      Before, After, [&](const ChangedFuncData *B, const ChangedFuncData *A) {
-        assert((B || A) && "Both functions cannot be missing.");
-        ChangedFuncData Missing;
-        if (!B)
-          B = &Missing;
-        else if (!A)
-          A = &Missing;
-        handleFunctionCompare(Name, Prefix, PassID, true, *B, *A);
-      });
+  unsigned Minor = 0;
+  FuncDataT<T> Missing;
+  IRDataT<T>::report(Before, After,
+                     [&](const FuncDataT<T> *B, const FuncDataT<T> *A) {
+                       assert((B || A) && "Both functions cannot be missing.");
+                       if (!B)
+                         B = &Missing;
+                       else if (!A)
+                         A = &Missing;
+                       CompareFunc(true, Minor++, *B, *A);
+                     });
 }
 
-void ChangedIRComparer::analyzeIR(Any IR, ChangedIRData &Data) {
+template <typename T> void IRComparer<T>::analyzeIR(Any IR, IRDataT<T> &Data) {
   if (const Module *M = getModuleForComparison(IR)) {
     // Create data for each existing/interesting function in the module.
     for (const Function &F : *M)
@@ -673,27 +676,16 @@ void ChangedIRComparer::analyzeIR(Any IR, ChangedIRData &Data) {
   generateFunctionData(Data, *F);
 }
 
-const Module *ChangedIRComparer::getModuleForComparison(Any IR) {
-  if (any_isa<const Module *>(IR))
-    return any_cast<const Module *>(IR);
-  if (any_isa<const LazyCallGraph::SCC *>(IR))
-    return any_cast<const LazyCallGraph::SCC *>(IR)
-        ->begin()
-        ->getFunction()
-        .getParent();
-  return nullptr;
-}
-
-bool ChangedIRComparer::generateFunctionData(ChangedIRData &Data,
-                                             const Function &F) {
+template <typename T>
+bool IRComparer<T>::generateFunctionData(IRDataT<T> &Data, const Function &F) {
   if (!F.isDeclaration() && isFunctionInPrintList(F.getName())) {
-    ChangedFuncData CFD;
+    FuncDataT<T> FD;
     for (const auto &B : F) {
-      CFD.getOrder().emplace_back(B.getName());
-      CFD.getData().insert({B.getName(), B});
+      FD.getOrder().emplace_back(B.getName());
+      FD.getData().insert({B.getName(), B});
     }
     Data.getOrder().emplace_back(F.getName());
-    Data.getData().insert({F.getName(), CFD});
+    Data.getData().insert({F.getName(), FD});
     return true;
   }
   return false;
@@ -787,7 +779,7 @@ bool PrintIRInstrumentation::shouldPrintBeforePass(StringRef PassID) {
     return true;
 
   StringRef PassName = PIC->getPassNameForClassName(PassID);
-  return llvm::is_contained(printBeforePasses(), PassName);
+  return is_contained(printBeforePasses(), PassName);
 }
 
 bool PrintIRInstrumentation::shouldPrintAfterPass(StringRef PassID) {
@@ -795,7 +787,7 @@ bool PrintIRInstrumentation::shouldPrintAfterPass(StringRef PassID) {
     return true;
 
   StringRef PassName = PIC->getPassNameForClassName(PassID);
-  return llvm::is_contained(printAfterPasses(), PassName);
+  return is_contained(printAfterPasses(), PassName);
 }
 
 void PrintIRInstrumentation::registerCallbacks(
@@ -869,14 +861,13 @@ void PrintPassInstrumentation::registerCallbacks(
     SpecialPasses.emplace_back("PassAdaptor");
   }
 
-  PIC.registerBeforeSkippedPassCallback(
-      [this, SpecialPasses](StringRef PassID, Any IR) {
-        assert(!isSpecialPass(PassID, SpecialPasses) &&
-               "Unexpectedly skipping special pass");
+  PIC.registerBeforeSkippedPassCallback([this, SpecialPasses](StringRef PassID,
+                                                              Any IR) {
+    assert(!isSpecialPass(PassID, SpecialPasses) &&
+           "Unexpectedly skipping special pass");
 
-        print() << "Skipping pass: " << PassID << " on " << getIRName(IR)
-                << "\n";
-      });
+    print() << "Skipping pass: " << PassID << " on " << getIRName(IR) << "\n";
+  });
   PIC.registerBeforeNonSkippedPassCallback([this, SpecialPasses](
                                                StringRef PassID, Any IR) {
     if (isSpecialPass(PassID, SpecialPasses))
@@ -1074,19 +1065,18 @@ void PreservedCFGCheckerInstrumentation::registerCallbacks(
     report_fatal_error(Twine("CFG unexpectedly changed by ", Pass));
   };
 
-  PIC.registerBeforeNonSkippedPassCallback(
-      [this, &FAM](StringRef P, Any IR) {
+  PIC.registerBeforeNonSkippedPassCallback([this, &FAM](StringRef P, Any IR) {
 #ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
-        assert(&PassStack.emplace_back(P));
+    assert(&PassStack.emplace_back(P));
 #endif
-        (void)this;
-        if (!any_isa<const Function *>(IR))
-          return;
+    (void)this;
+    if (!any_isa<const Function *>(IR))
+      return;
 
-        const auto *F = any_cast<const Function *>(IR);
-        // Make sure a fresh CFG snapshot is available before the pass.
-        FAM.getResult<PreservedCFGCheckerAnalysis>(*const_cast<Function *>(F));
-      });
+    const auto *F = any_cast<const Function *>(IR);
+    // Make sure a fresh CFG snapshot is available before the pass.
+    FAM.getResult<PreservedCFGCheckerAnalysis>(*const_cast<Function *>(F));
+  });
 
   PIC.registerAfterPassInvalidatedCallback(
       [this](StringRef P, const PreservedAnalyses &PassPA) {
@@ -1160,36 +1150,38 @@ void VerifyInstrumentation::registerCallbacks(
 InLineChangePrinter::~InLineChangePrinter() {}
 
 void InLineChangePrinter::generateIRRepresentation(Any IR, StringRef PassID,
-                                                   ChangedIRData &D) {
-  ChangedIRComparer::analyzeIR(IR, D);
+                                                   IRDataT<EmptyData> &D) {
+  IRComparer<EmptyData>::analyzeIR(IR, D);
 }
 
 void InLineChangePrinter::handleAfter(StringRef PassID, std::string &Name,
-                                      const ChangedIRData &Before,
-                                      const ChangedIRData &After, Any IR) {
+                                      const IRDataT<EmptyData> &Before,
+                                      const IRDataT<EmptyData> &After, Any IR) {
   SmallString<20> Banner =
       formatv("*** IR Dump After {0} on {1} ***\n", PassID, Name);
   Out << Banner;
-  ChangedIRComparer(Out, Before, After, UseColour)
-      .compare(IR, "", PassID, Name);
+  IRComparer<EmptyData>(Before, After)
+      .compare(getModuleForComparison(IR),
+               [&](bool InModule, unsigned Minor,
+                   const FuncDataT<EmptyData> &Before,
+                   const FuncDataT<EmptyData> &After) -> void {
+                 handleFunctionCompare(Name, "", PassID, " on ", InModule,
+                                       Minor, Before, After);
+               });
   Out << "\n";
 }
 
-bool InLineChangePrinter::same(const ChangedIRData &D1,
-                               const ChangedIRData &D2) {
-  return D1 == D2;
-}
-
-void ChangedIRComparer::handleFunctionCompare(StringRef Name, StringRef Prefix,
-                                              StringRef PassID, bool InModule,
-                                              const ChangedFuncData &Before,
-                                              const ChangedFuncData &After) {
+void InLineChangePrinter::handleFunctionCompare(
+    StringRef Name, StringRef Prefix, StringRef PassID, StringRef Divider,
+    bool InModule, unsigned Minor, const FuncDataT<EmptyData> &Before,
+    const FuncDataT<EmptyData> &After) {
   // Print a banner when this is being shown in the context of a module
   if (InModule)
     Out << "\n*** IR for function " << Name << " ***\n";
 
-  ChangedFuncData::report(
-      Before, After, [&](const ChangedBlockData *B, const ChangedBlockData *A) {
+  FuncDataT<EmptyData>::report(
+      Before, After,
+      [&](const BlockDataT<EmptyData> *B, const BlockDataT<EmptyData> *A) {
         StringRef BStr = B ? B->getBody() : "\n";
         StringRef AStr = A ? A->getBody() : "\n";
         const std::string Removed =
@@ -1205,9 +1197,11 @@ void InLineChangePrinter::registerCallbacks(PassInstrumentationCallbacks &PIC) {
       PrintChanged == ChangePrinter::PrintChangedDiffQuiet ||
       PrintChanged == ChangePrinter::PrintChangedColourDiffVerbose ||
       PrintChanged == ChangePrinter::PrintChangedColourDiffQuiet)
-    TextChangeReporter<ChangedIRData>::registerRequiredCallbacks(PIC);
+    TextChangeReporter<IRDataT<EmptyData>>::registerRequiredCallbacks(PIC);
 }
 
+namespace llvm {
+
 StandardInstrumentations::StandardInstrumentations(
     bool DebugLogging, bool VerifyEach, PrintPassOptions PrintPassOpts)
     : PrintPass(DebugLogging, PrintPassOpts), OptNone(DebugLogging),
@@ -1235,12 +1229,14 @@ void StandardInstrumentations::registerCallbacks(
   PrintChangedDiff.registerCallbacks(PIC);
 }
 
-namespace llvm {
-
 template class ChangeReporter<std::string>;
 template class TextChangeReporter<std::string>;
 
-template class ChangeReporter<ChangedIRData>;
-template class TextChangeReporter<ChangedIRData>;
+template class BlockDataT<EmptyData>;
+template class FuncDataT<EmptyData>;
+template class IRDataT<EmptyData>;
+template class ChangeReporter<IRDataT<EmptyData>>;
+template class TextChangeReporter<IRDataT<EmptyData>>;
+template class IRComparer<EmptyData>;
 
 } // namespace llvm