X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=blobdiff_plain;f=lib%2FCodeGen%2FGlobalMerge.cpp;h=0feff250e649acfa9a3c1c304cfc9a7164c814de;hp=aaa37896293f3a3d3a4e0fbf00315e0127a351db;hb=f47cf2495ddda26f6df71d7849838ed915463687;hpb=35e80553937f84d1b562f00fa757ee700d142f99 diff --git a/lib/CodeGen/GlobalMerge.cpp b/lib/CodeGen/GlobalMerge.cpp index aaa37896293..0feff250e64 100644 --- a/lib/CodeGen/GlobalMerge.cpp +++ b/lib/CodeGen/GlobalMerge.cpp @@ -108,27 +108,34 @@ 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 +static cl::opt 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 { class GlobalMerge : public FunctionPass { const TargetMachine *TM; - const DataLayout *DL; // FIXME: Infer the maximum possible offset depending on the actual users // (these max offsets are different for the users inside Thumb or ARM // functions), see the code that passes in the offset in the ARM backend // for more information. unsigned MaxOffset; + /// Whether we should try to optimize for size only. + /// Currently, this applies a dead simple heuristic: only consider globals + /// used in minsize functions for merging. + /// 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 &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 &Globals, + bool doMerge(const SmallVectorImpl &Globals, const BitVector &GlobalSet, Module &M, bool isConst, unsigned AddrSpace) const; @@ -152,9 +159,12 @@ namespace { public: static char ID; // Pass identification, replacement for typeid. explicit GlobalMerge(const TargetMachine *TM = nullptr, - unsigned MaximalOffset = 0) - : FunctionPass(ID), TM(TM), DL(TM->getDataLayout()), - MaxOffset(MaximalOffset) { + unsigned MaximalOffset = 0, + bool OnlyOptimizeForSize = false, + bool MergeExternalGlobals = false) + : FunctionPass(ID), TM(TM), MaxOffset(MaximalOffset), + OnlyOptimizeForSize(OnlyOptimizeForSize), + MergeExternalGlobals(MergeExternalGlobals) { initializeGlobalMergePass(*PassRegistry::getPassRegistry()); } @@ -181,14 +191,13 @@ INITIALIZE_PASS_END(GlobalMerge, "global-merge", "Merge global variables", bool GlobalMerge::doMerge(SmallVectorImpl &Globals, Module &M, bool isConst, unsigned AddrSpace) const { + auto &DL = M.getDataLayout(); // FIXME: Find better heuristics std::stable_sort(Globals.begin(), Globals.end(), - [this](const GlobalVariable *GV1, const GlobalVariable *GV2) { - Type *Ty1 = cast(GV1->getType())->getElementType(); - Type *Ty2 = cast(GV2->getType())->getElementType(); - - return (DL->getTypeAllocSize(Ty1) < DL->getTypeAllocSize(Ty2)); - }); + [&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) { @@ -199,7 +208,7 @@ bool GlobalMerge::doMerge(SmallVectorImpl &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 @@ -273,6 +282,8 @@ bool GlobalMerge::doMerge(SmallVectorImpl &Globals, // users, so look through ConstantExpr... Use *UI, *UE; if (ConstantExpr *CE = dyn_cast(U.getUser())) { + if (CE->use_empty()) + continue; UI = &*CE->use_begin(); UE = nullptr; } else if (isa(U.getUser())) { @@ -290,6 +301,11 @@ bool GlobalMerge::doMerge(SmallVectorImpl &Globals, continue; Function *ParentFn = I->getParent()->getParent(); + + // If we're only optimizing for size, ignore non-minsize functions. + if (OnlyOptimizeForSize && !ParentFn->optForMinSize()) + continue; + size_t UGSIdx = GlobalUsesByFunction[ParentFn]; // If this is the first global the basic block uses, map it to the set @@ -390,13 +406,13 @@ bool GlobalMerge::doMerge(SmallVectorImpl &Globals, return Changed; } -bool GlobalMerge::doMerge(SmallVectorImpl &Globals, +bool GlobalMerge::doMerge(const SmallVectorImpl &Globals, const BitVector &GlobalSet, Module &M, bool isConst, unsigned AddrSpace) const { + assert(Globals.size() > 1); Type *Int32Ty = Type::getInt32Ty(M.getContext()); - - assert(Globals.size() > 1); + auto &DL = M.getDataLayout(); DEBUG(dbgs() << " Trying to merge set, starts with #" << GlobalSet.find_first() << "\n"); @@ -408,40 +424,22 @@ bool GlobalMerge::doMerge(SmallVectorImpl &Globals, std::vector Tys; std::vector Inits; - bool HasExternal = false; - GlobalVariable *TheFirstExternal = 0; for (j = i; j != -1; j = GlobalSet.find_next(j)) { - Type *Ty = Globals[j]->getType()->getElementType(); - MergedSize += DL->getTypeAllocSize(Ty); + 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)) { GlobalValue::LinkageTypes Linkage = Globals[k]->getLinkage(); @@ -456,11 +454,15 @@ bool GlobalMerge::doMerge(SmallVectorImpl &Globals, Globals[k]->replaceAllUsesWith(GEP); Globals[k]->eraseFromParent(); - if (Linkage != GlobalValue::InternalLinkage) { - // Generate a new alias... + // 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()) { auto *PTy = cast(GEP->getType()); - GlobalAlias::create(PTy->getElementType(), PTy->getAddressSpace(), - Linkage, Name, GEP, &M); + GlobalAlias::create(PTy, Linkage, Name, GEP, &M); } NumMerged++; @@ -512,6 +514,7 @@ bool GlobalMerge::doInitialization(Module &M) { if (!EnableGlobalMerge) return false; + auto &DL = M.getDataLayout(); DenseMap > Globals, ConstGlobals, BSSGlobals; bool Changed = false; @@ -524,7 +527,7 @@ bool GlobalMerge::doInitialization(Module &M) { if (I->isDeclaration() || I->isThreadLocal() || I->hasSection()) continue; - if (!(EnableGlobalMergeOnExternal && I->hasExternalLinkage()) && + if (!(MergeExternalGlobals && I->hasExternalLinkage()) && !I->hasInternalLinkage()) continue; @@ -534,9 +537,9 @@ bool GlobalMerge::doInitialization(Module &M) { unsigned AddressSpace = PT->getAddressSpace(); // Ignore fancy-aligned globals for now. - unsigned Alignment = DL->getPreferredAlignment(I); - Type *Ty = I->getType()->getElementType(); - if (Alignment > DL->getABITypeAlignment(Ty)) + unsigned Alignment = DL.getPreferredAlignment(I); + Type *Ty = I->getValueType(); + if (Alignment > DL.getABITypeAlignment(Ty)) continue; // Ignore all 'special' globals. @@ -548,7 +551,7 @@ bool GlobalMerge::doInitialization(Module &M) { if (isMustKeepGlobalVariable(I)) continue; - if (DL->getTypeAllocSize(Ty) < MaxOffset) { + if (DL.getTypeAllocSize(Ty) < MaxOffset) { if (TargetLoweringObjectFile::getKindForGlobal(I, *TM).isBSSLocal()) BSSGlobals[AddressSpace].push_back(I); else if (I->isConstant()) @@ -558,21 +561,17 @@ bool GlobalMerge::doInitialization(Module &M) { } } - for (DenseMap >::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 >::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 >::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; } @@ -586,6 +585,10 @@ bool GlobalMerge::doFinalization(Module &M) { return false; } -Pass *llvm::createGlobalMergePass(const TargetMachine *TM, unsigned Offset) { - return new GlobalMerge(TM, Offset); +Pass *llvm::createGlobalMergePass(const TargetMachine *TM, unsigned Offset, + bool OnlyOptimizeForSize, + bool MergeExternalByDefault) { + bool MergeExternal = (EnableGlobalMergeOnExternal == cl::BOU_UNSET) ? + MergeExternalByDefault : (EnableGlobalMergeOnExternal == cl::BOU_TRUE); + return new GlobalMerge(TM, Offset, OnlyOptimizeForSize, MergeExternal); }