forked from OSchip/llvm-project
Cleanup and simplify manipulation of the program, eliminate the need for so
many 'friends' of bugdriver. llvm-svn: 11603
This commit is contained in:
parent
ead1dff00b
commit
327019b495
|
@ -38,6 +38,15 @@ namespace {
|
||||||
"(for miscompilation detection)"));
|
"(for miscompilation detection)"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// setNewProgram - If we reduce or update the program somehow, call this method
|
||||||
|
/// to update bugdriver with it. This deletes the old module and sets the
|
||||||
|
/// specified one as the current program.
|
||||||
|
void BugDriver::setNewProgram(Module *M) {
|
||||||
|
delete Program;
|
||||||
|
Program = M;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// getPassesString - Turn a list of passes into a string which indicates the
|
/// getPassesString - Turn a list of passes into a string which indicates the
|
||||||
/// command line options that must be passed to add the passes.
|
/// command line options that must be passed to add the passes.
|
||||||
///
|
///
|
||||||
|
@ -174,7 +183,7 @@ bool BugDriver::run() {
|
||||||
return debugMiscompilation();
|
return debugMiscompilation();
|
||||||
}
|
}
|
||||||
} catch (ToolExecutionError &TEE) {
|
} catch (ToolExecutionError &TEE) {
|
||||||
std::cerr << TEE.getMessage() << "*** Debugging code generator crash!\n";
|
std::cerr << TEE.getMessage();
|
||||||
return debugCodeGeneratorCrash();
|
return debugCodeGeneratorCrash();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,12 +48,10 @@ class BugDriver {
|
||||||
GCC *gcc;
|
GCC *gcc;
|
||||||
|
|
||||||
// FIXME: sort out public/private distinctions...
|
// FIXME: sort out public/private distinctions...
|
||||||
friend class DebugCrashes;
|
friend class ReducePassList;
|
||||||
friend class ReduceMiscompilingPasses;
|
friend class ReduceMiscompilingPasses;
|
||||||
friend class ReduceMiscompilingFunctions;
|
friend class ReduceMiscompilingFunctions;
|
||||||
friend class ReduceMisCodegenFunctions;
|
friend class ReduceMisCodegenFunctions;
|
||||||
friend class ReduceCrashingFunctions;
|
|
||||||
friend class ReduceCrashingBlocks;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BugDriver(const char *toolname);
|
BugDriver(const char *toolname);
|
||||||
|
@ -114,6 +112,23 @@ public:
|
||||||
///
|
///
|
||||||
bool isExecutingJIT();
|
bool isExecutingJIT();
|
||||||
|
|
||||||
|
/// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Module *getProgram() const { return Program; }
|
||||||
|
|
||||||
|
/// setNewProgram - If we reduce or update the program somehow, call this
|
||||||
|
/// method to update bugdriver with it. This deletes the old module and sets
|
||||||
|
/// the specified one as the current program.
|
||||||
|
void setNewProgram(Module *M);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// ParseInputFile - Given a bytecode or assembly input filename, parse and
|
/// ParseInputFile - Given a bytecode or assembly input filename, parse and
|
||||||
/// return it, or return null if not possible.
|
/// return it, or return null if not possible.
|
||||||
|
|
|
@ -31,10 +31,10 @@
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
class DebugCrashes : public ListReducer<const PassInfo*> {
|
class ReducePassList : public ListReducer<const PassInfo*> {
|
||||||
BugDriver &BD;
|
BugDriver &BD;
|
||||||
public:
|
public:
|
||||||
DebugCrashes(BugDriver &bd) : BD(bd) {}
|
ReducePassList(BugDriver &bd) : BD(bd) {}
|
||||||
|
|
||||||
// doTest - Return true iff running the "removed" passes succeeds, and
|
// doTest - Return true iff running the "removed" passes succeeds, and
|
||||||
// running the "Kept" passes fail when run on the output of the "removed"
|
// running the "Kept" passes fail when run on the output of the "removed"
|
||||||
|
@ -45,9 +45,9 @@ namespace llvm {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
DebugCrashes::TestResult
|
ReducePassList::TestResult
|
||||||
DebugCrashes::doTest(std::vector<const PassInfo*> &Prefix,
|
ReducePassList::doTest(std::vector<const PassInfo*> &Prefix,
|
||||||
std::vector<const PassInfo*> &Suffix) {
|
std::vector<const PassInfo*> &Suffix) {
|
||||||
std::string PrefixOutput;
|
std::string PrefixOutput;
|
||||||
Module *OrigProgram = 0;
|
Module *OrigProgram = 0;
|
||||||
if (!Prefix.empty()) {
|
if (!Prefix.empty()) {
|
||||||
|
@ -104,7 +104,7 @@ namespace llvm {
|
||||||
|
|
||||||
bool ReduceCrashingFunctions::TestFuncs(std::vector<Function*> &Funcs) {
|
bool ReduceCrashingFunctions::TestFuncs(std::vector<Function*> &Funcs) {
|
||||||
// Clone the program to try hacking it apart...
|
// Clone the program to try hacking it apart...
|
||||||
Module *M = CloneModule(BD.Program);
|
Module *M = CloneModule(BD.getProgram());
|
||||||
|
|
||||||
// Convert list to set for fast lookup...
|
// Convert list to set for fast lookup...
|
||||||
std::set<Function*> Functions;
|
std::set<Function*> Functions;
|
||||||
|
@ -131,17 +131,15 @@ bool ReduceCrashingFunctions::TestFuncs(std::vector<Function*> &Funcs) {
|
||||||
DeleteFunctionBody(I);
|
DeleteFunctionBody(I);
|
||||||
|
|
||||||
// Try running the hacked up program...
|
// Try running the hacked up program...
|
||||||
std::swap(BD.Program, M);
|
if (BD.runPasses(M)) {
|
||||||
if (BD.runPasses(BD.PassesToRun)) {
|
BD.setNewProgram(M); // It crashed, keep the trimmed version...
|
||||||
delete M; // It crashed, keep the trimmed version...
|
|
||||||
|
|
||||||
// Make sure to use function pointers that point into the now-current
|
// Make sure to use function pointers that point into the now-current
|
||||||
// module.
|
// module.
|
||||||
Funcs.assign(Functions.begin(), Functions.end());
|
Funcs.assign(Functions.begin(), Functions.end());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
delete BD.Program; // It didn't crash, revert...
|
delete M;
|
||||||
BD.Program = M;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,7 +170,7 @@ namespace llvm {
|
||||||
|
|
||||||
bool ReduceCrashingBlocks::TestBlocks(std::vector<BasicBlock*> &BBs) {
|
bool ReduceCrashingBlocks::TestBlocks(std::vector<BasicBlock*> &BBs) {
|
||||||
// Clone the program to try hacking it apart...
|
// Clone the program to try hacking it apart...
|
||||||
Module *M = CloneModule(BD.Program);
|
Module *M = CloneModule(BD.getProgram());
|
||||||
|
|
||||||
// Convert list to set for fast lookup...
|
// Convert list to set for fast lookup...
|
||||||
std::set<BasicBlock*> Blocks;
|
std::set<BasicBlock*> Blocks;
|
||||||
|
@ -237,9 +235,8 @@ bool ReduceCrashingBlocks::TestBlocks(std::vector<BasicBlock*> &BBs) {
|
||||||
Passes.run(*M);
|
Passes.run(*M);
|
||||||
|
|
||||||
// Try running on the hacked up program...
|
// Try running on the hacked up program...
|
||||||
std::swap(BD.Program, M);
|
if (BD.runPasses(M)) {
|
||||||
if (BD.runPasses(BD.PassesToRun)) {
|
BD.setNewProgram(M); // It crashed, keep the trimmed version...
|
||||||
delete M; // It crashed, keep the trimmed version...
|
|
||||||
|
|
||||||
// Make sure to use basic block pointers that point into the now-current
|
// Make sure to use basic block pointers that point into the now-current
|
||||||
// module, and that they don't include any deleted blocks.
|
// module, and that they don't include any deleted blocks.
|
||||||
|
@ -252,11 +249,15 @@ bool ReduceCrashingBlocks::TestBlocks(std::vector<BasicBlock*> &BBs) {
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
delete BD.Program; // It didn't crash, revert...
|
delete M; // It didn't crash, try something else.
|
||||||
BD.Program = M;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool TestForOptimizerCrash(BugDriver &BD) {
|
||||||
|
return BD.runPasses();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// debugOptimizerCrash - This method is called when some pass crashes on input.
|
/// debugOptimizerCrash - This method is called when some pass crashes on input.
|
||||||
/// It attempts to prune down the testcase to something reasonable, and figure
|
/// It attempts to prune down the testcase to something reasonable, and figure
|
||||||
/// out exactly which pass is crashing.
|
/// out exactly which pass is crashing.
|
||||||
|
@ -267,7 +268,7 @@ bool BugDriver::debugOptimizerCrash() {
|
||||||
|
|
||||||
// Reduce the list of passes which causes the optimizer to crash...
|
// Reduce the list of passes which causes the optimizer to crash...
|
||||||
unsigned OldSize = PassesToRun.size();
|
unsigned OldSize = PassesToRun.size();
|
||||||
DebugCrashes(*this).reduceList(PassesToRun);
|
ReducePassList(*this).reduceList(PassesToRun);
|
||||||
|
|
||||||
std::cout << "\n*** Found crashing pass"
|
std::cout << "\n*** Found crashing pass"
|
||||||
<< (PassesToRun.size() == 1 ? ": " : "es: ")
|
<< (PassesToRun.size() == 1 ? ": " : "es: ")
|
||||||
|
@ -292,15 +293,13 @@ bool BugDriver::debugOptimizerCrash() {
|
||||||
} else {
|
} else {
|
||||||
// See if the program still causes a crash...
|
// See if the program still causes a crash...
|
||||||
std::cout << "\nChecking to see if we can delete global inits: ";
|
std::cout << "\nChecking to see if we can delete global inits: ";
|
||||||
std::swap(Program, M);
|
if (runPasses(M)) { // Still crashes?
|
||||||
if (runPasses(PassesToRun)) { // Still crashes?
|
setNewProgram(M);
|
||||||
AnyReduction = true;
|
AnyReduction = true;
|
||||||
delete M;
|
|
||||||
std::cout << "\n*** Able to remove all global initializers!\n";
|
std::cout << "\n*** Able to remove all global initializers!\n";
|
||||||
} else { // No longer crashes?
|
} else { // No longer crashes?
|
||||||
delete Program; // Restore program.
|
|
||||||
Program = M;
|
|
||||||
std::cout << " - Removing all global inits hides problem!\n";
|
std::cout << " - Removing all global inits hides problem!\n";
|
||||||
|
delete M;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -365,23 +364,19 @@ bool BugDriver::debugOptimizerCrash() {
|
||||||
I != E; ++I) {
|
I != E; ++I) {
|
||||||
Module *M = deleteInstructionFromProgram(I, Simplification);
|
Module *M = deleteInstructionFromProgram(I, Simplification);
|
||||||
|
|
||||||
// Make the function the current program...
|
|
||||||
std::swap(Program, M);
|
|
||||||
|
|
||||||
// Find out if the pass still crashes on this pass...
|
// Find out if the pass still crashes on this pass...
|
||||||
std::cout << "Checking instruction '" << I->getName() << "': ";
|
std::cout << "Checking instruction '" << I->getName() << "': ";
|
||||||
if (runPasses(PassesToRun)) {
|
if (runPasses(M)) {
|
||||||
// Yup, it does, we delete the old module, and continue trying to
|
// Yup, it does, we delete the old module, and continue trying to
|
||||||
// reduce the testcase...
|
// reduce the testcase...
|
||||||
delete M;
|
setNewProgram(M);
|
||||||
AnyReduction = true;
|
AnyReduction = true;
|
||||||
goto TryAgain; // I wish I had a multi-level break here!
|
goto TryAgain; // I wish I had a multi-level break here!
|
||||||
}
|
}
|
||||||
|
|
||||||
// This pass didn't crash without this instruction, try the next
|
// This pass didn't crash without this instruction, try the next
|
||||||
// one.
|
// one.
|
||||||
delete Program;
|
delete M;
|
||||||
Program = M;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (Simplification);
|
} while (Simplification);
|
||||||
|
@ -390,16 +385,13 @@ bool BugDriver::debugOptimizerCrash() {
|
||||||
std::cout << "\n*** Attempting to perform final cleanups: ";
|
std::cout << "\n*** Attempting to perform final cleanups: ";
|
||||||
Module *M = CloneModule(Program);
|
Module *M = CloneModule(Program);
|
||||||
M = performFinalCleanups(M, true);
|
M = performFinalCleanups(M, true);
|
||||||
std::swap(Program, M);
|
|
||||||
|
|
||||||
// Find out if the pass still crashes on the cleaned up program...
|
// Find out if the pass still crashes on the cleaned up program...
|
||||||
if (runPasses(PassesToRun)) {
|
if (runPasses(M)) {
|
||||||
// Yup, it does, keep the reduced version...
|
setNewProgram(M); // Yup, it does, keep the reduced version...
|
||||||
delete M;
|
|
||||||
AnyReduction = true;
|
AnyReduction = true;
|
||||||
} else {
|
} else {
|
||||||
delete Program; // Otherwise, restore the original module...
|
delete M;
|
||||||
Program = M;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AnyReduction)
|
if (AnyReduction)
|
||||||
|
@ -414,6 +406,7 @@ bool BugDriver::debugOptimizerCrash() {
|
||||||
/// crashes on an input. It attempts to reduce the input as much as possible
|
/// crashes on an input. It attempts to reduce the input as much as possible
|
||||||
/// while still causing the code generator to crash.
|
/// while still causing the code generator to crash.
|
||||||
bool BugDriver::debugCodeGeneratorCrash() {
|
bool BugDriver::debugCodeGeneratorCrash() {
|
||||||
|
std::cerr << "*** Debugging code generator crash!\n";
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue