This commit adds a new feature called find-bugs. The find-bugs option can be invoked on a .bc file from the command like with -find-bugs and a list of passes you wish to test. This procedure takes the set of optimization passes the user specifies, randomizes the passes, runs the passes on the specified .bc file, compiles the program, and finally runs the program checking its output vs the .bc file with no optimizations. This process repeats until either the user kills bugpoint or an error occurs in the optimizations, program complitation, or the running of the program. If an error occurs, bugpoint attempts to diagnose the error by eliminating passes that are not at fault and code that is not needed.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@29703 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Patrick Jenkins 2006-08-15 16:40:49 +00:00
parent 19af0e1b49
commit 6a3f31cb70
5 changed files with 73 additions and 26 deletions

View File

@ -62,10 +62,11 @@ std::string llvm::getPassesString(const std::vector<const PassInfo*> &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()) {

View File

@ -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<const PassInfo*> &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<const PassInfo*> &AllPasses);
/// writeProgramToFile - This writes the current "Program" to the named
/// bytecode file. If an error occurs, true is returned.

View File

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

View File

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

View File

@ -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<bool>
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<bool>
FindBugs("find-bugs", cl::desc("Run many different optimization sequences"
"on program to find bugs"), cl::init(false));
static cl::list<std::string>
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());