Index: llvm/include/llvm/CodeGen/MachineModuleInfo.h =================================================================== --- llvm/include/llvm/CodeGen/MachineModuleInfo.h +++ llvm/include/llvm/CodeGen/MachineModuleInfo.h @@ -158,6 +158,9 @@ /// Machine Function map. void deleteMachineFunctionFor(Function &F); + /// Add an externally created MachineFunction \p MF for \p F. + void insertFunction(const Function &F, std::unique_ptr &&MF); + /// Keep track of various per-module pieces of information for backends /// that would like to do so. template Index: llvm/lib/CodeGen/MachineModuleInfo.cpp =================================================================== --- llvm/lib/CodeGen/MachineModuleInfo.cpp +++ llvm/lib/CodeGen/MachineModuleInfo.cpp @@ -140,6 +140,13 @@ LastResult = nullptr; } +void MachineModuleInfo::insertFunction(const Function &F, + std::unique_ptr &&MF) { + auto I = MachineFunctions.insert(std::make_pair(&F, std::move(MF))); + assert(I.second && "machine function already mapped"); + (void)I; +} + namespace { /// This pass frees the MachineFunction object associated with a Function. Index: llvm/test/tools/llvm-reduce/mir/multiple-functions.mir =================================================================== --- /dev/null +++ llvm/test/tools/llvm-reduce/mir/multiple-functions.mir @@ -0,0 +1,45 @@ +# REQUIRES: amdgpu-registered-target +# RUN: llvm-reduce -simplify-mir -mtriple=amdgcn-amd-amdhsa --test FileCheck --test-arg --check-prefix=CHECK-INTERESTINGNESS --test-arg %s --test-arg --input-file %s -o %t 2> %t.log +# RUN: FileCheck --check-prefix=RESULT %s < %t + +# CHECK-INTERESTINGNESS: S_NOP 0 + +# RESULT: name: func0 +# RESULT: S_NOP 0 + +# RESULT: name: func1 +# RESULT-NOT: S_NOP + +--- | + define void @func0() { + ret void + } + + define void @func1() { + ret void + } + +... +--- +name: func0 +tracksRegLiveness: true +body: | + bb.0: + S_WAITCNT 0 + S_NOP 0 + %0:vgpr_32 = V_MOV_B32_e32 0, implicit $exec + INLINEASM &"", 1 /* sideeffect attdialect */ + S_ENDPGM 0, implicit %0 +... + +--- +name: func1 +tracksRegLiveness: true +body: | + bb.0: + S_WAITCNT 0 + S_NOP 1 + %0:vgpr_32 = V_MOV_B32_e32 0, implicit $exec + INLINEASM &"", 1 /* sideeffect attdialect */ + S_ENDPGM 0, implicit %0 +... Index: llvm/tools/llvm-reduce/ReducerWorkItem.h =================================================================== --- llvm/tools/llvm-reduce/ReducerWorkItem.h +++ llvm/tools/llvm-reduce/ReducerWorkItem.h @@ -19,20 +19,23 @@ class ReducerWorkItem { public: std::shared_ptr M; - std::unique_ptr MF; + std::unique_ptr MMI; + + bool isMIR() const { return MMI != nullptr; } + + const Module &getModule() const { return *M; } + 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(const char *ToolName, StringRef Filename, LLVMContext &Ctxt, std::unique_ptr &TM, - std::unique_ptr &MMI, bool IsMIR); + bool IsMIR); std::unique_ptr -cloneReducerWorkItem(const ReducerWorkItem &MMM); +cloneReducerWorkItem(const ReducerWorkItem &MMM, const TargetMachine *TM); bool verifyReducerWorkItem(const ReducerWorkItem &MMM, raw_fd_ostream *OS); Index: llvm/tools/llvm-reduce/ReducerWorkItem.cpp =================================================================== --- llvm/tools/llvm-reduce/ReducerWorkItem.cpp +++ llvm/tools/llvm-reduce/ReducerWorkItem.cpp @@ -125,10 +125,11 @@ } } -static std::unique_ptr cloneMF(MachineFunction *SrcMF) { +static std::unique_ptr cloneMF(MachineFunction *SrcMF, + MachineModuleInfo &DestMMI) { auto DstMF = std::make_unique( SrcMF->getFunction(), SrcMF->getTarget(), SrcMF->getSubtarget(), - SrcMF->getFunctionNumber(), SrcMF->getMMI()); + SrcMF->getFunctionNumber(), DestMMI); DenseMap Src2DstMBB; auto *SrcMRI = &SrcMF->getRegInfo(); @@ -247,7 +248,7 @@ std::unique_ptr parseReducerWorkItem(const char *ToolName, StringRef Filename, LLVMContext &Ctxt, std::unique_ptr &TM, - std::unique_ptr &MMI, bool IsMIR) { + bool IsMIR) { Triple TheTriple; auto MMM = std::make_unique(); @@ -289,26 +290,9 @@ }; std::unique_ptr M = MParser->parseIRModule(SetDataLayout); - MMI = std::make_unique(TM.get()); - MParser->parseMachineFunctions(*M, *MMI); - MachineFunction *MF = nullptr; - for (auto &F : *M) { - if (F.getName() == "ignoreme") - continue; - - 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->MMI = std::make_unique(TM.get()); + MParser->parseMachineFunctions(*M, *MMM->MMI); MMM->M = std::move(M); - MMM->MF = cloneMF(MF); } else { SMDiagnostic Err; std::unique_ptr Result = parseIRFile(Filename, Err, Ctxt); @@ -327,16 +311,22 @@ } std::unique_ptr -cloneReducerWorkItem(const ReducerWorkItem &MMM) { +cloneReducerWorkItem(const ReducerWorkItem &MMM, const TargetMachine *TM) { 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); + if (TM) { + // We're assuming the Module IR contents are always unchanged by MIR + // reductions, and can share it as a constant. CloneMMM->M = MMM.M; - CloneMMM->MF = cloneMF(MMM.MF.get()); + + // MachineModuleInfo contains a lot of other state used during codegen which + // we won't be using here, but we should be able to ignore it (although this + // is pretty ugly). + CloneMMM->MMI = std::make_unique(TM); + + for (const Function &F : MMM.getModule()) { + if (auto *MF = MMM.MMI->getMachineFunction(F)) + CloneMMM->MMI->insertFunction(F, cloneMF(MF, *CloneMMM->MMI)); + } } else { CloneMMM->M = CloneModule(*MMM.M); } @@ -346,15 +336,27 @@ bool verifyReducerWorkItem(const ReducerWorkItem &MMM, raw_fd_ostream *OS) { if (verifyModule(*MMM.M, OS)) return true; - if (MMM.MF && !MMM.MF->verify(nullptr, "", /*AbortOnError=*/false)) - return true; + + if (!MMM.MMI) + return false; + + for (const Function &F : MMM.getModule()) { + if (const MachineFunction *MF = MMM.MMI->getMachineFunction(F)) { + if (!MF->verify(nullptr, "", /*AbortOnError=*/false)) + return true; + } + } + return false; } void ReducerWorkItem::print(raw_ostream &ROS, void *p) const { - if (MF) { + if (MMI) { printMIR(ROS, *M); - printMIR(ROS, *MF); + for (Function &F : *M) { + if (auto *MF = MMI->getMachineFunction(F)) + printMIR(ROS, *MF); + } } else { M->print(ROS, /*AssemblyAnnotationWriter=*/nullptr, /*ShouldPreserveUseListOrder=*/true); Index: llvm/tools/llvm-reduce/TestRunner.h =================================================================== --- llvm/tools/llvm-reduce/TestRunner.h +++ llvm/tools/llvm-reduce/TestRunner.h @@ -16,6 +16,7 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include "llvm/Support/Program.h" +#include "llvm/Target/TargetMachine.h" #include namespace llvm { @@ -26,7 +27,8 @@ class TestRunner { public: TestRunner(StringRef TestName, const std::vector &TestArgs, - std::unique_ptr Program); + std::unique_ptr Program, + std::unique_ptr TM); /// Runs the interesting-ness test for the specified file /// @returns 0 if test was successful, 1 if otherwise @@ -40,10 +42,13 @@ Program = std::move(P); } + const TargetMachine *getTargetMachine() const { return TM.get(); } + private: StringRef TestName; const std::vector &TestArgs; std::unique_ptr Program; + std::unique_ptr TM; }; } // namespace llvm Index: llvm/tools/llvm-reduce/TestRunner.cpp =================================================================== --- llvm/tools/llvm-reduce/TestRunner.cpp +++ llvm/tools/llvm-reduce/TestRunner.cpp @@ -12,8 +12,10 @@ TestRunner::TestRunner(StringRef TestName, const std::vector &TestArgs, - std::unique_ptr Program) - : TestName(TestName), TestArgs(TestArgs), Program(std::move(Program)) { + std::unique_ptr Program, + std::unique_ptr TM) + : TestName(TestName), TestArgs(TestArgs), Program(std::move(Program)), + TM(std::move(TM)) { assert(this->Program && "Initialized with null program?"); } Index: llvm/tools/llvm-reduce/deltas/Delta.h =================================================================== --- llvm/tools/llvm-reduce/deltas/Delta.h +++ llvm/tools/llvm-reduce/deltas/Delta.h @@ -85,6 +85,8 @@ int count() { return Index; } }; +using ReductionFunc = function_ref; + /// This function implements the Delta Debugging algorithm, it receives a /// number of Targets (e.g. Functions, Instructions, Basic Blocks, etc.) and /// splits them in half; these chunks of targets are then tested while ignoring @@ -103,12 +105,7 @@ /// /// Other implementations of the Delta Debugging algorithm can also be found in /// the CReduce, Delta, and Lithium projects. -void runDeltaPass( - TestRunner &Test, - function_ref ExtractChunksFromModule); -void runDeltaPass( - TestRunner &Test, - function_ref ExtractChunksFromModule); +void runDeltaPass(TestRunner &Test, ReductionFunc 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 @@ -132,13 +132,14 @@ } return SplitOne; } + // Check if \p ChunkToCheckForUninterestingness is interesting. Returns the // modified module if the chunk resulted in a reduction. -template +template static std::unique_ptr CheckChunk(Chunk &ChunkToCheckForUninterestingness, std::unique_ptr Clone, TestRunner &Test, - function_ref ExtractChunksFromModule, + FuncType ExtractChunksFromModule, std::set &UninterestingChunks, std::vector &ChunksStillConsideredInteresting) { // Take all of ChunksStillConsideredInteresting chunks, except those we've @@ -183,11 +184,10 @@ return Clone; } -template +template SmallString<0> ProcessChunkFromSerializedBitcode( Chunk &ChunkToCheckForUninterestingness, TestRunner &Test, - function_ref ExtractChunksFromModule, - std::set &UninterestingChunks, + FuncType ExtractChunksFromModule, std::set &UninterestingChunks, std::vector &ChunksStillConsideredInteresting, SmallString<0> &OriginalBC, std::atomic &AnyReduced) { LLVMContext Ctx; @@ -217,10 +217,8 @@ /// reduces the amount of chunks that are considered interesting by the /// given test. The number of chunks is determined by a preliminary run of the /// reduction pass where no change must be made to the module. -template -void runDeltaPassInt( - TestRunner &Test, - function_ref ExtractChunksFromModule) { +void llvm::runDeltaPass(TestRunner &Test, + ReductionFunc ExtractChunksFromModule) { assert(!verifyReducerWorkItem(Test.getProgram(), &errs()) && "input module is broken before making changes"); @@ -250,7 +248,7 @@ std::vector NoChunks; Oracle NoChunksCounter(NoChunks); std::unique_ptr Clone = - cloneReducerWorkItem(Test.getProgram()); + cloneReducerWorkItem(Test.getProgram(), Test.getTargetMachine()); ExtractChunksFromModule(NoChunksCounter, *Clone); assert(Targets == NoChunksCounter.count() && "number of chunks changes when reducing"); @@ -365,9 +363,11 @@ // Forward I to the last chunk processed in parallel. I += NumChunksProcessed - 1; } else { - Result = CheckChunk(*I, cloneReducerWorkItem(Test.getProgram()), Test, - ExtractChunksFromModule, UninterestingChunks, - ChunksStillConsideredInteresting); + Result = CheckChunk( + *I, + cloneReducerWorkItem(Test.getProgram(), Test.getTargetMachine()), + Test, ExtractChunksFromModule, UninterestingChunks, + ChunksStillConsideredInteresting); } if (!Result) @@ -394,15 +394,3 @@ Test.setProgram(std::move(ReducedProgram)); errs() << "Couldn't increase anymore.\n"; } - -void llvm::runDeltaPass( - TestRunner &Test, - function_ref ExtractChunksFromModule) { - runDeltaPassInt(Test, ExtractChunksFromModule); -} - -void llvm::runDeltaPass( - TestRunner &Test, - function_ref ExtractChunksFromModule) { - runDeltaPassInt(Test, ExtractChunksFromModule); -} Index: llvm/tools/llvm-reduce/deltas/ReduceInstructionsMIR.cpp =================================================================== --- llvm/tools/llvm-reduce/deltas/ReduceInstructionsMIR.cpp +++ llvm/tools/llvm-reduce/deltas/ReduceInstructionsMIR.cpp @@ -45,7 +45,7 @@ return 0; } -static void extractInstrFromModule(Oracle &O, MachineFunction &MF) { +static void extractInstrFromFunction(Oracle &O, MachineFunction &MF) { MachineDominatorTree MDT; MDT.runOnMachineFunction(MF); @@ -127,6 +127,13 @@ MI->eraseFromParent(); } +static void extractInstrFromModule(Oracle &O, ReducerWorkItem &WorkItem) { + for (const Function &F : WorkItem.getModule()) { + if (auto *MF = WorkItem.MMI->getMachineFunction(F)) + extractInstrFromFunction(O, *MF); + } +} + void llvm::reduceInstructionsMIRDeltaPass(TestRunner &Test) { outs() << "*** Reducing Instructions...\n"; runDeltaPass(Test, extractInstrFromModule); Index: llvm/tools/llvm-reduce/llvm-reduce.cpp =================================================================== --- llvm/tools/llvm-reduce/llvm-reduce.cpp +++ llvm/tools/llvm-reduce/llvm-reduce.cpp @@ -138,16 +138,16 @@ LLVMContext Context; std::unique_ptr TM; - std::unique_ptr MMI; - std::unique_ptr OriginalProgram = parseReducerWorkItem( - Argv[0], InputFilename, Context, TM, MMI, ReduceModeMIR); + std::unique_ptr OriginalProgram = + parseReducerWorkItem(Argv[0], InputFilename, Context, TM, ReduceModeMIR); if (!OriginalProgram) { return 1; } // Initialize test environment - TestRunner Tester(TestFilename, TestArguments, std::move(OriginalProgram)); + TestRunner Tester(TestFilename, TestArguments, std::move(OriginalProgram), + std::move(TM)); // Try to reduce code runDeltaPasses(Tester, MaxPassIterations);