[llvm] bc2773c - [llvm-reduce] Add MIR support

Markus Lavin via llvm-commits llvm-commits at lists.llvm.org
Tue Nov 2 01:24:22 PDT 2021


Author: Markus Lavin
Date: 2021-11-02T09:14:56+01:00
New Revision: bc2773cb1bdfacfda773eb492e7b0cc65a78cda6

URL: https://github.com/llvm/llvm-project/commit/bc2773cb1bdfacfda773eb492e7b0cc65a78cda6
DIFF: https://github.com/llvm/llvm-project/commit/bc2773cb1bdfacfda773eb492e7b0cc65a78cda6.diff

LOG: [llvm-reduce] Add MIR support

The llvm-reduce tool has been extended to operate on MIR (import, clone and
export). Current limitation is that only a single machine function is
supported. A single reducer pass that operates on machine instructions (while
on SSA-form) has been added. Additional MIR specific reducer passes can be
added later as needed.

Differential Revision: https://reviews.llvm.org/D110527

Added: 
    llvm/test/tools/llvm-reduce/mir/instr-reduce.mir
    llvm/test/tools/llvm-reduce/mir/instr-reduce.py
    llvm/tools/llvm-reduce/ReducerWorkItem.cpp
    llvm/tools/llvm-reduce/ReducerWorkItem.h
    llvm/tools/llvm-reduce/deltas/ReduceInstructionsMIR.cpp
    llvm/tools/llvm-reduce/deltas/ReduceInstructionsMIR.h

Modified: 
    llvm/tools/llvm-reduce/CMakeLists.txt
    llvm/tools/llvm-reduce/DeltaManager.cpp
    llvm/tools/llvm-reduce/TestRunner.cpp
    llvm/tools/llvm-reduce/TestRunner.h
    llvm/tools/llvm-reduce/deltas/Delta.cpp
    llvm/tools/llvm-reduce/deltas/Delta.h
    llvm/tools/llvm-reduce/llvm-reduce.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/test/tools/llvm-reduce/mir/instr-reduce.mir b/llvm/test/tools/llvm-reduce/mir/instr-reduce.mir
new file mode 100644
index 000000000000..f252ff3d5699
--- /dev/null
+++ b/llvm/test/tools/llvm-reduce/mir/instr-reduce.mir
@@ -0,0 +1,30 @@
+# RUN: llvm-reduce -mtriple=riscv32 --test %python --test-arg %p/instr-reduce.py %s -o %t
+# RUN: cat %t | FileCheck --match-full-lines %s
+
+# REQUIRES: riscv-registered-target
+
+# Verify that after reduction the following instruction sequence remains. The
+# interestingness-test 'instr-reduce.py' matches a '%[0-9]+:gpr = ADDI %[0-9]+, 5'
+# pattern in the output and that combined with that the MIR has to be valid
+# (pass verify) results in the given sequence.
+
+# CHECK:      %0:gpr = COPY $x10
+# CHECK-NEXT: %2:gpr = ADDI %0, 5
+# CHECK-NEXT: PseudoRET implicit $x10
+
+...
+---
+name:            f
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $x10
+
+    %10:gpr = COPY $x10
+    %20:gpr = ADDI %10, 1
+    %30:gpr = ADDI %20, 5
+    %40:gpr = ADDI %30, 9
+    $x10 = COPY %40
+    PseudoRET implicit $x10
+...
+---

diff  --git a/llvm/test/tools/llvm-reduce/mir/instr-reduce.py b/llvm/test/tools/llvm-reduce/mir/instr-reduce.py
new file mode 100755
index 000000000000..75e2cc54bbcf
--- /dev/null
+++ b/llvm/test/tools/llvm-reduce/mir/instr-reduce.py
@@ -0,0 +1,16 @@
+from subprocess import run, PIPE
+import re
+import sys
+
+llc = run( [ 'llc', '-disable-symbolication','-verify-machineinstrs', '-mtriple=riscv32', '-run-pass=none', '-o', '-', sys.argv[1]], stdout=PIPE, stderr=PIPE )
+
+stdout = llc.stdout.decode()
+
+p = re.compile(r'^\s*%[0-9]+:gpr = ADDI %[0-9]+, 5$', flags=re.MULTILINE)
+
+if (llc.returncode == 0 and p.search(stdout)):
+  print('This is interesting!')
+  sys.exit(0)
+else:
+  print('This is NOT interesting!')
+  sys.exit(1)

diff  --git a/llvm/tools/llvm-reduce/CMakeLists.txt b/llvm/tools/llvm-reduce/CMakeLists.txt
index eb842fccddaf..64f04f50c1fb 100644
--- a/llvm/tools/llvm-reduce/CMakeLists.txt
+++ b/llvm/tools/llvm-reduce/CMakeLists.txt
@@ -5,6 +5,7 @@ set(LLVM_LINK_COMPONENTS
   AllTargetsInfos
   Core
   IRReader
+  MIRParser
   Support
   Target
   TransformUtils
@@ -12,6 +13,7 @@ set(LLVM_LINK_COMPONENTS
 
 add_llvm_tool(llvm-reduce
   DeltaManager.cpp
+  ReducerWorkItem.cpp
   TestRunner.cpp
   deltas/Delta.cpp
   deltas/ReduceAliases.cpp
@@ -30,6 +32,7 @@ add_llvm_tool(llvm-reduce
   deltas/ReduceSpecialGlobals.cpp
   deltas/ReduceOperands.cpp
   deltas/ReduceOperandsToArgs.cpp
+  deltas/ReduceInstructionsMIR.cpp
   llvm-reduce.cpp
 
   DEPENDS

diff  --git a/llvm/tools/llvm-reduce/DeltaManager.cpp b/llvm/tools/llvm-reduce/DeltaManager.cpp
index dab404094629..8dd16b046cb0 100644
--- a/llvm/tools/llvm-reduce/DeltaManager.cpp
+++ b/llvm/tools/llvm-reduce/DeltaManager.cpp
@@ -24,6 +24,7 @@
 #include "deltas/ReduceGlobalVarInitializers.h"
 #include "deltas/ReduceGlobalVars.h"
 #include "deltas/ReduceInstructions.h"
+#include "deltas/ReduceInstructionsMIR.h"
 #include "deltas/ReduceMetadata.h"
 #include "deltas/ReduceModuleData.h"
 #include "deltas/ReduceOperandBundles.h"
@@ -59,9 +60,16 @@ static cl::opt<std::string>
   DELTA_PASS("attributes", reduceAttributesDeltaPass)                          \
   DELTA_PASS("module-data", reduceModuleDataDeltaPass)
 
+#define DELTA_PASSES_MIR                                                       \
+  DELTA_PASS("instructions", reduceInstructionsMIRDeltaPass)
+
 static void runAllDeltaPasses(TestRunner &Tester) {
 #define DELTA_PASS(NAME, FUNC) FUNC(Tester);
-  DELTA_PASSES
+  if (Tester.getProgram().isMIR()) {
+    DELTA_PASSES_MIR
+  } else {
+    DELTA_PASSES
+  }
 #undef DELTA_PASS
 }
 
@@ -71,7 +79,11 @@ static void runDeltaPassName(TestRunner &Tester, StringRef PassName) {
     FUNC(Tester);                                                              \
     return;                                                                    \
   }
-  DELTA_PASSES
+  if (Tester.getProgram().isMIR()) {
+    DELTA_PASSES_MIR
+  } else {
+    DELTA_PASSES
+  }
 #undef DELTA_PASS
   errs() << "unknown pass \"" << PassName << "\"";
   exit(1);
@@ -80,7 +92,10 @@ static void runDeltaPassName(TestRunner &Tester, StringRef PassName) {
 void llvm::printDeltaPasses(raw_ostream &OS) {
   OS << "Delta passes (pass to `--delta-passes=` as a comma separated list):\n";
 #define DELTA_PASS(NAME, FUNC) OS << "  " << NAME << "\n";
+  OS << " IR:\n";
   DELTA_PASSES
+  OS << " MIR:\n";
+  DELTA_PASSES_MIR
 #undef DELTA_PASS
 }
 

diff  --git a/llvm/tools/llvm-reduce/ReducerWorkItem.cpp b/llvm/tools/llvm-reduce/ReducerWorkItem.cpp
new file mode 100644
index 000000000000..e3845e8b897a
--- /dev/null
+++ b/llvm/tools/llvm-reduce/ReducerWorkItem.cpp
@@ -0,0 +1,174 @@
+//===- ReducerWorkItem.cpp - Wrapper for Module and MachineFunction -------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ReducerWorkItem.h"
+#include "llvm/CodeGen/MIRParser/MIRParser.h"
+#include "llvm/CodeGen/MIRPrinter.h"
+#include "llvm/CodeGen/MachineDominators.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/TargetInstrInfo.h"
+#include "llvm/IR/Verifier.h"
+#include "llvm/IRReader/IRReader.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Transforms/Utils/Cloning.h"
+
+static std::unique_ptr<MachineFunction> cloneMF(MachineFunction *SrcMF) {
+  auto DstMF = std::make_unique<MachineFunction>(
+      SrcMF->getFunction(), SrcMF->getTarget(), SrcMF->getSubtarget(),
+      SrcMF->getFunctionNumber(), SrcMF->getMMI());
+  DenseMap<MachineBasicBlock *, MachineBasicBlock *> Src2DstMBB;
+  DenseMap<Register, Register> Src2DstReg;
+
+  auto *SrcMRI = &SrcMF->getRegInfo();
+  auto *DstMRI = &DstMF->getRegInfo();
+
+  // Create vregs.
+  for (auto &SrcMBB : *SrcMF) {
+    for (auto &SrcMI : SrcMBB) {
+      for (unsigned I = 0, E = SrcMI.getNumOperands(); I < E; ++I) {
+        auto &DMO = SrcMI.getOperand(I);
+        if (!DMO.isReg() || !DMO.isDef())
+          continue;
+        Register SrcReg = DMO.getReg();
+        if (Register::isPhysicalRegister(SrcReg))
+          continue;
+        auto SrcRC = SrcMRI->getRegClass(SrcReg);
+        auto DstReg = DstMRI->createVirtualRegister(SrcRC);
+        Src2DstReg[SrcReg] = DstReg;
+      }
+    }
+  }
+
+  // Clone blocks.
+  for (auto &SrcMBB : *SrcMF)
+    Src2DstMBB[&SrcMBB] = DstMF->CreateMachineBasicBlock();
+  // Link blocks.
+  for (auto &SrcMBB : *SrcMF) {
+    auto *DstMBB = Src2DstMBB[&SrcMBB];
+    DstMF->push_back(DstMBB);
+    for (auto It = SrcMBB.succ_begin(), IterEnd = SrcMBB.succ_end();
+         It != IterEnd; ++It) {
+      auto *SrcSuccMBB = *It;
+      auto *DstSuccMBB = Src2DstMBB[SrcSuccMBB];
+      DstMBB->addSuccessor(DstSuccMBB);
+    }
+    for (auto &LI : SrcMBB.liveins())
+      DstMBB->addLiveIn(LI);
+  }
+  // Clone instructions.
+  for (auto &SrcMBB : *SrcMF) {
+    auto *DstMBB = Src2DstMBB[&SrcMBB];
+    for (auto &SrcMI : SrcMBB) {
+      const auto &MCID =
+          DstMF->getSubtarget().getInstrInfo()->get(SrcMI.getOpcode());
+      auto *DstMI = DstMF->CreateMachineInstr(MCID, SrcMI.getDebugLoc(),
+                                              /*NoImplicit=*/true);
+      DstMBB->push_back(DstMI);
+      for (auto &SrcMO : SrcMI.operands()) {
+        MachineOperand DstMO(SrcMO);
+        DstMO.clearParent();
+        // Update vreg.
+        if (DstMO.isReg() && Src2DstReg.count(DstMO.getReg())) {
+          DstMO.setReg(Src2DstReg[DstMO.getReg()]);
+        }
+        // Update MBB.
+        if (DstMO.isMBB()) {
+          DstMO.setMBB(Src2DstMBB[DstMO.getMBB()]);
+        }
+        DstMI->addOperand(DstMO);
+      }
+      DstMI->setMemRefs(*DstMF, SrcMI.memoperands());
+    }
+  }
+
+  DstMF->verify(nullptr, "", /*AbortOnErrors=*/true);
+  return DstMF;
+}
+
+std::unique_ptr<ReducerWorkItem> parseReducerWorkItem(StringRef Filename,
+                                                      LLVMContext &Ctxt,
+                                                      MachineModuleInfo *MMI) {
+  auto MMM = std::make_unique<ReducerWorkItem>();
+  if (MMI) {
+    auto FileOrErr = MemoryBuffer::getFileOrSTDIN(Filename, /*IsText=*/true);
+    std::unique_ptr<MIRParser> MParser =
+        createMIRParser(std::move(FileOrErr.get()), Ctxt);
+
+    auto SetDataLayout =
+        [&](StringRef DataLayoutTargetTriple) -> Optional<std::string> {
+      return MMI->getTarget().createDataLayout().getStringRepresentation();
+    };
+
+    std::unique_ptr<Module> M = MParser->parseIRModule(SetDataLayout);
+    MParser->parseMachineFunctions(*M, *MMI);
+    MachineFunction *MF = nullptr;
+    for (auto &F : *M) {
+      if (auto *MF4F = MMI->getMachineFunction(F)) {
+        // XXX: Maybe it would not be a lot of effort to handle multiple MFs by
+        // simply storing them in a ReducerWorkItem::SmallVector or similar. The
+        // single MF use-case seems a lot more common though so that will do for
+        // now.
+        assert(!MF && "Only single MF supported!");
+        MF = MF4F;
+      }
+    }
+    assert(MF && "No MF found!");
+
+    MMM->M = std::move(M);
+    MMM->MF = cloneMF(MF);
+  } else {
+    SMDiagnostic Err;
+    std::unique_ptr<Module> Result = parseIRFile(Filename, Err, Ctxt);
+    if (!Result) {
+      Err.print("llvm-reduce", errs());
+      return std::unique_ptr<ReducerWorkItem>();
+    }
+    MMM->M = std::move(Result);
+  }
+  if (verifyReducerWorkItem(*MMM, &errs())) {
+    errs() << "Error: " << Filename << " - input module is broken!\n";
+    return std::unique_ptr<ReducerWorkItem>();
+  }
+  return MMM;
+}
+
+std::unique_ptr<ReducerWorkItem>
+cloneReducerWorkItem(const ReducerWorkItem &MMM) {
+  auto CloneMMM = std::make_unique<ReducerWorkItem>();
+  if (MMM.MF) {
+    // Note that we cannot clone the Module as then we would need a way to
+    // updated the cloned MachineFunction's IR references.
+    // XXX: Actually have a look at
+    // std::unique_ptr<Module> CloneModule(const Module &M, ValueToValueMapTy
+    // &VMap);
+    CloneMMM->M = MMM.M;
+    CloneMMM->MF = cloneMF(MMM.MF.get());
+  } else {
+    CloneMMM->M = CloneModule(*MMM.M);
+  }
+  return CloneMMM;
+}
+
+bool verifyReducerWorkItem(const ReducerWorkItem &MMM, raw_fd_ostream *OS) {
+  if (verifyModule(*MMM.M, OS))
+    return true;
+  if (MMM.MF && !MMM.MF->verify(nullptr, "", /*AbortOnErrors=*/false))
+    return true;
+  return false;
+}
+
+void ReducerWorkItem::print(raw_ostream &ROS, void *p) const {
+  if (MF) {
+    printMIR(ROS, *M);
+    printMIR(ROS, *MF);
+  } else {
+    M->print(ROS, nullptr);
+  }
+}

diff  --git a/llvm/tools/llvm-reduce/ReducerWorkItem.h b/llvm/tools/llvm-reduce/ReducerWorkItem.h
new file mode 100644
index 000000000000..a86e158d916f
--- /dev/null
+++ b/llvm/tools/llvm-reduce/ReducerWorkItem.h
@@ -0,0 +1,37 @@
+//===- ReducerWorkItem.h - Wrapper for Module and MachineFunction ---------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVM_REDUCE_REDUCERWORKITEM_H
+#define LLVM_TOOLS_LLVM_REDUCE_REDUCERWORKITEM_H
+
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineModuleInfo.h"
+#include "llvm/IR/Module.h"
+
+using namespace llvm;
+
+class ReducerWorkItem {
+public:
+  std::shared_ptr<Module> M;
+  std::unique_ptr<MachineFunction> MF;
+  void print(raw_ostream &ROS, void *p = nullptr) const;
+  bool isMIR() { return MF != nullptr; }
+  operator Module &() const { return *M; }
+  operator MachineFunction &() const { return *MF; }
+};
+
+std::unique_ptr<ReducerWorkItem> parseReducerWorkItem(StringRef Filename,
+                                                      LLVMContext &Ctxt,
+                                                      MachineModuleInfo *MMI);
+
+std::unique_ptr<ReducerWorkItem>
+cloneReducerWorkItem(const ReducerWorkItem &MMM);
+
+bool verifyReducerWorkItem(const ReducerWorkItem &MMM, raw_fd_ostream *OS);
+
+#endif

diff  --git a/llvm/tools/llvm-reduce/TestRunner.cpp b/llvm/tools/llvm-reduce/TestRunner.cpp
index a3cd717ccd98..e8c12138936f 100644
--- a/llvm/tools/llvm-reduce/TestRunner.cpp
+++ b/llvm/tools/llvm-reduce/TestRunner.cpp
@@ -12,7 +12,7 @@ using namespace llvm;
 
 TestRunner::TestRunner(StringRef TestName,
                        const std::vector<std::string> &TestArgs,
-                       std::unique_ptr<Module> Program)
+                       std::unique_ptr<ReducerWorkItem> Program)
     : TestName(TestName), TestArgs(TestArgs), Program(std::move(Program)) {
   assert(this->Program && "Initialized with null program?");
 }

diff  --git a/llvm/tools/llvm-reduce/TestRunner.h b/llvm/tools/llvm-reduce/TestRunner.h
index 6edc1a1192fa..c14d0459a0fb 100644
--- a/llvm/tools/llvm-reduce/TestRunner.h
+++ b/llvm/tools/llvm-reduce/TestRunner.h
@@ -9,6 +9,7 @@
 #ifndef LLVM_TOOLS_LLVM_REDUCE_TESTRUNNER_H
 #define LLVM_TOOLS_LLVM_REDUCE_TESTRUNNER_H
 
+#include "ReducerWorkItem.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/IR/Module.h"
 #include "llvm/Support/Error.h"
@@ -25,16 +26,16 @@ namespace llvm {
 class TestRunner {
 public:
   TestRunner(StringRef TestName, const std::vector<std::string> &TestArgs,
-             std::unique_ptr<Module> Program);
+             std::unique_ptr<ReducerWorkItem> Program);
 
   /// Runs the interesting-ness test for the specified file
   /// @returns 0 if test was successful, 1 if otherwise
   int run(StringRef Filename);
 
   /// Returns the most reduced version of the original testcase
-  Module &getProgram() const { return *Program; }
+  ReducerWorkItem &getProgram() const { return *Program; }
 
-  void setProgram(std::unique_ptr<Module> P) {
+  void setProgram(std::unique_ptr<ReducerWorkItem> P) {
     assert(P && "Setting null program?");
     Program = std::move(P);
   }
@@ -42,7 +43,7 @@ class TestRunner {
 private:
   StringRef TestName;
   const std::vector<std::string> &TestArgs;
-  std::unique_ptr<Module> Program;
+  std::unique_ptr<ReducerWorkItem> Program;
 };
 
 } // namespace llvm

diff  --git a/llvm/tools/llvm-reduce/deltas/Delta.cpp b/llvm/tools/llvm-reduce/deltas/Delta.cpp
index f14b326c7e0b..cabbe9513e5d 100644
--- a/llvm/tools/llvm-reduce/deltas/Delta.cpp
+++ b/llvm/tools/llvm-reduce/deltas/Delta.cpp
@@ -13,11 +13,11 @@
 //===----------------------------------------------------------------------===//
 
 #include "Delta.h"
+#include "ReducerWorkItem.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/IR/Verifier.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/ToolOutputFile.h"
-#include "llvm/Transforms/Utils/Cloning.h"
 #include <fstream>
 #include <set>
 
@@ -27,13 +27,14 @@ static cl::opt<bool> AbortOnInvalidReduction(
     "abort-on-invalid-reduction",
     cl::desc("Abort if any reduction results in invalid IR"));
 
-void writeOutput(llvm::Module &M, llvm::StringRef Message);
+void writeOutput(ReducerWorkItem &M, llvm::StringRef Message);
 
-bool isReduced(Module &M, TestRunner &Test, SmallString<128> &CurrentFilepath) {
-  // Write Module to tmp file
+bool isReduced(ReducerWorkItem &M, TestRunner &Test,
+               SmallString<128> &CurrentFilepath) {
+  // Write ReducerWorkItem to tmp file
   int FD;
-  std::error_code EC =
-      sys::fs::createTemporaryFile("llvm-reduce", "ll", FD, CurrentFilepath);
+  std::error_code EC = sys::fs::createTemporaryFile(
+      "llvm-reduce", M.isMIR() ? "mir" : "ll", FD, CurrentFilepath);
   if (EC) {
     errs() << "Error making unique filename: " << EC.message() << "!\n";
     exit(1);
@@ -95,9 +96,10 @@ static bool increaseGranularity(std::vector<Chunk> &Chunks) {
 /// Runs the Delta Debugging algorithm, splits the code into chunks and
 /// reduces the amount of chunks that are considered interesting by the
 /// given test.
-void llvm::runDeltaPass(
+template <typename T>
+void runDeltaPassInt(
     TestRunner &Test, int Targets,
-    function_ref<void(Oracle &, Module &)> ExtractChunksFromModule) {
+    function_ref<void(Oracle &, T &)> ExtractChunksFromModule) {
   assert(Targets >= 0);
   if (!Targets) {
     errs() << "\nNothing to reduce\n";
@@ -110,11 +112,11 @@ void llvm::runDeltaPass(
     exit(1);
   }
 
-  assert(!verifyModule(Test.getProgram(), &errs()) &&
+  assert(!verifyReducerWorkItem(Test.getProgram(), &errs()) &&
          "input module is broken before making changes");
 
   std::vector<Chunk> ChunksStillConsideredInteresting = {{1, Targets}};
-  std::unique_ptr<Module> ReducedProgram;
+  std::unique_ptr<ReducerWorkItem> ReducedProgram;
 
   bool FoundAtLeastOneNewUninterestingChunkWithCurrentGranularity;
   do {
@@ -137,13 +139,14 @@ void llvm::runDeltaPass(
               });
 
       // Clone module before hacking it up..
-      std::unique_ptr<Module> Clone = CloneModule(Test.getProgram());
+      std::unique_ptr<ReducerWorkItem> Clone =
+          cloneReducerWorkItem(Test.getProgram());
       // Generate Module with only Targets inside Current Chunks
       Oracle O(CurrentChunks);
       ExtractChunksFromModule(O, *Clone);
 
       // Some reductions may result in invalid IR. Skip such reductions.
-      if (verifyModule(*Clone, &errs())) {
+      if (verifyReducerWorkItem(*Clone, &errs())) {
         if (AbortOnInvalidReduction) {
           errs() << "Invalid reduction\n";
           exit(1);
@@ -185,3 +188,15 @@ void llvm::runDeltaPass(
     Test.setProgram(std::move(ReducedProgram));
   errs() << "Couldn't increase anymore.\n";
 }
+
+void llvm::runDeltaPass(
+    TestRunner &Test, int Targets,
+    function_ref<void(Oracle &, Module &)> ExtractChunksFromModule) {
+  runDeltaPassInt<Module>(Test, Targets, ExtractChunksFromModule);
+}
+
+void llvm::runDeltaPass(
+    TestRunner &Test, int Targets,
+    function_ref<void(Oracle &, MachineFunction &)> ExtractChunksFromModule) {
+  runDeltaPassInt<MachineFunction>(Test, Targets, ExtractChunksFromModule);
+}

diff  --git a/llvm/tools/llvm-reduce/deltas/Delta.h b/llvm/tools/llvm-reduce/deltas/Delta.h
index 8ebfc9aca4d9..00829ea1ae81 100644
--- a/llvm/tools/llvm-reduce/deltas/Delta.h
+++ b/llvm/tools/llvm-reduce/deltas/Delta.h
@@ -104,6 +104,9 @@ class Oracle {
 void runDeltaPass(
     TestRunner &Test, int Targets,
     function_ref<void(Oracle &, Module &)> ExtractChunksFromModule);
+void runDeltaPass(
+    TestRunner &Test, int Targets,
+    function_ref<void(Oracle &, MachineFunction &)> ExtractChunksFromModule);
 } // namespace llvm
 
 #endif

diff  --git a/llvm/tools/llvm-reduce/deltas/ReduceInstructionsMIR.cpp b/llvm/tools/llvm-reduce/deltas/ReduceInstructionsMIR.cpp
new file mode 100644
index 000000000000..4998de02811f
--- /dev/null
+++ b/llvm/tools/llvm-reduce/deltas/ReduceInstructionsMIR.cpp
@@ -0,0 +1,143 @@
+//===- ReduceInstructionsMIR.cpp - Specialized Delta Pass -----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a function which calls the Generic Delta pass in order
+// to reduce uninteresting MachineInstr from the MachineFunction.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ReduceInstructionsMIR.h"
+
+#include "llvm/CodeGen/MachineDominators.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/TargetInstrInfo.h"
+
+using namespace llvm;
+
+static Register getPrevDefOfRCInMBB(MachineBasicBlock &MBB,
+                                    MachineBasicBlock::reverse_iterator &RI,
+                                    const TargetRegisterClass *RC,
+                                    SetVector<MachineInstr *> &ExcludeMIs) {
+  auto MRI = &MBB.getParent()->getRegInfo();
+  for (MachineBasicBlock::reverse_instr_iterator E = MBB.instr_rend(); RI != E;
+       ++RI) {
+    auto &MI = *RI;
+    // All Def operands explicit and implicit.
+    for (auto &MO : MI.operands()) {
+      if (!MO.isReg() || !MO.isDef())
+        continue;
+      auto Reg = MO.getReg();
+      if (Register::isPhysicalRegister(Reg))
+        continue;
+
+      if (MRI->getRegClass(Reg) == RC && !ExcludeMIs.count(MO.getParent()))
+        return Reg;
+    }
+  }
+  return 0;
+}
+
+static unsigned countInstructions(MachineFunction &MF) {
+  unsigned Count = 0;
+  MachineInstr *TopMI = nullptr;
+  for (auto &MBB : MF) {
+    for (auto &MI : MBB) {
+      if (MI.isTerminator())
+        continue;
+      if (MBB.isEntryBlock() && !TopMI) {
+        TopMI = &MI;
+        continue;
+      }
+      Count++;
+    }
+  }
+  return Count;
+}
+
+static void extractInstrFromModule(Oracle &O, MachineFunction &MF) {
+  MachineDominatorTree MDT;
+  MDT.runOnMachineFunction(MF);
+
+  auto MRI = &MF.getRegInfo();
+  SetVector<MachineInstr *> ToDelete;
+
+  MachineInstr *TopMI = nullptr;
+
+  // Mark MIs for deletion according to some criteria.
+  for (auto &MBB : MF) {
+    for (auto &MI : MBB) {
+      if (MI.isTerminator())
+        continue;
+      if (MBB.isEntryBlock() && !TopMI) {
+        TopMI = &MI;
+        continue;
+      }
+      if (!O.shouldKeep())
+        ToDelete.insert(&MI);
+    }
+  }
+
+  // For each MI to be deleted update users of regs defined by that MI to use
+  // some other dominating definition (that is not to be deleted).
+  for (auto *MI : ToDelete) {
+    for (auto &MO : MI->operands()) {
+      if (!MO.isReg() || !MO.isDef())
+        continue;
+      auto Reg = MO.getReg();
+      if (Register::isPhysicalRegister(Reg))
+        continue;
+      auto UI = MRI->use_begin(Reg);
+      auto UE = MRI->use_end();
+
+      auto RegRC = MRI->getRegClass(Reg);
+      Register NewReg = 0;
+      // If this is not a physical register and there are some uses.
+      if (UI != UE) {
+        MachineBasicBlock::reverse_iterator RI(*MI);
+        MachineBasicBlock *BB = MI->getParent();
+        ++RI;
+        while (NewReg == 0 && BB) {
+          NewReg = getPrevDefOfRCInMBB(*BB, RI, RegRC, ToDelete);
+          // Prepare for idom(BB).
+          if (auto *IDM = MDT.getNode(BB)->getIDom()) {
+            BB = IDM->getBlock();
+            RI = BB->rbegin();
+          } else {
+            BB = nullptr;
+          }
+        }
+      }
+
+      // If no dominating definition was found then add an implicit one to the
+      // first instruction in the entry block.
+      if (!NewReg && TopMI) {
+        NewReg = MRI->createVirtualRegister(RegRC);
+        TopMI->addOperand(MachineOperand::CreateReg(
+            NewReg, true /*IsDef*/, true /*IsImp*/, false /*IsKill*/));
+      }
+
+      // Update all uses.
+      while (UI != UE) {
+        auto &UMO = *UI++;
+        UMO.setReg(NewReg);
+      }
+    }
+  }
+
+  // Finally delete the MIs.
+  for (auto *MI : ToDelete)
+    MI->eraseFromParent();
+}
+
+void llvm::reduceInstructionsMIRDeltaPass(TestRunner &Test) {
+  outs() << "*** Reducing Instructions...\n";
+  unsigned InstCount = countInstructions(Test.getProgram());
+  runDeltaPass(Test, InstCount, extractInstrFromModule);
+}

diff  --git a/llvm/tools/llvm-reduce/deltas/ReduceInstructionsMIR.h b/llvm/tools/llvm-reduce/deltas/ReduceInstructionsMIR.h
new file mode 100644
index 000000000000..564cf63a0a32
--- /dev/null
+++ b/llvm/tools/llvm-reduce/deltas/ReduceInstructionsMIR.h
@@ -0,0 +1,23 @@
+//===- ReduceInstructionsMIR.h  - Specialized Delta Pass ------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a function which calls the Generic Delta pass in order
+// to reduce uninteresting MachineInstr from the MachineFunction.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVM_REDUCE_DELTAS_REDUCEINSTRUCTIONS_MIR_H
+#define LLVM_TOOLS_LLVM_REDUCE_DELTAS_REDUCEINSTRUCTIONS_MIR_H
+
+#include "Delta.h"
+
+namespace llvm {
+void reduceInstructionsMIRDeltaPass(TestRunner &Test);
+} // namespace llvm
+
+#endif

diff  --git a/llvm/tools/llvm-reduce/llvm-reduce.cpp b/llvm/tools/llvm-reduce/llvm-reduce.cpp
index 90b7ed5f8272..11e3dd039499 100644
--- a/llvm/tools/llvm-reduce/llvm-reduce.cpp
+++ b/llvm/tools/llvm-reduce/llvm-reduce.cpp
@@ -15,15 +15,21 @@
 //===----------------------------------------------------------------------===//
 
 #include "DeltaManager.h"
+#include "ReducerWorkItem.h"
 #include "TestRunner.h"
 #include "llvm/ADT/SmallString.h"
+#include "llvm/CodeGen/CommandFlags.h"
 #include "llvm/IR/LLVMContext.h"
 #include "llvm/IR/Verifier.h"
 #include "llvm/IRReader/IRReader.h"
+#include "llvm/MC/TargetRegistry.h"
 #include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Host.h"
 #include "llvm/Support/InitLLVM.h"
 #include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/TargetSelect.h"
 #include "llvm/Support/raw_ostream.h"
+#include "llvm/Target/TargetMachine.h"
 #include <system_error>
 #include <vector>
 
@@ -39,7 +45,8 @@ static cl::opt<bool> Version("v", cl::desc("Alias for -version"), cl::Hidden,
 static cl::opt<bool>
     PrintDeltaPasses("print-delta-passes",
                      cl::desc("Print list of delta passes, passable to "
-                              "--delta-passes as a comma separated list"));
+                              "--delta-passes as a comma separated list"),
+                     cl::cat(Options));
 
 static cl::opt<std::string> InputFilename(cl::Positional, cl::Required,
                                           cl::desc("<input llvm ll/bc file>"),
@@ -55,9 +62,8 @@ static cl::list<std::string>
                   cl::desc("Arguments passed onto the interesting-ness test"),
                   cl::cat(Options));
 
-static cl::opt<std::string>
-    OutputFilename("output",
-                   cl::desc("Specify the output file. default: reduced.ll"));
+static cl::opt<std::string> OutputFilename(
+    "output", cl::desc("Specify the output file. default: reduced.ll|mir"));
 static cl::alias OutputFileAlias("o", cl::desc("Alias for -output"),
                                  cl::aliasopt(OutputFilename),
                                  cl::cat(Options));
@@ -68,30 +74,27 @@ static cl::opt<bool>
                           "with the reduced version!"),
                  cl::cat(Options));
 
-// Parses IR into a Module and verifies it
-static std::unique_ptr<Module> parseInputFile(StringRef Filename,
-                                              LLVMContext &Ctxt) {
-  SMDiagnostic Err;
-  std::unique_ptr<Module> Result = parseIRFile(Filename, Err, Ctxt);
-  if (!Result) {
-    Err.print("llvm-reduce", errs());
-    return Result;
-  }
+enum class InputLanguages { None, IR, MIR };
 
-  if (verifyModule(*Result, &errs())) {
-    errs() << "Error: " << Filename << " - input module is broken!\n";
-    return std::unique_ptr<Module>();
-  }
+static cl::opt<InputLanguages>
+    InputLanguage("x", cl::ValueOptional,
+                  cl::desc("Input language ('ir' or 'mir')"),
+                  cl::init(InputLanguages::None),
+                  cl::values(clEnumValN(InputLanguages::IR, "ir", ""),
+                             clEnumValN(InputLanguages::MIR, "mir", "")),
+                  cl::cat(Options));
 
-  return Result;
-}
+static cl::opt<std::string> TargetTriple("mtriple",
+                                         cl::desc("Set the target triple"),
+                                         cl::cat(Options));
+
+static codegen::RegisterCodeGenFlags CGF;
 
-void writeOutput(Module &M, StringRef Message) {
+void writeOutput(ReducerWorkItem &M, StringRef Message) {
   if (ReplaceInput) // In-place
     OutputFilename = InputFilename.c_str();
   else if (OutputFilename.empty() || OutputFilename == "-")
-    OutputFilename = "reduced.ll";
-
+    OutputFilename = M.isMIR() ? "reduced.mir" : "reduced.ll";
   std::error_code EC;
   raw_fd_ostream Out(OutputFilename, EC);
   if (EC) {
@@ -102,21 +105,54 @@ void writeOutput(Module &M, StringRef Message) {
   errs() << Message << OutputFilename << "\n";
 }
 
+static std::unique_ptr<LLVMTargetMachine> createTargetMachine() {
+  InitializeAllTargets();
+  InitializeAllTargetMCs();
+  InitializeAllAsmPrinters();
+  InitializeAllAsmParsers();
+
+  if (TargetTriple == "")
+    TargetTriple = sys::getDefaultTargetTriple();
+  auto TT(Triple::normalize(TargetTriple));
+  std::string CPU(codegen::getCPUStr());
+  std::string FS(codegen::getFeaturesStr());
+
+  std::string Error;
+  const Target *TheTarget = TargetRegistry::lookupTarget(TT, Error);
+
+  return std::unique_ptr<LLVMTargetMachine>(
+      static_cast<LLVMTargetMachine *>(TheTarget->createTargetMachine(
+          TT, CPU, FS, TargetOptions(), None, None, CodeGenOpt::Default)));
+}
+
 int main(int Argc, char **Argv) {
   InitLLVM X(Argc, Argv);
 
   cl::HideUnrelatedOptions({&Options, &getColorCategory()});
   cl::ParseCommandLineOptions(Argc, Argv, "LLVM automatic testcase reducer.\n");
 
+  bool ReduceModeMIR = false;
+  if (InputLanguage != InputLanguages::None) {
+    if (InputLanguage == InputLanguages::MIR)
+      ReduceModeMIR = true;
+  } else if (StringRef(InputFilename).endswith(".mir")) {
+    ReduceModeMIR = true;
+  }
+
   if (PrintDeltaPasses) {
     printDeltaPasses(errs());
     return 0;
   }
 
   LLVMContext Context;
-  std::unique_ptr<Module> OriginalProgram =
-      parseInputFile(InputFilename, Context);
-
+  std::unique_ptr<LLVMTargetMachine> TM;
+  std::unique_ptr<MachineModuleInfo> MMI;
+  std::unique_ptr<ReducerWorkItem> OriginalProgram;
+  if (ReduceModeMIR) {
+    TM = createTargetMachine();
+    MMI = std::make_unique<MachineModuleInfo>(TM.get());
+  }
+  OriginalProgram = parseReducerWorkItem(InputFilename, Context, MMI.get());
   if (!OriginalProgram) {
     return 1;
   }


        


More information about the llvm-commits mailing list