Skip to content

Commit 1a10f85

Browse files
committed
[IRGen] Fix computation of spare bits for fixed arrays
rdar://159143492 Previously all bits after the spare bits of the first element were marked as spare bits. This caused enum tags to be stored in bits used by the payload.
1 parent 5f20a5b commit 1a10f85

File tree

3 files changed

+87
-2
lines changed

3 files changed

+87
-2
lines changed

lib/IRGen/GenArray.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -248,9 +248,15 @@ class FixedArrayTypeInfoBase : public ArrayTypeInfoBase<BaseTypeInfo> {
248248

249249
// Take spare bits from the first element only.
250250
SpareBitVector result = elementTI.getSpareBits();
251+
251252
// We can use the padding to the next element as spare bits too.
252-
result.appendSetBits(getArraySize(arraySize, elementTI).getValueInBits()
253-
- result.size());
253+
auto padding = elementTI.getFixedStride() - elementTI.getFixedSize();
254+
result.appendSetBits(padding.getValueInBits());
255+
256+
// spare bits of any other elements should not be considered
257+
result.appendClearBits(
258+
getArraySize(arraySize - 1, elementTI).getValueInBits());
259+
254260
return result;
255261
}
256262

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// RUN: %target-swift-frontend -disable-availability-checking -O -emit-ir %s | %FileCheck %s
2+
3+
// UNSUPPORTED: PTRSIZE=32
4+
5+
public struct Foo {
6+
let x: UInt64
7+
let y: InlineArray<2, UInt64>
8+
}
9+
10+
public struct Bar {
11+
let x: UInt64
12+
let y: [UInt64]
13+
}
14+
15+
// CHECK: define {{.*}} i32 @"$s22inline_array_enum_tags3BazOwug"(ptr noalias nocapture readonly %value, ptr nocapture readnone %Baz)
16+
// CHECK: [[TAG_ADDR:%.*]] = getelementptr inbounds i8, ptr %value, i64 24
17+
// CHECK: [[TAG_VAL:%.*]] = load i1, ptr [[TAG_ADDR]], align 8
18+
// CHECK: [[TAG_EXT:%.*]] = zext i1 [[TAG_VAL]] to i32
19+
// CHECK: ret i32 [[TAG_EXT]]
20+
// CHECK: }
21+
public enum Baz {
22+
case foo(Foo)
23+
case bar(Bar)
24+
}
25+
26+
public struct Padded {
27+
let x: UInt64
28+
let y: InlineArray<2, (UInt16, UInt8)>
29+
}
30+
31+
32+
// CHECK: define {{.*}} i32 @"$s22inline_array_enum_tags17WithPaddedPayloadOwug"(ptr noalias nocapture readonly %value, ptr nocapture readnone %WithPaddedPayload)
33+
// CHECK: entry:
34+
// CHECK: [[ADDR:%.*]] = getelementptr inbounds i8, ptr %value, i64 8
35+
// CHECK: [[VAL:%.*]] = load i64, ptr [[ADDR]], align 8
36+
// CHECK: [[MASKED:%.*]] = and i64 [[VAL]], 2147483648
37+
// CHECK: [[TAG:%.*]] = icmp ne i64 [[MASKED]], 0
38+
// CHECK: [[EXTENDED:%.*]] = zext i1 [[TAG]] to i32
39+
// CHECK: ret i32 [[EXTENDED]]
40+
// CHECK: }
41+
public enum WithPaddedPayload {
42+
case a(Padded)
43+
case b(Padded)
44+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// RUN: %target-run-simple-swift(-Xfrontend -disable-availability-checking) | %FileCheck %s
2+
// RUN: %target-run-simple-swift(-O -Xfrontend -disable-availability-checking) | %FileCheck %s
3+
4+
// REQUIRES: executable_test
5+
6+
// UNSUPPORTED: back_deployment_runtime || use_os_stdlib
7+
8+
struct Foo {
9+
let x: UInt64
10+
let y: InlineArray<2, UInt64>
11+
}
12+
13+
struct Bar {
14+
let x: UInt64
15+
let y: [UInt64]
16+
}
17+
18+
enum Baz {
19+
case foo(Foo)
20+
case bar(Bar)
21+
}
22+
23+
@inline(never)
24+
func createEnum() -> Baz {
25+
return .foo(Foo(x: 0, y: [0, 0xff00000000000000]))
26+
}
27+
28+
29+
let x = createEnum()
30+
31+
// CHECK: 0 - 18374686479671623680
32+
switch x {
33+
case .bar: fatalError("Expected .foo")
34+
case .foo(let x): print("\(x.y[0]) - \(x.y[1])")
35+
}

0 commit comments

Comments
 (0)