#include "llvm/Support/Debug.h"
#include "llvm/Support/FileUtilities.h"
#include "llvm/Support/SystemUtils.h"
+#include "llvm/Support/raw_ostream.h"
#include <fstream>
using namespace llvm;
// for miscompilation.
//
enum OutputType {
- AutoPick, RunLLI, RunJIT, RunLLC, RunCBE, CBE_bug, LLC_Safe, Custom
+ AutoPick, RunLLI, RunJIT, RunLLC, RunLLCIA, RunCBE, CBE_bug, LLC_Safe,Custom
};
cl::opt<double>
"Execute with the interpreter"),
clEnumValN(RunJIT, "run-jit", "Execute with JIT"),
clEnumValN(RunLLC, "run-llc", "Compile with LLC"),
+ clEnumValN(RunLLCIA, "run-llc-ia",
+ "Compile with LLC with integrated assembler"),
clEnumValN(RunCBE, "run-cbe", "Compile with CBE"),
clEnumValN(CBE_bug,"cbe-bug", "Find CBE bugs"),
clEnumValN(LLC_Safe, "llc-safe", "Use LLC for all"),
cl::list<std::string>
InputArgv("args", cl::Positional, cl::desc("<program arguments>..."),
cl::ZeroOrMore, cl::PositionalEatsArgs);
+
+ cl::opt<std::string>
+ OutputPrefix("output-prefix", cl::init("bugpoint"),
+ cl::desc("Prefix to use for outputs (default: 'bugpoint')"));
}
namespace {
&ToolArgv);
break;
case RunLLC:
+ case RunLLCIA:
case LLC_Safe:
Interpreter = AbstractInterpreter::createLLC(getToolName(), Message,
- &ToolArgv, &GCCToolArgv);
+ &ToolArgv, &GCCToolArgv,
+ InterpreterSel == RunLLCIA);
break;
case RunJIT:
Interpreter = AbstractInterpreter::createJIT(getToolName(), Message,
}
break;
case RunLLC:
+ case RunLLCIA:
SafeToolArgs.push_back("--relocation-model=pic");
SafeInterpreter = AbstractInterpreter::createLLC(Path.c_str(), Message,
&SafeToolArgs,
- &GCCToolArgv);
+ &GCCToolArgv,
+ SafeInterpreterSel == RunLLCIA);
break;
case RunCBE:
SafeInterpreter = AbstractInterpreter::createCBE(Path.c_str(), Message,
return Interpreter == 0;
}
-/// compileProgram - Try to compile the specified module, throwing an exception
-/// if an error occurs, or returning normally if not. This is used for code
-/// generation crash testing.
+/// compileProgram - Try to compile the specified module, returning false and
+/// setting Error if an error occurs. This is used for code generation
+/// crash testing.
///
-void BugDriver::compileProgram(Module *M) {
+void BugDriver::compileProgram(Module *M, std::string *Error) {
// Emit the program to a bitcode file...
- sys::Path BitcodeFile ("bugpoint-test-program.bc");
+ sys::Path BitcodeFile (OutputPrefix + "-test-program.bc");
std::string ErrMsg;
- if (BitcodeFile.makeUnique(true,&ErrMsg)) {
+ if (BitcodeFile.makeUnique(true, &ErrMsg)) {
errs() << ToolName << ": Error making unique filename: " << ErrMsg
<< "\n";
exit(1);
}
- if (writeProgramToFile(BitcodeFile.toString(), M)) {
+ if (writeProgramToFile(BitcodeFile.str(), M)) {
errs() << ToolName << ": Error emitting bitcode to file '"
- << BitcodeFile << "'!\n";
+ << BitcodeFile.str() << "'!\n";
exit(1);
}
- // Remove the temporary bitcode file when we are done.
+ // Remove the temporary bitcode file when we are done.
FileRemover BitcodeFileRemover(BitcodeFile, !SaveTemps);
// Actually compile the program!
- Interpreter->compileProgram(BitcodeFile.toString());
+ Interpreter->compileProgram(BitcodeFile.str(), Error);
}
std::string BitcodeFile,
const std::string &SharedObj,
AbstractInterpreter *AI,
- bool *ProgramExitedNonzero) {
+ std::string *Error) {
if (AI == 0) AI = Interpreter;
assert(AI && "Interpreter should have been created already!");
bool CreatedBitcode = false;
std::string ErrMsg;
if (BitcodeFile.empty()) {
// Emit the program to a bitcode file...
- sys::Path uniqueFilename("bugpoint-test-program.bc");
+ sys::Path uniqueFilename(OutputPrefix + "-test-program.bc");
if (uniqueFilename.makeUnique(true, &ErrMsg)) {
errs() << ToolName << ": Error making unique filename: "
<< ErrMsg << "!\n";
exit(1);
}
- BitcodeFile = uniqueFilename.toString();
+ BitcodeFile = uniqueFilename.str();
if (writeProgramToFile(BitcodeFile, Program)) {
errs() << ToolName << ": Error emitting bitcode to file '"
}
// Remove the temporary bitcode file when we are done.
- sys::Path BitcodePath (BitcodeFile);
+ sys::Path BitcodePath(BitcodeFile);
FileRemover BitcodeFileRemover(BitcodePath, CreatedBitcode && !SaveTemps);
- if (OutputFile.empty()) OutputFile = "bugpoint-execution-output";
+ if (OutputFile.empty()) OutputFile = OutputPrefix + "-execution-output";
// Check to see if this is a valid output filename...
sys::Path uniqueFile(OutputFile);
<< ErrMsg << "\n";
exit(1);
}
- OutputFile = uniqueFile.toString();
+ OutputFile = uniqueFile.str();
// Figure out which shared objects to run, if any.
std::vector<std::string> SharedObjs(AdditionalSOs);
if (!SharedObj.empty())
SharedObjs.push_back(SharedObj);
- int RetVal = AI->ExecuteProgram(BitcodeFile, InputArgv, InputFile,
- OutputFile, AdditionalLinkerArgs, SharedObjs,
+ int RetVal = AI->ExecuteProgram(BitcodeFile, InputArgv, InputFile, OutputFile,
+ Error, AdditionalLinkerArgs, SharedObjs,
Timeout, MemoryLimit);
+ if (!Error->empty())
+ return OutputFile;
if (RetVal == -1) {
errs() << "<timeout>";
outFile.close();
}
- if (ProgramExitedNonzero != 0)
- *ProgramExitedNonzero = (RetVal != 0);
-
// Return the filename we captured the output to.
return OutputFile;
}
/// executeProgramSafely - Used to create reference output with the "safe"
/// backend, if reference output is not provided.
///
-std::string BugDriver::executeProgramSafely(std::string OutputFile) {
- bool ProgramExitedNonzero;
- std::string outFN = executeProgram(OutputFile, "", "", SafeInterpreter,
- &ProgramExitedNonzero);
- return outFN;
+std::string BugDriver::executeProgramSafely(std::string OutputFile,
+ std::string *Error) {
+ return executeProgram(OutputFile, "", "", SafeInterpreter, Error);
}
-std::string BugDriver::compileSharedObject(const std::string &BitcodeFile) {
+std::string BugDriver::compileSharedObject(const std::string &BitcodeFile,
+ std::string &Error) {
assert(Interpreter && "Interpreter should have been created already!");
sys::Path OutputFile;
// Using the known-good backend.
- GCC::FileType FT = SafeInterpreter->OutputCode(BitcodeFile, OutputFile);
+ GCC::FileType FT = SafeInterpreter->OutputCode(BitcodeFile, OutputFile,
+ Error);
+ if (!Error.empty())
+ return "";
std::string SharedObjectFile;
- if (gcc->MakeSharedObject(OutputFile.toString(), FT,
- SharedObjectFile, AdditionalLinkerArgs))
+ bool Failure = gcc->MakeSharedObject(OutputFile.str(), FT, SharedObjectFile,
+ AdditionalLinkerArgs, Error);
+ if (!Error.empty())
+ return "";
+ if (Failure)
exit(1);
// Remove the intermediate C file
/// this function.
///
bool BugDriver::createReferenceFile(Module *M, const std::string &Filename) {
- try {
- compileProgram(Program);
- } catch (ToolExecutionError &) {
+ std::string Error;
+ compileProgram(Program, &Error);
+ if (!Error.empty())
return false;
- }
- try {
- ReferenceOutputFile = executeProgramSafely(Filename);
- outs() << "\nReference output is: " << ReferenceOutputFile << "\n\n";
- } catch (ToolExecutionError &TEE) {
- errs() << TEE.what();
+
+ ReferenceOutputFile = executeProgramSafely(Filename, &Error);
+ if (!Error.empty()) {
+ errs() << Error;
if (Interpreter != SafeInterpreter) {
errs() << "*** There is a bug running the \"safe\" backend. Either"
<< " debug it (for example with the -run-cbe bugpoint option,"
}
return false;
}
+ outs() << "\nReference output is: " << ReferenceOutputFile << "\n\n";
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. If there is a problem with the code
-/// generator (e.g., llc crashes), this will throw an exception.
+/// is different, 1 is returned. If there is a problem with the code
+/// generator (e.g., llc crashes), this will return -1 and set Error.
///
bool BugDriver::diffProgram(const std::string &BitcodeFile,
const std::string &SharedObject,
- bool RemoveBitcode) {
- bool ProgramExitedNonzero;
-
+ bool RemoveBitcode,
+ std::string *ErrMsg) {
// Execute the program, generating an output file...
- sys::Path Output(executeProgram("", BitcodeFile, SharedObject, 0,
- &ProgramExitedNonzero));
+ sys::Path Output(executeProgram("", BitcodeFile, SharedObject, 0, ErrMsg));
+ if (!ErrMsg->empty())
+ return false;
std::string Error;
bool FilesDifferent = false;
if (int Diff = DiffFilesWithTolerance(sys::Path(ReferenceOutputFile),
- sys::Path(Output.toString()),
+ sys::Path(Output.str()),
AbsTolerance, RelTolerance, &Error)) {
if (Diff == 2) {
errs() << "While diffing output: " << Error << '\n';