Index: llvm/test/tools/llvm-reduce/mir/instr-reduce.mir =================================================================== --- /dev/null +++ llvm/test/tools/llvm-reduce/mir/instr-reduce.mir @@ -0,0 +1,31 @@ +# RUN: llvm-reduce -mir -mtriple=riscv32 --test %python --test-arg %p/instr-reduce.py %s -o %t +# RUN: cat %t | FileCheck --match-full-lines %s + +# REQUIRES: plugins +# 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 +... +--- Index: llvm/test/tools/llvm-reduce/mir/instr-reduce.py =================================================================== --- /dev/null +++ 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) Index: llvm/tools/llvm-reduce/CMakeLists.txt =================================================================== --- llvm/tools/llvm-reduce/CMakeLists.txt +++ llvm/tools/llvm-reduce/CMakeLists.txt @@ -5,6 +5,7 @@ AllTargetsInfos Core IRReader + MIRParser Support Target TransformUtils @@ -29,6 +30,8 @@ deltas/ReduceOperandBundles.cpp deltas/ReduceSpecialGlobals.cpp deltas/ReduceOperands.cpp + deltas/ReduceInstructionsMIR.cpp + MyMachineModule.cpp llvm-reduce.cpp DEPENDS Index: llvm/tools/llvm-reduce/DeltaManager.cpp =================================================================== --- llvm/tools/llvm-reduce/DeltaManager.cpp +++ 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" @@ -37,6 +38,7 @@ DeltaPasses("delta-passes", cl::desc("Delta passes to run, separated by commas. By " "default, run all delta passes.")); +extern cl::opt EnableMIR; #define DELTA_PASSES \ DELTA_PASS("special-globals", reduceSpecialGlobalsDeltaPass) \ @@ -55,9 +57,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 (EnableMIR) { + DELTA_PASSES_MIR + } else { + DELTA_PASSES + } #undef DELTA_PASS } @@ -67,7 +76,11 @@ FUNC(Tester); \ return; \ } - DELTA_PASSES + if (EnableMIR) { + DELTA_PASSES_MIR + } else { + DELTA_PASSES + } #undef DELTA_PASS errs() << "unknown pass \"" << PassName << "\""; exit(1); @@ -76,7 +89,11 @@ 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"; - DELTA_PASSES + if (EnableMIR) { + DELTA_PASSES_MIR + } else { + DELTA_PASSES + } #undef DELTA_PASS } Index: llvm/tools/llvm-reduce/MyMachineModule.h =================================================================== --- /dev/null +++ llvm/tools/llvm-reduce/MyMachineModule.h @@ -0,0 +1,34 @@ +//===- MyMachineModule.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_MYMACHINEMODULE_H +#define LLVM_TOOLS_LLVM_REDUCE_MYMACHINEMODULE_H + +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/IR/Module.h" + +using namespace llvm; + +class MyMachineModule { +public: + std::shared_ptr M; + std::unique_ptr MF; + void print(raw_ostream &ROS, void *p = nullptr) const; +}; + +std::unique_ptr parseMyMachineModule(StringRef Filename, + LLVMContext &Ctxt, + MachineModuleInfo *MMI); + +std::unique_ptr +cloneMyMachineModule(const MyMachineModule &MMM); + +bool verifyMyMachineModule(const MyMachineModule &MMM, raw_fd_ostream *OS); + +#endif Index: llvm/tools/llvm-reduce/MyMachineModule.cpp =================================================================== --- /dev/null +++ llvm/tools/llvm-reduce/MyMachineModule.cpp @@ -0,0 +1,174 @@ +//===- MyMachineModule.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 "MyMachineModule.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 parseMyMachineModule(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 MyMachineModule::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 (verifyMyMachineModule(*MMM, &errs())) { + errs() << "Error: " << Filename << " - input module is broken!\n"; + return std::unique_ptr(); + } + return MMM; +} + +std::unique_ptr +cloneMyMachineModule(const MyMachineModule &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 verifyMyMachineModule(const MyMachineModule &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 MyMachineModule::print(raw_ostream &ROS, void *p) const { + if (MF) { + printMIR(ROS, *M); + printMIR(ROS, *MF); + } else { + M->print(ROS, nullptr); + } +} Index: llvm/tools/llvm-reduce/TestRunner.h =================================================================== --- llvm/tools/llvm-reduce/TestRunner.h +++ 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 "MyMachineModule.h" #include "llvm/ADT/SmallString.h" #include "llvm/IR/Module.h" #include "llvm/Support/Error.h" @@ -31,14 +32,16 @@ int run(StringRef Filename); /// Returns the most reduced version of the original testcase - Module *getProgram() const { return Program.get(); } + MyMachineModule *getProgram() const { return Program.get(); } - void setProgram(std::unique_ptr P) { Program = std::move(P); } + void setProgram(std::unique_ptr P) { + Program = std::move(P); + } private: StringRef TestName; const std::vector &TestArgs; - std::unique_ptr Program; + std::unique_ptr Program; }; } // namespace llvm Index: llvm/tools/llvm-reduce/deltas/Delta.h =================================================================== --- llvm/tools/llvm-reduce/deltas/Delta.h +++ llvm/tools/llvm-reduce/deltas/Delta.h @@ -101,9 +101,10 @@ /// /// Other implementations of the Delta Debugging algorithm can also be found in /// the CReduce, Delta, and Lithium projects. -void runDeltaPass(TestRunner &Test, int Targets, - std::function &, Module *)> - ExtractChunksFromModule); +void runDeltaPass( + TestRunner &Test, int Targets, + std::function &, MyMachineModule *)> + ExtractChunksFromModule); } // namespace llvm #endif Index: llvm/tools/llvm-reduce/deltas/Delta.cpp =================================================================== --- llvm/tools/llvm-reduce/deltas/Delta.cpp +++ llvm/tools/llvm-reduce/deltas/Delta.cpp @@ -13,11 +13,11 @@ //===----------------------------------------------------------------------===// #include "Delta.h" +#include "MyMachineModule.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,16 @@ "abort-on-invalid-reduction", cl::desc("Abort if any reduction results in invalid IR")); -void writeOutput(llvm::Module *M, llvm::StringRef Message); +extern cl::opt EnableMIR; -bool isReduced(Module &M, TestRunner &Test, SmallString<128> &CurrentFilepath) { - // Write Module to tmp file +void writeOutput(MyMachineModule *M, llvm::StringRef Message); + +bool isReduced(MyMachineModule &M, TestRunner &Test, + SmallString<128> &CurrentFilepath) { + // Write MyMachineModule 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", EnableMIR ? "mir" : "ll", FD, CurrentFilepath); if (EC) { errs() << "Error making unique filename: " << EC.message() << "!\n"; exit(1); @@ -97,7 +100,7 @@ /// given test. void llvm::runDeltaPass( TestRunner &Test, int Targets, - std::function &, Module *)> + std::function &, MyMachineModule *)> ExtractChunksFromModule) { assert(Targets >= 0); if (!Targets) { @@ -105,19 +108,19 @@ return; } - if (Module *Program = Test.getProgram()) { + if (MyMachineModule *Program = Test.getProgram()) { SmallString<128> CurrentFilepath; if (!isReduced(*Program, Test, CurrentFilepath)) { errs() << "\nInput isn't interesting! Verify interesting-ness test\n"; exit(1); } - assert(!verifyModule(*Program, &errs()) && + assert(!verifyMyMachineModule(*Program, &errs()) && "input module is broken before making changes"); } std::vector ChunksStillConsideredInteresting = {{1, Targets}}; - std::unique_ptr ReducedProgram; + std::unique_ptr ReducedProgram; bool FoundAtLeastOneNewUninterestingChunkWithCurrentGranularity; do { @@ -140,12 +143,13 @@ }); // Clone module before hacking it up.. - std::unique_ptr Clone = CloneModule(*Test.getProgram()); + std::unique_ptr Clone = + cloneMyMachineModule(*Test.getProgram()); // Generate Module with only Targets inside Current Chunks ExtractChunksFromModule(CurrentChunks, Clone.get()); // Some reductions may result in invalid IR. Skip such reductions. - if (verifyModule(*Clone.get(), &errs())) { + if (verifyMyMachineModule(*Clone.get(), &errs())) { if (AbortOnInvalidReduction) { errs() << "Invalid reduction\n"; exit(1); Index: llvm/tools/llvm-reduce/deltas/ReduceAliases.cpp =================================================================== --- llvm/tools/llvm-reduce/deltas/ReduceAliases.cpp +++ llvm/tools/llvm-reduce/deltas/ReduceAliases.cpp @@ -21,7 +21,8 @@ /// Removes all aliases aren't inside any of the /// desired Chunks. static void extractAliasesFromModule(const std::vector &ChunksToKeep, - Module *Program) { + MyMachineModule *MyProgram) { + Module *Program = MyProgram->M.get(); Oracle O(ChunksToKeep); for (auto &GA : make_early_inc_range(Program->aliases())) { @@ -33,7 +34,8 @@ } /// Counts the amount of aliases and prints their respective name & index. -static int countAliases(Module *Program) { +static int countAliases(MyMachineModule *MyProgram) { + Module *Program = MyProgram->M.get(); // TODO: Silence index with --quiet flag errs() << "----------------------------\n"; errs() << "Aliases Index Reference:\n"; Index: llvm/tools/llvm-reduce/deltas/ReduceArguments.cpp =================================================================== --- llvm/tools/llvm-reduce/deltas/ReduceArguments.cpp +++ llvm/tools/llvm-reduce/deltas/ReduceArguments.cpp @@ -54,7 +54,8 @@ /// Removes out-of-chunk arguments from functions, and modifies their calls /// accordingly. It also removes allocations of out-of-chunk arguments. static void extractArgumentsFromModule(std::vector ChunksToKeep, - Module *Program) { + MyMachineModule *MyProgram) { + Module *Program = MyProgram->M.get(); Oracle O(ChunksToKeep); std::set ArgsToKeep; @@ -115,7 +116,8 @@ /// Counts the amount of arguments in functions and prints their respective /// name, index, and parent function name -static int countArguments(Module *Program) { +static int countArguments(MyMachineModule *MyProgram) { + Module *Program = MyProgram->M.get(); // TODO: Silence index with --quiet flag outs() << "----------------------------\n"; outs() << "Param Index Reference:\n"; Index: llvm/tools/llvm-reduce/deltas/ReduceAttributes.cpp =================================================================== --- llvm/tools/llvm-reduce/deltas/ReduceAttributes.cpp +++ llvm/tools/llvm-reduce/deltas/ReduceAttributes.cpp @@ -168,7 +168,8 @@ /// Removes out-of-chunk attributes from module. static void extractAttributesFromModule(std::vector ChunksToKeep, - Module *Program) { + MyMachineModule *MyProgram) { + Module *Program = MyProgram->M.get(); AttributeRemapper R(ChunksToKeep); R.visit(Program); @@ -182,7 +183,8 @@ } /// Counts the amount of attributes. -static int countAttributes(Module *Program) { +static int countAttributes(MyMachineModule *MyProgram) { + Module *Program = MyProgram->M.get(); AttributeCounter C; // TODO: Silence index with --quiet flag Index: llvm/tools/llvm-reduce/deltas/ReduceBasicBlocks.cpp =================================================================== --- llvm/tools/llvm-reduce/deltas/ReduceBasicBlocks.cpp +++ llvm/tools/llvm-reduce/deltas/ReduceBasicBlocks.cpp @@ -88,7 +88,8 @@ /// Removes out-of-chunk arguments from functions, and modifies their calls /// accordingly. It also removes allocations of out-of-chunk arguments. static void extractBasicBlocksFromModule(std::vector ChunksToKeep, - Module *Program) { + MyMachineModule *MyProgram) { + Module *Program = MyProgram->M.get(); Oracle O(ChunksToKeep); std::set BBsToKeep; @@ -128,7 +129,8 @@ } /// Counts the amount of basic blocks and prints their name & respective index -static int countBasicBlocks(Module *Program) { +static int countBasicBlocks(MyMachineModule *MyProgram) { + Module *Program = MyProgram->M.get(); // TODO: Silence index with --quiet flag outs() << "----------------------------\n"; int BBCount = 0; Index: llvm/tools/llvm-reduce/deltas/ReduceFunctionBodies.cpp =================================================================== --- llvm/tools/llvm-reduce/deltas/ReduceFunctionBodies.cpp +++ llvm/tools/llvm-reduce/deltas/ReduceFunctionBodies.cpp @@ -21,7 +21,8 @@ /// desired Chunks. static void extractFunctionBodiesFromModule(const std::vector &ChunksToKeep, - Module *Program) { + MyMachineModule *MyProgram) { + Module *Program = MyProgram->M.get(); Oracle O(ChunksToKeep); // Delete out-of-chunk function bodies @@ -35,7 +36,8 @@ /// Counts the amount of non-declaration functions and prints their /// respective name & index -static int countFunctionDefinitions(Module *Program) { +static int countFunctionDefinitions(MyMachineModule *MyProgram) { + Module *Program = MyProgram->M.get(); // TODO: Silence index with --quiet flag errs() << "----------------------------\n"; errs() << "Function Definition Index Reference:\n"; Index: llvm/tools/llvm-reduce/deltas/ReduceFunctions.cpp =================================================================== --- llvm/tools/llvm-reduce/deltas/ReduceFunctions.cpp +++ llvm/tools/llvm-reduce/deltas/ReduceFunctions.cpp @@ -24,7 +24,8 @@ /// Removes all the Defined Functions /// that aren't inside any of the desired Chunks. static void extractFunctionsFromModule(const std::vector &ChunksToKeep, - Module *Program) { + MyMachineModule *MyProgram) { + Module *Program = MyProgram->M.get(); Oracle O(ChunksToKeep); // Record all out-of-chunk functions. @@ -53,7 +54,8 @@ /// Counts the amount of functions and prints their /// respective name & index -static int countFunctions(Module *Program) { +static int countFunctions(MyMachineModule *MyProgram) { + Module *Program = MyProgram->M.get(); // TODO: Silence index with --quiet flag errs() << "----------------------------\n"; errs() << "Function Index Reference:\n"; Index: llvm/tools/llvm-reduce/deltas/ReduceGlobalValues.cpp =================================================================== --- llvm/tools/llvm-reduce/deltas/ReduceGlobalValues.cpp +++ llvm/tools/llvm-reduce/deltas/ReduceGlobalValues.cpp @@ -23,7 +23,8 @@ /// Sets dso_local to false for all global values. static void extractGVsFromModule(std::vector ChunksToKeep, - Module *Program) { + MyMachineModule *MyProgram) { + Module *Program = MyProgram->M.get(); Oracle O(ChunksToKeep); // remove dso_local from global values @@ -35,7 +36,8 @@ /// Counts the amount of global values with dso_local and displays their /// respective name & index -static int countGVs(Module *Program) { +static int countGVs(MyMachineModule *MyProgram) { + Module *Program = MyProgram->M.get(); // TODO: Silence index with --quiet flag outs() << "----------------------------\n"; outs() << "GlobalValue Index Reference:\n"; Index: llvm/tools/llvm-reduce/deltas/ReduceGlobalVarInitializers.cpp =================================================================== --- llvm/tools/llvm-reduce/deltas/ReduceGlobalVarInitializers.cpp +++ llvm/tools/llvm-reduce/deltas/ReduceGlobalVarInitializers.cpp @@ -19,7 +19,8 @@ /// Removes all the Initialized GVs that aren't inside the desired Chunks. static void extractGVsFromModule(std::vector ChunksToKeep, - Module *Program) { + MyMachineModule *MyProgram) { + Module *Program = MyProgram->M.get(); Oracle O(ChunksToKeep); // Drop initializers of out-of-chunk GVs @@ -33,7 +34,8 @@ /// Counts the amount of initialized GVs and displays their /// respective name & index -static int countGVs(Module *Program) { +static int countGVs(MyMachineModule *MyProgram) { + Module *Program = MyProgram->M.get(); // TODO: Silence index with --quiet flag outs() << "----------------------------\n"; outs() << "GlobalVariable Index Reference:\n"; Index: llvm/tools/llvm-reduce/deltas/ReduceGlobalVars.cpp =================================================================== --- llvm/tools/llvm-reduce/deltas/ReduceGlobalVars.cpp +++ llvm/tools/llvm-reduce/deltas/ReduceGlobalVars.cpp @@ -19,7 +19,8 @@ /// Removes all the GVs that aren't inside the desired Chunks. static void extractGVsFromModule(std::vector ChunksToKeep, - Module *Program) { + MyMachineModule *MyProgram) { + Module *Program = MyProgram->M.get(); Oracle O(ChunksToKeep); // Get GVs inside desired chunks @@ -56,7 +57,8 @@ /// Counts the amount of GVs and displays their /// respective name & index -static int countGVs(Module *Program) { +static int countGVs(MyMachineModule *MyProgram) { + Module *Program = MyProgram->M.get(); // TODO: Silence index with --quiet flag outs() << "----------------------------\n"; outs() << "GlobalVariable Index Reference:\n"; Index: llvm/tools/llvm-reduce/deltas/ReduceInstructions.cpp =================================================================== --- llvm/tools/llvm-reduce/deltas/ReduceInstructions.cpp +++ llvm/tools/llvm-reduce/deltas/ReduceInstructions.cpp @@ -18,7 +18,8 @@ /// Removes out-of-chunk arguments from functions, and modifies their calls /// accordingly. It also removes allocations of out-of-chunk arguments. static void extractInstrFromModule(std::vector ChunksToKeep, - Module *Program) { + MyMachineModule *MyProgram) { + Module *Program = MyProgram->M.get(); Oracle O(ChunksToKeep); std::set InstToKeep; @@ -47,7 +48,8 @@ } /// Counts the amount of basic blocks and prints their name & respective index -static unsigned countInstructions(Module *Program) { +static unsigned countInstructions(MyMachineModule *MyProgram) { + Module *Program = MyProgram->M.get(); // TODO: Silence index with --quiet flag outs() << "----------------------------\n"; int InstCount = 0; Index: llvm/tools/llvm-reduce/deltas/ReduceInstructionsMIR.h =================================================================== --- /dev/null +++ llvm/tools/llvm-reduce/deltas/ReduceInstructionsMIR.h @@ -0,0 +1,23 @@ +//===- ReduceArguments.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 Arguments from defined functions. +// +//===----------------------------------------------------------------------===// + +#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 Index: llvm/tools/llvm-reduce/deltas/ReduceInstructionsMIR.cpp =================================================================== --- /dev/null +++ llvm/tools/llvm-reduce/deltas/ReduceInstructionsMIR.cpp @@ -0,0 +1,150 @@ +//===- ReduceArguments.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 Arguments from defined functions. +// +//===----------------------------------------------------------------------===// + +#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" +#include "llvm/Support/Debug.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(MyMachineModule *Program) { + unsigned Count = 0; + MachineInstr *TopMI = nullptr; + for (auto &MBB : *Program->MF) { + for (auto &MI : MBB) { + if (MI.isTerminator()) + continue; + if (MBB.isEntryBlock() && !TopMI) { + TopMI = &MI; + continue; + } + Count++; + } + } + return Count; +} + +static void extractInstrFromModule(std::vector ChunksToKeep, + MyMachineModule *Program) { + auto &MF = *Program->MF; + MachineDominatorTree MDT; + MDT.runOnMachineFunction(MF); + + Oracle O(ChunksToKeep); + + 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); + // errs() << "Deleting: " << 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); +} Index: llvm/tools/llvm-reduce/deltas/ReduceMetadata.cpp =================================================================== --- llvm/tools/llvm-reduce/deltas/ReduceMetadata.cpp +++ llvm/tools/llvm-reduce/deltas/ReduceMetadata.cpp @@ -23,7 +23,8 @@ /// Removes all the Named and Unnamed Metadata Nodes, as well as any debug /// functions that aren't inside the desired Chunks. static void extractMetadataFromModule(const std::vector &ChunksToKeep, - Module *Program) { + MyMachineModule *MyProgram) { + Module *Program = MyProgram->M.get(); Oracle O(ChunksToKeep); // Get out-of-chunk Named metadata nodes @@ -64,7 +65,8 @@ } } -static int countMetadataTargets(Module *Program) { +static int countMetadataTargets(MyMachineModule *MyProgram) { + Module *Program = MyProgram->M.get(); int NamedMetadataNodes = Program->named_metadata_size(); // Get metadata attached to globals. Index: llvm/tools/llvm-reduce/deltas/ReduceModuleData.cpp =================================================================== --- llvm/tools/llvm-reduce/deltas/ReduceModuleData.cpp +++ llvm/tools/llvm-reduce/deltas/ReduceModuleData.cpp @@ -14,7 +14,9 @@ using namespace llvm; -static void clearModuleData(std::vector ChunksToKeep, Module *Program) { +static void clearModuleData(std::vector ChunksToKeep, + MyMachineModule *MyProgram) { + Module *Program = MyProgram->M.get(); Oracle O(ChunksToKeep); if (!Program->getModuleIdentifier().empty() && !O.shouldKeep()) @@ -30,7 +32,8 @@ Program->setModuleInlineAsm(""); } -static int countModuleData(Module *M) { +static int countModuleData(MyMachineModule *MyM) { + Module *M = MyM->M.get(); int Count = 0; if (!M->getModuleIdentifier().empty()) ++Count; Index: llvm/tools/llvm-reduce/deltas/ReduceOperandBundles.cpp =================================================================== --- llvm/tools/llvm-reduce/deltas/ReduceOperandBundles.cpp +++ llvm/tools/llvm-reduce/deltas/ReduceOperandBundles.cpp @@ -97,7 +97,8 @@ /// Removes out-of-chunk operand bundles from calls. static void extractOperandBundesFromModule(std::vector ChunksToKeep, - Module *Program) { + MyMachineModule *MyProgram) { + Module *Program = MyProgram->M.get(); OperandBundleRemapper R(ChunksToKeep); R.visit(Program); @@ -106,7 +107,8 @@ } /// Counts the amount of operand bundles. -static int countOperandBundes(Module *Program) { +static int countOperandBundes(MyMachineModule *MyProgram) { + Module *Program = MyProgram->M.get(); OperandBundleCounter C; // TODO: Silence index with --quiet flag Index: llvm/tools/llvm-reduce/deltas/ReduceOperands.cpp =================================================================== --- llvm/tools/llvm-reduce/deltas/ReduceOperands.cpp +++ llvm/tools/llvm-reduce/deltas/ReduceOperands.cpp @@ -35,7 +35,8 @@ /// Sets Operands to undef. static void extractOperandsFromModule(std::vector ChunksToKeep, - Module *Program) { + MyMachineModule *MyProgram) { + Module *Program = MyProgram->M.get(); Oracle O(ChunksToKeep); // Extract Operands from the module. @@ -53,7 +54,8 @@ } /// Counts the amount of operands in the module that can be reduced. -static int countOperands(Module *Program) { +static int countOperands(MyMachineModule *MyProgram) { + Module *Program = MyProgram->M.get(); int Count = 0; for (auto &F : Program->functions()) { for (auto &I : instructions(&F)) { Index: llvm/tools/llvm-reduce/deltas/ReduceSpecialGlobals.cpp =================================================================== --- llvm/tools/llvm-reduce/deltas/ReduceSpecialGlobals.cpp +++ llvm/tools/llvm-reduce/deltas/ReduceSpecialGlobals.cpp @@ -28,7 +28,8 @@ /// desired Chunks. static void extractSpecialGlobalsFromModule(const std::vector &ChunksToKeep, - Module *Program) { + MyMachineModule *MyProgram) { + Module *Program = MyProgram->M.get(); Oracle O(ChunksToKeep); for (StringRef Name : SpecialGlobalNames) { @@ -41,7 +42,8 @@ /// Counts the amount of special globals and prints their /// respective name & index -static int countSpecialGlobals(Module *Program) { +static int countSpecialGlobals(MyMachineModule *MyProgram) { + Module *Program = MyProgram->M.get(); // TODO: Silence index with --quiet flag errs() << "----------------------------\n"; errs() << "Special Globals Index Reference:\n"; Index: llvm/tools/llvm-reduce/llvm-reduce.cpp =================================================================== --- llvm/tools/llvm-reduce/llvm-reduce.cpp +++ llvm/tools/llvm-reduce/llvm-reduce.cpp @@ -15,15 +15,21 @@ //===----------------------------------------------------------------------===// #include "DeltaManager.h" +#include "MyMachineModule.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/Support/CommandLine.h" +#include "llvm/Support/Host.h" #include "llvm/Support/InitLLVM.h" #include "llvm/Support/SourceMgr.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/TargetSelect.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetMachine.h" #include #include @@ -55,9 +61,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 +73,18 @@ "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; - } - - if (verifyModule(*Result, &errs())) { - errs() << "Error: " << Filename << " - input module is broken!\n"; - return std::unique_ptr(); - } +static cl::opt + TargetTriple("mtriple", cl::init(sys::getDefaultTargetTriple()), + cl::desc("Set the target triple")); +cl::opt EnableMIR("mir", cl::desc("MIR mode")); - return Result; -} +static codegen::RegisterCodeGenFlags CGF; -void writeOutput(Module *M, StringRef Message) { +void writeOutput(MyMachineModule *M, StringRef Message) { if (ReplaceInput) // In-place OutputFilename = InputFilename.c_str(); else if (OutputFilename.empty() || OutputFilename == "-") - OutputFilename = "reduced.ll"; - + OutputFilename = EnableMIR ? "reduced.mir" : "reduced.ll"; std::error_code EC; raw_fd_ostream Out(OutputFilename, EC); if (EC) { @@ -102,6 +95,24 @@ errs() << Message << OutputFilename << "\n"; } +static std::unique_ptr createTargetMachine() { + InitializeAllTargets(); + InitializeAllTargetMCs(); + InitializeAllAsmPrinters(); + InitializeAllAsmParsers(); + + 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); @@ -114,9 +125,14 @@ } LLVMContext Context; - std::unique_ptr OriginalProgram = - parseInputFile(InputFilename, Context); - + std::unique_ptr TM; + std::unique_ptr MMI; + std::unique_ptr OriginalProgram; + if (EnableMIR) { + TM = createTargetMachine(); + MMI = std::make_unique(TM.get()); + } + OriginalProgram = parseMyMachineModule(InputFilename, Context, MMI.get()); if (!OriginalProgram) { return 1; }