//===- ExecutionDriver.cpp - Allow execution of LLVM program --------------===//
-//
+//
// The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
-//
+//
//===----------------------------------------------------------------------===//
//
// This file contains code used to execute the program utilizing one of the
//===----------------------------------------------------------------------===//
#include "BugDriver.h"
-#include "llvm/Support/ToolRunner.h"
-#include "Support/CommandLine.h"
-#include "Support/Debug.h"
-#include "Support/FileUtilities.h"
-#include "Support/SystemUtils.h"
+#include "ToolRunner.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/FileUtilities.h"
+#include "llvm/Support/SystemUtils.h"
#include <fstream>
#include <iostream>
+
using namespace llvm;
namespace {
AutoPick, RunLLI, RunJIT, RunLLC, RunCBE
};
+ cl::opt<double>
+ AbsTolerance("abs-tolerance", cl::desc("Absolute error tolerated"),
+ cl::init(0.0));
+ cl::opt<double>
+ RelTolerance("rel-tolerance", cl::desc("Relative error tolerated"),
+ cl::init(0.0));
+
cl::opt<OutputType>
InterpreterSel(cl::desc("Specify how LLVM code should be executed:"),
cl::values(clEnumValN(AutoPick, "auto", "Use best guess"),
cl::opt<bool>
CheckProgramExitCode("check-exit-code",
- cl::desc("Assume nonzero exit code is failure (default on)"),
+ cl::desc("Assume nonzero exit code is failure (default on)"),
cl::init(true));
cl::opt<std::string>
AdditionalSOs("additional-so",
cl::desc("Additional shared objects to load "
"into executing programs"));
+
+ cl::list<std::string>
+ AdditionalLinkerArgs("Xlinker",
+ cl::desc("Additional arguments to pass to the linker"));
}
namespace llvm {
///
void BugDriver::compileProgram(Module *M) {
// Emit the program to a bytecode file...
- std::string BytecodeFile = getUniqueFilename("bugpoint-test-program.bc");
- if (writeProgramToFile(BytecodeFile, M)) {
+ sys::Path BytecodeFile ("bugpoint-test-program.bc");
+ BytecodeFile.makeUnique();
+ if (writeProgramToFile(BytecodeFile.toString(), M)) {
std::cerr << ToolName << ": Error emitting bytecode to file '"
<< BytecodeFile << "'!\n";
exit(1);
FileRemover BytecodeFileRemover(BytecodeFile);
// Actually compile the program!
- Interpreter->compileProgram(BytecodeFile);
+ Interpreter->compileProgram(BytecodeFile.toString());
}
bool CreatedBytecode = false;
if (BytecodeFile.empty()) {
// Emit the program to a bytecode file...
- BytecodeFile = getUniqueFilename("bugpoint-test-program.bc");
+ sys::Path uniqueFilename("bugpoint-test-program.bc");
+ uniqueFilename.makeUnique();
+ BytecodeFile = uniqueFilename.toString();
if (writeProgramToFile(BytecodeFile, Program)) {
std::cerr << ToolName << ": Error emitting bytecode to file '"
}
// Remove the temporary bytecode file when we are done.
- FileRemover BytecodeFileRemover(BytecodeFile, CreatedBytecode);
+ sys::Path BytecodePath (BytecodeFile);
+ FileRemover BytecodeFileRemover(BytecodePath, CreatedBytecode);
if (OutputFile.empty()) OutputFile = "bugpoint-execution-output";
// Check to see if this is a valid output filename...
- OutputFile = getUniqueFilename(OutputFile);
+ sys::Path uniqueFile(OutputFile);
+ uniqueFile.makeUnique();
+ OutputFile = uniqueFile.toString();
// Figure out which shared objects to run, if any.
std::vector<std::string> SharedObjs(AdditionalSOs);
if (!SharedObj.empty())
SharedObjs.push_back(SharedObj);
- // Actually execute the program!
- int RetVal = AI->ExecuteProgram(BytecodeFile, InputArgv, InputFile,
- OutputFile, SharedObjs);
+
+ // If this is an LLC or CBE run, then the GCC compiler might get run to
+ // compile the program. If so, we should pass the user's -Xlinker options
+ // as the GCCArgs.
+ int RetVal = 0;
+ if (InterpreterSel == RunLLC || InterpreterSel == RunCBE)
+ RetVal = AI->ExecuteProgram(BytecodeFile, InputArgv, InputFile,
+ OutputFile, AdditionalLinkerArgs, SharedObjs,
+ Timeout);
+ else
+ RetVal = AI->ExecuteProgram(BytecodeFile, InputArgv, InputFile,
+ OutputFile, std::vector<std::string>(),
+ SharedObjs, Timeout);
+
+ if (RetVal == -1) {
+ std::cerr << "<timeout>";
+ static bool FirstTimeout = true;
+ if (FirstTimeout) {
+ std::cout << "\n"
+ "*** Program execution timed out! This mechanism is designed to handle\n"
+ " programs stuck in infinite loops gracefully. The -timeout option\n"
+ " can be used to change the timeout threshold or disable it completely\n"
+ " (with -timeout=0). This message is only displayed once.\n";
+ FirstTimeout = false;
+ }
+ }
if (ProgramExitedNonzero != 0)
*ProgramExitedNonzero = (RetVal != 0);
std::string BugDriver::compileSharedObject(const std::string &BytecodeFile) {
assert(Interpreter && "Interpreter should have been created already!");
- std::string OutputCFile;
+ sys::Path OutputCFile;
// Using CBE
cbe->OutputC(BytecodeFile, OutputCFile);
#endif
std::string SharedObjectFile;
- if (gcc->MakeSharedObject(OutputCFile, GCC::CFile, SharedObjectFile))
+ if (gcc->MakeSharedObject(OutputCFile.toString(), GCC::CFile,
+ SharedObjectFile, AdditionalLinkerArgs))
exit(1);
// Remove the intermediate C file
- removeFile(OutputCFile);
+ OutputCFile.eraseFromDisk();
return "./" + SharedObjectFile;
}
bool ProgramExitedNonzero;
// Execute the program, generating an output file...
- std::string Output = executeProgram("", BytecodeFile, SharedObject, 0,
- &ProgramExitedNonzero);
+ sys::Path Output(executeProgram("", BytecodeFile, SharedObject, 0,
+ &ProgramExitedNonzero));
// If we're checking the program exit code, assume anything nonzero is bad.
if (CheckProgramExitCode && ProgramExitedNonzero) {
- removeFile(Output);
- if (RemoveBytecode) removeFile(BytecodeFile);
+ Output.eraseFromDisk();
+ if (RemoveBytecode)
+ sys::Path(BytecodeFile).eraseFromDisk();
return true;
}
std::string Error;
bool FilesDifferent = false;
- if (DiffFiles(ReferenceOutputFile, Output, &Error)) {
- if (!Error.empty()) {
- std::cerr << "While diffing output: " << Error << "\n";
+ if (int Diff = DiffFilesWithTolerance(sys::Path(ReferenceOutputFile),
+ sys::Path(Output.toString()),
+ AbsTolerance, RelTolerance, &Error)) {
+ if (Diff == 2) {
+ std::cerr << "While diffing output: " << Error << '\n';
exit(1);
}
FilesDifferent = true;
}
-
+
// Remove the generated output.
- removeFile(Output);
+ Output.eraseFromDisk();
// Remove the bytecode file if we are supposed to.
- if (RemoveBytecode) removeFile(BytecodeFile);
+ if (RemoveBytecode)
+ sys::Path(BytecodeFile).eraseFromDisk();
return FilesDifferent;
}