summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/lib/CodeGen/GlobalMerge.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/lib/CodeGen/GlobalMerge.cpp')
-rw-r--r--contrib/llvm/lib/CodeGen/GlobalMerge.cpp138
1 files changed, 61 insertions, 77 deletions
diff --git a/contrib/llvm/lib/CodeGen/GlobalMerge.cpp b/contrib/llvm/lib/CodeGen/GlobalMerge.cpp
index 6f9e839..dd9a840 100644
--- a/contrib/llvm/lib/CodeGen/GlobalMerge.cpp
+++ b/contrib/llvm/lib/CodeGen/GlobalMerge.cpp
@@ -108,10 +108,9 @@ EnableGlobalMergeOnConst("global-merge-on-const", cl::Hidden,
// FIXME: this could be a transitional option, and we probably need to remove
// it if only we are sure this optimization could always benefit all targets.
-static cl::opt<bool>
+static cl::opt<cl::boolOrDefault>
EnableGlobalMergeOnExternal("global-merge-on-external", cl::Hidden,
- cl::desc("Enable global merge pass on external linkage"),
- cl::init(false));
+ cl::desc("Enable global merge pass on external linkage"));
STATISTIC(NumMerged, "Number of globals merged");
namespace {
@@ -129,11 +128,14 @@ namespace {
/// FIXME: This could learn about optsize, and be used in the cost model.
bool OnlyOptimizeForSize;
+ /// Whether we should merge global variables that have external linkage.
+ bool MergeExternalGlobals;
+
bool doMerge(SmallVectorImpl<GlobalVariable*> &Globals,
Module &M, bool isConst, unsigned AddrSpace) const;
/// \brief Merge everything in \p Globals for which the corresponding bit
/// in \p GlobalSet is set.
- bool doMerge(SmallVectorImpl<GlobalVariable *> &Globals,
+ bool doMerge(const SmallVectorImpl<GlobalVariable *> &Globals,
const BitVector &GlobalSet, Module &M, bool isConst,
unsigned AddrSpace) const;
@@ -158,9 +160,11 @@ namespace {
static char ID; // Pass identification, replacement for typeid.
explicit GlobalMerge(const TargetMachine *TM = nullptr,
unsigned MaximalOffset = 0,
- bool OnlyOptimizeForSize = false)
+ bool OnlyOptimizeForSize = false,
+ bool MergeExternalGlobals = false)
: FunctionPass(ID), TM(TM), MaxOffset(MaximalOffset),
- OnlyOptimizeForSize(OnlyOptimizeForSize) {
+ OnlyOptimizeForSize(OnlyOptimizeForSize),
+ MergeExternalGlobals(MergeExternalGlobals) {
initializeGlobalMergePass(*PassRegistry::getPassRegistry());
}
@@ -189,14 +193,11 @@ bool GlobalMerge::doMerge(SmallVectorImpl<GlobalVariable*> &Globals,
Module &M, bool isConst, unsigned AddrSpace) const {
auto &DL = M.getDataLayout();
// FIXME: Find better heuristics
- std::stable_sort(
- Globals.begin(), Globals.end(),
- [&DL](const GlobalVariable *GV1, const GlobalVariable *GV2) {
- Type *Ty1 = cast<PointerType>(GV1->getType())->getElementType();
- Type *Ty2 = cast<PointerType>(GV2->getType())->getElementType();
-
- return (DL.getTypeAllocSize(Ty1) < DL.getTypeAllocSize(Ty2));
- });
+ std::stable_sort(Globals.begin(), Globals.end(),
+ [&DL](const GlobalVariable *GV1, const GlobalVariable *GV2) {
+ return DL.getTypeAllocSize(GV1->getValueType()) <
+ DL.getTypeAllocSize(GV2->getValueType());
+ });
// If we want to just blindly group all globals together, do so.
if (!GlobalMergeGroupByUse) {
@@ -207,7 +208,7 @@ bool GlobalMerge::doMerge(SmallVectorImpl<GlobalVariable*> &Globals,
// If we want to be smarter, look at all uses of each global, to try to
// discover all sets of globals used together, and how many times each of
- // these sets occured.
+ // these sets occurred.
//
// Keep this reasonably efficient, by having an append-only list of all sets
// discovered so far (UsedGlobalSet), and mapping each "together-ness" unit of
@@ -302,8 +303,7 @@ bool GlobalMerge::doMerge(SmallVectorImpl<GlobalVariable*> &Globals,
Function *ParentFn = I->getParent()->getParent();
// If we're only optimizing for size, ignore non-minsize functions.
- if (OnlyOptimizeForSize &&
- !ParentFn->hasFnAttribute(Attribute::MinSize))
+ if (OnlyOptimizeForSize && !ParentFn->optForMinSize())
continue;
size_t UGSIdx = GlobalUsesByFunction[ParentFn];
@@ -406,15 +406,14 @@ bool GlobalMerge::doMerge(SmallVectorImpl<GlobalVariable*> &Globals,
return Changed;
}
-bool GlobalMerge::doMerge(SmallVectorImpl<GlobalVariable *> &Globals,
+bool GlobalMerge::doMerge(const SmallVectorImpl<GlobalVariable *> &Globals,
const BitVector &GlobalSet, Module &M, bool isConst,
unsigned AddrSpace) const {
+ assert(Globals.size() > 1);
Type *Int32Ty = Type::getInt32Ty(M.getContext());
auto &DL = M.getDataLayout();
- assert(Globals.size() > 1);
-
DEBUG(dbgs() << " Trying to merge set, starts with #"
<< GlobalSet.find_first() << "\n");
@@ -425,58 +424,44 @@ bool GlobalMerge::doMerge(SmallVectorImpl<GlobalVariable *> &Globals,
std::vector<Type*> Tys;
std::vector<Constant*> Inits;
- bool HasExternal = false;
- GlobalVariable *TheFirstExternal = 0;
for (j = i; j != -1; j = GlobalSet.find_next(j)) {
- Type *Ty = Globals[j]->getType()->getElementType();
+ Type *Ty = Globals[j]->getValueType();
MergedSize += DL.getTypeAllocSize(Ty);
if (MergedSize > MaxOffset) {
break;
}
Tys.push_back(Ty);
Inits.push_back(Globals[j]->getInitializer());
-
- if (Globals[j]->hasExternalLinkage() && !HasExternal) {
- HasExternal = true;
- TheFirstExternal = Globals[j];
- }
}
- // If merged variables doesn't have external linkage, we needn't to expose
- // the symbol after merging.
- GlobalValue::LinkageTypes Linkage = HasExternal
- ? GlobalValue::ExternalLinkage
- : GlobalValue::InternalLinkage;
-
StructType *MergedTy = StructType::get(M.getContext(), Tys);
Constant *MergedInit = ConstantStruct::get(MergedTy, Inits);
- // If merged variables have external linkage, we use symbol name of the
- // first variable merged as the suffix of global symbol name. This would
- // be able to avoid the link-time naming conflict for globalm symbols.
GlobalVariable *MergedGV = new GlobalVariable(
- M, MergedTy, isConst, Linkage, MergedInit,
- HasExternal ? "_MergedGlobals_" + TheFirstExternal->getName()
- : "_MergedGlobals",
- nullptr, GlobalVariable::NotThreadLocal, AddrSpace);
+ M, MergedTy, isConst, GlobalValue::PrivateLinkage, MergedInit,
+ "_MergedGlobals", nullptr, GlobalVariable::NotThreadLocal, AddrSpace);
- for (ssize_t k = i, idx = 0; k != j; k = GlobalSet.find_next(k)) {
+ for (ssize_t k = i, idx = 0; k != j; k = GlobalSet.find_next(k), ++idx) {
GlobalValue::LinkageTypes Linkage = Globals[k]->getLinkage();
std::string Name = Globals[k]->getName();
Constant *Idx[2] = {
ConstantInt::get(Int32Ty, 0),
- ConstantInt::get(Int32Ty, idx++)
+ ConstantInt::get(Int32Ty, idx),
};
Constant *GEP =
ConstantExpr::getInBoundsGetElementPtr(MergedTy, MergedGV, Idx);
Globals[k]->replaceAllUsesWith(GEP);
Globals[k]->eraseFromParent();
- if (Linkage != GlobalValue::InternalLinkage) {
- // Generate a new alias...
- auto *PTy = cast<PointerType>(GEP->getType());
- GlobalAlias::create(PTy, Linkage, Name, GEP, &M);
+ // When the linkage is not internal we must emit an alias for the original
+ // variable name as it may be accessed from another object. On non-Mach-O
+ // we can also emit an alias for internal linkage as it's safe to do so.
+ // It's not safe on Mach-O as the alias (and thus the portion of the
+ // MergedGlobals variable) may be dead stripped at link time.
+ if (Linkage != GlobalValue::InternalLinkage ||
+ !TM->getTargetTriple().isOSBinFormatMachO()) {
+ GlobalAlias::create(Tys[idx], AddrSpace, Linkage, Name, GEP, &M);
}
NumMerged++;
@@ -535,61 +520,57 @@ bool GlobalMerge::doInitialization(Module &M) {
setMustKeepGlobalVariables(M);
// Grab all non-const globals.
- for (Module::global_iterator I = M.global_begin(),
- E = M.global_end(); I != E; ++I) {
+ for (auto &GV : M.globals()) {
// Merge is safe for "normal" internal or external globals only
- if (I->isDeclaration() || I->isThreadLocal() || I->hasSection())
+ if (GV.isDeclaration() || GV.isThreadLocal() || GV.hasSection())
continue;
- if (!(EnableGlobalMergeOnExternal && I->hasExternalLinkage()) &&
- !I->hasInternalLinkage())
+ if (!(MergeExternalGlobals && GV.hasExternalLinkage()) &&
+ !GV.hasInternalLinkage())
continue;
- PointerType *PT = dyn_cast<PointerType>(I->getType());
+ PointerType *PT = dyn_cast<PointerType>(GV.getType());
assert(PT && "Global variable is not a pointer!");
unsigned AddressSpace = PT->getAddressSpace();
// Ignore fancy-aligned globals for now.
- unsigned Alignment = DL.getPreferredAlignment(I);
- Type *Ty = I->getType()->getElementType();
+ unsigned Alignment = DL.getPreferredAlignment(&GV);
+ Type *Ty = GV.getValueType();
if (Alignment > DL.getABITypeAlignment(Ty))
continue;
// Ignore all 'special' globals.
- if (I->getName().startswith("llvm.") ||
- I->getName().startswith(".llvm."))
+ if (GV.getName().startswith("llvm.") ||
+ GV.getName().startswith(".llvm."))
continue;
// Ignore all "required" globals:
- if (isMustKeepGlobalVariable(I))
+ if (isMustKeepGlobalVariable(&GV))
continue;
if (DL.getTypeAllocSize(Ty) < MaxOffset) {
- if (TargetLoweringObjectFile::getKindForGlobal(I, *TM).isBSSLocal())
- BSSGlobals[AddressSpace].push_back(I);
- else if (I->isConstant())
- ConstGlobals[AddressSpace].push_back(I);
+ if (TargetLoweringObjectFile::getKindForGlobal(&GV, *TM).isBSSLocal())
+ BSSGlobals[AddressSpace].push_back(&GV);
+ else if (GV.isConstant())
+ ConstGlobals[AddressSpace].push_back(&GV);
else
- Globals[AddressSpace].push_back(I);
+ Globals[AddressSpace].push_back(&GV);
}
}
- for (DenseMap<unsigned, SmallVector<GlobalVariable*, 16> >::iterator
- I = Globals.begin(), E = Globals.end(); I != E; ++I)
- if (I->second.size() > 1)
- Changed |= doMerge(I->second, M, false, I->first);
+ for (auto &P : Globals)
+ if (P.second.size() > 1)
+ Changed |= doMerge(P.second, M, false, P.first);
- for (DenseMap<unsigned, SmallVector<GlobalVariable*, 16> >::iterator
- I = BSSGlobals.begin(), E = BSSGlobals.end(); I != E; ++I)
- if (I->second.size() > 1)
- Changed |= doMerge(I->second, M, false, I->first);
+ for (auto &P : BSSGlobals)
+ if (P.second.size() > 1)
+ Changed |= doMerge(P.second, M, false, P.first);
if (EnableGlobalMergeOnConst)
- for (DenseMap<unsigned, SmallVector<GlobalVariable*, 16> >::iterator
- I = ConstGlobals.begin(), E = ConstGlobals.end(); I != E; ++I)
- if (I->second.size() > 1)
- Changed |= doMerge(I->second, M, true, I->first);
+ for (auto &P : ConstGlobals)
+ if (P.second.size() > 1)
+ Changed |= doMerge(P.second, M, true, P.first);
return Changed;
}
@@ -604,6 +585,9 @@ bool GlobalMerge::doFinalization(Module &M) {
}
Pass *llvm::createGlobalMergePass(const TargetMachine *TM, unsigned Offset,
- bool OnlyOptimizeForSize) {
- return new GlobalMerge(TM, Offset, OnlyOptimizeForSize);
+ bool OnlyOptimizeForSize,
+ bool MergeExternalByDefault) {
+ bool MergeExternal = (EnableGlobalMergeOnExternal == cl::BOU_UNSET) ?
+ MergeExternalByDefault : (EnableGlobalMergeOnExternal == cl::BOU_TRUE);
+ return new GlobalMerge(TM, Offset, OnlyOptimizeForSize, MergeExternal);
}
OpenPOWER on IntegriCloud