From: Chris Lattner Date: Thu, 23 Jan 2003 02:48:33 +0000 (+0000) Subject: Make bugpoint *much* more powerful, giving it the capability to delete instructions X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=6520785dcd22012535934098942d57c07c7631c2;p=oota-llvm.git Make bugpoint *much* more powerful, giving it the capability to delete instructions out of a large function to reduce it. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@5408 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/tools/bugpoint/BugDriver.h b/tools/bugpoint/BugDriver.h index 6398366d8cf..3dbb84dab65 100644 --- a/tools/bugpoint/BugDriver.h +++ b/tools/bugpoint/BugDriver.h @@ -15,6 +15,7 @@ class PassInfo; class Module; class Function; class AbstractInterpreter; +class Instruction; class BugDriver { const std::string ToolName; // Name of bugpoint @@ -117,6 +118,13 @@ private: /// Module *extractFunctionFromModule(Function *F) const; + /// deleteInstructionFromProgram - This method clones the current Program and + /// deletes the specified instruction from the cloned module. It then runs a + /// series of cleanup passes (ADCE and SimplifyCFG) to eliminate any code + /// which depends on the value. The modified module is then returned. + /// + Module *deleteInstructionFromProgram(Instruction *I, unsigned Simp) const; + /// initializeExecutionEnvironment - This method is used to set up the /// environment for executing LLVM programs. /// diff --git a/tools/bugpoint/CrashDebugger.cpp b/tools/bugpoint/CrashDebugger.cpp index c69ca453621..daf3915a5eb 100644 --- a/tools/bugpoint/CrashDebugger.cpp +++ b/tools/bugpoint/CrashDebugger.cpp @@ -114,18 +114,63 @@ bool BugDriver::debugPassCrash(const PassInfo *Pass) { delete Program; Program = M; } - } - if (CountFunctions(Program) > 1) { - std::cout << "\n*** Couldn't reduce testcase to one function.\n" - << " Attempting to remove individual functions.\n"; - std::cout << "XXX Individual function removal unimplemented!\n"; + if (CountFunctions(Program) > 1) { + std::cout << "\n*** Couldn't reduce testcase to one function.\n" + << " Attempting to remove individual functions.\n"; + std::cout << "XXX Individual function removal unimplemented!\n"; + } } - // Now that we have deleted the functions that are unneccesary for the - // program, try to remove instructions and basic blocks that are not neccesary - // to cause the crash. - // + // FIXME: This should attempt to delete entire basic blocks at a time to speed + // up convergence... + + unsigned Simplification = 4; + do { + --Simplification; + std::cout << "\n*** Attempting to reduce testcase by deleting instruc" + << "tions: Simplification Level #" << Simplification << "\n"; + + // Now that we have deleted the functions that are unneccesary for the + // program, try to remove instructions that are not neccesary to cause the + // crash. To do this, we loop through all of the instructions in the + // remaining functions, deleting them (replacing any values produced with + // nulls), and then running ADCE and SimplifyCFG. If the transformed input + // still triggers failure, keep deleting until we cannot trigger failure + // anymore. + // + TryAgain: + + // Loop over all of the (non-terminator) instructions remaining in the + // function, attempting to delete them. + for (Module::iterator FI = Program->begin(), E = Program->end(); + FI != E; ++FI) + if (!FI->isExternal()) { + for (Function::iterator BI = FI->begin(), E = FI->end(); BI != E; ++BI) + for (BasicBlock::iterator I = BI->begin(), E = --BI->end(); + I != E; ++I) { + Module *M = deleteInstructionFromProgram(I, Simplification); + + // Make the function the current program... + std::swap(Program, M); + + // Find out if the pass still crashes on this pass... + std::cout << "Checking instruction '" << I->getName() << "': "; + if (runPass(Pass)) { + // Yup, it does, we delete the old module, and continue trying to + // reduce the testcase... + EmitProgressBytecode(Pass, "reduced-" + I->getName()); + delete M; + goto TryAgain; // I wish I had a multi-level break here! + } + + // This pass didn't crash without this instruction, try the next + // one. + delete Program; + Program = M; + } + } + } while (Simplification); return false; } diff --git a/tools/bugpoint/ExtractFunction.cpp b/tools/bugpoint/ExtractFunction.cpp index 76b2258f8a7..9b5440c0d4e 100644 --- a/tools/bugpoint/ExtractFunction.cpp +++ b/tools/bugpoint/ExtractFunction.cpp @@ -9,7 +9,10 @@ #include "llvm/Module.h" #include "llvm/PassManager.h" #include "llvm/Transforms/IPO.h" +#include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/Utils/Cloning.h" +#include "llvm/Type.h" +#include "llvm/Constant.h" /// extractFunctionFromModule - This method is used to extract the specified /// (non-external) function from the current program, slim down the module, and @@ -19,16 +22,62 @@ Module *BugDriver::extractFunctionFromModule(Function *F) const { Module *Result = CloneModule(Program); // Translate from the old module to the new copied module... - F = Result->getFunction(F->getName(), F->getFunctionType()); + Module::iterator RFI = Result->begin(); // Get iterator to corresponding fn + std::advance(RFI, std::distance(Program->begin(), Module::iterator(F))); // In addition to just parsing the input from GCC, we also want to spiff it up // a little bit. Do this now. // PassManager Passes; - Passes.add(createFunctionExtractionPass(F)); // Extract the function + Passes.add(createFunctionExtractionPass(RFI)); // Extract the function Passes.add(createGlobalDCEPass()); // Delete unreachable globals Passes.add(createFunctionResolvingPass()); // Delete prototypes Passes.add(createDeadTypeEliminationPass()); // Remove dead types... Passes.run(*Result); return Result; } + + +/// deleteInstructionFromProgram - This method clones the current Program and +/// deletes the specified instruction from the cloned module. It then runs a +/// series of cleanup passes (ADCE and SimplifyCFG) to eliminate any code which +/// depends on the value. The modified module is then returned. +/// +Module *BugDriver::deleteInstructionFromProgram(Instruction *I, + unsigned Simplification) const { + Module *Result = CloneModule(Program); + + BasicBlock *PBB = I->getParent(); + Function *PF = PBB->getParent(); + + Module::iterator RFI = Result->begin(); // Get iterator to corresponding fn + std::advance(RFI, std::distance(Program->begin(), Module::iterator(PF))); + + Function::iterator RBI = RFI->begin(); // Get iterator to corresponding BB + std::advance(RBI, std::distance(PF->begin(), Function::iterator(PBB))); + + BasicBlock::iterator RI = RBI->begin(); // Get iterator to corresponding inst + std::advance(RI, std::distance(PBB->begin(), BasicBlock::iterator(I))); + I = RI; // Got the corresponding instruction! + + // If this instruction produces a value, replace any users with null values + if (I->getType() != Type::VoidTy) + I->replaceAllUsesWith(Constant::getNullValue(I->getType())); + + // Remove the instruction from the program. + I->getParent()->getInstList().erase(I); + + // In addition to just parsing the input from GCC, we also want to spiff it up + // a little bit. Do this now. + // + PassManager Passes; + if (Simplification > 2) + Passes.add(createAggressiveDCEPass()); // Remove dead code... + //Passes.add(createInstructionCombiningPass()); + if (Simplification > 1) + Passes.add(createDeadCodeEliminationPass()); + if (Simplification) + Passes.add(createCFGSimplificationPass()); // Delete dead control flow + Passes.run(*Result); + return Result; +}