diff options
Diffstat (limited to 'contrib/llvm/tools/bugpoint')
-rw-r--r-- | contrib/llvm/tools/bugpoint/BugDriver.cpp | 29 | ||||
-rw-r--r-- | contrib/llvm/tools/bugpoint/BugDriver.h | 67 | ||||
-rw-r--r-- | contrib/llvm/tools/bugpoint/CMakeLists.txt | 1 | ||||
-rw-r--r-- | contrib/llvm/tools/bugpoint/CrashDebugger.cpp | 73 | ||||
-rw-r--r-- | contrib/llvm/tools/bugpoint/ExecutionDriver.cpp | 24 | ||||
-rw-r--r-- | contrib/llvm/tools/bugpoint/ExtractFunction.cpp | 93 | ||||
-rw-r--r-- | contrib/llvm/tools/bugpoint/FindBugs.cpp | 8 | ||||
-rw-r--r-- | contrib/llvm/tools/bugpoint/Miscompilation.cpp | 157 | ||||
-rw-r--r-- | contrib/llvm/tools/bugpoint/OptimizerDriver.cpp | 113 | ||||
-rw-r--r-- | contrib/llvm/tools/bugpoint/TestPasses.cpp | 75 | ||||
-rw-r--r-- | contrib/llvm/tools/bugpoint/ToolRunner.cpp | 12 | ||||
-rw-r--r-- | contrib/llvm/tools/bugpoint/bugpoint.cpp | 26 |
12 files changed, 322 insertions, 356 deletions
diff --git a/contrib/llvm/tools/bugpoint/BugDriver.cpp b/contrib/llvm/tools/bugpoint/BugDriver.cpp index 45a0d4d..6966671 100644 --- a/contrib/llvm/tools/bugpoint/BugDriver.cpp +++ b/contrib/llvm/tools/bugpoint/BugDriver.cpp @@ -56,22 +56,22 @@ void BugDriver::setNewProgram(Module *M) { /// getPassesString - Turn a list of passes into a string which indicates the /// command line options that must be passed to add the passes. /// -std::string llvm::getPassesString(const std::vector<const PassInfo*> &Passes) { +std::string llvm::getPassesString(const std::vector<std::string> &Passes) { std::string Result; for (unsigned i = 0, e = Passes.size(); i != e; ++i) { if (i) Result += " "; Result += "-"; - Result += Passes[i]->getPassArgument(); + Result += Passes[i]; } return Result; } -BugDriver::BugDriver(const char *toolname, bool as_child, bool find_bugs, +BugDriver::BugDriver(const char *toolname, bool find_bugs, unsigned timeout, unsigned memlimit, bool use_valgrind, LLVMContext& ctxt) : Context(ctxt), ToolName(toolname), ReferenceOutputFile(OutputFile), Program(0), Interpreter(0), SafeInterpreter(0), gcc(0), - run_as_child(as_child), run_find_bugs(find_bugs), Timeout(timeout), + run_find_bugs(find_bugs), Timeout(timeout), MemoryLimit(memlimit), UseValgrind(use_valgrind) {} BugDriver::~BugDriver() { @@ -119,15 +119,13 @@ bool BugDriver::addSources(const std::vector<std::string> &Filenames) { Program = ParseInputFile(Filenames[0], Context); if (Program == 0) return true; - if (!run_as_child) - outs() << "Read input file : '" << Filenames[0] << "'\n"; + outs() << "Read input file : '" << Filenames[0] << "'\n"; for (unsigned i = 1, e = Filenames.size(); i != e; ++i) { std::auto_ptr<Module> M(ParseInputFile(Filenames[i], Context)); if (M.get() == 0) return true; - if (!run_as_child) - outs() << "Linking in input file: '" << Filenames[i] << "'\n"; + outs() << "Linking in input file: '" << Filenames[i] << "'\n"; std::string ErrorMessage; if (Linker::LinkModules(Program, M.get(), &ErrorMessage)) { errs() << ToolName << ": error linking in '" << Filenames[i] << "': " @@ -136,8 +134,7 @@ bool BugDriver::addSources(const std::vector<std::string> &Filenames) { } } - if (!run_as_child) - outs() << "*** All input ok\n"; + outs() << "*** All input ok\n"; // All input files read successfully! return false; @@ -149,14 +146,6 @@ bool BugDriver::addSources(const std::vector<std::string> &Filenames) { /// variables are set up from command line arguments. /// bool BugDriver::run(std::string &ErrMsg) { - // The first thing to do is determine if we're running as a child. If we are, - // then what to do is very narrow. This form of invocation is only called - // from the runPasses method to actually run those passes in a child process. - if (run_as_child) { - // Execute the passes - return runPassesAsChild(PassesToRun); - } - if (run_find_bugs) { // Rearrange the passes and apply them to the program. Repeat this process // until the user kills the program or we find a bug. @@ -172,7 +161,7 @@ bool BugDriver::run(std::string &ErrMsg) { // miscompilation. if (!PassesToRun.empty()) { outs() << "Running selected passes on program to test for crash: "; - if (runPasses(PassesToRun)) + if (runPasses(Program, PassesToRun)) return debugOptimizerCrash(); } @@ -211,7 +200,7 @@ bool BugDriver::run(std::string &ErrMsg) { // matches, then we assume there is a miscompilation bug and try to // diagnose it. outs() << "*** Checking the code generator...\n"; - bool Diff = diffProgram("", "", false, &Error); + bool Diff = diffProgram(Program, "", "", false, &Error); if (!Error.empty()) { errs() << Error; return debugCodeGeneratorCrash(ErrMsg); diff --git a/contrib/llvm/tools/bugpoint/BugDriver.h b/contrib/llvm/tools/bugpoint/BugDriver.h index 4f6bae5..e48806a 100644 --- a/contrib/llvm/tools/bugpoint/BugDriver.h +++ b/contrib/llvm/tools/bugpoint/BugDriver.h @@ -47,11 +47,10 @@ class BugDriver { const char *ToolName; // argv[0] of bugpoint std::string ReferenceOutputFile; // Name of `good' output file Module *Program; // The raw program, linked together - std::vector<const PassInfo*> PassesToRun; + std::vector<std::string> PassesToRun; AbstractInterpreter *Interpreter; // How to run the program AbstractInterpreter *SafeInterpreter; // To generate reference output, etc. GCC *gcc; - bool run_as_child; bool run_find_bugs; unsigned Timeout; unsigned MemoryLimit; @@ -62,25 +61,24 @@ class BugDriver { friend class ReduceMisCodegenFunctions; public: - BugDriver(const char *toolname, bool as_child, bool find_bugs, + BugDriver(const char *toolname, bool find_bugs, unsigned timeout, unsigned memlimit, bool use_valgrind, LLVMContext& ctxt); ~BugDriver(); const char *getToolName() const { return ToolName; } - LLVMContext& getContext() { return Context; } + LLVMContext& getContext() const { return Context; } // Set up methods... these methods are used to copy information about the // command line arguments into instance variables of BugDriver. // bool addSources(const std::vector<std::string> &FileNames); - template<class It> - void addPasses(It I, It E) { PassesToRun.insert(PassesToRun.end(), I, E); } - void setPassesToRun(const std::vector<const PassInfo*> &PTR) { + void addPass(std::string p) { PassesToRun.push_back(p); } + void setPassesToRun(const std::vector<std::string> &PTR) { PassesToRun = PTR; } - const std::vector<const PassInfo*> &getPassesToRun() const { + const std::vector<std::string> &getPassesToRun() const { return PassesToRun; } @@ -132,12 +130,8 @@ public: /// runPasses - Run all of the passes in the "PassesToRun" list, discard the /// output, and return true if any of the passes crashed. - bool runPasses(Module *M = 0) { - if (M == 0) M = Program; - std::swap(M, Program); - bool Result = runPasses(PassesToRun); - std::swap(M, Program); - return Result; + bool runPasses(Module *M) const { + return runPasses(M, PassesToRun); } Module *getProgram() const { return Program; } @@ -169,23 +163,26 @@ public: /// setting Error if an error occurs. This is used for code generation /// crash testing. /// - void compileProgram(Module *M, std::string *Error); + void compileProgram(Module *M, std::string *Error) const; /// executeProgram - This method runs "Program", capturing the output of the /// program to a file. A recommended filename may be optionally specified. /// - std::string executeProgram(std::string OutputFilename, + std::string executeProgram(const Module *Program, + std::string OutputFilename, std::string Bitcode, const std::string &SharedObjects, AbstractInterpreter *AI, - std::string *Error); + std::string *Error) const; /// executeProgramSafely - Used to create reference output with the "safe" /// backend, if reference output is not provided. If there is a problem with /// the code generator (e.g., llc crashes), this will return false and set /// Error. /// - std::string executeProgramSafely(std::string OutputFile, std::string *Error); + std::string executeProgramSafely(const Module *Program, + std::string OutputFile, + std::string *Error) const; /// createReferenceFile - calls compileProgram and then records the output /// into ReferenceOutputFile. Returns true if reference file created, false @@ -200,23 +197,24 @@ public: /// is different, 1 is returned. If there is a problem with the code /// generator (e.g., llc crashes), this will return -1 and set Error. /// - bool diffProgram(const std::string &BitcodeFile = "", + bool diffProgram(const Module *Program, + const std::string &BitcodeFile = "", const std::string &SharedObj = "", bool RemoveBitcode = false, - std::string *Error = 0); + std::string *Error = 0) const; - /// EmitProgressBitcode - This function is used to output the current Program - /// to a file named "bugpoint-ID.bc". + /// EmitProgressBitcode - This function is used to output M to a file named + /// "bugpoint-ID.bc". /// - void EmitProgressBitcode(const std::string &ID, bool NoFlyer = false); + void EmitProgressBitcode(const Module *M, const std::string &ID, + bool NoFlyer = false) const; /// deleteInstructionFromProgram - This method clones the current Program and /// deletes the specified instruction from the cloned module. It then runs a /// series of cleanup passes (ADCE and SimplifyCFG) to eliminate any code /// which depends on the value. The modified module is then returned. /// - Module *deleteInstructionFromProgram(const Instruction *I, unsigned Simp) - const; + Module *deleteInstructionFromProgram(const Instruction *I, unsigned Simp); /// performFinalCleanups - This method clones the current Program and performs /// a series of cleanups intended to get rid of extra cruft on the module. If @@ -243,7 +241,7 @@ public: /// failure. If AutoDebugCrashes is set to true, then bugpoint will /// automatically attempt to track down a crashing pass if one exists, and /// this method will never return null. - Module *runPassesOn(Module *M, const std::vector<const PassInfo*> &Passes, + Module *runPassesOn(Module *M, const std::vector<std::string> &Passes, bool AutoDebugCrashes = false, unsigned NumExtraArgs = 0, const char * const *ExtraArgs = NULL); @@ -256,7 +254,8 @@ public: /// or failed, unless Quiet is set. ExtraArgs specifies additional arguments /// to pass to the child bugpoint instance. /// - bool runPasses(const std::vector<const PassInfo*> &PassesToRun, + bool runPasses(Module *Program, + const std::vector<std::string> &PassesToRun, std::string &OutputFilename, bool DeleteOutput = false, bool Quiet = false, unsigned NumExtraArgs = 0, const char * const *ExtraArgs = NULL) const; @@ -268,28 +267,26 @@ public: /// If the passes did not compile correctly, output the command required to /// recreate the failure. This returns true if a compiler error is found. /// - bool runManyPasses(const std::vector<const PassInfo*> &AllPasses, + bool runManyPasses(const std::vector<std::string> &AllPasses, std::string &ErrMsg); /// writeProgramToFile - This writes the current "Program" to the named /// bitcode file. If an error occurs, true is returned. /// - bool writeProgramToFile(const std::string &Filename, Module *M = 0) const; + bool writeProgramToFile(const std::string &Filename, const Module *M) const; private: /// runPasses - Just like the method above, but this just returns true or /// false indicating whether or not the optimizer crashed on the specified /// input (true = crashed). /// - bool runPasses(const std::vector<const PassInfo*> &PassesToRun, + bool runPasses(Module *M, + const std::vector<std::string> &PassesToRun, bool DeleteOutput = true) const { std::string Filename; - return runPasses(PassesToRun, Filename, DeleteOutput); + return runPasses(M, PassesToRun, Filename, DeleteOutput); } - /// runAsChild - The actual "runPasses" guts that runs in a child process. - int runPassesAsChild(const std::vector<const PassInfo*> &PassesToRun); - /// initializeExecutionEnvironment - This method is used to set up the /// environment for executing LLVM programs. /// @@ -306,7 +303,7 @@ Module *ParseInputFile(const std::string &InputFilename, /// getPassesString - Turn a list of passes into a string which indicates the /// command line options that must be passed to add the passes. /// -std::string getPassesString(const std::vector<const PassInfo*> &Passes); +std::string getPassesString(const std::vector<std::string> &Passes); /// PrintFunctionList - prints out list of problematic functions /// diff --git a/contrib/llvm/tools/bugpoint/CMakeLists.txt b/contrib/llvm/tools/bugpoint/CMakeLists.txt index 34b759f..e06feb1 100644 --- a/contrib/llvm/tools/bugpoint/CMakeLists.txt +++ b/contrib/llvm/tools/bugpoint/CMakeLists.txt @@ -9,7 +9,6 @@ add_llvm_tool(bugpoint FindBugs.cpp Miscompilation.cpp OptimizerDriver.cpp - TestPasses.cpp ToolRunner.cpp bugpoint.cpp ) diff --git a/contrib/llvm/tools/bugpoint/CrashDebugger.cpp b/contrib/llvm/tools/bugpoint/CrashDebugger.cpp index 2d0631c..57dc1c8 100644 --- a/contrib/llvm/tools/bugpoint/CrashDebugger.cpp +++ b/contrib/llvm/tools/bugpoint/CrashDebugger.cpp @@ -43,7 +43,7 @@ namespace { } namespace llvm { - class ReducePassList : public ListReducer<const PassInfo*> { + class ReducePassList : public ListReducer<std::string> { BugDriver &BD; public: ReducePassList(BugDriver &bd) : BD(bd) {} @@ -52,15 +52,15 @@ namespace llvm { // running the "Kept" passes fail when run on the output of the "removed" // passes. If we return true, we update the current module of bugpoint. // - virtual TestResult doTest(std::vector<const PassInfo*> &Removed, - std::vector<const PassInfo*> &Kept, + virtual TestResult doTest(std::vector<std::string> &Removed, + std::vector<std::string> &Kept, std::string &Error); }; } ReducePassList::TestResult -ReducePassList::doTest(std::vector<const PassInfo*> &Prefix, - std::vector<const PassInfo*> &Suffix, +ReducePassList::doTest(std::vector<std::string> &Prefix, + std::vector<std::string> &Suffix, std::string &Error) { sys::Path PrefixOutput; Module *OrigProgram = 0; @@ -68,7 +68,7 @@ ReducePassList::doTest(std::vector<const PassInfo*> &Prefix, outs() << "Checking to see if these passes crash: " << getPassesString(Prefix) << ": "; std::string PfxOutput; - if (BD.runPasses(Prefix, PfxOutput)) + if (BD.runPasses(BD.getProgram(), Prefix, PfxOutput)) return KeepPrefix; PrefixOutput.set(PfxOutput); @@ -86,7 +86,7 @@ ReducePassList::doTest(std::vector<const PassInfo*> &Prefix, outs() << "Checking to see if these passes crash: " << getPassesString(Suffix) << ": "; - if (BD.runPasses(Suffix)) { + if (BD.runPasses(BD.getProgram(), Suffix)) { delete OrigProgram; // The suffix crashes alone... return KeepSuffix; } @@ -106,10 +106,10 @@ namespace { /// class ReduceCrashingGlobalVariables : public ListReducer<GlobalVariable*> { BugDriver &BD; - bool (*TestFn)(BugDriver &, Module *); + bool (*TestFn)(const BugDriver &, Module *); public: ReduceCrashingGlobalVariables(BugDriver &bd, - bool (*testFn)(BugDriver &, Module *)) + bool (*testFn)(const BugDriver &, Module *)) : BD(bd), TestFn(testFn) {} virtual TestResult doTest(std::vector<GlobalVariable*> &Prefix, @@ -176,10 +176,10 @@ namespace llvm { /// class ReduceCrashingFunctions : public ListReducer<Function*> { BugDriver &BD; - bool (*TestFn)(BugDriver &, Module *); + bool (*TestFn)(const BugDriver &, Module *); public: ReduceCrashingFunctions(BugDriver &bd, - bool (*testFn)(BugDriver &, Module *)) + bool (*testFn)(const BugDriver &, Module *)) : BD(bd), TestFn(testFn) {} virtual TestResult doTest(std::vector<Function*> &Prefix, @@ -249,9 +249,10 @@ namespace { /// class ReduceCrashingBlocks : public ListReducer<const BasicBlock*> { BugDriver &BD; - bool (*TestFn)(BugDriver &, Module *); + bool (*TestFn)(const BugDriver &, Module *); public: - ReduceCrashingBlocks(BugDriver &bd, bool (*testFn)(BugDriver &, Module *)) + ReduceCrashingBlocks(BugDriver &bd, + bool (*testFn)(const BugDriver &, Module *)) : BD(bd), TestFn(testFn) {} virtual TestResult doTest(std::vector<const BasicBlock*> &Prefix, @@ -311,17 +312,24 @@ bool ReduceCrashingBlocks::TestBlocks(std::vector<const BasicBlock*> &BBs) { // 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 // have to take. - std::vector<std::pair<Function*, std::string> > BlockInfo; + std::vector<std::pair<std::string, std::string> > BlockInfo; for (SmallPtrSet<BasicBlock*, 8>::iterator I = Blocks.begin(), E = Blocks.end(); I != E; ++I) - BlockInfo.push_back(std::make_pair((*I)->getParent(), (*I)->getName())); + BlockInfo.push_back(std::make_pair((*I)->getParent()->getName(), + (*I)->getName())); // Now run the CFG simplify pass on the function... - PassManager Passes; - Passes.add(createCFGSimplificationPass()); - Passes.add(createVerifierPass()); - Passes.run(*M); + std::vector<std::string> Passes; + Passes.push_back("simplifycfg"); + Passes.push_back("verify"); + Module *New = BD.runPassesOn(M, Passes); + delete M; + if (!New) { + errs() << "simplifycfg failed!\n"; + exit(1); + } + M = New; // Try running on the hacked up program... if (TestFn(BD, M)) { @@ -330,8 +338,10 @@ bool ReduceCrashingBlocks::TestBlocks(std::vector<const BasicBlock*> &BBs) { // Make sure to use basic block pointers that point into the now-current // module, and that they don't include any deleted blocks. BBs.clear(); + const ValueSymbolTable &GST = M->getValueSymbolTable(); for (unsigned i = 0, e = BlockInfo.size(); i != e; ++i) { - ValueSymbolTable &ST = BlockInfo[i].first->getValueSymbolTable(); + Function *F = cast<Function>(GST.lookup(BlockInfo[i].first)); + ValueSymbolTable &ST = F->getValueSymbolTable(); Value* V = ST.lookup(BlockInfo[i].second); if (V && V->getType() == Type::getLabelTy(V->getContext())) BBs.push_back(cast<BasicBlock>(V)); @@ -348,10 +358,10 @@ namespace { /// class ReduceCrashingInstructions : public ListReducer<const Instruction*> { BugDriver &BD; - bool (*TestFn)(BugDriver &, Module *); + bool (*TestFn)(const BugDriver &, Module *); public: - ReduceCrashingInstructions(BugDriver &bd, bool (*testFn)(BugDriver &, - Module *)) + ReduceCrashingInstructions(BugDriver &bd, + bool (*testFn)(const BugDriver &, Module *)) : BD(bd), TestFn(testFn) {} virtual TestResult doTest(std::vector<const Instruction*> &Prefix, @@ -422,7 +432,8 @@ bool ReduceCrashingInstructions::TestInsts(std::vector<const Instruction*> /// DebugACrash - Given a predicate that determines whether a component crashes /// on a program, try to destructively reduce the program while still keeping /// the predicate true. -static bool DebugACrash(BugDriver &BD, bool (*TestFn)(BugDriver &, Module *), +static bool DebugACrash(BugDriver &BD, + bool (*TestFn)(const BugDriver &, Module *), std::string &Error) { // See if we can get away with nuking some of the global variable initializers // in the program... @@ -471,7 +482,7 @@ static bool DebugACrash(BugDriver &BD, bool (*TestFn)(BugDriver &, Module *), return true; if (GVs.size() < OldSize) - BD.EmitProgressBitcode("reduced-global-variables"); + BD.EmitProgressBitcode(BD.getProgram(), "reduced-global-variables"); } } } @@ -492,7 +503,7 @@ static bool DebugACrash(BugDriver &BD, bool (*TestFn)(BugDriver &, Module *), ReduceCrashingFunctions(BD, TestFn).reduceList(Functions, Error); if (Functions.size() < OldSize) - BD.EmitProgressBitcode("reduced-function"); + BD.EmitProgressBitcode(BD.getProgram(), "reduced-function"); } // Attempt to delete entire basic blocks at a time to speed up @@ -509,7 +520,7 @@ static bool DebugACrash(BugDriver &BD, bool (*TestFn)(BugDriver &, Module *), unsigned OldSize = Blocks.size(); ReduceCrashingBlocks(BD, TestFn).reduceList(Blocks, Error); if (Blocks.size() < OldSize) - BD.EmitProgressBitcode("reduced-blocks"); + BD.EmitProgressBitcode(BD.getProgram(), "reduced-blocks"); } // Attempt to delete instructions using bisection. This should help out nasty @@ -602,12 +613,12 @@ ExitLoops: } } - BD.EmitProgressBitcode("reduced-simplified"); + BD.EmitProgressBitcode(BD.getProgram(), "reduced-simplified"); return false; } -static bool TestForOptimizerCrash(BugDriver &BD, Module *M) { +static bool TestForOptimizerCrash(const BugDriver &BD, Module *M) { return BD.runPasses(M); } @@ -628,14 +639,14 @@ bool BugDriver::debugOptimizerCrash(const std::string &ID) { << (PassesToRun.size() == 1 ? ": " : "es: ") << getPassesString(PassesToRun) << '\n'; - EmitProgressBitcode(ID); + EmitProgressBitcode(Program, ID); bool Success = DebugACrash(*this, TestForOptimizerCrash, Error); assert(Error.empty()); return Success; } -static bool TestForCodeGenCrash(BugDriver &BD, Module *M) { +static bool TestForCodeGenCrash(const BugDriver &BD, Module *M) { std::string Error; BD.compileProgram(M, &Error); if (!Error.empty()) { diff --git a/contrib/llvm/tools/bugpoint/ExecutionDriver.cpp b/contrib/llvm/tools/bugpoint/ExecutionDriver.cpp index 57f12d5..7312484 100644 --- a/contrib/llvm/tools/bugpoint/ExecutionDriver.cpp +++ b/contrib/llvm/tools/bugpoint/ExecutionDriver.cpp @@ -293,7 +293,7 @@ bool BugDriver::initializeExecutionEnvironment() { /// setting Error if an error occurs. This is used for code generation /// crash testing. /// -void BugDriver::compileProgram(Module *M, std::string *Error) { +void BugDriver::compileProgram(Module *M, std::string *Error) const { // Emit the program to a bitcode file... sys::Path BitcodeFile (OutputPrefix + "-test-program.bc"); std::string ErrMsg; @@ -320,11 +320,12 @@ void BugDriver::compileProgram(Module *M, std::string *Error) { /// program to a file, returning the filename of the file. A recommended /// filename may be optionally specified. /// -std::string BugDriver::executeProgram(std::string OutputFile, +std::string BugDriver::executeProgram(const Module *Program, + std::string OutputFile, std::string BitcodeFile, const std::string &SharedObj, AbstractInterpreter *AI, - std::string *Error) { + std::string *Error) const { if (AI == 0) AI = Interpreter; assert(AI && "Interpreter should have been created already!"); bool CreatedBitcode = false; @@ -399,9 +400,10 @@ std::string BugDriver::executeProgram(std::string OutputFile, /// executeProgramSafely - Used to create reference output with the "safe" /// backend, if reference output is not provided. /// -std::string BugDriver::executeProgramSafely(std::string OutputFile, - std::string *Error) { - return executeProgram(OutputFile, "", "", SafeInterpreter, Error); +std::string BugDriver::executeProgramSafely(const Module *Program, + std::string OutputFile, + std::string *Error) const { + return executeProgram(Program, OutputFile, "", "", SafeInterpreter, Error); } std::string BugDriver::compileSharedObject(const std::string &BitcodeFile, @@ -440,7 +442,7 @@ bool BugDriver::createReferenceFile(Module *M, const std::string &Filename) { if (!Error.empty()) return false; - ReferenceOutputFile = executeProgramSafely(Filename, &Error); + ReferenceOutputFile = executeProgramSafely(Program, Filename, &Error); if (!Error.empty()) { errs() << Error; if (Interpreter != SafeInterpreter) { @@ -460,12 +462,14 @@ bool BugDriver::createReferenceFile(Module *M, const std::string &Filename) { /// is different, 1 is returned. If there is a problem with the code /// generator (e.g., llc crashes), this will return -1 and set Error. /// -bool BugDriver::diffProgram(const std::string &BitcodeFile, +bool BugDriver::diffProgram(const Module *Program, + const std::string &BitcodeFile, const std::string &SharedObject, bool RemoveBitcode, - std::string *ErrMsg) { + std::string *ErrMsg) const { // Execute the program, generating an output file... - sys::Path Output(executeProgram("", BitcodeFile, SharedObject, 0, ErrMsg)); + sys::Path Output(executeProgram(Program, "", BitcodeFile, SharedObject, 0, + ErrMsg)); if (!ErrMsg->empty()) return false; diff --git a/contrib/llvm/tools/bugpoint/ExtractFunction.cpp b/contrib/llvm/tools/bugpoint/ExtractFunction.cpp index d5611b5..524f130 100644 --- a/contrib/llvm/tools/bugpoint/ExtractFunction.cpp +++ b/contrib/llvm/tools/bugpoint/ExtractFunction.cpp @@ -55,13 +55,14 @@ namespace { /// depends on the value. The modified module is then returned. /// Module *BugDriver::deleteInstructionFromProgram(const Instruction *I, - unsigned Simplification) const { - Module *Result = CloneModule(Program); + unsigned Simplification) { + // FIXME, use vmap? + Module *Clone = CloneModule(Program); const BasicBlock *PBB = I->getParent(); const Function *PF = PBB->getParent(); - Module::iterator RFI = Result->begin(); // Get iterator to corresponding fn + Module::iterator RFI = Clone->begin(); // Get iterator to corresponding fn std::advance(RFI, std::distance(PF->getParent()->begin(), Module::const_iterator(PF))); @@ -79,30 +80,23 @@ Module *BugDriver::deleteInstructionFromProgram(const Instruction *I, // Remove the instruction from the program. TheInst->getParent()->getInstList().erase(TheInst); - - //writeProgramToFile("current.bc", Result); - // Spiff up the output a little bit. - PassManager Passes; - // Make sure that the appropriate target data is always used... - Passes.add(new TargetData(Result)); + std::vector<std::string> Passes; - /// FIXME: If this used runPasses() like the methods below, we could get rid - /// of the -disable-* options! + /// Can we get rid of the -disable-* options? if (Simplification > 1 && !NoDCE) - Passes.add(createDeadCodeEliminationPass()); + Passes.push_back("dce"); if (Simplification && !DisableSimplifyCFG) - Passes.add(createCFGSimplificationPass()); // Delete dead control flow - - Passes.add(createVerifierPass()); - Passes.run(*Result); - return Result; -} - -static const PassInfo *getPI(Pass *P) { - const PassInfo *PI = P->getPassInfo(); - delete P; - return PI; + Passes.push_back("simplifycfg"); // Delete dead control flow + + Passes.push_back("verify"); + Module *New = runPassesOn(Clone, Passes); + delete Clone; + if (!New) { + errs() << "Instruction removal failed. Sorry. :( Please report a bug!\n"; + exit(1); + } + return New; } /// performFinalCleanups - This method clones the current Program and performs @@ -114,15 +108,15 @@ Module *BugDriver::performFinalCleanups(Module *M, bool MayModifySemantics) { for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) I->setLinkage(GlobalValue::ExternalLinkage); - std::vector<const PassInfo*> CleanupPasses; - CleanupPasses.push_back(getPI(createGlobalDCEPass())); + std::vector<std::string> CleanupPasses; + CleanupPasses.push_back("globaldce"); if (MayModifySemantics) - CleanupPasses.push_back(getPI(createDeadArgHackingPass())); + CleanupPasses.push_back("deadarghaX0r"); else - CleanupPasses.push_back(getPI(createDeadArgEliminationPass())); + CleanupPasses.push_back("deadargelim"); - CleanupPasses.push_back(getPI(createDeadTypeEliminationPass())); + CleanupPasses.push_back("deadtypeelim"); Module *New = runPassesOn(M, CleanupPasses); if (New == 0) { @@ -138,16 +132,14 @@ Module *BugDriver::performFinalCleanups(Module *M, bool MayModifySemantics) { /// function. This returns null if there are no extractable loops in the /// program or if the loop extractor crashes. Module *BugDriver::ExtractLoop(Module *M) { - std::vector<const PassInfo*> LoopExtractPasses; - LoopExtractPasses.push_back(getPI(createSingleLoopExtractorPass())); + std::vector<std::string> LoopExtractPasses; + LoopExtractPasses.push_back("loop-extract-single"); Module *NewM = runPassesOn(M, LoopExtractPasses); if (NewM == 0) { - Module *Old = swapProgramIn(M); outs() << "*** Loop extraction failed: "; - EmitProgressBitcode("loopextraction", true); + EmitProgressBitcode(M, "loopextraction", true); outs() << "*** Sorry. :( Please report a bug!\n"; - swapProgramIn(Old); return 0; } @@ -201,7 +193,7 @@ static Constant *GetTorInit(std::vector<std::pair<Function*, int> > &TorList) { /// static ctors/dtors, we need to add an llvm.global_[cd]tors global to M2, and /// prune appropriate entries out of M1s list. static void SplitStaticCtorDtor(const char *GlobalName, Module *M1, Module *M2, - ValueMap<const Value*, Value*> VMap) { + ValueMap<const Value*, Value*> &VMap) { GlobalVariable *GV = M1->getNamedGlobal(GlobalName); if (!GV || GV->isDeclaration() || GV->hasLocalLinkage() || !GV->use_empty()) return; @@ -327,22 +319,18 @@ Module *BugDriver::ExtractMappedBlocksFromModule(const if (uniqueFilename.createTemporaryFileOnDisk(true, &ErrMsg)) { outs() << "*** Basic Block extraction failed!\n"; errs() << "Error creating temporary file: " << ErrMsg << "\n"; - M = swapProgramIn(M); - EmitProgressBitcode("basicblockextractfail", true); - swapProgramIn(M); + EmitProgressBitcode(M, "basicblockextractfail", true); return 0; } sys::RemoveFileOnSignal(uniqueFilename); std::string ErrorInfo; - raw_fd_ostream BlocksToNotExtractFile(uniqueFilename.c_str(), ErrorInfo); + tool_output_file BlocksToNotExtractFile(uniqueFilename.c_str(), ErrorInfo); if (!ErrorInfo.empty()) { outs() << "*** Basic Block extraction failed!\n"; errs() << "Error writing list of blocks to not extract: " << ErrorInfo << "\n"; - M = swapProgramIn(M); - EmitProgressBitcode("basicblockextractfail", true); - swapProgramIn(M); + EmitProgressBitcode(M, "basicblockextractfail", true); return 0; } for (std::vector<BasicBlock*>::const_iterator I = BBs.begin(), E = BBs.end(); @@ -351,26 +339,31 @@ Module *BugDriver::ExtractMappedBlocksFromModule(const // If the BB doesn't have a name, give it one so we have something to key // off of. if (!BB->hasName()) BB->setName("tmpbb"); - BlocksToNotExtractFile << BB->getParent()->getNameStr() << " " - << BB->getName() << "\n"; + BlocksToNotExtractFile.os() << BB->getParent()->getNameStr() << " " + << BB->getName() << "\n"; + } + BlocksToNotExtractFile.os().close(); + if (BlocksToNotExtractFile.os().has_error()) { + errs() << "Error writing list of blocks to not extract: " << ErrorInfo + << "\n"; + EmitProgressBitcode(M, "basicblockextractfail", true); + BlocksToNotExtractFile.os().clear_error(); + return 0; } - BlocksToNotExtractFile.close(); + BlocksToNotExtractFile.keep(); std::string uniqueFN = "--extract-blocks-file=" + uniqueFilename.str(); const char *ExtraArg = uniqueFN.c_str(); - std::vector<const PassInfo*> PI; - std::vector<BasicBlock *> EmptyBBs; // This parameter is ignored. - PI.push_back(getPI(createBlockExtractorPass(EmptyBBs))); + std::vector<std::string> PI; + PI.push_back("extract-blocks"); Module *Ret = runPassesOn(M, PI, false, 1, &ExtraArg); uniqueFilename.eraseFromDisk(); // Free disk space if (Ret == 0) { outs() << "*** Basic Block extraction failed, please report a bug!\n"; - M = swapProgramIn(M); - EmitProgressBitcode("basicblockextractfail", true); - swapProgramIn(M); + EmitProgressBitcode(M, "basicblockextractfail", true); } return Ret; } diff --git a/contrib/llvm/tools/bugpoint/FindBugs.cpp b/contrib/llvm/tools/bugpoint/FindBugs.cpp index 224c717..a291f9f 100644 --- a/contrib/llvm/tools/bugpoint/FindBugs.cpp +++ b/contrib/llvm/tools/bugpoint/FindBugs.cpp @@ -29,7 +29,7 @@ using namespace llvm; /// If the passes did not compile correctly, output the command required to /// recreate the failure. This returns true if a compiler error is found. /// -bool BugDriver::runManyPasses(const std::vector<const PassInfo*> &AllPasses, +bool BugDriver::runManyPasses(const std::vector<std::string> &AllPasses, std::string &ErrMsg) { setPassesToRun(AllPasses); outs() << "Starting bug finding procedure...\n\n"; @@ -58,11 +58,11 @@ bool BugDriver::runManyPasses(const std::vector<const PassInfo*> &AllPasses, // outs() << "Running selected passes on program to test for crash: "; for(int i = 0, e = PassesToRun.size(); i != e; i++) { - outs() << "-" << PassesToRun[i]->getPassArgument() << " "; + outs() << "-" << PassesToRun[i] << " "; } std::string Filename; - if(runPasses(PassesToRun, Filename, false)) { + if(runPasses(Program, PassesToRun, Filename, false)) { outs() << "\n"; outs() << "Optimizer passes caused failure!\n\n"; debugOptimizerCrash(); @@ -89,7 +89,7 @@ bool BugDriver::runManyPasses(const std::vector<const PassInfo*> &AllPasses, // output (created above). // outs() << "*** Checking if passes caused miscompliation:\n"; - bool Diff = diffProgram(Filename, "", false, &Error); + bool Diff = diffProgram(Program, Filename, "", false, &Error); if (Error.empty() && Diff) { outs() << "\n*** diffProgram returned true!\n"; debugMiscompilation(&Error); diff --git a/contrib/llvm/tools/bugpoint/Miscompilation.cpp b/contrib/llvm/tools/bugpoint/Miscompilation.cpp index 47ac3c5..3f2b696 100644 --- a/contrib/llvm/tools/bugpoint/Miscompilation.cpp +++ b/contrib/llvm/tools/bugpoint/Miscompilation.cpp @@ -43,13 +43,13 @@ namespace { cl::desc("Don't extract blocks when searching for miscompilations"), cl::init(false)); - class ReduceMiscompilingPasses : public ListReducer<const PassInfo*> { + class ReduceMiscompilingPasses : public ListReducer<std::string> { BugDriver &BD; public: ReduceMiscompilingPasses(BugDriver &bd) : BD(bd) {} - virtual TestResult doTest(std::vector<const PassInfo*> &Prefix, - std::vector<const PassInfo*> &Suffix, + virtual TestResult doTest(std::vector<std::string> &Prefix, + std::vector<std::string> &Suffix, std::string &Error); }; } @@ -58,8 +58,8 @@ namespace { /// group, see if they still break the program. /// ReduceMiscompilingPasses::TestResult -ReduceMiscompilingPasses::doTest(std::vector<const PassInfo*> &Prefix, - std::vector<const PassInfo*> &Suffix, +ReduceMiscompilingPasses::doTest(std::vector<std::string> &Prefix, + std::vector<std::string> &Suffix, std::string &Error) { // First, run the program with just the Suffix passes. If it is still broken // with JUST the kept passes, discard the prefix passes. @@ -67,17 +67,18 @@ ReduceMiscompilingPasses::doTest(std::vector<const PassInfo*> &Prefix, << "' compiles correctly: "; std::string BitcodeResult; - if (BD.runPasses(Suffix, BitcodeResult, false/*delete*/, true/*quiet*/)) { + if (BD.runPasses(BD.getProgram(), Suffix, BitcodeResult, false/*delete*/, + true/*quiet*/)) { errs() << " Error running this sequence of passes" << " on the input program!\n"; BD.setPassesToRun(Suffix); - BD.EmitProgressBitcode("pass-error", false); + BD.EmitProgressBitcode(BD.getProgram(), "pass-error", false); exit(BD.debugOptimizerCrash()); } // Check to see if the finished program matches the reference output... - bool Diff = BD.diffProgram(BitcodeResult, "", true /*delete bitcode*/, - &Error); + bool Diff = BD.diffProgram(BD.getProgram(), BitcodeResult, "", + true /*delete bitcode*/, &Error); if (!Error.empty()) return InternalError; if (Diff) { @@ -104,16 +105,17 @@ ReduceMiscompilingPasses::doTest(std::vector<const PassInfo*> &Prefix, // kept passes, we can update our bitcode file to include the result of the // prefix passes, then discard the prefix passes. // - if (BD.runPasses(Prefix, BitcodeResult, false/*delete*/, true/*quiet*/)) { + if (BD.runPasses(BD.getProgram(), Prefix, BitcodeResult, false/*delete*/, + true/*quiet*/)) { errs() << " Error running this sequence of passes" << " on the input program!\n"; BD.setPassesToRun(Prefix); - BD.EmitProgressBitcode("pass-error", false); + BD.EmitProgressBitcode(BD.getProgram(), "pass-error", false); exit(BD.debugOptimizerCrash()); } // If the prefix maintains the predicate by itself, only keep the prefix! - Diff = BD.diffProgram(BitcodeResult, "", false, &Error); + Diff = BD.diffProgram(BD.getProgram(), BitcodeResult, "", false, &Error); if (!Error.empty()) return InternalError; if (Diff) { @@ -144,16 +146,18 @@ ReduceMiscompilingPasses::doTest(std::vector<const PassInfo*> &Prefix, << getPassesString(Prefix) << "' passes: "; OwningPtr<Module> OriginalInput(BD.swapProgramIn(PrefixOutput.take())); - if (BD.runPasses(Suffix, BitcodeResult, false/*delete*/, true/*quiet*/)) { + if (BD.runPasses(BD.getProgram(), Suffix, BitcodeResult, false/*delete*/, + true/*quiet*/)) { errs() << " Error running this sequence of passes" << " on the input program!\n"; BD.setPassesToRun(Suffix); - BD.EmitProgressBitcode("pass-error", false); + BD.EmitProgressBitcode(BD.getProgram(), "pass-error", false); exit(BD.debugOptimizerCrash()); } // Run the result... - Diff = BD.diffProgram(BitcodeResult, "", true /*delete bitcode*/, &Error); + Diff = BD.diffProgram(BD.getProgram(), BitcodeResult, "", + true /*delete bitcode*/, &Error); if (!Error.empty()) return InternalError; if (Diff) { @@ -198,18 +202,20 @@ namespace { return NoFailure; } - int TestFuncs(const std::vector<Function*> &Prefix, std::string &Error); + bool TestFuncs(const std::vector<Function*> &Prefix, std::string &Error); }; } /// TestMergedProgram - Given two modules, link them together and run the -/// program, checking to see if the program matches the diff. If the diff -/// matches, return false, otherwise return true. If the DeleteInputs argument -/// is set to true then this function deletes both input modules before it -/// returns. +/// program, checking to see if the program matches the diff. If there is +/// an error, return NULL. If not, return the merged module. The Broken argument +/// will be set to true if the output is different. If the DeleteInputs +/// argument is set to true then this function deletes both input +/// modules before it returns. /// -static bool TestMergedProgram(BugDriver &BD, Module *M1, Module *M2, - bool DeleteInputs, std::string &Error) { +static Module *TestMergedProgram(const BugDriver &BD, Module *M1, Module *M2, + bool DeleteInputs, std::string &Error, + bool &Broken) { // Link the two portions of the program back to together. std::string ErrorMsg; if (!DeleteInputs) { @@ -223,24 +229,22 @@ static bool TestMergedProgram(BugDriver &BD, Module *M1, Module *M2, } delete M2; // We are done with this module. - OwningPtr<Module> OldProgram(BD.swapProgramIn(M1)); - - // Execute the program. If it does not match the expected output, we must - // return true. - bool Broken = BD.diffProgram("", "", false, &Error); + // Execute the program. + Broken = BD.diffProgram(M1, "", "", false, &Error); if (!Error.empty()) { - // Delete the linked module & restore the original - delete BD.swapProgramIn(OldProgram.take()); + // Delete the linked module + delete M1; + return NULL; } - return Broken; + return M1; } /// TestFuncs - split functions in a Module into two groups: those that are /// under consideration for miscompilation vs. those that are not, and test /// accordingly. Each group of functions becomes a separate Module. /// -int ReduceMiscompilingFunctions::TestFuncs(const std::vector<Function*> &Funcs, - std::string &Error) { +bool ReduceMiscompilingFunctions::TestFuncs(const std::vector<Function*> &Funcs, + std::string &Error) { // Test to see if the function is misoptimized if we ONLY run it on the // functions listed in Funcs. outs() << "Checking to see if the program is misoptimized when " @@ -250,14 +254,35 @@ int ReduceMiscompilingFunctions::TestFuncs(const std::vector<Function*> &Funcs, PrintFunctionList(Funcs); outs() << '\n'; - // Split the module into the two halves of the program we want. + // Create a clone for two reasons: + // * If the optimization passes delete any function, the deleted function + // will be in the clone and Funcs will still point to valid memory + // * If the optimization passes use interprocedural information to break + // a function, we want to continue with the original function. Otherwise + // we can conclude that a function triggers the bug when in fact one + // needs a larger set of original functions to do so. ValueMap<const Value*, Value*> VMap; + Module *Clone = CloneModule(BD.getProgram(), VMap); + Module *Orig = BD.swapProgramIn(Clone); + + std::vector<Function*> FuncsOnClone; + for (unsigned i = 0, e = Funcs.size(); i != e; ++i) { + Function *F = cast<Function>(VMap[Funcs[i]]); + FuncsOnClone.push_back(F); + } + + // Split the module into the two halves of the program we want. + VMap.clear(); Module *ToNotOptimize = CloneModule(BD.getProgram(), VMap); - Module *ToOptimize = SplitFunctionsOutOfModule(ToNotOptimize, Funcs, + Module *ToOptimize = SplitFunctionsOutOfModule(ToNotOptimize, FuncsOnClone, VMap); // Run the predicate, note that the predicate will delete both input modules. - return TestFn(BD, ToOptimize, ToNotOptimize, Error); + bool Broken = TestFn(BD, ToOptimize, ToNotOptimize, Error); + + delete BD.swapProgramIn(Orig); + + return Broken; } /// DisambiguateGlobalSymbols - Give anonymous global values names. @@ -307,10 +332,13 @@ static bool ExtractLoops(BugDriver &BD, // has broken. If something broke, then we'll inform the user and stop // extraction. AbstractInterpreter *AI = BD.switchToSafeInterpreter(); - bool Failure = TestMergedProgram(BD, ToOptimizeLoopExtracted, ToNotOptimize, - false, Error); - if (!Error.empty()) + bool Failure; + Module *New = TestMergedProgram(BD, ToOptimizeLoopExtracted, ToNotOptimize, + false, Error, Failure); + if (!New) return false; + // Delete the original and set the new program. + delete BD.swapProgramIn(New); if (Failure) { BD.switchToInterpreter(AI); @@ -449,18 +477,36 @@ bool ReduceMiscompiledBlocks::TestFuncs(const std::vector<BasicBlock*> &BBs, // Split the module into the two halves of the program we want. ValueMap<const Value*, Value*> VMap; + Module *Clone = CloneModule(BD.getProgram(), VMap); + Module *Orig = BD.swapProgramIn(Clone); + std::vector<Function*> FuncsOnClone; + std::vector<BasicBlock*> BBsOnClone; + for (unsigned i = 0, e = FunctionsBeingTested.size(); i != e; ++i) { + Function *F = cast<Function>(VMap[FunctionsBeingTested[i]]); + FuncsOnClone.push_back(F); + } + for (unsigned i = 0, e = BBs.size(); i != e; ++i) { + BasicBlock *BB = cast<BasicBlock>(VMap[BBs[i]]); + BBsOnClone.push_back(BB); + } + VMap.clear(); + Module *ToNotOptimize = CloneModule(BD.getProgram(), VMap); Module *ToOptimize = SplitFunctionsOutOfModule(ToNotOptimize, - FunctionsBeingTested, + FuncsOnClone, VMap); // Try the extraction. If it doesn't work, then the block extractor crashed // or something, in which case bugpoint can't chase down this possibility. - if (Module *New = BD.ExtractMappedBlocksFromModule(BBs, ToOptimize)) { + if (Module *New = BD.ExtractMappedBlocksFromModule(BBsOnClone, ToOptimize)) { delete ToOptimize; - // Run the predicate, not that the predicate will delete both input modules. - return TestFn(BD, New, ToNotOptimize, Error); + // Run the predicate, + // note that the predicate will delete both input modules. + bool Ret = TestFn(BD, New, ToNotOptimize, Error); + delete BD.swapProgramIn(Orig); + return Ret; } + delete BD.swapProgramIn(Orig); delete ToOptimize; delete ToNotOptimize; return false; @@ -655,8 +701,13 @@ static bool TestOptimizer(BugDriver &BD, Module *Test, Module *Safe, delete Test; outs() << " Checking to see if the merged program executes correctly: "; - bool Broken = TestMergedProgram(BD, Optimized, Safe, true, Error); - if (Error.empty()) outs() << (Broken ? " nope.\n" : " yup.\n"); + bool Broken; + Module *New = TestMergedProgram(BD, Optimized, Safe, true, Error, Broken); + if (New) { + outs() << (Broken ? " nope.\n" : " yup.\n"); + // Delete the original and set the new program. + delete BD.swapProgramIn(New); + } return Broken; } @@ -678,7 +729,7 @@ void BugDriver::debugMiscompilation(std::string *Error) { outs() << "\n*** Found miscompiling pass" << (getPassesToRun().size() == 1 ? "" : "es") << ": " << getPassesString(getPassesToRun()) << '\n'; - EmitProgressBitcode("passinput"); + EmitProgressBitcode(Program, "passinput"); std::vector<Function *> MiscompiledFunctions = DebugAMiscompilation(*this, TestOptimizer, *Error); @@ -694,14 +745,12 @@ void BugDriver::debugMiscompilation(std::string *Error) { VMap); outs() << " Non-optimized portion: "; - ToNotOptimize = swapProgramIn(ToNotOptimize); - EmitProgressBitcode("tonotoptimize", true); - setNewProgram(ToNotOptimize); // Delete hacked module. + EmitProgressBitcode(ToNotOptimize, "tonotoptimize", true); + delete ToNotOptimize; // Delete hacked module. outs() << " Portion that is input to optimizer: "; - ToOptimize = swapProgramIn(ToOptimize); - EmitProgressBitcode("tooptimize"); - setNewProgram(ToOptimize); // Delete hacked module. + EmitProgressBitcode(ToOptimize, "tooptimize"); + delete ToOptimize; // Delete hacked module. return; } @@ -921,7 +970,8 @@ static bool TestCodeGenerator(BugDriver &BD, Module *Test, Module *Safe, // Run the code generator on the `Test' code, loading the shared library. // The function returns whether or not the new output differs from reference. - bool Result = BD.diffProgram(TestModuleBC.str(), SharedObject, false, &Error); + bool Result = BD.diffProgram(BD.getProgram(), TestModuleBC.str(), + SharedObject, false, &Error); if (!Error.empty()) return false; @@ -938,7 +988,8 @@ static bool TestCodeGenerator(BugDriver &BD, Module *Test, Module *Safe, /// bool BugDriver::debugCodeGenerator(std::string *Error) { if ((void*)SafeInterpreter == (void*)Interpreter) { - std::string Result = executeProgramSafely("bugpoint.safe.out", Error); + std::string Result = executeProgramSafely(Program, "bugpoint.safe.out", + Error); if (Error->empty()) { outs() << "\n*** The \"safe\" i.e. 'known good' backend cannot match " << "the reference diff. This may be due to a\n front-end " diff --git a/contrib/llvm/tools/bugpoint/OptimizerDriver.cpp b/contrib/llvm/tools/bugpoint/OptimizerDriver.cpp index 3a6149b..3600ca6 100644 --- a/contrib/llvm/tools/bugpoint/OptimizerDriver.cpp +++ b/contrib/llvm/tools/bugpoint/OptimizerDriver.cpp @@ -27,6 +27,8 @@ #include "llvm/Target/TargetData.h" #include "llvm/Support/FileUtilities.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/SystemUtils.h" +#include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" #include "llvm/System/Path.h" #include "llvm/System/Program.h" @@ -51,26 +53,34 @@ namespace { /// file. If an error occurs, true is returned. /// bool BugDriver::writeProgramToFile(const std::string &Filename, - Module *M) const { + const Module *M) const { std::string ErrInfo; - raw_fd_ostream Out(Filename.c_str(), ErrInfo, - raw_fd_ostream::F_Binary); - if (!ErrInfo.empty()) return true; - - WriteBitcodeToFile(M ? M : Program, Out); - return false; + tool_output_file Out(Filename.c_str(), ErrInfo, + raw_fd_ostream::F_Binary); + if (ErrInfo.empty()) { + WriteBitcodeToFile(M, Out.os()); + Out.os().close(); + if (!Out.os().has_error()) { + Out.keep(); + return false; + } + } + Out.os().clear_error(); + return true; } /// EmitProgressBitcode - This function is used to output the current Program /// to a file named "bugpoint-ID.bc". /// -void BugDriver::EmitProgressBitcode(const std::string &ID, bool NoFlyer) { +void BugDriver::EmitProgressBitcode(const Module *M, + const std::string &ID, + bool NoFlyer) const { // 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 // std::string Filename = OutputPrefix + "-" + ID + ".bc"; - if (writeProgramToFile(Filename)) { + if (writeProgramToFile(Filename, M)) { errs() << "Error opening file '" << Filename << "' for writing!\n"; return; } @@ -83,39 +93,12 @@ void BugDriver::EmitProgressBitcode(const std::string &ID, bool NoFlyer) { outs() << getPassesString(PassesToRun) << "\n"; } -int BugDriver::runPassesAsChild(const std::vector<const PassInfo*> &Passes) { - std::string ErrInfo; - raw_fd_ostream OutFile(ChildOutput.c_str(), ErrInfo, - raw_fd_ostream::F_Binary); - if (!ErrInfo.empty()) { - errs() << "Error opening bitcode file: " << ChildOutput << "\n"; - return 1; - } - - PassManager PM; - // Make sure that the appropriate target data is always used... - PM.add(new TargetData(Program)); - - for (unsigned i = 0, e = Passes.size(); i != e; ++i) { - if (Passes[i]->getNormalCtor()) - PM.add(Passes[i]->getNormalCtor()()); - else - errs() << "Cannot create pass yet: " << Passes[i]->getPassName() << "\n"; - } - // Check that the module is well formed on completion of optimization - PM.add(createVerifierPass()); - - // Write bitcode out to disk as the last step... - PM.add(createBitcodeWriterPass(OutFile)); - - // Run all queued passes. - PM.run(*Program); - - return 0; -} - cl::opt<bool> SilencePasses("silence-passes", cl::desc("Suppress output of running passes (both stdout and stderr)")); +static cl::list<std::string> OptArgs("opt-args", cl::Positional, + cl::desc("<opt arguments>..."), + cl::ZeroOrMore, cl::PositionalEatsArgs); + /// runPasses - Run the specified passes on Program, outputting a bitcode file /// and writing the filename into OutputFile if successful. If the /// optimizations fail for some reason (optimizer crashes), return true, @@ -124,7 +107,8 @@ cl::opt<bool> SilencePasses("silence-passes", cl::desc("Suppress output of runni /// outs() a single line message indicating whether compilation was successful /// or failed. /// -bool BugDriver::runPasses(const std::vector<const PassInfo*> &Passes, +bool BugDriver::runPasses(Module *Program, + const std::vector<std::string> &Passes, std::string &OutputFilename, bool DeleteOutput, bool Quiet, unsigned NumExtraArgs, const char * const *ExtraArgs) const { @@ -148,39 +132,47 @@ bool BugDriver::runPasses(const std::vector<const PassInfo*> &Passes, } std::string ErrInfo; - raw_fd_ostream InFile(inputFilename.c_str(), ErrInfo, - raw_fd_ostream::F_Binary); + tool_output_file InFile(inputFilename.c_str(), ErrInfo, + raw_fd_ostream::F_Binary); if (!ErrInfo.empty()) { errs() << "Error opening bitcode file: " << inputFilename.str() << "\n"; return 1; } - WriteBitcodeToFile(Program, InFile); - InFile.close(); + WriteBitcodeToFile(Program, InFile.os()); + InFile.os().close(); + if (InFile.os().has_error()) { + errs() << "Error writing bitcode file: " << inputFilename.str() << "\n"; + InFile.os().clear_error(); + return 1; + } + InFile.keep(); // setup the child process' arguments SmallVector<const char*, 8> Args; - sys::Path tool = sys::Program::FindProgramByName(ToolName); + sys::Path tool = FindExecutable("opt", getToolName(), (void*)"opt"); + std::string Opt = tool.str(); if (UseValgrind) { Args.push_back("valgrind"); Args.push_back("--error-exitcode=1"); Args.push_back("-q"); Args.push_back(tool.c_str()); } else - Args.push_back(ToolName); + Args.push_back(Opt.c_str()); - Args.push_back("-as-child"); - Args.push_back("-child-output"); + Args.push_back("-o"); Args.push_back(OutputFilename.c_str()); + for (unsigned i = 0, e = OptArgs.size(); i != e; ++i) + Args.push_back(OptArgs[i].c_str()); std::vector<std::string> pass_args; for (unsigned i = 0, e = PluginLoader::getNumPlugins(); i != e; ++i) { pass_args.push_back( std::string("-load")); pass_args.push_back( PluginLoader::getPlugin(i)); } - for (std::vector<const PassInfo*>::const_iterator I = Passes.begin(), + for (std::vector<std::string>::const_iterator I = Passes.begin(), E = Passes.end(); I != E; ++I ) - pass_args.push_back( std::string("-") + (*I)->getPassArgument() ); + pass_args.push_back( std::string("-") + (*I) ); for (std::vector<std::string>::const_iterator I = pass_args.begin(), E = pass_args.end(); I != E; ++I ) Args.push_back(I->c_str()); @@ -189,6 +181,12 @@ bool BugDriver::runPasses(const std::vector<const PassInfo*> &Passes, Args.push_back(*ExtraArgs); Args.push_back(0); + DEBUG(errs() << "\nAbout to run:\t"; + for (unsigned i = 0, e = Args.size()-1; i != e; ++i) + errs() << " " << Args[i]; + errs() << "\n"; + ); + sys::Path prog; if (UseValgrind) prog = sys::Program::FindProgramByName("valgrind"); @@ -235,27 +233,22 @@ bool BugDriver::runPasses(const std::vector<const PassInfo*> &Passes, /// module, returning the transformed module on success, or a null pointer on /// failure. Module *BugDriver::runPassesOn(Module *M, - const std::vector<const PassInfo*> &Passes, + const std::vector<std::string> &Passes, bool AutoDebugCrashes, unsigned NumExtraArgs, const char * const *ExtraArgs) { - Module *OldProgram = swapProgramIn(M); std::string BitcodeResult; - if (runPasses(Passes, BitcodeResult, false/*delete*/, true/*quiet*/, + if (runPasses(M, Passes, BitcodeResult, false/*delete*/, true/*quiet*/, NumExtraArgs, ExtraArgs)) { if (AutoDebugCrashes) { errs() << " Error running this sequence of passes" << " on the input program!\n"; - delete OldProgram; - EmitProgressBitcode("pass-error", false); + delete swapProgramIn(M); + EmitProgressBitcode(M, "pass-error", false); exit(debugOptimizerCrash()); } - swapProgramIn(OldProgram); return 0; } - // Restore the current program. - swapProgramIn(OldProgram); - Module *Ret = ParseInputFile(BitcodeResult, Context); if (Ret == 0) { errs() << getToolName() << ": Error reading bitcode file '" diff --git a/contrib/llvm/tools/bugpoint/TestPasses.cpp b/contrib/llvm/tools/bugpoint/TestPasses.cpp deleted file mode 100644 index 900bf63..0000000 --- a/contrib/llvm/tools/bugpoint/TestPasses.cpp +++ /dev/null @@ -1,75 +0,0 @@ -//===- TestPasses.cpp - "buggy" passes used to test bugpoint --------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file contains "buggy" passes that are used to test bugpoint, to check -// that it is narrowing down testcases correctly. -// -//===----------------------------------------------------------------------===// - -#include "llvm/BasicBlock.h" -#include "llvm/Constant.h" -#include "llvm/Instructions.h" -#include "llvm/Pass.h" -#include "llvm/Type.h" -#include "llvm/Support/InstVisitor.h" - -using namespace llvm; - -namespace { - /// CrashOnCalls - This pass is used to test bugpoint. It intentionally - /// crashes on any call instructions. - class CrashOnCalls : public BasicBlockPass { - public: - static char ID; // Pass ID, replacement for typeid - CrashOnCalls() : BasicBlockPass(&ID) {} - private: - virtual void getAnalysisUsage(AnalysisUsage &AU) const { - AU.setPreservesAll(); - } - - bool runOnBasicBlock(BasicBlock &BB) { - for (BasicBlock::iterator I = BB.begin(), E = BB.end(); I != E; ++I) - if (isa<CallInst>(*I)) - abort(); - - return false; - } - }; - - char CrashOnCalls::ID = 0; - RegisterPass<CrashOnCalls> - X("bugpoint-crashcalls", - "BugPoint Test Pass - Intentionally crash on CallInsts"); -} - -namespace { - /// DeleteCalls - This pass is used to test bugpoint. It intentionally - /// deletes some call instructions, "misoptimizing" the program. - class DeleteCalls : public BasicBlockPass { - public: - static char ID; // Pass ID, replacement for typeid - DeleteCalls() : BasicBlockPass(&ID) {} - private: - bool runOnBasicBlock(BasicBlock &BB) { - for (BasicBlock::iterator I = BB.begin(), E = BB.end(); I != E; ++I) - if (CallInst *CI = dyn_cast<CallInst>(I)) { - if (!CI->use_empty()) - CI->replaceAllUsesWith(Constant::getNullValue(CI->getType())); - CI->getParent()->getInstList().erase(CI); - break; - } - return false; - } - }; - - char DeleteCalls::ID = 0; - RegisterPass<DeleteCalls> - Y("bugpoint-deletecalls", - "BugPoint Test Pass - Intentionally 'misoptimize' CallInsts"); -} diff --git a/contrib/llvm/tools/bugpoint/ToolRunner.cpp b/contrib/llvm/tools/bugpoint/ToolRunner.cpp index 3149a7a..36dbe14 100644 --- a/contrib/llvm/tools/bugpoint/ToolRunner.cpp +++ b/contrib/llvm/tools/bugpoint/ToolRunner.cpp @@ -627,8 +627,8 @@ CBE *AbstractInterpreter::createCBE(const char *Argv0, // GCC abstraction // -static bool IsARMArchitecture(std::vector<std::string> Args) { - for (std::vector<std::string>::const_iterator +static bool IsARMArchitecture(std::vector<const char*> Args) { + for (std::vector<const char*>::const_iterator I = Args.begin(), E = Args.end(); I != E; ++I) { if (StringRef(*I).equals_lower("-arch")) { ++I; @@ -673,7 +673,7 @@ int GCC::ExecuteProgram(const std::string &ProgramFile, // explicitly told what architecture it is working on, so we get // it from gcc flags if ((TargetTriple.getOS() == Triple::Darwin) && - !IsARMArchitecture(ArgsForGCC)) + !IsARMArchitecture(GCCArgs)) GCCArgs.push_back("-force_cpusubtype_ALL"); } } @@ -721,6 +721,10 @@ int GCC::ExecuteProgram(const std::string &ProgramFile, std::vector<const char*> ProgramArgs; + // Declared here so that the destructor only runs after + // ProgramArgs is used. + std::string Exec; + if (RemoteClientPath.isEmpty()) ProgramArgs.push_back(OutputBinary.c_str()); else { @@ -741,7 +745,7 @@ int GCC::ExecuteProgram(const std::string &ProgramFile, // 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 char* env_pwd = getenv("PWD"); - std::string Exec = "cd "; + Exec = "cd "; Exec += env_pwd; Exec += "; ./"; Exec += OutputBinary.c_str(); diff --git a/contrib/llvm/tools/bugpoint/bugpoint.cpp b/contrib/llvm/tools/bugpoint/bugpoint.cpp index ba5234b..79cf563 100644 --- a/contrib/llvm/tools/bugpoint/bugpoint.cpp +++ b/contrib/llvm/tools/bugpoint/bugpoint.cpp @@ -29,13 +29,6 @@ #include "llvm/LinkAllVMCore.h" using namespace llvm; -// AsChild - Specifies that this invocation of bugpoint is being generated -// from a parent process. It is not intended to be used by users so the -// option is hidden. -static cl::opt<bool> -AsChild("as-child", cl::desc("Run bugpoint as child process"), - cl::ReallyHidden); - static cl::opt<bool> FindBugs("find-bugs", cl::desc("Run many different optimization sequences " "on program to find bugs"), cl::init(false)); @@ -90,8 +83,9 @@ namespace { AddToDriver(BugDriver &_D) : D(_D) {} virtual void add(Pass *P) { - const PassInfo *PI = P->getPassInfo(); - D.addPasses(&PI, &PI + 1); + const void *ID = P->getPassID(); + const PassInfo *PI = PassRegistry::getPassRegistry()->getPassInfo(ID); + D.addPass(PI->getPassArgument()); } }; } @@ -110,8 +104,8 @@ int main(int argc, char **argv) { // If we have an override, set it and then track the triple we want Modules // to use. if (!OverrideTriple.empty()) { - TargetTriple.setTriple(OverrideTriple); - outs() << "Override triple set to '" << OverrideTriple << "'\n"; + TargetTriple.setTriple(Triple::normalize(OverrideTriple)); + outs() << "Override triple set to '" << TargetTriple.getTriple() << "'\n"; } if (MemoryLimit < 0) { @@ -123,7 +117,7 @@ int main(int argc, char **argv) { MemoryLimit = 100; } - BugDriver D(argv[0], AsChild, FindBugs, TimeoutValue, MemoryLimit, + BugDriver D(argv[0], FindBugs, TimeoutValue, MemoryLimit, UseValgrind, Context); if (D.addSources(InputFilenames)) return 1; @@ -143,7 +137,13 @@ int main(int argc, char **argv) { /*RunInliner=*/true, /*VerifyEach=*/false); - D.addPasses(PassList.begin(), PassList.end()); + + for (std::vector<const PassInfo*>::iterator I = PassList.begin(), + E = PassList.end(); + I != E; ++I) { + const PassInfo* PI = *I; + D.addPass(PI->getPassArgument()); + } // Bugpoint has the ability of generating a plethora of core files, so to // avoid filling up the disk, we prevent it |