Don't replace an alias in llvm.used with its target.

When we replace an internal alias with its target, be careful not to
replace the entry in llvm.used (and llvm.compiler_used).

llvm-svn: 181524
This commit is contained in:
Rafael Espindola 2013-05-09 17:22:59 +00:00
parent 0321b8ffd6
commit 007521673b
2 changed files with 144 additions and 2 deletions

View File

@ -3041,6 +3041,105 @@ bool GlobalOpt::OptimizeGlobalCtorsList(GlobalVariable *&GCL) {
return true;
}
static Value::use_iterator getFirst(Value *V, SmallPtrSet<Use*, 8> &Tried) {
for (Value::use_iterator I = V->use_begin(), E = V->use_end(); I != E; ++I) {
Use *U = &I.getUse();
if (Tried.count(U))
continue;
User *Usr = *I;
GlobalVariable *GV = dyn_cast<GlobalVariable>(Usr);
if (!GV || !GV->hasName()) {
Tried.insert(U);
return I;
}
StringRef Name = GV->getName();
if (Name != "llvm.used" && Name != "llvm.compiler_used") {
Tried.insert(U);
return I;
}
}
return V->use_end();
}
static bool replaceAllNonLLVMUsedUsesWith(Constant *Old, Constant *New);
static bool replaceUsesOfWithOnConstant(ConstantArray *CA, Value *From,
Value *ToV, Use *U) {
Constant *To = cast<Constant>(ToV);
SmallVector<Constant*, 8> NewOps;
for (unsigned i = 0, e = CA->getNumOperands(); i != e; ++i) {
Constant *Op = CA->getOperand(i);
NewOps.push_back(Op == From ? To : Op);
}
Constant *Replacement = ConstantArray::get(CA->getType(), NewOps);
assert(Replacement != CA && "CA didn't contain From!");
bool Ret = replaceAllNonLLVMUsedUsesWith(CA, Replacement);
if (Replacement->use_empty())
Replacement->destroyConstant();
if (CA->use_empty())
CA->destroyConstant();
return Ret;
}
static bool replaceUsesOfWithOnConstant(ConstantExpr *CE, Value *From,
Value *ToV, Use *U) {
Constant *To = cast<Constant>(ToV);
SmallVector<Constant*, 8> NewOps;
for (unsigned i = 0, e = CE->getNumOperands(); i != e; ++i) {
Constant *Op = CE->getOperand(i);
NewOps.push_back(Op == From ? To : Op);
}
Constant *Replacement = CE->getWithOperands(NewOps);
assert(Replacement != CE && "CE didn't contain From!");
bool Ret = replaceAllNonLLVMUsedUsesWith(CE, Replacement);
if (Replacement->use_empty())
Replacement->destroyConstant();
if (CE->use_empty())
CE->destroyConstant();
return Ret;
}
static bool replaceUsesOfWithOnConstant(Constant *C, Value *From, Value *To,
Use *U) {
if (ConstantArray *CA = dyn_cast<ConstantArray>(C))
return replaceUsesOfWithOnConstant(CA, From, To, U);
if (ConstantExpr *CE = dyn_cast<ConstantExpr>(C))
return replaceUsesOfWithOnConstant(CE, From, To, U);
C->replaceUsesOfWithOnConstant(From, To, U);
return true;
}
static bool replaceAllNonLLVMUsedUsesWith(Constant *Old, Constant *New) {
SmallPtrSet<Use*, 8> Tried;
bool Ret = false;
for (;;) {
Value::use_iterator I = getFirst(Old, Tried);
if (I == Old->use_end())
break;
Use &U = I.getUse();
// Must handle Constants specially, we cannot call replaceUsesOfWith on a
// constant because they are uniqued.
if (Constant *C = dyn_cast<Constant>(U.getUser())) {
if (!isa<GlobalValue>(C)) {
Ret |= replaceUsesOfWithOnConstant(C, Old, New, &U);
continue;
}
}
U.set(New);
Ret = true;
}
return Ret;
}
bool GlobalOpt::OptimizeGlobalAliases(Module &M) {
bool Changed = false;
@ -3060,11 +3159,12 @@ bool GlobalOpt::OptimizeGlobalAliases(Module &M) {
bool hasOneUse = Target->hasOneUse() && Aliasee->hasOneUse();
// Make all users of the alias use the aliasee instead.
if (!J->use_empty()) {
J->replaceAllUsesWith(Aliasee);
if (replaceAllNonLLVMUsedUsesWith(J, Aliasee)) {
++NumAliasesResolved;
Changed = true;
}
if (!J->use_empty())
continue;
// If the alias is externally visible, we may still be able to simplify it.
if (!J->hasLocalLinkage()) {

View File

@ -0,0 +1,42 @@
; RUN: opt < %s -globalopt -S | FileCheck %s
@c = global i8 42
@llvm.used = appending global [3 x i8*] [i8* bitcast (void ()* @fa to i8*), i8* bitcast (void ()* @f to i8*), i8* @ca], section "llvm.metadata"
; CHECK: @llvm.used = appending global [3 x i8*] [i8* bitcast (void ()* @fa to i8*), i8* bitcast (void ()* @f to i8*), i8* @ca], section "llvm.metadata"
@llvm.compiler_used = appending global [2 x i8*] [i8* bitcast (void ()* @fa to i8*), i8* bitcast (void ()* @fa3 to i8*)], section "llvm.metadata"
@sameAsUsed = global [3 x i8*] [i8* bitcast (void ()* @fa to i8*), i8* bitcast (void ()* @f to i8*), i8* @ca]
; CHECK: @sameAsUsed = global [3 x i8*] [i8* bitcast (void ()* @f to i8*), i8* bitcast (void ()* @f to i8*), i8* @c]
@other = global i32* bitcast (void ()* @fa to i32*)
; CHECK: @other = global i32* bitcast (void ()* @f to i32*)
@fa = alias internal void ()* @f
; CHECK: @fa = alias internal void ()* @f
@fa2 = alias internal void ()* @f
; CHECK-NOT: @fa2
@fa3 = alias internal void ()* @f
; CHECK: @fa3
@ca = alias internal i8* @c
; CHECK: @ca = alias internal i8* @c
define void @f() {
ret void
}
define i8* @g() {
ret i8* bitcast (void ()* @fa to i8*);
}
define i8* @g2() {
ret i8* bitcast (void ()* @fa2 to i8*);
}
define i8* @h() {
ret i8* @ca
}