forked from OSchip/llvm-project
bugpoint: clang-format all of bugpoint. NFC
I'm going to clean up the APIs here a bit and touch many many lines anyway. llvm-svn: 280450
This commit is contained in:
parent
bc46927659
commit
8d0a08115a
|
@ -29,20 +29,20 @@
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
Triple TargetTriple;
|
Triple TargetTriple;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Anonymous namespace to define command line options for debugging.
|
// Anonymous namespace to define command line options for debugging.
|
||||||
//
|
//
|
||||||
namespace {
|
namespace {
|
||||||
// Output - The user can specify a file containing the expected output of the
|
// 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,
|
// 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
|
// otherwise the raw input run through an interpreter is used as the reference
|
||||||
// source.
|
// source.
|
||||||
//
|
//
|
||||||
cl::opt<std::string>
|
cl::opt<std::string> OutputFile("output",
|
||||||
OutputFile("output", cl::desc("Specify a reference program output "
|
cl::desc("Specify a reference program output "
|
||||||
"(for miscompilation detection)"));
|
"(for miscompilation detection)"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// setNewProgram - If we reduce or update the program somehow, call this method
|
/// setNewProgram - If we reduce or update the program somehow, call this method
|
||||||
|
@ -53,27 +53,26 @@ void BugDriver::setNewProgram(Module *M) {
|
||||||
Program = M;
|
Program = M;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// getPassesString - Turn a list of passes into a string which indicates the
|
/// getPassesString - Turn a list of passes into a string which indicates the
|
||||||
/// command line options that must be passed to add the passes.
|
/// command line options that must be passed to add the passes.
|
||||||
///
|
///
|
||||||
std::string llvm::getPassesString(const std::vector<std::string> &Passes) {
|
std::string llvm::getPassesString(const std::vector<std::string> &Passes) {
|
||||||
std::string Result;
|
std::string Result;
|
||||||
for (unsigned i = 0, e = Passes.size(); i != e; ++i) {
|
for (unsigned i = 0, e = Passes.size(); i != e; ++i) {
|
||||||
if (i) Result += " ";
|
if (i)
|
||||||
|
Result += " ";
|
||||||
Result += "-";
|
Result += "-";
|
||||||
Result += Passes[i];
|
Result += Passes[i];
|
||||||
}
|
}
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
BugDriver::BugDriver(const char *toolname, bool find_bugs,
|
BugDriver::BugDriver(const char *toolname, bool find_bugs, unsigned timeout,
|
||||||
unsigned timeout, unsigned memlimit, bool use_valgrind,
|
unsigned memlimit, bool use_valgrind, LLVMContext &ctxt)
|
||||||
LLVMContext& ctxt)
|
: Context(ctxt), ToolName(toolname), ReferenceOutputFile(OutputFile),
|
||||||
: Context(ctxt), ToolName(toolname), ReferenceOutputFile(OutputFile),
|
Program(nullptr), Interpreter(nullptr), SafeInterpreter(nullptr),
|
||||||
Program(nullptr), Interpreter(nullptr), SafeInterpreter(nullptr),
|
cc(nullptr), run_find_bugs(find_bugs), Timeout(timeout),
|
||||||
cc(nullptr), run_find_bugs(find_bugs), Timeout(timeout),
|
MemoryLimit(memlimit), UseValgrind(use_valgrind) {}
|
||||||
MemoryLimit(memlimit), UseValgrind(use_valgrind) {}
|
|
||||||
|
|
||||||
BugDriver::~BugDriver() {
|
BugDriver::~BugDriver() {
|
||||||
delete Program;
|
delete Program;
|
||||||
|
@ -123,13 +122,15 @@ bool BugDriver::addSources(const std::vector<std::string> &Filenames) {
|
||||||
|
|
||||||
// Load the first input file.
|
// Load the first input file.
|
||||||
Program = parseInputFile(Filenames[0], Context).release();
|
Program = parseInputFile(Filenames[0], Context).release();
|
||||||
if (!Program) return true;
|
if (!Program)
|
||||||
|
return true;
|
||||||
|
|
||||||
outs() << "Read input file : '" << Filenames[0] << "'\n";
|
outs() << "Read input file : '" << Filenames[0] << "'\n";
|
||||||
|
|
||||||
for (unsigned i = 1, e = Filenames.size(); i != e; ++i) {
|
for (unsigned i = 1, e = Filenames.size(); i != e; ++i) {
|
||||||
std::unique_ptr<Module> M = parseInputFile(Filenames[i], Context);
|
std::unique_ptr<Module> M = parseInputFile(Filenames[i], Context);
|
||||||
if (!M.get()) return true;
|
if (!M.get())
|
||||||
|
return true;
|
||||||
|
|
||||||
outs() << "Linking in input file: '" << Filenames[i] << "'\n";
|
outs() << "Linking in input file: '" << Filenames[i] << "'\n";
|
||||||
if (Linker::linkModules(*Program, std::move(M)))
|
if (Linker::linkModules(*Program, std::move(M)))
|
||||||
|
@ -142,8 +143,6 @@ bool BugDriver::addSources(const std::vector<std::string> &Filenames) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// run - The top level method that is invoked after all of the instance
|
/// run - The top level method that is invoked after all of the instance
|
||||||
/// variables are set up from command line arguments.
|
/// variables are set up from command line arguments.
|
||||||
///
|
///
|
||||||
|
@ -168,7 +167,8 @@ bool BugDriver::run(std::string &ErrMsg) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up the execution environment, selecting a method to run LLVM bitcode.
|
// Set up the execution environment, selecting a method to run LLVM bitcode.
|
||||||
if (initializeExecutionEnvironment()) return true;
|
if (initializeExecutionEnvironment())
|
||||||
|
return true;
|
||||||
|
|
||||||
// Test to see if we have a code generator crash.
|
// Test to see if we have a code generator crash.
|
||||||
outs() << "Running the code generator to test for a crash: ";
|
outs() << "Running the code generator to test for a crash: ";
|
||||||
|
@ -227,9 +227,10 @@ bool BugDriver::run(std::string &ErrMsg) {
|
||||||
return Failure;
|
return Failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
void llvm::PrintFunctionList(const std::vector<Function*> &Funcs) {
|
void llvm::PrintFunctionList(const std::vector<Function *> &Funcs) {
|
||||||
unsigned NumPrint = Funcs.size();
|
unsigned NumPrint = Funcs.size();
|
||||||
if (NumPrint > 10) NumPrint = 10;
|
if (NumPrint > 10)
|
||||||
|
NumPrint = 10;
|
||||||
for (unsigned i = 0; i != NumPrint; ++i)
|
for (unsigned i = 0; i != NumPrint; ++i)
|
||||||
outs() << " " << Funcs[i]->getName();
|
outs() << " " << Funcs[i]->getName();
|
||||||
if (NumPrint < Funcs.size())
|
if (NumPrint < Funcs.size())
|
||||||
|
@ -237,9 +238,10 @@ void llvm::PrintFunctionList(const std::vector<Function*> &Funcs) {
|
||||||
outs().flush();
|
outs().flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
void llvm::PrintGlobalVariableList(const std::vector<GlobalVariable*> &GVs) {
|
void llvm::PrintGlobalVariableList(const std::vector<GlobalVariable *> &GVs) {
|
||||||
unsigned NumPrint = GVs.size();
|
unsigned NumPrint = GVs.size();
|
||||||
if (NumPrint > 10) NumPrint = 10;
|
if (NumPrint > 10)
|
||||||
|
NumPrint = 10;
|
||||||
for (unsigned i = 0; i != NumPrint; ++i)
|
for (unsigned i = 0; i != NumPrint; ++i)
|
||||||
outs() << " " << GVs[i]->getName();
|
outs() << " " << GVs[i]->getName();
|
||||||
if (NumPrint < GVs.size())
|
if (NumPrint < GVs.size())
|
||||||
|
|
|
@ -45,13 +45,13 @@ extern bool DisableSimplifyCFG;
|
||||||
extern bool BugpointIsInterrupted;
|
extern bool BugpointIsInterrupted;
|
||||||
|
|
||||||
class BugDriver {
|
class BugDriver {
|
||||||
LLVMContext& Context;
|
LLVMContext &Context;
|
||||||
const char *ToolName; // argv[0] of bugpoint
|
const char *ToolName; // argv[0] of bugpoint
|
||||||
std::string ReferenceOutputFile; // Name of `good' output file
|
std::string ReferenceOutputFile; // Name of `good' output file
|
||||||
Module *Program; // The raw program, linked together
|
Module *Program; // The raw program, linked together
|
||||||
std::vector<std::string> PassesToRun;
|
std::vector<std::string> PassesToRun;
|
||||||
AbstractInterpreter *Interpreter; // How to run the program
|
AbstractInterpreter *Interpreter; // How to run the program
|
||||||
AbstractInterpreter *SafeInterpreter; // To generate reference output, etc.
|
AbstractInterpreter *SafeInterpreter; // To generate reference output, etc.
|
||||||
CC *cc;
|
CC *cc;
|
||||||
bool run_find_bugs;
|
bool run_find_bugs;
|
||||||
unsigned Timeout;
|
unsigned Timeout;
|
||||||
|
@ -63,14 +63,13 @@ class BugDriver {
|
||||||
friend class ReduceMisCodegenFunctions;
|
friend class ReduceMisCodegenFunctions;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BugDriver(const char *toolname, bool find_bugs,
|
BugDriver(const char *toolname, bool find_bugs, unsigned timeout,
|
||||||
unsigned timeout, unsigned memlimit, bool use_valgrind,
|
unsigned memlimit, bool use_valgrind, LLVMContext &ctxt);
|
||||||
LLVMContext& ctxt);
|
|
||||||
~BugDriver();
|
~BugDriver();
|
||||||
|
|
||||||
const char *getToolName() const { return ToolName; }
|
const char *getToolName() const { return ToolName; }
|
||||||
|
|
||||||
LLVMContext& getContext() const { return Context; }
|
LLVMContext &getContext() const { return Context; }
|
||||||
|
|
||||||
// Set up methods... these methods are used to copy information about the
|
// Set up methods... these methods are used to copy information about the
|
||||||
// command line arguments into instance variables of BugDriver.
|
// command line arguments into instance variables of BugDriver.
|
||||||
|
@ -80,9 +79,7 @@ public:
|
||||||
void setPassesToRun(const std::vector<std::string> &PTR) {
|
void setPassesToRun(const std::vector<std::string> &PTR) {
|
||||||
PassesToRun = PTR;
|
PassesToRun = PTR;
|
||||||
}
|
}
|
||||||
const std::vector<std::string> &getPassesToRun() const {
|
const std::vector<std::string> &getPassesToRun() const { return PassesToRun; }
|
||||||
return PassesToRun;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// run - The top level method that is invoked after all of the instance
|
/// run - The top level method that is invoked after all of the instance
|
||||||
/// variables are set up from command line arguments. The \p as_child argument
|
/// variables are set up from command line arguments. The \p as_child argument
|
||||||
|
@ -142,13 +139,11 @@ public:
|
||||||
|
|
||||||
AbstractInterpreter *switchToSafeInterpreter() {
|
AbstractInterpreter *switchToSafeInterpreter() {
|
||||||
AbstractInterpreter *Old = Interpreter;
|
AbstractInterpreter *Old = Interpreter;
|
||||||
Interpreter = (AbstractInterpreter*)SafeInterpreter;
|
Interpreter = (AbstractInterpreter *)SafeInterpreter;
|
||||||
return Old;
|
return Old;
|
||||||
}
|
}
|
||||||
|
|
||||||
void switchToInterpreter(AbstractInterpreter *AI) {
|
void switchToInterpreter(AbstractInterpreter *AI) { Interpreter = AI; }
|
||||||
Interpreter = AI;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// setNewProgram - If we reduce or update the program somehow, call this
|
/// setNewProgram - If we reduce or update the program somehow, call this
|
||||||
/// method to update bugdriver with it. This deletes the old module and sets
|
/// method to update bugdriver with it. This deletes the old module and sets
|
||||||
|
@ -164,12 +159,10 @@ public:
|
||||||
/// executeProgram - This method runs "Program", capturing the output of the
|
/// executeProgram - This method runs "Program", capturing the output of the
|
||||||
/// program to a file. A recommended filename may be optionally specified.
|
/// program to a file. A recommended filename may be optionally specified.
|
||||||
///
|
///
|
||||||
std::string executeProgram(const Module *Program,
|
std::string executeProgram(const Module *Program, std::string OutputFilename,
|
||||||
std::string OutputFilename,
|
|
||||||
std::string Bitcode,
|
std::string Bitcode,
|
||||||
const std::string &SharedObjects,
|
const std::string &SharedObjects,
|
||||||
AbstractInterpreter *AI,
|
AbstractInterpreter *AI, std::string *Error) const;
|
||||||
std::string *Error) const;
|
|
||||||
|
|
||||||
/// executeProgramSafely - Used to create reference output with the "safe"
|
/// executeProgramSafely - Used to create reference output with the "safe"
|
||||||
/// backend, if reference output is not provided. If there is a problem with
|
/// backend, if reference output is not provided. If there is a problem with
|
||||||
|
@ -181,20 +174,19 @@ public:
|
||||||
std::string *Error) const;
|
std::string *Error) const;
|
||||||
|
|
||||||
/// createReferenceFile - calls compileProgram and then records the output
|
/// createReferenceFile - calls compileProgram and then records the output
|
||||||
/// into ReferenceOutputFile. Returns true if reference file created, false
|
/// into ReferenceOutputFile. Returns true if reference file created, false
|
||||||
/// otherwise. Note: initializeExecutionEnvironment should be called BEFORE
|
/// otherwise. Note: initializeExecutionEnvironment should be called BEFORE
|
||||||
/// this function.
|
/// this function.
|
||||||
///
|
///
|
||||||
bool createReferenceFile(Module *M, const std::string &Filename
|
bool createReferenceFile(Module *M, const std::string &Filename =
|
||||||
= "bugpoint.reference.out-%%%%%%%");
|
"bugpoint.reference.out-%%%%%%%");
|
||||||
|
|
||||||
/// diffProgram - This method executes the specified module and diffs the
|
/// diffProgram - This method executes the specified module and diffs the
|
||||||
/// output against the file specified by ReferenceOutputFile. If the output
|
/// output against the file specified by ReferenceOutputFile. If the output
|
||||||
/// is different, 1 is returned. If there is a problem with the code
|
/// 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.
|
/// generator (e.g., llc crashes), this will return -1 and set Error.
|
||||||
///
|
///
|
||||||
bool diffProgram(const Module *Program,
|
bool diffProgram(const Module *Program, const std::string &BitcodeFile = "",
|
||||||
const std::string &BitcodeFile = "",
|
|
||||||
const std::string &SharedObj = "",
|
const std::string &SharedObj = "",
|
||||||
bool RemoveBitcode = false,
|
bool RemoveBitcode = false,
|
||||||
std::string *Error = nullptr) const;
|
std::string *Error = nullptr) const;
|
||||||
|
@ -251,27 +243,27 @@ public:
|
||||||
/// or failed, unless Quiet is set. ExtraArgs specifies additional arguments
|
/// or failed, unless Quiet is set. ExtraArgs specifies additional arguments
|
||||||
/// to pass to the child bugpoint instance.
|
/// to pass to the child bugpoint instance.
|
||||||
///
|
///
|
||||||
bool runPasses(Module *Program,
|
bool runPasses(Module *Program, const std::vector<std::string> &PassesToRun,
|
||||||
const std::vector<std::string> &PassesToRun,
|
|
||||||
std::string &OutputFilename, bool DeleteOutput = false,
|
std::string &OutputFilename, bool DeleteOutput = false,
|
||||||
bool Quiet = false, unsigned NumExtraArgs = 0,
|
bool Quiet = false, unsigned NumExtraArgs = 0,
|
||||||
const char * const *ExtraArgs = nullptr) const;
|
const char *const *ExtraArgs = nullptr) const;
|
||||||
|
|
||||||
/// runPasses - Just like the method above, but this just returns true or
|
/// runPasses - Just like the method above, but this just returns true or
|
||||||
/// false indicating whether or not the optimizer crashed on the specified
|
/// false indicating whether or not the optimizer crashed on the specified
|
||||||
/// input (true = crashed). Does not produce any output.
|
/// input (true = crashed). Does not produce any output.
|
||||||
///
|
///
|
||||||
bool runPasses(Module *M,
|
bool runPasses(Module *M, const std::vector<std::string> &PassesToRun) const {
|
||||||
const std::vector<std::string> &PassesToRun) const {
|
|
||||||
std::string Filename;
|
std::string Filename;
|
||||||
return runPasses(M, PassesToRun, Filename, true);
|
return runPasses(M, PassesToRun, Filename, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// runManyPasses - Take the specified pass list and create different
|
/// runManyPasses - Take the specified pass list and create different
|
||||||
/// combinations of passes to compile the program with. Compile the program with
|
/// combinations of passes to compile the program with. Compile the program
|
||||||
/// each set and mark test to see if it compiled correctly. If the passes
|
/// with
|
||||||
/// compiled correctly output nothing and rearrange the passes into a new order.
|
/// each set and mark test to see if it compiled correctly. If the passes
|
||||||
/// If the passes did not compile correctly, output the command required to
|
/// 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.
|
/// recreate the failure. This returns true if a compiler error is found.
|
||||||
///
|
///
|
||||||
bool runManyPasses(const std::vector<std::string> &AllPasses,
|
bool runManyPasses(const std::vector<std::string> &AllPasses,
|
||||||
|
@ -304,11 +296,11 @@ std::string getPassesString(const std::vector<std::string> &Passes);
|
||||||
|
|
||||||
/// PrintFunctionList - prints out list of problematic functions
|
/// PrintFunctionList - prints out list of problematic functions
|
||||||
///
|
///
|
||||||
void PrintFunctionList(const std::vector<Function*> &Funcs);
|
void PrintFunctionList(const std::vector<Function *> &Funcs);
|
||||||
|
|
||||||
/// PrintGlobalVariableList - prints out list of problematic global variables
|
/// PrintGlobalVariableList - prints out list of problematic global variables
|
||||||
///
|
///
|
||||||
void PrintGlobalVariableList(const std::vector<GlobalVariable*> &GVs);
|
void PrintGlobalVariableList(const std::vector<GlobalVariable *> &GVs);
|
||||||
|
|
||||||
// DeleteGlobalInitializer - "Remove" the global variable by deleting its
|
// DeleteGlobalInitializer - "Remove" the global variable by deleting its
|
||||||
// initializer, making it external.
|
// initializer, making it external.
|
||||||
|
|
|
@ -14,9 +14,9 @@
|
||||||
#include "BugDriver.h"
|
#include "BugDriver.h"
|
||||||
#include "ListReducer.h"
|
#include "ListReducer.h"
|
||||||
#include "ToolRunner.h"
|
#include "ToolRunner.h"
|
||||||
#include "llvm/Analysis/TargetTransformInfo.h"
|
|
||||||
#include "llvm/ADT/SmallPtrSet.h"
|
#include "llvm/ADT/SmallPtrSet.h"
|
||||||
#include "llvm/ADT/StringSet.h"
|
#include "llvm/ADT/StringSet.h"
|
||||||
|
#include "llvm/Analysis/TargetTransformInfo.h"
|
||||||
#include "llvm/IR/CFG.h"
|
#include "llvm/IR/CFG.h"
|
||||||
#include "llvm/IR/Constants.h"
|
#include "llvm/IR/Constants.h"
|
||||||
#include "llvm/IR/DerivedTypes.h"
|
#include "llvm/IR/DerivedTypes.h"
|
||||||
|
@ -36,52 +36,49 @@
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
cl::opt<bool>
|
cl::opt<bool> KeepMain("keep-main",
|
||||||
KeepMain("keep-main",
|
cl::desc("Force function reduction to keep main"),
|
||||||
cl::desc("Force function reduction to keep main"),
|
cl::init(false));
|
||||||
cl::init(false));
|
cl::opt<bool> NoGlobalRM("disable-global-remove",
|
||||||
cl::opt<bool>
|
cl::desc("Do not remove global variables"),
|
||||||
NoGlobalRM ("disable-global-remove",
|
cl::init(false));
|
||||||
cl::desc("Do not remove global variables"),
|
|
||||||
cl::init(false));
|
|
||||||
|
|
||||||
cl::opt<bool>
|
cl::opt<bool> ReplaceFuncsWithNull(
|
||||||
ReplaceFuncsWithNull("replace-funcs-with-null",
|
"replace-funcs-with-null",
|
||||||
cl::desc("When stubbing functions, replace all uses will null"),
|
cl::desc("When stubbing functions, replace all uses will null"),
|
||||||
cl::init(false));
|
cl::init(false));
|
||||||
cl::opt<bool>
|
cl::opt<bool> DontReducePassList("disable-pass-list-reduction",
|
||||||
DontReducePassList("disable-pass-list-reduction",
|
cl::desc("Skip pass list reduction steps"),
|
||||||
cl::desc("Skip pass list reduction steps"),
|
cl::init(false));
|
||||||
cl::init(false));
|
|
||||||
|
|
||||||
cl::opt<bool> NoNamedMDRM("disable-namedmd-remove",
|
cl::opt<bool> NoNamedMDRM("disable-namedmd-remove",
|
||||||
cl::desc("Do not remove global named metadata"),
|
cl::desc("Do not remove global named metadata"),
|
||||||
cl::init(false));
|
cl::init(false));
|
||||||
cl::opt<bool> VerboseErrors("verbose-errors",
|
cl::opt<bool> VerboseErrors("verbose-errors",
|
||||||
cl::desc("Print the output of crashing program"),
|
cl::desc("Print the output of crashing program"),
|
||||||
cl::init(false));
|
cl::init(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
class ReducePassList : public ListReducer<std::string> {
|
class ReducePassList : public ListReducer<std::string> {
|
||||||
BugDriver &BD;
|
BugDriver &BD;
|
||||||
public:
|
|
||||||
ReducePassList(BugDriver &bd) : BD(bd) {}
|
|
||||||
|
|
||||||
// doTest - Return true iff running the "removed" passes succeeds, and
|
public:
|
||||||
// running the "Kept" passes fail when run on the output of the "removed"
|
ReducePassList(BugDriver &bd) : BD(bd) {}
|
||||||
// passes. If we return true, we update the current module of bugpoint.
|
|
||||||
//
|
// doTest - Return true iff running the "removed" passes succeeds, and
|
||||||
TestResult doTest(std::vector<std::string> &Removed,
|
// running the "Kept" passes fail when run on the output of the "removed"
|
||||||
std::vector<std::string> &Kept,
|
// passes. If we return true, we update the current module of bugpoint.
|
||||||
std::string &Error) override;
|
//
|
||||||
};
|
TestResult doTest(std::vector<std::string> &Removed,
|
||||||
|
std::vector<std::string> &Kept,
|
||||||
|
std::string &Error) override;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
ReducePassList::TestResult
|
ReducePassList::TestResult
|
||||||
ReducePassList::doTest(std::vector<std::string> &Prefix,
|
ReducePassList::doTest(std::vector<std::string> &Prefix,
|
||||||
std::vector<std::string> &Suffix,
|
std::vector<std::string> &Suffix, std::string &Error) {
|
||||||
std::string &Error) {
|
|
||||||
std::string PrefixOutput;
|
std::string PrefixOutput;
|
||||||
Module *OrigProgram = nullptr;
|
Module *OrigProgram = nullptr;
|
||||||
if (!Prefix.empty()) {
|
if (!Prefix.empty()) {
|
||||||
|
@ -101,11 +98,11 @@ ReducePassList::doTest(std::vector<std::string> &Prefix,
|
||||||
sys::fs::remove(PrefixOutput);
|
sys::fs::remove(PrefixOutput);
|
||||||
}
|
}
|
||||||
|
|
||||||
outs() << "Checking to see if these passes crash: "
|
outs() << "Checking to see if these passes crash: " << getPassesString(Suffix)
|
||||||
<< getPassesString(Suffix) << ": ";
|
<< ": ";
|
||||||
|
|
||||||
if (BD.runPasses(BD.getProgram(), Suffix)) {
|
if (BD.runPasses(BD.getProgram(), Suffix)) {
|
||||||
delete OrigProgram; // The suffix crashes alone...
|
delete OrigProgram; // The suffix crashes alone...
|
||||||
return KeepSuffix;
|
return KeepSuffix;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,44 +115,44 @@ ReducePassList::doTest(std::vector<std::string> &Prefix,
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
/// ReduceCrashingGlobalVariables - This works by removing the global
|
/// ReduceCrashingGlobalVariables - This works by removing the global
|
||||||
/// variable's initializer and seeing if the program still crashes. If it
|
/// variable's initializer and seeing if the program still crashes. If it
|
||||||
/// does, then we keep that program and try again.
|
/// does, then we keep that program and try again.
|
||||||
///
|
///
|
||||||
class ReduceCrashingGlobalVariables : public ListReducer<GlobalVariable*> {
|
class ReduceCrashingGlobalVariables : public ListReducer<GlobalVariable *> {
|
||||||
BugDriver &BD;
|
BugDriver &BD;
|
||||||
bool (*TestFn)(const BugDriver &, Module *);
|
bool (*TestFn)(const BugDriver &, Module *);
|
||||||
public:
|
|
||||||
ReduceCrashingGlobalVariables(BugDriver &bd,
|
public:
|
||||||
bool (*testFn)(const BugDriver &, Module *))
|
ReduceCrashingGlobalVariables(BugDriver &bd,
|
||||||
|
bool (*testFn)(const BugDriver &, Module *))
|
||||||
: BD(bd), TestFn(testFn) {}
|
: BD(bd), TestFn(testFn) {}
|
||||||
|
|
||||||
TestResult doTest(std::vector<GlobalVariable*> &Prefix,
|
TestResult doTest(std::vector<GlobalVariable *> &Prefix,
|
||||||
std::vector<GlobalVariable*> &Kept,
|
std::vector<GlobalVariable *> &Kept,
|
||||||
std::string &Error) override {
|
std::string &Error) override {
|
||||||
if (!Kept.empty() && TestGlobalVariables(Kept))
|
if (!Kept.empty() && TestGlobalVariables(Kept))
|
||||||
return KeepSuffix;
|
return KeepSuffix;
|
||||||
if (!Prefix.empty() && TestGlobalVariables(Prefix))
|
if (!Prefix.empty() && TestGlobalVariables(Prefix))
|
||||||
return KeepPrefix;
|
return KeepPrefix;
|
||||||
return NoFailure;
|
return NoFailure;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TestGlobalVariables(std::vector<GlobalVariable*> &GVs);
|
bool TestGlobalVariables(std::vector<GlobalVariable *> &GVs);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool ReduceCrashingGlobalVariables::TestGlobalVariables(
|
||||||
ReduceCrashingGlobalVariables::TestGlobalVariables(
|
std::vector<GlobalVariable *> &GVs) {
|
||||||
std::vector<GlobalVariable*> &GVs) {
|
|
||||||
// Clone the program to try hacking it apart...
|
// Clone the program to try hacking it apart...
|
||||||
ValueToValueMapTy VMap;
|
ValueToValueMapTy VMap;
|
||||||
Module *M = CloneModule(BD.getProgram(), VMap).release();
|
Module *M = CloneModule(BD.getProgram(), VMap).release();
|
||||||
|
|
||||||
// Convert list to set for fast lookup...
|
// Convert list to set for fast lookup...
|
||||||
std::set<GlobalVariable*> GVSet;
|
std::set<GlobalVariable *> GVSet;
|
||||||
|
|
||||||
for (unsigned i = 0, e = GVs.size(); i != e; ++i) {
|
for (unsigned i = 0, e = GVs.size(); i != e; ++i) {
|
||||||
GlobalVariable* CMGV = cast<GlobalVariable>(VMap[GVs[i]]);
|
GlobalVariable *CMGV = cast<GlobalVariable>(VMap[GVs[i]]);
|
||||||
assert(CMGV && "Global Variable not in module?!");
|
assert(CMGV && "Global Variable not in module?!");
|
||||||
GVSet.insert(CMGV);
|
GVSet.insert(CMGV);
|
||||||
}
|
}
|
||||||
|
@ -175,7 +172,7 @@ ReduceCrashingGlobalVariables::TestGlobalVariables(
|
||||||
|
|
||||||
// Try running the hacked up program...
|
// Try running the hacked up program...
|
||||||
if (TestFn(BD, M)) {
|
if (TestFn(BD, M)) {
|
||||||
BD.setNewProgram(M); // It crashed, keep the trimmed version...
|
BD.setNewProgram(M); // It crashed, keep the trimmed version...
|
||||||
|
|
||||||
// Make sure to use global variable pointers that point into the now-current
|
// Make sure to use global variable pointers that point into the now-current
|
||||||
// module.
|
// module.
|
||||||
|
@ -188,45 +185,47 @@ ReduceCrashingGlobalVariables::TestGlobalVariables(
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
/// ReduceCrashingFunctions reducer - This works by removing functions and
|
/// ReduceCrashingFunctions reducer - This works by removing functions and
|
||||||
/// seeing if the program still crashes. If it does, then keep the newer,
|
/// seeing if the program still crashes. If it does, then keep the newer,
|
||||||
/// smaller program.
|
/// smaller program.
|
||||||
///
|
///
|
||||||
class ReduceCrashingFunctions : public ListReducer<Function*> {
|
class ReduceCrashingFunctions : public ListReducer<Function *> {
|
||||||
BugDriver &BD;
|
BugDriver &BD;
|
||||||
bool (*TestFn)(const BugDriver &, Module *);
|
bool (*TestFn)(const BugDriver &, Module *);
|
||||||
public:
|
|
||||||
ReduceCrashingFunctions(BugDriver &bd,
|
public:
|
||||||
bool (*testFn)(const BugDriver &, Module *))
|
ReduceCrashingFunctions(BugDriver &bd,
|
||||||
|
bool (*testFn)(const BugDriver &, Module *))
|
||||||
: BD(bd), TestFn(testFn) {}
|
: BD(bd), TestFn(testFn) {}
|
||||||
|
|
||||||
TestResult doTest(std::vector<Function*> &Prefix,
|
TestResult doTest(std::vector<Function *> &Prefix,
|
||||||
std::vector<Function*> &Kept,
|
std::vector<Function *> &Kept,
|
||||||
std::string &Error) override {
|
std::string &Error) override {
|
||||||
if (!Kept.empty() && TestFuncs(Kept))
|
if (!Kept.empty() && TestFuncs(Kept))
|
||||||
return KeepSuffix;
|
return KeepSuffix;
|
||||||
if (!Prefix.empty() && TestFuncs(Prefix))
|
if (!Prefix.empty() && TestFuncs(Prefix))
|
||||||
return KeepPrefix;
|
return KeepPrefix;
|
||||||
return NoFailure;
|
return NoFailure;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TestFuncs(std::vector<Function*> &Prefix);
|
bool TestFuncs(std::vector<Function *> &Prefix);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static void RemoveFunctionReferences(Module *M, const char* Name) {
|
static void RemoveFunctionReferences(Module *M, const char *Name) {
|
||||||
auto *UsedVar = M->getGlobalVariable(Name, true);
|
auto *UsedVar = M->getGlobalVariable(Name, true);
|
||||||
if (!UsedVar || !UsedVar->hasInitializer()) return;
|
if (!UsedVar || !UsedVar->hasInitializer())
|
||||||
|
return;
|
||||||
if (isa<ConstantAggregateZero>(UsedVar->getInitializer())) {
|
if (isa<ConstantAggregateZero>(UsedVar->getInitializer())) {
|
||||||
assert(UsedVar->use_empty());
|
assert(UsedVar->use_empty());
|
||||||
UsedVar->eraseFromParent();
|
UsedVar->eraseFromParent();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto *OldUsedVal = cast<ConstantArray>(UsedVar->getInitializer());
|
auto *OldUsedVal = cast<ConstantArray>(UsedVar->getInitializer());
|
||||||
std::vector<Constant*> Used;
|
std::vector<Constant *> Used;
|
||||||
for(Value *V : OldUsedVal->operand_values()) {
|
for (Value *V : OldUsedVal->operand_values()) {
|
||||||
Constant *Op = cast<Constant>(V->stripPointerCasts());
|
Constant *Op = cast<Constant>(V->stripPointerCasts());
|
||||||
if(!Op->isNullValue()) {
|
if (!Op->isNullValue()) {
|
||||||
Used.push_back(cast<Constant>(V));
|
Used.push_back(cast<Constant>(V));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -237,7 +236,7 @@ static void RemoveFunctionReferences(Module *M, const char* Name) {
|
||||||
UsedVar->setInitializer(NewUsedVal);
|
UsedVar->setInitializer(NewUsedVal);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ReduceCrashingFunctions::TestFuncs(std::vector<Function*> &Funcs) {
|
bool ReduceCrashingFunctions::TestFuncs(std::vector<Function *> &Funcs) {
|
||||||
// If main isn't present, claim there is no problem.
|
// If main isn't present, claim there is no problem.
|
||||||
if (KeepMain && !is_contained(Funcs, BD.getProgram()->getFunction("main")))
|
if (KeepMain && !is_contained(Funcs, BD.getProgram()->getFunction("main")))
|
||||||
return false;
|
return false;
|
||||||
|
@ -247,7 +246,7 @@ bool ReduceCrashingFunctions::TestFuncs(std::vector<Function*> &Funcs) {
|
||||||
Module *M = CloneModule(BD.getProgram(), VMap).release();
|
Module *M = CloneModule(BD.getProgram(), VMap).release();
|
||||||
|
|
||||||
// Convert list to set for fast lookup...
|
// Convert list to set for fast lookup...
|
||||||
std::set<Function*> Functions;
|
std::set<Function *> Functions;
|
||||||
for (unsigned i = 0, e = Funcs.size(); i != e; ++i) {
|
for (unsigned i = 0, e = Funcs.size(); i != e; ++i) {
|
||||||
Function *CMF = cast<Function>(VMap[Funcs[i]]);
|
Function *CMF = cast<Function>(VMap[Funcs[i]]);
|
||||||
assert(CMF && "Function not in module?!");
|
assert(CMF && "Function not in module?!");
|
||||||
|
@ -266,7 +265,7 @@ bool ReduceCrashingFunctions::TestFuncs(std::vector<Function*> &Funcs) {
|
||||||
if (!I.isDeclaration() && !Functions.count(&I))
|
if (!I.isDeclaration() && !Functions.count(&I))
|
||||||
DeleteFunctionBody(&I);
|
DeleteFunctionBody(&I);
|
||||||
} else {
|
} else {
|
||||||
std::vector<GlobalValue*> ToRemove;
|
std::vector<GlobalValue *> ToRemove;
|
||||||
// First, remove aliases to functions we're about to purge.
|
// First, remove aliases to functions we're about to purge.
|
||||||
for (GlobalAlias &Alias : M->aliases()) {
|
for (GlobalAlias &Alias : M->aliases()) {
|
||||||
GlobalObject *Root = Alias.getBaseObject();
|
GlobalObject *Root = Alias.getBaseObject();
|
||||||
|
@ -308,7 +307,7 @@ bool ReduceCrashingFunctions::TestFuncs(std::vector<Function*> &Funcs) {
|
||||||
}
|
}
|
||||||
// Try running the hacked up program...
|
// Try running the hacked up program...
|
||||||
if (TestFn(BD, M)) {
|
if (TestFn(BD, M)) {
|
||||||
BD.setNewProgram(M); // It crashed, keep the trimmed version...
|
BD.setNewProgram(M); // It crashed, keep the trimmed version...
|
||||||
|
|
||||||
// Make sure to use function pointers that point into the now-current
|
// Make sure to use function pointers that point into the now-current
|
||||||
// module.
|
// module.
|
||||||
|
@ -350,7 +349,7 @@ void simpleSimplifyCfg(Function &F, SmallVectorImpl<BasicBlock *> &BBs) {
|
||||||
// The dead BB's may be in a dead cycle or otherwise have references to each
|
// The dead BB's may be in a dead cycle or otherwise have references to each
|
||||||
// other. Because of this, we have to drop all references first, then delete
|
// other. Because of this, we have to drop all references first, then delete
|
||||||
// them all at once.
|
// them all at once.
|
||||||
for (auto *BB : Unreachable) {
|
for (auto *BB : Unreachable) {
|
||||||
for (BasicBlock *Successor : successors(&*BB))
|
for (BasicBlock *Successor : successors(&*BB))
|
||||||
if (Visited.count(Successor))
|
if (Visited.count(Successor))
|
||||||
Successor->removePredecessor(&*BB);
|
Successor->removePredecessor(&*BB);
|
||||||
|
@ -359,46 +358,48 @@ void simpleSimplifyCfg(Function &F, SmallVectorImpl<BasicBlock *> &BBs) {
|
||||||
for (auto *BB : Unreachable)
|
for (auto *BB : Unreachable)
|
||||||
BB->eraseFromParent();
|
BB->eraseFromParent();
|
||||||
}
|
}
|
||||||
/// ReduceCrashingBlocks reducer - This works by setting the terminators of
|
/// ReduceCrashingBlocks reducer - This works by setting the terminators of
|
||||||
/// all terminators except the specified basic blocks to a 'ret' instruction,
|
/// all terminators except the specified basic blocks to a 'ret' instruction,
|
||||||
/// then running the simplify-cfg pass. This has the effect of chopping up
|
/// then running the simplify-cfg pass. This has the effect of chopping up
|
||||||
/// the CFG really fast which can reduce large functions quickly.
|
/// the CFG really fast which can reduce large functions quickly.
|
||||||
///
|
///
|
||||||
class ReduceCrashingBlocks : public ListReducer<const BasicBlock*> {
|
class ReduceCrashingBlocks : public ListReducer<const BasicBlock *> {
|
||||||
BugDriver &BD;
|
BugDriver &BD;
|
||||||
bool (*TestFn)(const BugDriver &, Module *);
|
bool (*TestFn)(const BugDriver &, Module *);
|
||||||
public:
|
|
||||||
ReduceCrashingBlocks(BugDriver &BD,
|
public:
|
||||||
bool (*testFn)(const BugDriver &, Module *))
|
ReduceCrashingBlocks(BugDriver &BD,
|
||||||
|
bool (*testFn)(const BugDriver &, Module *))
|
||||||
: BD(BD), TestFn(testFn) {}
|
: BD(BD), TestFn(testFn) {}
|
||||||
|
|
||||||
TestResult doTest(std::vector<const BasicBlock*> &Prefix,
|
TestResult doTest(std::vector<const BasicBlock *> &Prefix,
|
||||||
std::vector<const BasicBlock*> &Kept,
|
std::vector<const BasicBlock *> &Kept,
|
||||||
std::string &Error) override {
|
std::string &Error) override {
|
||||||
if (!Kept.empty() && TestBlocks(Kept))
|
if (!Kept.empty() && TestBlocks(Kept))
|
||||||
return KeepSuffix;
|
return KeepSuffix;
|
||||||
if (!Prefix.empty() && TestBlocks(Prefix))
|
if (!Prefix.empty() && TestBlocks(Prefix))
|
||||||
return KeepPrefix;
|
return KeepPrefix;
|
||||||
return NoFailure;
|
return NoFailure;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TestBlocks(std::vector<const BasicBlock*> &Prefix);
|
bool TestBlocks(std::vector<const BasicBlock *> &Prefix);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ReduceCrashingBlocks::TestBlocks(std::vector<const BasicBlock*> &BBs) {
|
bool ReduceCrashingBlocks::TestBlocks(std::vector<const BasicBlock *> &BBs) {
|
||||||
// Clone the program to try hacking it apart...
|
// Clone the program to try hacking it apart...
|
||||||
ValueToValueMapTy VMap;
|
ValueToValueMapTy VMap;
|
||||||
Module *M = CloneModule(BD.getProgram(), VMap).release();
|
Module *M = CloneModule(BD.getProgram(), VMap).release();
|
||||||
|
|
||||||
// Convert list to set for fast lookup...
|
// Convert list to set for fast lookup...
|
||||||
SmallPtrSet<BasicBlock*, 8> Blocks;
|
SmallPtrSet<BasicBlock *, 8> Blocks;
|
||||||
for (unsigned i = 0, e = BBs.size(); i != e; ++i)
|
for (unsigned i = 0, e = BBs.size(); i != e; ++i)
|
||||||
Blocks.insert(cast<BasicBlock>(VMap[BBs[i]]));
|
Blocks.insert(cast<BasicBlock>(VMap[BBs[i]]));
|
||||||
|
|
||||||
outs() << "Checking for crash with only these blocks:";
|
outs() << "Checking for crash with only these blocks:";
|
||||||
unsigned NumPrint = Blocks.size();
|
unsigned NumPrint = Blocks.size();
|
||||||
if (NumPrint > 10) NumPrint = 10;
|
if (NumPrint > 10)
|
||||||
|
NumPrint = 10;
|
||||||
for (unsigned i = 0, e = NumPrint; i != e; ++i)
|
for (unsigned i = 0, e = NumPrint; i != e; ++i)
|
||||||
outs() << " " << BBs[i]->getName();
|
outs() << " " << BBs[i]->getName();
|
||||||
if (NumPrint < Blocks.size())
|
if (NumPrint < Blocks.size())
|
||||||
|
@ -431,13 +432,13 @@ bool ReduceCrashingBlocks::TestBlocks(std::vector<const BasicBlock*> &BBs) {
|
||||||
// a "persistent mapping" by turning basic blocks into <function, name> pairs.
|
// a "persistent mapping" by turning basic blocks into <function, name> pairs.
|
||||||
// This won't work well if blocks are unnamed, but that is just the risk we
|
// This won't work well if blocks are unnamed, but that is just the risk we
|
||||||
// have to take.
|
// have to take.
|
||||||
std::vector<std::pair<std::string, std::string> > BlockInfo;
|
std::vector<std::pair<std::string, std::string>> BlockInfo;
|
||||||
|
|
||||||
for (BasicBlock *BB : Blocks)
|
for (BasicBlock *BB : Blocks)
|
||||||
BlockInfo.emplace_back(BB->getParent()->getName(), BB->getName());
|
BlockInfo.emplace_back(BB->getParent()->getName(), BB->getName());
|
||||||
|
|
||||||
SmallVector<BasicBlock *, 16> ToProcess;
|
SmallVector<BasicBlock *, 16> ToProcess;
|
||||||
for (auto &F :*M) {
|
for (auto &F : *M) {
|
||||||
for (auto &BB : F)
|
for (auto &BB : F)
|
||||||
if (!Blocks.count(&BB))
|
if (!Blocks.count(&BB))
|
||||||
ToProcess.push_back(&BB);
|
ToProcess.push_back(&BB);
|
||||||
|
@ -454,10 +455,10 @@ bool ReduceCrashingBlocks::TestBlocks(std::vector<const BasicBlock*> &BBs) {
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
M = New.release();
|
M = New.release();
|
||||||
|
|
||||||
// Try running on the hacked up program...
|
// Try running on the hacked up program...
|
||||||
if (TestFn(BD, M)) {
|
if (TestFn(BD, M)) {
|
||||||
BD.setNewProgram(M); // It crashed, keep the trimmed version...
|
BD.setNewProgram(M); // It crashed, keep the trimmed version...
|
||||||
|
|
||||||
// Make sure to use basic block pointers that point into the now-current
|
// Make sure to use basic block pointers that point into the now-current
|
||||||
// module, and that they don't include any deleted blocks.
|
// module, and that they don't include any deleted blocks.
|
||||||
|
@ -466,13 +467,13 @@ bool ReduceCrashingBlocks::TestBlocks(std::vector<const BasicBlock*> &BBs) {
|
||||||
for (unsigned i = 0, e = BlockInfo.size(); i != e; ++i) {
|
for (unsigned i = 0, e = BlockInfo.size(); i != e; ++i) {
|
||||||
Function *F = cast<Function>(GST.lookup(BlockInfo[i].first));
|
Function *F = cast<Function>(GST.lookup(BlockInfo[i].first));
|
||||||
ValueSymbolTable &ST = F->getValueSymbolTable();
|
ValueSymbolTable &ST = F->getValueSymbolTable();
|
||||||
Value* V = ST.lookup(BlockInfo[i].second);
|
Value *V = ST.lookup(BlockInfo[i].second);
|
||||||
if (V && V->getType() == Type::getLabelTy(V->getContext()))
|
if (V && V->getType() == Type::getLabelTy(V->getContext()))
|
||||||
BBs.push_back(cast<BasicBlock>(V));
|
BBs.push_back(cast<BasicBlock>(V));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
delete M; // It didn't crash, try something else.
|
delete M; // It didn't crash, try something else.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -515,7 +516,7 @@ bool ReduceCrashingConditionals::TestBlocks(
|
||||||
|
|
||||||
// Convert list to set for fast lookup...
|
// Convert list to set for fast lookup...
|
||||||
SmallPtrSet<const BasicBlock *, 8> Blocks;
|
SmallPtrSet<const BasicBlock *, 8> Blocks;
|
||||||
for (const auto *BB: BBs)
|
for (const auto *BB : BBs)
|
||||||
Blocks.insert(cast<BasicBlock>(VMap[BB]));
|
Blocks.insert(cast<BasicBlock>(VMap[BB]));
|
||||||
|
|
||||||
outs() << "Checking for crash with changing conditionals to always jump to "
|
outs() << "Checking for crash with changing conditionals to always jump to "
|
||||||
|
@ -530,7 +531,7 @@ bool ReduceCrashingConditionals::TestBlocks(
|
||||||
outs() << ": ";
|
outs() << ": ";
|
||||||
|
|
||||||
// Loop over and delete any hack up any blocks that are not listed...
|
// Loop over and delete any hack up any blocks that are not listed...
|
||||||
for (auto &F: *M)
|
for (auto &F : *M)
|
||||||
for (auto &BB : F)
|
for (auto &BB : F)
|
||||||
if (!Blocks.count(&BB)) {
|
if (!Blocks.count(&BB)) {
|
||||||
auto *BR = dyn_cast<BranchInst>(BB.getTerminator());
|
auto *BR = dyn_cast<BranchInst>(BB.getTerminator());
|
||||||
|
@ -549,7 +550,7 @@ bool ReduceCrashingConditionals::TestBlocks(
|
||||||
BlockInfo.emplace_back(BB->getParent()->getName(), BB->getName());
|
BlockInfo.emplace_back(BB->getParent()->getName(), BB->getName());
|
||||||
|
|
||||||
SmallVector<BasicBlock *, 16> ToProcess;
|
SmallVector<BasicBlock *, 16> ToProcess;
|
||||||
for (auto &F :*M) {
|
for (auto &F : *M) {
|
||||||
for (auto &BB : F)
|
for (auto &BB : F)
|
||||||
if (!Blocks.count(&BB))
|
if (!Blocks.count(&BB))
|
||||||
ToProcess.push_back(&BB);
|
ToProcess.push_back(&BB);
|
||||||
|
@ -596,12 +597,10 @@ class ReduceSimplifyCFG : public ListReducer<const BasicBlock *> {
|
||||||
BugDriver &BD;
|
BugDriver &BD;
|
||||||
bool (*TestFn)(const BugDriver &, Module *);
|
bool (*TestFn)(const BugDriver &, Module *);
|
||||||
TargetTransformInfo TTI;
|
TargetTransformInfo TTI;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ReduceSimplifyCFG(BugDriver &bd,
|
ReduceSimplifyCFG(BugDriver &bd, bool (*testFn)(const BugDriver &, Module *))
|
||||||
bool (*testFn)(const BugDriver &, Module *))
|
: BD(bd), TestFn(testFn), TTI(bd.getProgram()->getDataLayout()) {}
|
||||||
: BD(bd), TestFn(testFn), TTI(bd.getProgram()->getDataLayout())
|
|
||||||
{}
|
|
||||||
|
|
||||||
TestResult doTest(std::vector<const BasicBlock *> &Prefix,
|
TestResult doTest(std::vector<const BasicBlock *> &Prefix,
|
||||||
std::vector<const BasicBlock *> &Kept,
|
std::vector<const BasicBlock *> &Kept,
|
||||||
|
@ -617,15 +616,14 @@ public:
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ReduceSimplifyCFG::TestBlocks(
|
bool ReduceSimplifyCFG::TestBlocks(std::vector<const BasicBlock *> &BBs) {
|
||||||
std::vector<const BasicBlock *> &BBs) {
|
|
||||||
// Clone the program to try hacking it apart...
|
// Clone the program to try hacking it apart...
|
||||||
ValueToValueMapTy VMap;
|
ValueToValueMapTy VMap;
|
||||||
Module *M = CloneModule(BD.getProgram(), VMap).release();
|
Module *M = CloneModule(BD.getProgram(), VMap).release();
|
||||||
|
|
||||||
// Convert list to set for fast lookup...
|
// Convert list to set for fast lookup...
|
||||||
SmallPtrSet<const BasicBlock *, 8> Blocks;
|
SmallPtrSet<const BasicBlock *, 8> Blocks;
|
||||||
for (const auto *BB: BBs)
|
for (const auto *BB : BBs)
|
||||||
Blocks.insert(cast<BasicBlock>(VMap[BB]));
|
Blocks.insert(cast<BasicBlock>(VMap[BB]));
|
||||||
|
|
||||||
outs() << "Checking for crash with CFG simplifying:";
|
outs() << "Checking for crash with CFG simplifying:";
|
||||||
|
@ -638,23 +636,22 @@ bool ReduceSimplifyCFG::TestBlocks(
|
||||||
outs() << "... <" << Blocks.size() << " total>";
|
outs() << "... <" << Blocks.size() << " total>";
|
||||||
outs() << ": ";
|
outs() << ": ";
|
||||||
|
|
||||||
// The following may destroy some blocks, so we save them first
|
// The following may destroy some blocks, so we save them first
|
||||||
std::vector<std::pair<std::string, std::string>> BlockInfo;
|
std::vector<std::pair<std::string, std::string>> BlockInfo;
|
||||||
|
|
||||||
for (const BasicBlock *BB : Blocks)
|
for (const BasicBlock *BB : Blocks)
|
||||||
BlockInfo.emplace_back(BB->getParent()->getName(), BB->getName());
|
BlockInfo.emplace_back(BB->getParent()->getName(), BB->getName());
|
||||||
|
|
||||||
|
|
||||||
// Loop over and delete any hack up any blocks that are not listed...
|
// Loop over and delete any hack up any blocks that are not listed...
|
||||||
for (auto &F: *M)
|
for (auto &F : *M)
|
||||||
// Loop over all of the basic blocks and remove them if they are unneeded.
|
// Loop over all of the basic blocks and remove them if they are unneeded.
|
||||||
for (Function::iterator BBIt = F.begin(); BBIt != F.end(); ) {
|
for (Function::iterator BBIt = F.begin(); BBIt != F.end();) {
|
||||||
if (!Blocks.count(&*BBIt)) {
|
if (!Blocks.count(&*BBIt)) {
|
||||||
++BBIt;
|
++BBIt;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
SimplifyCFG(&*BBIt++, TTI, 1);
|
SimplifyCFG(&*BBIt++, TTI, 1);
|
||||||
}
|
}
|
||||||
// Verify we didn't break anything
|
// Verify we didn't break anything
|
||||||
std::vector<std::string> Passes;
|
std::vector<std::string> Passes;
|
||||||
Passes.push_back("verify");
|
Passes.push_back("verify");
|
||||||
|
@ -674,7 +671,7 @@ bool ReduceSimplifyCFG::TestBlocks(
|
||||||
// module, and that they don't include any deleted blocks.
|
// module, and that they don't include any deleted blocks.
|
||||||
BBs.clear();
|
BBs.clear();
|
||||||
const ValueSymbolTable &GST = M->getValueSymbolTable();
|
const ValueSymbolTable &GST = M->getValueSymbolTable();
|
||||||
for (auto &BI : BlockInfo){
|
for (auto &BI : BlockInfo) {
|
||||||
auto *F = cast<Function>(GST.lookup(BI.first));
|
auto *F = cast<Function>(GST.lookup(BI.first));
|
||||||
ValueSymbolTable &ST = F->getValueSymbolTable();
|
ValueSymbolTable &ST = F->getValueSymbolTable();
|
||||||
Value *V = ST.lookup(BI.second);
|
Value *V = ST.lookup(BI.second);
|
||||||
|
@ -688,39 +685,40 @@ bool ReduceSimplifyCFG::TestBlocks(
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
/// ReduceCrashingInstructions reducer - This works by removing the specified
|
/// ReduceCrashingInstructions reducer - This works by removing the specified
|
||||||
/// non-terminator instructions and replacing them with undef.
|
/// non-terminator instructions and replacing them with undef.
|
||||||
///
|
///
|
||||||
class ReduceCrashingInstructions : public ListReducer<const Instruction*> {
|
class ReduceCrashingInstructions : public ListReducer<const Instruction *> {
|
||||||
BugDriver &BD;
|
BugDriver &BD;
|
||||||
bool (*TestFn)(const BugDriver &, Module *);
|
bool (*TestFn)(const BugDriver &, Module *);
|
||||||
public:
|
|
||||||
ReduceCrashingInstructions(BugDriver &bd,
|
public:
|
||||||
bool (*testFn)(const BugDriver &, Module *))
|
ReduceCrashingInstructions(BugDriver &bd,
|
||||||
|
bool (*testFn)(const BugDriver &, Module *))
|
||||||
: BD(bd), TestFn(testFn) {}
|
: BD(bd), TestFn(testFn) {}
|
||||||
|
|
||||||
TestResult doTest(std::vector<const Instruction*> &Prefix,
|
TestResult doTest(std::vector<const Instruction *> &Prefix,
|
||||||
std::vector<const Instruction*> &Kept,
|
std::vector<const Instruction *> &Kept,
|
||||||
std::string &Error) override {
|
std::string &Error) override {
|
||||||
if (!Kept.empty() && TestInsts(Kept))
|
if (!Kept.empty() && TestInsts(Kept))
|
||||||
return KeepSuffix;
|
return KeepSuffix;
|
||||||
if (!Prefix.empty() && TestInsts(Prefix))
|
if (!Prefix.empty() && TestInsts(Prefix))
|
||||||
return KeepPrefix;
|
return KeepPrefix;
|
||||||
return NoFailure;
|
return NoFailure;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TestInsts(std::vector<const Instruction*> &Prefix);
|
bool TestInsts(std::vector<const Instruction *> &Prefix);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ReduceCrashingInstructions::TestInsts(std::vector<const Instruction*>
|
bool ReduceCrashingInstructions::TestInsts(
|
||||||
&Insts) {
|
std::vector<const Instruction *> &Insts) {
|
||||||
// Clone the program to try hacking it apart...
|
// Clone the program to try hacking it apart...
|
||||||
ValueToValueMapTy VMap;
|
ValueToValueMapTy VMap;
|
||||||
Module *M = CloneModule(BD.getProgram(), VMap).release();
|
Module *M = CloneModule(BD.getProgram(), VMap).release();
|
||||||
|
|
||||||
// Convert list to set for fast lookup...
|
// Convert list to set for fast lookup...
|
||||||
SmallPtrSet<Instruction*, 32> Instructions;
|
SmallPtrSet<Instruction *, 32> Instructions;
|
||||||
for (unsigned i = 0, e = Insts.size(); i != e; ++i) {
|
for (unsigned i = 0, e = Insts.size(); i != e; ++i) {
|
||||||
assert(!isa<TerminatorInst>(Insts[i]));
|
assert(!isa<TerminatorInst>(Insts[i]));
|
||||||
Instructions.insert(cast<Instruction>(VMap[Insts[i]]));
|
Instructions.insert(cast<Instruction>(VMap[Insts[i]]));
|
||||||
|
@ -751,7 +749,7 @@ bool ReduceCrashingInstructions::TestInsts(std::vector<const Instruction*>
|
||||||
|
|
||||||
// Try running on the hacked up program...
|
// Try running on the hacked up program...
|
||||||
if (TestFn(BD, M)) {
|
if (TestFn(BD, M)) {
|
||||||
BD.setNewProgram(M); // It crashed, keep the trimmed version...
|
BD.setNewProgram(M); // It crashed, keep the trimmed version...
|
||||||
|
|
||||||
// Make sure to use instruction pointers that point into the now-current
|
// Make sure to use instruction pointers that point into the now-current
|
||||||
// module, and that they don't include any deleted blocks.
|
// module, and that they don't include any deleted blocks.
|
||||||
|
@ -760,7 +758,7 @@ bool ReduceCrashingInstructions::TestInsts(std::vector<const Instruction*>
|
||||||
Insts.push_back(Inst);
|
Insts.push_back(Inst);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
delete M; // It didn't crash, try something else.
|
delete M; // It didn't crash, try something else.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -910,7 +908,8 @@ bool ReduceCrashingNamedMDOps::TestNamedMDOps(
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ReduceGlobalInitializers(BugDriver &BD,
|
static void ReduceGlobalInitializers(BugDriver &BD,
|
||||||
bool (*TestFn)(const BugDriver &, Module *),
|
bool (*TestFn)(const BugDriver &,
|
||||||
|
Module *),
|
||||||
std::string &Error) {
|
std::string &Error) {
|
||||||
if (BD.getProgram()->global_begin() != BD.getProgram()->global_end()) {
|
if (BD.getProgram()->global_begin() != BD.getProgram()->global_end()) {
|
||||||
// Now try to reduce the number of global variable initializers in the
|
// Now try to reduce the number of global variable initializers in the
|
||||||
|
@ -928,28 +927,29 @@ static void ReduceGlobalInitializers(BugDriver &BD,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!DeletedInit) {
|
if (!DeletedInit) {
|
||||||
delete M; // No change made...
|
delete M; // No change made...
|
||||||
} else {
|
} else {
|
||||||
// See if the program still causes a crash...
|
// See if the program still causes a crash...
|
||||||
outs() << "\nChecking to see if we can delete global inits: ";
|
outs() << "\nChecking to see if we can delete global inits: ";
|
||||||
|
|
||||||
if (TestFn(BD, M)) { // Still crashes?
|
if (TestFn(BD, M)) { // Still crashes?
|
||||||
BD.setNewProgram(M);
|
BD.setNewProgram(M);
|
||||||
outs() << "\n*** Able to remove all global initializers!\n";
|
outs() << "\n*** Able to remove all global initializers!\n";
|
||||||
} else { // No longer crashes?
|
} else { // No longer crashes?
|
||||||
outs() << " - Removing all global inits hides problem!\n";
|
outs() << " - Removing all global inits hides problem!\n";
|
||||||
delete M;
|
delete M;
|
||||||
|
|
||||||
std::vector<GlobalVariable*> GVs;
|
std::vector<GlobalVariable *> GVs;
|
||||||
|
|
||||||
for (Module::global_iterator I = BD.getProgram()->global_begin(),
|
for (Module::global_iterator I = BD.getProgram()->global_begin(),
|
||||||
E = BD.getProgram()->global_end(); I != E; ++I)
|
E = BD.getProgram()->global_end();
|
||||||
|
I != E; ++I)
|
||||||
if (I->hasInitializer())
|
if (I->hasInitializer())
|
||||||
GVs.push_back(&*I);
|
GVs.push_back(&*I);
|
||||||
|
|
||||||
if (GVs.size() > 1 && !BugpointIsInterrupted) {
|
if (GVs.size() > 1 && !BugpointIsInterrupted) {
|
||||||
outs() << "\n*** Attempting to reduce the number of global "
|
outs() << "\n*** Attempting to reduce the number of global "
|
||||||
<< "variables in the testcase\n";
|
<< "variables in the testcase\n";
|
||||||
|
|
||||||
unsigned OldSize = GVs.size();
|
unsigned OldSize = GVs.size();
|
||||||
ReduceCrashingGlobalVariables(BD, TestFn).reduceList(GVs, Error);
|
ReduceCrashingGlobalVariables(BD, TestFn).reduceList(GVs, Error);
|
||||||
|
@ -969,7 +969,7 @@ static void ReduceInsts(BugDriver &BD,
|
||||||
// Attempt to delete instructions using bisection. This should help out nasty
|
// Attempt to delete instructions using bisection. This should help out nasty
|
||||||
// cases with large basic blocks where the problem is at one end.
|
// cases with large basic blocks where the problem is at one end.
|
||||||
if (!BugpointIsInterrupted) {
|
if (!BugpointIsInterrupted) {
|
||||||
std::vector<const Instruction*> Insts;
|
std::vector<const Instruction *> Insts;
|
||||||
for (const Function &F : *BD.getProgram())
|
for (const Function &F : *BD.getProgram())
|
||||||
for (const BasicBlock &BB : F)
|
for (const BasicBlock &BB : F)
|
||||||
for (const Instruction &I : BB)
|
for (const Instruction &I : BB)
|
||||||
|
@ -1002,7 +1002,8 @@ static void ReduceInsts(BugDriver &BD,
|
||||||
// function, attempting to delete them.
|
// function, attempting to delete them.
|
||||||
unsigned CurInstructionNum = 0;
|
unsigned CurInstructionNum = 0;
|
||||||
for (Module::const_iterator FI = BD.getProgram()->begin(),
|
for (Module::const_iterator FI = BD.getProgram()->begin(),
|
||||||
E = BD.getProgram()->end(); FI != E; ++FI)
|
E = BD.getProgram()->end();
|
||||||
|
FI != E; ++FI)
|
||||||
if (!FI->isDeclaration())
|
if (!FI->isDeclaration())
|
||||||
for (Function::const_iterator BI = FI->begin(), E = FI->end(); BI != E;
|
for (Function::const_iterator BI = FI->begin(), E = FI->end(); BI != E;
|
||||||
++BI)
|
++BI)
|
||||||
|
@ -1027,7 +1028,7 @@ static void ReduceInsts(BugDriver &BD,
|
||||||
// to reduce the testcase...
|
// to reduce the testcase...
|
||||||
BD.setNewProgram(M.release());
|
BD.setNewProgram(M.release());
|
||||||
InstructionsToSkipBeforeDeleting = CurInstructionNum;
|
InstructionsToSkipBeforeDeleting = CurInstructionNum;
|
||||||
goto TryAgain; // I wish I had a multi-level break here!
|
goto TryAgain; // I wish I had a multi-level break here!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1041,7 +1042,6 @@ static void ReduceInsts(BugDriver &BD,
|
||||||
BD.EmitProgressBitcode(BD.getProgram(), "reduced-instructions");
|
BD.EmitProgressBitcode(BD.getProgram(), "reduced-instructions");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// DebugACrash - Given a predicate that determines whether a component crashes
|
/// DebugACrash - Given a predicate that determines whether a component crashes
|
||||||
/// on a program, try to destructively reduce the program while still keeping
|
/// on a program, try to destructively reduce the program while still keeping
|
||||||
/// the predicate true.
|
/// the predicate true.
|
||||||
|
@ -1054,14 +1054,14 @@ static bool DebugACrash(BugDriver &BD,
|
||||||
ReduceGlobalInitializers(BD, TestFn, Error);
|
ReduceGlobalInitializers(BD, TestFn, Error);
|
||||||
|
|
||||||
// Now try to reduce the number of functions in the module to something small.
|
// Now try to reduce the number of functions in the module to something small.
|
||||||
std::vector<Function*> Functions;
|
std::vector<Function *> Functions;
|
||||||
for (Function &F : *BD.getProgram())
|
for (Function &F : *BD.getProgram())
|
||||||
if (!F.isDeclaration())
|
if (!F.isDeclaration())
|
||||||
Functions.push_back(&F);
|
Functions.push_back(&F);
|
||||||
|
|
||||||
if (Functions.size() > 1 && !BugpointIsInterrupted) {
|
if (Functions.size() > 1 && !BugpointIsInterrupted) {
|
||||||
outs() << "\n*** Attempting to reduce the number of functions "
|
outs() << "\n*** Attempting to reduce the number of functions "
|
||||||
"in the testcase\n";
|
"in the testcase\n";
|
||||||
|
|
||||||
unsigned OldSize = Functions.size();
|
unsigned OldSize = Functions.size();
|
||||||
ReduceCrashingFunctions(BD, TestFn).reduceList(Functions, Error);
|
ReduceCrashingFunctions(BD, TestFn).reduceList(Functions, Error);
|
||||||
|
@ -1073,7 +1073,7 @@ static bool DebugACrash(BugDriver &BD,
|
||||||
// Attempt to change conditional branches into unconditional branches to
|
// Attempt to change conditional branches into unconditional branches to
|
||||||
// eliminate blocks.
|
// eliminate blocks.
|
||||||
if (!DisableSimplifyCFG && !BugpointIsInterrupted) {
|
if (!DisableSimplifyCFG && !BugpointIsInterrupted) {
|
||||||
std::vector<const BasicBlock*> Blocks;
|
std::vector<const BasicBlock *> Blocks;
|
||||||
for (Function &F : *BD.getProgram())
|
for (Function &F : *BD.getProgram())
|
||||||
for (BasicBlock &BB : F)
|
for (BasicBlock &BB : F)
|
||||||
Blocks.push_back(&BB);
|
Blocks.push_back(&BB);
|
||||||
|
@ -1090,7 +1090,7 @@ static bool DebugACrash(BugDriver &BD,
|
||||||
// shrinks the code dramatically quickly
|
// shrinks the code dramatically quickly
|
||||||
//
|
//
|
||||||
if (!DisableSimplifyCFG && !BugpointIsInterrupted) {
|
if (!DisableSimplifyCFG && !BugpointIsInterrupted) {
|
||||||
std::vector<const BasicBlock*> Blocks;
|
std::vector<const BasicBlock *> Blocks;
|
||||||
for (Function &F : *BD.getProgram())
|
for (Function &F : *BD.getProgram())
|
||||||
for (BasicBlock &BB : F)
|
for (BasicBlock &BB : F)
|
||||||
Blocks.push_back(&BB);
|
Blocks.push_back(&BB);
|
||||||
|
@ -1101,7 +1101,7 @@ static bool DebugACrash(BugDriver &BD,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!DisableSimplifyCFG & !BugpointIsInterrupted) {
|
if (!DisableSimplifyCFG & !BugpointIsInterrupted) {
|
||||||
std::vector<const BasicBlock*> Blocks;
|
std::vector<const BasicBlock *> Blocks;
|
||||||
for (Function &F : *BD.getProgram())
|
for (Function &F : *BD.getProgram())
|
||||||
for (BasicBlock &BB : F)
|
for (BasicBlock &BB : F)
|
||||||
Blocks.push_back(&BB);
|
Blocks.push_back(&BB);
|
||||||
|
@ -1110,7 +1110,7 @@ static bool DebugACrash(BugDriver &BD,
|
||||||
if (Blocks.size() < OldSize)
|
if (Blocks.size() < OldSize)
|
||||||
BD.EmitProgressBitcode(BD.getProgram(), "reduced-simplifycfg");
|
BD.EmitProgressBitcode(BD.getProgram(), "reduced-simplifycfg");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attempt to delete instructions using bisection. This should help out nasty
|
// Attempt to delete instructions using bisection. This should help out nasty
|
||||||
// cases with large basic blocks where the problem is at one end.
|
// cases with large basic blocks where the problem is at one end.
|
||||||
if (!BugpointIsInterrupted)
|
if (!BugpointIsInterrupted)
|
||||||
|
@ -1147,7 +1147,7 @@ static bool DebugACrash(BugDriver &BD,
|
||||||
|
|
||||||
// Find out if the pass still crashes on the cleaned up program...
|
// Find out if the pass still crashes on the cleaned up program...
|
||||||
if (TestFn(BD, M)) {
|
if (TestFn(BD, M)) {
|
||||||
BD.setNewProgram(M); // Yup, it does, keep the reduced version...
|
BD.setNewProgram(M); // Yup, it does, keep the reduced version...
|
||||||
} else {
|
} else {
|
||||||
delete M;
|
delete M;
|
||||||
}
|
}
|
||||||
|
@ -1194,7 +1194,7 @@ static bool TestForCodeGenCrash(const BugDriver &BD, Module *M) {
|
||||||
errs() << Error << "\n";
|
errs() << Error << "\n";
|
||||||
else
|
else
|
||||||
errs() << "<crash>\n";
|
errs() << "<crash>\n";
|
||||||
return true; // Tool is still crashing.
|
return true; // Tool is still crashing.
|
||||||
}
|
}
|
||||||
errs() << '\n';
|
errs() << '\n';
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -25,112 +25,113 @@
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
// OutputType - Allow the user to specify the way code should be run, to test
|
// OutputType - Allow the user to specify the way code should be run, to test
|
||||||
// for miscompilation.
|
// for miscompilation.
|
||||||
//
|
//
|
||||||
enum OutputType {
|
enum OutputType {
|
||||||
AutoPick, RunLLI, RunJIT, RunLLC, RunLLCIA, LLC_Safe, CompileCustom, Custom
|
AutoPick,
|
||||||
};
|
RunLLI,
|
||||||
|
RunJIT,
|
||||||
|
RunLLC,
|
||||||
|
RunLLCIA,
|
||||||
|
LLC_Safe,
|
||||||
|
CompileCustom,
|
||||||
|
Custom
|
||||||
|
};
|
||||||
|
|
||||||
cl::opt<double>
|
cl::opt<double> AbsTolerance("abs-tolerance",
|
||||||
AbsTolerance("abs-tolerance", cl::desc("Absolute error tolerated"),
|
cl::desc("Absolute error tolerated"),
|
||||||
cl::init(0.0));
|
cl::init(0.0));
|
||||||
cl::opt<double>
|
cl::opt<double> RelTolerance("rel-tolerance",
|
||||||
RelTolerance("rel-tolerance", cl::desc("Relative error tolerated"),
|
cl::desc("Relative error tolerated"),
|
||||||
cl::init(0.0));
|
cl::init(0.0));
|
||||||
|
|
||||||
cl::opt<OutputType>
|
cl::opt<OutputType> InterpreterSel(
|
||||||
InterpreterSel(cl::desc("Specify the \"test\" i.e. suspect back-end:"),
|
cl::desc("Specify the \"test\" i.e. suspect back-end:"),
|
||||||
cl::values(clEnumValN(AutoPick, "auto", "Use best guess"),
|
cl::values(clEnumValN(AutoPick, "auto", "Use best guess"),
|
||||||
clEnumValN(RunLLI, "run-int",
|
clEnumValN(RunLLI, "run-int", "Execute with the interpreter"),
|
||||||
"Execute with the interpreter"),
|
clEnumValN(RunJIT, "run-jit", "Execute with JIT"),
|
||||||
clEnumValN(RunJIT, "run-jit", "Execute with JIT"),
|
clEnumValN(RunLLC, "run-llc", "Compile with LLC"),
|
||||||
clEnumValN(RunLLC, "run-llc", "Compile with LLC"),
|
clEnumValN(RunLLCIA, "run-llc-ia",
|
||||||
clEnumValN(RunLLCIA, "run-llc-ia",
|
"Compile with LLC with integrated assembler"),
|
||||||
"Compile with LLC with integrated assembler"),
|
clEnumValN(LLC_Safe, "llc-safe", "Use LLC for all"),
|
||||||
clEnumValN(LLC_Safe, "llc-safe", "Use LLC for all"),
|
clEnumValN(CompileCustom, "compile-custom",
|
||||||
clEnumValN(CompileCustom, "compile-custom",
|
"Use -compile-command to define a command to "
|
||||||
"Use -compile-command to define a command to "
|
"compile the bitcode. Useful to avoid linking."),
|
||||||
"compile the bitcode. Useful to avoid linking."),
|
clEnumValN(Custom, "run-custom",
|
||||||
clEnumValN(Custom, "run-custom",
|
"Use -exec-command to define a command to execute "
|
||||||
"Use -exec-command to define a command to execute "
|
"the bitcode. Useful for cross-compilation."),
|
||||||
"the bitcode. Useful for cross-compilation."),
|
clEnumValEnd),
|
||||||
clEnumValEnd),
|
cl::init(AutoPick));
|
||||||
cl::init(AutoPick));
|
|
||||||
|
|
||||||
cl::opt<OutputType>
|
cl::opt<OutputType> SafeInterpreterSel(
|
||||||
SafeInterpreterSel(cl::desc("Specify \"safe\" i.e. known-good backend:"),
|
cl::desc("Specify \"safe\" i.e. known-good backend:"),
|
||||||
cl::values(clEnumValN(AutoPick, "safe-auto", "Use best guess"),
|
cl::values(clEnumValN(AutoPick, "safe-auto", "Use best guess"),
|
||||||
clEnumValN(RunLLC, "safe-run-llc", "Compile with LLC"),
|
clEnumValN(RunLLC, "safe-run-llc", "Compile with LLC"),
|
||||||
clEnumValN(Custom, "safe-run-custom",
|
clEnumValN(Custom, "safe-run-custom",
|
||||||
"Use -exec-command to define a command to execute "
|
"Use -exec-command to define a command to execute "
|
||||||
"the bitcode. Useful for cross-compilation."),
|
"the bitcode. Useful for cross-compilation."),
|
||||||
clEnumValEnd),
|
clEnumValEnd),
|
||||||
cl::init(AutoPick));
|
cl::init(AutoPick));
|
||||||
|
|
||||||
cl::opt<std::string>
|
cl::opt<std::string> SafeInterpreterPath(
|
||||||
SafeInterpreterPath("safe-path",
|
"safe-path", cl::desc("Specify the path to the \"safe\" backend program"),
|
||||||
cl::desc("Specify the path to the \"safe\" backend program"),
|
cl::init(""));
|
||||||
cl::init(""));
|
|
||||||
|
|
||||||
cl::opt<bool>
|
cl::opt<bool> AppendProgramExitCode(
|
||||||
AppendProgramExitCode("append-exit-code",
|
"append-exit-code",
|
||||||
cl::desc("Append the exit code to the output so it gets diff'd too"),
|
cl::desc("Append the exit code to the output so it gets diff'd too"),
|
||||||
cl::init(false));
|
cl::init(false));
|
||||||
|
|
||||||
cl::opt<std::string>
|
cl::opt<std::string>
|
||||||
InputFile("input", cl::init("/dev/null"),
|
InputFile("input", cl::init("/dev/null"),
|
||||||
cl::desc("Filename to pipe in as stdin (default: /dev/null)"));
|
cl::desc("Filename to pipe in as stdin (default: /dev/null)"));
|
||||||
|
|
||||||
cl::list<std::string>
|
cl::list<std::string>
|
||||||
AdditionalSOs("additional-so",
|
AdditionalSOs("additional-so", cl::desc("Additional shared objects to load "
|
||||||
cl::desc("Additional shared objects to load "
|
"into executing programs"));
|
||||||
"into executing programs"));
|
|
||||||
|
|
||||||
cl::list<std::string>
|
cl::list<std::string> AdditionalLinkerArgs(
|
||||||
AdditionalLinkerArgs("Xlinker",
|
"Xlinker", cl::desc("Additional arguments to pass to the linker"));
|
||||||
cl::desc("Additional arguments to pass to the linker"));
|
|
||||||
|
|
||||||
cl::opt<std::string>
|
cl::opt<std::string> CustomCompileCommand(
|
||||||
CustomCompileCommand("compile-command", cl::init("llc"),
|
"compile-command", cl::init("llc"),
|
||||||
cl::desc("Command to compile the bitcode (use with -compile-custom) "
|
cl::desc("Command to compile the bitcode (use with -compile-custom) "
|
||||||
"(default: llc)"));
|
"(default: llc)"));
|
||||||
|
|
||||||
cl::opt<std::string>
|
cl::opt<std::string> CustomExecCommand(
|
||||||
CustomExecCommand("exec-command", cl::init("simulate"),
|
"exec-command", cl::init("simulate"),
|
||||||
cl::desc("Command to execute the bitcode (use with -run-custom) "
|
cl::desc("Command to execute the bitcode (use with -run-custom) "
|
||||||
"(default: simulate)"));
|
"(default: simulate)"));
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
// Anything specified after the --args option are taken as arguments to the
|
// Anything specified after the --args option are taken as arguments to the
|
||||||
// program being debugged.
|
// program being debugged.
|
||||||
cl::list<std::string>
|
cl::list<std::string> InputArgv("args", cl::Positional,
|
||||||
InputArgv("args", cl::Positional, cl::desc("<program arguments>..."),
|
cl::desc("<program arguments>..."),
|
||||||
cl::ZeroOrMore, cl::PositionalEatsArgs);
|
cl::ZeroOrMore, cl::PositionalEatsArgs);
|
||||||
|
|
||||||
cl::opt<std::string>
|
cl::opt<std::string>
|
||||||
OutputPrefix("output-prefix", cl::init("bugpoint"),
|
OutputPrefix("output-prefix", cl::init("bugpoint"),
|
||||||
cl::desc("Prefix to use for outputs (default: 'bugpoint')"));
|
cl::desc("Prefix to use for outputs (default: 'bugpoint')"));
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
cl::list<std::string>
|
cl::list<std::string> ToolArgv("tool-args", cl::Positional,
|
||||||
ToolArgv("tool-args", cl::Positional, cl::desc("<tool arguments>..."),
|
cl::desc("<tool arguments>..."), cl::ZeroOrMore,
|
||||||
cl::ZeroOrMore, cl::PositionalEatsArgs);
|
cl::PositionalEatsArgs);
|
||||||
|
|
||||||
cl::list<std::string>
|
cl::list<std::string> SafeToolArgv("safe-tool-args", cl::Positional,
|
||||||
SafeToolArgv("safe-tool-args", cl::Positional,
|
cl::desc("<safe-tool arguments>..."),
|
||||||
cl::desc("<safe-tool arguments>..."),
|
cl::ZeroOrMore, cl::PositionalEatsArgs);
|
||||||
cl::ZeroOrMore, cl::PositionalEatsArgs);
|
|
||||||
|
|
||||||
cl::opt<std::string>
|
cl::opt<std::string> CCBinary("gcc", cl::init(""),
|
||||||
CCBinary("gcc", cl::init(""), cl::desc("The gcc binary to use."));
|
cl::desc("The gcc binary to use."));
|
||||||
|
|
||||||
cl::list<std::string>
|
cl::list<std::string> CCToolArgv("gcc-tool-args", cl::Positional,
|
||||||
CCToolArgv("gcc-tool-args", cl::Positional,
|
cl::desc("<gcc-tool arguments>..."),
|
||||||
cl::desc("<gcc-tool arguments>..."),
|
cl::ZeroOrMore, cl::PositionalEatsArgs);
|
||||||
cl::ZeroOrMore, cl::PositionalEatsArgs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
@ -159,19 +160,18 @@ bool BugDriver::initializeExecutionEnvironment() {
|
||||||
case AutoPick:
|
case AutoPick:
|
||||||
if (!Interpreter) {
|
if (!Interpreter) {
|
||||||
InterpreterSel = RunJIT;
|
InterpreterSel = RunJIT;
|
||||||
Interpreter = AbstractInterpreter::createJIT(getToolName(), Message,
|
Interpreter =
|
||||||
&ToolArgv);
|
AbstractInterpreter::createJIT(getToolName(), Message, &ToolArgv);
|
||||||
}
|
}
|
||||||
if (!Interpreter) {
|
if (!Interpreter) {
|
||||||
InterpreterSel = RunLLC;
|
InterpreterSel = RunLLC;
|
||||||
Interpreter = AbstractInterpreter::createLLC(getToolName(), Message,
|
Interpreter = AbstractInterpreter::createLLC(
|
||||||
CCBinary, &ToolArgv,
|
getToolName(), Message, CCBinary, &ToolArgv, &CCToolArgv);
|
||||||
&CCToolArgv);
|
|
||||||
}
|
}
|
||||||
if (!Interpreter) {
|
if (!Interpreter) {
|
||||||
InterpreterSel = RunLLI;
|
InterpreterSel = RunLLI;
|
||||||
Interpreter = AbstractInterpreter::createLLI(getToolName(), Message,
|
Interpreter =
|
||||||
&ToolArgv);
|
AbstractInterpreter::createLLI(getToolName(), Message, &ToolArgv);
|
||||||
}
|
}
|
||||||
if (!Interpreter) {
|
if (!Interpreter) {
|
||||||
InterpreterSel = AutoPick;
|
InterpreterSel = AutoPick;
|
||||||
|
@ -179,28 +179,27 @@ bool BugDriver::initializeExecutionEnvironment() {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case RunLLI:
|
case RunLLI:
|
||||||
Interpreter = AbstractInterpreter::createLLI(getToolName(), Message,
|
Interpreter =
|
||||||
&ToolArgv);
|
AbstractInterpreter::createLLI(getToolName(), Message, &ToolArgv);
|
||||||
break;
|
break;
|
||||||
case RunLLC:
|
case RunLLC:
|
||||||
case RunLLCIA:
|
case RunLLCIA:
|
||||||
case LLC_Safe:
|
case LLC_Safe:
|
||||||
Interpreter = AbstractInterpreter::createLLC(getToolName(), Message,
|
Interpreter = AbstractInterpreter::createLLC(
|
||||||
CCBinary, &ToolArgv,
|
getToolName(), Message, CCBinary, &ToolArgv, &CCToolArgv,
|
||||||
&CCToolArgv,
|
InterpreterSel == RunLLCIA);
|
||||||
InterpreterSel == RunLLCIA);
|
|
||||||
break;
|
break;
|
||||||
case RunJIT:
|
case RunJIT:
|
||||||
Interpreter = AbstractInterpreter::createJIT(getToolName(), Message,
|
Interpreter =
|
||||||
&ToolArgv);
|
AbstractInterpreter::createJIT(getToolName(), Message, &ToolArgv);
|
||||||
break;
|
break;
|
||||||
case CompileCustom:
|
case CompileCustom:
|
||||||
Interpreter =
|
Interpreter = AbstractInterpreter::createCustomCompiler(
|
||||||
AbstractInterpreter::createCustomCompiler(Message, CustomCompileCommand);
|
Message, CustomCompileCommand);
|
||||||
break;
|
break;
|
||||||
case Custom:
|
case Custom:
|
||||||
Interpreter =
|
Interpreter =
|
||||||
AbstractInterpreter::createCustomExecutor(Message, CustomExecCommand);
|
AbstractInterpreter::createCustomExecutor(Message, CustomExecCommand);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!Interpreter)
|
if (!Interpreter)
|
||||||
|
@ -215,25 +214,19 @@ bool BugDriver::initializeExecutionEnvironment() {
|
||||||
switch (SafeInterpreterSel) {
|
switch (SafeInterpreterSel) {
|
||||||
case AutoPick:
|
case AutoPick:
|
||||||
// In "llc-safe" mode, default to using LLC as the "safe" backend.
|
// In "llc-safe" mode, default to using LLC as the "safe" backend.
|
||||||
if (!SafeInterpreter &&
|
if (!SafeInterpreter && InterpreterSel == LLC_Safe) {
|
||||||
InterpreterSel == LLC_Safe) {
|
|
||||||
SafeInterpreterSel = RunLLC;
|
SafeInterpreterSel = RunLLC;
|
||||||
SafeToolArgs.push_back("--relocation-model=pic");
|
SafeToolArgs.push_back("--relocation-model=pic");
|
||||||
SafeInterpreter = AbstractInterpreter::createLLC(Path.c_str(), Message,
|
SafeInterpreter = AbstractInterpreter::createLLC(
|
||||||
CCBinary,
|
Path.c_str(), Message, CCBinary, &SafeToolArgs, &CCToolArgv);
|
||||||
&SafeToolArgs,
|
|
||||||
&CCToolArgv);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!SafeInterpreter &&
|
if (!SafeInterpreter && InterpreterSel != RunLLC &&
|
||||||
InterpreterSel != RunLLC &&
|
|
||||||
InterpreterSel != RunJIT) {
|
InterpreterSel != RunJIT) {
|
||||||
SafeInterpreterSel = RunLLC;
|
SafeInterpreterSel = RunLLC;
|
||||||
SafeToolArgs.push_back("--relocation-model=pic");
|
SafeToolArgs.push_back("--relocation-model=pic");
|
||||||
SafeInterpreter = AbstractInterpreter::createLLC(Path.c_str(), Message,
|
SafeInterpreter = AbstractInterpreter::createLLC(
|
||||||
CCBinary,
|
Path.c_str(), Message, CCBinary, &SafeToolArgs, &CCToolArgv);
|
||||||
&SafeToolArgs,
|
|
||||||
&CCToolArgv);
|
|
||||||
}
|
}
|
||||||
if (!SafeInterpreter) {
|
if (!SafeInterpreter) {
|
||||||
SafeInterpreterSel = AutoPick;
|
SafeInterpreterSel = AutoPick;
|
||||||
|
@ -243,24 +236,29 @@ bool BugDriver::initializeExecutionEnvironment() {
|
||||||
case RunLLC:
|
case RunLLC:
|
||||||
case RunLLCIA:
|
case RunLLCIA:
|
||||||
SafeToolArgs.push_back("--relocation-model=pic");
|
SafeToolArgs.push_back("--relocation-model=pic");
|
||||||
SafeInterpreter = AbstractInterpreter::createLLC(Path.c_str(), Message,
|
SafeInterpreter = AbstractInterpreter::createLLC(
|
||||||
CCBinary, &SafeToolArgs,
|
Path.c_str(), Message, CCBinary, &SafeToolArgs, &CCToolArgv,
|
||||||
&CCToolArgv,
|
SafeInterpreterSel == RunLLCIA);
|
||||||
SafeInterpreterSel == RunLLCIA);
|
|
||||||
break;
|
break;
|
||||||
case Custom:
|
case Custom:
|
||||||
SafeInterpreter =
|
SafeInterpreter =
|
||||||
AbstractInterpreter::createCustomExecutor(Message, CustomExecCommand);
|
AbstractInterpreter::createCustomExecutor(Message, CustomExecCommand);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
Message = "Sorry, this back-end is not supported by bugpoint as the "
|
Message = "Sorry, this back-end is not supported by bugpoint as the "
|
||||||
"\"safe\" backend right now!\n";
|
"\"safe\" backend right now!\n";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!SafeInterpreter) { outs() << Message << "\nExiting.\n"; exit(1); }
|
if (!SafeInterpreter) {
|
||||||
|
outs() << Message << "\nExiting.\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
cc = CC::create(Message, CCBinary, &CCToolArgv);
|
cc = CC::create(Message, CCBinary, &CCToolArgv);
|
||||||
if (!cc) { outs() << Message << "\nExiting.\n"; exit(1); }
|
if (!cc) {
|
||||||
|
outs() << Message << "\nExiting.\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
// If there was an error creating the selected interpreter, quit with error.
|
// If there was an error creating the selected interpreter, quit with error.
|
||||||
return Interpreter == nullptr;
|
return Interpreter == nullptr;
|
||||||
|
@ -294,18 +292,16 @@ void BugDriver::compileProgram(Module *M, std::string *Error) const {
|
||||||
Interpreter->compileProgram(BitcodeFile.str(), Error, Timeout, MemoryLimit);
|
Interpreter->compileProgram(BitcodeFile.str(), Error, Timeout, MemoryLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// executeProgram - This method runs "Program", capturing the output of the
|
/// executeProgram - This method runs "Program", capturing the output of the
|
||||||
/// program to a file, returning the filename of the file. A recommended
|
/// program to a file, returning the filename of the file. A recommended
|
||||||
/// filename may be optionally specified.
|
/// filename may be optionally specified.
|
||||||
///
|
///
|
||||||
std::string BugDriver::executeProgram(const Module *Program,
|
std::string
|
||||||
std::string OutputFile,
|
BugDriver::executeProgram(const Module *Program, std::string OutputFile,
|
||||||
std::string BitcodeFile,
|
std::string BitcodeFile, const std::string &SharedObj,
|
||||||
const std::string &SharedObj,
|
AbstractInterpreter *AI, std::string *Error) const {
|
||||||
AbstractInterpreter *AI,
|
if (!AI)
|
||||||
std::string *Error) const {
|
AI = Interpreter;
|
||||||
if (!AI) AI = Interpreter;
|
|
||||||
assert(AI && "Interpreter should have been created already!");
|
assert(AI && "Interpreter should have been created already!");
|
||||||
bool CreatedBitcode = false;
|
bool CreatedBitcode = false;
|
||||||
if (BitcodeFile.empty()) {
|
if (BitcodeFile.empty()) {
|
||||||
|
@ -315,15 +311,15 @@ std::string BugDriver::executeProgram(const Module *Program,
|
||||||
std::error_code EC = sys::fs::createUniqueFile(
|
std::error_code EC = sys::fs::createUniqueFile(
|
||||||
OutputPrefix + "-test-program-%%%%%%%.bc", UniqueFD, UniqueFilename);
|
OutputPrefix + "-test-program-%%%%%%%.bc", UniqueFD, UniqueFilename);
|
||||||
if (EC) {
|
if (EC) {
|
||||||
errs() << ToolName << ": Error making unique filename: "
|
errs() << ToolName << ": Error making unique filename: " << EC.message()
|
||||||
<< EC.message() << "!\n";
|
<< "!\n";
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
BitcodeFile = UniqueFilename.str();
|
BitcodeFile = UniqueFilename.str();
|
||||||
|
|
||||||
if (writeProgramToFile(BitcodeFile, UniqueFD, Program)) {
|
if (writeProgramToFile(BitcodeFile, UniqueFD, Program)) {
|
||||||
errs() << ToolName << ": Error emitting bitcode to file '"
|
errs() << ToolName << ": Error emitting bitcode to file '" << BitcodeFile
|
||||||
<< BitcodeFile << "'!\n";
|
<< "'!\n";
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
CreatedBitcode = true;
|
CreatedBitcode = true;
|
||||||
|
@ -331,17 +327,17 @@ std::string BugDriver::executeProgram(const Module *Program,
|
||||||
|
|
||||||
// Remove the temporary bitcode file when we are done.
|
// Remove the temporary bitcode file when we are done.
|
||||||
std::string BitcodePath(BitcodeFile);
|
std::string BitcodePath(BitcodeFile);
|
||||||
FileRemover BitcodeFileRemover(BitcodePath,
|
FileRemover BitcodeFileRemover(BitcodePath, CreatedBitcode && !SaveTemps);
|
||||||
CreatedBitcode && !SaveTemps);
|
|
||||||
|
|
||||||
if (OutputFile.empty()) OutputFile = OutputPrefix + "-execution-output-%%%%%%%";
|
if (OutputFile.empty())
|
||||||
|
OutputFile = OutputPrefix + "-execution-output-%%%%%%%";
|
||||||
|
|
||||||
// Check to see if this is a valid output filename...
|
// Check to see if this is a valid output filename...
|
||||||
SmallString<128> UniqueFile;
|
SmallString<128> UniqueFile;
|
||||||
std::error_code EC = sys::fs::createUniqueFile(OutputFile, UniqueFile);
|
std::error_code EC = sys::fs::createUniqueFile(OutputFile, UniqueFile);
|
||||||
if (EC) {
|
if (EC) {
|
||||||
errs() << ToolName << ": Error making unique filename: "
|
errs() << ToolName << ": Error making unique filename: " << EC.message()
|
||||||
<< EC.message() << "\n";
|
<< "\n";
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
OutputFile = UniqueFile.str();
|
OutputFile = UniqueFile.str();
|
||||||
|
@ -361,11 +357,15 @@ std::string BugDriver::executeProgram(const Module *Program,
|
||||||
errs() << "<timeout>";
|
errs() << "<timeout>";
|
||||||
static bool FirstTimeout = true;
|
static bool FirstTimeout = true;
|
||||||
if (FirstTimeout) {
|
if (FirstTimeout) {
|
||||||
outs() << "\n"
|
outs()
|
||||||
"*** Program execution timed out! This mechanism is designed to handle\n"
|
<< "\n"
|
||||||
" programs stuck in infinite loops gracefully. The -timeout option\n"
|
"*** Program execution timed out! This mechanism is designed to "
|
||||||
" can be used to change the timeout threshold or disable it completely\n"
|
"handle\n"
|
||||||
" (with -timeout=0). This message is only displayed once.\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;
|
FirstTimeout = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -395,14 +395,13 @@ std::string BugDriver::compileSharedObject(const std::string &BitcodeFile,
|
||||||
std::string OutputFile;
|
std::string OutputFile;
|
||||||
|
|
||||||
// Using the known-good backend.
|
// Using the known-good backend.
|
||||||
CC::FileType FT = SafeInterpreter->OutputCode(BitcodeFile, OutputFile,
|
CC::FileType FT = SafeInterpreter->OutputCode(BitcodeFile, OutputFile, Error);
|
||||||
Error);
|
|
||||||
if (!Error.empty())
|
if (!Error.empty())
|
||||||
return "";
|
return "";
|
||||||
|
|
||||||
std::string SharedObjectFile;
|
std::string SharedObjectFile;
|
||||||
bool Failure = cc->MakeSharedObject(OutputFile, FT, SharedObjectFile,
|
bool Failure = cc->MakeSharedObject(OutputFile, FT, SharedObjectFile,
|
||||||
AdditionalLinkerArgs, Error);
|
AdditionalLinkerArgs, Error);
|
||||||
if (!Error.empty())
|
if (!Error.empty())
|
||||||
return "";
|
return "";
|
||||||
if (Failure)
|
if (Failure)
|
||||||
|
@ -447,8 +446,7 @@ bool BugDriver::createReferenceFile(Module *M, const std::string &Filename) {
|
||||||
///
|
///
|
||||||
bool BugDriver::diffProgram(const Module *Program,
|
bool BugDriver::diffProgram(const Module *Program,
|
||||||
const std::string &BitcodeFile,
|
const std::string &BitcodeFile,
|
||||||
const std::string &SharedObject,
|
const std::string &SharedObject, bool RemoveBitcode,
|
||||||
bool RemoveBitcode,
|
|
||||||
std::string *ErrMsg) const {
|
std::string *ErrMsg) const {
|
||||||
// Execute the program, generating an output file...
|
// Execute the program, generating an output file...
|
||||||
std::string Output(
|
std::string Output(
|
||||||
|
@ -458,16 +456,14 @@ bool BugDriver::diffProgram(const Module *Program,
|
||||||
|
|
||||||
std::string Error;
|
std::string Error;
|
||||||
bool FilesDifferent = false;
|
bool FilesDifferent = false;
|
||||||
if (int Diff = DiffFilesWithTolerance(ReferenceOutputFile,
|
if (int Diff = DiffFilesWithTolerance(ReferenceOutputFile, Output,
|
||||||
Output,
|
|
||||||
AbsTolerance, RelTolerance, &Error)) {
|
AbsTolerance, RelTolerance, &Error)) {
|
||||||
if (Diff == 2) {
|
if (Diff == 2) {
|
||||||
errs() << "While diffing output: " << Error << '\n';
|
errs() << "While diffing output: " << Error << '\n';
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
FilesDifferent = true;
|
FilesDifferent = true;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// Remove the generated output if there are no differences.
|
// Remove the generated output if there are no differences.
|
||||||
sys::fs::remove(Output);
|
sys::fs::remove(Output);
|
||||||
}
|
}
|
||||||
|
@ -478,7 +474,4 @@ bool BugDriver::diffProgram(const Module *Program,
|
||||||
return FilesDifferent;
|
return FilesDifferent;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BugDriver::isExecutingJIT() {
|
bool BugDriver::isExecutingJIT() { return InterpreterSel == RunJIT; }
|
||||||
return InterpreterSel == RunJIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -37,50 +37,49 @@ using namespace llvm;
|
||||||
#define DEBUG_TYPE "bugpoint"
|
#define DEBUG_TYPE "bugpoint"
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
bool DisableSimplifyCFG = false;
|
bool DisableSimplifyCFG = false;
|
||||||
extern cl::opt<std::string> OutputPrefix;
|
extern cl::opt<std::string> OutputPrefix;
|
||||||
} // End llvm namespace
|
} // End llvm namespace
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
cl::opt<bool>
|
cl::opt<bool> NoDCE("disable-dce",
|
||||||
NoDCE ("disable-dce",
|
cl::desc("Do not use the -dce pass to reduce testcases"));
|
||||||
cl::desc("Do not use the -dce pass to reduce testcases"));
|
cl::opt<bool, true>
|
||||||
cl::opt<bool, true>
|
NoSCFG("disable-simplifycfg", cl::location(DisableSimplifyCFG),
|
||||||
NoSCFG("disable-simplifycfg", cl::location(DisableSimplifyCFG),
|
cl::desc("Do not use the -simplifycfg pass to reduce testcases"));
|
||||||
cl::desc("Do not use the -simplifycfg pass to reduce testcases"));
|
|
||||||
|
|
||||||
Function* globalInitUsesExternalBA(GlobalVariable* GV) {
|
Function *globalInitUsesExternalBA(GlobalVariable *GV) {
|
||||||
if (!GV->hasInitializer())
|
if (!GV->hasInitializer())
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
Constant *I = GV->getInitializer();
|
|
||||||
|
|
||||||
// walk the values used by the initializer
|
|
||||||
// (and recurse into things like ConstantExpr)
|
|
||||||
std::vector<Constant*> Todo;
|
|
||||||
std::set<Constant*> Done;
|
|
||||||
Todo.push_back(I);
|
|
||||||
|
|
||||||
while (!Todo.empty()) {
|
|
||||||
Constant* V = Todo.back();
|
|
||||||
Todo.pop_back();
|
|
||||||
Done.insert(V);
|
|
||||||
|
|
||||||
if (BlockAddress *BA = dyn_cast<BlockAddress>(V)) {
|
|
||||||
Function *F = BA->getFunction();
|
|
||||||
if (F->isDeclaration())
|
|
||||||
return F;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (User::op_iterator i = V->op_begin(), e = V->op_end(); i != e; ++i) {
|
|
||||||
Constant *C = dyn_cast<Constant>(*i);
|
|
||||||
if (C && !isa<GlobalValue>(C) && !Done.count(C))
|
|
||||||
Todo.push_back(C);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
Constant *I = GV->getInitializer();
|
||||||
|
|
||||||
|
// walk the values used by the initializer
|
||||||
|
// (and recurse into things like ConstantExpr)
|
||||||
|
std::vector<Constant *> Todo;
|
||||||
|
std::set<Constant *> Done;
|
||||||
|
Todo.push_back(I);
|
||||||
|
|
||||||
|
while (!Todo.empty()) {
|
||||||
|
Constant *V = Todo.back();
|
||||||
|
Todo.pop_back();
|
||||||
|
Done.insert(V);
|
||||||
|
|
||||||
|
if (BlockAddress *BA = dyn_cast<BlockAddress>(V)) {
|
||||||
|
Function *F = BA->getFunction();
|
||||||
|
if (F->isDeclaration())
|
||||||
|
return F;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (User::op_iterator i = V->op_begin(), e = V->op_end(); i != e; ++i) {
|
||||||
|
Constant *C = dyn_cast<Constant>(*i);
|
||||||
|
if (C && !isa<GlobalValue>(C) && !Done.count(C))
|
||||||
|
Todo.push_back(C);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} // end anonymous namespace
|
return nullptr;
|
||||||
|
}
|
||||||
|
} // end anonymous namespace
|
||||||
|
|
||||||
std::unique_ptr<Module>
|
std::unique_ptr<Module>
|
||||||
BugDriver::deleteInstructionFromProgram(const Instruction *I,
|
BugDriver::deleteInstructionFromProgram(const Instruction *I,
|
||||||
|
@ -92,10 +91,10 @@ BugDriver::deleteInstructionFromProgram(const Instruction *I,
|
||||||
const Function *PF = PBB->getParent();
|
const Function *PF = PBB->getParent();
|
||||||
|
|
||||||
Module::iterator RFI = Clone->begin(); // Get iterator to corresponding fn
|
Module::iterator RFI = Clone->begin(); // Get iterator to corresponding fn
|
||||||
std::advance(RFI, std::distance(PF->getParent()->begin(),
|
std::advance(
|
||||||
Module::const_iterator(PF)));
|
RFI, std::distance(PF->getParent()->begin(), Module::const_iterator(PF)));
|
||||||
|
|
||||||
Function::iterator RBI = RFI->begin(); // Get iterator to corresponding BB
|
Function::iterator RBI = RFI->begin(); // Get iterator to corresponding BB
|
||||||
std::advance(RBI, std::distance(PF->begin(), Function::const_iterator(PBB)));
|
std::advance(RBI, std::distance(PF->begin(), Function::const_iterator(PBB)));
|
||||||
|
|
||||||
BasicBlock::iterator RI = RBI->begin(); // Get iterator to corresponding inst
|
BasicBlock::iterator RI = RBI->begin(); // Get iterator to corresponding inst
|
||||||
|
@ -116,7 +115,7 @@ BugDriver::deleteInstructionFromProgram(const Instruction *I,
|
||||||
if (Simplification > 1 && !NoDCE)
|
if (Simplification > 1 && !NoDCE)
|
||||||
Passes.push_back("dce");
|
Passes.push_back("dce");
|
||||||
if (Simplification && !DisableSimplifyCFG)
|
if (Simplification && !DisableSimplifyCFG)
|
||||||
Passes.push_back("simplifycfg"); // Delete dead control flow
|
Passes.push_back("simplifycfg"); // Delete dead control flow
|
||||||
|
|
||||||
Passes.push_back("verify");
|
Passes.push_back("verify");
|
||||||
std::unique_ptr<Module> New = runPassesOn(Clone, Passes);
|
std::unique_ptr<Module> New = runPassesOn(Clone, Passes);
|
||||||
|
@ -184,15 +183,16 @@ static void eliminateAliases(GlobalValue *GV) {
|
||||||
// GlobalAlias MAY NOT reference declarations.
|
// GlobalAlias MAY NOT reference declarations.
|
||||||
for (;;) {
|
for (;;) {
|
||||||
// 1. Find aliases
|
// 1. Find aliases
|
||||||
SmallVector<GlobalAlias*,1> aliases;
|
SmallVector<GlobalAlias *, 1> aliases;
|
||||||
Module *M = GV->getParent();
|
Module *M = GV->getParent();
|
||||||
for (Module::alias_iterator I=M->alias_begin(), E=M->alias_end(); I!=E; ++I)
|
for (Module::alias_iterator I = M->alias_begin(), E = M->alias_end();
|
||||||
|
I != E; ++I)
|
||||||
if (I->getAliasee()->stripPointerCasts() == GV)
|
if (I->getAliasee()->stripPointerCasts() == GV)
|
||||||
aliases.push_back(&*I);
|
aliases.push_back(&*I);
|
||||||
if (aliases.empty())
|
if (aliases.empty())
|
||||||
break;
|
break;
|
||||||
// 2. Resolve aliases
|
// 2. Resolve aliases
|
||||||
for (unsigned i=0, e=aliases.size(); i<e; ++i) {
|
for (unsigned i = 0, e = aliases.size(); i < e; ++i) {
|
||||||
aliases[i]->replaceAllUsesWith(aliases[i]->getAliasee());
|
aliases[i]->replaceAllUsesWith(aliases[i]->getAliasee());
|
||||||
aliases[i]->eraseFromParent();
|
aliases[i]->eraseFromParent();
|
||||||
}
|
}
|
||||||
|
@ -202,7 +202,8 @@ static void eliminateAliases(GlobalValue *GV) {
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// DeleteGlobalInitializer - "Remove" the global variable by deleting its initializer,
|
// DeleteGlobalInitializer - "Remove" the global variable by deleting its
|
||||||
|
// initializer,
|
||||||
// making it external.
|
// making it external.
|
||||||
//
|
//
|
||||||
void llvm::DeleteGlobalInitializer(GlobalVariable *GV) {
|
void llvm::DeleteGlobalInitializer(GlobalVariable *GV) {
|
||||||
|
@ -225,23 +226,20 @@ void llvm::DeleteFunctionBody(Function *F) {
|
||||||
|
|
||||||
/// GetTorInit - Given a list of entries for static ctors/dtors, return them
|
/// GetTorInit - Given a list of entries for static ctors/dtors, return them
|
||||||
/// as a constant array.
|
/// as a constant array.
|
||||||
static Constant *GetTorInit(std::vector<std::pair<Function*, int> > &TorList) {
|
static Constant *GetTorInit(std::vector<std::pair<Function *, int>> &TorList) {
|
||||||
assert(!TorList.empty() && "Don't create empty tor list!");
|
assert(!TorList.empty() && "Don't create empty tor list!");
|
||||||
std::vector<Constant*> ArrayElts;
|
std::vector<Constant *> ArrayElts;
|
||||||
Type *Int32Ty = Type::getInt32Ty(TorList[0].first->getContext());
|
Type *Int32Ty = Type::getInt32Ty(TorList[0].first->getContext());
|
||||||
|
|
||||||
StructType *STy =
|
StructType *STy =
|
||||||
StructType::get(Int32Ty, TorList[0].first->getType(), nullptr);
|
StructType::get(Int32Ty, TorList[0].first->getType(), nullptr);
|
||||||
for (unsigned i = 0, e = TorList.size(); i != e; ++i) {
|
for (unsigned i = 0, e = TorList.size(); i != e; ++i) {
|
||||||
Constant *Elts[] = {
|
Constant *Elts[] = {ConstantInt::get(Int32Ty, TorList[i].second),
|
||||||
ConstantInt::get(Int32Ty, TorList[i].second),
|
TorList[i].first};
|
||||||
TorList[i].first
|
|
||||||
};
|
|
||||||
ArrayElts.push_back(ConstantStruct::get(STy, Elts));
|
ArrayElts.push_back(ConstantStruct::get(STy, Elts));
|
||||||
}
|
}
|
||||||
return ConstantArray::get(ArrayType::get(ArrayElts[0]->getType(),
|
return ConstantArray::get(
|
||||||
ArrayElts.size()),
|
ArrayType::get(ArrayElts[0]->getType(), ArrayElts.size()), ArrayElts);
|
||||||
ArrayElts);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// SplitStaticCtorDtor - A module was recently split into two parts, M1/M2, and
|
/// SplitStaticCtorDtor - A module was recently split into two parts, M1/M2, and
|
||||||
|
@ -251,23 +249,26 @@ static Constant *GetTorInit(std::vector<std::pair<Function*, int> > &TorList) {
|
||||||
static void SplitStaticCtorDtor(const char *GlobalName, Module *M1, Module *M2,
|
static void SplitStaticCtorDtor(const char *GlobalName, Module *M1, Module *M2,
|
||||||
ValueToValueMapTy &VMap) {
|
ValueToValueMapTy &VMap) {
|
||||||
GlobalVariable *GV = M1->getNamedGlobal(GlobalName);
|
GlobalVariable *GV = M1->getNamedGlobal(GlobalName);
|
||||||
if (!GV || GV->isDeclaration() || GV->hasLocalLinkage() ||
|
if (!GV || GV->isDeclaration() || GV->hasLocalLinkage() || !GV->use_empty())
|
||||||
!GV->use_empty()) return;
|
return;
|
||||||
|
|
||||||
std::vector<std::pair<Function*, int> > M1Tors, M2Tors;
|
std::vector<std::pair<Function *, int>> M1Tors, M2Tors;
|
||||||
ConstantArray *InitList = dyn_cast<ConstantArray>(GV->getInitializer());
|
ConstantArray *InitList = dyn_cast<ConstantArray>(GV->getInitializer());
|
||||||
if (!InitList) return;
|
if (!InitList)
|
||||||
|
return;
|
||||||
|
|
||||||
for (unsigned i = 0, e = InitList->getNumOperands(); i != e; ++i) {
|
for (unsigned i = 0, e = InitList->getNumOperands(); i != e; ++i) {
|
||||||
if (ConstantStruct *CS = dyn_cast<ConstantStruct>(InitList->getOperand(i))){
|
if (ConstantStruct *CS =
|
||||||
if (CS->getNumOperands() != 2) return; // Not array of 2-element structs.
|
dyn_cast<ConstantStruct>(InitList->getOperand(i))) {
|
||||||
|
if (CS->getNumOperands() != 2)
|
||||||
|
return; // Not array of 2-element structs.
|
||||||
|
|
||||||
if (CS->getOperand(1)->isNullValue())
|
if (CS->getOperand(1)->isNullValue())
|
||||||
break; // Found a null terminator, stop here.
|
break; // Found a null terminator, stop here.
|
||||||
|
|
||||||
ConstantInt *CI = dyn_cast<ConstantInt>(CS->getOperand(0));
|
ConstantInt *CI = dyn_cast<ConstantInt>(CS->getOperand(0));
|
||||||
int Priority = CI ? CI->getSExtValue() : 0;
|
int Priority = CI ? CI->getSExtValue() : 0;
|
||||||
|
|
||||||
Constant *FP = CS->getOperand(1);
|
Constant *FP = CS->getOperand(1);
|
||||||
if (ConstantExpr *CE = dyn_cast<ConstantExpr>(FP))
|
if (ConstantExpr *CE = dyn_cast<ConstantExpr>(FP))
|
||||||
if (CE->isCast())
|
if (CE->isCast())
|
||||||
|
@ -283,13 +284,12 @@ static void SplitStaticCtorDtor(const char *GlobalName, Module *M1, Module *M2,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GV->eraseFromParent();
|
GV->eraseFromParent();
|
||||||
if (!M1Tors.empty()) {
|
if (!M1Tors.empty()) {
|
||||||
Constant *M1Init = GetTorInit(M1Tors);
|
Constant *M1Init = GetTorInit(M1Tors);
|
||||||
new GlobalVariable(*M1, M1Init->getType(), false,
|
new GlobalVariable(*M1, M1Init->getType(), false,
|
||||||
GlobalValue::AppendingLinkage,
|
GlobalValue::AppendingLinkage, M1Init, GlobalName);
|
||||||
M1Init, GlobalName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GV = M2->getNamedGlobal(GlobalName);
|
GV = M2->getNamedGlobal(GlobalName);
|
||||||
|
@ -300,8 +300,7 @@ static void SplitStaticCtorDtor(const char *GlobalName, Module *M1, Module *M2,
|
||||||
if (!M2Tors.empty()) {
|
if (!M2Tors.empty()) {
|
||||||
Constant *M2Init = GetTorInit(M2Tors);
|
Constant *M2Init = GetTorInit(M2Tors);
|
||||||
new GlobalVariable(*M2, M2Init->getType(), false,
|
new GlobalVariable(*M2, M2Init->getType(), false,
|
||||||
GlobalValue::AppendingLinkage,
|
GlobalValue::AppendingLinkage, M2Init, GlobalName);
|
||||||
M2Init, GlobalName);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -330,10 +329,9 @@ llvm::SplitFunctionsOutOfModule(Module *M, const std::vector<Function *> &F,
|
||||||
DEBUG(TNOF->printAsOperand(errs(), false));
|
DEBUG(TNOF->printAsOperand(errs(), false));
|
||||||
DEBUG(errs() << "\n");
|
DEBUG(errs() << "\n");
|
||||||
TestFunctions.insert(cast<Function>(NewVMap[TNOF]));
|
TestFunctions.insert(cast<Function>(NewVMap[TNOF]));
|
||||||
DeleteFunctionBody(TNOF); // Function is now external in this module!
|
DeleteFunctionBody(TNOF); // Function is now external in this module!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Remove the Safe functions from the Test module
|
// Remove the Safe functions from the Test module
|
||||||
for (Function &I : *New)
|
for (Function &I : *New)
|
||||||
if (!TestFunctions.count(&I))
|
if (!TestFunctions.count(&I))
|
||||||
|
@ -348,8 +346,9 @@ llvm::SplitFunctionsOutOfModule(Module *M, const std::vector<Function *> &F,
|
||||||
"the global '";
|
"the global '";
|
||||||
GV->printAsOperand(errs(), false);
|
GV->printAsOperand(errs(), false);
|
||||||
errs() << "' with an initializer that references blockaddresses "
|
errs() << "' with an initializer that references blockaddresses "
|
||||||
"from safe function '" << SafeFn->getName()
|
"from safe function '"
|
||||||
<< "' and from test function '" << TestFn->getName() << "'.\n";
|
<< SafeFn->getName() << "' and from test function '"
|
||||||
|
<< TestFn->getName() << "'.\n";
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
DeleteGlobalInitializer(&I); // Delete the initializer to make it external
|
DeleteGlobalInitializer(&I); // Delete the initializer to make it external
|
||||||
|
@ -387,12 +386,13 @@ BugDriver::extractMappedBlocksFromModule(const std::vector<BasicBlock *> &BBs,
|
||||||
sys::RemoveFileOnSignal(Filename);
|
sys::RemoveFileOnSignal(Filename);
|
||||||
|
|
||||||
tool_output_file BlocksToNotExtractFile(Filename.c_str(), FD);
|
tool_output_file BlocksToNotExtractFile(Filename.c_str(), FD);
|
||||||
for (std::vector<BasicBlock*>::const_iterator I = BBs.begin(), E = BBs.end();
|
for (std::vector<BasicBlock *>::const_iterator I = BBs.begin(), E = BBs.end();
|
||||||
I != E; ++I) {
|
I != E; ++I) {
|
||||||
BasicBlock *BB = *I;
|
BasicBlock *BB = *I;
|
||||||
// If the BB doesn't have a name, give it one so we have something to key
|
// If the BB doesn't have a name, give it one so we have something to key
|
||||||
// off of.
|
// off of.
|
||||||
if (!BB->hasName()) BB->setName("tmpbb");
|
if (!BB->hasName())
|
||||||
|
BB->setName("tmpbb");
|
||||||
BlocksToNotExtractFile.os() << BB->getParent()->getName() << " "
|
BlocksToNotExtractFile.os() << BB->getParent()->getName() << " "
|
||||||
<< BB->getName() << "\n";
|
<< BB->getName() << "\n";
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,8 @@
|
||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
//
|
//
|
||||||
// This file defines an interface that allows bugpoint to choose different
|
// This file defines an interface that allows bugpoint to choose different
|
||||||
// combinations of optimizations to run on the selected input. Bugpoint will
|
// combinations of optimizations to run on the selected input. Bugpoint will
|
||||||
// run these optimizations and record the success/failure of each. This way
|
// run these optimizations and record the success/failure of each. This way
|
||||||
// we can hopefully spot bugs in the optimizations.
|
// we can hopefully spot bugs in the optimizations.
|
||||||
//
|
//
|
||||||
|
@ -23,47 +23,48 @@
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
/// runManyPasses - Take the specified pass list and create different
|
/// runManyPasses - Take the specified pass list and create different
|
||||||
/// combinations of passes to compile the program with. Compile the program with
|
/// 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
|
/// 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.
|
/// compiled correctly output nothing and rearrange the passes into a new order.
|
||||||
/// If the passes did not compile correctly, output the command required to
|
/// If the passes did not compile correctly, output the command required to
|
||||||
/// recreate the failure. This returns true if a compiler error is found.
|
/// recreate the failure. This returns true if a compiler error is found.
|
||||||
///
|
///
|
||||||
bool BugDriver::runManyPasses(const std::vector<std::string> &AllPasses,
|
bool BugDriver::runManyPasses(const std::vector<std::string> &AllPasses,
|
||||||
std::string &ErrMsg) {
|
std::string &ErrMsg) {
|
||||||
setPassesToRun(AllPasses);
|
setPassesToRun(AllPasses);
|
||||||
outs() << "Starting bug finding procedure...\n\n";
|
outs() << "Starting bug finding procedure...\n\n";
|
||||||
|
|
||||||
// Creating a reference output if necessary
|
// Creating a reference output if necessary
|
||||||
if (initializeExecutionEnvironment()) return false;
|
if (initializeExecutionEnvironment())
|
||||||
|
return false;
|
||||||
|
|
||||||
outs() << "\n";
|
outs() << "\n";
|
||||||
if (ReferenceOutputFile.empty()) {
|
if (ReferenceOutputFile.empty()) {
|
||||||
outs() << "Generating reference output from raw program: \n";
|
outs() << "Generating reference output from raw program: \n";
|
||||||
if (!createReferenceFile(Program))
|
if (!createReferenceFile(Program))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
srand(time(nullptr));
|
srand(time(nullptr));
|
||||||
|
|
||||||
unsigned num = 1;
|
unsigned num = 1;
|
||||||
while(1) {
|
while (1) {
|
||||||
//
|
//
|
||||||
// Step 1: Randomize the order of the optimizer passes.
|
// Step 1: Randomize the order of the optimizer passes.
|
||||||
//
|
//
|
||||||
std::random_shuffle(PassesToRun.begin(), PassesToRun.end());
|
std::random_shuffle(PassesToRun.begin(), PassesToRun.end());
|
||||||
|
|
||||||
//
|
//
|
||||||
// Step 2: Run optimizer passes on the program and check for success.
|
// Step 2: Run optimizer passes on the program and check for success.
|
||||||
//
|
//
|
||||||
outs() << "Running selected passes on program to test for crash: ";
|
outs() << "Running selected passes on program to test for crash: ";
|
||||||
for(int i = 0, e = PassesToRun.size(); i != e; i++) {
|
for (int i = 0, e = PassesToRun.size(); i != e; i++) {
|
||||||
outs() << "-" << PassesToRun[i] << " ";
|
outs() << "-" << PassesToRun[i] << " ";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Filename;
|
std::string Filename;
|
||||||
if(runPasses(Program, PassesToRun, Filename, false)) {
|
if (runPasses(Program, PassesToRun, Filename, false)) {
|
||||||
outs() << "\n";
|
outs() << "\n";
|
||||||
outs() << "Optimizer passes caused failure!\n\n";
|
outs() << "Optimizer passes caused failure!\n\n";
|
||||||
debugOptimizerCrash();
|
debugOptimizerCrash();
|
||||||
|
@ -71,7 +72,7 @@ bool BugDriver::runManyPasses(const std::vector<std::string> &AllPasses,
|
||||||
} else {
|
} else {
|
||||||
outs() << "Combination " << num << " optimized successfully!\n";
|
outs() << "Combination " << num << " optimized successfully!\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Step 3: Compile the optimized code.
|
// Step 3: Compile the optimized code.
|
||||||
//
|
//
|
||||||
|
@ -84,9 +85,9 @@ bool BugDriver::runManyPasses(const std::vector<std::string> &AllPasses,
|
||||||
return debugCodeGeneratorCrash(ErrMsg);
|
return debugCodeGeneratorCrash(ErrMsg);
|
||||||
}
|
}
|
||||||
outs() << '\n';
|
outs() << '\n';
|
||||||
|
|
||||||
//
|
//
|
||||||
// Step 4: Run the program and compare its output to the reference
|
// Step 4: Run the program and compare its output to the reference
|
||||||
// output (created above).
|
// output (created above).
|
||||||
//
|
//
|
||||||
outs() << "*** Checking if passes caused miscompliation:\n";
|
outs() << "*** Checking if passes caused miscompliation:\n";
|
||||||
|
@ -103,12 +104,12 @@ bool BugDriver::runManyPasses(const std::vector<std::string> &AllPasses,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
outs() << "\n*** diff'd output matches!\n";
|
outs() << "\n*** diff'd output matches!\n";
|
||||||
|
|
||||||
sys::fs::remove(Filename);
|
sys::fs::remove(Filename);
|
||||||
|
|
||||||
outs() << "\n\n";
|
outs() << "\n\n";
|
||||||
num++;
|
num++;
|
||||||
} //end while
|
} // end while
|
||||||
|
|
||||||
// Unreachable.
|
// Unreachable.
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
#include "BugDriver.h"
|
#include "BugDriver.h"
|
||||||
#include "ListReducer.h"
|
#include "ListReducer.h"
|
||||||
#include "ToolRunner.h"
|
#include "ToolRunner.h"
|
||||||
#include "llvm/Config/config.h" // for HAVE_LINK_R
|
#include "llvm/Config/config.h" // for HAVE_LINK_R
|
||||||
#include "llvm/IR/Constants.h"
|
#include "llvm/IR/Constants.h"
|
||||||
#include "llvm/IR/DerivedTypes.h"
|
#include "llvm/IR/DerivedTypes.h"
|
||||||
#include "llvm/IR/Instructions.h"
|
#include "llvm/IR/Instructions.h"
|
||||||
|
@ -30,29 +30,30 @@
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
extern cl::opt<std::string> OutputPrefix;
|
extern cl::opt<std::string> OutputPrefix;
|
||||||
extern cl::list<std::string> InputArgv;
|
extern cl::list<std::string> InputArgv;
|
||||||
} // end namespace llvm
|
} // end namespace llvm
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
static llvm::cl::opt<bool>
|
static llvm::cl::opt<bool> DisableLoopExtraction(
|
||||||
DisableLoopExtraction("disable-loop-extraction",
|
"disable-loop-extraction",
|
||||||
cl::desc("Don't extract loops when searching for miscompilations"),
|
cl::desc("Don't extract loops when searching for miscompilations"),
|
||||||
cl::init(false));
|
cl::init(false));
|
||||||
static llvm::cl::opt<bool>
|
static llvm::cl::opt<bool> DisableBlockExtraction(
|
||||||
DisableBlockExtraction("disable-block-extraction",
|
"disable-block-extraction",
|
||||||
cl::desc("Don't extract blocks when searching for miscompilations"),
|
cl::desc("Don't extract blocks when searching for miscompilations"),
|
||||||
cl::init(false));
|
cl::init(false));
|
||||||
|
|
||||||
class ReduceMiscompilingPasses : public ListReducer<std::string> {
|
class ReduceMiscompilingPasses : public ListReducer<std::string> {
|
||||||
BugDriver &BD;
|
BugDriver &BD;
|
||||||
public:
|
|
||||||
ReduceMiscompilingPasses(BugDriver &bd) : BD(bd) {}
|
|
||||||
|
|
||||||
TestResult doTest(std::vector<std::string> &Prefix,
|
public:
|
||||||
std::vector<std::string> &Suffix,
|
ReduceMiscompilingPasses(BugDriver &bd) : BD(bd) {}
|
||||||
std::string &Error) override;
|
|
||||||
};
|
TestResult doTest(std::vector<std::string> &Prefix,
|
||||||
|
std::vector<std::string> &Suffix,
|
||||||
|
std::string &Error) override;
|
||||||
|
};
|
||||||
} // end anonymous namespace
|
} // end anonymous namespace
|
||||||
|
|
||||||
/// TestResult - After passes have been split into a test group and a control
|
/// TestResult - After passes have been split into a test group and a control
|
||||||
|
@ -68,12 +69,12 @@ ReduceMiscompilingPasses::doTest(std::vector<std::string> &Prefix,
|
||||||
<< "' compiles correctly: ";
|
<< "' compiles correctly: ";
|
||||||
|
|
||||||
std::string BitcodeResult;
|
std::string BitcodeResult;
|
||||||
if (BD.runPasses(BD.getProgram(), Suffix, BitcodeResult, false/*delete*/,
|
if (BD.runPasses(BD.getProgram(), Suffix, BitcodeResult, false /*delete*/,
|
||||||
true/*quiet*/)) {
|
true /*quiet*/)) {
|
||||||
errs() << " Error running this sequence of passes"
|
errs() << " Error running this sequence of passes"
|
||||||
<< " on the input program!\n";
|
<< " on the input program!\n";
|
||||||
BD.setPassesToRun(Suffix);
|
BD.setPassesToRun(Suffix);
|
||||||
BD.EmitProgressBitcode(BD.getProgram(), "pass-error", false);
|
BD.EmitProgressBitcode(BD.getProgram(), "pass-error", false);
|
||||||
exit(BD.debugOptimizerCrash());
|
exit(BD.debugOptimizerCrash());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,11 +90,12 @@ ReduceMiscompilingPasses::doTest(std::vector<std::string> &Prefix,
|
||||||
<< "no passes are run, nondeterministic program?\n";
|
<< "no passes are run, nondeterministic program?\n";
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
return KeepSuffix; // Miscompilation detected!
|
return KeepSuffix; // Miscompilation detected!
|
||||||
}
|
}
|
||||||
outs() << " yup.\n"; // No miscompilation!
|
outs() << " yup.\n"; // No miscompilation!
|
||||||
|
|
||||||
if (Prefix.empty()) return NoFailure;
|
if (Prefix.empty())
|
||||||
|
return NoFailure;
|
||||||
|
|
||||||
// Next, see if the program is broken if we run the "prefix" passes first,
|
// Next, see if the program is broken if we run the "prefix" passes first,
|
||||||
// then separately run the "kept" passes.
|
// then separately run the "kept" passes.
|
||||||
|
@ -106,12 +108,12 @@ ReduceMiscompilingPasses::doTest(std::vector<std::string> &Prefix,
|
||||||
// kept passes, we can update our bitcode file to include the result of the
|
// kept passes, we can update our bitcode file to include the result of the
|
||||||
// prefix passes, then discard the prefix passes.
|
// prefix passes, then discard the prefix passes.
|
||||||
//
|
//
|
||||||
if (BD.runPasses(BD.getProgram(), Prefix, BitcodeResult, false/*delete*/,
|
if (BD.runPasses(BD.getProgram(), Prefix, BitcodeResult, false /*delete*/,
|
||||||
true/*quiet*/)) {
|
true /*quiet*/)) {
|
||||||
errs() << " Error running this sequence of passes"
|
errs() << " Error running this sequence of passes"
|
||||||
<< " on the input program!\n";
|
<< " on the input program!\n";
|
||||||
BD.setPassesToRun(Prefix);
|
BD.setPassesToRun(Prefix);
|
||||||
BD.EmitProgressBitcode(BD.getProgram(), "pass-error", false);
|
BD.EmitProgressBitcode(BD.getProgram(), "pass-error", false);
|
||||||
exit(BD.debugOptimizerCrash());
|
exit(BD.debugOptimizerCrash());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,7 +126,7 @@ ReduceMiscompilingPasses::doTest(std::vector<std::string> &Prefix,
|
||||||
sys::fs::remove(BitcodeResult);
|
sys::fs::remove(BitcodeResult);
|
||||||
return KeepPrefix;
|
return KeepPrefix;
|
||||||
}
|
}
|
||||||
outs() << " yup.\n"; // No miscompilation!
|
outs() << " yup.\n"; // No miscompilation!
|
||||||
|
|
||||||
// Ok, so now we know that the prefix passes work, try running the suffix
|
// Ok, so now we know that the prefix passes work, try running the suffix
|
||||||
// passes on the result of the prefix passes.
|
// passes on the result of the prefix passes.
|
||||||
|
@ -143,17 +145,17 @@ ReduceMiscompilingPasses::doTest(std::vector<std::string> &Prefix,
|
||||||
return NoFailure;
|
return NoFailure;
|
||||||
|
|
||||||
outs() << "Checking to see if '" << getPassesString(Suffix)
|
outs() << "Checking to see if '" << getPassesString(Suffix)
|
||||||
<< "' passes compile correctly after the '"
|
<< "' passes compile correctly after the '" << getPassesString(Prefix)
|
||||||
<< getPassesString(Prefix) << "' passes: ";
|
<< "' passes: ";
|
||||||
|
|
||||||
std::unique_ptr<Module> OriginalInput(
|
std::unique_ptr<Module> OriginalInput(
|
||||||
BD.swapProgramIn(PrefixOutput.release()));
|
BD.swapProgramIn(PrefixOutput.release()));
|
||||||
if (BD.runPasses(BD.getProgram(), Suffix, BitcodeResult, false/*delete*/,
|
if (BD.runPasses(BD.getProgram(), Suffix, BitcodeResult, false /*delete*/,
|
||||||
true/*quiet*/)) {
|
true /*quiet*/)) {
|
||||||
errs() << " Error running this sequence of passes"
|
errs() << " Error running this sequence of passes"
|
||||||
<< " on the input program!\n";
|
<< " on the input program!\n";
|
||||||
BD.setPassesToRun(Suffix);
|
BD.setPassesToRun(Suffix);
|
||||||
BD.EmitProgressBitcode(BD.getProgram(), "pass-error", false);
|
BD.EmitProgressBitcode(BD.getProgram(), "pass-error", false);
|
||||||
exit(BD.debugOptimizerCrash());
|
exit(BD.debugOptimizerCrash());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,47 +170,46 @@ ReduceMiscompilingPasses::doTest(std::vector<std::string> &Prefix,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, we must not be running the bad pass anymore.
|
// Otherwise, we must not be running the bad pass anymore.
|
||||||
outs() << " yup.\n"; // No miscompilation!
|
outs() << " yup.\n"; // No miscompilation!
|
||||||
// Restore orig program & free test.
|
// Restore orig program & free test.
|
||||||
delete BD.swapProgramIn(OriginalInput.release());
|
delete BD.swapProgramIn(OriginalInput.release());
|
||||||
return NoFailure;
|
return NoFailure;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
class ReduceMiscompilingFunctions : public ListReducer<Function*> {
|
class ReduceMiscompilingFunctions : public ListReducer<Function *> {
|
||||||
BugDriver &BD;
|
BugDriver &BD;
|
||||||
bool (*TestFn)(BugDriver &, std::unique_ptr<Module>,
|
bool (*TestFn)(BugDriver &, std::unique_ptr<Module>, std::unique_ptr<Module>,
|
||||||
std::unique_ptr<Module>, std::string &);
|
std::string &);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ReduceMiscompilingFunctions(BugDriver &bd,
|
ReduceMiscompilingFunctions(BugDriver &bd,
|
||||||
bool (*F)(BugDriver &, std::unique_ptr<Module>,
|
bool (*F)(BugDriver &, std::unique_ptr<Module>,
|
||||||
std::unique_ptr<Module>,
|
std::unique_ptr<Module>, std::string &))
|
||||||
std::string &))
|
: BD(bd), TestFn(F) {}
|
||||||
: BD(bd), TestFn(F) {}
|
|
||||||
|
|
||||||
TestResult doTest(std::vector<Function*> &Prefix,
|
TestResult doTest(std::vector<Function *> &Prefix,
|
||||||
std::vector<Function*> &Suffix,
|
std::vector<Function *> &Suffix,
|
||||||
std::string &Error) override {
|
std::string &Error) override {
|
||||||
if (!Suffix.empty()) {
|
if (!Suffix.empty()) {
|
||||||
bool Ret = TestFuncs(Suffix, Error);
|
bool Ret = TestFuncs(Suffix, Error);
|
||||||
if (!Error.empty())
|
if (!Error.empty())
|
||||||
return InternalError;
|
return InternalError;
|
||||||
if (Ret)
|
if (Ret)
|
||||||
return KeepSuffix;
|
return KeepSuffix;
|
||||||
}
|
|
||||||
if (!Prefix.empty()) {
|
|
||||||
bool Ret = TestFuncs(Prefix, Error);
|
|
||||||
if (!Error.empty())
|
|
||||||
return InternalError;
|
|
||||||
if (Ret)
|
|
||||||
return KeepPrefix;
|
|
||||||
}
|
|
||||||
return NoFailure;
|
|
||||||
}
|
}
|
||||||
|
if (!Prefix.empty()) {
|
||||||
|
bool Ret = TestFuncs(Prefix, Error);
|
||||||
|
if (!Error.empty())
|
||||||
|
return InternalError;
|
||||||
|
if (Ret)
|
||||||
|
return KeepPrefix;
|
||||||
|
}
|
||||||
|
return NoFailure;
|
||||||
|
}
|
||||||
|
|
||||||
bool TestFuncs(const std::vector<Function*> &Prefix, std::string &Error);
|
bool TestFuncs(const std::vector<Function *> &Prefix, std::string &Error);
|
||||||
};
|
};
|
||||||
} // end anonymous namespace
|
} // end anonymous namespace
|
||||||
|
|
||||||
/// Given two modules, link them together and run the program, checking to see
|
/// Given two modules, link them together and run the program, checking to see
|
||||||
|
@ -236,12 +237,12 @@ static std::unique_ptr<Module> testMergedProgram(const BugDriver &BD,
|
||||||
/// under consideration for miscompilation vs. those that are not, and test
|
/// under consideration for miscompilation vs. those that are not, and test
|
||||||
/// accordingly. Each group of functions becomes a separate Module.
|
/// accordingly. Each group of functions becomes a separate Module.
|
||||||
///
|
///
|
||||||
bool ReduceMiscompilingFunctions::TestFuncs(const std::vector<Function*> &Funcs,
|
bool ReduceMiscompilingFunctions::TestFuncs(
|
||||||
std::string &Error) {
|
const std::vector<Function *> &Funcs, std::string &Error) {
|
||||||
// Test to see if the function is misoptimized if we ONLY run it on the
|
// Test to see if the function is misoptimized if we ONLY run it on the
|
||||||
// functions listed in Funcs.
|
// functions listed in Funcs.
|
||||||
outs() << "Checking to see if the program is misoptimized when "
|
outs() << "Checking to see if the program is misoptimized when "
|
||||||
<< (Funcs.size()==1 ? "this function is" : "these functions are")
|
<< (Funcs.size() == 1 ? "this function is" : "these functions are")
|
||||||
<< " run through the pass"
|
<< " run through the pass"
|
||||||
<< (BD.getPassesToRun().size() == 1 ? "" : "es") << ":";
|
<< (BD.getPassesToRun().size() == 1 ? "" : "es") << ":";
|
||||||
PrintFunctionList(Funcs);
|
PrintFunctionList(Funcs);
|
||||||
|
@ -258,7 +259,7 @@ bool ReduceMiscompilingFunctions::TestFuncs(const std::vector<Function*> &Funcs,
|
||||||
Module *Clone = CloneModule(BD.getProgram(), VMap).release();
|
Module *Clone = CloneModule(BD.getProgram(), VMap).release();
|
||||||
Module *Orig = BD.swapProgramIn(Clone);
|
Module *Orig = BD.swapProgramIn(Clone);
|
||||||
|
|
||||||
std::vector<Function*> FuncsOnClone;
|
std::vector<Function *> FuncsOnClone;
|
||||||
for (unsigned i = 0, e = Funcs.size(); i != e; ++i) {
|
for (unsigned i = 0, e = Funcs.size(); i != e; ++i) {
|
||||||
Function *F = cast<Function>(VMap[Funcs[i]]);
|
Function *F = cast<Function>(VMap[Funcs[i]]);
|
||||||
FuncsOnClone.push_back(F);
|
FuncsOnClone.push_back(F);
|
||||||
|
@ -301,7 +302,8 @@ static bool ExtractLoops(BugDriver &BD,
|
||||||
std::string &Error) {
|
std::string &Error) {
|
||||||
bool MadeChange = false;
|
bool MadeChange = false;
|
||||||
while (1) {
|
while (1) {
|
||||||
if (BugpointIsInterrupted) return MadeChange;
|
if (BugpointIsInterrupted)
|
||||||
|
return MadeChange;
|
||||||
|
|
||||||
ValueToValueMapTy VMap;
|
ValueToValueMapTy VMap;
|
||||||
std::unique_ptr<Module> ToNotOptimize = CloneModule(BD.getProgram(), VMap);
|
std::unique_ptr<Module> ToNotOptimize = CloneModule(BD.getProgram(), VMap);
|
||||||
|
@ -353,8 +355,8 @@ static bool ExtractLoops(BugDriver &BD,
|
||||||
BD.writeProgramToFile(OutputPrefix + "-loop-extract-fail-to-le.bc",
|
BD.writeProgramToFile(OutputPrefix + "-loop-extract-fail-to-le.bc",
|
||||||
ToOptimizeLoopExtracted.get());
|
ToOptimizeLoopExtracted.get());
|
||||||
|
|
||||||
errs() << "Please submit the "
|
errs() << "Please submit the " << OutputPrefix
|
||||||
<< OutputPrefix << "-loop-extract-fail-*.bc files.\n";
|
<< "-loop-extract-fail-*.bc files.\n";
|
||||||
delete ToOptimize;
|
delete ToOptimize;
|
||||||
return MadeChange;
|
return MadeChange;
|
||||||
}
|
}
|
||||||
|
@ -383,7 +385,7 @@ static bool ExtractLoops(BugDriver &BD,
|
||||||
// If the program is not still broken, then loop extraction did something
|
// If the program is not still broken, then loop extraction did something
|
||||||
// that masked the error. Stop loop extraction now.
|
// that masked the error. Stop loop extraction now.
|
||||||
|
|
||||||
std::vector<std::pair<std::string, FunctionType*> > MisCompFunctions;
|
std::vector<std::pair<std::string, FunctionType *>> MisCompFunctions;
|
||||||
for (Function *F : MiscompiledFunctions) {
|
for (Function *F : MiscompiledFunctions) {
|
||||||
MisCompFunctions.emplace_back(F->getName(), F->getFunctionType());
|
MisCompFunctions.emplace_back(F->getName(), F->getFunctionType());
|
||||||
}
|
}
|
||||||
|
@ -406,9 +408,10 @@ static bool ExtractLoops(BugDriver &BD,
|
||||||
|
|
||||||
outs() << "*** Loop extraction successful!\n";
|
outs() << "*** Loop extraction successful!\n";
|
||||||
|
|
||||||
std::vector<std::pair<std::string, FunctionType*> > MisCompFunctions;
|
std::vector<std::pair<std::string, FunctionType *>> MisCompFunctions;
|
||||||
for (Module::iterator I = ToOptimizeLoopExtracted->begin(),
|
for (Module::iterator I = ToOptimizeLoopExtracted->begin(),
|
||||||
E = ToOptimizeLoopExtracted->end(); I != E; ++I)
|
E = ToOptimizeLoopExtracted->end();
|
||||||
|
I != E; ++I)
|
||||||
if (!I->isDeclaration())
|
if (!I->isDeclaration())
|
||||||
MisCompFunctions.emplace_back(I->getName(), I->getFunctionType());
|
MisCompFunctions.emplace_back(I->getName(), I->getFunctionType());
|
||||||
|
|
||||||
|
@ -436,46 +439,47 @@ static bool ExtractLoops(BugDriver &BD,
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
class ReduceMiscompiledBlocks : public ListReducer<BasicBlock*> {
|
class ReduceMiscompiledBlocks : public ListReducer<BasicBlock *> {
|
||||||
BugDriver &BD;
|
BugDriver &BD;
|
||||||
bool (*TestFn)(BugDriver &, std::unique_ptr<Module>,
|
bool (*TestFn)(BugDriver &, std::unique_ptr<Module>, std::unique_ptr<Module>,
|
||||||
std::unique_ptr<Module>, std::string &);
|
std::string &);
|
||||||
std::vector<Function*> FunctionsBeingTested;
|
std::vector<Function *> FunctionsBeingTested;
|
||||||
public:
|
|
||||||
ReduceMiscompiledBlocks(BugDriver &bd,
|
|
||||||
bool (*F)(BugDriver &, std::unique_ptr<Module>,
|
|
||||||
std::unique_ptr<Module>, std::string &),
|
|
||||||
const std::vector<Function *> &Fns)
|
|
||||||
: BD(bd), TestFn(F), FunctionsBeingTested(Fns) {}
|
|
||||||
|
|
||||||
TestResult doTest(std::vector<BasicBlock*> &Prefix,
|
public:
|
||||||
std::vector<BasicBlock*> &Suffix,
|
ReduceMiscompiledBlocks(BugDriver &bd,
|
||||||
std::string &Error) override {
|
bool (*F)(BugDriver &, std::unique_ptr<Module>,
|
||||||
if (!Suffix.empty()) {
|
std::unique_ptr<Module>, std::string &),
|
||||||
bool Ret = TestFuncs(Suffix, Error);
|
const std::vector<Function *> &Fns)
|
||||||
if (!Error.empty())
|
: BD(bd), TestFn(F), FunctionsBeingTested(Fns) {}
|
||||||
return InternalError;
|
|
||||||
if (Ret)
|
TestResult doTest(std::vector<BasicBlock *> &Prefix,
|
||||||
return KeepSuffix;
|
std::vector<BasicBlock *> &Suffix,
|
||||||
}
|
std::string &Error) override {
|
||||||
if (!Prefix.empty()) {
|
if (!Suffix.empty()) {
|
||||||
bool Ret = TestFuncs(Prefix, Error);
|
bool Ret = TestFuncs(Suffix, Error);
|
||||||
if (!Error.empty())
|
if (!Error.empty())
|
||||||
return InternalError;
|
return InternalError;
|
||||||
if (Ret)
|
if (Ret)
|
||||||
return KeepPrefix;
|
return KeepSuffix;
|
||||||
}
|
|
||||||
return NoFailure;
|
|
||||||
}
|
}
|
||||||
|
if (!Prefix.empty()) {
|
||||||
|
bool Ret = TestFuncs(Prefix, Error);
|
||||||
|
if (!Error.empty())
|
||||||
|
return InternalError;
|
||||||
|
if (Ret)
|
||||||
|
return KeepPrefix;
|
||||||
|
}
|
||||||
|
return NoFailure;
|
||||||
|
}
|
||||||
|
|
||||||
bool TestFuncs(const std::vector<BasicBlock*> &BBs, std::string &Error);
|
bool TestFuncs(const std::vector<BasicBlock *> &BBs, std::string &Error);
|
||||||
};
|
};
|
||||||
} // end anonymous namespace
|
} // end anonymous namespace
|
||||||
|
|
||||||
/// TestFuncs - Extract all blocks for the miscompiled functions except for the
|
/// TestFuncs - Extract all blocks for the miscompiled functions except for the
|
||||||
/// specified blocks. If the problem still exists, return true.
|
/// specified blocks. If the problem still exists, return true.
|
||||||
///
|
///
|
||||||
bool ReduceMiscompiledBlocks::TestFuncs(const std::vector<BasicBlock*> &BBs,
|
bool ReduceMiscompiledBlocks::TestFuncs(const std::vector<BasicBlock *> &BBs,
|
||||||
std::string &Error) {
|
std::string &Error) {
|
||||||
// Test to see if the function is misoptimized if we ONLY run it on the
|
// Test to see if the function is misoptimized if we ONLY run it on the
|
||||||
// functions listed in Funcs.
|
// functions listed in Funcs.
|
||||||
|
@ -484,7 +488,8 @@ bool ReduceMiscompiledBlocks::TestFuncs(const std::vector<BasicBlock*> &BBs,
|
||||||
outs() << "but these " << BBs.size() << " blocks are extracted: ";
|
outs() << "but these " << BBs.size() << " blocks are extracted: ";
|
||||||
for (unsigned i = 0, e = BBs.size() < 10 ? BBs.size() : 10; i != e; ++i)
|
for (unsigned i = 0, e = BBs.size() < 10 ? BBs.size() : 10; i != e; ++i)
|
||||||
outs() << BBs[i]->getName() << " ";
|
outs() << BBs[i]->getName() << " ";
|
||||||
if (BBs.size() > 10) outs() << "...";
|
if (BBs.size() > 10)
|
||||||
|
outs() << "...";
|
||||||
} else {
|
} else {
|
||||||
outs() << "blocks are extracted.";
|
outs() << "blocks are extracted.";
|
||||||
}
|
}
|
||||||
|
@ -494,8 +499,8 @@ bool ReduceMiscompiledBlocks::TestFuncs(const std::vector<BasicBlock*> &BBs,
|
||||||
ValueToValueMapTy VMap;
|
ValueToValueMapTy VMap;
|
||||||
Module *Clone = CloneModule(BD.getProgram(), VMap).release();
|
Module *Clone = CloneModule(BD.getProgram(), VMap).release();
|
||||||
Module *Orig = BD.swapProgramIn(Clone);
|
Module *Orig = BD.swapProgramIn(Clone);
|
||||||
std::vector<Function*> FuncsOnClone;
|
std::vector<Function *> FuncsOnClone;
|
||||||
std::vector<BasicBlock*> BBsOnClone;
|
std::vector<BasicBlock *> BBsOnClone;
|
||||||
for (unsigned i = 0, e = FunctionsBeingTested.size(); i != e; ++i) {
|
for (unsigned i = 0, e = FunctionsBeingTested.size(); i != e; ++i) {
|
||||||
Function *F = cast<Function>(VMap[FunctionsBeingTested[i]]);
|
Function *F = cast<Function>(VMap[FunctionsBeingTested[i]]);
|
||||||
FuncsOnClone.push_back(F);
|
FuncsOnClone.push_back(F);
|
||||||
|
@ -531,9 +536,10 @@ static bool ExtractBlocks(BugDriver &BD,
|
||||||
std::string &),
|
std::string &),
|
||||||
std::vector<Function *> &MiscompiledFunctions,
|
std::vector<Function *> &MiscompiledFunctions,
|
||||||
std::string &Error) {
|
std::string &Error) {
|
||||||
if (BugpointIsInterrupted) return false;
|
if (BugpointIsInterrupted)
|
||||||
|
return false;
|
||||||
|
|
||||||
std::vector<BasicBlock*> Blocks;
|
std::vector<BasicBlock *> Blocks;
|
||||||
for (unsigned i = 0, e = MiscompiledFunctions.size(); i != e; ++i)
|
for (unsigned i = 0, e = MiscompiledFunctions.size(); i != e; ++i)
|
||||||
for (BasicBlock &BB : *MiscompiledFunctions[i])
|
for (BasicBlock &BB : *MiscompiledFunctions[i])
|
||||||
Blocks.push_back(&BB);
|
Blocks.push_back(&BB);
|
||||||
|
@ -545,14 +551,14 @@ static bool ExtractBlocks(BugDriver &BD,
|
||||||
|
|
||||||
// Check to see if all blocks are extractible first.
|
// Check to see if all blocks are extractible first.
|
||||||
bool Ret = ReduceMiscompiledBlocks(BD, TestFn, MiscompiledFunctions)
|
bool Ret = ReduceMiscompiledBlocks(BD, TestFn, MiscompiledFunctions)
|
||||||
.TestFuncs(std::vector<BasicBlock*>(), Error);
|
.TestFuncs(std::vector<BasicBlock *>(), Error);
|
||||||
if (!Error.empty())
|
if (!Error.empty())
|
||||||
return false;
|
return false;
|
||||||
if (Ret) {
|
if (Ret) {
|
||||||
Blocks.clear();
|
Blocks.clear();
|
||||||
} else {
|
} else {
|
||||||
ReduceMiscompiledBlocks(BD, TestFn,
|
ReduceMiscompiledBlocks(BD, TestFn, MiscompiledFunctions)
|
||||||
MiscompiledFunctions).reduceList(Blocks, Error);
|
.reduceList(Blocks, Error);
|
||||||
if (!Error.empty())
|
if (!Error.empty())
|
||||||
return false;
|
return false;
|
||||||
if (Blocks.size() == OldSize)
|
if (Blocks.size() == OldSize)
|
||||||
|
@ -578,9 +584,9 @@ static bool ExtractBlocks(BugDriver &BD,
|
||||||
// together.
|
// together.
|
||||||
delete ToExtract;
|
delete ToExtract;
|
||||||
|
|
||||||
std::vector<std::pair<std::string, FunctionType*> > MisCompFunctions;
|
std::vector<std::pair<std::string, FunctionType *>> MisCompFunctions;
|
||||||
for (Module::iterator I = Extracted->begin(), E = Extracted->end();
|
for (Module::iterator I = Extracted->begin(), E = Extracted->end(); I != E;
|
||||||
I != E; ++I)
|
++I)
|
||||||
if (!I->isDeclaration())
|
if (!I->isDeclaration())
|
||||||
MisCompFunctions.emplace_back(I->getName(), I->getFunctionType());
|
MisCompFunctions.emplace_back(I->getName(), I->getFunctionType());
|
||||||
|
|
||||||
|
@ -614,7 +620,7 @@ DebugAMiscompilation(BugDriver &BD,
|
||||||
// failure, see if we can pin down which functions are being
|
// failure, see if we can pin down which functions are being
|
||||||
// miscompiled... first build a list of all of the non-external functions in
|
// miscompiled... first build a list of all of the non-external functions in
|
||||||
// the program.
|
// the program.
|
||||||
std::vector<Function*> MiscompiledFunctions;
|
std::vector<Function *> MiscompiledFunctions;
|
||||||
Module *Prog = BD.getProgram();
|
Module *Prog = BD.getProgram();
|
||||||
for (Function &F : *Prog)
|
for (Function &F : *Prog)
|
||||||
if (!F.isDeclaration())
|
if (!F.isDeclaration())
|
||||||
|
@ -622,8 +628,8 @@ DebugAMiscompilation(BugDriver &BD,
|
||||||
|
|
||||||
// Do the reduction...
|
// Do the reduction...
|
||||||
if (!BugpointIsInterrupted)
|
if (!BugpointIsInterrupted)
|
||||||
ReduceMiscompilingFunctions(BD, TestFn).reduceList(MiscompiledFunctions,
|
ReduceMiscompilingFunctions(BD, TestFn)
|
||||||
Error);
|
.reduceList(MiscompiledFunctions, Error);
|
||||||
if (!Error.empty()) {
|
if (!Error.empty()) {
|
||||||
errs() << "\n***Cannot reduce functions: ";
|
errs() << "\n***Cannot reduce functions: ";
|
||||||
return MiscompiledFunctions;
|
return MiscompiledFunctions;
|
||||||
|
@ -648,8 +654,8 @@ DebugAMiscompilation(BugDriver &BD,
|
||||||
|
|
||||||
// Do the reduction...
|
// Do the reduction...
|
||||||
if (!BugpointIsInterrupted)
|
if (!BugpointIsInterrupted)
|
||||||
ReduceMiscompilingFunctions(BD, TestFn).reduceList(MiscompiledFunctions,
|
ReduceMiscompilingFunctions(BD, TestFn)
|
||||||
Error);
|
.reduceList(MiscompiledFunctions, Error);
|
||||||
if (!Error.empty())
|
if (!Error.empty())
|
||||||
return MiscompiledFunctions;
|
return MiscompiledFunctions;
|
||||||
|
|
||||||
|
@ -671,8 +677,8 @@ DebugAMiscompilation(BugDriver &BD,
|
||||||
DisambiguateGlobalSymbols(BD.getProgram());
|
DisambiguateGlobalSymbols(BD.getProgram());
|
||||||
|
|
||||||
// Do the reduction...
|
// Do the reduction...
|
||||||
ReduceMiscompilingFunctions(BD, TestFn).reduceList(MiscompiledFunctions,
|
ReduceMiscompilingFunctions(BD, TestFn)
|
||||||
Error);
|
.reduceList(MiscompiledFunctions, Error);
|
||||||
if (!Error.empty())
|
if (!Error.empty())
|
||||||
return MiscompiledFunctions;
|
return MiscompiledFunctions;
|
||||||
|
|
||||||
|
@ -702,7 +708,7 @@ static bool TestOptimizer(BugDriver &BD, std::unique_ptr<Module> Test,
|
||||||
errs() << " Error running this sequence of passes"
|
errs() << " Error running this sequence of passes"
|
||||||
<< " on the input program!\n";
|
<< " on the input program!\n";
|
||||||
delete BD.swapProgramIn(Test.get());
|
delete BD.swapProgramIn(Test.get());
|
||||||
BD.EmitProgressBitcode(Test.get(), "pass-error", false);
|
BD.EmitProgressBitcode(Test.get(), "pass-error", false);
|
||||||
return BD.debugOptimizerCrash();
|
return BD.debugOptimizerCrash();
|
||||||
}
|
}
|
||||||
outs() << "done.\n";
|
outs() << "done.\n";
|
||||||
|
@ -739,7 +745,7 @@ void BugDriver::debugMiscompilation(std::string *Error) {
|
||||||
EmitProgressBitcode(Program, "passinput");
|
EmitProgressBitcode(Program, "passinput");
|
||||||
|
|
||||||
std::vector<Function *> MiscompiledFunctions =
|
std::vector<Function *> MiscompiledFunctions =
|
||||||
DebugAMiscompilation(*this, TestOptimizer, *Error);
|
DebugAMiscompilation(*this, TestOptimizer, *Error);
|
||||||
if (!Error->empty())
|
if (!Error->empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -753,11 +759,11 @@ void BugDriver::debugMiscompilation(std::string *Error) {
|
||||||
|
|
||||||
outs() << " Non-optimized portion: ";
|
outs() << " Non-optimized portion: ";
|
||||||
EmitProgressBitcode(ToNotOptimize, "tonotoptimize", true);
|
EmitProgressBitcode(ToNotOptimize, "tonotoptimize", true);
|
||||||
delete ToNotOptimize; // Delete hacked module.
|
delete ToNotOptimize; // Delete hacked module.
|
||||||
|
|
||||||
outs() << " Portion that is input to optimizer: ";
|
outs() << " Portion that is input to optimizer: ";
|
||||||
EmitProgressBitcode(ToOptimize, "tooptimize");
|
EmitProgressBitcode(ToOptimize, "tooptimize");
|
||||||
delete ToOptimize; // Delete hacked module.
|
delete ToOptimize; // Delete hacked module.
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the specified modules ready for code generator testing.
|
/// Get the specified modules ready for code generator testing.
|
||||||
|
@ -769,7 +775,8 @@ static void CleanupAndPrepareModules(BugDriver &BD,
|
||||||
Test = BD.performFinalCleanups(Test.get());
|
Test = BD.performFinalCleanups(Test.get());
|
||||||
|
|
||||||
// If we are executing the JIT, we have several nasty issues to take care of.
|
// If we are executing the JIT, we have several nasty issues to take care of.
|
||||||
if (!BD.isExecutingJIT()) return;
|
if (!BD.isExecutingJIT())
|
||||||
|
return;
|
||||||
|
|
||||||
// First, if the main function is in the Safe module, we must add a stub to
|
// First, if the main function is in the Safe module, we must add a stub to
|
||||||
// the Test module to call into it. Thus, we create a new function `main'
|
// the Test module to call into it. Thus, we create a new function `main'
|
||||||
|
@ -788,11 +795,12 @@ static void CleanupAndPrepareModules(BugDriver &BD,
|
||||||
GlobalValue::ExternalLinkage,
|
GlobalValue::ExternalLinkage,
|
||||||
oldMain->getName(), Test.get());
|
oldMain->getName(), Test.get());
|
||||||
// Set up and remember the argument list for the main function.
|
// Set up and remember the argument list for the main function.
|
||||||
std::vector<Value*> args;
|
std::vector<Value *> args;
|
||||||
for (Function::arg_iterator
|
for (Function::arg_iterator I = newMain->arg_begin(),
|
||||||
I = newMain->arg_begin(), E = newMain->arg_end(),
|
E = newMain->arg_end(),
|
||||||
OI = oldMain->arg_begin(); I != E; ++I, ++OI) {
|
OI = oldMain->arg_begin();
|
||||||
I->setName(OI->getName()); // Copy argument names from oldMain
|
I != E; ++I, ++OI) {
|
||||||
|
I->setName(OI->getName()); // Copy argument names from oldMain
|
||||||
args.push_back(&*I);
|
args.push_back(&*I);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -811,11 +819,9 @@ static void CleanupAndPrepareModules(BugDriver &BD,
|
||||||
|
|
||||||
// Add the resolver to the Safe module.
|
// Add the resolver to the Safe module.
|
||||||
// Prototype: void *getPointerToNamedFunction(const char* Name)
|
// Prototype: void *getPointerToNamedFunction(const char* Name)
|
||||||
Constant *resolverFunc =
|
Constant *resolverFunc = Safe->getOrInsertFunction(
|
||||||
Safe->getOrInsertFunction("getPointerToNamedFunction",
|
"getPointerToNamedFunction", Type::getInt8PtrTy(Safe->getContext()),
|
||||||
Type::getInt8PtrTy(Safe->getContext()),
|
Type::getInt8PtrTy(Safe->getContext()), (Type *)nullptr);
|
||||||
Type::getInt8PtrTy(Safe->getContext()),
|
|
||||||
(Type *)nullptr);
|
|
||||||
|
|
||||||
// Use the function we just added to get addresses of functions we need.
|
// Use the function we just added to get addresses of functions we need.
|
||||||
for (Module::iterator F = Safe->begin(), E = Safe->end(); F != E; ++F) {
|
for (Module::iterator F = Safe->begin(), E = Safe->end(); F != E; ++F) {
|
||||||
|
@ -827,21 +833,20 @@ static void CleanupAndPrepareModules(BugDriver &BD,
|
||||||
if (TestFn && !TestFn->isDeclaration()) {
|
if (TestFn && !TestFn->isDeclaration()) {
|
||||||
// 1. Add a string constant with its name to the global file
|
// 1. Add a string constant with its name to the global file
|
||||||
Constant *InitArray =
|
Constant *InitArray =
|
||||||
ConstantDataArray::getString(F->getContext(), F->getName());
|
ConstantDataArray::getString(F->getContext(), F->getName());
|
||||||
GlobalVariable *funcName =
|
GlobalVariable *funcName = new GlobalVariable(
|
||||||
new GlobalVariable(*Safe, InitArray->getType(), true /*isConstant*/,
|
*Safe, InitArray->getType(), true /*isConstant*/,
|
||||||
GlobalValue::InternalLinkage, InitArray,
|
GlobalValue::InternalLinkage, InitArray, F->getName() + "_name");
|
||||||
F->getName() + "_name");
|
|
||||||
|
|
||||||
// 2. Use `GetElementPtr *funcName, 0, 0' to convert the string to an
|
// 2. Use `GetElementPtr *funcName, 0, 0' to convert the string to an
|
||||||
// sbyte* so it matches the signature of the resolver function.
|
// sbyte* so it matches the signature of the resolver function.
|
||||||
|
|
||||||
// GetElementPtr *funcName, ulong 0, ulong 0
|
// GetElementPtr *funcName, ulong 0, ulong 0
|
||||||
std::vector<Constant*> GEPargs(2,
|
std::vector<Constant *> GEPargs(
|
||||||
Constant::getNullValue(Type::getInt32Ty(F->getContext())));
|
2, Constant::getNullValue(Type::getInt32Ty(F->getContext())));
|
||||||
Value *GEP = ConstantExpr::getGetElementPtr(InitArray->getType(),
|
Value *GEP = ConstantExpr::getGetElementPtr(InitArray->getType(),
|
||||||
funcName, GEPargs);
|
funcName, GEPargs);
|
||||||
std::vector<Value*> ResolverArgs;
|
std::vector<Value *> ResolverArgs;
|
||||||
ResolverArgs.push_back(GEP);
|
ResolverArgs.push_back(GEP);
|
||||||
|
|
||||||
// Rewrite uses of F in global initializers, etc. to uses of a wrapper
|
// Rewrite uses of F in global initializers, etc. to uses of a wrapper
|
||||||
|
@ -849,23 +854,21 @@ static void CleanupAndPrepareModules(BugDriver &BD,
|
||||||
if (!F->use_empty()) {
|
if (!F->use_empty()) {
|
||||||
// Create a new global to hold the cached function pointer.
|
// Create a new global to hold the cached function pointer.
|
||||||
Constant *NullPtr = ConstantPointerNull::get(F->getType());
|
Constant *NullPtr = ConstantPointerNull::get(F->getType());
|
||||||
GlobalVariable *Cache =
|
GlobalVariable *Cache = new GlobalVariable(
|
||||||
new GlobalVariable(*F->getParent(), F->getType(),
|
*F->getParent(), F->getType(), false,
|
||||||
false, GlobalValue::InternalLinkage,
|
GlobalValue::InternalLinkage, NullPtr, F->getName() + ".fpcache");
|
||||||
NullPtr,F->getName()+".fpcache");
|
|
||||||
|
|
||||||
// Construct a new stub function that will re-route calls to F
|
// Construct a new stub function that will re-route calls to F
|
||||||
FunctionType *FuncTy = F->getFunctionType();
|
FunctionType *FuncTy = F->getFunctionType();
|
||||||
Function *FuncWrapper = Function::Create(FuncTy,
|
Function *FuncWrapper =
|
||||||
GlobalValue::InternalLinkage,
|
Function::Create(FuncTy, GlobalValue::InternalLinkage,
|
||||||
F->getName() + "_wrapper",
|
F->getName() + "_wrapper", F->getParent());
|
||||||
F->getParent());
|
BasicBlock *EntryBB =
|
||||||
BasicBlock *EntryBB = BasicBlock::Create(F->getContext(),
|
BasicBlock::Create(F->getContext(), "entry", FuncWrapper);
|
||||||
"entry", FuncWrapper);
|
BasicBlock *DoCallBB =
|
||||||
BasicBlock *DoCallBB = BasicBlock::Create(F->getContext(),
|
BasicBlock::Create(F->getContext(), "usecache", FuncWrapper);
|
||||||
"usecache", FuncWrapper);
|
BasicBlock *LookupBB =
|
||||||
BasicBlock *LookupBB = BasicBlock::Create(F->getContext(),
|
BasicBlock::Create(F->getContext(), "lookupfp", FuncWrapper);
|
||||||
"lookupfp", FuncWrapper);
|
|
||||||
|
|
||||||
// Check to see if we already looked up the value.
|
// Check to see if we already looked up the value.
|
||||||
Value *CachedVal = new LoadInst(Cache, "fpcache", EntryBB);
|
Value *CachedVal = new LoadInst(Cache, "fpcache", EntryBB);
|
||||||
|
@ -876,26 +879,25 @@ static void CleanupAndPrepareModules(BugDriver &BD,
|
||||||
// Resolve the call to function F via the JIT API:
|
// Resolve the call to function F via the JIT API:
|
||||||
//
|
//
|
||||||
// call resolver(GetElementPtr...)
|
// call resolver(GetElementPtr...)
|
||||||
CallInst *Resolver =
|
CallInst *Resolver = CallInst::Create(resolverFunc, ResolverArgs,
|
||||||
CallInst::Create(resolverFunc, ResolverArgs, "resolver", LookupBB);
|
"resolver", LookupBB);
|
||||||
|
|
||||||
// Cast the result from the resolver to correctly-typed function.
|
// Cast the result from the resolver to correctly-typed function.
|
||||||
CastInst *CastedResolver =
|
CastInst *CastedResolver = new BitCastInst(
|
||||||
new BitCastInst(Resolver,
|
Resolver, PointerType::getUnqual(F->getFunctionType()),
|
||||||
PointerType::getUnqual(F->getFunctionType()),
|
"resolverCast", LookupBB);
|
||||||
"resolverCast", LookupBB);
|
|
||||||
|
|
||||||
// Save the value in our cache.
|
// Save the value in our cache.
|
||||||
new StoreInst(CastedResolver, Cache, LookupBB);
|
new StoreInst(CastedResolver, Cache, LookupBB);
|
||||||
BranchInst::Create(DoCallBB, LookupBB);
|
BranchInst::Create(DoCallBB, LookupBB);
|
||||||
|
|
||||||
PHINode *FuncPtr = PHINode::Create(NullPtr->getType(), 2,
|
PHINode *FuncPtr =
|
||||||
"fp", DoCallBB);
|
PHINode::Create(NullPtr->getType(), 2, "fp", DoCallBB);
|
||||||
FuncPtr->addIncoming(CastedResolver, LookupBB);
|
FuncPtr->addIncoming(CastedResolver, LookupBB);
|
||||||
FuncPtr->addIncoming(CachedVal, EntryBB);
|
FuncPtr->addIncoming(CachedVal, EntryBB);
|
||||||
|
|
||||||
// Save the argument list.
|
// Save the argument list.
|
||||||
std::vector<Value*> Args;
|
std::vector<Value *> Args;
|
||||||
for (Argument &A : FuncWrapper->args())
|
for (Argument &A : FuncWrapper->args())
|
||||||
Args.push_back(&A);
|
Args.push_back(&A);
|
||||||
|
|
||||||
|
@ -904,9 +906,9 @@ static void CleanupAndPrepareModules(BugDriver &BD,
|
||||||
CallInst::Create(FuncPtr, Args, "", DoCallBB);
|
CallInst::Create(FuncPtr, Args, "", DoCallBB);
|
||||||
ReturnInst::Create(F->getContext(), DoCallBB);
|
ReturnInst::Create(F->getContext(), DoCallBB);
|
||||||
} else {
|
} else {
|
||||||
CallInst *Call = CallInst::Create(FuncPtr, Args,
|
CallInst *Call =
|
||||||
"retval", DoCallBB);
|
CallInst::Create(FuncPtr, Args, "retval", DoCallBB);
|
||||||
ReturnInst::Create(F->getContext(),Call, DoCallBB);
|
ReturnInst::Create(F->getContext(), Call, DoCallBB);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use the wrapper function instead of the old function
|
// Use the wrapper function instead of the old function
|
||||||
|
@ -936,8 +938,8 @@ static bool TestCodeGenerator(BugDriver &BD, std::unique_ptr<Module> Test,
|
||||||
std::error_code EC = sys::fs::createTemporaryFile("bugpoint.test", "bc",
|
std::error_code EC = sys::fs::createTemporaryFile("bugpoint.test", "bc",
|
||||||
TestModuleFD, TestModuleBC);
|
TestModuleFD, TestModuleBC);
|
||||||
if (EC) {
|
if (EC) {
|
||||||
errs() << BD.getToolName() << "Error making unique filename: "
|
errs() << BD.getToolName()
|
||||||
<< EC.message() << "\n";
|
<< "Error making unique filename: " << EC.message() << "\n";
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
if (BD.writeProgramToFile(TestModuleBC.str(), TestModuleFD, Test.get())) {
|
if (BD.writeProgramToFile(TestModuleBC.str(), TestModuleFD, Test.get())) {
|
||||||
|
@ -954,14 +956,13 @@ static bool TestCodeGenerator(BugDriver &BD, std::unique_ptr<Module> Test,
|
||||||
EC = sys::fs::createTemporaryFile("bugpoint.safe", "bc", SafeModuleFD,
|
EC = sys::fs::createTemporaryFile("bugpoint.safe", "bc", SafeModuleFD,
|
||||||
SafeModuleBC);
|
SafeModuleBC);
|
||||||
if (EC) {
|
if (EC) {
|
||||||
errs() << BD.getToolName() << "Error making unique filename: "
|
errs() << BD.getToolName()
|
||||||
<< EC.message() << "\n";
|
<< "Error making unique filename: " << EC.message() << "\n";
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (BD.writeProgramToFile(SafeModuleBC.str(), SafeModuleFD, Safe.get())) {
|
if (BD.writeProgramToFile(SafeModuleBC.str(), SafeModuleFD, Safe.get())) {
|
||||||
errs() << "Error writing bitcode to `" << SafeModuleBC
|
errs() << "Error writing bitcode to `" << SafeModuleBC << "'\nExiting.";
|
||||||
<< "'\nExiting.";
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -991,9 +992,9 @@ static bool TestCodeGenerator(BugDriver &BD, std::unique_ptr<Module> Test,
|
||||||
/// debugCodeGenerator - debug errors in LLC, LLI, or CBE.
|
/// debugCodeGenerator - debug errors in LLC, LLI, or CBE.
|
||||||
///
|
///
|
||||||
bool BugDriver::debugCodeGenerator(std::string *Error) {
|
bool BugDriver::debugCodeGenerator(std::string *Error) {
|
||||||
if ((void*)SafeInterpreter == (void*)Interpreter) {
|
if ((void *)SafeInterpreter == (void *)Interpreter) {
|
||||||
std::string Result = executeProgramSafely(Program, "bugpoint.safe.out",
|
std::string Result =
|
||||||
Error);
|
executeProgramSafely(Program, "bugpoint.safe.out", Error);
|
||||||
if (Error->empty()) {
|
if (Error->empty()) {
|
||||||
outs() << "\n*** The \"safe\" i.e. 'known good' backend cannot match "
|
outs() << "\n*** The \"safe\" i.e. 'known good' backend cannot match "
|
||||||
<< "the reference diff. This may be due to a\n front-end "
|
<< "the reference diff. This may be due to a\n front-end "
|
||||||
|
@ -1001,16 +1002,15 @@ bool BugDriver::debugCodeGenerator(std::string *Error) {
|
||||||
<< "happen if bugpoint isn't running the program with the "
|
<< "happen if bugpoint isn't running the program with the "
|
||||||
<< "right flags or input.\n I left the result of executing "
|
<< "right flags or input.\n I left the result of executing "
|
||||||
<< "the program with the \"safe\" backend in this file for "
|
<< "the program with the \"safe\" backend in this file for "
|
||||||
<< "you: '"
|
<< "you: '" << Result << "'.\n";
|
||||||
<< Result << "'.\n";
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
DisambiguateGlobalSymbols(Program);
|
DisambiguateGlobalSymbols(Program);
|
||||||
|
|
||||||
std::vector<Function*> Funcs = DebugAMiscompilation(*this, TestCodeGenerator,
|
std::vector<Function *> Funcs =
|
||||||
*Error);
|
DebugAMiscompilation(*this, TestCodeGenerator, *Error);
|
||||||
if (!Error->empty())
|
if (!Error->empty())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@ -1028,14 +1028,13 @@ bool BugDriver::debugCodeGenerator(std::string *Error) {
|
||||||
std::error_code EC = sys::fs::createTemporaryFile("bugpoint.test", "bc",
|
std::error_code EC = sys::fs::createTemporaryFile("bugpoint.test", "bc",
|
||||||
TestModuleFD, TestModuleBC);
|
TestModuleFD, TestModuleBC);
|
||||||
if (EC) {
|
if (EC) {
|
||||||
errs() << getToolName() << "Error making unique filename: "
|
errs() << getToolName() << "Error making unique filename: " << EC.message()
|
||||||
<< EC.message() << "\n";
|
<< "\n";
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (writeProgramToFile(TestModuleBC.str(), TestModuleFD, ToCodeGen.get())) {
|
if (writeProgramToFile(TestModuleBC.str(), TestModuleFD, ToCodeGen.get())) {
|
||||||
errs() << "Error writing bitcode to `" << TestModuleBC
|
errs() << "Error writing bitcode to `" << TestModuleBC << "'\nExiting.";
|
||||||
<< "'\nExiting.";
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1045,15 +1044,14 @@ bool BugDriver::debugCodeGenerator(std::string *Error) {
|
||||||
EC = sys::fs::createTemporaryFile("bugpoint.safe", "bc", SafeModuleFD,
|
EC = sys::fs::createTemporaryFile("bugpoint.safe", "bc", SafeModuleFD,
|
||||||
SafeModuleBC);
|
SafeModuleBC);
|
||||||
if (EC) {
|
if (EC) {
|
||||||
errs() << getToolName() << "Error making unique filename: "
|
errs() << getToolName() << "Error making unique filename: " << EC.message()
|
||||||
<< EC.message() << "\n";
|
<< "\n";
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (writeProgramToFile(SafeModuleBC.str(), SafeModuleFD,
|
if (writeProgramToFile(SafeModuleBC.str(), SafeModuleFD,
|
||||||
ToNotCodeGen.get())) {
|
ToNotCodeGen.get())) {
|
||||||
errs() << "Error writing bitcode to `" << SafeModuleBC
|
errs() << "Error writing bitcode to `" << SafeModuleBC << "'\nExiting.";
|
||||||
<< "'\nExiting.";
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
std::string SharedObject = compileSharedObject(SafeModuleBC.str(), *Error);
|
std::string SharedObject = compileSharedObject(SafeModuleBC.str(), *Error);
|
||||||
|
@ -1064,11 +1062,10 @@ bool BugDriver::debugCodeGenerator(std::string *Error) {
|
||||||
if (isExecutingJIT()) {
|
if (isExecutingJIT()) {
|
||||||
outs() << " lli -load " << SharedObject << " " << TestModuleBC;
|
outs() << " lli -load " << SharedObject << " " << TestModuleBC;
|
||||||
} else {
|
} else {
|
||||||
outs() << " llc " << TestModuleBC << " -o " << TestModuleBC
|
outs() << " llc " << TestModuleBC << " -o " << TestModuleBC << ".s\n";
|
||||||
<< ".s\n";
|
outs() << " cc " << SharedObject << " " << TestModuleBC.str() << ".s -o "
|
||||||
outs() << " cc " << SharedObject << " " << TestModuleBC.str()
|
<< TestModuleBC << ".exe";
|
||||||
<< ".s -o " << TestModuleBC << ".exe";
|
#if defined(HAVE_LINK_R)
|
||||||
#if defined (HAVE_LINK_R)
|
|
||||||
outs() << " -Wl,-R.";
|
outs() << " -Wl,-R.";
|
||||||
#endif
|
#endif
|
||||||
outs() << "\n";
|
outs() << "\n";
|
||||||
|
@ -1081,9 +1078,9 @@ bool BugDriver::debugCodeGenerator(std::string *Error) {
|
||||||
<< SafeModuleBC.str() << " -o temporary.c\n"
|
<< SafeModuleBC.str() << " -o temporary.c\n"
|
||||||
<< " cc -xc temporary.c -O2 -o " << SharedObject;
|
<< " cc -xc temporary.c -O2 -o " << SharedObject;
|
||||||
if (TargetTriple.getArch() == Triple::sparc)
|
if (TargetTriple.getArch() == Triple::sparc)
|
||||||
outs() << " -G"; // Compile a shared library, `-G' for Sparc
|
outs() << " -G"; // Compile a shared library, `-G' for Sparc
|
||||||
else
|
else
|
||||||
outs() << " -fPIC -shared"; // `-shared' for Linux/X86, maybe others
|
outs() << " -fPIC -shared"; // `-shared' for Linux/X86, maybe others
|
||||||
|
|
||||||
outs() << " -fno-strict-aliasing\n";
|
outs() << " -fno-strict-aliasing\n";
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@ using namespace llvm;
|
||||||
#define DEBUG_TYPE "bugpoint"
|
#define DEBUG_TYPE "bugpoint"
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
extern cl::opt<std::string> OutputPrefix;
|
extern cl::opt<std::string> OutputPrefix;
|
||||||
}
|
}
|
||||||
|
|
||||||
static cl::opt<bool> PreserveBitcodeUseListOrder(
|
static cl::opt<bool> PreserveBitcodeUseListOrder(
|
||||||
|
@ -48,12 +48,12 @@ static cl::opt<bool> PreserveBitcodeUseListOrder(
|
||||||
cl::init(true), cl::Hidden);
|
cl::init(true), cl::Hidden);
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
// ChildOutput - This option captures the name of the child output file that
|
// ChildOutput - This option captures the name of the child output file that
|
||||||
// is set up by the parent bugpoint process
|
// is set up by the parent bugpoint process
|
||||||
cl::opt<std::string> ChildOutput("child-output", cl::ReallyHidden);
|
cl::opt<std::string> ChildOutput("child-output", cl::ReallyHidden);
|
||||||
cl::opt<std::string> OptCmd("opt-command", cl::init(""),
|
cl::opt<std::string> OptCmd("opt-command", cl::init(""),
|
||||||
cl::desc("Path to opt. (default: search path "
|
cl::desc("Path to opt. (default: search path "
|
||||||
"for 'opt'.)"));
|
"for 'opt'.)"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// writeProgramToFile - This writes the current "Program" to the named bitcode
|
/// writeProgramToFile - This writes the current "Program" to the named bitcode
|
||||||
|
@ -84,26 +84,26 @@ bool BugDriver::writeProgramToFile(const std::string &Filename,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// EmitProgressBitcode - This function is used to output the current Program
|
/// EmitProgressBitcode - This function is used to output the current Program
|
||||||
/// to a file named "bugpoint-ID.bc".
|
/// to a file named "bugpoint-ID.bc".
|
||||||
///
|
///
|
||||||
void BugDriver::EmitProgressBitcode(const Module *M,
|
void BugDriver::EmitProgressBitcode(const Module *M, const std::string &ID,
|
||||||
const std::string &ID,
|
bool NoFlyer) const {
|
||||||
bool NoFlyer) const {
|
|
||||||
// Output the input to the current pass to a bitcode file, emit a message
|
// Output the input to the current pass to a bitcode file, emit a message
|
||||||
// telling the user how to reproduce it: opt -foo blah.bc
|
// telling the user how to reproduce it: opt -foo blah.bc
|
||||||
//
|
//
|
||||||
std::string Filename = OutputPrefix + "-" + ID + ".bc";
|
std::string Filename = OutputPrefix + "-" + ID + ".bc";
|
||||||
if (writeProgramToFile(Filename, M)) {
|
if (writeProgramToFile(Filename, M)) {
|
||||||
errs() << "Error opening file '" << Filename << "' for writing!\n";
|
errs() << "Error opening file '" << Filename << "' for writing!\n";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
outs() << "Emitted bitcode to '" << Filename << "'\n";
|
outs() << "Emitted bitcode to '" << Filename << "'\n";
|
||||||
if (NoFlyer || PassesToRun.empty()) return;
|
if (NoFlyer || PassesToRun.empty())
|
||||||
|
return;
|
||||||
outs() << "\n*** You can reproduce the problem with: ";
|
outs() << "\n*** You can reproduce the problem with: ";
|
||||||
if (UseValgrind) outs() << "valgrind ";
|
if (UseValgrind)
|
||||||
|
outs() << "valgrind ";
|
||||||
outs() << "opt " << Filename;
|
outs() << "opt " << Filename;
|
||||||
for (unsigned i = 0, e = PluginLoader::getNumPlugins(); i != e; ++i) {
|
for (unsigned i = 0, e = PluginLoader::getNumPlugins(); i != e; ++i) {
|
||||||
outs() << " -load " << PluginLoader::getPlugin(i);
|
outs() << " -load " << PluginLoader::getPlugin(i);
|
||||||
|
@ -111,8 +111,9 @@ void BugDriver::EmitProgressBitcode(const Module *M,
|
||||||
outs() << " " << getPassesString(PassesToRun) << "\n";
|
outs() << " " << getPassesString(PassesToRun) << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
cl::opt<bool> SilencePasses("silence-passes",
|
cl::opt<bool> SilencePasses(
|
||||||
cl::desc("Suppress output of running passes (both stdout and stderr)"));
|
"silence-passes",
|
||||||
|
cl::desc("Suppress output of running passes (both stdout and stderr)"));
|
||||||
|
|
||||||
static cl::list<std::string> OptArgs("opt-args", cl::Positional,
|
static cl::list<std::string> OptArgs("opt-args", cl::Positional,
|
||||||
cl::desc("<opt arguments>..."),
|
cl::desc("<opt arguments>..."),
|
||||||
|
@ -130,15 +131,15 @@ bool BugDriver::runPasses(Module *Program,
|
||||||
const std::vector<std::string> &Passes,
|
const std::vector<std::string> &Passes,
|
||||||
std::string &OutputFilename, bool DeleteOutput,
|
std::string &OutputFilename, bool DeleteOutput,
|
||||||
bool Quiet, unsigned NumExtraArgs,
|
bool Quiet, unsigned NumExtraArgs,
|
||||||
const char * const *ExtraArgs) const {
|
const char *const *ExtraArgs) const {
|
||||||
// setup the output file name
|
// setup the output file name
|
||||||
outs().flush();
|
outs().flush();
|
||||||
SmallString<128> UniqueFilename;
|
SmallString<128> UniqueFilename;
|
||||||
std::error_code EC = sys::fs::createUniqueFile(
|
std::error_code EC = sys::fs::createUniqueFile(
|
||||||
OutputPrefix + "-output-%%%%%%%.bc", UniqueFilename);
|
OutputPrefix + "-output-%%%%%%%.bc", UniqueFilename);
|
||||||
if (EC) {
|
if (EC) {
|
||||||
errs() << getToolName() << ": Error making unique filename: "
|
errs() << getToolName()
|
||||||
<< EC.message() << "\n";
|
<< ": Error making unique filename: " << EC.message() << "\n";
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
OutputFilename = UniqueFilename.str();
|
OutputFilename = UniqueFilename.str();
|
||||||
|
@ -149,8 +150,8 @@ bool BugDriver::runPasses(Module *Program,
|
||||||
EC = sys::fs::createUniqueFile(OutputPrefix + "-input-%%%%%%%.bc", InputFD,
|
EC = sys::fs::createUniqueFile(OutputPrefix + "-input-%%%%%%%.bc", InputFD,
|
||||||
InputFilename);
|
InputFilename);
|
||||||
if (EC) {
|
if (EC) {
|
||||||
errs() << getToolName() << ": Error making unique filename: "
|
errs() << getToolName()
|
||||||
<< EC.message() << "\n";
|
<< ": Error making unique filename: " << EC.message() << "\n";
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,7 +194,7 @@ bool BugDriver::runPasses(Module *Program,
|
||||||
InFile.keep();
|
InFile.keep();
|
||||||
|
|
||||||
// setup the child process' arguments
|
// setup the child process' arguments
|
||||||
SmallVector<const char*, 8> Args;
|
SmallVector<const char *, 8> Args;
|
||||||
if (UseValgrind) {
|
if (UseValgrind) {
|
||||||
Args.push_back("valgrind");
|
Args.push_back("valgrind");
|
||||||
Args.push_back("--error-exitcode=1");
|
Args.push_back("--error-exitcode=1");
|
||||||
|
@ -208,14 +209,16 @@ bool BugDriver::runPasses(Module *Program,
|
||||||
Args.push_back(OptArgs[i].c_str());
|
Args.push_back(OptArgs[i].c_str());
|
||||||
std::vector<std::string> pass_args;
|
std::vector<std::string> pass_args;
|
||||||
for (unsigned i = 0, e = PluginLoader::getNumPlugins(); i != e; ++i) {
|
for (unsigned i = 0, e = PluginLoader::getNumPlugins(); i != e; ++i) {
|
||||||
pass_args.push_back( std::string("-load"));
|
pass_args.push_back(std::string("-load"));
|
||||||
pass_args.push_back( PluginLoader::getPlugin(i));
|
pass_args.push_back(PluginLoader::getPlugin(i));
|
||||||
}
|
}
|
||||||
for (std::vector<std::string>::const_iterator I = Passes.begin(),
|
for (std::vector<std::string>::const_iterator I = Passes.begin(),
|
||||||
E = Passes.end(); I != E; ++I )
|
E = Passes.end();
|
||||||
pass_args.push_back( std::string("-") + (*I) );
|
I != E; ++I)
|
||||||
|
pass_args.push_back(std::string("-") + (*I));
|
||||||
for (std::vector<std::string>::const_iterator I = pass_args.begin(),
|
for (std::vector<std::string>::const_iterator I = pass_args.begin(),
|
||||||
E = pass_args.end(); I != E; ++I )
|
E = pass_args.end();
|
||||||
|
I != E; ++I)
|
||||||
Args.push_back(I->c_str());
|
Args.push_back(I->c_str());
|
||||||
Args.push_back(InputFilename.c_str());
|
Args.push_back(InputFilename.c_str());
|
||||||
for (unsigned i = 0; i < NumExtraArgs; ++i)
|
for (unsigned i = 0; i < NumExtraArgs; ++i)
|
||||||
|
@ -223,10 +226,9 @@ bool BugDriver::runPasses(Module *Program,
|
||||||
Args.push_back(nullptr);
|
Args.push_back(nullptr);
|
||||||
|
|
||||||
DEBUG(errs() << "\nAbout to run:\t";
|
DEBUG(errs() << "\nAbout to run:\t";
|
||||||
for (unsigned i = 0, e = Args.size()-1; i != e; ++i)
|
for (unsigned i = 0, e = Args.size() - 1; i != e; ++i) errs()
|
||||||
errs() << " " << Args[i];
|
<< " " << Args[i];
|
||||||
errs() << "\n";
|
errs() << "\n";);
|
||||||
);
|
|
||||||
|
|
||||||
// Redirect stdout and stderr to nowhere if SilencePasses is given
|
// Redirect stdout and stderr to nowhere if SilencePasses is given
|
||||||
StringRef Nowhere;
|
StringRef Nowhere;
|
||||||
|
@ -264,21 +266,19 @@ bool BugDriver::runPasses(Module *Program,
|
||||||
return result != 0;
|
return result != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::unique_ptr<Module>
|
std::unique_ptr<Module>
|
||||||
BugDriver::runPassesOn(Module *M, const std::vector<std::string> &Passes,
|
BugDriver::runPassesOn(Module *M, const std::vector<std::string> &Passes,
|
||||||
unsigned NumExtraArgs,
|
unsigned NumExtraArgs, const char *const *ExtraArgs) {
|
||||||
const char *const *ExtraArgs) {
|
|
||||||
std::string BitcodeResult;
|
std::string BitcodeResult;
|
||||||
if (runPasses(M, Passes, BitcodeResult, false/*delete*/, true/*quiet*/,
|
if (runPasses(M, Passes, BitcodeResult, false /*delete*/, true /*quiet*/,
|
||||||
NumExtraArgs, ExtraArgs)) {
|
NumExtraArgs, ExtraArgs)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Module> Ret = parseInputFile(BitcodeResult, Context);
|
std::unique_ptr<Module> Ret = parseInputFile(BitcodeResult, Context);
|
||||||
if (!Ret) {
|
if (!Ret) {
|
||||||
errs() << getToolName() << ": Error reading bitcode file '"
|
errs() << getToolName() << ": Error reading bitcode file '" << BitcodeResult
|
||||||
<< BitcodeResult << "'!\n";
|
<< "'!\n";
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
sys::fs::remove(BitcodeResult);
|
sys::fs::remove(BitcodeResult);
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "ToolRunner.h"
|
#include "ToolRunner.h"
|
||||||
#include "llvm/Config/config.h" // for HAVE_LINK_R
|
#include "llvm/Config/config.h" // for HAVE_LINK_R
|
||||||
#include "llvm/Support/CommandLine.h"
|
#include "llvm/Support/CommandLine.h"
|
||||||
#include "llvm/Support/Debug.h"
|
#include "llvm/Support/Debug.h"
|
||||||
#include "llvm/Support/FileSystem.h"
|
#include "llvm/Support/FileSystem.h"
|
||||||
|
@ -27,46 +27,40 @@ using namespace llvm;
|
||||||
#define DEBUG_TYPE "toolrunner"
|
#define DEBUG_TYPE "toolrunner"
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
cl::opt<bool>
|
cl::opt<bool> SaveTemps("save-temps", cl::init(false),
|
||||||
SaveTemps("save-temps", cl::init(false), cl::desc("Save temporary files"));
|
cl::desc("Save temporary files"));
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
cl::opt<std::string>
|
cl::opt<std::string>
|
||||||
RemoteClient("remote-client",
|
RemoteClient("remote-client",
|
||||||
cl::desc("Remote execution client (rsh/ssh)"));
|
cl::desc("Remote execution client (rsh/ssh)"));
|
||||||
|
|
||||||
cl::opt<std::string>
|
cl::opt<std::string> RemoteHost("remote-host",
|
||||||
RemoteHost("remote-host",
|
cl::desc("Remote execution (rsh/ssh) host"));
|
||||||
cl::desc("Remote execution (rsh/ssh) host"));
|
|
||||||
|
|
||||||
cl::opt<std::string>
|
cl::opt<std::string> RemotePort("remote-port",
|
||||||
RemotePort("remote-port",
|
cl::desc("Remote execution (rsh/ssh) port"));
|
||||||
cl::desc("Remote execution (rsh/ssh) port"));
|
|
||||||
|
|
||||||
cl::opt<std::string>
|
cl::opt<std::string> RemoteUser("remote-user",
|
||||||
RemoteUser("remote-user",
|
cl::desc("Remote execution (rsh/ssh) user id"));
|
||||||
cl::desc("Remote execution (rsh/ssh) user id"));
|
|
||||||
|
|
||||||
cl::opt<std::string>
|
cl::opt<std::string>
|
||||||
RemoteExtra("remote-extra-options",
|
RemoteExtra("remote-extra-options",
|
||||||
cl::desc("Remote execution (rsh/ssh) extra options"));
|
cl::desc("Remote execution (rsh/ssh) extra options"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// RunProgramWithTimeout - This function provides an alternate interface
|
/// RunProgramWithTimeout - This function provides an alternate interface
|
||||||
/// to the sys::Program::ExecuteAndWait interface.
|
/// to the sys::Program::ExecuteAndWait interface.
|
||||||
/// @see sys::Program::ExecuteAndWait
|
/// @see sys::Program::ExecuteAndWait
|
||||||
static int RunProgramWithTimeout(StringRef ProgramPath,
|
static int RunProgramWithTimeout(StringRef ProgramPath, const char **Args,
|
||||||
const char **Args,
|
StringRef StdInFile, StringRef StdOutFile,
|
||||||
StringRef StdInFile,
|
StringRef StdErrFile, unsigned NumSeconds = 0,
|
||||||
StringRef StdOutFile,
|
|
||||||
StringRef StdErrFile,
|
|
||||||
unsigned NumSeconds = 0,
|
|
||||||
unsigned MemoryLimit = 0,
|
unsigned MemoryLimit = 0,
|
||||||
std::string *ErrMsg = nullptr) {
|
std::string *ErrMsg = nullptr) {
|
||||||
const StringRef *Redirects[3] = { &StdInFile, &StdOutFile, &StdErrFile };
|
const StringRef *Redirects[3] = {&StdInFile, &StdOutFile, &StdErrFile};
|
||||||
return sys::ExecuteAndWait(ProgramPath, Args, nullptr, Redirects,
|
return sys::ExecuteAndWait(ProgramPath, Args, nullptr, Redirects, NumSeconds,
|
||||||
NumSeconds, MemoryLimit, ErrMsg);
|
MemoryLimit, ErrMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// RunProgramRemotelyWithTimeout - This function runs the given program
|
/// RunProgramRemotelyWithTimeout - This function runs the given program
|
||||||
|
@ -76,13 +70,12 @@ static int RunProgramWithTimeout(StringRef ProgramPath,
|
||||||
/// code otherwise.
|
/// code otherwise.
|
||||||
/// @see sys::Program::ExecuteAndWait
|
/// @see sys::Program::ExecuteAndWait
|
||||||
static int RunProgramRemotelyWithTimeout(StringRef RemoteClientPath,
|
static int RunProgramRemotelyWithTimeout(StringRef RemoteClientPath,
|
||||||
const char **Args,
|
const char **Args, StringRef StdInFile,
|
||||||
StringRef StdInFile,
|
|
||||||
StringRef StdOutFile,
|
StringRef StdOutFile,
|
||||||
StringRef StdErrFile,
|
StringRef StdErrFile,
|
||||||
unsigned NumSeconds = 0,
|
unsigned NumSeconds = 0,
|
||||||
unsigned MemoryLimit = 0) {
|
unsigned MemoryLimit = 0) {
|
||||||
const StringRef *Redirects[3] = { &StdInFile, &StdOutFile, &StdErrFile };
|
const StringRef *Redirects[3] = {&StdInFile, &StdOutFile, &StdErrFile};
|
||||||
|
|
||||||
// Run the program remotely with the remote client
|
// Run the program remotely with the remote client
|
||||||
int ReturnCode = sys::ExecuteAndWait(RemoteClientPath, Args, nullptr,
|
int ReturnCode = sys::ExecuteAndWait(RemoteClientPath, Args, nullptr,
|
||||||
|
@ -112,7 +105,7 @@ static int RunProgramRemotelyWithTimeout(StringRef RemoteClientPath,
|
||||||
return ReturnCode;
|
return ReturnCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string ProcessFailure(StringRef ProgPath, const char** Args,
|
static std::string ProcessFailure(StringRef ProgPath, const char **Args,
|
||||||
unsigned Timeout = 0,
|
unsigned Timeout = 0,
|
||||||
unsigned MemoryLimit = 0) {
|
unsigned MemoryLimit = 0) {
|
||||||
std::ostringstream OS;
|
std::ostringstream OS;
|
||||||
|
@ -151,44 +144,41 @@ static std::string ProcessFailure(StringRef ProgPath, const char** Args,
|
||||||
// LLI Implementation of AbstractIntepreter interface
|
// LLI Implementation of AbstractIntepreter interface
|
||||||
//
|
//
|
||||||
namespace {
|
namespace {
|
||||||
class LLI : public AbstractInterpreter {
|
class LLI : public AbstractInterpreter {
|
||||||
std::string LLIPath; // The path to the LLI executable
|
std::string LLIPath; // The path to the LLI executable
|
||||||
std::vector<std::string> ToolArgs; // Args to pass to LLI
|
std::vector<std::string> ToolArgs; // Args to pass to LLI
|
||||||
public:
|
public:
|
||||||
LLI(const std::string &Path, const std::vector<std::string> *Args)
|
LLI(const std::string &Path, const std::vector<std::string> *Args)
|
||||||
: LLIPath(Path) {
|
: LLIPath(Path) {
|
||||||
ToolArgs.clear ();
|
ToolArgs.clear();
|
||||||
if (Args) { ToolArgs = *Args; }
|
if (Args) {
|
||||||
|
ToolArgs = *Args;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int ExecuteProgram(const std::string &Bitcode,
|
int ExecuteProgram(
|
||||||
const std::vector<std::string> &Args,
|
const std::string &Bitcode, const std::vector<std::string> &Args,
|
||||||
const std::string &InputFile,
|
const std::string &InputFile, const std::string &OutputFile,
|
||||||
const std::string &OutputFile,
|
std::string *Error, const std::vector<std::string> &CCArgs,
|
||||||
std::string *Error,
|
const std::vector<std::string> &SharedLibs = std::vector<std::string>(),
|
||||||
const std::vector<std::string> &CCArgs,
|
unsigned Timeout = 0, unsigned MemoryLimit = 0) override;
|
||||||
const std::vector<std::string> &SharedLibs =
|
};
|
||||||
std::vector<std::string>(),
|
|
||||||
unsigned Timeout = 0,
|
|
||||||
unsigned MemoryLimit = 0) override;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int LLI::ExecuteProgram(const std::string &Bitcode,
|
int LLI::ExecuteProgram(const std::string &Bitcode,
|
||||||
const std::vector<std::string> &Args,
|
const std::vector<std::string> &Args,
|
||||||
const std::string &InputFile,
|
const std::string &InputFile,
|
||||||
const std::string &OutputFile,
|
const std::string &OutputFile, std::string *Error,
|
||||||
std::string *Error,
|
|
||||||
const std::vector<std::string> &CCArgs,
|
const std::vector<std::string> &CCArgs,
|
||||||
const std::vector<std::string> &SharedLibs,
|
const std::vector<std::string> &SharedLibs,
|
||||||
unsigned Timeout,
|
unsigned Timeout, unsigned MemoryLimit) {
|
||||||
unsigned MemoryLimit) {
|
std::vector<const char *> LLIArgs;
|
||||||
std::vector<const char*> LLIArgs;
|
|
||||||
LLIArgs.push_back(LLIPath.c_str());
|
LLIArgs.push_back(LLIPath.c_str());
|
||||||
LLIArgs.push_back("-force-interpreter=true");
|
LLIArgs.push_back("-force-interpreter=true");
|
||||||
|
|
||||||
for (std::vector<std::string>::const_iterator i = SharedLibs.begin(),
|
for (std::vector<std::string>::const_iterator i = SharedLibs.begin(),
|
||||||
e = SharedLibs.end(); i != e; ++i) {
|
e = SharedLibs.end();
|
||||||
|
i != e; ++i) {
|
||||||
LLIArgs.push_back("-load");
|
LLIArgs.push_back("-load");
|
||||||
LLIArgs.push_back((*i).c_str());
|
LLIArgs.push_back((*i).c_str());
|
||||||
}
|
}
|
||||||
|
@ -199,26 +189,25 @@ int LLI::ExecuteProgram(const std::string &Bitcode,
|
||||||
|
|
||||||
LLIArgs.push_back(Bitcode.c_str());
|
LLIArgs.push_back(Bitcode.c_str());
|
||||||
// Add optional parameters to the running program from Argv
|
// Add optional parameters to the running program from Argv
|
||||||
for (unsigned i=0, e = Args.size(); i != e; ++i)
|
for (unsigned i = 0, e = Args.size(); i != e; ++i)
|
||||||
LLIArgs.push_back(Args[i].c_str());
|
LLIArgs.push_back(Args[i].c_str());
|
||||||
LLIArgs.push_back(nullptr);
|
LLIArgs.push_back(nullptr);
|
||||||
|
|
||||||
outs() << "<lli>"; outs().flush();
|
outs() << "<lli>";
|
||||||
|
outs().flush();
|
||||||
DEBUG(errs() << "\nAbout to run:\t";
|
DEBUG(errs() << "\nAbout to run:\t";
|
||||||
for (unsigned i=0, e = LLIArgs.size()-1; i != e; ++i)
|
for (unsigned i = 0, e = LLIArgs.size() - 1; i != e; ++i) errs()
|
||||||
errs() << " " << LLIArgs[i];
|
<< " " << LLIArgs[i];
|
||||||
errs() << "\n";
|
errs() << "\n";);
|
||||||
);
|
return RunProgramWithTimeout(LLIPath, &LLIArgs[0], InputFile, OutputFile,
|
||||||
return RunProgramWithTimeout(LLIPath, &LLIArgs[0],
|
OutputFile, Timeout, MemoryLimit, Error);
|
||||||
InputFile, OutputFile, OutputFile,
|
|
||||||
Timeout, MemoryLimit, Error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AbstractInterpreter::anchor() { }
|
void AbstractInterpreter::anchor() {}
|
||||||
|
|
||||||
#if defined(LLVM_ON_UNIX)
|
#if defined(LLVM_ON_UNIX)
|
||||||
const char EXESuffix[] = "";
|
const char EXESuffix[] = "";
|
||||||
#elif defined (LLVM_ON_WIN32)
|
#elif defined(LLVM_ON_WIN32)
|
||||||
const char EXESuffix[] = "exe";
|
const char EXESuffix[] = "exe";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -248,11 +237,11 @@ static std::string PrependMainExecutablePath(const std::string &ExeName,
|
||||||
}
|
}
|
||||||
|
|
||||||
// LLI create method - Try to find the LLI executable
|
// LLI create method - Try to find the LLI executable
|
||||||
AbstractInterpreter *AbstractInterpreter::createLLI(const char *Argv0,
|
AbstractInterpreter *
|
||||||
std::string &Message,
|
AbstractInterpreter::createLLI(const char *Argv0, std::string &Message,
|
||||||
const std::vector<std::string> *ToolArgs) {
|
const std::vector<std::string> *ToolArgs) {
|
||||||
std::string LLIPath =
|
std::string LLIPath =
|
||||||
PrependMainExecutablePath("lli", Argv0, (void *)(intptr_t) & createLLI);
|
PrependMainExecutablePath("lli", Argv0, (void *)(intptr_t)&createLLI);
|
||||||
if (!LLIPath.empty()) {
|
if (!LLIPath.empty()) {
|
||||||
Message = "Found lli: " + LLIPath + "\n";
|
Message = "Found lli: " + LLIPath + "\n";
|
||||||
return new LLI(LLIPath, ToolArgs);
|
return new LLI(LLIPath, ToolArgs);
|
||||||
|
@ -269,42 +258,36 @@ AbstractInterpreter *AbstractInterpreter::createLLI(const char *Argv0,
|
||||||
// example, to compile a bitcode fragment without linking or executing, then
|
// example, to compile a bitcode fragment without linking or executing, then
|
||||||
// using a custom wrapper script to check for compiler errors.
|
// using a custom wrapper script to check for compiler errors.
|
||||||
namespace {
|
namespace {
|
||||||
class CustomCompiler : public AbstractInterpreter {
|
class CustomCompiler : public AbstractInterpreter {
|
||||||
std::string CompilerCommand;
|
std::string CompilerCommand;
|
||||||
std::vector<std::string> CompilerArgs;
|
std::vector<std::string> CompilerArgs;
|
||||||
public:
|
|
||||||
CustomCompiler(const std::string &CompilerCmd,
|
|
||||||
std::vector<std::string> CompArgs)
|
|
||||||
: CompilerCommand(CompilerCmd), CompilerArgs(std::move(CompArgs)) {}
|
|
||||||
|
|
||||||
void compileProgram(const std::string &Bitcode,
|
public:
|
||||||
std::string *Error,
|
CustomCompiler(const std::string &CompilerCmd,
|
||||||
unsigned Timeout = 0,
|
std::vector<std::string> CompArgs)
|
||||||
unsigned MemoryLimit = 0) override;
|
: CompilerCommand(CompilerCmd), CompilerArgs(std::move(CompArgs)) {}
|
||||||
|
|
||||||
int ExecuteProgram(const std::string &Bitcode,
|
void compileProgram(const std::string &Bitcode, std::string *Error,
|
||||||
const std::vector<std::string> &Args,
|
unsigned Timeout = 0, unsigned MemoryLimit = 0) override;
|
||||||
const std::string &InputFile,
|
|
||||||
const std::string &OutputFile,
|
int ExecuteProgram(
|
||||||
std::string *Error,
|
const std::string &Bitcode, const std::vector<std::string> &Args,
|
||||||
const std::vector<std::string> &CCArgs =
|
const std::string &InputFile, const std::string &OutputFile,
|
||||||
std::vector<std::string>(),
|
std::string *Error,
|
||||||
const std::vector<std::string> &SharedLibs =
|
const std::vector<std::string> &CCArgs = std::vector<std::string>(),
|
||||||
std::vector<std::string>(),
|
const std::vector<std::string> &SharedLibs = std::vector<std::string>(),
|
||||||
unsigned Timeout = 0,
|
unsigned Timeout = 0, unsigned MemoryLimit = 0) override {
|
||||||
unsigned MemoryLimit = 0) override {
|
*Error = "Execution not supported with -compile-custom";
|
||||||
*Error = "Execution not supported with -compile-custom";
|
return -1;
|
||||||
return -1;
|
}
|
||||||
}
|
};
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CustomCompiler::compileProgram(const std::string &Bitcode,
|
void CustomCompiler::compileProgram(const std::string &Bitcode,
|
||||||
std::string *Error,
|
std::string *Error, unsigned Timeout,
|
||||||
unsigned Timeout,
|
|
||||||
unsigned MemoryLimit) {
|
unsigned MemoryLimit) {
|
||||||
|
|
||||||
std::vector<const char*> ProgramArgs;
|
std::vector<const char *> ProgramArgs;
|
||||||
ProgramArgs.push_back(CompilerCommand.c_str());
|
ProgramArgs.push_back(CompilerCommand.c_str());
|
||||||
|
|
||||||
for (std::size_t i = 0; i < CompilerArgs.size(); ++i)
|
for (std::size_t i = 0; i < CompilerArgs.size(); ++i)
|
||||||
|
@ -316,11 +299,10 @@ void CustomCompiler::compileProgram(const std::string &Bitcode,
|
||||||
for (unsigned i = 0, e = CompilerArgs.size(); i != e; ++i)
|
for (unsigned i = 0, e = CompilerArgs.size(); i != e; ++i)
|
||||||
ProgramArgs.push_back(CompilerArgs[i].c_str());
|
ProgramArgs.push_back(CompilerArgs[i].c_str());
|
||||||
|
|
||||||
if (RunProgramWithTimeout(CompilerCommand, &ProgramArgs[0],
|
if (RunProgramWithTimeout(CompilerCommand, &ProgramArgs[0], "", "", "",
|
||||||
"", "", "",
|
Timeout, MemoryLimit, Error))
|
||||||
Timeout, MemoryLimit, Error))
|
*Error =
|
||||||
*Error = ProcessFailure(CompilerCommand, &ProgramArgs[0],
|
ProcessFailure(CompilerCommand, &ProgramArgs[0], Timeout, MemoryLimit);
|
||||||
Timeout, MemoryLimit);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//===---------------------------------------------------------------------===//
|
//===---------------------------------------------------------------------===//
|
||||||
|
@ -330,38 +312,34 @@ void CustomCompiler::compileProgram(const std::string &Bitcode,
|
||||||
// for example, to invoke a cross compiler for code generation followed by
|
// for example, to invoke a cross compiler for code generation followed by
|
||||||
// a simulator that executes the generated binary.
|
// a simulator that executes the generated binary.
|
||||||
namespace {
|
namespace {
|
||||||
class CustomExecutor : public AbstractInterpreter {
|
class CustomExecutor : public AbstractInterpreter {
|
||||||
std::string ExecutionCommand;
|
std::string ExecutionCommand;
|
||||||
std::vector<std::string> ExecutorArgs;
|
std::vector<std::string> ExecutorArgs;
|
||||||
public:
|
|
||||||
CustomExecutor(const std::string &ExecutionCmd,
|
|
||||||
std::vector<std::string> ExecArgs)
|
|
||||||
: ExecutionCommand(ExecutionCmd), ExecutorArgs(std::move(ExecArgs)) {}
|
|
||||||
|
|
||||||
int ExecuteProgram(const std::string &Bitcode,
|
public:
|
||||||
const std::vector<std::string> &Args,
|
CustomExecutor(const std::string &ExecutionCmd,
|
||||||
const std::string &InputFile,
|
std::vector<std::string> ExecArgs)
|
||||||
const std::string &OutputFile,
|
: ExecutionCommand(ExecutionCmd), ExecutorArgs(std::move(ExecArgs)) {}
|
||||||
std::string *Error,
|
|
||||||
const std::vector<std::string> &CCArgs,
|
int ExecuteProgram(
|
||||||
const std::vector<std::string> &SharedLibs =
|
const std::string &Bitcode, const std::vector<std::string> &Args,
|
||||||
std::vector<std::string>(),
|
const std::string &InputFile, const std::string &OutputFile,
|
||||||
unsigned Timeout = 0,
|
std::string *Error, const std::vector<std::string> &CCArgs,
|
||||||
unsigned MemoryLimit = 0) override;
|
const std::vector<std::string> &SharedLibs = std::vector<std::string>(),
|
||||||
};
|
unsigned Timeout = 0, unsigned MemoryLimit = 0) override;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
int CustomExecutor::ExecuteProgram(const std::string &Bitcode,
|
int CustomExecutor::ExecuteProgram(const std::string &Bitcode,
|
||||||
const std::vector<std::string> &Args,
|
const std::vector<std::string> &Args,
|
||||||
const std::string &InputFile,
|
const std::string &InputFile,
|
||||||
const std::string &OutputFile,
|
const std::string &OutputFile,
|
||||||
std::string *Error,
|
std::string *Error,
|
||||||
const std::vector<std::string> &CCArgs,
|
const std::vector<std::string> &CCArgs,
|
||||||
const std::vector<std::string> &SharedLibs,
|
const std::vector<std::string> &SharedLibs,
|
||||||
unsigned Timeout,
|
unsigned Timeout, unsigned MemoryLimit) {
|
||||||
unsigned MemoryLimit) {
|
|
||||||
|
|
||||||
std::vector<const char*> ProgramArgs;
|
std::vector<const char *> ProgramArgs;
|
||||||
ProgramArgs.push_back(ExecutionCommand.c_str());
|
ProgramArgs.push_back(ExecutionCommand.c_str());
|
||||||
|
|
||||||
for (std::size_t i = 0; i < ExecutorArgs.size(); ++i)
|
for (std::size_t i = 0; i < ExecutorArgs.size(); ++i)
|
||||||
|
@ -373,10 +351,9 @@ int CustomExecutor::ExecuteProgram(const std::string &Bitcode,
|
||||||
for (unsigned i = 0, e = Args.size(); i != e; ++i)
|
for (unsigned i = 0, e = Args.size(); i != e; ++i)
|
||||||
ProgramArgs.push_back(Args[i].c_str());
|
ProgramArgs.push_back(Args[i].c_str());
|
||||||
|
|
||||||
return RunProgramWithTimeout(
|
return RunProgramWithTimeout(ExecutionCommand, &ProgramArgs[0], InputFile,
|
||||||
ExecutionCommand,
|
OutputFile, OutputFile, Timeout, MemoryLimit,
|
||||||
&ProgramArgs[0], InputFile, OutputFile,
|
Error);
|
||||||
OutputFile, Timeout, MemoryLimit, Error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tokenize the CommandLine to the command and the args to allow
|
// Tokenize the CommandLine to the command and the args to allow
|
||||||
|
@ -400,9 +377,9 @@ static void lexCommand(std::string &Message, const std::string &CommandLine,
|
||||||
while (std::string::npos != pos || std::string::npos != lastPos) {
|
while (std::string::npos != pos || std::string::npos != lastPos) {
|
||||||
std::string token = CommandLine.substr(lastPos, pos - lastPos);
|
std::string token = CommandLine.substr(lastPos, pos - lastPos);
|
||||||
if (Command == "")
|
if (Command == "")
|
||||||
Command = token;
|
Command = token;
|
||||||
else
|
else
|
||||||
Args.push_back(token);
|
Args.push_back(token);
|
||||||
// Skip delimiters. Note the "not_of"
|
// Skip delimiters. Note the "not_of"
|
||||||
lastPos = CommandLine.find_first_not_of(delimiters, pos);
|
lastPos = CommandLine.find_first_not_of(delimiters, pos);
|
||||||
// Find next "non-delimiter"
|
// Find next "non-delimiter"
|
||||||
|
@ -411,9 +388,8 @@ static void lexCommand(std::string &Message, const std::string &CommandLine,
|
||||||
|
|
||||||
auto Path = sys::findProgramByName(Command);
|
auto Path = sys::findProgramByName(Command);
|
||||||
if (!Path) {
|
if (!Path) {
|
||||||
Message =
|
Message = std::string("Cannot find '") + Command + "' in PATH: " +
|
||||||
std::string("Cannot find '") + Command +
|
Path.getError().message() + "\n";
|
||||||
"' in PATH: " + Path.getError().message() + "\n";
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
CmdPath = *Path;
|
CmdPath = *Path;
|
||||||
|
@ -424,8 +400,7 @@ static void lexCommand(std::string &Message, const std::string &CommandLine,
|
||||||
// Custom execution environment create method, takes the execution command
|
// Custom execution environment create method, takes the execution command
|
||||||
// as arguments
|
// as arguments
|
||||||
AbstractInterpreter *AbstractInterpreter::createCustomCompiler(
|
AbstractInterpreter *AbstractInterpreter::createCustomCompiler(
|
||||||
std::string &Message,
|
std::string &Message, const std::string &CompileCommandLine) {
|
||||||
const std::string &CompileCommandLine) {
|
|
||||||
|
|
||||||
std::string CmdPath;
|
std::string CmdPath;
|
||||||
std::vector<std::string> Args;
|
std::vector<std::string> Args;
|
||||||
|
@ -438,10 +413,9 @@ AbstractInterpreter *AbstractInterpreter::createCustomCompiler(
|
||||||
|
|
||||||
// Custom execution environment create method, takes the execution command
|
// Custom execution environment create method, takes the execution command
|
||||||
// as arguments
|
// as arguments
|
||||||
AbstractInterpreter *AbstractInterpreter::createCustomExecutor(
|
AbstractInterpreter *
|
||||||
std::string &Message,
|
AbstractInterpreter::createCustomExecutor(std::string &Message,
|
||||||
const std::string &ExecCommandLine) {
|
const std::string &ExecCommandLine) {
|
||||||
|
|
||||||
|
|
||||||
std::string CmdPath;
|
std::string CmdPath;
|
||||||
std::vector<std::string> Args;
|
std::vector<std::string> Args;
|
||||||
|
@ -456,8 +430,8 @@ AbstractInterpreter *AbstractInterpreter::createCustomExecutor(
|
||||||
// LLC Implementation of AbstractIntepreter interface
|
// LLC Implementation of AbstractIntepreter interface
|
||||||
//
|
//
|
||||||
CC::FileType LLC::OutputCode(const std::string &Bitcode,
|
CC::FileType LLC::OutputCode(const std::string &Bitcode,
|
||||||
std::string &OutputAsmFile, std::string &Error,
|
std::string &OutputAsmFile, std::string &Error,
|
||||||
unsigned Timeout, unsigned MemoryLimit) {
|
unsigned Timeout, unsigned MemoryLimit) {
|
||||||
const char *Suffix = (UseIntegratedAssembler ? ".llc.o" : ".llc.s");
|
const char *Suffix = (UseIntegratedAssembler ? ".llc.o" : ".llc.s");
|
||||||
|
|
||||||
SmallString<128> UniqueFile;
|
SmallString<128> UniqueFile;
|
||||||
|
@ -477,25 +451,22 @@ CC::FileType LLC::OutputCode(const std::string &Bitcode,
|
||||||
|
|
||||||
LLCArgs.push_back("-o");
|
LLCArgs.push_back("-o");
|
||||||
LLCArgs.push_back(OutputAsmFile.c_str()); // Output to the Asm file
|
LLCArgs.push_back(OutputAsmFile.c_str()); // Output to the Asm file
|
||||||
LLCArgs.push_back(Bitcode.c_str()); // This is the input bitcode
|
LLCArgs.push_back(Bitcode.c_str()); // This is the input bitcode
|
||||||
|
|
||||||
if (UseIntegratedAssembler)
|
if (UseIntegratedAssembler)
|
||||||
LLCArgs.push_back("-filetype=obj");
|
LLCArgs.push_back("-filetype=obj");
|
||||||
|
|
||||||
LLCArgs.push_back (nullptr);
|
LLCArgs.push_back(nullptr);
|
||||||
|
|
||||||
outs() << (UseIntegratedAssembler ? "<llc-ia>" : "<llc>");
|
outs() << (UseIntegratedAssembler ? "<llc-ia>" : "<llc>");
|
||||||
outs().flush();
|
outs().flush();
|
||||||
DEBUG(errs() << "\nAbout to run:\t";
|
DEBUG(errs() << "\nAbout to run:\t";
|
||||||
for (unsigned i = 0, e = LLCArgs.size()-1; i != e; ++i)
|
for (unsigned i = 0, e = LLCArgs.size() - 1; i != e; ++i) errs()
|
||||||
errs() << " " << LLCArgs[i];
|
<< " " << LLCArgs[i];
|
||||||
errs() << "\n";
|
errs() << "\n";);
|
||||||
);
|
if (RunProgramWithTimeout(LLCPath, &LLCArgs[0], "", "", "", Timeout,
|
||||||
if (RunProgramWithTimeout(LLCPath, &LLCArgs[0],
|
MemoryLimit))
|
||||||
"", "", "",
|
Error = ProcessFailure(LLCPath, &LLCArgs[0], Timeout, MemoryLimit);
|
||||||
Timeout, MemoryLimit))
|
|
||||||
Error = ProcessFailure(LLCPath, &LLCArgs[0],
|
|
||||||
Timeout, MemoryLimit);
|
|
||||||
return UseIntegratedAssembler ? CC::ObjectFile : CC::AsmFile;
|
return UseIntegratedAssembler ? CC::ObjectFile : CC::AsmFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -509,37 +480,33 @@ void LLC::compileProgram(const std::string &Bitcode, std::string *Error,
|
||||||
int LLC::ExecuteProgram(const std::string &Bitcode,
|
int LLC::ExecuteProgram(const std::string &Bitcode,
|
||||||
const std::vector<std::string> &Args,
|
const std::vector<std::string> &Args,
|
||||||
const std::string &InputFile,
|
const std::string &InputFile,
|
||||||
const std::string &OutputFile,
|
const std::string &OutputFile, std::string *Error,
|
||||||
std::string *Error,
|
|
||||||
const std::vector<std::string> &ArgsForCC,
|
const std::vector<std::string> &ArgsForCC,
|
||||||
const std::vector<std::string> &SharedLibs,
|
const std::vector<std::string> &SharedLibs,
|
||||||
unsigned Timeout,
|
unsigned Timeout, unsigned MemoryLimit) {
|
||||||
unsigned MemoryLimit) {
|
|
||||||
|
|
||||||
std::string OutputAsmFile;
|
std::string OutputAsmFile;
|
||||||
CC::FileType FileKind = OutputCode(Bitcode, OutputAsmFile, *Error, Timeout,
|
CC::FileType FileKind =
|
||||||
MemoryLimit);
|
OutputCode(Bitcode, OutputAsmFile, *Error, Timeout, MemoryLimit);
|
||||||
FileRemover OutFileRemover(OutputAsmFile, !SaveTemps);
|
FileRemover OutFileRemover(OutputAsmFile, !SaveTemps);
|
||||||
|
|
||||||
std::vector<std::string> CCArgs(ArgsForCC);
|
std::vector<std::string> CCArgs(ArgsForCC);
|
||||||
CCArgs.insert(CCArgs.end(), SharedLibs.begin(), SharedLibs.end());
|
CCArgs.insert(CCArgs.end(), SharedLibs.begin(), SharedLibs.end());
|
||||||
|
|
||||||
// Assuming LLC worked, compile the result with CC and run it.
|
// Assuming LLC worked, compile the result with CC and run it.
|
||||||
return cc->ExecuteProgram(OutputAsmFile, Args, FileKind,
|
return cc->ExecuteProgram(OutputAsmFile, Args, FileKind, InputFile,
|
||||||
InputFile, OutputFile, Error, CCArgs,
|
OutputFile, Error, CCArgs, Timeout, MemoryLimit);
|
||||||
Timeout, MemoryLimit);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// createLLC - Try to find the LLC executable
|
/// createLLC - Try to find the LLC executable
|
||||||
///
|
///
|
||||||
LLC *AbstractInterpreter::createLLC(const char *Argv0,
|
LLC *AbstractInterpreter::createLLC(const char *Argv0, std::string &Message,
|
||||||
std::string &Message,
|
|
||||||
const std::string &CCBinary,
|
const std::string &CCBinary,
|
||||||
const std::vector<std::string> *Args,
|
const std::vector<std::string> *Args,
|
||||||
const std::vector<std::string> *CCArgs,
|
const std::vector<std::string> *CCArgs,
|
||||||
bool UseIntegratedAssembler) {
|
bool UseIntegratedAssembler) {
|
||||||
std::string LLCPath =
|
std::string LLCPath =
|
||||||
PrependMainExecutablePath("llc", Argv0, (void *)(intptr_t) & createLLC);
|
PrependMainExecutablePath("llc", Argv0, (void *)(intptr_t)&createLLC);
|
||||||
if (LLCPath.empty()) {
|
if (LLCPath.empty()) {
|
||||||
Message = "Cannot find `llc' in executable directory!\n";
|
Message = "Cannot find `llc' in executable directory!\n";
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -558,41 +525,37 @@ LLC *AbstractInterpreter::createLLC(const char *Argv0,
|
||||||
// JIT Implementation of AbstractIntepreter interface
|
// JIT Implementation of AbstractIntepreter interface
|
||||||
//
|
//
|
||||||
namespace {
|
namespace {
|
||||||
class JIT : public AbstractInterpreter {
|
class JIT : public AbstractInterpreter {
|
||||||
std::string LLIPath; // The path to the LLI executable
|
std::string LLIPath; // The path to the LLI executable
|
||||||
std::vector<std::string> ToolArgs; // Args to pass to LLI
|
std::vector<std::string> ToolArgs; // Args to pass to LLI
|
||||||
public:
|
public:
|
||||||
JIT(const std::string &Path, const std::vector<std::string> *Args)
|
JIT(const std::string &Path, const std::vector<std::string> *Args)
|
||||||
: LLIPath(Path) {
|
: LLIPath(Path) {
|
||||||
ToolArgs.clear ();
|
ToolArgs.clear();
|
||||||
if (Args) { ToolArgs = *Args; }
|
if (Args) {
|
||||||
|
ToolArgs = *Args;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int ExecuteProgram(const std::string &Bitcode,
|
int ExecuteProgram(
|
||||||
const std::vector<std::string> &Args,
|
const std::string &Bitcode, const std::vector<std::string> &Args,
|
||||||
const std::string &InputFile,
|
const std::string &InputFile, const std::string &OutputFile,
|
||||||
const std::string &OutputFile,
|
std::string *Error,
|
||||||
std::string *Error,
|
const std::vector<std::string> &CCArgs = std::vector<std::string>(),
|
||||||
const std::vector<std::string> &CCArgs =
|
const std::vector<std::string> &SharedLibs = std::vector<std::string>(),
|
||||||
std::vector<std::string>(),
|
unsigned Timeout = 0, unsigned MemoryLimit = 0) override;
|
||||||
const std::vector<std::string> &SharedLibs =
|
};
|
||||||
std::vector<std::string>(),
|
|
||||||
unsigned Timeout = 0,
|
|
||||||
unsigned MemoryLimit = 0) override;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int JIT::ExecuteProgram(const std::string &Bitcode,
|
int JIT::ExecuteProgram(const std::string &Bitcode,
|
||||||
const std::vector<std::string> &Args,
|
const std::vector<std::string> &Args,
|
||||||
const std::string &InputFile,
|
const std::string &InputFile,
|
||||||
const std::string &OutputFile,
|
const std::string &OutputFile, std::string *Error,
|
||||||
std::string *Error,
|
|
||||||
const std::vector<std::string> &CCArgs,
|
const std::vector<std::string> &CCArgs,
|
||||||
const std::vector<std::string> &SharedLibs,
|
const std::vector<std::string> &SharedLibs,
|
||||||
unsigned Timeout,
|
unsigned Timeout, unsigned MemoryLimit) {
|
||||||
unsigned MemoryLimit) {
|
|
||||||
// Construct a vector of parameters, incorporating those from the command-line
|
// Construct a vector of parameters, incorporating those from the command-line
|
||||||
std::vector<const char*> JITArgs;
|
std::vector<const char *> JITArgs;
|
||||||
JITArgs.push_back(LLIPath.c_str());
|
JITArgs.push_back(LLIPath.c_str());
|
||||||
JITArgs.push_back("-force-interpreter=false");
|
JITArgs.push_back("-force-interpreter=false");
|
||||||
|
|
||||||
|
@ -606,28 +569,28 @@ int JIT::ExecuteProgram(const std::string &Bitcode,
|
||||||
}
|
}
|
||||||
JITArgs.push_back(Bitcode.c_str());
|
JITArgs.push_back(Bitcode.c_str());
|
||||||
// Add optional parameters to the running program from Argv
|
// Add optional parameters to the running program from Argv
|
||||||
for (unsigned i=0, e = Args.size(); i != e; ++i)
|
for (unsigned i = 0, e = Args.size(); i != e; ++i)
|
||||||
JITArgs.push_back(Args[i].c_str());
|
JITArgs.push_back(Args[i].c_str());
|
||||||
JITArgs.push_back(nullptr);
|
JITArgs.push_back(nullptr);
|
||||||
|
|
||||||
outs() << "<jit>"; outs().flush();
|
outs() << "<jit>";
|
||||||
|
outs().flush();
|
||||||
DEBUG(errs() << "\nAbout to run:\t";
|
DEBUG(errs() << "\nAbout to run:\t";
|
||||||
for (unsigned i=0, e = JITArgs.size()-1; i != e; ++i)
|
for (unsigned i = 0, e = JITArgs.size() - 1; i != e; ++i) errs()
|
||||||
errs() << " " << JITArgs[i];
|
<< " " << JITArgs[i];
|
||||||
errs() << "\n";
|
errs() << "\n";);
|
||||||
);
|
|
||||||
DEBUG(errs() << "\nSending output to " << OutputFile << "\n");
|
DEBUG(errs() << "\nSending output to " << OutputFile << "\n");
|
||||||
return RunProgramWithTimeout(LLIPath, &JITArgs[0],
|
return RunProgramWithTimeout(LLIPath, &JITArgs[0], InputFile, OutputFile,
|
||||||
InputFile, OutputFile, OutputFile,
|
OutputFile, Timeout, MemoryLimit, Error);
|
||||||
Timeout, MemoryLimit, Error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// createJIT - Try to find the LLI executable
|
/// createJIT - Try to find the LLI executable
|
||||||
///
|
///
|
||||||
AbstractInterpreter *AbstractInterpreter::createJIT(const char *Argv0,
|
AbstractInterpreter *
|
||||||
std::string &Message, const std::vector<std::string> *Args) {
|
AbstractInterpreter::createJIT(const char *Argv0, std::string &Message,
|
||||||
|
const std::vector<std::string> *Args) {
|
||||||
std::string LLIPath =
|
std::string LLIPath =
|
||||||
PrependMainExecutablePath("lli", Argv0, (void *)(intptr_t) & createJIT);
|
PrependMainExecutablePath("lli", Argv0, (void *)(intptr_t)&createJIT);
|
||||||
if (!LLIPath.empty()) {
|
if (!LLIPath.empty()) {
|
||||||
Message = "Found lli: " + LLIPath + "\n";
|
Message = "Found lli: " + LLIPath + "\n";
|
||||||
return new JIT(LLIPath, Args);
|
return new JIT(LLIPath, Args);
|
||||||
|
@ -641,9 +604,10 @@ AbstractInterpreter *AbstractInterpreter::createJIT(const char *Argv0,
|
||||||
// CC abstraction
|
// CC abstraction
|
||||||
//
|
//
|
||||||
|
|
||||||
static bool IsARMArchitecture(std::vector<const char*> Args) {
|
static bool IsARMArchitecture(std::vector<const char *> Args) {
|
||||||
for (std::vector<const char*>::const_iterator
|
for (std::vector<const char *>::const_iterator I = Args.begin(),
|
||||||
I = Args.begin(), E = Args.end(); I != E; ++I) {
|
E = Args.end();
|
||||||
|
I != E; ++I) {
|
||||||
if (StringRef(*I).equals_lower("-arch")) {
|
if (StringRef(*I).equals_lower("-arch")) {
|
||||||
++I;
|
++I;
|
||||||
if (I != E && StringRef(*I).startswith_lower("arm"))
|
if (I != E && StringRef(*I).startswith_lower("arm"))
|
||||||
|
@ -655,23 +619,21 @@ static bool IsARMArchitecture(std::vector<const char*> Args) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int CC::ExecuteProgram(const std::string &ProgramFile,
|
int CC::ExecuteProgram(const std::string &ProgramFile,
|
||||||
const std::vector<std::string> &Args,
|
const std::vector<std::string> &Args, FileType fileType,
|
||||||
FileType fileType,
|
const std::string &InputFile,
|
||||||
const std::string &InputFile,
|
const std::string &OutputFile, std::string *Error,
|
||||||
const std::string &OutputFile,
|
const std::vector<std::string> &ArgsForCC,
|
||||||
std::string *Error,
|
unsigned Timeout, unsigned MemoryLimit) {
|
||||||
const std::vector<std::string> &ArgsForCC,
|
std::vector<const char *> CCArgs;
|
||||||
unsigned Timeout,
|
|
||||||
unsigned MemoryLimit) {
|
|
||||||
std::vector<const char*> CCArgs;
|
|
||||||
|
|
||||||
CCArgs.push_back(CCPath.c_str());
|
CCArgs.push_back(CCPath.c_str());
|
||||||
|
|
||||||
if (TargetTriple.getArch() == Triple::x86)
|
if (TargetTriple.getArch() == Triple::x86)
|
||||||
CCArgs.push_back("-m32");
|
CCArgs.push_back("-m32");
|
||||||
|
|
||||||
for (std::vector<std::string>::const_iterator
|
for (std::vector<std::string>::const_iterator I = ccArgs.begin(),
|
||||||
I = ccArgs.begin(), E = ccArgs.end(); I != E; ++I)
|
E = ccArgs.end();
|
||||||
|
I != E; ++I)
|
||||||
CCArgs.push_back(I->c_str());
|
CCArgs.push_back(I->c_str());
|
||||||
|
|
||||||
// Specify -x explicitly in case the extension is wonky
|
// Specify -x explicitly in case the extension is wonky
|
||||||
|
@ -691,7 +653,7 @@ int CC::ExecuteProgram(const std::string &ProgramFile,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CCArgs.push_back(ProgramFile.c_str()); // Specify the input filename.
|
CCArgs.push_back(ProgramFile.c_str()); // Specify the input filename.
|
||||||
|
|
||||||
CCArgs.push_back("-x");
|
CCArgs.push_back("-x");
|
||||||
CCArgs.push_back("none");
|
CCArgs.push_back("none");
|
||||||
|
@ -713,27 +675,27 @@ int CC::ExecuteProgram(const std::string &ProgramFile,
|
||||||
for (unsigned i = 0, e = ArgsForCC.size(); i != e; ++i)
|
for (unsigned i = 0, e = ArgsForCC.size(); i != e; ++i)
|
||||||
CCArgs.push_back(ArgsForCC[i].c_str());
|
CCArgs.push_back(ArgsForCC[i].c_str());
|
||||||
|
|
||||||
CCArgs.push_back("-lm"); // Hard-code the math library...
|
CCArgs.push_back("-lm"); // Hard-code the math library...
|
||||||
CCArgs.push_back("-O2"); // Optimize the program a bit...
|
CCArgs.push_back("-O2"); // Optimize the program a bit...
|
||||||
#if defined (HAVE_LINK_R)
|
#if defined(HAVE_LINK_R)
|
||||||
CCArgs.push_back("-Wl,-R."); // Search this dir for .so files
|
CCArgs.push_back("-Wl,-R."); // Search this dir for .so files
|
||||||
#endif
|
#endif
|
||||||
if (TargetTriple.getArch() == Triple::sparc)
|
if (TargetTriple.getArch() == Triple::sparc)
|
||||||
CCArgs.push_back("-mcpu=v9");
|
CCArgs.push_back("-mcpu=v9");
|
||||||
CCArgs.push_back(nullptr); // NULL terminator
|
CCArgs.push_back(nullptr); // NULL terminator
|
||||||
|
|
||||||
outs() << "<CC>"; outs().flush();
|
outs() << "<CC>";
|
||||||
|
outs().flush();
|
||||||
DEBUG(errs() << "\nAbout to run:\t";
|
DEBUG(errs() << "\nAbout to run:\t";
|
||||||
for (unsigned i = 0, e = CCArgs.size()-1; i != e; ++i)
|
for (unsigned i = 0, e = CCArgs.size() - 1; i != e; ++i) errs()
|
||||||
errs() << " " << CCArgs[i];
|
<< " " << CCArgs[i];
|
||||||
errs() << "\n";
|
errs() << "\n";);
|
||||||
);
|
|
||||||
if (RunProgramWithTimeout(CCPath, &CCArgs[0], "", "", "")) {
|
if (RunProgramWithTimeout(CCPath, &CCArgs[0], "", "", "")) {
|
||||||
*Error = ProcessFailure(CCPath, &CCArgs[0]);
|
*Error = ProcessFailure(CCPath, &CCArgs[0]);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<const char*> ProgramArgs;
|
std::vector<const char *> ProgramArgs;
|
||||||
|
|
||||||
// Declared here so that the destructor only runs after
|
// Declared here so that the destructor only runs after
|
||||||
// ProgramArgs is used.
|
// ProgramArgs is used.
|
||||||
|
@ -758,7 +720,7 @@ int CC::ExecuteProgram(const std::string &ProgramFile,
|
||||||
|
|
||||||
// Full path to the binary. We need to cd to the exec directory because
|
// Full path to the binary. We need to cd to the exec directory because
|
||||||
// there is a dylib there that the exec expects to find in the CWD
|
// there is a dylib there that the exec expects to find in the CWD
|
||||||
char* env_pwd = getenv("PWD");
|
char *env_pwd = getenv("PWD");
|
||||||
Exec = "cd ";
|
Exec = "cd ";
|
||||||
Exec += env_pwd;
|
Exec += env_pwd;
|
||||||
Exec += "; ./";
|
Exec += "; ./";
|
||||||
|
@ -769,15 +731,15 @@ int CC::ExecuteProgram(const std::string &ProgramFile,
|
||||||
// Add optional parameters to the running program from Argv
|
// Add optional parameters to the running program from Argv
|
||||||
for (unsigned i = 0, e = Args.size(); i != e; ++i)
|
for (unsigned i = 0, e = Args.size(); i != e; ++i)
|
||||||
ProgramArgs.push_back(Args[i].c_str());
|
ProgramArgs.push_back(Args[i].c_str());
|
||||||
ProgramArgs.push_back(nullptr); // NULL terminator
|
ProgramArgs.push_back(nullptr); // NULL terminator
|
||||||
|
|
||||||
// Now that we have a binary, run it!
|
// Now that we have a binary, run it!
|
||||||
outs() << "<program>"; outs().flush();
|
outs() << "<program>";
|
||||||
|
outs().flush();
|
||||||
DEBUG(errs() << "\nAbout to run:\t";
|
DEBUG(errs() << "\nAbout to run:\t";
|
||||||
for (unsigned i = 0, e = ProgramArgs.size()-1; i != e; ++i)
|
for (unsigned i = 0, e = ProgramArgs.size() - 1; i != e; ++i) errs()
|
||||||
errs() << " " << ProgramArgs[i];
|
<< " " << ProgramArgs[i];
|
||||||
errs() << "\n";
|
errs() << "\n";);
|
||||||
);
|
|
||||||
|
|
||||||
FileRemover OutputBinaryRemover(OutputBinary.str(), !SaveTemps);
|
FileRemover OutputBinaryRemover(OutputBinary.str(), !SaveTemps);
|
||||||
|
|
||||||
|
@ -796,17 +758,18 @@ int CC::ExecuteProgram(const std::string &ProgramFile,
|
||||||
}
|
}
|
||||||
return ExitCode;
|
return ExitCode;
|
||||||
} else {
|
} else {
|
||||||
outs() << "<run remotely>"; outs().flush();
|
outs() << "<run remotely>";
|
||||||
return RunProgramRemotelyWithTimeout(RemoteClientPath,
|
outs().flush();
|
||||||
&ProgramArgs[0], InputFile, OutputFile,
|
return RunProgramRemotelyWithTimeout(RemoteClientPath, &ProgramArgs[0],
|
||||||
OutputFile, Timeout, MemoryLimit);
|
InputFile, OutputFile, OutputFile,
|
||||||
|
Timeout, MemoryLimit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int CC::MakeSharedObject(const std::string &InputFile, FileType fileType,
|
int CC::MakeSharedObject(const std::string &InputFile, FileType fileType,
|
||||||
std::string &OutputFile,
|
std::string &OutputFile,
|
||||||
const std::vector<std::string> &ArgsForCC,
|
const std::vector<std::string> &ArgsForCC,
|
||||||
std::string &Error) {
|
std::string &Error) {
|
||||||
SmallString<128> UniqueFilename;
|
SmallString<128> UniqueFilename;
|
||||||
std::error_code EC = sys::fs::createUniqueFile(
|
std::error_code EC = sys::fs::createUniqueFile(
|
||||||
InputFile + "-%%%%%%%" + LTDL_SHLIB_EXT, UniqueFilename);
|
InputFile + "-%%%%%%%" + LTDL_SHLIB_EXT, UniqueFilename);
|
||||||
|
@ -816,15 +779,16 @@ int CC::MakeSharedObject(const std::string &InputFile, FileType fileType,
|
||||||
}
|
}
|
||||||
OutputFile = UniqueFilename.str();
|
OutputFile = UniqueFilename.str();
|
||||||
|
|
||||||
std::vector<const char*> CCArgs;
|
std::vector<const char *> CCArgs;
|
||||||
|
|
||||||
CCArgs.push_back(CCPath.c_str());
|
CCArgs.push_back(CCPath.c_str());
|
||||||
|
|
||||||
if (TargetTriple.getArch() == Triple::x86)
|
if (TargetTriple.getArch() == Triple::x86)
|
||||||
CCArgs.push_back("-m32");
|
CCArgs.push_back("-m32");
|
||||||
|
|
||||||
for (std::vector<std::string>::const_iterator
|
for (std::vector<std::string>::const_iterator I = ccArgs.begin(),
|
||||||
I = ccArgs.begin(), E = ccArgs.end(); I != E; ++I)
|
E = ccArgs.end();
|
||||||
|
I != E; ++I)
|
||||||
CCArgs.push_back(I->c_str());
|
CCArgs.push_back(I->c_str());
|
||||||
|
|
||||||
// Compile the C/asm file into a shared object
|
// Compile the C/asm file into a shared object
|
||||||
|
@ -833,25 +797,25 @@ int CC::MakeSharedObject(const std::string &InputFile, FileType fileType,
|
||||||
CCArgs.push_back(fileType == AsmFile ? "assembler" : "c");
|
CCArgs.push_back(fileType == AsmFile ? "assembler" : "c");
|
||||||
}
|
}
|
||||||
CCArgs.push_back("-fno-strict-aliasing");
|
CCArgs.push_back("-fno-strict-aliasing");
|
||||||
CCArgs.push_back(InputFile.c_str()); // Specify the input filename.
|
CCArgs.push_back(InputFile.c_str()); // Specify the input filename.
|
||||||
CCArgs.push_back("-x");
|
CCArgs.push_back("-x");
|
||||||
CCArgs.push_back("none");
|
CCArgs.push_back("none");
|
||||||
if (TargetTriple.getArch() == Triple::sparc)
|
if (TargetTriple.getArch() == Triple::sparc)
|
||||||
CCArgs.push_back("-G"); // Compile a shared library, `-G' for Sparc
|
CCArgs.push_back("-G"); // Compile a shared library, `-G' for Sparc
|
||||||
else if (TargetTriple.isOSDarwin()) {
|
else if (TargetTriple.isOSDarwin()) {
|
||||||
// link all source files into a single module in data segment, rather than
|
// link all source files into a single module in data segment, rather than
|
||||||
// generating blocks. dynamic_lookup requires that you set
|
// generating blocks. dynamic_lookup requires that you set
|
||||||
// MACOSX_DEPLOYMENT_TARGET=10.3 in your env. FIXME: it would be better for
|
// MACOSX_DEPLOYMENT_TARGET=10.3 in your env. FIXME: it would be better for
|
||||||
// bugpoint to just pass that in the environment of CC.
|
// bugpoint to just pass that in the environment of CC.
|
||||||
CCArgs.push_back("-single_module");
|
CCArgs.push_back("-single_module");
|
||||||
CCArgs.push_back("-dynamiclib"); // `-dynamiclib' for MacOS X/PowerPC
|
CCArgs.push_back("-dynamiclib"); // `-dynamiclib' for MacOS X/PowerPC
|
||||||
CCArgs.push_back("-undefined");
|
CCArgs.push_back("-undefined");
|
||||||
CCArgs.push_back("dynamic_lookup");
|
CCArgs.push_back("dynamic_lookup");
|
||||||
} else
|
} else
|
||||||
CCArgs.push_back("-shared"); // `-shared' for Linux/X86, maybe others
|
CCArgs.push_back("-shared"); // `-shared' for Linux/X86, maybe others
|
||||||
|
|
||||||
if (TargetTriple.getArch() == Triple::x86_64)
|
if (TargetTriple.getArch() == Triple::x86_64)
|
||||||
CCArgs.push_back("-fPIC"); // Requires shared objs to contain PIC
|
CCArgs.push_back("-fPIC"); // Requires shared objs to contain PIC
|
||||||
|
|
||||||
if (TargetTriple.getArch() == Triple::sparc)
|
if (TargetTriple.getArch() == Triple::sparc)
|
||||||
CCArgs.push_back("-mcpu=v9");
|
CCArgs.push_back("-mcpu=v9");
|
||||||
|
@ -860,24 +824,20 @@ int CC::MakeSharedObject(const std::string &InputFile, FileType fileType,
|
||||||
CCArgs.push_back(OutputFile.c_str()); // Output to the right filename.
|
CCArgs.push_back(OutputFile.c_str()); // Output to the right filename.
|
||||||
CCArgs.push_back("-O2"); // Optimize the program a bit.
|
CCArgs.push_back("-O2"); // Optimize the program a bit.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Add any arguments intended for CC. We locate them here because this is
|
// Add any arguments intended for CC. We locate them here because this is
|
||||||
// most likely -L and -l options that need to come before other libraries but
|
// most likely -L and -l options that need to come before other libraries but
|
||||||
// after the source. Other options won't be sensitive to placement on the
|
// after the source. Other options won't be sensitive to placement on the
|
||||||
// command line, so this should be safe.
|
// command line, so this should be safe.
|
||||||
for (unsigned i = 0, e = ArgsForCC.size(); i != e; ++i)
|
for (unsigned i = 0, e = ArgsForCC.size(); i != e; ++i)
|
||||||
CCArgs.push_back(ArgsForCC[i].c_str());
|
CCArgs.push_back(ArgsForCC[i].c_str());
|
||||||
CCArgs.push_back(nullptr); // NULL terminator
|
CCArgs.push_back(nullptr); // NULL terminator
|
||||||
|
|
||||||
|
outs() << "<CC>";
|
||||||
|
outs().flush();
|
||||||
outs() << "<CC>"; outs().flush();
|
|
||||||
DEBUG(errs() << "\nAbout to run:\t";
|
DEBUG(errs() << "\nAbout to run:\t";
|
||||||
for (unsigned i = 0, e = CCArgs.size()-1; i != e; ++i)
|
for (unsigned i = 0, e = CCArgs.size() - 1; i != e; ++i) errs()
|
||||||
errs() << " " << CCArgs[i];
|
<< " " << CCArgs[i];
|
||||||
errs() << "\n";
|
errs() << "\n";);
|
||||||
);
|
|
||||||
if (RunProgramWithTimeout(CCPath, &CCArgs[0], "", "", "")) {
|
if (RunProgramWithTimeout(CCPath, &CCArgs[0], "", "", "")) {
|
||||||
Error = ProcessFailure(CCPath, &CCArgs[0]);
|
Error = ProcessFailure(CCPath, &CCArgs[0]);
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -887,9 +847,8 @@ int CC::MakeSharedObject(const std::string &InputFile, FileType fileType,
|
||||||
|
|
||||||
/// create - Try to find the CC executable
|
/// create - Try to find the CC executable
|
||||||
///
|
///
|
||||||
CC *CC::create(std::string &Message,
|
CC *CC::create(std::string &Message, const std::string &CCBinary,
|
||||||
const std::string &CCBinary,
|
const std::vector<std::string> *Args) {
|
||||||
const std::vector<std::string> *Args) {
|
|
||||||
auto CCPath = sys::findProgramByName(CCBinary);
|
auto CCPath = sys::findProgramByName(CCBinary);
|
||||||
if (!CCPath) {
|
if (!CCPath) {
|
||||||
Message = "Cannot find `" + CCBinary + "' in PATH: " +
|
Message = "Cannot find `" + CCBinary + "' in PATH: " +
|
||||||
|
|
|
@ -36,20 +36,21 @@ class LLC;
|
||||||
// CC abstraction
|
// CC abstraction
|
||||||
//
|
//
|
||||||
class CC {
|
class CC {
|
||||||
std::string CCPath; // The path to the cc executable.
|
std::string CCPath; // The path to the cc executable.
|
||||||
std::string RemoteClientPath; // The path to the rsh / ssh executable.
|
std::string RemoteClientPath; // The path to the rsh / ssh executable.
|
||||||
std::vector<std::string> ccArgs; // CC-specific arguments.
|
std::vector<std::string> ccArgs; // CC-specific arguments.
|
||||||
CC(StringRef ccPath, StringRef RemotePath,
|
CC(StringRef ccPath, StringRef RemotePath,
|
||||||
const std::vector<std::string> *CCArgs)
|
const std::vector<std::string> *CCArgs)
|
||||||
: CCPath(ccPath), RemoteClientPath(RemotePath) {
|
: CCPath(ccPath), RemoteClientPath(RemotePath) {
|
||||||
if (CCArgs) ccArgs = *CCArgs;
|
if (CCArgs)
|
||||||
|
ccArgs = *CCArgs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum FileType { AsmFile, ObjectFile, CFile };
|
enum FileType { AsmFile, ObjectFile, CFile };
|
||||||
|
|
||||||
static CC *create(std::string &Message,
|
static CC *create(std::string &Message, const std::string &CCBinary,
|
||||||
const std::string &CCBinary,
|
const std::vector<std::string> *Args);
|
||||||
const std::vector<std::string> *Args);
|
|
||||||
|
|
||||||
/// ExecuteProgram - Execute the program specified by "ProgramFile" (which is
|
/// ExecuteProgram - Execute the program specified by "ProgramFile" (which is
|
||||||
/// either a .s file, or a .c file, specified by FileType), with the specified
|
/// either a .s file, or a .c file, specified by FileType), with the specified
|
||||||
|
@ -58,16 +59,12 @@ public:
|
||||||
/// option specifies optional native shared objects that can be loaded into
|
/// option specifies optional native shared objects that can be loaded into
|
||||||
/// the program for execution.
|
/// the program for execution.
|
||||||
///
|
///
|
||||||
int ExecuteProgram(const std::string &ProgramFile,
|
int ExecuteProgram(
|
||||||
const std::vector<std::string> &Args,
|
const std::string &ProgramFile, const std::vector<std::string> &Args,
|
||||||
FileType fileType,
|
FileType fileType, const std::string &InputFile,
|
||||||
const std::string &InputFile,
|
const std::string &OutputFile, std::string *Error = nullptr,
|
||||||
const std::string &OutputFile,
|
const std::vector<std::string> &CCArgs = std::vector<std::string>(),
|
||||||
std::string *Error = nullptr,
|
unsigned Timeout = 0, unsigned MemoryLimit = 0);
|
||||||
const std::vector<std::string> &CCArgs =
|
|
||||||
std::vector<std::string>(),
|
|
||||||
unsigned Timeout = 0,
|
|
||||||
unsigned MemoryLimit = 0);
|
|
||||||
|
|
||||||
/// MakeSharedObject - This compiles the specified file (which is either a .c
|
/// MakeSharedObject - This compiles the specified file (which is either a .c
|
||||||
/// file or a .s file) into a shared object.
|
/// file or a .s file) into a shared object.
|
||||||
|
@ -78,7 +75,6 @@ public:
|
||||||
std::string &Error);
|
std::string &Error);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
//===---------------------------------------------------------------------===//
|
//===---------------------------------------------------------------------===//
|
||||||
/// AbstractInterpreter Class - Subclasses of this class are used to execute
|
/// AbstractInterpreter Class - Subclasses of this class are used to execute
|
||||||
/// LLVM bitcode in a variety of ways. This abstract interface hides this
|
/// LLVM bitcode in a variety of ways. This abstract interface hides this
|
||||||
|
@ -86,30 +82,30 @@ public:
|
||||||
///
|
///
|
||||||
class AbstractInterpreter {
|
class AbstractInterpreter {
|
||||||
virtual void anchor();
|
virtual void anchor();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static LLC *createLLC(const char *Argv0, std::string &Message,
|
static LLC *createLLC(const char *Argv0, std::string &Message,
|
||||||
const std::string &CCBinary,
|
const std::string &CCBinary,
|
||||||
const std::vector<std::string> *Args = nullptr,
|
const std::vector<std::string> *Args = nullptr,
|
||||||
const std::vector<std::string> *CCArgs = nullptr,
|
const std::vector<std::string> *CCArgs = nullptr,
|
||||||
bool UseIntegratedAssembler = false);
|
bool UseIntegratedAssembler = false);
|
||||||
|
|
||||||
static AbstractInterpreter*
|
static AbstractInterpreter *
|
||||||
createLLI(const char *Argv0, std::string &Message,
|
createLLI(const char *Argv0, std::string &Message,
|
||||||
const std::vector<std::string> *Args = nullptr);
|
const std::vector<std::string> *Args = nullptr);
|
||||||
|
|
||||||
static AbstractInterpreter*
|
static AbstractInterpreter *
|
||||||
createJIT(const char *Argv0, std::string &Message,
|
createJIT(const char *Argv0, std::string &Message,
|
||||||
const std::vector<std::string> *Args = nullptr);
|
const std::vector<std::string> *Args = nullptr);
|
||||||
|
|
||||||
static AbstractInterpreter*
|
static AbstractInterpreter *
|
||||||
createCustomCompiler(std::string &Message,
|
createCustomCompiler(std::string &Message,
|
||||||
const std::string &CompileCommandLine);
|
const std::string &CompileCommandLine);
|
||||||
|
|
||||||
static AbstractInterpreter*
|
static AbstractInterpreter *
|
||||||
createCustomExecutor(std::string &Message,
|
createCustomExecutor(std::string &Message,
|
||||||
const std::string &ExecCommandLine);
|
const std::string &ExecCommandLine);
|
||||||
|
|
||||||
|
|
||||||
virtual ~AbstractInterpreter() {}
|
virtual ~AbstractInterpreter() {}
|
||||||
|
|
||||||
/// compileProgram - Compile the specified program from bitcode to executable
|
/// compileProgram - Compile the specified program from bitcode to executable
|
||||||
|
@ -123,9 +119,9 @@ public:
|
||||||
/// fails, it sets Error, otherwise, this function returns the type of code
|
/// fails, it sets Error, otherwise, this function returns the type of code
|
||||||
/// emitted.
|
/// emitted.
|
||||||
virtual CC::FileType OutputCode(const std::string &Bitcode,
|
virtual CC::FileType OutputCode(const std::string &Bitcode,
|
||||||
std::string &OutFile, std::string &Error,
|
std::string &OutFile, std::string &Error,
|
||||||
unsigned Timeout = 0,
|
unsigned Timeout = 0,
|
||||||
unsigned MemoryLimit = 0) {
|
unsigned MemoryLimit = 0) {
|
||||||
Error = "OutputCode not supported by this AbstractInterpreter!";
|
Error = "OutputCode not supported by this AbstractInterpreter!";
|
||||||
return CC::AsmFile;
|
return CC::AsmFile;
|
||||||
}
|
}
|
||||||
|
@ -135,17 +131,13 @@ public:
|
||||||
/// returns false if a problem was encountered that prevented execution of
|
/// returns false if a problem was encountered that prevented execution of
|
||||||
/// the program.
|
/// the program.
|
||||||
///
|
///
|
||||||
virtual int ExecuteProgram(const std::string &Bitcode,
|
virtual int ExecuteProgram(
|
||||||
const std::vector<std::string> &Args,
|
const std::string &Bitcode, const std::vector<std::string> &Args,
|
||||||
const std::string &InputFile,
|
const std::string &InputFile, const std::string &OutputFile,
|
||||||
const std::string &OutputFile,
|
std::string *Error,
|
||||||
std::string *Error,
|
const std::vector<std::string> &CCArgs = std::vector<std::string>(),
|
||||||
const std::vector<std::string> &CCArgs =
|
const std::vector<std::string> &SharedLibs = std::vector<std::string>(),
|
||||||
std::vector<std::string>(),
|
unsigned Timeout = 0, unsigned MemoryLimit = 0) = 0;
|
||||||
const std::vector<std::string> &SharedLibs =
|
|
||||||
std::vector<std::string>(),
|
|
||||||
unsigned Timeout = 0,
|
|
||||||
unsigned MemoryLimit = 0) = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//===---------------------------------------------------------------------===//
|
//===---------------------------------------------------------------------===//
|
||||||
|
@ -156,14 +148,15 @@ class LLC : public AbstractInterpreter {
|
||||||
std::vector<std::string> ToolArgs; // Extra args to pass to LLC.
|
std::vector<std::string> ToolArgs; // Extra args to pass to LLC.
|
||||||
CC *cc;
|
CC *cc;
|
||||||
bool UseIntegratedAssembler;
|
bool UseIntegratedAssembler;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
LLC(const std::string &llcPath, CC *cc,
|
LLC(const std::string &llcPath, CC *cc, const std::vector<std::string> *Args,
|
||||||
const std::vector<std::string> *Args,
|
|
||||||
bool useIntegratedAssembler)
|
bool useIntegratedAssembler)
|
||||||
: LLCPath(llcPath), cc(cc),
|
: LLCPath(llcPath), cc(cc),
|
||||||
UseIntegratedAssembler(useIntegratedAssembler) {
|
UseIntegratedAssembler(useIntegratedAssembler) {
|
||||||
ToolArgs.clear();
|
ToolArgs.clear();
|
||||||
if (Args) ToolArgs = *Args;
|
if (Args)
|
||||||
|
ToolArgs = *Args;
|
||||||
}
|
}
|
||||||
~LLC() override { delete cc; }
|
~LLC() override { delete cc; }
|
||||||
|
|
||||||
|
@ -173,26 +166,21 @@ public:
|
||||||
void compileProgram(const std::string &Bitcode, std::string *Error,
|
void compileProgram(const std::string &Bitcode, std::string *Error,
|
||||||
unsigned Timeout = 0, unsigned MemoryLimit = 0) override;
|
unsigned Timeout = 0, unsigned MemoryLimit = 0) override;
|
||||||
|
|
||||||
int ExecuteProgram(const std::string &Bitcode,
|
int ExecuteProgram(
|
||||||
const std::vector<std::string> &Args,
|
const std::string &Bitcode, const std::vector<std::string> &Args,
|
||||||
const std::string &InputFile,
|
const std::string &InputFile, const std::string &OutputFile,
|
||||||
const std::string &OutputFile,
|
std::string *Error,
|
||||||
std::string *Error,
|
const std::vector<std::string> &CCArgs = std::vector<std::string>(),
|
||||||
const std::vector<std::string> &CCArgs =
|
const std::vector<std::string> &SharedLibs = std::vector<std::string>(),
|
||||||
std::vector<std::string>(),
|
unsigned Timeout = 0, unsigned MemoryLimit = 0) override;
|
||||||
const std::vector<std::string> &SharedLibs =
|
|
||||||
std::vector<std::string>(),
|
|
||||||
unsigned Timeout = 0,
|
|
||||||
unsigned MemoryLimit = 0) override;
|
|
||||||
|
|
||||||
/// OutputCode - Compile the specified program from bitcode to code
|
/// OutputCode - Compile the specified program from bitcode to code
|
||||||
/// understood by the CC driver (either C or asm). If the code generator
|
/// understood by the CC driver (either C or asm). If the code generator
|
||||||
/// fails, it sets Error, otherwise, this function returns the type of code
|
/// fails, it sets Error, otherwise, this function returns the type of code
|
||||||
/// emitted.
|
/// emitted.
|
||||||
CC::FileType OutputCode(const std::string &Bitcode,
|
CC::FileType OutputCode(const std::string &Bitcode, std::string &OutFile,
|
||||||
std::string &OutFile, std::string &Error,
|
std::string &Error, unsigned Timeout = 0,
|
||||||
unsigned Timeout = 0,
|
unsigned MemoryLimit = 0) override;
|
||||||
unsigned MemoryLimit = 0) override;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // End llvm namespace
|
} // End llvm namespace
|
||||||
|
|
|
@ -30,84 +30,82 @@
|
||||||
#include "llvm/Transforms/IPO/AlwaysInliner.h"
|
#include "llvm/Transforms/IPO/AlwaysInliner.h"
|
||||||
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
||||||
|
|
||||||
//Enable this macro to debug bugpoint itself.
|
// Enable this macro to debug bugpoint itself.
|
||||||
//#define DEBUG_BUGPOINT 1
|
//#define DEBUG_BUGPOINT 1
|
||||||
|
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
static cl::opt<bool>
|
static cl::opt<bool>
|
||||||
FindBugs("find-bugs", cl::desc("Run many different optimization sequences "
|
FindBugs("find-bugs", cl::desc("Run many different optimization sequences "
|
||||||
"on program to find bugs"), cl::init(false));
|
"on program to find bugs"),
|
||||||
|
cl::init(false));
|
||||||
|
|
||||||
static cl::list<std::string>
|
static cl::list<std::string>
|
||||||
InputFilenames(cl::Positional, cl::OneOrMore,
|
InputFilenames(cl::Positional, cl::OneOrMore,
|
||||||
cl::desc("<input llvm ll/bc files>"));
|
cl::desc("<input llvm ll/bc files>"));
|
||||||
|
|
||||||
static cl::opt<unsigned>
|
static cl::opt<unsigned> TimeoutValue(
|
||||||
TimeoutValue("timeout", cl::init(300), cl::value_desc("seconds"),
|
"timeout", cl::init(300), cl::value_desc("seconds"),
|
||||||
cl::desc("Number of seconds program is allowed to run before it "
|
cl::desc("Number of seconds program is allowed to run before it "
|
||||||
"is killed (default is 300s), 0 disables timeout"));
|
"is killed (default is 300s), 0 disables timeout"));
|
||||||
|
|
||||||
static cl::opt<int>
|
static cl::opt<int>
|
||||||
MemoryLimit("mlimit", cl::init(-1), cl::value_desc("MBytes"),
|
MemoryLimit("mlimit", cl::init(-1), cl::value_desc("MBytes"),
|
||||||
cl::desc("Maximum amount of memory to use. 0 disables check."
|
cl::desc("Maximum amount of memory to use. 0 disables check."
|
||||||
" Defaults to 400MB (800MB under valgrind)."));
|
" Defaults to 400MB (800MB under valgrind)."));
|
||||||
|
|
||||||
static cl::opt<bool>
|
static cl::opt<bool>
|
||||||
UseValgrind("enable-valgrind",
|
UseValgrind("enable-valgrind",
|
||||||
cl::desc("Run optimizations through valgrind"));
|
cl::desc("Run optimizations through valgrind"));
|
||||||
|
|
||||||
// The AnalysesList is automatically populated with registered Passes by the
|
// The AnalysesList is automatically populated with registered Passes by the
|
||||||
// PassNameParser.
|
// PassNameParser.
|
||||||
//
|
//
|
||||||
static cl::list<const PassInfo*, bool, PassNameParser>
|
static cl::list<const PassInfo *, bool, PassNameParser>
|
||||||
PassList(cl::desc("Passes available:"), cl::ZeroOrMore);
|
PassList(cl::desc("Passes available:"), cl::ZeroOrMore);
|
||||||
|
|
||||||
static cl::opt<bool>
|
static cl::opt<bool>
|
||||||
StandardLinkOpts("std-link-opts",
|
StandardLinkOpts("std-link-opts",
|
||||||
cl::desc("Include the standard link time optimizations"));
|
cl::desc("Include the standard link time optimizations"));
|
||||||
|
|
||||||
static cl::opt<bool>
|
static cl::opt<bool>
|
||||||
OptLevelO1("O1",
|
OptLevelO1("O1", cl::desc("Optimization level 1. Identical to 'opt -O1'"));
|
||||||
cl::desc("Optimization level 1. Identical to 'opt -O1'"));
|
|
||||||
|
|
||||||
static cl::opt<bool>
|
static cl::opt<bool>
|
||||||
OptLevelO2("O2",
|
OptLevelO2("O2", cl::desc("Optimization level 2. Identical to 'opt -O2'"));
|
||||||
cl::desc("Optimization level 2. Identical to 'opt -O2'"));
|
|
||||||
|
static cl::opt<bool> OptLevelOs(
|
||||||
|
"Os",
|
||||||
|
cl::desc(
|
||||||
|
"Like -O2 with extra optimizations for size. Similar to clang -Os"));
|
||||||
|
|
||||||
static cl::opt<bool>
|
static cl::opt<bool>
|
||||||
OptLevelOs("Os",
|
OptLevelO3("O3", cl::desc("Optimization level 3. Identical to 'opt -O3'"));
|
||||||
cl::desc("Like -O2 with extra optimizations for size. Similar to clang -Os"));
|
|
||||||
|
|
||||||
static cl::opt<bool>
|
|
||||||
OptLevelO3("O3",
|
|
||||||
cl::desc("Optimization level 3. Identical to 'opt -O3'"));
|
|
||||||
|
|
||||||
static cl::opt<std::string>
|
static cl::opt<std::string>
|
||||||
OverrideTriple("mtriple", cl::desc("Override target triple for module"));
|
OverrideTriple("mtriple", cl::desc("Override target triple for module"));
|
||||||
|
|
||||||
/// BugpointIsInterrupted - Set to true when the user presses ctrl-c.
|
/// BugpointIsInterrupted - Set to true when the user presses ctrl-c.
|
||||||
bool llvm::BugpointIsInterrupted = false;
|
bool llvm::BugpointIsInterrupted = false;
|
||||||
|
|
||||||
#ifndef DEBUG_BUGPOINT
|
#ifndef DEBUG_BUGPOINT
|
||||||
static void BugpointInterruptFunction() {
|
static void BugpointInterruptFunction() { BugpointIsInterrupted = true; }
|
||||||
BugpointIsInterrupted = true;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Hack to capture a pass list.
|
// Hack to capture a pass list.
|
||||||
namespace {
|
namespace {
|
||||||
class AddToDriver : public legacy::FunctionPassManager {
|
class AddToDriver : public legacy::FunctionPassManager {
|
||||||
BugDriver &D;
|
BugDriver &D;
|
||||||
public:
|
|
||||||
AddToDriver(BugDriver &_D) : FunctionPassManager(nullptr), D(_D) {}
|
|
||||||
|
|
||||||
void add(Pass *P) override {
|
public:
|
||||||
const void *ID = P->getPassID();
|
AddToDriver(BugDriver &_D) : FunctionPassManager(nullptr), D(_D) {}
|
||||||
const PassInfo *PI = PassRegistry::getPassRegistry()->getPassInfo(ID);
|
|
||||||
D.addPass(PI->getPassArgument());
|
void add(Pass *P) override {
|
||||||
}
|
const void *ID = P->getPassID();
|
||||||
};
|
const PassInfo *PI = PassRegistry::getPassRegistry()->getPassInfo(ID);
|
||||||
|
D.addPass(PI->getPassArgument());
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef LINK_POLLY_INTO_TOOLS
|
#ifdef LINK_POLLY_INTO_TOOLS
|
||||||
|
@ -120,7 +118,7 @@ int main(int argc, char **argv) {
|
||||||
#ifndef DEBUG_BUGPOINT
|
#ifndef DEBUG_BUGPOINT
|
||||||
llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
|
llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
|
||||||
llvm::PrettyStackTraceProgram X(argc, argv);
|
llvm::PrettyStackTraceProgram X(argc, argv);
|
||||||
llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
|
llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Initialize passes
|
// Initialize passes
|
||||||
|
@ -165,9 +163,10 @@ int main(int argc, char **argv) {
|
||||||
MemoryLimit = 400;
|
MemoryLimit = 400;
|
||||||
}
|
}
|
||||||
|
|
||||||
BugDriver D(argv[0], FindBugs, TimeoutValue, MemoryLimit,
|
BugDriver D(argv[0], FindBugs, TimeoutValue, MemoryLimit, UseValgrind,
|
||||||
UseValgrind, Context);
|
Context);
|
||||||
if (D.addSources(InputFilenames)) return 1;
|
if (D.addSources(InputFilenames))
|
||||||
|
return 1;
|
||||||
|
|
||||||
AddToDriver PM(D);
|
AddToDriver PM(D);
|
||||||
|
|
||||||
|
@ -192,8 +191,8 @@ int main(int argc, char **argv) {
|
||||||
for (const PassInfo *PI : PassList)
|
for (const PassInfo *PI : PassList)
|
||||||
D.addPass(PI->getPassArgument());
|
D.addPass(PI->getPassArgument());
|
||||||
|
|
||||||
// Bugpoint has the ability of generating a plethora of core files, so to
|
// Bugpoint has the ability of generating a plethora of core files, so to
|
||||||
// avoid filling up the disk, we prevent it
|
// avoid filling up the disk, we prevent it
|
||||||
#ifndef DEBUG_BUGPOINT
|
#ifndef DEBUG_BUGPOINT
|
||||||
sys::Process::PreventCoreFiles();
|
sys::Process::PreventCoreFiles();
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue