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 --- /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 --- /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 --- a/llvm/tools/llvm-reduce/CMakeLists.txt +++ b/llvm/tools/llvm-reduce/CMakeLists.txt @@ -5,6 +5,7 @@ AllTargetsInfos Core IRReader + MIRParser Support Target TransformUtils @@ -12,6 +13,7 @@ add_llvm_tool(llvm-reduce DeltaManager.cpp + ReducerWorkItem.cpp TestRunner.cpp deltas/Delta.cpp deltas/ReduceAliases.cpp @@ -30,6 +32,7 @@ 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 --- 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 @@ 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 @@ 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 @@ 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.h b/llvm/tools/llvm-reduce/ReducerWorkItem.h new file mode 100644 --- /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 M; + std::unique_ptr 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 parseReducerWorkItem(StringRef Filename, + LLVMContext &Ctxt, + MachineModuleInfo *MMI); + +std::unique_ptr +cloneReducerWorkItem(const ReducerWorkItem &MMM); + +bool verifyReducerWorkItem(const ReducerWorkItem &MMM, raw_fd_ostream *OS); + +#endif diff --git a/llvm/tools/llvm-reduce/ReducerWorkItem.cpp b/llvm/tools/llvm-reduce/ReducerWorkItem.cpp new file mode 100644 --- /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 cloneMF(MachineFunction *SrcMF) { + auto DstMF = std::make_unique( + SrcMF->getFunction(), SrcMF->getTarget(), SrcMF->getSubtarget(), + SrcMF->getFunctionNumber(), SrcMF->getMMI()); + DenseMap Src2DstMBB; + DenseMap 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 parseReducerWorkItem(StringRef Filename, + LLVMContext &Ctxt, + MachineModuleInfo *MMI) { + auto MMM = std::make_unique(); + if (MMI) { + auto FileOrErr = MemoryBuffer::getFileOrSTDIN(Filename, /*IsText=*/true); + std::unique_ptr MParser = + createMIRParser(std::move(FileOrErr.get()), Ctxt); + + auto SetDataLayout = + [&](StringRef DataLayoutTargetTriple) -> Optional { + return MMI->getTarget().createDataLayout().getStringRepresentation(); + }; + + std::unique_ptr 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 Result = parseIRFile(Filename, Err, Ctxt); + if (!Result) { + Err.print("llvm-reduce", errs()); + return std::unique_ptr(); + } + MMM->M = std::move(Result); + } + if (verifyReducerWorkItem(*MMM, &errs())) { + errs() << "Error: " << Filename << " - input module is broken!\n"; + return std::unique_ptr(); + } + return MMM; +} + +std::unique_ptr +cloneReducerWorkItem(const ReducerWorkItem &MMM) { + auto CloneMMM = std::make_unique(); + 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 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/TestRunner.h b/llvm/tools/llvm-reduce/TestRunner.h --- 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 @@ class TestRunner { public: TestRunner(StringRef TestName, const std::vector &TestArgs, - std::unique_ptr Program); + std::unique_ptr 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 P) { + void setProgram(std::unique_ptr P) { assert(P && "Setting null program?"); Program = std::move(P); } @@ -42,7 +43,7 @@ private: StringRef TestName; const std::vector &TestArgs; - std::unique_ptr Program; + std::unique_ptr Program; }; } // namespace llvm diff --git a/llvm/tools/llvm-reduce/TestRunner.cpp b/llvm/tools/llvm-reduce/TestRunner.cpp --- a/llvm/tools/llvm-reduce/TestRunner.cpp +++ b/llvm/tools/llvm-reduce/TestRunner.cpp @@ -12,7 +12,7 @@ TestRunner::TestRunner(StringRef TestName, const std::vector &TestArgs, - std::unique_ptr Program) + std::unique_ptr Program) : TestName(TestName), TestArgs(TestArgs), Program(std::move(Program)) { assert(this->Program && "Initialized with null program?"); } diff --git a/llvm/tools/llvm-reduce/deltas/Delta.h b/llvm/tools/llvm-reduce/deltas/Delta.h --- a/llvm/tools/llvm-reduce/deltas/Delta.h +++ b/llvm/tools/llvm-reduce/deltas/Delta.h @@ -104,6 +104,9 @@ void runDeltaPass( TestRunner &Test, int Targets, function_ref ExtractChunksFromModule); +void runDeltaPass( + TestRunner &Test, int Targets, + function_ref ExtractChunksFromModule); } // namespace llvm #endif diff --git a/llvm/tools/llvm-reduce/deltas/Delta.cpp b/llvm/tools/llvm-reduce/deltas/Delta.cpp --- 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 #include @@ -27,13 +27,14 @@ "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 @@ /// 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 +void runDeltaPassInt( TestRunner &Test, int Targets, - function_ref ExtractChunksFromModule) { + function_ref ExtractChunksFromModule) { assert(Targets >= 0); if (!Targets) { errs() << "\nNothing to reduce\n"; @@ -110,11 +112,11 @@ exit(1); } - assert(!verifyModule(Test.getProgram(), &errs()) && + assert(!verifyReducerWorkItem(Test.getProgram(), &errs()) && "input module is broken before making changes"); std::vector ChunksStillConsideredInteresting = {{1, Targets}}; - std::unique_ptr ReducedProgram; + std::unique_ptr ReducedProgram; bool FoundAtLeastOneNewUninterestingChunkWithCurrentGranularity; do { @@ -137,13 +139,14 @@ }); // Clone module before hacking it up.. - std::unique_ptr Clone = CloneModule(Test.getProgram()); + std::unique_ptr 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 @@ Test.setProgram(std::move(ReducedProgram)); errs() << "Couldn't increase anymore.\n"; } + +void llvm::runDeltaPass( + TestRunner &Test, int Targets, + function_ref ExtractChunksFromModule) { + runDeltaPassInt(Test, Targets, ExtractChunksFromModule); +} + +void llvm::runDeltaPass( + TestRunner &Test, int Targets, + function_ref ExtractChunksFromModule) { + runDeltaPassInt(Test, Targets, ExtractChunksFromModule); +} diff --git a/llvm/tools/llvm-reduce/deltas/ReduceInstructionsMIR.h b/llvm/tools/llvm-reduce/deltas/ReduceInstructionsMIR.h new file mode 100644 --- /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/deltas/ReduceInstructionsMIR.cpp b/llvm/tools/llvm-reduce/deltas/ReduceInstructionsMIR.cpp new file mode 100644 --- /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 &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 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/llvm-reduce.cpp b/llvm/tools/llvm-reduce/llvm-reduce.cpp --- 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 #include @@ -39,7 +45,8 @@ static cl::opt 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 InputFilename(cl::Positional, cl::Required, cl::desc(""), @@ -55,9 +62,8 @@ cl::desc("Arguments passed onto the interesting-ness test"), cl::cat(Options)); -static cl::opt - OutputFilename("output", - cl::desc("Specify the output file. default: reduced.ll")); +static cl::opt 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 @@ "with the reduced version!"), cl::cat(Options)); -// Parses IR into a Module and verifies it -static std::unique_ptr parseInputFile(StringRef Filename, - LLVMContext &Ctxt) { - SMDiagnostic Err; - std::unique_ptr 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(); - } +static cl::opt + 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 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 @@ errs() << Message << OutputFilename << "\n"; } +static std::unique_ptr 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( + static_cast(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 OriginalProgram = - parseInputFile(InputFilename, Context); - + std::unique_ptr TM; + std::unique_ptr MMI; + std::unique_ptr OriginalProgram; + if (ReduceModeMIR) { + TM = createTargetMachine(); + MMI = std::make_unique(TM.get()); + } + OriginalProgram = parseReducerWorkItem(InputFilename, Context, MMI.get()); if (!OriginalProgram) { return 1; }