llvm/tools/bugpoint/Miscompilation.cpp
Chris Lattner 4a10645c70 New files for miscompilation detection
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@5120 91177308-0d34-0410-b5e6-96231b3b80d8
2002-12-23 23:50:16 +00:00

142 lines
5.1 KiB
C++

//===- Miscompilation.cpp - Debug program miscompilations -----------------===//
//
// This file implements program miscompilation debugging support.
//
//===----------------------------------------------------------------------===//
#include "BugDriver.h"
#include "SystemUtils.h"
#include "llvm/Pass.h"
#include "llvm/Module.h"
#include "Support/CommandLine.h"
// Anonymous namespace to define command line options for miscompilation
// debugging.
//
namespace {
// Output - The user can specify a file containing the expected output of the
// program. If this filename is set, it is used as the reference diff source,
// otherwise the raw input run through an interpreter is used as the reference
// source.
//
cl::opt<std::string>
Output("output", cl::desc("Specify a reference program output "
"(for miscompilation detection)"));
}
/// 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";
// Set up the execution environment, selecting a method to run LLVM bytecode.
if (initializeExecutionEnvironment()) return true;
// Run the raw input to see where we are coming from. If a reference output
// was specified, make sure that the raw output matches it. If not, it's a
// problem in the front-end or whatever produced the input code.
//
bool CreatedOutput = false;
if (Output.empty()) {
std::cout << "Generating reference output from raw program...";
Output = executeProgram("bugpoint.reference.out");
CreatedOutput = true;
std::cout << " done!\n";
} else if (diffProgram(Output)) {
std::cout << "\n*** Input program does not match reference diff!\n"
<< " Must be problem with input source!\n";
return false; // Problem found
}
// Figure out which transformation is the first to miscompile the input
// program. We do a binary search here in case there are a large number of
// passes involved.
//
unsigned LastGood = 0, LastBad = PassesToRun.size();
while (LastGood != LastBad) {
unsigned Mid = (LastBad+LastGood+1) / 2;
std::vector<const PassInfo*> P(PassesToRun.begin(),
PassesToRun.begin()+Mid);
std::cout << "Checking to see if the first " << Mid << " passes are ok: ";
std::string BytecodeResult;
if (runPasses(P, BytecodeResult, false, true)) {
std::cerr << ToolName << ": Error running this sequence of passes"
<< " on the input program!\n";
exit(1);
}
// Check to see if the finished program matches the reference output...
if (diffProgram(Output, BytecodeResult)) {
std::cout << "nope.\n";
LastBad = Mid-1; // Miscompilation detected!
} else {
std::cout << "yup.\n";
LastGood = Mid; // No miscompilation!
}
// We are now done with the optimized output... so remove it.
removeFile(BytecodeResult);
}
// Make sure something was miscompiled...
if (LastBad >= PassesToRun.size()) {
std::cerr << "*** Optimized program matches reference output! No problem "
<< "detected...\nbugpoint can't help you with your problem!\n";
return false;
}
// Calculate which pass it is that miscompiles...
const PassInfo *ThePass = PassesToRun[LastBad];
std::cout << "\n*** Found miscompiling pass '-" << ThePass->getPassArgument()
<< "': " << ThePass->getPassName() << "\n";
if (LastGood != 0) {
std::vector<const PassInfo*> P(PassesToRun.begin(),
PassesToRun.begin()+LastGood);
std::string Filename;
std::cout << "Running good passes to get input for pass:";
if (runPasses(P, Filename, false, true)) {
std::cerr << "ERROR: Running the first " << LastGood
<< " passes crashed!\n";
return true;
}
std::cout << " done!\n";
// Assuming everything was successful, we now have a valid bytecode file in
// OutputName. Use it for "Program" Instead.
delete Program;
Program = ParseInputFile(Filename);
// Delete the file now.
removeFile(Filename);
}
bool Result = debugPassMiscompilation(ThePass, Output);
if (CreatedOutput) removeFile(Output);
return Result;
}
/// 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 BugDriver::debugPassMiscompilation(const PassInfo *Pass,
const std::string &ReferenceOutput) {
EmitProgressBytecode(Pass, "passinput");
// Loop over all of the functions in the program, attempting to find one that
// is being miscompiled. We do this by extracting the function into a module,
// running the "bad" optimization on that module, then linking it back into
// the program. If the program fails the diff, the function got misoptimized.
//
return false;
}