[bugpoint] Fix "Alias must point to a definition" problems
authorHal Finkel <hfinkel@anl.gov>
Thu, 26 Nov 2015 19:23:49 +0000 (19:23 +0000)
committerHal Finkel <hfinkel@anl.gov>
Thu, 26 Nov 2015 19:23:49 +0000 (19:23 +0000)
GlobalAliases may reference function definitions, but not function declarations.

bugpoint would sometimes create invalid IR by deleting a function's body (thus
mutating a function definition into a declaration) without first 'fixing' any
GlobalAliases that reference that function definition.

This change iteratively prevents that issue. Before deleting a function's body,
it scans the module for GlobalAliases which reference that function. When
found, it eliminates them using replaceAllUsesWith.

Fixes PR20788.

Patch by Nick Johnson!

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@254171 91177308-0d34-0410-b5e6-96231b3b80d8

tools/bugpoint/BugDriver.h
tools/bugpoint/CrashDebugger.cpp
tools/bugpoint/ExtractFunction.cpp

index 1bd2e80a63035e3de1d5a2c4b1547c28a9c38c98..45fcf74aa6bf2ff7036457af7afc9b0b7ee5c398 100644 (file)
@@ -321,6 +321,11 @@ void PrintFunctionList(const std::vector<Function*> &Funcs);
 ///
 void PrintGlobalVariableList(const std::vector<GlobalVariable*> &GVs);
 
+// DeleteGlobalInitializer - "Remove" the global variable by deleting its
+// initializer, making it external.
+//
+void DeleteGlobalInitializer(GlobalVariable *GV);
+
 // DeleteFunctionBody - "Remove" the function by deleting all of it's basic
 // blocks, making it external.
 //
index 1bfcc87e06ed530562df463049d2a67ebd7ad653..631a58455c5b93968d32e4187fd3e9feee71e2e1 100644 (file)
@@ -162,7 +162,7 @@ ReduceCrashingGlobalVariables::TestGlobalVariables(
   // playing with...
   for (GlobalVariable &I : M->globals())
     if (I.hasInitializer() && !GVSet.count(&I)) {
-      I.setInitializer(nullptr);
+      DeleteGlobalInitializer(&I);
       I.setLinkage(GlobalValue::ExternalLinkage);
     }
 
@@ -664,7 +664,7 @@ static bool DebugACrash(BugDriver &BD,
     for (Module::global_iterator I = M->global_begin(), E = M->global_end();
          I != E; ++I)
       if (I->hasInitializer()) {
-        I->setInitializer(nullptr);
+        DeleteGlobalInitializer(&*I);
         I->setLinkage(GlobalValue::ExternalLinkage);
         DeletedInit = true;
       }
index 21d3d98459966db6364e7270e05102fe781958da..7b98cb8fb55cb06763ca34bedc3438c26726f705 100644 (file)
@@ -179,11 +179,43 @@ std::unique_ptr<Module> BugDriver::extractLoop(Module *M) {
   return NewM;
 }
 
+static void eliminateAliases(GlobalValue *GV) {
+  // First, check whether a GlobalAlias references this definition.
+  // GlobalAlias MAY NOT reference declarations.
+  for (;;) {
+    // 1. Find aliases
+    SmallVector<GlobalAlias*,1> aliases;
+    Module *M = GV->getParent();
+    for (Module::alias_iterator I=M->alias_begin(), E=M->alias_end(); I!=E; ++I)
+      if (I->getAliasee()->stripPointerCasts() == GV)
+        aliases.push_back(&*I);
+    if (aliases.empty())
+      break;
+    // 2. Resolve aliases
+    for (unsigned i=0, e=aliases.size(); i<e; ++i) {
+      aliases[i]->replaceAllUsesWith(aliases[i]->getAliasee());
+      aliases[i]->eraseFromParent();
+    }
+    // 3. Repeat until no more aliases found; there might
+    // be an alias to an alias...
+  }
+}
+
+//
+// DeleteGlobalInitializer - "Remove" the global variable by deleting its initializer,
+// making it external.
+//
+void llvm::DeleteGlobalInitializer(GlobalVariable *GV) {
+  eliminateAliases(GV);
+  GV->setInitializer(nullptr);
+}
 
 // DeleteFunctionBody - "Remove" the function by deleting all of its basic
 // blocks, making it external.
 //
 void llvm::DeleteFunctionBody(Function *F) {
+  eliminateAliases(F);
+
   // delete the body of the function...
   F->deleteBody();
   assert(F->isDeclaration() && "This didn't make the function external!");
@@ -323,10 +355,10 @@ llvm::SplitFunctionsOutOfModule(Module *M,
                << "' and from test function '" << TestFn->getName() << "'.\n";
         exit(1);
       }
-      I.setInitializer(nullptr); // Delete the initializer to make it external
+      DeleteGlobalInitializer(&I); // Delete the initializer to make it external
     } else {
       // If we keep it in the safe module, then delete it in the test module
-      GV->setInitializer(nullptr);
+      DeleteGlobalInitializer(GV);
     }
   }