diff --git a/tools/bugpoint/BugDriver.cpp b/tools/bugpoint/BugDriver.cpp index 14e5606f6c6..4359622777f 100644 --- a/tools/bugpoint/BugDriver.cpp +++ b/tools/bugpoint/BugDriver.cpp @@ -38,6 +38,15 @@ namespace { "(for miscompilation detection)")); } +/// setNewProgram - If we reduce or update the program somehow, call this method +/// to update bugdriver with it. This deletes the old module and sets the +/// specified one as the current program. +void BugDriver::setNewProgram(Module *M) { + delete Program; + Program = M; +} + + /// getPassesString - Turn a list of passes into a string which indicates the /// command line options that must be passed to add the passes. /// @@ -174,7 +183,7 @@ bool BugDriver::run() { return debugMiscompilation(); } } catch (ToolExecutionError &TEE) { - std::cerr << TEE.getMessage() << "*** Debugging code generator crash!\n"; + std::cerr << TEE.getMessage(); return debugCodeGeneratorCrash(); } diff --git a/tools/bugpoint/BugDriver.h b/tools/bugpoint/BugDriver.h index 4d6754aa7cd..a5f1e3f3563 100644 --- a/tools/bugpoint/BugDriver.h +++ b/tools/bugpoint/BugDriver.h @@ -48,12 +48,10 @@ class BugDriver { GCC *gcc; // FIXME: sort out public/private distinctions... - friend class DebugCrashes; + friend class ReducePassList; friend class ReduceMiscompilingPasses; friend class ReduceMiscompilingFunctions; friend class ReduceMisCodegenFunctions; - friend class ReduceCrashingFunctions; - friend class ReduceCrashingBlocks; public: BugDriver(const char *toolname); @@ -114,6 +112,23 @@ public: /// bool isExecutingJIT(); + /// runPasses - Run all of the passes in the "PassesToRun" list, discard the + /// output, and return true if any of the passes crashed. + bool runPasses(Module *M = 0) { + if (M == 0) M = Program; + std::swap(M, Program); + bool Result = runPasses(PassesToRun); + std::swap(M, Program); + return Result; + } + + const Module *getProgram() const { return Program; } + + /// setNewProgram - If we reduce or update the program somehow, call this + /// method to update bugdriver with it. This deletes the old module and sets + /// the specified one as the current program. + void setNewProgram(Module *M); + private: /// ParseInputFile - Given a bytecode or assembly input filename, parse and /// return it, or return null if not possible. diff --git a/tools/bugpoint/CrashDebugger.cpp b/tools/bugpoint/CrashDebugger.cpp index 92b8f7c12c8..3a64e94eba4 100644 --- a/tools/bugpoint/CrashDebugger.cpp +++ b/tools/bugpoint/CrashDebugger.cpp @@ -31,10 +31,10 @@ using namespace llvm; namespace llvm { - class DebugCrashes : public ListReducer { + class ReducePassList : public ListReducer { BugDriver &BD; public: - DebugCrashes(BugDriver &bd) : BD(bd) {} + ReducePassList(BugDriver &bd) : BD(bd) {} // doTest - Return true iff running the "removed" passes succeeds, and // running the "Kept" passes fail when run on the output of the "removed" @@ -45,9 +45,9 @@ namespace llvm { }; } -DebugCrashes::TestResult -DebugCrashes::doTest(std::vector &Prefix, - std::vector &Suffix) { +ReducePassList::TestResult +ReducePassList::doTest(std::vector &Prefix, + std::vector &Suffix) { std::string PrefixOutput; Module *OrigProgram = 0; if (!Prefix.empty()) { @@ -104,7 +104,7 @@ namespace llvm { bool ReduceCrashingFunctions::TestFuncs(std::vector &Funcs) { // Clone the program to try hacking it apart... - Module *M = CloneModule(BD.Program); + Module *M = CloneModule(BD.getProgram()); // Convert list to set for fast lookup... std::set Functions; @@ -131,17 +131,15 @@ bool ReduceCrashingFunctions::TestFuncs(std::vector &Funcs) { DeleteFunctionBody(I); // Try running the hacked up program... - std::swap(BD.Program, M); - if (BD.runPasses(BD.PassesToRun)) { - delete M; // It crashed, keep the trimmed version... + if (BD.runPasses(M)) { + BD.setNewProgram(M); // It crashed, keep the trimmed version... // Make sure to use function pointers that point into the now-current // module. Funcs.assign(Functions.begin(), Functions.end()); return true; } - delete BD.Program; // It didn't crash, revert... - BD.Program = M; + delete M; return false; } @@ -172,7 +170,7 @@ namespace llvm { bool ReduceCrashingBlocks::TestBlocks(std::vector &BBs) { // Clone the program to try hacking it apart... - Module *M = CloneModule(BD.Program); + Module *M = CloneModule(BD.getProgram()); // Convert list to set for fast lookup... std::set Blocks; @@ -237,9 +235,8 @@ bool ReduceCrashingBlocks::TestBlocks(std::vector &BBs) { Passes.run(*M); // Try running on the hacked up program... - std::swap(BD.Program, M); - if (BD.runPasses(BD.PassesToRun)) { - delete M; // It crashed, keep the trimmed version... + if (BD.runPasses(M)) { + BD.setNewProgram(M); // It crashed, keep the trimmed version... // Make sure to use basic block pointers that point into the now-current // module, and that they don't include any deleted blocks. @@ -252,11 +249,15 @@ bool ReduceCrashingBlocks::TestBlocks(std::vector &BBs) { } return true; } - delete BD.Program; // It didn't crash, revert... - BD.Program = M; + delete M; // It didn't crash, try something else. return false; } +static bool TestForOptimizerCrash(BugDriver &BD) { + return BD.runPasses(); +} + + /// debugOptimizerCrash - This method is called when some pass crashes on input. /// It attempts to prune down the testcase to something reasonable, and figure /// out exactly which pass is crashing. @@ -267,7 +268,7 @@ bool BugDriver::debugOptimizerCrash() { // Reduce the list of passes which causes the optimizer to crash... unsigned OldSize = PassesToRun.size(); - DebugCrashes(*this).reduceList(PassesToRun); + ReducePassList(*this).reduceList(PassesToRun); std::cout << "\n*** Found crashing pass" << (PassesToRun.size() == 1 ? ": " : "es: ") @@ -292,15 +293,13 @@ bool BugDriver::debugOptimizerCrash() { } else { // See if the program still causes a crash... std::cout << "\nChecking to see if we can delete global inits: "; - std::swap(Program, M); - if (runPasses(PassesToRun)) { // Still crashes? + if (runPasses(M)) { // Still crashes? + setNewProgram(M); AnyReduction = true; - delete M; std::cout << "\n*** Able to remove all global initializers!\n"; } else { // No longer crashes? - delete Program; // Restore program. - Program = M; std::cout << " - Removing all global inits hides problem!\n"; + delete M; } } } @@ -365,23 +364,19 @@ bool BugDriver::debugOptimizerCrash() { 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 (runPasses(PassesToRun)) { + if (runPasses(M)) { // Yup, it does, we delete the old module, and continue trying to // reduce the testcase... - delete M; + setNewProgram(M); AnyReduction = true; 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; + delete M; } } } while (Simplification); @@ -390,16 +385,13 @@ bool BugDriver::debugOptimizerCrash() { std::cout << "\n*** Attempting to perform final cleanups: "; Module *M = CloneModule(Program); M = performFinalCleanups(M, true); - std::swap(Program, M); // Find out if the pass still crashes on the cleaned up program... - if (runPasses(PassesToRun)) { - // Yup, it does, keep the reduced version... - delete M; + if (runPasses(M)) { + setNewProgram(M); // Yup, it does, keep the reduced version... AnyReduction = true; } else { - delete Program; // Otherwise, restore the original module... - Program = M; + delete M; } if (AnyReduction) @@ -414,6 +406,7 @@ bool BugDriver::debugOptimizerCrash() { /// crashes on an input. It attempts to reduce the input as much as possible /// while still causing the code generator to crash. bool BugDriver::debugCodeGeneratorCrash() { + std::cerr << "*** Debugging code generator crash!\n"; return false; }