Skip to content

Commit 7b1a43b

Browse files
Merge pull request #33485 from apple/irgen_store_bits_as_bytes
IRGen: Store scalars as bytes to avoid undefined bits
2 parents 7b86cce + 9b29ec6 commit 7b1a43b

File tree

5 files changed

+128
-29
lines changed

5 files changed

+128
-29
lines changed

lib/IRGen/ScalarTypeInfo.h

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -117,10 +117,33 @@ class SingleScalarTypeInfo : public ScalarTypeInfo<Derived, Base> {
117117
schema.add(ExplosionSchema::Element::forScalar(ty));
118118
}
119119

120+
void storeAsBytes(IRGenFunction &IGF, Explosion &src, Address addr) const {
121+
auto &IGM = IGF.IGM;
122+
123+
// Store in multiples of bytes to avoid undefined bits.
124+
auto storageTy = addr.getAddress()->getType()->getPointerElementType();
125+
if (storageTy->isIntegerTy() && (storageTy->getIntegerBitWidth() % 8)) {
126+
auto &Builder = IGF.Builder;
127+
auto nextByteSize = (storageTy->getIntegerBitWidth() + 7) & ~7UL;
128+
auto nextByteSizedIntTy =
129+
llvm::IntegerType::get(IGM.getLLVMContext(), nextByteSize);
130+
auto newAddr =
131+
Address(Builder.CreatePointerCast(addr.getAddress(),
132+
nextByteSizedIntTy->getPointerTo()),
133+
addr.getAlignment());
134+
auto newValue = Builder.CreateZExt(src.claimNext(), nextByteSizedIntTy);
135+
Builder.CreateStore(newValue, newAddr);
136+
return;
137+
}
138+
139+
IGF.Builder.CreateStore(src.claimNext(), addr);
140+
}
141+
120142
void initialize(IRGenFunction &IGF, Explosion &src, Address addr,
121143
bool isOutlined) const override {
122144
addr = asDerived().projectScalar(IGF, addr);
123-
IGF.Builder.CreateStore(src.claimNext(), addr);
145+
146+
storeAsBytes(IGF, src, addr);
124147
}
125148

126149
void loadAsCopy(IRGenFunction &IGF, Address addr,
@@ -149,8 +172,7 @@ class SingleScalarTypeInfo : public ScalarTypeInfo<Derived, Base> {
149172
}
150173

151174
// Store.
152-
llvm::Value *newValue = src.claimNext();
153-
IGF.Builder.CreateStore(newValue, dest);
175+
storeAsBytes(IGF, src, dest);
154176

155177
// Release the old value if we need to.
156178
if (!Derived::IsScalarPOD) {

test/IRGen/builtins.swift

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -235,37 +235,42 @@ func cmpxchg_test(_ ptr: Builtin.RawPointer, a: Builtin.Int32, b: Builtin.Int32)
235235
// CHECK: [[Z_VAL:%.*]] = extractvalue { i32, i1 } [[Z_RES]], 0
236236
// CHECK: [[Z_SUCCESS:%.*]] = extractvalue { i32, i1 } [[Z_RES]], 1
237237
// CHECK: store i32 [[Z_VAL]], i32* {{.*}}, align 4
238-
// CHECK: store i1 [[Z_SUCCESS]], i1* {{.*}}, align 1
238+
// CHECK: [[Z_SUCCESS_B:%.*]] = zext i1 [[Z_SUCCESS]] to i8
239+
// CHECK: store i8 [[Z_SUCCESS_B]], i8* {{.*}}, align 1
239240
var (z, zSuccess) = Builtin.cmpxchg_acquire_acquire_Int32(ptr, a, b)
240241

241242
// CHECK: [[Y_RES:%.*]] = cmpxchg volatile i32* {{.*}}, i32 {{.*}}, i32 {{.*}} monotonic monotonic
242243
// CHECK: [[Y_VAL:%.*]] = extractvalue { i32, i1 } [[Y_RES]], 0
243244
// CHECK: [[Y_SUCCESS:%.*]] = extractvalue { i32, i1 } [[Y_RES]], 1
244245
// CHECK: store i32 [[Y_VAL]], i32* {{.*}}, align 4
245-
// CHECK: store i1 [[Y_SUCCESS]], i1* {{.*}}, align 1
246+
// CHECK: [[Y_SUCCESS_B:%.*]] = zext i1 [[Y_SUCCESS]] to i8
247+
// CHECK: store i8 [[Y_SUCCESS_B]], i8* {{.*}}, align 1
246248
var (y, ySuccess) = Builtin.cmpxchg_monotonic_monotonic_volatile_Int32(ptr, a, b)
247249

248250
// CHECK: [[X_RES:%.*]] = cmpxchg volatile i32* {{.*}}, i32 {{.*}}, i32 {{.*}} syncscope("singlethread") acquire monotonic
249251
// CHECK: [[X_VAL:%.*]] = extractvalue { i32, i1 } [[X_RES]], 0
250252
// CHECK: [[X_SUCCESS:%.*]] = extractvalue { i32, i1 } [[X_RES]], 1
251253
// CHECK: store i32 [[X_VAL]], i32* {{.*}}, align 4
252-
// CHECK: store i1 [[X_SUCCESS]], i1* {{.*}}, align 1
254+
// CHECK: [[X_SUCCESS_B:%.*]] = zext i1 [[X_SUCCESS]] to i8
255+
// CHECK: store i8 [[X_SUCCESS_B]], i8* {{.*}}, align 1
253256
var (x, xSuccess) = Builtin.cmpxchg_acquire_monotonic_volatile_singlethread_Int32(ptr, a, b)
254257

255258
// CHECK: [[W_RES:%.*]] = cmpxchg volatile i64* {{.*}}, i64 {{.*}}, i64 {{.*}} seq_cst seq_cst
256259
// CHECK: [[W_VAL:%.*]] = extractvalue { i64, i1 } [[W_RES]], 0
257260
// CHECK: [[W_SUCCESS:%.*]] = extractvalue { i64, i1 } [[W_RES]], 1
258261
// CHECK: [[W_VAL_PTR:%.*]] = inttoptr i64 [[W_VAL]] to i8*
259262
// CHECK: store i8* [[W_VAL_PTR]], i8** {{.*}}, align 8
260-
// CHECK: store i1 [[W_SUCCESS]], i1* {{.*}}, align 1
263+
// CHECK: [[W_SUCCESS_B:%.*]] = zext i1 [[W_SUCCESS]] to i8
264+
// CHECK: store i8 [[W_SUCCESS_B]], i8* {{.*}}, align 1
261265
var (w, wSuccess) = Builtin.cmpxchg_seqcst_seqcst_volatile_singlethread_RawPointer(ptr, ptr, ptr)
262266

263267
// CHECK: [[V_RES:%.*]] = cmpxchg weak volatile i64* {{.*}}, i64 {{.*}}, i64 {{.*}} seq_cst seq_cst
264268
// CHECK: [[V_VAL:%.*]] = extractvalue { i64, i1 } [[V_RES]], 0
265269
// CHECK: [[V_SUCCESS:%.*]] = extractvalue { i64, i1 } [[V_RES]], 1
266270
// CHECK: [[V_VAL_PTR:%.*]] = inttoptr i64 [[V_VAL]] to i8*
267271
// CHECK: store i8* [[V_VAL_PTR]], i8** {{.*}}, align 8
268-
// CHECK: store i1 [[V_SUCCESS]], i1* {{.*}}, align 1
272+
// CHECK: [[V_SUCCESS_B:%.*]] = zext i1 [[V_SUCCESS]] to i8
273+
// CHECK: store i8 [[V_SUCCESS_B]], i8* {{.*}}, align 1
269274
var (v, vSuccess) = Builtin.cmpxchg_seqcst_seqcst_weak_volatile_singlethread_RawPointer(ptr, ptr, ptr)
270275
}
271276

@@ -558,7 +563,8 @@ struct Pair { var i: Int, b: Bool }
558563
// CHECK: [[FLDI:%.*]] = getelementptr inbounds {{.*}} [[PAIR]], i32 0, i32 0
559564
// CHECK: store i32 0, i32* [[FLDI]]
560565
// CHECK: [[FLDB:%.*]] = getelementptr inbounds {{.*}} [[PAIR]], i32 0, i32 1
561-
// CHECK: store i1 false, i1* [[FLDB]]
566+
// CHECK: [[BYTE_ADDR:%.*]] = bitcast i1* [[FLDB]] to i8*
567+
// CHECK: store i8 0, i8* [[BYTE_ADDR]]
562568
// CHECK: [[RET:%.*]] = getelementptr inbounds {{.*}} [[ALLOCA]], i32 0, i32 0
563569
// CHECK: [[RES:%.*]] = load i64, i64* [[RET]]
564570
// CHECK: ret i64 [[RES]]
@@ -575,7 +581,8 @@ func zeroInitializer() -> (Empty, Pair) {
575581
// CHECK: [[FLDI:%.*]] = getelementptr inbounds {{.*}} [[PAIR]], i32 0, i32 0
576582
// CHECK: store i32 0, i32* [[FLDI]]
577583
// CHECK: [[FLDB:%.*]] = getelementptr inbounds {{.*}} [[PAIR]], i32 0, i32 1
578-
// CHECK: store i1 false, i1* [[FLDB]]
584+
// CHECK: [[BYTE_ADDR:%.*]] = bitcast i1* [[FLDB]] to i8*
585+
// CHECK: store i8 0, i8* [[BYTE_ADDR]]
579586
// CHECK: [[RET:%.*]] = getelementptr inbounds {{.*}} [[ALLOCA]], i32 0, i32 0
580587
// CHECK: [[RES:%.*]] = load i64, i64* [[RET]]
581588
// CHECK: ret i64 [[RES]]
@@ -695,14 +702,16 @@ func generic_ispod_test<T>(_: T) {
695702
// CHECK-NEXT: [[FLAGS:%.*]] = load i32, i32* [[T0]]
696703
// CHECK-NEXT: [[ISNOTPOD:%.*]] = and i32 [[FLAGS]], 65536
697704
// CHECK-NEXT: [[ISPOD:%.*]] = icmp eq i32 [[ISNOTPOD]], 0
698-
// CHECK-NEXT: store i1 [[ISPOD]], i1* [[S:%.*]]
705+
// CHECK-NEXT: [[BYTE_ADDR:%.*]] = bitcast i1* [[S:%.*]] to i8*
706+
// CHECK-NEXT: [[BYTE:%.*]] = zext i1 [[ISPOD]] to i8
707+
// CHECK-NEXT: store i8 [[BYTE]], i8* [[BYTE_ADDR]]
699708
var s = Builtin.ispod(T.self)
700709
}
701710

702711
// CHECK-LABEL: define {{.*}} @{{.*}}ispod_test
703712
func ispod_test() {
704-
// CHECK: store i1 true, i1*
705-
// CHECK: store i1 false, i1*
713+
// CHECK: store i8 1, i8*
714+
// CHECK: store i8 0, i8*
706715
var t = Builtin.ispod(Int.self)
707716
var f = Builtin.ispod(Builtin.NativeObject.self)
708717
}
@@ -713,17 +722,19 @@ func generic_isbitwisetakable_test<T>(_: T) {
713722
// CHECK-NEXT: [[FLAGS:%.*]] = load i32, i32* [[T0]]
714723
// CHECK-NEXT: [[ISNOTBITWISETAKABLE:%.*]] = and i32 [[FLAGS]], 1048576
715724
// CHECK-NEXT: [[ISBITWISETAKABLE:%.*]] = icmp eq i32 [[ISNOTBITWISETAKABLE]], 0
716-
// CHECK-NEXT: store i1 [[ISBITWISETAKABLE]], i1* [[S:%.*]]
725+
// CHECK-NEXT: [[BYTE_ADDR:%.*]] = bitcast i1* [[S:%.*]]
726+
// CHECK-NEXT: [[BYTE:%.*]] = zext i1 [[ISBITWISETAKABLE]] to i8
727+
// CHECK-NEXT: store i8 [[BYTE]], i8* [[BYTE_ADDR]]
717728
var s = Builtin.isbitwisetakable(T.self)
718729
}
719730

720731
// CHECK-LABEL: define {{.*}} @{{.*}}isbitwisetakable_test
721732
func isbitwisetakable_test() {
722-
// CHECK: store i1 true, i1*
723-
// CHECK: store i1 true, i1*
724-
// CHECK: store i1 true, i1*
725-
// CHECK: store i1 true, i1*
726-
// CHECK: store i1 false, i1*
733+
// CHECK: store i8 1, i8*
734+
// CHECK: store i8 1, i8*
735+
// CHECK: store i8 1, i8*
736+
// CHECK: store i8 1, i8*
737+
// CHECK: store i8 0, i8*
727738
var t1 = Builtin.isbitwisetakable(Int.self)
728739
var t2 = Builtin.isbitwisetakable(C.self)
729740
var t3 = Builtin.isbitwisetakable(Abc.self)

test/IRGen/enum.sil

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1010,7 +1010,9 @@ entry(%0 : $Builtin.Int63):
10101010
// CHECK-64: entry:
10111011
// CHECK-64: [[T:%.*]] = trunc i64 %0 to i63
10121012
// CHECK-64: [[DATA_ADDR:%.*]] = bitcast %T4enum21SinglePayloadSpareBitO* %1 to i63*
1013-
// CHECK-64: store i63 [[T]], i63* [[DATA_ADDR]]
1013+
// CHECK-64: [[BYTE_ADDR:%.*]] = bitcast i63* [[DATA_ADDR]] to i64*
1014+
// CHECK-64: [[BYTE:%.*]] = zext i63 [[T]] to i64
1015+
// CHECK-64: store i64 [[BYTE]], i64* [[BYTE_ADDR]]
10141016
// CHECK-64: ret void
10151017
// CHECK-64: }
10161018
sil @single_payload_spare_bit_inject_x_indirect : $(Builtin.Int63, @inout SinglePayloadSpareBit) -> () {
@@ -1784,7 +1786,9 @@ entry(%0 : $Builtin.Int62):
17841786
// CHECK-64: entry:
17851787
// CHECK-64: [[NATIVECC_TRUNC:%.*]] = trunc i64 %0 to i62
17861788
// CHECK-64: [[DATA_ADDR:%.*]] = bitcast %T4enum23MultiPayloadOneSpareBitO* %1 to i62*
1787-
// CHECK-64: store i62 [[NATIVECC_TRUNC]], i62* [[DATA_ADDR]]
1789+
// CHECK-64: [[BYTE_ADDR:%.*]] = bitcast i62* [[DATA_ADDR]] to i64*
1790+
// CHECK-64: [[BYTE:%.*]] = zext i62 [[NATIVECC_TRUNC]] to i64
1791+
// CHECK-64: store i64 [[BYTE]], i64* [[BYTE_ADDR]]
17881792
// CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %T4enum23MultiPayloadOneSpareBitO* %1 to i64*
17891793
// CHECK-64: [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]]
17901794
// -- 0x7FFF_FFFF_FFFF_FFFF
@@ -1825,7 +1829,9 @@ entry(%0 : $Builtin.Int63):
18251829
// CHECK-64: entry:
18261830
// CHECK-64: [[NATIVECC_TRUNC:%.*]] = trunc i64 %0 to i63
18271831
// CHECK-64: [[DATA_ADDR:%.*]] = bitcast %T4enum23MultiPayloadOneSpareBitO* %1 to i63*
1828-
// CHECK-64: store i63 [[NATIVECC_TRUNC]], i63* [[DATA_ADDR]]
1832+
// CHECK-64: [[BYTE_ADDR:%.*]] = bitcast i63* [[DATA_ADDR]] to i64*
1833+
// CHECK-64: [[BYTE:%.*]] = zext i63 [[NATIVECC_TRUNC]] to i64
1834+
// CHECK-64: store i64 [[BYTE]], i64* [[BYTE_ADDR]]
18291835
// CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %T4enum23MultiPayloadOneSpareBitO* %1 to i64*
18301836
// CHECK-64: [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]]
18311837
// -- 0x7FFF_FFFF_FFFF_FFFF
@@ -2024,7 +2030,9 @@ entry(%0 : $Builtin.Int62):
20242030
// CHECK-64: entry:
20252031
// CHECK-64: [[NATIVECC_TRUNC:%.*]] = trunc i64 %0 to i62
20262032
// CHECK-64: [[DATA_ADDR:%.*]] = bitcast %T4enum24MultiPayloadTwoSpareBitsO* %1 to i62*
2027-
// CHECK-64: store i62 [[NATIVECC_TRUNC]], i62* [[DATA_ADDR]]
2033+
// CHECK-64: [[BYTE_ADDR:%.*]] = bitcast i62* [[DATA_ADDR]] to i64*
2034+
// CHECK-64: [[BYTE:%.*]] = zext i62 [[NATIVECC_TRUNC]] to i64
2035+
// CHECK-64: store i64 [[BYTE]], i64* [[BYTE_ADDR]]
20282036
// CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %T4enum24MultiPayloadTwoSpareBitsO* %1 to i64*
20292037
// CHECK-64: [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]]
20302038
// -- 0x3FFF_FFFF_FFFF_FFFF
@@ -2060,7 +2068,9 @@ entry(%0 : $Builtin.Int60):
20602068
// CHECK-64: entry:
20612069
// CHECK-64: [[NATIVECC_TRUNC:%.*]] = trunc i64 %0 to i60
20622070
// CHECK-64: [[DATA_ADDR:%.*]] = bitcast %T4enum24MultiPayloadTwoSpareBitsO* %1 to i60*
2063-
// CHECK-64: store i60 [[NATIVECC_TRUNC]], i60* [[DATA_ADDR]]
2071+
// CHECK-64: [[BYTE_ADDR:%.*]] = bitcast i60* [[DATA_ADDR]] to i64*
2072+
// CHECK-64: [[BYTE:%.*]] = zext i60 [[NATIVECC_TRUNC]] to i64
2073+
// CHECK-64: store i64 [[BYTE]], i64* [[BYTE_ADDR]]
20642074
// CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %T4enum24MultiPayloadTwoSpareBitsO* %1 to i64*
20652075
// CHECK-64: [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]]
20662076
// -- 0x3FFF_FFFF_FFFF_FFFF

test/IRGen/enum_future.sil

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1014,7 +1014,9 @@ entry(%0 : $Builtin.Int63):
10141014
// CHECK-64: entry:
10151015
// CHECK-64: [[T:%.*]] = trunc i64 %0 to i63
10161016
// CHECK-64: [[DATA_ADDR:%.*]] = bitcast %T11enum_future21SinglePayloadSpareBitO* %1 to i63*
1017-
// CHECK-64: store i63 [[T]], i63* [[DATA_ADDR]]
1017+
// CHECK-64: [[BYTE_ADDR:%.*]] = bitcast i63* [[DATA_ADDR]] to i64*
1018+
// CHECK-64: [[BYTE:%.*]] = zext i63 [[T]] to i64
1019+
// CHECK-64: store i64 [[BYTE]], i64* [[BYTE_ADDR]]
10181020
// CHECK-64: ret void
10191021
// CHECK-64: }
10201022
sil @single_payload_spare_bit_inject_x_indirect : $(Builtin.Int63, @inout SinglePayloadSpareBit) -> () {
@@ -1788,7 +1790,9 @@ entry(%0 : $Builtin.Int62):
17881790
// CHECK-64: entry:
17891791
// CHECK-64: [[NATIVECC_TRUNC:%.*]] = trunc i64 %0 to i62
17901792
// CHECK-64: [[DATA_ADDR:%.*]] = bitcast %T11enum_future23MultiPayloadOneSpareBitO* %1 to i62*
1791-
// CHECK-64: store i62 [[NATIVECC_TRUNC]], i62* [[DATA_ADDR]]
1793+
// CHECK-64: [[BYTE_ADDR:%.*]] = bitcast i62* [[DATA_ADDR]] to i64*
1794+
// CHECK-64: [[VAL:%.*]] = zext i62 [[NATIVECC_TRUNC]] to i64
1795+
// CHECK-64: store i64 [[VAL]], i64* [[BYTE_ADDR]]
17921796
// CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %T11enum_future23MultiPayloadOneSpareBitO* %1 to i64*
17931797
// CHECK-64: [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]]
17941798
// -- 0x7FFF_FFFF_FFFF_FFFF
@@ -1829,7 +1833,9 @@ entry(%0 : $Builtin.Int63):
18291833
// CHECK-64: entry:
18301834
// CHECK-64: [[NATIVECC_TRUNC:%.*]] = trunc i64 %0 to i63
18311835
// CHECK-64: [[DATA_ADDR:%.*]] = bitcast %T11enum_future23MultiPayloadOneSpareBitO* %1 to i63*
1832-
// CHECK-64: store i63 [[NATIVECC_TRUNC]], i63* [[DATA_ADDR]]
1836+
// CHECK-64: [[BYTE_ADDR:%.*]] = bitcast i63* [[DATA_ADDR]] to i64*
1837+
// CHECK-64: [[VAL:%.*]] = zext i63 [[NATIVECC_TRUNC]] to i64
1838+
// CHECK-64: store i64 [[VAL]], i64* [[BYTE_ADDR]]
18331839
// CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %T11enum_future23MultiPayloadOneSpareBitO* %1 to i64*
18341840
// CHECK-64: [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]]
18351841
// -- 0x7FFF_FFFF_FFFF_FFFF
@@ -2028,7 +2034,9 @@ entry(%0 : $Builtin.Int62):
20282034
// CHECK-64: entry:
20292035
// CHECK-64: [[NATIVECC_TRUNC:%.*]] = trunc i64 %0 to i62
20302036
// CHECK-64: [[DATA_ADDR:%.*]] = bitcast %T11enum_future24MultiPayloadTwoSpareBitsO* %1 to i62*
2031-
// CHECK-64: store i62 [[NATIVECC_TRUNC]], i62* [[DATA_ADDR]]
2037+
// CHECK-64: [[BYTE_ADDR:%.*]] = bitcast i62* [[DATA_ADDR]] to i64*
2038+
// CHECK-64: [[VAL:%.*]] = zext i62 [[NATIVECC_TRUNC]] to i64
2039+
// CHECK-64: store i64 [[VAL]], i64* [[BYTE_ADDR]]
20322040
// CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %T11enum_future24MultiPayloadTwoSpareBitsO* %1 to i64*
20332041
// CHECK-64: [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]]
20342042
// -- 0x3FFF_FFFF_FFFF_FFFF
@@ -2064,7 +2072,9 @@ entry(%0 : $Builtin.Int60):
20642072
// CHECK-64: entry:
20652073
// CHECK-64: [[NATIVECC_TRUNC:%.*]] = trunc i64 %0 to i60
20662074
// CHECK-64: [[DATA_ADDR:%.*]] = bitcast %T11enum_future24MultiPayloadTwoSpareBitsO* %1 to i60*
2067-
// CHECK-64: store i60 [[NATIVECC_TRUNC]], i60* [[DATA_ADDR]]
2075+
// CHECK-64: [[BYTE_ADDR:%.*]] = bitcast i60* [[DATA_ADDR]] to i64*
2076+
// CHECK-64: [[VAL:%.*]] = zext i60 [[NATIVECC_TRUNC]] to i64
2077+
// CHECK-64: store i64 [[VAL]], i64* [[BYTE_ADDR]]
20682078
// CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %T11enum_future24MultiPayloadTwoSpareBitsO* %1 to i64*
20692079
// CHECK-64: [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]]
20702080
// -- 0x3FFF_FFFF_FFFF_FFFF

test/Interpreter/enum.swift

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -698,3 +698,49 @@ func testCase() {
698698

699699
// CHECK: Container(storage: a.MultiIndirectRef.ind(5))
700700
testCase()
701+
702+
703+
enum BitEnum {
704+
case first
705+
case second
706+
}
707+
protocol Init {
708+
init()
709+
}
710+
struct TrailingByte : Init {
711+
var x = 2
712+
var y = BitEnum.first
713+
init() {
714+
x = 2
715+
y = BitEnum.first
716+
}
717+
}
718+
719+
@inline(never)
720+
func capture<T>(_ t: inout T) {
721+
print("captured \(t)")
722+
}
723+
724+
@inline(never)
725+
func reproduction<T: Init>(_ x: Int, _ y: Int, _ t: T) {
726+
var o : Optional<T> = nil
727+
728+
729+
for i in 0 ..< x {
730+
if i == y {
731+
o = T()
732+
}
733+
}
734+
735+
capture(&o)
736+
737+
if var byte = o {
738+
print("there is a byte (failure)")
739+
print(byte)
740+
} else {
741+
print("there is no byte")
742+
}
743+
}
744+
745+
// CHECK: there is no byte
746+
reproduction(2, 3, TrailingByte())

0 commit comments

Comments
 (0)