mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-13 20:32:21 +00:00
Change how globalopt handles aliases in llvm.used.
Instead of a custom implementation of replaceAllUsesWith, we just call replaceAllUsesWith and recreate llvm.used and llvm.compiler-used. This change is particularity interesting because it makes llvm see through what clang is doing with static used functions in extern "C" contexts. With this change, running clang -O2 in extern "C" { __attribute__((used)) static void foo() {} } produces @llvm.used = appending global [1 x i8*] [i8* bitcast (void ()* @foo to i8*)], section "llvm.metadata" define internal void @foo() #0 { entry: ret void } git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@183756 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
9e26acb5b5
commit
d1b6ca23b4
@ -3041,107 +3041,168 @@ bool GlobalOpt::OptimizeGlobalCtorsList(GlobalVariable *&GCL) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Value::use_iterator getFirst(Value *V, SmallPtrSet<Use*, 8> &Tried) {
|
/// \brief Given "llvm.used" or "llvm.compiler_used" as a global name, collect
|
||||||
for (Value::use_iterator I = V->use_begin(), E = V->use_end(); I != E; ++I) {
|
/// the initializer elements of that global in Set and return the global itself.
|
||||||
Use *U = &I.getUse();
|
static GlobalVariable *
|
||||||
if (Tried.count(U))
|
collectUsedGlobalVariables(const Module &M, const char *Name,
|
||||||
continue;
|
SmallPtrSet<GlobalValue *, 8> &Set) {
|
||||||
|
GlobalVariable *GV = M.getGlobalVariable(Name);
|
||||||
|
if (!GV || !GV->hasInitializer())
|
||||||
|
return GV;
|
||||||
|
|
||||||
User *Usr = *I;
|
const ConstantArray *Init = cast<ConstantArray>(GV->getInitializer());
|
||||||
GlobalVariable *GV = dyn_cast<GlobalVariable>(Usr);
|
for (unsigned I = 0, E = Init->getNumOperands(); I != E; ++I) {
|
||||||
if (!GV || !GV->hasName()) {
|
Value *Op = Init->getOperand(I);
|
||||||
Tried.insert(U);
|
GlobalValue *G = cast<GlobalValue>(Op->stripPointerCastsNoFollowAliases());
|
||||||
return I;
|
Set.insert(G);
|
||||||
|
}
|
||||||
|
return GV;
|
||||||
}
|
}
|
||||||
|
|
||||||
StringRef Name = GV->getName();
|
static int compareNames(const void *A, const void *B) {
|
||||||
if (Name != "llvm.used" && Name != "llvm.compiler_used") {
|
const GlobalValue *VA = *reinterpret_cast<GlobalValue* const*>(A);
|
||||||
Tried.insert(U);
|
const GlobalValue *VB = *reinterpret_cast<GlobalValue* const*>(B);
|
||||||
return I;
|
if (VA->getName() < VB->getName())
|
||||||
}
|
return -1;
|
||||||
}
|
if (VB->getName() < VA->getName())
|
||||||
return V->use_end();
|
return 1;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool replaceAllNonLLVMUsedUsesWith(Constant *Old, Constant *New);
|
static void setUsedInitializer(GlobalVariable &V,
|
||||||
|
SmallPtrSet<GlobalValue *, 8> Init) {
|
||||||
|
SmallVector<llvm::Constant *, 8> UsedArray;
|
||||||
|
PointerType *Int8PtrTy = Type::getInt8PtrTy(V.getContext());
|
||||||
|
|
||||||
static bool replaceUsesOfWithOnConstant(ConstantArray *CA, Value *From,
|
for (SmallPtrSet<GlobalValue *, 8>::iterator I = Init.begin(), E = Init.end();
|
||||||
Value *ToV, Use *U) {
|
I != E; ++I) {
|
||||||
Constant *To = cast<Constant>(ToV);
|
Constant *Cast = llvm::ConstantExpr::getBitCast(*I, Int8PtrTy);
|
||||||
|
UsedArray.push_back(Cast);
|
||||||
|
}
|
||||||
|
// Sort to get deterministic order.
|
||||||
|
array_pod_sort(UsedArray.begin(), UsedArray.end(), compareNames);
|
||||||
|
ArrayType *ATy = ArrayType::get(Int8PtrTy, UsedArray.size());
|
||||||
|
|
||||||
SmallVector<Constant*, 8> NewOps;
|
Module *M = V.getParent();
|
||||||
for (unsigned i = 0, e = CA->getNumOperands(); i != e; ++i) {
|
V.removeFromParent();
|
||||||
Constant *Op = CA->getOperand(i);
|
GlobalVariable *NV =
|
||||||
NewOps.push_back(Op == From ? To : Op);
|
new GlobalVariable(*M, ATy, false, llvm::GlobalValue::AppendingLinkage,
|
||||||
|
llvm::ConstantArray::get(ATy, UsedArray), "");
|
||||||
|
NV->takeName(&V);
|
||||||
|
NV->setSection("llvm.metadata");
|
||||||
|
delete &V;
|
||||||
}
|
}
|
||||||
|
|
||||||
Constant *Replacement = ConstantArray::get(CA->getType(), NewOps);
|
namespace {
|
||||||
assert(Replacement != CA && "CA didn't contain From!");
|
/// \brief An easy to access representation of llvm.used and llvm.compiler_used.
|
||||||
|
class LLVMUsed {
|
||||||
|
SmallPtrSet<GlobalValue *, 8> Used;
|
||||||
|
SmallPtrSet<GlobalValue *, 8> CompilerUsed;
|
||||||
|
GlobalVariable *UsedV;
|
||||||
|
GlobalVariable *CompilerUsedV;
|
||||||
|
|
||||||
bool Ret = replaceAllNonLLVMUsedUsesWith(CA, Replacement);
|
public:
|
||||||
if (Replacement->use_empty())
|
LLVMUsed(const Module &M) {
|
||||||
Replacement->destroyConstant();
|
UsedV = collectUsedGlobalVariables(M, "llvm.used", Used);
|
||||||
if (CA->use_empty())
|
CompilerUsedV =
|
||||||
CA->destroyConstant();
|
collectUsedGlobalVariables(M, "llvm.compiler_used", CompilerUsed);
|
||||||
return Ret;
|
}
|
||||||
|
typedef SmallPtrSet<GlobalValue *, 8>::iterator iterator;
|
||||||
|
iterator usedBegin() { return Used.begin(); }
|
||||||
|
iterator usedEnd() { return Used.end(); }
|
||||||
|
iterator compilerUsedBegin() { return CompilerUsed.begin(); }
|
||||||
|
iterator compilerUsedEnd() { return CompilerUsed.end(); }
|
||||||
|
bool usedCount(GlobalValue *GV) const { return Used.count(GV); }
|
||||||
|
bool compilerUsedCount(GlobalValue *GV) const {
|
||||||
|
return CompilerUsed.count(GV);
|
||||||
|
}
|
||||||
|
bool usedErase(GlobalValue *GV) { return Used.erase(GV); }
|
||||||
|
bool compilerUsedErase(GlobalValue *GV) { return CompilerUsed.erase(GV); }
|
||||||
|
bool usedInsert(GlobalValue *GV) { return Used.insert(GV); }
|
||||||
|
bool compilerUsedInsert(GlobalValue *GV) { return CompilerUsed.insert(GV); }
|
||||||
|
|
||||||
|
void syncVariablesAndSets() {
|
||||||
|
if (UsedV)
|
||||||
|
setUsedInitializer(*UsedV, Used);
|
||||||
|
if (CompilerUsedV)
|
||||||
|
setUsedInitializer(*CompilerUsedV, CompilerUsed);
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool replaceUsesOfWithOnConstant(ConstantExpr *CE, Value *From,
|
static bool hasUseOtherThanLLVMUsed(GlobalAlias &GA, const LLVMUsed &U) {
|
||||||
Value *ToV, Use *U) {
|
if (GA.use_empty()) // No use at all.
|
||||||
Constant *To = cast<Constant>(ToV);
|
return false;
|
||||||
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((!U.usedCount(&GA) || !U.compilerUsedCount(&GA)) &&
|
||||||
assert(Replacement != CE && "CE didn't contain From!");
|
"We should have removed the duplicated "
|
||||||
|
"element from llvm.compiler_used");
|
||||||
bool Ret = replaceAllNonLLVMUsedUsesWith(CE, Replacement);
|
if (!GA.hasOneUse())
|
||||||
if (Replacement->use_empty())
|
// Strictly more than one use. So at least one is not in llvm.used and
|
||||||
Replacement->destroyConstant();
|
// llvm.compiler_used.
|
||||||
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;
|
return true;
|
||||||
|
|
||||||
|
// Exactly one use. Check if it is in llvm.used or llvm.compiler_used.
|
||||||
|
return !U.usedCount(&GA) && !U.compilerUsedCount(&GA);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool replaceAllNonLLVMUsedUsesWith(Constant *Old, Constant *New) {
|
static bool hasMoreThanOneUseOtherThanLLVMUsed(GlobalValue &V,
|
||||||
SmallPtrSet<Use*, 8> Tried;
|
const LLVMUsed &U) {
|
||||||
|
unsigned N = 2;
|
||||||
|
assert((!U.usedCount(&V) || !U.compilerUsedCount(&V)) &&
|
||||||
|
"We should have removed the duplicated "
|
||||||
|
"element from llvm.compiler_used");
|
||||||
|
if (U.usedCount(&V) || U.compilerUsedCount(&V))
|
||||||
|
++N;
|
||||||
|
return V.hasNUsesOrMore(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool mayHaveOtherReferences(GlobalAlias &GA, const LLVMUsed &U) {
|
||||||
|
if (!GA.hasLocalLinkage())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return U.usedCount(&GA) || U.compilerUsedCount(&GA);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool hasUsesToReplace(GlobalAlias &GA, LLVMUsed &U, bool &RenameTarget) {
|
||||||
|
RenameTarget = false;
|
||||||
bool Ret = false;
|
bool Ret = false;
|
||||||
for (;;) {
|
if (hasUseOtherThanLLVMUsed(GA, U))
|
||||||
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;
|
Ret = true;
|
||||||
}
|
|
||||||
|
// If the alias is externally visible, we may still be able to simplify it.
|
||||||
|
if (!mayHaveOtherReferences(GA, U))
|
||||||
return Ret;
|
return Ret;
|
||||||
|
|
||||||
|
// If the aliasee has internal linkage, give it the name and linkage
|
||||||
|
// of the alias, and delete the alias. This turns:
|
||||||
|
// define internal ... @f(...)
|
||||||
|
// @a = alias ... @f
|
||||||
|
// into:
|
||||||
|
// define ... @a(...)
|
||||||
|
Constant *Aliasee = GA.getAliasee();
|
||||||
|
GlobalValue *Target = cast<GlobalValue>(Aliasee->stripPointerCasts());
|
||||||
|
if (!Target->hasLocalLinkage())
|
||||||
|
return Ret;
|
||||||
|
|
||||||
|
// Do not perform the transform if multiple aliases potentially target the
|
||||||
|
// aliasee. This check also ensures that it is safe to replace the section
|
||||||
|
// and other attributes of the aliasee with those of the alias.
|
||||||
|
if (hasMoreThanOneUseOtherThanLLVMUsed(*Target, U))
|
||||||
|
return Ret;
|
||||||
|
|
||||||
|
RenameTarget = true;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GlobalOpt::OptimizeGlobalAliases(Module &M) {
|
bool GlobalOpt::OptimizeGlobalAliases(Module &M) {
|
||||||
bool Changed = false;
|
bool Changed = false;
|
||||||
|
LLVMUsed Used(M);
|
||||||
|
|
||||||
|
for (SmallPtrSet<GlobalValue *, 8>::iterator I = Used.usedBegin(),
|
||||||
|
E = Used.usedEnd();
|
||||||
|
I != E; ++I)
|
||||||
|
Used.compilerUsedErase(*I);
|
||||||
|
|
||||||
for (Module::alias_iterator I = M.alias_begin(), E = M.alias_end();
|
for (Module::alias_iterator I = M.alias_begin(), E = M.alias_end();
|
||||||
I != E;) {
|
I != E;) {
|
||||||
@ -3156,45 +3217,40 @@ bool GlobalOpt::OptimizeGlobalAliases(Module &M) {
|
|||||||
Constant *Aliasee = J->getAliasee();
|
Constant *Aliasee = J->getAliasee();
|
||||||
GlobalValue *Target = cast<GlobalValue>(Aliasee->stripPointerCasts());
|
GlobalValue *Target = cast<GlobalValue>(Aliasee->stripPointerCasts());
|
||||||
Target->removeDeadConstantUsers();
|
Target->removeDeadConstantUsers();
|
||||||
bool hasOneUse = Target->hasOneUse() && Aliasee->hasOneUse();
|
|
||||||
|
|
||||||
// Make all users of the alias use the aliasee instead.
|
// Make all users of the alias use the aliasee instead.
|
||||||
if (replaceAllNonLLVMUsedUsesWith(J, Aliasee)) {
|
bool RenameTarget;
|
||||||
|
if (!hasUsesToReplace(*J, Used, RenameTarget))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
J->replaceAllUsesWith(Aliasee);
|
||||||
++NumAliasesResolved;
|
++NumAliasesResolved;
|
||||||
Changed = true;
|
Changed = true;
|
||||||
}
|
|
||||||
if (!J->use_empty())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// If the alias is externally visible, we may still be able to simplify it.
|
|
||||||
if (!J->hasLocalLinkage()) {
|
|
||||||
// If the aliasee has internal linkage, give it the name and linkage
|
|
||||||
// of the alias, and delete the alias. This turns:
|
|
||||||
// define internal ... @f(...)
|
|
||||||
// @a = alias ... @f
|
|
||||||
// into:
|
|
||||||
// define ... @a(...)
|
|
||||||
if (!Target->hasLocalLinkage())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Do not perform the transform if multiple aliases potentially target the
|
|
||||||
// aliasee. This check also ensures that it is safe to replace the section
|
|
||||||
// and other attributes of the aliasee with those of the alias.
|
|
||||||
if (!hasOneUse)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
|
if (RenameTarget) {
|
||||||
// Give the aliasee the name, linkage and other attributes of the alias.
|
// Give the aliasee the name, linkage and other attributes of the alias.
|
||||||
Target->takeName(J);
|
Target->takeName(J);
|
||||||
Target->setLinkage(J->getLinkage());
|
Target->setLinkage(J->getLinkage());
|
||||||
Target->GlobalValue::copyAttributesFrom(J);
|
Target->GlobalValue::copyAttributesFrom(J);
|
||||||
|
|
||||||
|
if (Used.usedErase(J))
|
||||||
|
Used.usedInsert(Target);
|
||||||
|
|
||||||
|
if (Used.compilerUsedErase(J))
|
||||||
|
Used.compilerUsedInsert(Target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mayHaveOtherReferences(*J, Used))
|
||||||
|
continue;
|
||||||
|
|
||||||
// Delete the alias.
|
// Delete the alias.
|
||||||
M.getAliasList().erase(J);
|
M.getAliasList().erase(J);
|
||||||
++NumAliasesRemoved;
|
++NumAliasesRemoved;
|
||||||
Changed = true;
|
Changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Used.syncVariablesAndSets();
|
||||||
|
|
||||||
return Changed;
|
return Changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,16 +2,21 @@
|
|||||||
|
|
||||||
@c = global i8 42
|
@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"
|
@i = internal global i8 42
|
||||||
; 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"
|
; CHECK: @ia = internal global i8 42
|
||||||
|
@ia = alias internal i8* @i
|
||||||
|
|
||||||
@llvm.compiler_used = appending global [2 x i8*] [i8* bitcast (void ()* @fa to i8*), i8* bitcast (void ()* @fa3 to i8*)], section "llvm.metadata"
|
@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-DAG: @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 [4 x i8*] [i8* bitcast (void ()* @fa3 to i8*), i8* bitcast (void ()* @fa to i8*), i8* @ia, i8* @i], section "llvm.metadata"
|
||||||
|
; CHECK-DAG: @llvm.compiler_used = appending global [2 x i8*] [i8* bitcast (void ()* @fa3 to i8*), i8* @ia], section "llvm.metadata"
|
||||||
|
|
||||||
@sameAsUsed = global [3 x i8*] [i8* bitcast (void ()* @fa to i8*), i8* bitcast (void ()* @f to i8*), i8* @ca]
|
@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]
|
; CHECK-DAG: @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*)
|
@other = global i32* bitcast (void ()* @fa to i32*)
|
||||||
; CHECK: @other = global i32* bitcast (void ()* @f to i32*)
|
; CHECK-DAG: @other = global i32* bitcast (void ()* @f to i32*)
|
||||||
|
|
||||||
@fa = alias internal void ()* @f
|
@fa = alias internal void ()* @f
|
||||||
; CHECK: @fa = alias internal void ()* @f
|
; CHECK: @fa = alias internal void ()* @f
|
||||||
|
Loading…
Reference in New Issue
Block a user