Skip to content

Commit 2ac198d

Browse files
committed
IRGen: Use packed structs to accurately lay out aggregate types.
LLVM's normal data layout doesn't jive with our own StructLayout's more aggressive use of padding space, and causes problems such as <rdar://problem/14336903>. Because we do our own alignment and stride management, we can safely use LLVM packed struct types with manual padding to get the level of control we need to accurately reflect our desired struct layout. Swift SVN r9056
1 parent 5cfdb86 commit 2ac198d

File tree

6 files changed

+37
-42
lines changed

6 files changed

+37
-42
lines changed

lib/IRGen/GenEnum.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2852,7 +2852,7 @@ namespace {
28522852
EnumDecl *theEnum,
28532853
llvm::StructType *enumTy) {
28542854
if (ElementsWithPayload.empty()) {
2855-
enumTy->setBody(ArrayRef<llvm::Type*>{});
2855+
enumTy->setBody(ArrayRef<llvm::Type*>{}, /*isPacked*/ true);
28562856
return registerEnumTypeInfo(new LoadableEnumTypeInfo(*this, enumTy,
28572857
Size(0), {},
28582858
Alignment(1),
@@ -2863,9 +2863,9 @@ namespace {
28632863
// Use the singleton element's storage type if fixed-size.
28642864
if (eltTI.isFixedSize()) {
28652865
llvm::Type *body[] = { eltTI.StorageType };
2866-
enumTy->setBody(body);
2866+
enumTy->setBody(body, /*isPacked*/ true);
28672867
} else {
2868-
enumTy->setBody(ArrayRef<llvm::Type*>{});
2868+
enumTy->setBody(ArrayRef<llvm::Type*>{}, /*isPacked*/ true);
28692869
}
28702870

28712871
if (TIK <= Opaque) {
@@ -2900,7 +2900,7 @@ namespace {
29002900
Size tagSize(tagBytes);
29012901

29022902
llvm::Type *body[] = { tagTy };
2903-
enumTy->setBody(body);
2903+
enumTy->setBody(body, /*isPacked*/true);
29042904

29052905
// Unused tag bits in the physical size can be used as spare bits.
29062906
// TODO: We can use all values greater than the largest discriminator as
@@ -2924,10 +2924,10 @@ namespace {
29242924
auto extraTagTy = llvm::IntegerType::get(IGM.getLLVMContext(),
29252925
extraTagBits);
29262926
llvm::Type *body[] = { payloadEnumTy, extraTagTy };
2927-
bodyStruct->setBody(body);
2927+
bodyStruct->setBody(body, /*isPacked*/true);
29282928
} else {
29292929
llvm::Type *body[] = { payloadEnumTy };
2930-
bodyStruct->setBody(body);
2930+
bodyStruct->setBody(body, /*isPacked*/true);
29312931
}
29322932
}
29332933

@@ -2991,7 +2991,7 @@ namespace {
29912991
llvm::StructType *enumTy) {
29922992
// The body is runtime-dependent, so we can't put anything useful here
29932993
// statically.
2994-
enumTy->setBody(ArrayRef<llvm::Type*>{});
2994+
enumTy->setBody(ArrayRef<llvm::Type*>{}, /*isPacked*/true);
29952995

29962996
// Layout has to be done when the value witness table is instantiated,
29972997
// during initializeValueWitnessTable.

lib/IRGen/StructLayout.cpp

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -211,14 +211,7 @@ void StructLayoutBuilder::addFixedSizeElement(ElementLayout &elt) {
211211
= eltAlignment.getValue() - offsetFromAlignment.getValue();
212212
assert(paddingRequired != 0);
213213

214-
// We don't actually need to uglify the IR unless the natural
215-
// alignment of the IR type for the field isn't good enough.
216-
// We also don't need to bother actually adding an IR field if
217-
// the field can't be statically accessed.
218-
Alignment fieldIRAlignment(
219-
IGM.DataLayout.getABITypeAlignment(eltTI.StorageType));
220-
assert(fieldIRAlignment <= eltAlignment);
221-
if (fieldIRAlignment != eltAlignment && isFixedLayout()) {
214+
if (isFixedLayout()) {
222215
auto paddingTy = llvm::ArrayType::get(IGM.Int8Ty, paddingRequired);
223216
StructFields.push_back(paddingTy);
224217
}
@@ -292,11 +285,13 @@ void StructLayoutBuilder::addNonFixedSizeElementAtOffsetZero(ElementLayout &elt)
292285

293286
/// Produce the current fields as an anonymous structure.
294287
llvm::StructType *StructLayoutBuilder::getAsAnonStruct() const {
295-
return llvm::StructType::get(IGM.getLLVMContext(), StructFields);
288+
auto ty = llvm::StructType::get(IGM.getLLVMContext(), StructFields,
289+
/*isPacked*/ true);
290+
return ty;
296291
}
297292

298293
/// Set the current fields as the body of the given struct type.
299294
void StructLayoutBuilder::setAsBodyOfStruct(llvm::StructType *type) const {
300295
assert(type->isOpaque());
301-
type->setBody(StructFields);
296+
type->setBody(StructFields, /*isPacked*/ true);
302297
}

test/IRGen/enum.sil

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,37 +3,37 @@
33
import Builtin
44

55
// -- Singleton enum. The representation is just the singleton payload.
6-
// CHECK: %O4enum9Singleton = type { { i64, i64 } }
6+
// CHECK: %O4enum9Singleton = type <{ <{ i64, i64 }> }>
77

88
// -- No-payload enums. The representation is just an enum tag.
9-
// CHECK: %O4enum10NoPayloads = type { i2 }
10-
// CHECK: %O4enum11NoPayloads2 = type { i3 }
9+
// CHECK: %O4enum10NoPayloads = type <{ i2 }>
10+
// CHECK: %O4enum11NoPayloads2 = type <{ i3 }>
1111

1212
// -- Single-payload enum, no extra inhabitants in the payload type. The
1313
// representation adds a tag bit to distinguish payload from enum tag:
1414
// case x(i64): X0 X1 X2 ... X63 | 0, where X0...X63 are the payload bits
1515
// case y: 0 0 0 ... 0 | 1
1616
// case z: 1 0 0 ... 0 | 1
17-
// CHECK: %O4enum17SinglePayloadNoXI = type { i64, i1 }
18-
// CHECK: %O4enum18SinglePayloadNoXI2 = type { i64, i1 }
17+
// CHECK: %O4enum17SinglePayloadNoXI = type <{ i64, i1 }>
18+
// CHECK: %O4enum18SinglePayloadNoXI2 = type <{ i64, i1 }>
1919

2020
// -- Single-payload enum, spare bits. The representation uses a tag bit
2121
// out of the payload to distinguish payload from enum tag:
2222
// case x(i3): X0 X1 X2 0 0 0 0 0
2323
// case y: 0 0 0 1 0 0 0 0
2424
// case z: 1 0 0 1 0 0 0 0
25-
// CHECK: %O4enum21SinglePayloadSpareBit = type { i64 }
25+
// CHECK: %O4enum21SinglePayloadSpareBit = type <{ i64 }>
2626

2727
// -- Single-payload enum containing a no-payload enum as its payload.
2828
// The representation takes extra inhabitants starting after the greatest
2929
// discriminator value used by the nested no-payload enum.
30-
// CHECK: %O4enum19SinglePayloadNested = type { i8 }
30+
// CHECK: %O4enum19SinglePayloadNested = type <{ i8 }>
3131

3232
// -- Single-payload enum containing another single-payload enum as its
3333
// payload.
3434
// The representation takes extra inhabitants from the nested enum's payload
3535
// that were unused by the nested enum.
36-
// CHECK: %O4enum25SinglePayloadNestedNested = type { i8 }
36+
// CHECK: %O4enum25SinglePayloadNestedNested = type <{ i8 }>
3737

3838
// -- Multi-payload enum, no spare bits. The representation adds tag bits
3939
// to discriminate payloads. No-payload cases all share a tag.
@@ -43,7 +43,7 @@ import Builtin
4343
// case a: 0 0 0 ... 0 0 | 1 1
4444
// case b: 1 0 0 ... 0 0 | 1 1
4545
// case c: 0 1 0 ... 0 0 | 1 1
46-
// CHECK: %O4enum23MultiPayloadNoSpareBits = type { i64, i2 }
46+
// CHECK: %O4enum23MultiPayloadNoSpareBits = type <{ i64, i2 }>
4747

4848
// -- Multi-payload enum, one spare bit. The representation uses spare bits
4949
// common to all payloads to partially discriminate payloads, with added
@@ -54,7 +54,7 @@ import Builtin
5454
// case a: 0 0 0 0 0 0 0 1 | 1
5555
// case b: 1 0 0 0 0 0 0 1 | 1
5656
// case c: 0 1 0 0 0 0 0 1 | 1
57-
// CHECK: %O4enum23MultiPayloadOneSpareBit = type { i64, i1 }
57+
// CHECK: %O4enum23MultiPayloadOneSpareBit = type <{ i64, i1 }>
5858

5959
// -- Multi-payload enum, two spare bits. Same as above, except we have enough
6060
// spare bits not to require any added tag bits.
@@ -64,12 +64,12 @@ import Builtin
6464
// case a: 0 0 0 0 0 0 1 1
6565
// case b: 1 0 0 0 0 0 1 1
6666
// case c: 0 1 0 0 0 0 1 1
67-
// CHECK: %O4enum24MultiPayloadTwoSpareBits = type { i64 }
67+
// CHECK: %O4enum24MultiPayloadTwoSpareBits = type <{ i64 }>
6868

6969
// -- Dynamic enums. The type layout is opaque; we dynamically bitcast to
7070
// the element type.
71-
// CHECK: %O4enum20DynamicSinglePayload = type {}
72-
// CHECK: %O4enum16DynamicSingleton = type {}
71+
// CHECK: %O4enum20DynamicSinglePayload = type <{}>
72+
// CHECK: %O4enum16DynamicSingleton = type <{}>
7373

7474
// -- Dynamic metadata template carries a value witness table pattern
7575
// we fill in on instantiation.
@@ -174,10 +174,10 @@ dest(%u2 : $(Builtin.Int64, Builtin.Int64)):
174174
// CHECK: entry:
175175
// CHECK: br label %[[PREDEST:[0-9]+]]
176176
// CHECK: ; <label>:[[PREDEST]]
177-
// CHECK: [[ADDR:%.*]] = bitcast %O4enum9Singleton* %0 to { i64, i64 }*
177+
// CHECK: [[ADDR:%.*]] = bitcast %O4enum9Singleton* %0 to <{ i64, i64 }>*
178178
// CHECK: br label %[[DEST:[0-9]+]]
179179
// CHECK: ; <label>:[[DEST]]
180-
// CHECK: phi { i64, i64 }* [ [[ADDR]], %[[PREDEST]] ]
180+
// CHECK: phi <{ i64, i64 }>* [ [[ADDR]], %[[PREDEST]] ]
181181
// CHECK: ret void
182182
// CHECK: }
183183
sil @singleton_switch_indirect : $([inout] Singleton) -> () {
@@ -203,10 +203,10 @@ entry(%0 : $Builtin.Int64, %1 : $Builtin.Int64):
203203

204204
// CHECK: define void @singleton_inject_indirect(i64, i64, %O4enum9Singleton*) {
205205
// CHECK: entry:
206-
// CHECK: [[DATA_ADDR:%.*]] = bitcast %O4enum9Singleton* %2 to { i64, i64 }*
207-
// CHECK: [[DATA_0_ADDR:%.*]] = getelementptr inbounds { i64, i64 }* [[DATA_ADDR]], i32 0, i32 0
206+
// CHECK: [[DATA_ADDR:%.*]] = bitcast %O4enum9Singleton* %2 to <{ i64, i64 }>*
207+
// CHECK: [[DATA_0_ADDR:%.*]] = getelementptr inbounds <{ i64, i64 }>* [[DATA_ADDR]], i32 0, i32 0
208208
// CHECK: store i64 %0, i64* [[DATA_0_ADDR]], align 8
209-
// CHECK: [[DATA_1_ADDR:%.*]] = getelementptr inbounds { i64, i64 }* [[DATA_ADDR]], i32 0, i32 1
209+
// CHECK: [[DATA_1_ADDR:%.*]] = getelementptr inbounds <{ i64, i64 }>* [[DATA_ADDR]], i32 0, i32 1
210210
// CHECK: store i64 %1, i64* [[DATA_1_ADDR]], align 8
211211
// CHECK: ret void
212212
// CHECK: }

test/IRGen/partial_apply.sil

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ entry(%x : $Builtin.Int64, %c : $ObjCClass):
3636
// CHECK-LABEL: define { i8*, %swift.refcounted* } @indirect_partial_apply(i8*, %swift.refcounted*, i64) {
3737
// CHECK: entry:
3838
// CHECK: [[OBJ:%.*]] = call noalias %swift.refcounted* @swift_allocObject(%swift.type* getelementptr inbounds (%swift.full_heapmetadata* @metadata, i32 0, i32 2), i64 40, i64 7)
39-
// CHECK: [[DATA_ADDR:%.*]] = bitcast %swift.refcounted* [[OBJ]] to [[DATA_TYPE:{ %swift.refcounted, i64, %swift.refcounted\*, i8\* }]]*
39+
// CHECK: [[DATA_ADDR:%.*]] = bitcast %swift.refcounted* [[OBJ]] to [[DATA_TYPE:<{ %swift.refcounted, i64, %swift.refcounted\*, i8\* }>]]*
4040
// CHECK: [[X_ADDR:%.*]] = getelementptr inbounds [[DATA_TYPE]]* [[DATA_ADDR]], i32 0, i32 1
4141
// CHECK: store i64 %2, i64* [[X_ADDR]], align 8
4242
// CHECK: [[CONTEXT_ADDR:%.*]] = getelementptr inbounds [[DATA_TYPE]]* [[DATA_ADDR]], i32 0, i32 2
@@ -69,7 +69,7 @@ entry(%f : $(Builtin.Int64) -> (), %x : $Builtin.Int64):
6969
// CHECK-LABEL: define { i8*, %swift.refcounted* } @objc_partial_apply(%CSo9ObjCClass*) {
7070
// CHECK: entry:
7171
// CHECK: [[OBJ:%.*]] = call noalias %swift.refcounted* @swift_allocObject(%swift.type* getelementptr inbounds (%swift.full_heapmetadata* @metadata2, i32 0, i32 2), i64 24, i64 7) #0
72-
// CHECK: [[DATA_ADDR:%.*]] = bitcast %swift.refcounted* [[OBJ]] to [[DATA_TYPE:{ %swift.refcounted, %CSo9ObjCClass\* }]]*
72+
// CHECK: [[DATA_ADDR:%.*]] = bitcast %swift.refcounted* [[OBJ]] to [[DATA_TYPE:<{ %swift.refcounted, %CSo9ObjCClass\* }>]]*
7373
// CHECK: [[X_ADDR:%.*]] = getelementptr inbounds [[DATA_TYPE]]* [[DATA_ADDR]], i32 0, i32 1
7474
// CHECK: store %CSo9ObjCClass* %0, %CSo9ObjCClass** [[X_ADDR]], align 8
7575
// CHECK: [[RET:%.*]] = insertvalue { i8*, %swift.refcounted* } { i8* bitcast (void (i64, %swift.refcounted*)* [[OBJC_PARTIAL_APPLY_STUB:@partial_apply[0-9]*]] to i8*), %swift.refcounted* undef }, %swift.refcounted* [[OBJ]], 1

test/IRGen/unowned.sil

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
// CHECK: [[OPAQUE:%swift.opaque]] = type opaque
44
// CHECK: [[TYPE:%swift.type]] = type
55
// CHECK: [[REF:%swift.refcounted]] = type
6-
// CHECK: [[C:%C7unowned1C]] = type { [[REF]] }
6+
// CHECK: [[C:%C7unowned1C]] = type <{ [[REF]] }>
77
// CHECK: [[UNKNOWN:%objc_object]] = type opaque
8-
// CHECK: [[A:%V7unowned1A]] = type { [[C]]* }
8+
// CHECK: [[A:%V7unowned1A]] = type <{ [[C]]* }>
99

1010
class C {}
1111
protocol [class_protocol] P {

test/IRGen/weak.sil

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
// CHECK: [[OPAQUE:%swift.opaque]] = type opaque
44
// CHECK: [[TYPE:%swift.type]] = type
55
// CHECK: [[REF:%swift.refcounted]] = type
6-
// CHECK: [[A:%V4weak1A]] = type { [[WEAK:%swift.weak]] }
6+
// CHECK: [[A:%V4weak1A]] = type <{ [[WEAK:%swift.weak]] }>
77
// CHECK: [[WEAK]] = type
8-
// CHECK: [[C:%C4weak1C]] = type { [[REF]] }
9-
// CHECK: [[B:%V4weak1B]] = type { { i8**, [[WEAK]] } }
8+
// CHECK: [[C:%C4weak1C]] = type <{ [[REF]] }>
9+
// CHECK: [[B:%V4weak1B]] = type <{ { i8**, [[WEAK]] } }>
1010
// CHECK: [[UNKNOWN:%objc_object]] = type opaque
1111

1212
import swift

0 commit comments

Comments
 (0)