diff --git a/tools/bugpoint/BugDriver.h b/tools/bugpoint/BugDriver.h index 51798d29a56..192ed527178 100644 --- a/tools/bugpoint/BugDriver.h +++ b/tools/bugpoint/BugDriver.h @@ -35,6 +35,10 @@ class GCC; extern bool DisableSimplifyCFG; +/// BugpointIsInterrupted - Set to true when the user presses ctrl-c. +/// +extern bool BugpointIsInterrupted; + class BugDriver { const std::string ToolName; // Name of bugpoint std::string ReferenceOutputFile; // Name of `good' output file diff --git a/tools/bugpoint/CrashDebugger.cpp b/tools/bugpoint/CrashDebugger.cpp index b63ce219e89..0d04b2563fe 100644 --- a/tools/bugpoint/CrashDebugger.cpp +++ b/tools/bugpoint/CrashDebugger.cpp @@ -261,8 +261,6 @@ bool ReduceCrashingBlocks::TestBlocks(std::vector &BBs) { /// on a program, try to destructively reduce the program while still keeping /// the predicate true. static bool DebugACrash(BugDriver &BD, bool (*TestFn)(BugDriver &, Module *)) { - bool AnyReduction = false; - // See if we can get away with nuking all of the global variable initializers // in the program... if (BD.getProgram()->global_begin() != BD.getProgram()->global_end()) { @@ -282,7 +280,6 @@ static bool DebugACrash(BugDriver &BD, bool (*TestFn)(BugDriver &, Module *)) { std::cout << "\nChecking to see if we can delete global inits: "; if (TestFn(BD, M)) { // Still crashes? BD.setNewProgram(M); - AnyReduction = true; std::cout << "\n*** Able to remove all global initializers!\n"; } else { // No longer crashes? std::cout << " - Removing all global inits hides problem!\n"; @@ -298,17 +295,15 @@ static bool DebugACrash(BugDriver &BD, bool (*TestFn)(BugDriver &, Module *)) { if (!I->isExternal()) Functions.push_back(I); - if (Functions.size() > 1) { + if (Functions.size() > 1 && !BugpointIsInterrupted) { std::cout << "\n*** Attempting to reduce the number of functions " "in the testcase\n"; unsigned OldSize = Functions.size(); ReduceCrashingFunctions(BD, TestFn).reduceList(Functions); - if (Functions.size() < OldSize) { + if (Functions.size() < OldSize) BD.EmitProgressBytecode("reduced-function"); - AnyReduction = true; - } } // Attempt to delete entire basic blocks at a time to speed up @@ -316,7 +311,7 @@ static bool DebugACrash(BugDriver &BD, bool (*TestFn)(BugDriver &, Module *)) { // to a return instruction then running simplifycfg, which can potentially // shrinks the code dramatically quickly // - if (!DisableSimplifyCFG) { + if (!DisableSimplifyCFG && !BugpointIsInterrupted) { std::vector Blocks; for (Module::const_iterator I = BD.getProgram()->begin(), E = BD.getProgram()->end(); I != E; ++I) @@ -329,6 +324,7 @@ static bool DebugACrash(BugDriver &BD, bool (*TestFn)(BugDriver &, Module *)) { // larger chunks of instructions at a time! unsigned Simplification = 2; do { + if (BugpointIsInterrupted) break; --Simplification; std::cout << "\n*** Attempting to reduce testcase by deleting instruc" << "tions: Simplification Level #" << Simplification << '\n'; @@ -357,6 +353,8 @@ static bool DebugACrash(BugDriver &BD, bool (*TestFn)(BugDriver &, Module *)) { if (InstructionsToSkipBeforeDeleting) { --InstructionsToSkipBeforeDeleting; } else { + if (BugpointIsInterrupted) goto ExitLoops; + std::cout << "Checking instruction '" << I->getName() << "': "; Module *M = BD.deleteInstructionFromProgram(I, Simplification); @@ -365,7 +363,6 @@ static bool DebugACrash(BugDriver &BD, bool (*TestFn)(BugDriver &, Module *)) { // Yup, it does, we delete the old module, and continue trying // to reduce the testcase... BD.setNewProgram(M); - AnyReduction = true; InstructionsToSkipBeforeDeleting = CurInstructionNum; goto TryAgain; // I wish I had a multi-level break here! } @@ -381,22 +378,23 @@ static bool DebugACrash(BugDriver &BD, bool (*TestFn)(BugDriver &, Module *)) { } } while (Simplification); +ExitLoops: // Try to clean up the testcase by running funcresolve and globaldce... - std::cout << "\n*** Attempting to perform final cleanups: "; - Module *M = CloneModule(BD.getProgram()); - M = BD.performFinalCleanups(M, true); + if (!BugpointIsInterrupted) { + std::cout << "\n*** Attempting to perform final cleanups: "; + Module *M = CloneModule(BD.getProgram()); + M = BD.performFinalCleanups(M, true); - // Find out if the pass still crashes on the cleaned up program... - if (TestFn(BD, M)) { - BD.setNewProgram(M); // Yup, it does, keep the reduced version... - AnyReduction = true; - } else { - delete M; + // Find out if the pass still crashes on the cleaned up program... + if (TestFn(BD, M)) { + BD.setNewProgram(M); // Yup, it does, keep the reduced version... + } else { + delete M; + } } - if (AnyReduction) - BD.EmitProgressBytecode("reduced-simplified"); + BD.EmitProgressBytecode("reduced-simplified"); return false; } @@ -414,7 +412,8 @@ bool BugDriver::debugOptimizerCrash() { // Reduce the list of passes which causes the optimizer to crash... unsigned OldSize = PassesToRun.size(); - ReducePassList(*this).reduceList(PassesToRun); + if (!BugpointIsInterrupted) + ReducePassList(*this).reduceList(PassesToRun); std::cout << "\n*** Found crashing pass" << (PassesToRun.size() == 1 ? ": " : "es: ") diff --git a/tools/bugpoint/ListReducer.h b/tools/bugpoint/ListReducer.h index daeadba8854..ff2a11d5e91 100644 --- a/tools/bugpoint/ListReducer.h +++ b/tools/bugpoint/ListReducer.h @@ -19,6 +19,8 @@ #include namespace llvm { + + extern bool BugpointIsInterrupted; template struct ListReducer { @@ -62,6 +64,12 @@ struct ListReducer { unsigned MidTop = TheList.size(); while (MidTop > 1) { + // Halt if the user presses ctrl-c. + if (BugpointIsInterrupted) { + std::cerr << "\n\n*** Reduction Interrupted, cleaning up...\n\n"; + return true; + } + unsigned Mid = MidTop / 2; std::vector Prefix(TheList.begin(), TheList.begin()+Mid); std::vector Suffix(TheList.begin()+Mid, TheList.end()); @@ -97,6 +105,11 @@ struct ListReducer { Changed = false; std::vector TrimmedList; for (unsigned i = 1; i < TheList.size()-1; ++i) { // Check interior elts + if (BugpointIsInterrupted) { + std::cerr << "\n\n*** Reduction Interrupted, cleaning up...\n\n"; + return true; + } + std::vector TestList(TheList); TestList.erase(TestList.begin()+i); diff --git a/tools/bugpoint/Miscompilation.cpp b/tools/bugpoint/Miscompilation.cpp index dc43126670c..834e6879958 100644 --- a/tools/bugpoint/Miscompilation.cpp +++ b/tools/bugpoint/Miscompilation.cpp @@ -407,6 +407,8 @@ bool ReduceMiscompiledBlocks::TestFuncs(const std::vector &BBs) { static bool ExtractBlocks(BugDriver &BD, bool (*TestFn)(BugDriver &, Module *, Module *), std::vector &MiscompiledFunctions) { + if (BugpointIsInterrupted) return false; + std::vector Blocks; for (unsigned i = 0, e = MiscompiledFunctions.size(); i != e; ++i) for (Function::iterator I = MiscompiledFunctions[i]->begin(), @@ -493,7 +495,8 @@ DebugAMiscompilation(BugDriver &BD, MiscompiledFunctions.push_back(I); // Do the reduction... - ReduceMiscompilingFunctions(BD, TestFn).reduceList(MiscompiledFunctions); + if (!BugpointIsInterrupted) + ReduceMiscompilingFunctions(BD, TestFn).reduceList(MiscompiledFunctions); std::cout << "\n*** The following function" << (MiscompiledFunctions.size() == 1 ? " is" : "s are") @@ -513,7 +516,8 @@ DebugAMiscompilation(BugDriver &BD, DisambiguateGlobalSymbols(BD.getProgram()); // Do the reduction... - ReduceMiscompilingFunctions(BD, TestFn).reduceList(MiscompiledFunctions); + if (!BugpointIsInterrupted) + ReduceMiscompilingFunctions(BD, TestFn).reduceList(MiscompiledFunctions); std::cout << "\n*** The following function" << (MiscompiledFunctions.size() == 1 ? " is" : "s are") @@ -570,11 +574,12 @@ static bool TestOptimizer(BugDriver &BD, Module *Test, Module *Safe) { /// bool BugDriver::debugMiscompilation() { // Make sure something was miscompiled... - if (!ReduceMiscompilingPasses(*this).reduceList(PassesToRun)) { - std::cerr << "*** Optimized program matches reference output! No problem " - << "detected...\nbugpoint can't help you with your problem!\n"; - return false; - } + if (!BugpointIsInterrupted) + if (!ReduceMiscompilingPasses(*this).reduceList(PassesToRun)) { + std::cerr << "*** Optimized program matches reference output! No problem" + << " detected...\nbugpoint can't help you with your problem!\n"; + return false; + } std::cout << "\n*** Found miscompiling pass" << (getPassesToRun().size() == 1 ? "" : "es") << ": " @@ -663,7 +668,7 @@ static void CleanupAndPrepareModules(BugDriver &BD, Module *&Test, for (Module::iterator F = Safe->begin(), E = Safe->end(); F != E; ++F) { if (F->isExternal() && !F->use_empty() && &*F != resolverFunc && F->getIntrinsicID() == 0 /* ignore intrinsics */) { - Function *TestFn = Test->getFunction(F->getName(), F->getFunctionType()); + Function *TestFn = Test->getNamedFunction(F->getName()); // Don't forward functions which are external in the test module too. if (TestFn && !TestFn->isExternal()) { diff --git a/tools/bugpoint/bugpoint.cpp b/tools/bugpoint/bugpoint.cpp index 3cbb4c0ff67..a4442c7ef97 100644 --- a/tools/bugpoint/bugpoint.cpp +++ b/tools/bugpoint/bugpoint.cpp @@ -32,13 +32,21 @@ InputFilenames(cl::Positional, cl::OneOrMore, static cl::list PassList(cl::desc("Passes available:"), cl::ZeroOrMore); +/// BugpointIsInterrupted - Set to true when the user presses ctrl-c. +bool llvm::BugpointIsInterrupted = false; + +static void BugpointInterruptFunction() { + BugpointIsInterrupted = true; +} + int main(int argc, char **argv) { cl::ParseCommandLineOptions(argc, argv, " LLVM automatic testcase reducer. See\nhttp://" "llvm.cs.uiuc.edu/docs/CommandGuide/bugpoint.html" " for more information.\n"); sys::PrintStackTraceOnErrorSignal(); - + sys::SetInterruptFunction(BugpointInterruptFunction); + BugDriver D(argv[0]); if (D.addSources(InputFilenames)) return 1; D.addPasses(PassList.begin(), PassList.end());