diff --git a/llvm/lib/Transforms/IPO/GlobalOpt.cpp b/llvm/lib/Transforms/IPO/GlobalOpt.cpp --- a/llvm/lib/Transforms/IPO/GlobalOpt.cpp +++ b/llvm/lib/Transforms/IPO/GlobalOpt.cpp @@ -342,6 +342,7 @@ /// loads and stores with the given type. struct GlobalPart { Type *Ty; + Constant *Initializer = nullptr; bool IsLoaded = false; bool IsStored = false; }; @@ -384,15 +385,27 @@ // TODO: We currently require that all accesses at a given offset must // use the same type. This could be relaxed. Type *Ty = getLoadStoreType(V); - auto It = Parts.try_emplace(Offset.getZExtValue(), GlobalPart{Ty}).first; + const auto &[It, Inserted] = + Parts.try_emplace(Offset.getZExtValue(), GlobalPart{Ty}); if (Ty != It->second.Ty) return false; + if (Inserted) { + It->second.Initializer = + ConstantFoldLoadFromConst(GV->getInitializer(), Ty, Offset, DL); + if (!It->second.Initializer) { + LLVM_DEBUG(dbgs() << "Global SRA: Failed to evaluate initializer of " + << *GV << " with type " << *Ty << " at offset " + << Offset.getZExtValue()); + return false; + } + } + // Scalable types not currently supported. if (isa(Ty)) return false; - auto IsStored = [GV, &DL, &Offset](Value *V) { + auto IsStored = [](Value *V, Constant *Initializer) { auto *SI = dyn_cast(V); if (!SI) return false; @@ -402,15 +415,11 @@ return true; // Don't consider stores that only write the initializer value. - if (Constant *Result = ConstantFoldLoadFromConst( - GV->getInitializer(), StoredConst->getType(), Offset, DL)) - return Result != StoredConst; - - return true; + return Initializer != StoredConst; }; It->second.IsLoaded |= isa(V); - It->second.IsStored |= IsStored(V); + It->second.IsStored |= IsStored(V, It->second.Initializer); continue; } @@ -531,14 +540,16 @@ return nullptr; // Sort by offset. - SmallVector, 16> TypesVector; - for (const auto &Pair : Parts) - TypesVector.push_back({Pair.first, Pair.second.Ty}); + SmallVector, 16> TypesVector; + for (const auto &Pair : Parts) { + TypesVector.push_back( + {Pair.first, Pair.second.Ty, Pair.second.Initializer}); + } sort(TypesVector, llvm::less_first()); // Check that the types are non-overlapping. uint64_t Offset = 0; - for (const auto &[OffsetForTy, Ty] : TypesVector) { + for (const auto &[OffsetForTy, Ty, _] : TypesVector) { // Overlaps with previous type. if (OffsetForTy < Offset) return nullptr; @@ -550,21 +561,6 @@ if (Offset > DL.getTypeAllocSize(GV->getValueType())) return nullptr; - // Collect initializers for new globals. - Constant *OrigInit = GV->getInitializer(); - DenseMap Initializers; - for (const auto &[OffsetForTy, Ty] : TypesVector) { - Constant *NewInit = - ConstantFoldLoadFromConst(OrigInit, Ty, APInt(64, OffsetForTy), DL); - if (!NewInit) { - LLVM_DEBUG(dbgs() << "Global SRA: Failed to evaluate initializer of " - << *GV << " with type " << *Ty << " at offset " - << OffsetForTy << "\n"); - return nullptr; - } - Initializers.insert({OffsetForTy, NewInit}); - } - LLVM_DEBUG(dbgs() << "PERFORMING GLOBAL SRA ON: " << *GV << "\n"); // Get the alignment of the global, either explicit or target-specific. @@ -575,11 +571,11 @@ // Create replacement globals. DenseMap NewGlobals; unsigned NameSuffix = 0; - for (auto &[OffsetForTy, Ty] : TypesVector) { + for (auto &[OffsetForTy, Ty, Initializer] : TypesVector) { GlobalVariable *NGV = new GlobalVariable( *GV->getParent(), Ty, false, GlobalVariable::InternalLinkage, - Initializers[OffsetForTy], GV->getName() + "." + Twine(NameSuffix++), - GV, GV->getThreadLocalMode(), GV->getAddressSpace()); + Initializer, GV->getName() + "." + Twine(NameSuffix++), GV, + GV->getThreadLocalMode(), GV->getAddressSpace()); NGV->copyAttributesFrom(GV); NewGlobals.insert({OffsetForTy, NGV});