Remove dangling initializers in GlobalDCE
authorBruno Cardoso Lopes <bruno.cardoso@gmail.com>
Mon, 25 Aug 2014 17:51:14 +0000 (17:51 +0000)
committerBruno Cardoso Lopes <bruno.cardoso@gmail.com>
Mon, 25 Aug 2014 17:51:14 +0000 (17:51 +0000)
GlobalDCE deletes global vars and updates their initializers to nullptr
while leaving underlying constants to be cleaned up later by its uses.
The clean up may never happen, fix this by forcing it every time it's
safe to destroy constants.

Final patch by Rafael Espindola
http://reviews.llvm.org/D4931

<rdar://problem/17523868>

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

lib/Transforms/IPO/GlobalDCE.cpp
lib/Transforms/Utils/GlobalStatus.cpp
test/Transforms/GlobalDCE/deadblockaddr.ll [new file with mode: 0644]

index 7e7a4c0ae8354c69cae1470acbb266681f2b4dc3..e50cdb7358cf8aed23454d892b9bd2cbed408ae3 100644 (file)
@@ -22,6 +22,7 @@
 #include "llvm/IR/Instructions.h"
 #include "llvm/IR/Module.h"
 #include "llvm/Transforms/Utils/CtorUtils.h"
+#include "llvm/Transforms/Utils/GlobalStatus.h"
 #include "llvm/Pass.h"
 using namespace llvm;
 
@@ -141,7 +142,12 @@ bool GlobalDCE::runOnModule(Module &M) {
        I != E; ++I)
     if (!AliveGlobals.count(I)) {
       DeadGlobalVars.push_back(I);         // Keep track of dead globals
-      I->setInitializer(nullptr);
+      if (I->hasInitializer()) {
+        Constant *Init = I->getInitializer();
+        I->setInitializer(nullptr);
+        if (isSafeToDestroyConstant(Init))
+          Init->destroyConstant();
+      }
     }
 
   // The second pass drops the bodies of functions which are dead...
index 33e34a9941e051b921bb0b5b53156533a3f265f9..97a0b4ee5ac94d034d97327c5b9e58a286021f29 100644 (file)
@@ -35,6 +35,9 @@ bool llvm::isSafeToDestroyConstant(const Constant *C) {
   if (isa<GlobalValue>(C))
     return false;
 
+  if (isa<ConstantInt>(C) || isa<ConstantFP>(C))
+    return false;
+
   for (const User *U : C->users())
     if (const Constant *CU = dyn_cast<Constant>(U)) {
       if (!isSafeToDestroyConstant(CU))
diff --git a/test/Transforms/GlobalDCE/deadblockaddr.ll b/test/Transforms/GlobalDCE/deadblockaddr.ll
new file mode 100644 (file)
index 0000000..1ec5994
--- /dev/null
@@ -0,0 +1,16 @@
+; RUN: opt -globaldce -simplifycfg -S < %s | FileCheck %s
+
+; Tests whether globaldce does the right cleanup while removing @bar
+; so that a dead BlockAddress reference to foo won't prevent other passes
+; to work properly, e.g. simplifycfg
+@bar = internal unnamed_addr constant i8* blockaddress(@foo, %L1)
+
+; CHECK-LABEL: foo
+; CHECK-NOT: br label %L1
+; CHECK: ret void
+define void @foo() {
+entry:
+  br label %L1
+L1:
+  ret void
+}