From 4e3be89cb5cde6e2df294c64db3bc28133b67594 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 25 Oct 2006 18:36:14 +0000 Subject: [PATCH] Fix for PR960. Improves bugpoint so that it removes global variable initializers as well. This is only a first pass. It can be slow because it clones the module for each pass. An obvious improvement is not to do that. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@31182 91177308-0d34-0410-b5e6-96231b3b80d8 --- tools/bugpoint/BugDriver.cpp | 10 +++ tools/bugpoint/BugDriver.h | 5 ++ tools/bugpoint/CrashDebugger.cpp | 118 +++++++++++++++++++++++++------ 3 files changed, 110 insertions(+), 23 deletions(-) diff --git a/tools/bugpoint/BugDriver.cpp b/tools/bugpoint/BugDriver.cpp index e499477630d..236e8a3cac1 100644 --- a/tools/bugpoint/BugDriver.cpp +++ b/tools/bugpoint/BugDriver.cpp @@ -221,3 +221,13 @@ void llvm::PrintFunctionList(const std::vector &Funcs) { std::cout << "... <" << Funcs.size() << " total>"; std::cout << std::flush; } + +void llvm::PrintGlobalVariableList(const std::vector &GVs) { + unsigned NumPrint = GVs.size(); + if (NumPrint > 10) NumPrint = 10; + for (unsigned i = 0; i != NumPrint; ++i) + std::cout << " " << GVs[i]->getName(); + if (NumPrint < GVs.size()) + std::cout << "... <" << GVs.size() << " total>"; + std::cout << std::flush; +} diff --git a/tools/bugpoint/BugDriver.h b/tools/bugpoint/BugDriver.h index 2029e2da029..3de7b055f94 100644 --- a/tools/bugpoint/BugDriver.h +++ b/tools/bugpoint/BugDriver.h @@ -23,6 +23,7 @@ namespace llvm { class PassInfo; class Module; +class GlobalVariable; class Function; class BasicBlock; class AbstractInterpreter; @@ -295,6 +296,10 @@ std::string getPassesString(const std::vector &Passes); /// void PrintFunctionList(const std::vector &Funcs); +/// PrintGlobalVariableList - prints out list of problematic global variables +/// +void PrintGlobalVariableList(const std::vector &GVs); + // DeleteFunctionBody - "Remove" the function by deleting all of it's basic // blocks, making it external. // diff --git a/tools/bugpoint/CrashDebugger.cpp b/tools/bugpoint/CrashDebugger.cpp index 63926464e23..b86bb8fa042 100644 --- a/tools/bugpoint/CrashDebugger.cpp +++ b/tools/bugpoint/CrashDebugger.cpp @@ -15,12 +15,12 @@ #include "ToolRunner.h" #include "ListReducer.h" #include "llvm/Constant.h" +#include "llvm/DerivedTypes.h" #include "llvm/Instructions.h" #include "llvm/Module.h" #include "llvm/Pass.h" #include "llvm/PassManager.h" #include "llvm/SymbolTable.h" -#include "llvm/Type.h" #include "llvm/Analysis/Verifier.h" #include "llvm/Bytecode/Writer.h" #include "llvm/Support/CFG.h" @@ -94,7 +94,81 @@ ReducePassList::doTest(std::vector &Prefix, return NoFailure; } +namespace { + /// ReduceCrashingGlobalVariables - This works by removing the global + /// variable's initializer and seeing if the program still crashes. If it + /// does, then we keep that program and try again. + /// + class ReduceCrashingGlobalVariables : public ListReducer { + BugDriver &BD; + bool (*TestFn)(BugDriver &, Module *); + public: + ReduceCrashingGlobalVariables(BugDriver &bd, + bool (*testFn)(BugDriver&, Module*)) + : BD(bd), TestFn(testFn) {} + + virtual TestResult doTest(std::vector& Prefix, + std::vector& Kept) { + if (!Kept.empty() && TestGlobalVariables(Kept)) + return KeepSuffix; + + if (!Prefix.empty() && TestGlobalVariables(Prefix)) + return KeepPrefix; + + return NoFailure; + } + + bool TestGlobalVariables(std::vector& GVs); + }; +} + +bool +ReduceCrashingGlobalVariables::TestGlobalVariables( + std::vector& GVs) { + // Clone the program to try hacking it apart... + Module *M = CloneModule(BD.getProgram()); + + // Convert list to set for fast lookup... + std::set GVSet; + + for (unsigned i = 0, e = GVs.size(); i != e; ++i) { + GlobalVariable* CMGV = M->getNamedGlobal(GVs[i]->getName()); + assert(CMGV && "Global Variable not in module?!"); + GVSet.insert(CMGV); + } + + std::cout << "Checking for crash with only these global variables: "; + PrintGlobalVariableList(GVs); + std::cout << ": "; + + // Loop over and delete any global variables which we aren't supposed to be + // playing with... + for (Module::global_iterator I = M->global_begin(), E = M->global_end(); + I != E; ++I) + if (I->hasInitializer()) { + I->setInitializer(0); + I->setLinkage(GlobalValue::ExternalLinkage); + } + + // Try running the hacked up program... + if (TestFn(BD, M)) { + BD.setNewProgram(M); // It crashed, keep the trimmed version... + + // Make sure to use global variable pointers that point into the now-current + // module. + GVs.assign(GVSet.begin(), GVSet.end()); + return true; + } + + delete M; + return false; +} + namespace llvm { + /// ReduceCrashingFunctions reducer - This works by removing functions and + /// seeing if the program still crashes. If it does, then keep the newer, + /// smaller program. + /// class ReduceCrashingFunctions : public ListReducer { BugDriver &BD; bool (*TestFn)(BugDriver &, Module *); @@ -119,7 +193,8 @@ namespace llvm { bool ReduceCrashingFunctions::TestFuncs(std::vector &Funcs) { //if main isn't present, claim there is no problem - if (KeepMain && find(Funcs.begin(), Funcs.end(), BD.getProgram()->getMainFunction()) == Funcs.end()) + if (KeepMain && find(Funcs.begin(), Funcs.end(), + BD.getProgram()->getMainFunction()) == Funcs.end()) return false; // Clone the program to try hacking it apart... @@ -277,30 +352,27 @@ bool ReduceCrashingBlocks::TestBlocks(std::vector &BBs) { /// on a program, try to destructively reduce the program while still keeping /// the predicate true. static bool DebugACrash(BugDriver &BD, bool (*TestFn)(BugDriver &, Module *)) { - // See if we can get away with nuking all of the global variable initializers + // See if we can get away with nuking some of the global variable initializers // in the program... if (BD.getProgram()->global_begin() != BD.getProgram()->global_end()) { - Module *M = CloneModule(BD.getProgram()); - bool DeletedInit = false; - for (Module::global_iterator I = M->global_begin(), E = M->global_end(); I != E; ++I) - if (I->hasInitializer()) { - I->setInitializer(0); - I->setLinkage(GlobalValue::ExternalLinkage); - DeletedInit = true; - } + // Now try to reduce the number of global variable initializers in the + // module to something small. + std::vector GVs; - if (!DeletedInit) { - delete M; // No change made... - } else { - // See if the program still causes a crash... - std::cout << "\nChecking to see if we can delete global inits: "; - if (TestFn(BD, M)) { // Still crashes? - BD.setNewProgram(M); - std::cout << "\n*** Able to remove all global initializers!\n"; - } else { // No longer crashes? - std::cout << " - Removing all global inits hides problem!\n"; - delete M; - } + for (Module::global_iterator I = BD.getProgram()->global_begin(), + E = BD.getProgram()->global_end(); I != E; ++I) + if (I->hasInitializer()) + GVs.push_back(I); + + if (GVs.size() > 1 && !BugpointIsInterrupted) { + std::cout << "\n*** Attempting to reduce the number of global variables " + << "in the testcase\n"; + + unsigned OldSize = GVs.size(); + ReduceCrashingGlobalVariables(BD, TestFn).reduceList(GVs); + + if (GVs.size() < OldSize) + BD.EmitProgressBytecode("reduced-global-variables"); } }