Index: llvm/lib/Transforms/IPO/GlobalDCE.cpp =================================================================== --- llvm/lib/Transforms/IPO/GlobalDCE.cpp +++ llvm/lib/Transforms/IPO/GlobalDCE.cpp @@ -286,6 +286,44 @@ ); } +static int compareNames(Constant *const *A, Constant *const *B) { + Value *AStripped = (*A)->stripPointerCasts(); + Value *BStripped = (*B)->stripPointerCasts(); + return AStripped->getName().compare(BStripped->getName()); +} + +static GlobalVariable * +setUsedInitializer(GlobalVariable &V, + const SmallPtrSetImpl &Init) { + if (Init.empty()) { + V.eraseFromParent(); + return nullptr; + } + + // Type of pointer to the array of pointers. + PointerType *Int8PtrTy = Type::getInt8PtrTy(V.getContext(), 0); + + SmallVector UsedArray; + for (GlobalValue *GV : Init) { + Constant *Cast = + ConstantExpr::getPointerBitCastOrAddrSpaceCast(GV, 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, GlobalValue::AppendingLinkage, + ConstantArray::get(ATy, UsedArray), ""); + NV->takeName(&V); + NV->setSection("llvm.metadata"); + delete &V; + return NV; +} + PreservedAnalyses GlobalDCEPass::run(Module &M, ModuleAnalysisManager &MAM) { bool Changed = false; @@ -315,6 +353,42 @@ // might call, if we have that information. AddVirtualFunctionDependencies(M); + auto *LTOPostLinkMD = + cast_or_null(M.getModuleFlag("LTOPostLink")); + bool LTOPostLink = + LTOPostLinkMD && + (cast(LTOPostLinkMD->getValue())->getZExtValue() != 0); + + auto *Used = M.getGlobalVariable("llvm.used"); + auto *UsedConditional = M.getNamedMetadata("llvm.used.conditional"); + if (UsedConditional && UsedConditional->getNumOperands() == 0) + UsedConditional = nullptr; + SmallPtrSet NewUsedArray; + if (LTOPostLink && Used) { + // Construct a set of conditionally used targets. + SmallPtrSet UsedConditionalTargets; + if (UsedConditional) { + for (auto *M : UsedConditional->operands()) { + assert(M->getNumOperands() == 3); + auto *V = mdconst::extract_or_null(M->getOperand(0)); + if (!V) + continue; + UsedConditionalTargets.insert(V); + } + } + + // Strip away all conditionally used targets from @llvm.used. + const ConstantArray *Init = cast(Used->getInitializer()); + for (Value *Op : Init->operands()) { + GlobalValue *G = cast(Op->stripPointerCasts()); + // G is one of the conditional targets, don't mark it as live. + if (UsedConditionalTargets.contains(G)) + continue; + NewUsedArray.insert(G); + } + Used = setUsedInitializer(*Used, NewUsedArray); + } + // Loop over the module, adding globals which are obviously necessary. for (GlobalObject &GO : M.global_objects()) { Changed |= RemoveUnusedGlobalValue(GO); @@ -348,6 +422,83 @@ UpdateGVDependencies(GIF); } + // We need to repeat this, if a conditional used variable is marked alive and + // added to NewUsedArray, we should check if that will enable other + // conditional used variables to become alive. + bool HasUpdateInIteration = true; + while (LTOPostLink && Used && UsedConditional && HasUpdateInIteration) { + // Propagate liveness from collected Global Values through the computed + // dependencies. + SmallVector NewLiveGVs{AliveGlobals.begin(), + AliveGlobals.end()}; + while (!NewLiveGVs.empty()) { + GlobalValue *LGV = NewLiveGVs.pop_back_val(); + for (auto *GVD : GVDependencies[LGV]) { + MarkLive(*GVD, &NewLiveGVs); + } + } + + unsigned oldSize = NewUsedArray.size(); + for (auto *M : UsedConditional->operands()) { + assert(M->getNumOperands() == 3); + auto *V = mdconst::extract_or_null(M->getOperand(0)); + if (!V) + continue; + + auto *T = mdconst::extract_or_null(M->getOperand(1)); + if (!T) + continue; + APInt type = T->getValue(); + + SmallPtrSet Others; + if (M->getOperand(2) == nullptr) { + Others.insert(nullptr); + } else { + if (auto *SingleOther = + mdconst::dyn_extract_or_null(M->getOperand(2))) { + Others.insert(SingleOther); + } else { + Metadata *MultipleOthers = M->getOperand(2).get(); + MDNode *node = dyn_cast_or_null(MultipleOthers); + for (auto &x : node->operands()) { + auto *y = x.get(); + if (!y) + continue; + auto *C = mdconst::extract_or_null(y); + C = C->stripPointerCasts(); + auto *O = cast(C); + Others.insert(O); + } + } + } + + bool allOthersAlive = true; + bool anyOtherAlive = false; + for (auto *GV : Others) { + bool live = AliveGlobals.count(GV) != 0; + if (live) + anyOtherAlive = true; + else + allOthersAlive = false; + } + + if ((type == 0 && anyOtherAlive) || (type == 1 && allOthersAlive)) { + NewUsedArray.insert(V); + MarkLive(*V); + LLVM_DEBUG(dbgs() << "Mark conditional used GV " << V->getName() + << " to be live.\n"); + } + } + LLVM_DEBUG(dbgs() << "Optimizing UsedConditional iteration end " << oldSize + << ' ' << NewUsedArray.size() << "\n"); + HasUpdateInIteration = NewUsedArray.size() > oldSize; + } + if (LTOPostLink && Used && UsedConditional) { + + Used = setUsedInitializer(*Used, NewUsedArray); + MarkLive(*Used); + } + // Propagate liveness from collected Global Values through the computed // dependencies. SmallVector NewLiveGVs{AliveGlobals.begin(),