diff options
Diffstat (limited to 'lib/Transforms/IPO/GlobalOpt.cpp')
-rw-r--r-- | lib/Transforms/IPO/GlobalOpt.cpp | 206 |
1 files changed, 180 insertions, 26 deletions
diff --git a/lib/Transforms/IPO/GlobalOpt.cpp b/lib/Transforms/IPO/GlobalOpt.cpp index b035a82..a4de71b 100644 --- a/lib/Transforms/IPO/GlobalOpt.cpp +++ b/lib/Transforms/IPO/GlobalOpt.cpp @@ -3041,8 +3041,168 @@ bool GlobalOpt::OptimizeGlobalCtorsList(GlobalVariable *&GCL) { return true; } +/// \brief Given "llvm.used" or "llvm.compiler_used" as a global name, collect +/// the initializer elements of that global in Set and return the global itself. +static GlobalVariable * +collectUsedGlobalVariables(const Module &M, const char *Name, + SmallPtrSet<GlobalValue *, 8> &Set) { + GlobalVariable *GV = M.getGlobalVariable(Name); + if (!GV || !GV->hasInitializer()) + return GV; + + const ConstantArray *Init = cast<ConstantArray>(GV->getInitializer()); + for (unsigned I = 0, E = Init->getNumOperands(); I != E; ++I) { + Value *Op = Init->getOperand(I); + GlobalValue *G = cast<GlobalValue>(Op->stripPointerCastsNoFollowAliases()); + Set.insert(G); + } + return GV; +} + +static int compareNames(const void *A, const void *B) { + const GlobalValue *VA = *reinterpret_cast<GlobalValue* const*>(A); + const GlobalValue *VB = *reinterpret_cast<GlobalValue* const*>(B); + if (VA->getName() < VB->getName()) + return -1; + if (VB->getName() < VA->getName()) + return 1; + return 0; +} + +static void setUsedInitializer(GlobalVariable &V, + SmallPtrSet<GlobalValue *, 8> Init) { + SmallVector<llvm::Constant *, 8> UsedArray; + PointerType *Int8PtrTy = Type::getInt8PtrTy(V.getContext()); + + for (SmallPtrSet<GlobalValue *, 8>::iterator I = Init.begin(), E = Init.end(); + I != E; ++I) { + 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()); + + Module *M = V.getParent(); + V.removeFromParent(); + GlobalVariable *NV = + new GlobalVariable(*M, ATy, false, llvm::GlobalValue::AppendingLinkage, + llvm::ConstantArray::get(ATy, UsedArray), ""); + NV->takeName(&V); + NV->setSection("llvm.metadata"); + delete &V; +} + +namespace { +/// \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; + +public: + LLVMUsed(const Module &M) { + UsedV = collectUsedGlobalVariables(M, "llvm.used", Used); + CompilerUsedV = + collectUsedGlobalVariables(M, "llvm.compiler_used", CompilerUsed); + } + 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 hasUseOtherThanLLVMUsed(GlobalAlias &GA, const LLVMUsed &U) { + if (GA.use_empty()) // No use at all. + return false; + + assert((!U.usedCount(&GA) || !U.compilerUsedCount(&GA)) && + "We should have removed the duplicated " + "element from llvm.compiler_used"); + if (!GA.hasOneUse()) + // Strictly more than one use. So at least one is not in llvm.used and + // llvm.compiler_used. + 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 hasMoreThanOneUseOtherThanLLVMUsed(GlobalValue &V, + 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; + if (hasUseOtherThanLLVMUsed(GA, U)) + Ret = true; + + // If the alias is externally visible, we may still be able to simplify it. + if (!mayHaveOtherReferences(GA, U)) + 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 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(); I != E;) { @@ -3057,37 +3217,29 @@ bool GlobalOpt::OptimizeGlobalAliases(Module &M) { Constant *Aliasee = J->getAliasee(); GlobalValue *Target = cast<GlobalValue>(Aliasee->stripPointerCasts()); Target->removeDeadConstantUsers(); - bool hasOneUse = Target->hasOneUse() && Aliasee->hasOneUse(); // Make all users of the alias use the aliasee instead. - if (!J->use_empty()) { - J->replaceAllUsesWith(Aliasee); - ++NumAliasesResolved; - Changed = true; - } - - // 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; + bool RenameTarget; + if (!hasUsesToReplace(*J, Used, RenameTarget)) + 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; + J->replaceAllUsesWith(Aliasee); + ++NumAliasesResolved; + Changed = true; + if (RenameTarget) { // Give the aliasee the name, linkage and other attributes of the alias. Target->takeName(J); Target->setLinkage(J->getLinkage()); Target->GlobalValue::copyAttributesFrom(J); - } + + if (Used.usedErase(J)) + Used.usedInsert(Target); + + if (Used.compilerUsedErase(J)) + Used.compilerUsedInsert(Target); + } else if (mayHaveOtherReferences(*J, Used)) + continue; // Delete the alias. M.getAliasList().erase(J); @@ -3095,6 +3247,8 @@ bool GlobalOpt::OptimizeGlobalAliases(Module &M) { Changed = true; } + Used.syncVariablesAndSets(); + return Changed; } @@ -3223,8 +3377,6 @@ bool GlobalOpt::runOnModule(Module &M) { // Try to find the llvm.globalctors list. GlobalVariable *GlobalCtors = FindGlobalCtors(M); - Function *CXAAtExitFn = FindCXAAtExit(M, TLI); - bool LocalChange = true; while (LocalChange) { LocalChange = false; @@ -3242,7 +3394,9 @@ bool GlobalOpt::runOnModule(Module &M) { // Resolve aliases, when possible. LocalChange |= OptimizeGlobalAliases(M); - // Try to remove trivial global destructors. + // Try to remove trivial global destructors if they are not removed + // already. + Function *CXAAtExitFn = FindCXAAtExit(M, TLI); if (CXAAtExitFn) LocalChange |= OptimizeEmptyGlobalCXXDtors(CXAAtExitFn); |