Rework GlobalValue::removeDeadConstantUsers to always remove dead constant
authorChris Lattner <sabre@nondot.org>
Sun, 25 Feb 2007 21:06:13 +0000 (21:06 +0000)
committerChris Lattner <sabre@nondot.org>
Sun, 25 Feb 2007 21:06:13 +0000 (21:06 +0000)
exprs hanging off a global, even if the global is not otherwise dead.  This
requires some tricky iterator gymnastics.

This implements Transforms/GlobalOpt/constantexpr-dangle.ll by deleting a
constantexpr that made it appear that the address of the function was taken.

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

include/llvm/GlobalValue.h
lib/VMCore/Globals.cpp

index ca9149e6caf5ab219a5bb4fca632d5c1f1b12233..576fbe6521ac0d679ef61be898b9caa63dccbae9 100644 (file)
@@ -128,10 +128,6 @@ public:
   /// off of this global value, remove them.  This method is useful for clients
   /// that want to check to see if a global is unused, but don't want to deal
   /// with potentially dead constants hanging off of the globals.
-  ///
-  /// This method tries to make the global dead.  If it detects a user that
-  /// would prevent it from becoming completely dead, it gives up early,
-  /// potentially leaving some dead constant users around.
   void removeDeadConstantUsers();
 
   // Methods for support type inquiry through isa, cast, and dyn_cast:
index 327e2ad9aa2698b4a33eb674cbfa899f2b864886..198948d90288ca42175cc87fbc2b8e0a7326b27f 100644 (file)
@@ -22,20 +22,18 @@ using namespace llvm;
 //                            GlobalValue Class
 //===----------------------------------------------------------------------===//
 
-/// This could be named "SafeToDestroyGlobalValue". It just makes sure that
-/// there are no non-constant uses of this GlobalValue. If there aren't then
-/// this and the transitive closure of the constants can be deleted. See the
-/// destructor for details.
-static bool removeDeadConstantUsers(Constant* C) {
+/// removeDeadUsersOfConstant - If the specified constantexpr is dead, remove
+/// it.  This involves recursively eliminating any dead users of the
+/// constantexpr.
+static bool removeDeadUsersOfConstant(Constant *C) {
   if (isa<GlobalValue>(C)) return false; // Cannot remove this
 
-  while (!C->use_empty())
-    if (Constant *User = dyn_cast<Constant>(C->use_back())) {
-      if (!removeDeadConstantUsers(User))
-        return false; // Constant wasn't dead
-    } else {
-      return false; // Non-constant usage;
-    }
+  while (!C->use_empty()) {
+    Constant *User = dyn_cast<Constant>(C->use_back());
+    if (!User) return false; // Non-constant usage;
+    if (!removeDeadUsersOfConstant(User))
+      return false; // Constant wasn't dead
+  }
 
   C->destroyConstant();
   return true;
@@ -45,17 +43,27 @@ static bool removeDeadConstantUsers(Constant* C) {
 /// off of this global value, remove them.  This method is useful for clients
 /// that want to check to see if a global is unused, but don't want to deal
 /// with potentially dead constants hanging off of the globals.
-///
-/// This function returns true if the global value is now dead.  If all
-/// users of this global are not dead, this method may return false and
-/// leave some of them around.
 void GlobalValue::removeDeadConstantUsers() {
-  while(!use_empty()) {
-    if (Constant* User = dyn_cast<Constant>(use_back())) {
-      if (!::removeDeadConstantUsers(User))
-        return; // Constant wasn't dead
+  
+  Value::use_iterator I = use_begin(), E = use_end();
+  Value::use_iterator LastNonDeadUser = E;
+  for (; I != E; ++I) {
+    if (Constant *User = dyn_cast<Constant>(*I)) {
+      if (!removeDeadUsersOfConstant(User)) {
+        // If the constant wasn't dead, remember that this was the last live use
+        // and move on to the next constant.
+        LastNonDeadUser = I;
+      } else {
+        // If the constant was dead, then the iterator is invalidated.
+        if (LastNonDeadUser == E) {
+          I = use_begin();
+          if (I == E) break;
+        } else {
+          I = LastNonDeadUser;
+        }
+      }
     } else {
-      return; // Non-constant usage;
+      LastNonDeadUser = I;
     }
   }
 }