forked from OSchip/llvm-project
Implement the start of the miscompilation detection stuff
llvm-svn: 5119
This commit is contained in:
parent
f3628b3d67
commit
d4e0474dcf
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue