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
This commit is contained in:
Chris Lattner 2004-03-14 22:08:00 +00:00
parent 44a64bccac
commit a1cf1c8c87
2 changed files with 110 additions and 28 deletions

View File

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

View File

@ -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<Function*>&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<Function*>&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<Function*> &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());