[llvm] [Instrumentation] Support MachineFunction in ChangeReporter (PR #80946)

via llvm-commits llvm-commits at lists.llvm.org
Tue Apr 9 03:40:25 PDT 2024


https://github.com/paperchalice updated https://github.com/llvm/llvm-project/pull/80946

>From 04424463f7223acbc177dd59d0a292d218de5c9a Mon Sep 17 00:00:00 2001
From: PaperChalice <liujunchang97 at outlook.com>
Date: Wed, 7 Feb 2024 15:09:38 +0800
Subject: [PATCH] [Instrumentation] Support MachineFunction in ChangeReporter

---
 .../llvm/Passes/StandardInstrumentations.h    |  13 +-
 llvm/lib/Passes/StandardInstrumentations.cpp  | 170 ++++++++++++------
 .../DotCfg/print-changed-dot-cfg.mir          |  24 +++
 llvm/test/Other/change-printer.mir            |  21 +++
 4 files changed, 177 insertions(+), 51 deletions(-)
 create mode 100644 llvm/test/Other/ChangePrinters/DotCfg/print-changed-dot-cfg.mir
 create mode 100644 llvm/test/Other/change-printer.mir

diff --git a/llvm/include/llvm/Passes/StandardInstrumentations.h b/llvm/include/llvm/Passes/StandardInstrumentations.h
index 8c6a44876d5459b..b053e6307a653ca 100644
--- a/llvm/include/llvm/Passes/StandardInstrumentations.h
+++ b/llvm/include/llvm/Passes/StandardInstrumentations.h
@@ -18,6 +18,8 @@
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/CodeGen/MachineBasicBlock.h"
 #include "llvm/IR/BasicBlock.h"
 #include "llvm/IR/OptBisect.h"
 #include "llvm/IR/PassTimingInfo.h"
@@ -33,6 +35,7 @@ namespace llvm {
 
 class Module;
 class Function;
+class MachineFunction;
 class PassInstrumentationCallbacks;
 
 /// Instrumentation to print IR before/after passes.
@@ -313,6 +316,11 @@ template <typename T> class BlockDataT {
     B.print(SS, nullptr, true, true);
   }
 
+  BlockDataT(const MachineBasicBlock &B) : Label(B.getName().str()), Data(B) {
+    raw_string_ostream SS(Body);
+    B.print(SS);
+  }
+
   bool operator==(const BlockDataT &That) const { return Body == That.Body; }
   bool operator!=(const BlockDataT &That) const { return Body != That.Body; }
 
@@ -364,6 +372,7 @@ template <typename T> class OrderedChangedData {
 class EmptyData {
 public:
   EmptyData(const BasicBlock &) {}
+  EmptyData(const MachineBasicBlock &) {}
 };
 
 // The data saved for comparing functions.
@@ -405,7 +414,8 @@ template <typename T> class IRComparer {
 
 protected:
   // Generate the data for \p F into \p Data.
-  static bool generateFunctionData(IRDataT<T> &Data, const Function &F);
+  template <typename FunctionT>
+  static bool generateFunctionData(IRDataT<T> &Data, const FunctionT &F);
 
   const IRDataT<T> &Before;
   const IRDataT<T> &After;
@@ -475,6 +485,7 @@ class DCData {
 public:
   // Fill the map with the transitions from basic block \p B.
   DCData(const BasicBlock &B);
+  DCData(const MachineBasicBlock &B);
 
   // Return an iterator to the names of the successor blocks.
   StringMap<std::string>::const_iterator begin() const {
diff --git a/llvm/lib/Passes/StandardInstrumentations.cpp b/llvm/lib/Passes/StandardInstrumentations.cpp
index 697988b3fc7c0b3..f27c6e0ef864007 100644
--- a/llvm/lib/Passes/StandardInstrumentations.cpp
+++ b/llvm/lib/Passes/StandardInstrumentations.cpp
@@ -19,7 +19,10 @@
 #include "llvm/Analysis/CallGraphSCCPass.h"
 #include "llvm/Analysis/LazyCallGraph.h"
 #include "llvm/Analysis/LoopInfo.h"
+#include "llvm/CodeGen/FreeMachineFunction.h"
+#include "llvm/CodeGen/MIRPrinter.h"
 #include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineModuleInfo.h"
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/Function.h"
 #include "llvm/IR/Module.h"
@@ -105,18 +108,19 @@ static cl::opt<std::string> PrintOnCrashPath(
     cl::desc("Print the last form of the IR before crash to a file"),
     cl::Hidden);
 
-static cl::opt<bool> PrintOnCrash(
-    "print-on-crash",
-    cl::desc("Print the last form of the IR before crash (use -print-on-crash-path to dump to a file)"),
-    cl::Hidden);
+static cl::opt<bool>
+    PrintOnCrash("print-on-crash",
+                 cl::desc("Print the last form of the IR before crash (use "
+                          "-print-on-crash-path to dump to a file)"),
+                 cl::Hidden);
 
 static cl::opt<std::string> OptBisectPrintIRPath(
     "opt-bisect-print-ir-path",
     cl::desc("Print IR to path when opt-bisect-limit is reached"), cl::Hidden);
 
-static cl::opt<bool> PrintPassNumbers(
-    "print-pass-numbers", cl::init(false), cl::Hidden,
-    cl::desc("Print pass names and their ordinals"));
+static cl::opt<bool>
+    PrintPassNumbers("print-pass-numbers", cl::init(false), cl::Hidden,
+                     cl::desc("Print pass names and their ordinals"));
 
 static cl::opt<unsigned> PrintBeforePassNumber(
     "print-before-pass-number", cl::init(0), cl::Hidden,
@@ -180,6 +184,12 @@ const Module *unwrapModule(Any IR, bool Force = false) {
     return F->getParent();
   }
 
+  if (const auto *MF = unwrapIR<MachineFunction>(IR)) {
+    if (!Force && !isFunctionInPrintList(MF->getName()))
+      return nullptr;
+    return MF->getFunction().getParent();
+  }
+
   llvm_unreachable("Unknown IR unit");
 }
 
@@ -215,6 +225,12 @@ void printIR(raw_ostream &OS, const Loop *L) {
   printLoop(const_cast<Loop &>(*L), OS);
 }
 
+void printIR(raw_ostream &OS, const MachineFunction *MF) {
+  if (!isFunctionInPrintList(MF->getName()))
+    return;
+  MF->print(OS);
+}
+
 std::string getIRName(Any IR) {
   if (unwrapIR<Module>(IR))
     return "[module]";
@@ -262,6 +278,9 @@ bool shouldPrintIR(Any IR) {
 
   if (const auto *L = unwrapIR<Loop>(IR))
     return isFunctionInPrintList(L->getHeader()->getParent()->getName());
+
+  if (const auto *MF = unwrapIR<MachineFunction>(IR))
+    return isFunctionInPrintList(MF->getName());
   llvm_unreachable("Unknown wrapped IR type");
 }
 
@@ -275,6 +294,14 @@ void unwrapAndPrint(raw_ostream &OS, Any IR) {
     auto *M = unwrapModule(IR);
     assert(M && "should have unwrapped module");
     printIR(OS, M);
+
+    if (const auto *MF = unwrapIR<MachineFunction>(IR)) {
+      auto &MMI = MF->getMMI();
+      for (const auto &F : *M) {
+        if (auto *MF = MMI.getMachineFunction(F))
+          MF->print(OS);
+      }
+    }
     return;
   }
 
@@ -297,6 +324,11 @@ void unwrapAndPrint(raw_ostream &OS, Any IR) {
     printIR(OS, L);
     return;
   }
+
+  if (const auto *MF = unwrapIR<MachineFunction>(IR)) {
+    printIR(OS, MF);
+    return;
+  }
   llvm_unreachable("Unknown wrapped IR type");
 }
 
@@ -305,7 +337,8 @@ bool isIgnored(StringRef PassID) {
   return isSpecialPass(PassID,
                        {"PassManager", "PassAdaptor", "AnalysisManagerProxy",
                         "DevirtSCCRepeatedPass", "ModuleInlinerWrapperPass",
-                        "VerifierPass", "PrintModulePass"});
+                        "VerifierPass", "PrintModulePass", "PrintMIRPass",
+                        "PrintMIRPreparePass"});
 }
 
 std::string makeHTMLReady(StringRef SR) {
@@ -409,6 +442,10 @@ template <typename T>
 void ChangeReporter<T>::handleInvalidatedPass(StringRef PassID) {
   assert(!BeforeStack.empty() && "Unexpected empty stack encountered.");
 
+  // Prepare to process the next MIR.
+  if (PassID == FreeMachineFunctionPass::name())
+    InitialIR = true;
+
   // Always flag it as invalidated as we cannot determine when
   // a pass for a filtered function is invalidated since we do not
   // get the IR in the call.  Also, the output is just alternate
@@ -440,6 +477,13 @@ TextChangeReporter<T>::TextChangeReporter(bool Verbose)
     : ChangeReporter<T>(Verbose), Out(dbgs()) {}
 
 template <typename T> void TextChangeReporter<T>::handleInitialIR(Any IR) {
+  // MIR is special, not all MIRs are available at the beginning.
+  if (const auto *MF = unwrapIR<MachineFunction>(IR)) {
+    Out << "*** MIR Dump At Start ***\n";
+    MF->print(Out);
+    return;
+  }
+
   // Always print the module.
   // Unwrap and print directly to avoid filtering problems in general routines.
   auto *M = unwrapModule(IR, /*Force=*/true);
@@ -664,20 +708,38 @@ template <typename T> void IRComparer<T>::analyzeIR(Any IR, IRDataT<T> &Data) {
     return;
   }
 
-  const auto *F = unwrapIR<Function>(IR);
-  if (!F) {
-    const auto *L = unwrapIR<Loop>(IR);
-    assert(L && "Unknown IR unit.");
-    F = L->getHeader()->getParent();
+  if (const auto *F = unwrapIR<Function>(IR)) {
+    generateFunctionData(Data, *F);
+    return;
   }
-  assert(F && "Unknown IR unit.");
-  generateFunctionData(Data, *F);
+
+  if (const auto *L = unwrapIR<Loop>(IR)) {
+    auto *F = L->getHeader()->getParent();
+    generateFunctionData(Data, *F);
+    return;
+  }
+
+  if (const auto *MF = unwrapIR<MachineFunction>(IR)) {
+    generateFunctionData(Data, *MF);
+    return;
+  }
+
+  llvm_unreachable("Unknown IR unit");
+}
+
+static bool shouldGenerateData(const Function &F) {
+  return !F.isDeclaration() && isFunctionInPrintList(F.getName());
+}
+
+static bool shouldGenerateData(const MachineFunction &MF) {
+  return isFunctionInPrintList(MF.getName());
 }
 
 template <typename T>
-bool IRComparer<T>::generateFunctionData(IRDataT<T> &Data, const Function &F) {
-  if (!F.isDeclaration() && isFunctionInPrintList(F.getName())) {
-    FuncDataT<T> FD(F.getEntryBlock().getName().str());
+template <typename FunctionT>
+bool IRComparer<T>::generateFunctionData(IRDataT<T> &Data, const FunctionT &F) {
+  if (shouldGenerateData(F)) {
+    FuncDataT<T> FD(F.front().getName().str());
     int I = 0;
     for (const auto &B : F) {
       std::string BBName = B.getName().str();
@@ -722,6 +784,12 @@ static SmallString<32> getIRFileDisplayName(Any IR) {
     ResultStream << "-loop-";
     stable_hash LoopNameHash = stable_hash_combine_string(L->getName());
     write_hex(ResultStream, LoopNameHash, HexPrintStyle::Lower, MaxHashWidth);
+  } else if (const auto *MF = unwrapIR<MachineFunction>(IR)) {
+    ResultStream << "-machine-function-";
+    stable_hash MachineFunctionNameHash =
+        stable_hash_combine_string(MF->getName());
+    write_hex(ResultStream, MachineFunctionNameHash, HexPrintStyle::Lower,
+              MaxHashWidth);
   } else {
     llvm_unreachable("Unknown wrapped IR type");
   }
@@ -815,8 +883,8 @@ void PrintIRInstrumentation::printBeforePass(StringRef PassID, Any IR) {
   ++CurrentPassNumber;
 
   if (shouldPrintPassNumbers())
-    dbgs() << " Running pass " << CurrentPassNumber << " " << PassID
-           << " on " << getIRName(IR) << "\n";
+    dbgs() << " Running pass " << CurrentPassNumber << " " << PassID << " on "
+           << getIRName(IR) << "\n";
 
   if (!shouldPrintBeforePass(PassID))
     return;
@@ -1038,29 +1106,29 @@ void PrintPassInstrumentation::registerCallbacks(
 
     print() << "Skipping pass: " << PassID << " on " << getIRName(IR) << "\n";
   });
-  PIC.registerBeforeNonSkippedPassCallback([this, SpecialPasses](
-                                               StringRef PassID, Any IR) {
-    if (isSpecialPass(PassID, SpecialPasses))
-      return;
+  PIC.registerBeforeNonSkippedPassCallback(
+      [this, SpecialPasses](StringRef PassID, Any IR) {
+        if (isSpecialPass(PassID, SpecialPasses))
+          return;
 
-    auto &OS = print();
-    OS << "Running pass: " << PassID << " on " << getIRName(IR);
-    if (const auto *F = unwrapIR<Function>(IR)) {
-      unsigned Count = F->getInstructionCount();
-      OS << " (" << Count << " instruction";
-      if (Count != 1)
-        OS << 's';
-      OS << ')';
-    } else if (const auto *C = unwrapIR<LazyCallGraph::SCC>(IR)) {
-      int Count = C->size();
-      OS << " (" << Count << " node";
-      if (Count != 1)
-        OS << 's';
-      OS << ')';
-    }
-    OS << "\n";
-    Indent += 2;
-  });
+        auto &OS = print();
+        OS << "Running pass: " << PassID << " on " << getIRName(IR);
+        if (const auto *F = unwrapIR<Function>(IR)) {
+          unsigned Count = F->getInstructionCount();
+          OS << " (" << Count << " instruction";
+          if (Count != 1)
+            OS << 's';
+          OS << ')';
+        } else if (const auto *C = unwrapIR<LazyCallGraph::SCC>(IR)) {
+          int Count = C->size();
+          OS << " (" << Count << " node";
+          if (Count != 1)
+            OS << 's';
+          OS << ')';
+        }
+        OS << "\n";
+        Indent += 2;
+      });
   PIC.registerAfterPassCallback(
       [this, SpecialPasses](StringRef PassID, Any IR,
                             const PreservedAnalyses &) {
@@ -1419,16 +1487,14 @@ void VerifyInstrumentation::registerCallbacks(
 
 InLineChangePrinter::~InLineChangePrinter() = default;
 
-void InLineChangePrinter::generateIRRepresentation(Any IR,
-                                                   StringRef PassID,
+void InLineChangePrinter::generateIRRepresentation(Any IR, StringRef PassID,
                                                    IRDataT<EmptyData> &D) {
   IRComparer<EmptyData>::analyzeIR(IR, D);
 }
 
 void InLineChangePrinter::handleAfter(StringRef PassID, std::string &Name,
                                       const IRDataT<EmptyData> &Before,
-                                      const IRDataT<EmptyData> &After,
-                                      Any IR) {
+                                      const IRDataT<EmptyData> &After, Any IR) {
   SmallString<20> Banner =
       formatv("*** IR Dump After {0} on {1} ***\n", PassID, Name);
   Out << Banner;
@@ -2122,6 +2188,11 @@ DCData::DCData(const BasicBlock &B) {
       addSuccessorLabel(Succ->getName().str(), "");
 }
 
+DCData::DCData(const MachineBasicBlock &B) {
+  for (const MachineBasicBlock *Succ : successors(&B))
+    addSuccessorLabel(Succ->getName().str(), "");
+}
+
 DotCfgChangeReporter::DotCfgChangeReporter(bool Verbose)
     : ChangeReporter<IRDataT<DCData>>(Verbose) {}
 
@@ -2188,7 +2259,7 @@ std::string DotCfgChangeReporter::genHTML(StringRef Text, StringRef DotFile,
 
 void DotCfgChangeReporter::handleInitialIR(Any IR) {
   assert(HTML && "Expected outstream to be set");
-  *HTML << "<button type=\"button\" class=\"collapsible\">0. "
+  *HTML << "<button type=\"button\" class=\"collapsible\">" << N << ". "
         << "Initial IR (by function)</button>\n"
         << "<div class=\"content\">\n"
         << "  <p>\n";
@@ -2329,7 +2400,7 @@ DotCfgChangeReporter::~DotCfgChangeReporter() {
 void DotCfgChangeReporter::registerCallbacks(
     PassInstrumentationCallbacks &PIC) {
   if (PrintChanged == ChangePrinter::DotCfgVerbose ||
-       PrintChanged == ChangePrinter::DotCfgQuiet) {
+      PrintChanged == ChangePrinter::DotCfgQuiet) {
     SmallString<128> OutputDir;
     sys::fs::expand_tilde(DotCfgDir, OutputDir);
     sys::fs::make_absolute(OutputDir);
@@ -2346,8 +2417,7 @@ void DotCfgChangeReporter::registerCallbacks(
 StandardInstrumentations::StandardInstrumentations(
     LLVMContext &Context, bool DebugLogging, bool VerifyEach,
     PrintPassOptions PrintPassOpts)
-    : PrintPass(DebugLogging, PrintPassOpts),
-      OptNone(DebugLogging),
+    : PrintPass(DebugLogging, PrintPassOpts), OptNone(DebugLogging),
       OptPassGate(Context),
       PrintChangedIR(PrintChanged == ChangePrinter::Verbose),
       PrintChangedDiff(PrintChanged == ChangePrinter::DiffVerbose ||
diff --git a/llvm/test/Other/ChangePrinters/DotCfg/print-changed-dot-cfg.mir b/llvm/test/Other/ChangePrinters/DotCfg/print-changed-dot-cfg.mir
new file mode 100644
index 000000000000000..340ece93aa02bbf
--- /dev/null
+++ b/llvm/test/Other/ChangePrinters/DotCfg/print-changed-dot-cfg.mir
@@ -0,0 +1,24 @@
+# REQUIRES: x86-registered-target
+# Simple functionality check.
+# RUN: rm -rf %t && mkdir -p %t
+# RUN: llc -filetype=null -print-changed=dot-cfg -passes=no-op-machine-function -dot-cfg-dir=%t %s
+# RUN: ls %t/*.pdf %t/passes.html | count 3
+
+---
+name:            g
+body:             |
+  bb.0.entry:
+    %0:gr32 = MOV32ri 5
+    $eax = COPY %0
+    RET 0, $eax
+
+...
+---
+name:            f
+body:             |
+  bb.0.entry:
+    %0:gr32 = MOV32ri 7
+    $eax = COPY %0
+    RET 0, $eax
+
+...
diff --git a/llvm/test/Other/change-printer.mir b/llvm/test/Other/change-printer.mir
new file mode 100644
index 000000000000000..5e57da50e625dc0
--- /dev/null
+++ b/llvm/test/Other/change-printer.mir
@@ -0,0 +1,21 @@
+# REQUIRES: x86-registered-target
+# RUN: llc -mtriple=x86_64-unknown-linux-gnu -filetype=null %s \
+# RUN: -p no-op-machine-function -print-changed 2>&1 | FileCheck %s --check-prefix=CHECK-NO-OP
+
+# RUN: llc -mtriple=x86_64-unknown-linux-gnu -filetype=null %s \
+# RUN: -p dead-mi-elimination -print-changed 2>&1 | FileCheck %s --check-prefix=CHECK-SIMPLE
+
+---
+name:            test
+body:             |
+  bb.0:
+    %1:gr64 = MOV64ri 0
+    %2:gr64 = MOV64ri 0
+    $eax = COPY %1
+    RET64 implicit $eax
+...
+
+# CHECK-NO-OP: *** IR Dump After NoOpMachineFunctionPass on test omitted because no change ***
+
+# CHECK-SIMPLE: *** IR Dump After DeadMachineInstructionElimPass on test ***
+# CHECK-SIMPLE-NOT: %2:gr64 = MOV64ri 0



More information about the llvm-commits mailing list