mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 20:51:52 +01:00
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... llvm-svn: 12398
This commit is contained in:
parent
acf045e970
commit
4ef444f59b
@ -131,7 +131,11 @@ Module *BugDriver::ExtractLoop(Module *M) {
|
|||||||
|
|
||||||
Module *NewM = runPassesOn(M, LoopExtractPasses);
|
Module *NewM = runPassesOn(M, LoopExtractPasses);
|
||||||
if (NewM == 0) {
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,17 +142,20 @@ namespace {
|
|||||||
|
|
||||||
/// TestMergedProgram - Given two modules, link them together and run the
|
/// TestMergedProgram - Given two modules, link them together and run the
|
||||||
/// program, checking to see if the program matches the diff. If the diff
|
/// program, checking to see if the program matches the diff. If the diff
|
||||||
/// matches, return false, otherwise return true. In either case, we delete
|
/// matches, return false, otherwise return true. If the DeleteInputs argument
|
||||||
/// both input modules before we return.
|
/// is set to true then this function deletes both input modules before it
|
||||||
static bool TestMergedProgram(BugDriver &BD, Module *M1, Module *M2) {
|
/// returns.
|
||||||
|
static bool TestMergedProgram(BugDriver &BD, Module *M1, Module *M2,
|
||||||
|
bool DeleteInputs) {
|
||||||
// Link the two portions of the program back to together.
|
// Link the two portions of the program back to together.
|
||||||
std::string ErrorMsg;
|
std::string ErrorMsg;
|
||||||
|
if (!DeleteInputs) M1 = CloneModule(M1);
|
||||||
if (LinkModules(M1, M2, &ErrorMsg)) {
|
if (LinkModules(M1, M2, &ErrorMsg)) {
|
||||||
std::cerr << BD.getToolName() << ": Error linking modules together:"
|
std::cerr << BD.getToolName() << ": Error linking modules together:"
|
||||||
<< ErrorMsg << "\n";
|
<< ErrorMsg << "\n";
|
||||||
exit(1);
|
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);
|
Module *OldProgram = BD.swapProgramIn(M1);
|
||||||
|
|
||||||
@ -161,7 +164,8 @@ static bool TestMergedProgram(BugDriver &BD, Module *M1, Module *M2) {
|
|||||||
bool Broken = BD.diffProgram();
|
bool Broken = BD.diffProgram();
|
||||||
|
|
||||||
// Delete the linked module & restore the original
|
// Delete the linked module & restore the original
|
||||||
delete BD.swapProgramIn(OldProgram);
|
BD.swapProgramIn(OldProgram);
|
||||||
|
if (DeleteInputs) delete M1;
|
||||||
return Broken;
|
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 "
|
std::cout << "Checking to see if the program is misoptimized when "
|
||||||
<< (Funcs.size()==1 ? "this function is" : "these functions are")
|
<< (Funcs.size()==1 ? "this function is" : "these functions are")
|
||||||
<< " run through the pass"
|
<< " run through the pass"
|
||||||
<< (BD.getPassesToRun().size() == 1 ? "" : "es") << ": ";
|
<< (BD.getPassesToRun().size() == 1 ? "" : "es") << ":";
|
||||||
PrintFunctionList(Funcs);
|
PrintFunctionList(Funcs);
|
||||||
std::cout << "\n";
|
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
|
// Run the optimization passes on ToOptimize, producing a transformed version
|
||||||
// of the functions being tested.
|
// of the functions being tested.
|
||||||
Module *OldProgram = BD.swapProgramIn(ToOptimize);
|
|
||||||
|
|
||||||
std::cout << " Optimizing functions being tested: ";
|
std::cout << " Optimizing functions being tested: ";
|
||||||
std::string BytecodeResult;
|
Module *Optimized = BD.runPassesOn(ToOptimize, BD.getPassesToRun(),
|
||||||
if (BD.runPasses(BD.getPassesToRun(), BytecodeResult, false/*delete*/,
|
/*AutoDebugCrashes*/true);
|
||||||
true/*quiet*/)) {
|
|
||||||
std::cerr << " Error running this sequence of passes"
|
|
||||||
<< " on the input program!\n";
|
|
||||||
BD.EmitProgressBytecode("pass-error", false);
|
|
||||||
exit(BD.debugOptimizerCrash());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << "done.\n";
|
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: ";
|
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");
|
std::cout << (Broken ? " nope.\n" : " yup.\n");
|
||||||
return Broken;
|
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
|
/// debugMiscompilation - This method is used when the passes selected are not
|
||||||
/// crashing, but the generated output is semantically different from the
|
/// crashing, but the generated output is semantically different from the
|
||||||
/// input.
|
/// input.
|
||||||
@ -246,6 +308,22 @@ bool BugDriver::debugMiscompilation() {
|
|||||||
PrintFunctionList(MiscompiledFunctions);
|
PrintFunctionList(MiscompiledFunctions);
|
||||||
std::cout << "\n";
|
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...
|
// Output a bunch of bytecode files for the user...
|
||||||
std::cout << "Outputting reduced bytecode files which expose the problem:\n";
|
std::cout << "Outputting reduced bytecode files which expose the problem:\n";
|
||||||
Module *ToNotOptimize = CloneModule(getProgram());
|
Module *ToNotOptimize = CloneModule(getProgram());
|
||||||
|
Loading…
x
Reference in New Issue
Block a user