diff options
author | Nick Lewycky <nicholas@mxc.ca> | 2010-04-12 05:08:25 +0000 |
---|---|---|
committer | Nick Lewycky <nicholas@mxc.ca> | 2010-04-12 05:08:25 +0000 |
commit | 22ff748712b348300e51248339b6e8cf9b59e2c6 (patch) | |
tree | ab07a4e3d46ed34d8f3510ed11ea772016bca4bd /tools/bugpoint/Miscompilation.cpp | |
parent | 67a71b5306c42f1d56a0d58635432b86206c2a9a (diff) | |
download | external_llvm-22ff748712b348300e51248339b6e8cf9b59e2c6.zip external_llvm-22ff748712b348300e51248339b6e8cf9b59e2c6.tar.gz external_llvm-22ff748712b348300e51248339b6e8cf9b59e2c6.tar.bz2 |
Remove use of exceptions from bugpoint. No deliberate functionality change!
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@101013 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'tools/bugpoint/Miscompilation.cpp')
-rw-r--r-- | tools/bugpoint/Miscompilation.cpp | 287 |
1 files changed, 189 insertions, 98 deletions
diff --git a/tools/bugpoint/Miscompilation.cpp b/tools/bugpoint/Miscompilation.cpp index c2b002f..96aab95 100644 --- a/tools/bugpoint/Miscompilation.cpp +++ b/tools/bugpoint/Miscompilation.cpp @@ -49,7 +49,8 @@ namespace { ReduceMiscompilingPasses(BugDriver &bd) : BD(bd) {} virtual TestResult doTest(std::vector<const PassInfo*> &Prefix, - std::vector<const PassInfo*> &Suffix); + std::vector<const PassInfo*> &Suffix, + std::string &Error); }; } @@ -58,7 +59,8 @@ namespace { /// ReduceMiscompilingPasses::TestResult ReduceMiscompilingPasses::doTest(std::vector<const PassInfo*> &Prefix, - std::vector<const PassInfo*> &Suffix) { + std::vector<const PassInfo*> &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. outs() << "Checking to see if '" << getPassesString(Suffix) @@ -74,7 +76,11 @@ ReduceMiscompilingPasses::doTest(std::vector<const PassInfo*> &Prefix, } // Check to see if the finished program matches the reference output... - if (BD.diffProgram(BitcodeResult, "", true /*delete bitcode*/)) { + bool Diff = BD.diffProgram(BitcodeResult, "", true /*delete bitcode*/, + &Error); + if (!Error.empty()) + return InternalError; + if (Diff) { outs() << " nope.\n"; if (Suffix.empty()) { errs() << BD.getToolName() << ": I'm confused: the test fails when " @@ -107,7 +113,10 @@ ReduceMiscompilingPasses::doTest(std::vector<const PassInfo*> &Prefix, } // If the prefix maintains the predicate by itself, only keep the prefix! - if (BD.diffProgram(BitcodeResult)) { + Diff = BD.diffProgram(BitcodeResult, "", false, &Error); + if (!Error.empty()) + return InternalError; + if (Diff) { outs() << " nope.\n"; sys::Path(BitcodeResult).eraseFromDisk(); return KeepPrefix; @@ -143,7 +152,10 @@ ReduceMiscompilingPasses::doTest(std::vector<const PassInfo*> &Prefix, } // Run the result... - if (BD.diffProgram(BitcodeResult, "", true/*delete bitcode*/)) { + Diff = BD.diffProgram(BitcodeResult, "", true /*delete bitcode*/, &Error); + if (!Error.empty()) + return InternalError; + if (Diff) { outs() << " nope.\n"; delete OriginalInput; // We pruned down the original input... return KeepSuffix; @@ -158,22 +170,34 @@ ReduceMiscompilingPasses::doTest(std::vector<const PassInfo*> &Prefix, namespace { class ReduceMiscompilingFunctions : public ListReducer<Function*> { BugDriver &BD; - bool (*TestFn)(BugDriver &, Module *, Module *); + bool (*TestFn)(BugDriver &, Module *, Module *, std::string &); public: ReduceMiscompilingFunctions(BugDriver &bd, - bool (*F)(BugDriver &, Module *, Module *)) + bool (*F)(BugDriver &, Module *, Module *, + std::string &)) : BD(bd), TestFn(F) {} virtual TestResult doTest(std::vector<Function*> &Prefix, - std::vector<Function*> &Suffix) { - if (!Suffix.empty() && TestFuncs(Suffix)) - return KeepSuffix; - if (!Prefix.empty() && TestFuncs(Prefix)) - return KeepPrefix; + std::vector<Function*> &Suffix, + std::string &Error) { + if (!Suffix.empty()) { + bool Ret = TestFuncs(Suffix, Error); + if (!Error.empty()) + return InternalError; + if (Ret) + return KeepSuffix; + } + 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); + int TestFuncs(const std::vector<Function*> &Prefix, std::string &Error); }; } @@ -184,7 +208,7 @@ namespace { /// returns. /// static bool TestMergedProgram(BugDriver &BD, Module *M1, Module *M2, - bool DeleteInputs) { + bool DeleteInputs, std::string &Error) { // Link the two portions of the program back to together. std::string ErrorMsg; if (!DeleteInputs) { @@ -202,11 +226,12 @@ static bool TestMergedProgram(BugDriver &BD, Module *M1, Module *M2, // Execute the program. If it does not match the expected output, we must // return true. - bool Broken = BD.diffProgram(); - - // Delete the linked module & restore the original - BD.swapProgramIn(OldProgram); - delete M1; + bool Broken = BD.diffProgram("", "", false, &Error); + if (!Error.empty()) { + // Delete the linked module & restore the original + BD.swapProgramIn(OldProgram); + delete M1; + } return Broken; } @@ -214,7 +239,8 @@ static bool TestMergedProgram(BugDriver &BD, Module *M1, Module *M2, /// under consideration for miscompilation vs. those that are not, and test /// accordingly. Each group of functions becomes a separate Module. /// -bool ReduceMiscompilingFunctions::TestFuncs(const std::vector<Function*>&Funcs){ +int 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 " @@ -231,7 +257,7 @@ bool ReduceMiscompilingFunctions::TestFuncs(const std::vector<Function*>&Funcs){ ValueMap); // Run the predicate, note that the predicate will delete both input modules. - return TestFn(BD, ToOptimize, ToNotOptimize); + return TestFn(BD, ToOptimize, ToNotOptimize, Error); } /// DisambiguateGlobalSymbols - Give anonymous global values names. @@ -251,8 +277,10 @@ static void DisambiguateGlobalSymbols(Module *M) { /// bug. If so, it reduces the amount of code identified. /// static bool ExtractLoops(BugDriver &BD, - bool (*TestFn)(BugDriver &, Module *, Module *), - std::vector<Function*> &MiscompiledFunctions) { + bool (*TestFn)(BugDriver &, Module *, Module *, + std::string &), + std::vector<Function*> &MiscompiledFunctions, + std::string &Error) { bool MadeChange = false; while (1) { if (BugpointIsInterrupted) return MadeChange; @@ -279,7 +307,11 @@ static bool ExtractLoops(BugDriver &BD, // has broken. If something broke, then we'll inform the user and stop // extraction. AbstractInterpreter *AI = BD.switchToSafeInterpreter(); - if (TestMergedProgram(BD, ToOptimizeLoopExtracted, ToNotOptimize, false)) { + bool Failure = TestMergedProgram(BD, ToOptimizeLoopExtracted, ToNotOptimize, + false, Error); + if (!Error.empty()) + return false; + if (Failure) { BD.switchToInterpreter(AI); // Merged program doesn't work anymore! @@ -308,7 +340,10 @@ static bool ExtractLoops(BugDriver &BD, // Clone modules, the tester function will free them. Module *TOLEBackup = CloneModule(ToOptimizeLoopExtracted); Module *TNOBackup = CloneModule(ToNotOptimize); - if (!TestFn(BD, ToOptimizeLoopExtracted, ToNotOptimize)) { + Failure = TestFn(BD, ToOptimizeLoopExtracted, ToNotOptimize, Error); + if (!Error.empty()) + return false; + if (!Failure) { outs() << "*** Loop extraction masked the problem. Undoing.\n"; // If the program is not still broken, then loop extraction did something // that masked the error. Stop loop extraction now. @@ -361,31 +396,44 @@ static bool ExtractLoops(BugDriver &BD, namespace { class ReduceMiscompiledBlocks : public ListReducer<BasicBlock*> { BugDriver &BD; - bool (*TestFn)(BugDriver &, Module *, Module *); + bool (*TestFn)(BugDriver &, Module *, Module *, std::string &); std::vector<Function*> FunctionsBeingTested; public: ReduceMiscompiledBlocks(BugDriver &bd, - bool (*F)(BugDriver &, Module *, Module *), + bool (*F)(BugDriver &, Module *, Module *, + std::string &), const std::vector<Function*> &Fns) : BD(bd), TestFn(F), FunctionsBeingTested(Fns) {} virtual TestResult doTest(std::vector<BasicBlock*> &Prefix, - std::vector<BasicBlock*> &Suffix) { - if (!Suffix.empty() && TestFuncs(Suffix)) - return KeepSuffix; - if (TestFuncs(Prefix)) - return KeepPrefix; + std::vector<BasicBlock*> &Suffix, + std::string &Error) { + if (!Suffix.empty()) { + bool Ret = TestFuncs(Suffix, Error); + if (!Error.empty()) + return InternalError; + if (Ret) + return KeepSuffix; + } + 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*> &Prefix); + bool TestFuncs(const std::vector<BasicBlock*> &BBs, std::string &Error); }; } /// TestFuncs - Extract all blocks for the miscompiled functions except for the /// 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) { // 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 all "; @@ -411,7 +459,7 @@ bool ReduceMiscompiledBlocks::TestFuncs(const std::vector<BasicBlock*> &BBs) { if (Module *New = BD.ExtractMappedBlocksFromModule(BBs, ToOptimize)) { delete ToOptimize; // Run the predicate, not that the predicate will delete both input modules. - return TestFn(BD, New, ToNotOptimize); + return TestFn(BD, New, ToNotOptimize, Error); } delete ToOptimize; delete ToNotOptimize; @@ -424,8 +472,10 @@ bool ReduceMiscompiledBlocks::TestFuncs(const std::vector<BasicBlock*> &BBs) { /// the bug. /// static bool ExtractBlocks(BugDriver &BD, - bool (*TestFn)(BugDriver &, Module *, Module *), - std::vector<Function*> &MiscompiledFunctions) { + bool (*TestFn)(BugDriver &, Module *, Module *, + std::string &), + std::vector<Function*> &MiscompiledFunctions, + std::string &Error) { if (BugpointIsInterrupted) return false; std::vector<BasicBlock*> Blocks; @@ -440,11 +490,17 @@ static bool ExtractBlocks(BugDriver &BD, unsigned OldSize = Blocks.size(); // Check to see if all blocks are extractible first. - if (ReduceMiscompiledBlocks(BD, TestFn, - MiscompiledFunctions).TestFuncs(std::vector<BasicBlock*>())) { + bool Ret = ReduceMiscompiledBlocks(BD, TestFn, MiscompiledFunctions) + .TestFuncs(std::vector<BasicBlock*>(), Error); + if (!Error.empty()) + return false; + if (Ret) { Blocks.clear(); } else { - ReduceMiscompiledBlocks(BD, TestFn,MiscompiledFunctions).reduceList(Blocks); + ReduceMiscompiledBlocks(BD, TestFn, + MiscompiledFunctions).reduceList(Blocks, Error); + if (!Error.empty()) + return false; if (Blocks.size() == OldSize) return false; } @@ -505,7 +561,9 @@ static bool ExtractBlocks(BugDriver &BD, /// static std::vector<Function*> DebugAMiscompilation(BugDriver &BD, - bool (*TestFn)(BugDriver &, Module *, Module *)) { + bool (*TestFn)(BugDriver &, Module *, Module *, + std::string &), + std::string &Error) { // Okay, now that we have reduced the list of passes which are causing the // failure, see if we can pin down which functions are being // miscompiled... first build a list of all of the non-external functions in @@ -518,7 +576,10 @@ DebugAMiscompilation(BugDriver &BD, // Do the reduction... if (!BugpointIsInterrupted) - ReduceMiscompilingFunctions(BD, TestFn).reduceList(MiscompiledFunctions); + ReduceMiscompilingFunctions(BD, TestFn).reduceList(MiscompiledFunctions, + Error); + if (!Error.empty()) + return MiscompiledFunctions; outs() << "\n*** The following function" << (MiscompiledFunctions.size() == 1 ? " is" : "s are") @@ -529,37 +590,51 @@ DebugAMiscompilation(BugDriver &BD, // See if we can rip any loops out of the miscompiled functions and still // trigger the problem. - if (!BugpointIsInterrupted && !DisableLoopExtraction && - ExtractLoops(BD, TestFn, MiscompiledFunctions)) { - // Okay, we extracted some loops and the problem still appears. See if we - // can eliminate some of the created functions from being candidates. - DisambiguateGlobalSymbols(BD.getProgram()); - - // Do the reduction... - if (!BugpointIsInterrupted) - ReduceMiscompilingFunctions(BD, TestFn).reduceList(MiscompiledFunctions); - - outs() << "\n*** The following function" - << (MiscompiledFunctions.size() == 1 ? " is" : "s are") - << " being miscompiled: "; - PrintFunctionList(MiscompiledFunctions); - outs() << '\n'; + if (!BugpointIsInterrupted && !DisableLoopExtraction) { + bool Ret = ExtractLoops(BD, TestFn, MiscompiledFunctions, Error); + if (!Error.empty()) + return MiscompiledFunctions; + if (Ret) { + // Okay, we extracted some loops and the problem still appears. See if + // we can eliminate some of the created functions from being candidates. + DisambiguateGlobalSymbols(BD.getProgram()); + + // Do the reduction... + if (!BugpointIsInterrupted) + ReduceMiscompilingFunctions(BD, TestFn).reduceList(MiscompiledFunctions, + Error); + if (!Error.empty()) + return MiscompiledFunctions; + + outs() << "\n*** The following function" + << (MiscompiledFunctions.size() == 1 ? " is" : "s are") + << " being miscompiled: "; + PrintFunctionList(MiscompiledFunctions); + outs() << '\n'; + } } - if (!BugpointIsInterrupted && !DisableBlockExtraction && - ExtractBlocks(BD, TestFn, MiscompiledFunctions)) { - // Okay, we extracted some blocks and the problem still appears. See if we - // can eliminate some of the created functions from being candidates. - DisambiguateGlobalSymbols(BD.getProgram()); - - // Do the reduction... - ReduceMiscompilingFunctions(BD, TestFn).reduceList(MiscompiledFunctions); - - outs() << "\n*** The following function" - << (MiscompiledFunctions.size() == 1 ? " is" : "s are") - << " being miscompiled: "; - PrintFunctionList(MiscompiledFunctions); - outs() << '\n'; + if (!BugpointIsInterrupted && !DisableBlockExtraction) { + bool Ret = ExtractBlocks(BD, TestFn, MiscompiledFunctions, Error); + if (!Error.empty()) + return MiscompiledFunctions; + if (Ret) { + // Okay, we extracted some blocks and the problem still appears. See if + // we can eliminate some of the created functions from being candidates. + DisambiguateGlobalSymbols(BD.getProgram()); + + // Do the reduction... + ReduceMiscompilingFunctions(BD, TestFn).reduceList(MiscompiledFunctions, + Error); + if (!Error.empty()) + return MiscompiledFunctions; + + outs() << "\n*** The following function" + << (MiscompiledFunctions.size() == 1 ? " is" : "s are") + << " being miscompiled: "; + PrintFunctionList(MiscompiledFunctions); + outs() << '\n'; + } } return MiscompiledFunctions; @@ -569,7 +644,8 @@ DebugAMiscompilation(BugDriver &BD, /// "Test" portion of the program is misoptimized. If so, return true. In any /// case, both module arguments are deleted. /// -static bool TestOptimizer(BugDriver &BD, Module *Test, Module *Safe) { +static bool TestOptimizer(BugDriver &BD, Module *Test, Module *Safe, + std::string &Error) { // Run the optimization passes on ToOptimize, producing a transformed version // of the functions being tested. outs() << " Optimizing functions being tested: "; @@ -579,8 +655,8 @@ 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); - outs() << (Broken ? " nope.\n" : " yup.\n"); + bool Broken = TestMergedProgram(BD, Optimized, Safe, true, Error); + if (Error.empty()) outs() << (Broken ? " nope.\n" : " yup.\n"); return Broken; } @@ -589,13 +665,14 @@ static bool TestOptimizer(BugDriver &BD, Module *Test, Module *Safe) { /// crashing, but the generated output is semantically different from the /// input. /// -bool BugDriver::debugMiscompilation() { +void BugDriver::debugMiscompilation(std::string *Error) { // Make sure something was miscompiled... if (!BugpointIsInterrupted) - if (!ReduceMiscompilingPasses(*this).reduceList(PassesToRun)) { - errs() << "*** Optimized program matches reference output! No problem" - << " detected...\nbugpoint can't help you with your problem!\n"; - return false; + if (!ReduceMiscompilingPasses(*this).reduceList(PassesToRun, *Error)) { + if (Error->empty()) + errs() << "*** Optimized program matches reference output! No problem" + << " detected...\nbugpoint can't help you with your problem!\n"; + return; } outs() << "\n*** Found miscompiling pass" @@ -603,8 +680,10 @@ bool BugDriver::debugMiscompilation() { << getPassesString(getPassesToRun()) << '\n'; EmitProgressBitcode("passinput"); - std::vector<Function*> MiscompiledFunctions = - DebugAMiscompilation(*this, TestOptimizer); + std::vector<Function *> MiscompiledFunctions = + DebugAMiscompilation(*this, TestOptimizer, *Error); + if (!Error->empty()) + return; // Output a bunch of bitcode files for the user... outs() << "Outputting reduced bitcode files which expose the problem:\n"; @@ -624,7 +703,7 @@ bool BugDriver::debugMiscompilation() { EmitProgressBitcode("tooptimize"); setNewProgram(ToOptimize); // Delete hacked module. - return false; + return; } /// CleanupAndPrepareModules - Get the specified modules ready for code @@ -797,7 +876,8 @@ static void CleanupAndPrepareModules(BugDriver &BD, Module *&Test, /// the "Test" portion of the program is miscompiled by the code generator under /// test. If so, return true. In any case, both module arguments are deleted. /// -static bool TestCodeGenerator(BugDriver &BD, Module *Test, Module *Safe) { +static bool TestCodeGenerator(BugDriver &BD, Module *Test, Module *Safe, + std::string &Error) { CleanupAndPrepareModules(BD, Test, Safe); sys::Path TestModuleBC("bugpoint.test.bc"); @@ -827,12 +907,16 @@ static bool TestCodeGenerator(BugDriver &BD, Module *Test, Module *Safe) { << "'\nExiting."; exit(1); } - std::string SharedObject = BD.compileSharedObject(SafeModuleBC.str()); + std::string SharedObject = BD.compileSharedObject(SafeModuleBC.str(), Error); + if (!Error.empty()) + return -1; delete 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. - int Result = BD.diffProgram(TestModuleBC.str(), SharedObject, false); + bool Result = BD.diffProgram(TestModuleBC.str(), SharedObject, false, &Error); + if (!Error.empty()) + return false; if (Result) errs() << ": still failing!\n"; @@ -848,23 +932,28 @@ static bool TestCodeGenerator(BugDriver &BD, Module *Test, Module *Safe) { /// debugCodeGenerator - debug errors in LLC, LLI, or CBE. /// -bool BugDriver::debugCodeGenerator() { +bool BugDriver::debugCodeGenerator(std::string *Error) { if ((void*)SafeInterpreter == (void*)Interpreter) { - std::string Result = executeProgramSafely("bugpoint.safe.out"); - outs() << "\n*** The \"safe\" i.e. 'known good' backend cannot match " - << "the reference diff. This may be due to a\n front-end " - << "bug or a bug in the original program, but this can also " - << "happen if bugpoint isn't running the program with the " - << "right flags or input.\n I left the result of executing " - << "the program with the \"safe\" backend in this file for " - << "you: '" - << Result << "'.\n"; + std::string Result = executeProgramSafely("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 " + << "bug or a bug in the original program, but this can also " + << "happen if bugpoint isn't running the program with the " + << "right flags or input.\n I left the result of executing " + << "the program with the \"safe\" backend in this file for " + << "you: '" + << Result << "'.\n"; + } return true; } DisambiguateGlobalSymbols(Program); - std::vector<Function*> Funcs = DebugAMiscompilation(*this, TestCodeGenerator); + std::vector<Function*> Funcs = DebugAMiscompilation(*this, TestCodeGenerator, + *Error); + if (!Error->empty()) + return true; // Split the module into the two halves of the program we want. DenseMap<const Value*, Value*> ValueMap; @@ -902,7 +991,9 @@ bool BugDriver::debugCodeGenerator() { << "'\nExiting."; exit(1); } - std::string SharedObject = compileSharedObject(SafeModuleBC.str()); + std::string SharedObject = compileSharedObject(SafeModuleBC.str(), *Error); + if (!Error->empty()) + return true; delete ToNotCodeGen; outs() << "You can reproduce the problem with the command line: \n"; @@ -919,7 +1010,7 @@ bool BugDriver::debugCodeGenerator() { outs() << "\n"; outs() << " " << TestModuleBC.str() << ".exe"; } - for (unsigned i=0, e = InputArgv.size(); i != e; ++i) + for (unsigned i = 0, e = InputArgv.size(); i != e; ++i) outs() << " " << InputArgv[i]; outs() << '\n'; outs() << "The shared object was created with:\n llc -march=c " |