diff --git a/tools/bugpoint/BugDriver.cpp b/tools/bugpoint/BugDriver.cpp index 0343f6381d6..c204ab45b29 100644 --- a/tools/bugpoint/BugDriver.cpp +++ b/tools/bugpoint/BugDriver.cpp @@ -82,19 +82,3 @@ bool BugDriver::run() { else return debugMiscompilation(); } - - -/// debugMiscompilation - This method is used when the passes selected are not -/// crashing, but the generated output is semantically different from the -/// input. -/// -bool BugDriver::debugMiscompilation() { - std::cout << "*** Debugging miscompilation!\n"; - std::cerr << "Sorry, bugpoint cannot debug a miscompilation yet!\n"; - - // If no reference output was specified, run the program without optimizations - // to get a reference output. - // - - return true; -} diff --git a/tools/bugpoint/BugDriver.h b/tools/bugpoint/BugDriver.h index f419249afa0..6398366d8cf 100644 --- a/tools/bugpoint/BugDriver.h +++ b/tools/bugpoint/BugDriver.h @@ -14,13 +14,18 @@ class PassInfo; class Module; class Function; +class AbstractInterpreter; class BugDriver { const std::string ToolName; // Name of bugpoint Module *Program; // The raw program, linked together std::vector PassesToRun; + AbstractInterpreter *Interpreter; // How to run the program public: - BugDriver(const char *toolname) : ToolName(toolname), Program(0) {} + BugDriver(const char *toolname) + : ToolName(toolname), Program(0), Interpreter(0) {} + + const std::string &getToolName() const { return ToolName; } // Set up methods... these methods are used to copy information about the // command line arguments into instance variables of BugDriver. @@ -51,20 +56,25 @@ public: /// input. bool debugMiscompilation(); + /// debugPassMiscompilation - This method is called when the specified pass + /// miscompiles Program as input. It tries to reduce the testcase to + /// something that smaller that still miscompiles the program. + /// ReferenceOutput contains the filename of the file containing the output we + /// are to match. + /// + bool debugPassMiscompilation(const PassInfo *ThePass, + const std::string &ReferenceOutput); + private: /// ParseInputFile - Given a bytecode or assembly input filename, parse and /// return it, or return null if not possible. /// Module *ParseInputFile(const std::string &InputFilename) const; - /// removeFile - Delete the specified file - /// - void removeFile(const std::string &Filename) const; - /// writeProgramToFile - This writes the current "Program" to the named /// bytecode file. If an error occurs, true is returned. /// - bool writeProgramToFile(const std::string &Filename) const; + bool writeProgramToFile(const std::string &Filename, Module *M = 0) const; /// EmitProgressBytecode - This function is used to output the current Program @@ -78,10 +88,11 @@ private: /// otherwise return false. If DeleteOutput is set to true, the bytecode is /// deleted on success, and the filename string is undefined. This prints to /// cout a single line message indicating whether compilation was successful - /// or failed. + /// or failed, unless Quiet is set. /// bool runPasses(const std::vector &PassesToRun, - std::string &OutputFilename, bool DeleteOutput = false) const; + std::string &OutputFilename, bool DeleteOutput = false, + bool Quiet = false) const; /// runPasses - Just like the method above, but this just returns true or /// false indicating whether or not the optimizer crashed on the specified @@ -94,6 +105,7 @@ private: } /// runPass - Run only the specified pass on the program. + /// bool runPass(const PassInfo *P, bool DeleteOutput = true) const { return runPasses(std::vector(1, P), DeleteOutput); } @@ -102,8 +114,27 @@ private: /// (non-external) function from the current program, slim down the module, /// and then return it. This does not modify Program at all, it modifies a /// copy, which it returns. + /// Module *extractFunctionFromModule(Function *F) const; + /// initializeExecutionEnvironment - This method is used to set up the + /// environment for executing LLVM programs. + /// + bool initializeExecutionEnvironment(); + + /// executeProgram - This method runs "Program", capturing the output of the + /// program to a file, returning the filename of the file. A recommended + /// filename may be optionally specified. + /// + std::string executeProgram(std::string RequestedOutputFilename = "", + std::string Bytecode = ""); + + /// 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. + /// + bool diffProgram(const std::string &ReferenceOutputFile, + const std::string &BytecodeFile = ""); }; #endif diff --git a/tools/bugpoint/CrashDebugger.cpp b/tools/bugpoint/CrashDebugger.cpp index 3c4fa2dd479..c69ca453621 100644 --- a/tools/bugpoint/CrashDebugger.cpp +++ b/tools/bugpoint/CrashDebugger.cpp @@ -5,6 +5,7 @@ //===----------------------------------------------------------------------===// #include "BugDriver.h" +#include "SystemUtils.h" #include "llvm/Module.h" #include "llvm/Bytecode/Writer.h" #include "llvm/Pass.h" @@ -44,8 +45,7 @@ bool BugDriver::debugCrash() { << "': " << CrashingPass->getPassName() << "\n"; // Compile the program with just the passes that don't crash. - if (LastToPass != 0) { - // Don't bother doing this if the first pass crashes... + if (LastToPass != 0) { // Don't bother doing this if the first pass crashes... std::vector P(PassesToRun.begin(), PassesToRun.begin()+LastToPass); std::string Filename; @@ -87,7 +87,7 @@ bool BugDriver::debugPassCrash(const PassInfo *Pass) { if (CountFunctions(Program) > 1) { // Attempt to reduce the input program down to a single function that still - // crashes. + // crashes. Do this by removing everything except for that one function... // std::cout << "\n*** Attempting to reduce the testcase to one function\n"; @@ -116,5 +116,16 @@ bool BugDriver::debugPassCrash(const PassInfo *Pass) { } } + 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. + // + return false; } diff --git a/tools/bugpoint/Makefile b/tools/bugpoint/Makefile index 43f1c91d300..a648a3c4759 100644 --- a/tools/bugpoint/Makefile +++ b/tools/bugpoint/Makefile @@ -2,10 +2,10 @@ LEVEL = ../.. TOOLNAME = bugpoint -OPTLIBS = instrument profpaths scalaropts ipo -ANALIBS = datastructure ipa target.a analysis +#OPTLIBS = instrument profpaths +ANALIBS = datastructure ipa target.a -USEDLIBS = ipo scalaropts $(ANALIBS) \ +USEDLIBS = ipo scalaropts analysis $(OPTLIBS) $(ANALIBS) \ transformutils asmparser bcreader bcwriter vmcore support TOOLLINKOPTS = -ldl diff --git a/tools/bugpoint/OptimizerDriver.cpp b/tools/bugpoint/OptimizerDriver.cpp index 26a6ae70fe6..aae5791935c 100644 --- a/tools/bugpoint/OptimizerDriver.cpp +++ b/tools/bugpoint/OptimizerDriver.cpp @@ -9,6 +9,7 @@ //===----------------------------------------------------------------------===// #include "BugDriver.h" +#include "SystemUtils.h" #include "llvm/PassManager.h" #include "llvm/Analysis/Verifier.h" #include "llvm/Bytecode/WriteBytecodePass.h" @@ -18,20 +19,14 @@ #include #include -/// removeFile - Delete the specified file -/// -void BugDriver::removeFile(const std::string &Filename) const { - unlink(Filename.c_str()); -} - /// writeProgramToFile - This writes the current "Program" to the named bytecode /// file. If an error occurs, true is returned. /// -bool BugDriver::writeProgramToFile(const std::string &Filename) const { +bool BugDriver::writeProgramToFile(const std::string &Filename, + Module *M) const { std::ofstream Out(Filename.c_str()); if (!Out.good()) return true; - - WriteBytecodeToFile(Program, Out); + WriteBytecodeToFile(M ? M : Program, Out); return false; } @@ -50,7 +45,7 @@ void BugDriver::EmitProgressBytecode(const PassInfo *Pass, return; } - std::cout << "Emitted bytecode to 'bugpoint-" << Filename << ".bc'\n"; + std::cout << "Emitted bytecode to '" << Filename << "'\n"; std::cout << "\n*** You can reproduce the problem with: "; unsigned PassType = Pass->getPassType(); @@ -101,23 +96,11 @@ static void RunChild(Module *Program,const std::vector &Passes, /// failed. /// bool BugDriver::runPasses(const std::vector &Passes, - std::string &OutputFilename, bool DeleteOutput) const{ + std::string &OutputFilename, bool DeleteOutput, + bool Quiet) const{ std::cout << std::flush; + OutputFilename = getUniqueFilename("bugpoint-output.bc"); - // Agree on a temporary file name to use.... - char FNBuffer[] = "bugpoint-output.bc-XXXXXX"; - int TempFD; - if ((TempFD = mkstemp(FNBuffer)) == -1) { - std::cerr << ToolName << ": ERROR: Cannot create temporary" - << " file in the current directory!\n"; - exit(1); - } - OutputFilename = FNBuffer; - - // We don't need to hold the temp file descriptor... we will trust that noone - // will overwrite/delete the file while we are working on it... - close(TempFD); - pid_t child_pid; switch (child_pid = fork()) { case -1: // Error occurred @@ -143,7 +126,7 @@ bool BugDriver::runPasses(const std::vector &Passes, if (DeleteOutput) removeFile(OutputFilename); - std::cout << (Status ? "Crashed!\n" : "Success!\n"); + if (!Quiet) std::cout << (Status ? "Crashed!\n" : "Success!\n"); // Was the child successful? return Status != 0;