From a1cf1c8c87f10f12343ff6ae75f332390e7205ab Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Sun, 14 Mar 2004 22:08:00 +0000 Subject: [PATCH] After reducing a miscompiled program down to the functions which are being miscompiled, try to use the loop extractor to reduce the program down to a loop nest that is being miscompiled. In practice, the loop extractor appears to have too many bugs for this to be useful, but hopefully they will be fixed soon... git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@12398 91177308-0d34-0410-b5e6-96231b3b80d8 --- tools/bugpoint/ExtractFunction.cpp | 6 +- tools/bugpoint/Miscompilation.cpp | 132 +++++++++++++++++++++++------ 2 files changed, 110 insertions(+), 28 deletions(-) diff --git a/tools/bugpoint/ExtractFunction.cpp b/tools/bugpoint/ExtractFunction.cpp index 53afd474fdd..e8fe499ffdd 100644 --- a/tools/bugpoint/ExtractFunction.cpp +++ b/tools/bugpoint/ExtractFunction.cpp @@ -131,7 +131,11 @@ Module *BugDriver::ExtractLoop(Module *M) { Module *NewM = runPassesOn(M, LoopExtractPasses); if (NewM == 0) { - std::cerr << "Loop extraction failed. Sorry. :( Please report a bug!\n"; + Module *Old = swapProgramIn(M); + std::cout << "*** Loop extraction failed: "; + EmitProgressBytecode("loopextraction", true); + std::cout << "*** Sorry. :( Please report a bug!\n"; + swapProgramIn(Old); return 0; } diff --git a/tools/bugpoint/Miscompilation.cpp b/tools/bugpoint/Miscompilation.cpp index 830f26f5146..0d568753609 100644 --- a/tools/bugpoint/Miscompilation.cpp +++ b/tools/bugpoint/Miscompilation.cpp @@ -142,17 +142,20 @@ namespace { /// 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. In either case, we delete -/// both input modules before we return. -static bool TestMergedProgram(BugDriver &BD, Module *M1, Module *M2) { +/// matches, return false, otherwise return true. 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) { // Link the two portions of the program back to together. std::string ErrorMsg; + if (!DeleteInputs) M1 = CloneModule(M1); if (LinkModules(M1, M2, &ErrorMsg)) { std::cerr << BD.getToolName() << ": Error linking modules together:" << ErrorMsg << "\n"; exit(1); } - delete M2; // We are done with this module... + if (DeleteInputs) delete M2; // We are done with this module... Module *OldProgram = BD.swapProgramIn(M1); @@ -161,7 +164,8 @@ static bool TestMergedProgram(BugDriver &BD, Module *M1, Module *M2) { bool Broken = BD.diffProgram(); // Delete the linked module & restore the original - delete BD.swapProgramIn(OldProgram); + BD.swapProgramIn(OldProgram); + if (DeleteInputs) delete M1; return Broken; } @@ -171,7 +175,7 @@ bool ReduceMiscompilingFunctions::TestFuncs(const std::vector&Funcs){ std::cout << "Checking to see if the program is misoptimized when " << (Funcs.size()==1 ? "this function is" : "these functions are") << " run through the pass" - << (BD.getPassesToRun().size() == 1 ? "" : "es") << ": "; + << (BD.getPassesToRun().size() == 1 ? "" : "es") << ":"; PrintFunctionList(Funcs); std::cout << "\n"; @@ -181,36 +185,94 @@ bool ReduceMiscompilingFunctions::TestFuncs(const std::vector&Funcs){ // Run the optimization passes on ToOptimize, producing a transformed version // of the functions being tested. - Module *OldProgram = BD.swapProgramIn(ToOptimize); - std::cout << " Optimizing functions being tested: "; - std::string BytecodeResult; - if (BD.runPasses(BD.getPassesToRun(), BytecodeResult, false/*delete*/, - true/*quiet*/)) { - std::cerr << " Error running this sequence of passes" - << " on the input program!\n"; - BD.EmitProgressBytecode("pass-error", false); - exit(BD.debugOptimizerCrash()); - } - + Module *Optimized = BD.runPassesOn(ToOptimize, BD.getPassesToRun(), + /*AutoDebugCrashes*/true); std::cout << "done.\n"; + delete ToOptimize; - // Delete the old "ToOptimize" module - delete BD.swapProgramIn(OldProgram); - Module *Optimized = ParseInputFile(BytecodeResult); - if (Optimized == 0) { - std::cerr << BD.getToolName() << ": Error reading bytecode file '" - << BytecodeResult << "'!\n"; - exit(1); - } - removeFile(BytecodeResult); // No longer need the file on disk std::cout << " Checking to see if the merged program executes correctly: "; - bool Broken = TestMergedProgram(BD, Optimized, ToNotOptimize); + bool Broken = TestMergedProgram(BD, Optimized, ToNotOptimize, true); std::cout << (Broken ? " nope.\n" : " yup.\n"); return Broken; } +/// ExtractLoops - Given a reduced list of functions that still exposed the bug, +/// check to see if we can extract the loops in the region without obscuring the +/// bug. If so, it reduces the amount of code identified. +static bool ExtractLoops(BugDriver &BD, + std::vector &MiscompiledFunctions) { + bool MadeChange = false; + while (1) { + Module *ToNotOptimize = CloneModule(BD.getProgram()); + Module *ToOptimize = SplitFunctionsOutOfModule(ToNotOptimize, + MiscompiledFunctions); + Module *ToOptimizeLoopExtracted = BD.ExtractLoop(ToOptimize); + if (!ToOptimizeLoopExtracted) { + // If the loop extractor crashed or if there were no extractible loops, + // then this chapter of our odyssey is over with. + delete ToNotOptimize; + delete ToOptimize; + return MadeChange; + } + + std::cerr << "Extracted a loop from the breaking portion of the program.\n"; + delete ToOptimize; + + // Bugpoint is intentionally not very trusting of LLVM transformations. In + // particular, we're not going to assume that the loop extractor works, so + // we're going to test the newly loop extracted program to make sure nothing + // has broken. If something broke, then we'll inform the user and stop + // extraction. + if (TestMergedProgram(BD, ToOptimizeLoopExtracted, ToNotOptimize, false)) { + // Merged program doesn't work anymore! + std::cerr << " *** ERROR: Loop extraction broke the program. :(" + << " Please report a bug!\n"; + std::cerr << " Continuing on with un-loop-extracted version.\n"; + delete ToNotOptimize; + delete ToOptimizeLoopExtracted; + return MadeChange; + } + + // Okay, the loop extractor didn't break the program. Run the series of + // optimizations on the loop extracted portion and see if THEY still break + // the program. If so, it was safe to extract these loops! + std::cout << " Running optimizations on loop extracted portion: "; + Module *Optimized = BD.runPassesOn(ToOptimizeLoopExtracted, + BD.getPassesToRun(), + /*AutoDebugCrashes*/true); + std::cout << "done.\n"; + + std::cout << " Checking to see if the merged program executes correctly: "; + bool Broken = TestMergedProgram(BD, Optimized, ToNotOptimize, true); + delete Optimized; + if (!Broken) { + std::cout << "yup: 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. + delete ToNotOptimize; + delete ToOptimizeLoopExtracted; + return MadeChange; + } + std::cout << "nope: loop extraction successful!\n"; + + // Okay, great! Now we know that we extracted a loop and that loop + // extraction both didn't break the program, and didn't mask the problem. + // Replace the current program with the loop extracted version, and try to + // extract another loop. + std::string ErrorMsg; + if (LinkModules(ToNotOptimize, ToOptimizeLoopExtracted, &ErrorMsg)) { + std::cerr << BD.getToolName() << ": Error linking modules together:" + << ErrorMsg << "\n"; + exit(1); + } + delete ToOptimizeLoopExtracted; + BD.setNewProgram(ToNotOptimize); + MadeChange = true; + } +} + /// debugMiscompilation - This method is used when the passes selected are not /// crashing, but the generated output is semantically different from the /// input. @@ -246,6 +308,22 @@ bool BugDriver::debugMiscompilation() { PrintFunctionList(MiscompiledFunctions); std::cout << "\n"; + // See if we can rip any loops out of the miscompiled functions and still + // trigger the problem. + if (ExtractLoops(*this, MiscompiledFunctions)) { + // Okay, we extracted some loops and the problem still appears. See if we + // can eliminate some of the created functions from being candidates. + + // Do the reduction... + ReduceMiscompilingFunctions(*this).reduceList(MiscompiledFunctions); + + std::cout << "\n*** The following function" + << (MiscompiledFunctions.size() == 1 ? " is" : "s are") + << " being miscompiled: "; + PrintFunctionList(MiscompiledFunctions); + std::cout << "\n"; + } + // Output a bunch of bytecode files for the user... std::cout << "Outputting reduced bytecode files which expose the problem:\n"; Module *ToNotOptimize = CloneModule(getProgram()); -- 2.34.1