Fix for PR960. Improves bugpoint so that it removes global variable
authorBill Wendling <isanbard@gmail.com>
Wed, 25 Oct 2006 18:36:14 +0000 (18:36 +0000)
committerBill Wendling <isanbard@gmail.com>
Wed, 25 Oct 2006 18:36:14 +0000 (18:36 +0000)
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
tools/bugpoint/BugDriver.h
tools/bugpoint/CrashDebugger.cpp

index e499477630d53d5808ae78d41da70ebacd36e424..236e8a3cac193ea7ca5210701e95ea1be4cdcb69 100644 (file)
@@ -221,3 +221,13 @@ void llvm::PrintFunctionList(const std::vector<Function*> &Funcs) {
     std::cout << "... <" << Funcs.size() << " total>";
   std::cout << std::flush;
 }
+
+void llvm::PrintGlobalVariableList(const std::vector<GlobalVariable*> &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;
+}
index 2029e2da029926c6d4dd5bf005be1283433d71c0..3de7b055f94c7d29e5651de766d36c53fd0dc23f 100644 (file)
@@ -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<const PassInfo*> &Passes);
 ///
 void PrintFunctionList(const std::vector<Function*> &Funcs);
 
+/// PrintGlobalVariableList - prints out list of problematic global variables
+///
+void PrintGlobalVariableList(const std::vector<GlobalVariable*> &GVs);
+
 // DeleteFunctionBody - "Remove" the function by deleting all of it's basic
 // blocks, making it external.
 //
index 63926464e23d272d5faf1b391de0d2441c7411c9..b86bb8fa042d0853c50266c6a8a3dc018c7ea2e0 100644 (file)
 #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<const PassInfo*> &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<GlobalVariable*> {
+    BugDriver &BD;
+    bool (*TestFn)(BugDriver &, Module *);
+  public:
+    ReduceCrashingGlobalVariables(BugDriver &bd,
+                                  bool (*testFn)(BugDriver&, Module*))
+      : BD(bd), TestFn(testFn) {}
+
+    virtual TestResult doTest(std::vector<GlobalVariable*>& Prefix,
+                              std::vector<GlobalVariable*>& Kept) {
+      if (!Kept.empty() && TestGlobalVariables(Kept))
+        return KeepSuffix;
+
+      if (!Prefix.empty() && TestGlobalVariables(Prefix))
+        return KeepPrefix;
+
+      return NoFailure;
+    }
+
+    bool TestGlobalVariables(std::vector<GlobalVariable*>& GVs);
+  };
+}
+
+bool
+ReduceCrashingGlobalVariables::TestGlobalVariables(
+                              std::vector<GlobalVariable*>& GVs) {
+  // Clone the program to try hacking it apart...
+  Module *M = CloneModule(BD.getProgram());
+
+  // Convert list to set for fast lookup...
+  std::set<GlobalVariable*> 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<Function*> {
     BugDriver &BD;
     bool (*TestFn)(BugDriver &, Module *);
@@ -119,7 +193,8 @@ namespace llvm {
 bool ReduceCrashingFunctions::TestFuncs(std::vector<Function*> &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<const BasicBlock*> &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<GlobalVariable*> 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");
     }
   }