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;
-}
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<const PassInfo*> 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.
/// 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
/// 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<const PassInfo*> &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
}
/// runPass - Run only the specified pass on the program.
+ ///
bool runPass(const PassInfo *P, bool DeleteOutput = true) const {
return runPasses(std::vector<const PassInfo*>(1, P), DeleteOutput);
}
/// (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
//===----------------------------------------------------------------------===//
#include "BugDriver.h"
+#include "SystemUtils.h"
#include "llvm/Module.h"
#include "llvm/Bytecode/Writer.h"
#include "llvm/Pass.h"
<< "': " << 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<const PassInfo*> P(PassesToRun.begin(),
PassesToRun.begin()+LastToPass);
std::string Filename;
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";
}
}
+ 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;
}
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
//===----------------------------------------------------------------------===//
#include "BugDriver.h"
+#include "SystemUtils.h"
#include "llvm/PassManager.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/Bytecode/WriteBytecodePass.h"
#include <stdlib.h>
#include <fstream>
-/// 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;
}
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();
/// failed.
///
bool BugDriver::runPasses(const std::vector<const PassInfo*> &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
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;