[GlobalMerge] Allow merging globals with arbitrary alignment.

Instead of depending on implicit padding from the structure layout code,
use a packed struct and emit the padding explicitly.

Differential Revision: https://reviews.llvm.org/D49710

llvm-svn: 337961
This commit is contained in:
Eli Friedman 2018-07-25 20:58:01 +00:00
parent c55ac1055a
commit 0887cf9cab
5 changed files with 74 additions and 24 deletions

View File

@ -440,6 +440,7 @@ bool GlobalMerge::doMerge(const SmallVectorImpl<GlobalVariable *> &Globals,
assert(Globals.size() > 1);
Type *Int32Ty = Type::getInt32Ty(M.getContext());
Type *Int8Ty = Type::getInt8Ty(M.getContext());
auto &DL = M.getDataLayout();
LLVM_DEBUG(dbgs() << " Trying to merge set, starts with #"
@ -452,17 +453,31 @@ bool GlobalMerge::doMerge(const SmallVectorImpl<GlobalVariable *> &Globals,
uint64_t MergedSize = 0;
std::vector<Type*> Tys;
std::vector<Constant*> Inits;
std::vector<unsigned> StructIdxs;
bool HasExternal = false;
StringRef FirstExternalName;
unsigned MaxAlign = 1;
unsigned CurIdx = 0;
for (j = i; j != -1; j = GlobalSet.find_next(j)) {
Type *Ty = Globals[j]->getValueType();
unsigned Align = DL.getPreferredAlignment(Globals[j]);
unsigned Padding = alignTo(MergedSize, Align) - MergedSize;
MergedSize += Padding;
MergedSize += DL.getTypeAllocSize(Ty);
if (MergedSize > MaxOffset) {
break;
}
if (Padding) {
Tys.push_back(ArrayType::get(Int8Ty, Padding));
Inits.push_back(ConstantAggregateZero::get(Tys.back()));
++CurIdx;
}
Tys.push_back(Ty);
Inits.push_back(Globals[j]->getInitializer());
StructIdxs.push_back(CurIdx++);
MaxAlign = std::max(MaxAlign, Align);
if (Globals[j]->hasExternalLinkage() && !HasExternal) {
HasExternal = true;
@ -481,7 +496,8 @@ bool GlobalMerge::doMerge(const SmallVectorImpl<GlobalVariable *> &Globals,
GlobalValue::LinkageTypes Linkage = HasExternal
? GlobalValue::ExternalLinkage
: GlobalValue::InternalLinkage;
StructType *MergedTy = StructType::get(M.getContext(), Tys);
// Use a packed struct so we can control alignment.
StructType *MergedTy = StructType::get(M.getContext(), Tys, true);
Constant *MergedInit = ConstantStruct::get(MergedTy, Inits);
// On Darwin external linkage needs to be preserved, otherwise
@ -499,13 +515,9 @@ bool GlobalMerge::doMerge(const SmallVectorImpl<GlobalVariable *> &Globals,
M, MergedTy, isConst, MergedLinkage, MergedInit, MergedName, nullptr,
GlobalVariable::NotThreadLocal, AddrSpace);
const StructLayout *MergedLayout = DL.getStructLayout(MergedTy);
// Set the alignment of the merged struct as the maximum alignment of the
// globals to prevent over-alignment. We don't handle globals that are not
// default aligned, so the alignment of the MergedLayout struct is
// equivalent.
MergedGV->setAlignment(MergedLayout->getAlignment());
MergedGV->setAlignment(MaxAlign);
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();
@ -514,11 +526,12 @@ bool GlobalMerge::doMerge(const SmallVectorImpl<GlobalVariable *> &Globals,
// 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));
MergedGV->copyMetadata(Globals[k],
MergedLayout->getElementOffset(StructIdxs[idx]));
Constant *Idx[2] = {
ConstantInt::get(Int32Ty, 0),
ConstantInt::get(Int32Ty, idx),
ConstantInt::get(Int32Ty, 0),
ConstantInt::get(Int32Ty, StructIdxs[idx]),
};
Constant *GEP =
ConstantExpr::getInBoundsGetElementPtr(MergedTy, MergedGV, Idx);
@ -531,8 +544,8 @@ bool GlobalMerge::doMerge(const SmallVectorImpl<GlobalVariable *> &Globals,
// 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);
GlobalAlias *GA = GlobalAlias::create(Tys[StructIdxs[idx]], AddrSpace,
Linkage, Name, GEP, &M);
GA->setDLLStorageClass(DLLStorage);
}
@ -610,12 +623,6 @@ bool GlobalMerge::doInitialization(Module &M) {
unsigned AddressSpace = PT->getAddressSpace();
// Ignore fancy-aligned globals for now.
unsigned Alignment = DL.getPreferredAlignment(&GV);
Type *Ty = GV.getValueType();
if (Alignment > DL.getABITypeAlignment(Ty))
continue;
// Ignore all 'special' globals.
if (GV.getName().startswith("llvm.") ||
GV.getName().startswith(".llvm."))
@ -625,6 +632,7 @@ bool GlobalMerge::doInitialization(Module &M) {
if (isMustKeepGlobalVariable(&GV))
continue;
Type *Ty = GV.getValueType();
if (DL.getTypeAllocSize(Ty) < MaxOffset) {
if (TM &&
TargetLoweringObjectFile::getKindForGlobal(&GV, *TM).isBSSLocal())

View File

@ -0,0 +1,22 @@
; RUN: opt -global-merge -global-merge-max-offset=100 -S -o - %s | FileCheck %s
target datalayout = "e-p:64:64"
target triple = "x86_64-unknown-linux-gnu"
; This produces align 4, not the obvious align 1, to be consistent with what
; the AsmPrinter would do.
; CHECK: @_MergedGlobals = private global <{ [2 x i32], [2 x i32] }> <{ [2 x i32] [i32 1, i32 1], [2 x i32] [i32 2, i32 2] }>, align 4
; CHECK: @a = internal alias [2 x i32], getelementptr inbounds (<{ [2 x i32], [2 x i32] }>, <{ [2 x i32], [2 x i32] }>* @_MergedGlobals, i32 0, i32 0)
@a = internal global [2 x i32] [i32 1, i32 1], align 1
; CHECK: @b = internal alias [2 x i32], getelementptr inbounds (<{ [2 x i32], [2 x i32] }>, <{ [2 x i32], [2 x i32] }>* @_MergedGlobals, i32 0, i32 1)
@b = internal global [2 x i32] [i32 2, i32 2], align 1
define void @use() {
; CHECK: load i32, i32* getelementptr inbounds (<{ [2 x i32], [2 x i32] }>, <{ [2 x i32], [2 x i32] }>* @_MergedGlobals, i32 0, i32 0, i32 0)
%x = load i32, i32* bitcast ([2 x i32]* @a to i32*)
; CHECK: load i32, i32* getelementptr inbounds (<{ [2 x i32], [2 x i32] }>, <{ [2 x i32], [2 x i32] }>* @_MergedGlobals, i32 0, i32 1, i32 0)
%y = load i32, i32* bitcast ([2 x i32]* @b to i32*)
ret void
}

View File

@ -0,0 +1,20 @@
; RUN: opt -global-merge -global-merge-max-offset=100 -S -o - %s | FileCheck %s
target datalayout = "e-p:64:64"
target triple = "x86_64-unknown-linux-gnu"
; CHECK: @_MergedGlobals = private global <{ [5 x i8], [3 x i8], [2 x i32] }> <{ [5 x i8] c"\01\01\01\01\01", [3 x i8] zeroinitializer, [2 x i32] [i32 2, i32 2] }>, align 4
; CHECK: @a = internal alias [5 x i8], getelementptr inbounds (<{ [5 x i8], [3 x i8], [2 x i32] }>, <{ [5 x i8], [3 x i8], [2 x i32] }>* @_MergedGlobals, i32 0, i32 0)
@a = internal global [5 x i8] [i8 1, i8 1, i8 1, i8 1, i8 1], align 4
; CHECK: @b = internal alias [2 x i32], getelementptr inbounds (<{ [5 x i8], [3 x i8], [2 x i32] }>, <{ [5 x i8], [3 x i8], [2 x i32] }>* @_MergedGlobals, i32 0, i32 2)
@b = internal global [2 x i32] [i32 2, i32 2]
define void @use() {
; CHECK: load i32, i32* bitcast (<{ [5 x i8], [3 x i8], [2 x i32] }>* @_MergedGlobals to i32*)
%x = load i32, i32* bitcast ([5 x i8]* @a to i32*)
; CHECK: load i32, i32* getelementptr inbounds (<{ [5 x i8], [3 x i8], [2 x i32] }>, <{ [5 x i8], [3 x i8], [2 x i32] }>* @_MergedGlobals, i32 0, i32 2, i32 0)
%y = load i32, i32* bitcast ([2 x i32]* @b to i32*)
ret void
}

View File

@ -3,18 +3,18 @@
target datalayout = "e-p:64:64"
target triple = "x86_64-unknown-linux-gnu"
; CHECK: @_MergedGlobals = private global { i32, i32 } { i32 1, i32 2 }
; CHECK: @_MergedGlobals = private global <{ i32, i32 }> <{ i32 1, i32 2 }>, align 4
; CHECK: @a = internal alias i32, getelementptr inbounds ({ i32, i32 }, { i32, i32 }* @_MergedGlobals, i32 0, i32 0)
; CHECK: @a = internal alias i32, getelementptr inbounds (<{ i32, i32 }>, <{ i32, i32 }>* @_MergedGlobals, i32 0, i32 0)
@a = internal global i32 1
; CHECK: @b = internal alias i32, getelementptr inbounds ({ i32, i32 }, { i32, i32 }* @_MergedGlobals, i32 0, i32 1)
; CHECK: @b = internal alias i32, getelementptr inbounds (<{ i32, i32 }>, <{ i32, i32 }>* @_MergedGlobals, i32 0, i32 1)
@b = internal global i32 2
define void @use() {
; CHECK: load i32, i32* getelementptr inbounds ({ i32, i32 }, { i32, i32 }* @_MergedGlobals, i32 0, i32 0)
; CHECK: load i32, i32* getelementptr inbounds (<{ i32, i32 }>, <{ i32, i32 }>* @_MergedGlobals, i32 0, i32 0)
%x = load i32, i32* @a
; CHECK: load i32, i32* getelementptr inbounds ({ i32, i32 }, { i32, i32 }* @_MergedGlobals, i32 0, i32 1)
; CHECK: load i32, i32* getelementptr inbounds (<{ i32, i32 }>, <{ i32, i32 }>* @_MergedGlobals, i32 0, i32 1)
%y = load i32, i32* @b
ret void
}

View File

@ -3,7 +3,7 @@
source_filename = "test/Transforms/GlobalMerge/debug-info.ll"
target datalayout = "e-p:64:64"
target triple = "x86_64-unknown-linux-gnu"
; CHECK: @_MergedGlobals = private global { i32, i32 } { i32 1, i32 2 }, align 4, !dbg [[A:![0-9]+]], !dbg [[B:![0-9]+]]
; CHECK: @_MergedGlobals = private global <{ i32, i32 }> <{ i32 1, i32 2 }>, align 4, !dbg [[A:![0-9]+]], !dbg [[B:![0-9]+]]
@a = internal global i32 1, !dbg !0
@b = internal global i32 2, !dbg !2