diff --git a/tools/bugpoint/BugDriver.cpp b/tools/bugpoint/BugDriver.cpp index f8beb2a64c2..9d82e8b3ccb 100644 --- a/tools/bugpoint/BugDriver.cpp +++ b/tools/bugpoint/BugDriver.cpp @@ -62,10 +62,11 @@ std::string llvm::getPassesString(const std::vector &Passes) { return Result; } -BugDriver::BugDriver(const char *toolname, bool as_child, unsigned timeout) +BugDriver::BugDriver(const char *toolname, bool as_child, bool find_bugs, + unsigned timeout) : ToolName(toolname), ReferenceOutputFile(OutputFile), Program(0), Interpreter(0), cbe(0), gcc(0), run_as_child(as_child), - Timeout(timeout) {} + run_find_bugs(find_bugs), Timeout(timeout) {} /// ParseInputFile - Given a bytecode or assembly input filename, parse and @@ -140,6 +141,12 @@ bool BugDriver::run() { // Execute the passes return runPassesAsChild(PassesToRun); } + + if (run_find_bugs) { + // Rearrange the passes and apply them to the program. Repeat this process + // until the user kills the program or we find a bug. + return runManyPasses(PassesToRun); + } // If we're not running as a child, the first thing that we must do is // determine what the problem is. Does the optimization series crash the @@ -175,20 +182,10 @@ bool BugDriver::run() { bool CreatedOutput = false; if (ReferenceOutputFile.empty()) { std::cout << "Generating reference output from raw program: "; - try { - ReferenceOutputFile = executeProgramWithCBE("bugpoint.reference.out"); - CreatedOutput = true; - std::cout << "Reference output is: " << ReferenceOutputFile << '\n'; - } catch (ToolExecutionError &TEE) { - std::cerr << TEE.what(); - if (Interpreter != cbe) { - std::cerr << "*** There is a bug running the C backend. Either debug" - << " it (use the -run-cbe bugpoint option), or fix the error" - << " some other way.\n"; - return 1; - } - return debugCodeGeneratorCrash(); + if(!createReferenceFile(Program)){ + return debugCodeGeneratorCrash(); } + CreatedOutput = true; } // Make sure the reference output file gets deleted on exit from this @@ -197,7 +194,8 @@ bool BugDriver::run() { FileRemover RemoverInstance(ROF, CreatedOutput); // Diff the output of the raw program against the reference output. If it - // matches, then we have a miscompilation bug. + // matches, then we assume there is a miscompilation bug and try to + // diagnose it. std::cout << "*** Checking the code generator...\n"; try { if (!diffProgram()) { diff --git a/tools/bugpoint/BugDriver.h b/tools/bugpoint/BugDriver.h index ec687b3c7bc..ced7df81baf 100644 --- a/tools/bugpoint/BugDriver.h +++ b/tools/bugpoint/BugDriver.h @@ -48,6 +48,7 @@ class BugDriver { CBE *cbe; GCC *gcc; bool run_as_child; + bool run_find_bugs; unsigned Timeout; // FIXME: sort out public/private distinctions... @@ -55,7 +56,8 @@ class BugDriver { friend class ReduceMisCodegenFunctions; public: - BugDriver(const char *toolname, bool as_child, unsigned timeout); + BugDriver(const char *toolname, bool as_child, bool find_bugs, + unsigned timeout); const std::string &getToolName() const { return ToolName; } @@ -82,7 +84,7 @@ public: /// crashes on input. It attempts to prune down the testcase to something /// reasonable, and figure out exactly which pass is crashing. /// - bool debugOptimizerCrash(); + bool debugOptimizerCrash(const std::string &ID = "passes"); /// debugCodeGeneratorCrash - This method is called when the code generator /// crashes on an input. It attempts to reduce the input as much as possible @@ -175,6 +177,13 @@ public: /// std::string executeProgramWithCBE(std::string OutputFile = ""); + /// createReferenceFile - calls compileProgram and then records the output + /// into ReferenceOutputFile. Returns true if reference file created, false + /// otherwise. Note: initializeExecutionEnvironment should be called BEFORE + /// this function. + /// + bool createReferenceFile(Module *M, const std::string &Filename = "bugpoint.reference.out"); + /// diffProgram - This method executes the specified module and diffs the /// output against the file specified by ReferenceOutputFile. If the output /// is different, true is returned. If there is a problem with the code @@ -183,6 +192,7 @@ public: bool diffProgram(const std::string &BytecodeFile = "", const std::string &SharedObj = "", bool RemoveBytecode = false); + /// EmitProgressBytecode - This function is used to output the current Program /// to a file named "bugpoint-ID.bc". /// @@ -235,6 +245,15 @@ public: bool runPasses(const std::vector &PassesToRun, std::string &OutputFilename, bool DeleteOutput = false, bool Quiet = false) const; + + /// runManyPasses - Take the specified pass list and create different + /// combinations of passes to compile the program with. Compile the program with + /// each set and mark test to see if it compiled correctly. If the passes + /// compiled correctly output nothing and rearrange the passes into a new order. + /// If the passes did not compile correctly, output the command required to + /// recreate the failure. This returns true if a compiler error is found. + /// + bool runManyPasses(const std::vector &AllPasses); /// writeProgramToFile - This writes the current "Program" to the named /// bytecode file. If an error occurs, true is returned. diff --git a/tools/bugpoint/CrashDebugger.cpp b/tools/bugpoint/CrashDebugger.cpp index 2e2ab20fa04..63926464e23 100644 --- a/tools/bugpoint/CrashDebugger.cpp +++ b/tools/bugpoint/CrashDebugger.cpp @@ -423,7 +423,7 @@ static bool TestForOptimizerCrash(BugDriver &BD, Module *M) { /// It attempts to prune down the testcase to something reasonable, and figure /// out exactly which pass is crashing. /// -bool BugDriver::debugOptimizerCrash() { +bool BugDriver::debugOptimizerCrash(const std::string &ID) { std::cout << "\n*** Debugging optimizer crash!\n"; // Reduce the list of passes which causes the optimizer to crash... @@ -435,7 +435,7 @@ bool BugDriver::debugOptimizerCrash() { << (PassesToRun.size() == 1 ? ": " : "es: ") << getPassesString(PassesToRun) << '\n'; - EmitProgressBytecode("passinput"); + EmitProgressBytecode(ID); return DebugACrash(*this, TestForOptimizerCrash); } diff --git a/tools/bugpoint/ExecutionDriver.cpp b/tools/bugpoint/ExecutionDriver.cpp index 453833eb8df..93eef5dbc56 100644 --- a/tools/bugpoint/ExecutionDriver.cpp +++ b/tools/bugpoint/ExecutionDriver.cpp @@ -297,10 +297,36 @@ std::string BugDriver::compileSharedObject(const std::string &BytecodeFile) { return "./" + SharedObjectFile; } +/// createReferenceFile - calls compileProgram and then records the output +/// into ReferenceOutputFile. Returns true if reference file created, false +/// otherwise. Note: initializeExecutionEnvironment should be called BEFORE +/// this function. +/// +bool BugDriver::createReferenceFile(Module *M, const std::string &Filename){ + try { + compileProgram(Program); + } catch (ToolExecutionError &TEE) { + return false; + } + try { + ReferenceOutputFile = executeProgramWithCBE(Filename); + std::cout << "Reference output is: " << ReferenceOutputFile << "\n\n"; + } catch (ToolExecutionError &TEE) { + std::cerr << TEE.what(); + if (Interpreter != cbe) { + std::cerr << "*** There is a bug running the C backend. Either debug" + << " it (use the -run-cbe bugpoint option), or fix the error" + << " some other way.\n"; + } + return false; + } + return true; +} -/// diffProgram - This method executes the specified module and diffs the output -/// against the file specified by ReferenceOutputFile. If the output is -/// different, true is returned. +/// diffProgram - This method executes the specified module and diffs the +/// output against the file specified by ReferenceOutputFile. If the output +/// is different, true is returned. If there is a problem with the code +/// generator (e.g., llc crashes), this will throw an exception. /// bool BugDriver::diffProgram(const std::string &BytecodeFile, const std::string &SharedObject, diff --git a/tools/bugpoint/bugpoint.cpp b/tools/bugpoint/bugpoint.cpp index cc05fea6508..353e117369a 100644 --- a/tools/bugpoint/bugpoint.cpp +++ b/tools/bugpoint/bugpoint.cpp @@ -29,8 +29,12 @@ using namespace llvm; // from a parent process. It is not intended to be used by users so the // option is hidden. static cl::opt - AsChild("as-child", cl::desc("Run bugpoint as child process"), - cl::ReallyHidden); +AsChild("as-child", cl::desc("Run bugpoint as child process"), + cl::ReallyHidden); + +static cl::opt +FindBugs("find-bugs", cl::desc("Run many different optimization sequences" + "on program to find bugs"), cl::init(false)); static cl::list InputFilenames(cl::Positional, cl::OneOrMore, @@ -62,7 +66,7 @@ int main(int argc, char **argv) { sys::PrintStackTraceOnErrorSignal(); sys::SetInterruptFunction(BugpointInterruptFunction); - BugDriver D(argv[0],AsChild,TimeoutValue); + BugDriver D(argv[0],AsChild,FindBugs,TimeoutValue); if (D.addSources(InputFilenames)) return 1; D.addPasses(PassList.begin(), PassList.end());