Skip to content
This repository was archived by the owner on Nov 1, 2021. It is now read-only.

Commit 3517074

Browse files
committed
Respect alignment of nested bitfields
tools/clang/test/CodeGen/packed-nest-unpacked.c contains this test: struct XBitfield { unsigned b1 : 10; unsigned b2 : 12; unsigned b3 : 10; }; struct YBitfield { char x; struct XBitfield y; } __attribute((packed)); struct YBitfield gbitfield; unsigned test7() { // CHECK: @test7 // CHECK: load i32, i32* getelementptr inbounds (%struct.YBitfield, %struct.YBitfield* @gbitfield, i32 0, i32 1, i32 0), align 4 return gbitfield.y.b2; } The "align 4" is actually wrong. Accessing all of "gbitfield.y" as a single i32 is of course possible, but that still doesn't make it 4-byte aligned as it remains packed at offset 1 in the surrounding gbitfield object. This alignment was changed by commit r169489, which also introduced changes to bitfield access code in CGExpr.cpp. Code before that change used to take into account *both* the alignment of the field to be accessed within the current struct, *and* the alignment of that outer struct itself; this logic was removed by the above commit. Neglecting to consider both values can cause incorrect code to be generated (I've seen an unaligned access crash on SystemZ due to this bug). In order to always use the best known alignment value, this patch removes the CGBitFieldInfo::StorageAlignment member and replaces it with a StorageOffset member specifying the offset from the start of the surrounding struct to the bitfield's underlying storage. This offset can then be combined with the best-known alignment for a bitfield access lvalue to determine the alignment to use when accessing the bitfield's storage. Differential Revision: http://reviews.llvm.org/D11034 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@241916 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 8813b5b commit 3517074

8 files changed

+62
-42
lines changed

lib/CodeGen/CGAtomic.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ namespace {
9393
BFI = OrigBFI;
9494
BFI.Offset = Offset;
9595
BFI.StorageSize = AtomicSizeInBits;
96+
BFI.StorageOffset += OffsetInChars;
9697
LVal = LValue::MakeBitfield(Addr, BFI, lvalue.getType(),
9798
lvalue.getAlignment());
9899
LVal.setTBAAInfo(lvalue.getTBAAInfo());

lib/CodeGen/CGClass.cpp

+4-11
Original file line numberDiff line numberDiff line change
@@ -911,32 +911,22 @@ namespace {
911911
return;
912912
}
913913

914-
CharUnits Alignment;
915-
916914
uint64_t FirstByteOffset;
917915
if (FirstField->isBitField()) {
918916
const CGRecordLayout &RL =
919917
CGF.getTypes().getCGRecordLayout(FirstField->getParent());
920918
const CGBitFieldInfo &BFInfo = RL.getBitFieldInfo(FirstField);
921-
Alignment = CharUnits::fromQuantity(BFInfo.StorageAlignment);
922919
// FirstFieldOffset is not appropriate for bitfields,
923920
// it won't tell us what the storage offset should be and thus might not
924921
// be properly aligned.
925922
//
926923
// Instead calculate the storage offset using the offset of the field in
927924
// the struct type.
928-
const llvm::DataLayout &DL = CGF.CGM.getDataLayout();
929-
FirstByteOffset =
930-
DL.getStructLayout(RL.getLLVMType())
931-
->getElementOffsetInBits(RL.getLLVMFieldNo(FirstField));
925+
FirstByteOffset = CGF.getContext().toBits(BFInfo.StorageOffset);
932926
} else {
933-
Alignment = CGF.getContext().getDeclAlign(FirstField);
934927
FirstByteOffset = FirstFieldOffset;
935928
}
936929

937-
assert((CGF.getContext().toCharUnitsFromBits(FirstByteOffset) %
938-
Alignment) == 0 && "Bad field alignment.");
939-
940930
CharUnits MemcpySize = getMemcpySize(FirstByteOffset);
941931
QualType RecordTy = CGF.getContext().getTypeDeclType(ClassDecl);
942932
llvm::Value *ThisPtr = CGF.LoadCXXThis();
@@ -946,6 +936,9 @@ namespace {
946936
LValue SrcLV = CGF.MakeNaturalAlignAddrLValue(SrcPtr, RecordTy);
947937
LValue Src = CGF.EmitLValueForFieldInitialization(SrcLV, FirstField);
948938

939+
CharUnits Offset = CGF.getContext().toCharUnitsFromBits(FirstByteOffset);
940+
CharUnits Alignment = DestLV.getAlignment().alignmentAtOffset(Offset);
941+
949942
emitMemcpyIR(Dest.isBitField() ? Dest.getBitFieldAddr() : Dest.getAddress(),
950943
Src.isBitField() ? Src.getBitFieldAddr() : Src.getAddress(),
951944
MemcpySize, Alignment);

lib/CodeGen/CGExpr.cpp

+10-9
Original file line numberDiff line numberDiff line change
@@ -1356,14 +1356,15 @@ RValue CodeGenFunction::EmitLoadOfLValue(LValue LV, SourceLocation Loc) {
13561356

13571357
RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV) {
13581358
const CGBitFieldInfo &Info = LV.getBitFieldInfo();
1359+
CharUnits Align = LV.getAlignment().alignmentAtOffset(Info.StorageOffset);
13591360

13601361
// Get the output type.
13611362
llvm::Type *ResLTy = ConvertType(LV.getType());
13621363

13631364
llvm::Value *Ptr = LV.getBitFieldAddr();
1364-
llvm::Value *Val = Builder.CreateLoad(Ptr, LV.isVolatileQualified(),
1365-
"bf.load");
1366-
cast<llvm::LoadInst>(Val)->setAlignment(Info.StorageAlignment);
1365+
llvm::Value *Val = Builder.CreateAlignedLoad(Ptr, Align.getQuantity(),
1366+
LV.isVolatileQualified(),
1367+
"bf.load");
13671368

13681369
if (Info.IsSigned) {
13691370
assert(static_cast<unsigned>(Info.Offset + Info.Size) <= Info.StorageSize);
@@ -1559,6 +1560,7 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst,
15591560
void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst,
15601561
llvm::Value **Result) {
15611562
const CGBitFieldInfo &Info = Dst.getBitFieldInfo();
1563+
CharUnits Align = Dst.getAlignment().alignmentAtOffset(Info.StorageOffset);
15621564
llvm::Type *ResLTy = ConvertTypeForMem(Dst.getType());
15631565
llvm::Value *Ptr = Dst.getBitFieldAddr();
15641566

@@ -1575,9 +1577,9 @@ void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst,
15751577
// and mask together with source before storing.
15761578
if (Info.StorageSize != Info.Size) {
15771579
assert(Info.StorageSize > Info.Size && "Invalid bitfield size.");
1578-
llvm::Value *Val = Builder.CreateLoad(Ptr, Dst.isVolatileQualified(),
1579-
"bf.load");
1580-
cast<llvm::LoadInst>(Val)->setAlignment(Info.StorageAlignment);
1580+
llvm::Value *Val = Builder.CreateAlignedLoad(Ptr, Align.getQuantity(),
1581+
Dst.isVolatileQualified(),
1582+
"bf.load");
15811583

15821584
// Mask the source value as needed.
15831585
if (!hasBooleanRepresentation(Dst.getType()))
@@ -1603,9 +1605,8 @@ void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst,
16031605
}
16041606

16051607
// Write the new value back out.
1606-
llvm::StoreInst *Store = Builder.CreateStore(SrcVal, Ptr,
1607-
Dst.isVolatileQualified());
1608-
Store->setAlignment(Info.StorageAlignment);
1608+
Builder.CreateAlignedStore(SrcVal, Ptr, Align.getQuantity(),
1609+
Dst.isVolatileQualified());
16091610

16101611
// Return the new value of the bit-field, if requested.
16111612
if (Result) {

lib/CodeGen/CGObjCRuntime.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF,
134134
CGBitFieldInfo *Info = new (CGF.CGM.getContext()) CGBitFieldInfo(
135135
CGBitFieldInfo::MakeInfo(CGF.CGM.getTypes(), Ivar, BitOffset, BitFieldSize,
136136
CGF.CGM.getContext().toBits(StorageSize),
137-
Alignment.getQuantity()));
137+
CharUnits::fromQuantity(0)));
138138

139139
V = CGF.Builder.CreateBitCast(V,
140140
llvm::Type::getIntNPtrTy(CGF.getLLVMContext(),

lib/CodeGen/CGRecordLayout.h

+6-6
Original file line numberDiff line numberDiff line change
@@ -78,16 +78,16 @@ struct CGBitFieldInfo {
7878
/// bitfield.
7979
unsigned StorageSize;
8080

81-
/// The alignment which should be used when accessing the bitfield.
82-
unsigned StorageAlignment;
81+
/// The offset of the bitfield storage from the start of the struct.
82+
CharUnits StorageOffset;
8383

8484
CGBitFieldInfo()
85-
: Offset(), Size(), IsSigned(), StorageSize(), StorageAlignment() {}
85+
: Offset(), Size(), IsSigned(), StorageSize(), StorageOffset() {}
8686

8787
CGBitFieldInfo(unsigned Offset, unsigned Size, bool IsSigned,
88-
unsigned StorageSize, unsigned StorageAlignment)
88+
unsigned StorageSize, CharUnits StorageOffset)
8989
: Offset(Offset), Size(Size), IsSigned(IsSigned),
90-
StorageSize(StorageSize), StorageAlignment(StorageAlignment) {}
90+
StorageSize(StorageSize), StorageOffset(StorageOffset) {}
9191

9292
void print(raw_ostream &OS) const;
9393
void dump() const;
@@ -99,7 +99,7 @@ struct CGBitFieldInfo {
9999
const FieldDecl *FD,
100100
uint64_t Offset, uint64_t Size,
101101
uint64_t StorageSize,
102-
uint64_t StorageAlignment);
102+
CharUnits StorageOffset);
103103
};
104104

105105
/// CGRecordLayout - This class handles struct and union layout info while

lib/CodeGen/CGRecordLayoutBuilder.cpp

+4-8
Original file line numberDiff line numberDiff line change
@@ -228,11 +228,7 @@ void CGRecordLowering::setBitFieldInfo(
228228
Info.Offset = (unsigned)(getFieldBitOffset(FD) - Context.toBits(StartOffset));
229229
Info.Size = FD->getBitWidthValue(Context);
230230
Info.StorageSize = (unsigned)DataLayout.getTypeAllocSizeInBits(StorageType);
231-
// Here we calculate the actual storage alignment of the bits. E.g if we've
232-
// got an alignment >= 2 and the bitfield starts at offset 6 we've got an
233-
// alignment of 2.
234-
Info.StorageAlignment =
235-
Layout.getAlignment().alignmentAtOffset(StartOffset).getQuantity();
231+
Info.StorageOffset = StartOffset;
236232
if (Info.Size > Info.StorageSize)
237233
Info.Size = Info.StorageSize;
238234
// Reverse the bit offsets for big endian machines. Because we represent
@@ -651,7 +647,7 @@ CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types,
651647
const FieldDecl *FD,
652648
uint64_t Offset, uint64_t Size,
653649
uint64_t StorageSize,
654-
uint64_t StorageAlignment) {
650+
CharUnits StorageOffset) {
655651
// This function is vestigial from CGRecordLayoutBuilder days but is still
656652
// used in GCObjCRuntime.cpp. That usage has a "fixme" attached to it that
657653
// when addressed will allow for the removal of this function.
@@ -683,7 +679,7 @@ CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types,
683679
Offset = StorageSize - (Offset + Size);
684680
}
685681

686-
return CGBitFieldInfo(Offset, Size, IsSigned, StorageSize, StorageAlignment);
682+
return CGBitFieldInfo(Offset, Size, IsSigned, StorageSize, StorageOffset);
687683
}
688684

689685
CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D,
@@ -856,7 +852,7 @@ void CGBitFieldInfo::print(raw_ostream &OS) const {
856852
<< " Size:" << Size
857853
<< " IsSigned:" << IsSigned
858854
<< " StorageSize:" << StorageSize
859-
<< " StorageAlignment:" << StorageAlignment << ">";
855+
<< " StorageOffset:" << StorageOffset.getQuantity() << ">";
860856
}
861857

862858
void CGBitFieldInfo::dump() const {

test/CodeGen/bitfield-2.c

+6-6
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
// CHECK-RECORD: LLVMType:%struct.s0 = type { [3 x i8] }
1515
// CHECK-RECORD: IsZeroInitializable:1
1616
// CHECK-RECORD: BitFields:[
17-
// CHECK-RECORD: <CGBitFieldInfo Offset:0 Size:24 IsSigned:1 StorageSize:24 StorageAlignment:1>
17+
// CHECK-RECORD: <CGBitFieldInfo Offset:0 Size:24 IsSigned:1 StorageSize:24 StorageOffset:0>
1818
struct __attribute((packed)) s0 {
1919
int f0 : 24;
2020
};
@@ -54,8 +54,8 @@ unsigned long long test_0() {
5454
// CHECK-RECORD: LLVMType:%struct.s1 = type { [3 x i8] }
5555
// CHECK-RECORD: IsZeroInitializable:1
5656
// CHECK-RECORD: BitFields:[
57-
// CHECK-RECORD: <CGBitFieldInfo Offset:0 Size:10 IsSigned:1 StorageSize:24 StorageAlignment:1>
58-
// CHECK-RECORD: <CGBitFieldInfo Offset:10 Size:10 IsSigned:1 StorageSize:24 StorageAlignment:1>
57+
// CHECK-RECORD: <CGBitFieldInfo Offset:0 Size:10 IsSigned:1 StorageSize:24 StorageOffset:0>
58+
// CHECK-RECORD: <CGBitFieldInfo Offset:10 Size:10 IsSigned:1 StorageSize:24 StorageOffset:0>
5959

6060
#pragma pack(push)
6161
#pragma pack(1)
@@ -102,7 +102,7 @@ unsigned long long test_1() {
102102
// CHECK-RECORD: LLVMType:%union.u2 = type { i8 }
103103
// CHECK-RECORD: IsZeroInitializable:1
104104
// CHECK-RECORD: BitFields:[
105-
// CHECK-RECORD: <CGBitFieldInfo Offset:0 Size:3 IsSigned:0 StorageSize:8 StorageAlignment:1>
105+
// CHECK-RECORD: <CGBitFieldInfo Offset:0 Size:3 IsSigned:0 StorageSize:8 StorageOffset:0>
106106

107107
union __attribute__((packed)) u2 {
108108
unsigned long long f0 : 3;
@@ -274,8 +274,8 @@ _Bool test_6() {
274274
// CHECK-RECORD: LLVMType:%struct.s7 = type { i32, i32, i32, i8, i32, [12 x i8] }
275275
// CHECK-RECORD: IsZeroInitializable:1
276276
// CHECK-RECORD: BitFields:[
277-
// CHECK-RECORD: <CGBitFieldInfo Offset:0 Size:5 IsSigned:1 StorageSize:8 StorageAlignment:4>
278-
// CHECK-RECORD: <CGBitFieldInfo Offset:0 Size:29 IsSigned:1 StorageSize:32 StorageAlignment:16>
277+
// CHECK-RECORD: <CGBitFieldInfo Offset:0 Size:5 IsSigned:1 StorageSize:8 StorageOffset:12>
278+
// CHECK-RECORD: <CGBitFieldInfo Offset:0 Size:29 IsSigned:1 StorageSize:32 StorageOffset:16>
279279

280280
struct __attribute__((aligned(16))) s7 {
281281
int a, b, c;

test/CodeGen/packed-nest-unpacked.c

+30-1
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,35 @@ struct YBitfield gbitfield;
6060

6161
unsigned test7() {
6262
// CHECK: @test7
63-
// CHECK: load i32, i32* getelementptr inbounds (%struct.YBitfield, %struct.YBitfield* @gbitfield, i32 0, i32 1, i32 0), align 4
63+
// CHECK: load i32, i32* getelementptr inbounds (%struct.YBitfield, %struct.YBitfield* @gbitfield, i32 0, i32 1, i32 0), align 1
6464
return gbitfield.y.b2;
6565
}
66+
67+
void test8(unsigned x) {
68+
// CHECK: @test8
69+
// CHECK: load i32, i32* getelementptr inbounds (%struct.YBitfield, %struct.YBitfield* @gbitfield, i32 0, i32 1, i32 0), align 1
70+
// CHECK: store i32 {{.*}}, i32* getelementptr inbounds (%struct.YBitfield, %struct.YBitfield* @gbitfield, i32 0, i32 1, i32 0), align 1
71+
gbitfield.y.b2 = x;
72+
}
73+
74+
struct TBitfield
75+
{
76+
long a;
77+
char b;
78+
unsigned c:15;
79+
};
80+
struct TBitfield tbitfield;
81+
82+
unsigned test9() {
83+
// CHECK: @test9
84+
// CHECK: load i16, i16* getelementptr inbounds (%struct.TBitfield, %struct.TBitfield* @tbitfield, i32 0, i32 2), align 1
85+
return tbitfield.c;
86+
}
87+
88+
void test10(unsigned x) {
89+
// CHECK: @test10
90+
// CHECK: load i16, i16* getelementptr inbounds (%struct.TBitfield, %struct.TBitfield* @tbitfield, i32 0, i32 2), align 1
91+
// CHECK: store i16 {{.*}}, i16* getelementptr inbounds (%struct.TBitfield, %struct.TBitfield* @tbitfield, i32 0, i32 2), align 1
92+
tbitfield.c = x;
93+
}
94+

0 commit comments

Comments
 (0)