diff --git a/lib/Transforms/IPO/GlobalOpt.cpp b/lib/Transforms/IPO/GlobalOpt.cpp index b035a821b4c..0ef900e2b9a 100644 --- a/lib/Transforms/IPO/GlobalOpt.cpp +++ b/lib/Transforms/IPO/GlobalOpt.cpp @@ -3041,6 +3041,105 @@ bool GlobalOpt::OptimizeGlobalCtorsList(GlobalVariable *&GCL) { return true; } +static Value::use_iterator getFirst(Value *V, SmallPtrSet &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(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(ToV); + + SmallVector 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(ToV); + SmallVector 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(C)) + return replaceUsesOfWithOnConstant(CA, From, To, U); + if (ConstantExpr *CE = dyn_cast(C)) + return replaceUsesOfWithOnConstant(CE, From, To, U); + C->replaceUsesOfWithOnConstant(From, To, U); + return true; +} + +static bool replaceAllNonLLVMUsedUsesWith(Constant *Old, Constant *New) { + SmallPtrSet 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(U.getUser())) { + if (!isa(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()) { diff --git a/test/Transforms/GlobalOpt/alias-used.ll b/test/Transforms/GlobalOpt/alias-used.ll new file mode 100644 index 00000000000..f91579bf050 --- /dev/null +++ b/test/Transforms/GlobalOpt/alias-used.ll @@ -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 +}