[GlobalOpt] Collect initializer when building GlobalPart.
Update the code to collect the initializer when collecting the types for a global, as suggested by @nikic in D144476. This replaces code which bailed out if *any* part doesn't have an initializer with a continue to just skip parts which don't have an initializer. Depends on D145489. Reviewed By: nikic Differential Revision: https://reviews.llvm.org/D145490
This commit is contained in:
parent
ef860cf150
commit
84870c4abb
|
@ -342,6 +342,7 @@ static bool CleanupConstantGlobalUsers(GlobalVariable *GV,
|
|||
/// loads and stores with the given type.
|
||||
struct GlobalPart {
|
||||
Type *Ty;
|
||||
Constant *Initializer = nullptr;
|
||||
bool IsLoaded = false;
|
||||
bool IsStored = false;
|
||||
};
|
||||
|
@ -384,15 +385,27 @@ static bool collectSRATypes(DenseMap<uint64_t, GlobalPart> &Parts,
|
|||
// 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<ScalableVectorType>(Ty))
|
||||
return false;
|
||||
|
||||
auto IsStored = [GV, &DL, &Offset](Value *V) {
|
||||
auto IsStored = [](Value *V, Constant *Initializer) {
|
||||
auto *SI = dyn_cast<StoreInst>(V);
|
||||
if (!SI)
|
||||
return false;
|
||||
|
@ -402,15 +415,11 @@ static bool collectSRATypes(DenseMap<uint64_t, GlobalPart> &Parts,
|
|||
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<LoadInst>(V);
|
||||
It->second.IsStored |= IsStored(V);
|
||||
It->second.IsStored |= IsStored(V, It->second.Initializer);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -531,14 +540,16 @@ static GlobalVariable *SRAGlobal(GlobalVariable *GV, const DataLayout &DL) {
|
|||
return nullptr;
|
||||
|
||||
// Sort by offset.
|
||||
SmallVector<std::pair<uint64_t, Type *>, 16> TypesVector;
|
||||
for (const auto &Pair : Parts)
|
||||
TypesVector.push_back({Pair.first, Pair.second.Ty});
|
||||
SmallVector<std::tuple<uint64_t, Type *, Constant *>, 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 @@ static GlobalVariable *SRAGlobal(GlobalVariable *GV, const DataLayout &DL) {
|
|||
if (Offset > DL.getTypeAllocSize(GV->getValueType()))
|
||||
return nullptr;
|
||||
|
||||
// Collect initializers for new globals.
|
||||
Constant *OrigInit = GV->getInitializer();
|
||||
DenseMap<uint64_t, Constant *> 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 @@ static GlobalVariable *SRAGlobal(GlobalVariable *GV, const DataLayout &DL) {
|
|||
// Create replacement globals.
|
||||
DenseMap<uint64_t, GlobalVariable *> 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});
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user