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(); LLVM_DEBUG(dbgs() << " Trying to merge set, starts with #" << GlobalSet.find_first() << "\n"); bool Changed = false; ssize_t i = GlobalSet.find_first(); while (i != -1) { ssize_t j = 0; uint64_t MergedSize = 0; std::vector<Type*> Tys; std::vector<Constant*> Inits; bool HasExternal = false; StringRef FirstExternalName; for (j = i; j != -1; j = GlobalSet.find_next(j)) { 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; FirstExternalName = Globals[j]->getName(); } } // Exit early if there is only one global to merge. if (Tys.size() < 2) { i = j; continue; } // 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); // On Darwin external linkage needs to be preserved, otherwise // dsymutil cannot preserve the debug info for the merged // variables. If they have external linkage, use the symbol name // of the first variable merged as the suffix of global symbol // name. This avoids a link-time naming conflict for the // _MergedGlobals symbols. Twine MergedName = (IsMachO && HasExternal) ? "_MergedGlobals_" + FirstExternalName : "_MergedGlobals"; auto MergedLinkage = IsMachO ? Linkage : GlobalValue::PrivateLinkage; auto *MergedGV = new GlobalVariable( M, MergedTy, isConst, MergedLinkage, MergedInit, MergedName, nullptr, GlobalVariable::NotThreadLocal, AddrSpace); const StructLayout *MergedLayout = DL.getStructLayout(MergedTy); 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(); GlobalValue::DLLStorageClassTypes DLLStorage = Globals[k]->getDLLStorageClass(); // Copy metadata while adjusting any debug info metadata by the original // global's offset within the merged global. MergedGV->copyMetadata(Globals[k], MergedLayout->getElementOffset(idx)); Constant *Idx[2] = { ConstantInt::get(Int32Ty, 0), ConstantInt::get(Int32Ty, idx), }; Constant *GEP = ConstantExpr::getInBoundsGetElementPtr(MergedTy, MergedGV, Idx); Globals[k]->replaceAllUsesWith(GEP); Globals[k]->eraseFromParent(); // 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 || !IsMachO) { GlobalAlias *GA = GlobalAlias::create(Tys[idx], AddrSpace, Linkage, Name, GEP, &M); GA->setDLLStorageClass(DLLStorage); } NumMerged++; } Changed = true; i = j; } return Changed; }