Implement the start of the miscompilation detection stuff

llvm-svn: 5119
This commit is contained in:
Chris Lattner 2002-12-23 23:49:59 +00:00
parent f3628b3d67
commit d4e0474dcf
5 changed files with 65 additions and 56 deletions

View File

@ -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;
}

View File

@ -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<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.
@ -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<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
@ -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<const PassInfo*>(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

View File

@ -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<const PassInfo*> 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;
}

View File

@ -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

View File

@ -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 <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;
}
@ -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,22 +96,10 @@ static void RunChild(Module *Program,const std::vector<const PassInfo*> &Passes,
/// 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;
// 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);
OutputFilename = getUniqueFilename("bugpoint-output.bc");
pid_t child_pid;
switch (child_pid = fork()) {
@ -143,7 +126,7 @@ bool BugDriver::runPasses(const std::vector<const PassInfo*> &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;