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:
Justin Bogner 2016-09-02 01:21:37 +00:00
parent bc46927659
commit 8d0a08115a
11 changed files with 1062 additions and 1131 deletions

View File

@ -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())

View File

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

View File

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

View File

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

View File

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

View File

@ -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.
} }

View File

@ -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";

View File

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

View File

@ -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: " +

View File

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

View File

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