Remove dangling initializers in GlobalDCE

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>

llvm-svn: 216390
This commit is contained in:
Bruno Cardoso Lopes 2014-08-25 17:51:14 +00:00
parent 785adbdd91
commit 0d2047fa29
3 changed files with 26 additions and 1 deletions

View 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...

View 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))

View File

@ -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
}