Skip to content

Commit 7c6a009

Browse files
committed
[GenPack] Always heapify metadata packs.
Until the optimization to leave packs on-stack is in place. Even then, we'll want to keep this as a fallback. rdar://110123679
1 parent 6ddf14e commit 7c6a009

File tree

3 files changed

+115
-10
lines changed

3 files changed

+115
-10
lines changed

lib/IRGen/GenPack.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,11 @@ irgen::emitTypeMetadataPackRef(IRGenFunction &IGF, CanPackType packType,
512512
metadata = IGF.Builder.CreatePointerCast(
513513
metadata, IGF.IGM.TypeMetadataPtrTy->getPointerTo());
514514

515+
metadata = IGF.Builder.CreateCall(
516+
IGF.IGM.getAllocateMetadataPackFunctionPointer(), {metadata, shape});
517+
518+
cleanupTypeMetadataPack(IGF, pack, shape);
519+
515520
auto response = MetadataResponse::forComplete(metadata);
516521
IGF.setScopedLocalTypeMetadata(packType, response);
517522

@@ -669,6 +674,11 @@ llvm::Value *irgen::emitWitnessTablePackRef(IRGenFunction &IGF,
669674
result = IGF.Builder.CreatePointerCast(
670675
result, IGF.IGM.WitnessTablePtrTy->getPointerTo());
671676

677+
result = IGF.Builder.CreateCall(
678+
IGF.IGM.getAllocateWitnessTablePackFunctionPointer(), {result, shape});
679+
680+
cleanupWitnessTablePack(IGF, pack, shape);
681+
672682
IGF.setScopedLocalTypeData(packType, localDataKind, result);
673683

674684
return result;

test/IRGen/variadic_generic_functions.sil

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,12 @@ struct Gen2<Fwd : Q> : Q {}
3232
// CHECK: [[METADATA_ELEMENT_0:%[^,]+]] = getelementptr inbounds [1 x %swift.type*], [1 x %swift.type*]* [[METADATA_PACK]]
3333
// CHECK: store %swift.type* bitcast {{.*}}$s26variadic_generic_functions3S_2VMf{{.*}}, %swift.type** [[METADATA_ELEMENT_0]]
3434
// CHECK: [[METADATA_PACK_PTR:%[^,]+]] = bitcast [1 x %swift.type*]* [[METADATA_PACK]] to %swift.type**
35+
// CHECK: [[HEAPIFIED_METADATA_PACK_PTR:%[^,]+]] = call swiftcc %swift.type** @swift_allocateMetadataPack(%swift.type** [[METADATA_PACK_PTR]], i64 1)
3536
// CHECK: [[WTABLE_ELEMENT_0:%[^,]+]] = getelementptr inbounds [1 x i8**], [1 x i8**]* [[WTABLE_PACK]]
3637
// CHECK: store i8** getelementptr inbounds {{.*}}$s26variadic_generic_functions3S_2VAA1PAAWP{{.*}}, i8*** [[WTABLE_ELEMENT_0]]
37-
// CHECK: [[WTABLE_PACK_ADDR:%[^,]+]] = bitcast [1 x i8**]* [[WTABLE_PACK]] to i8***
38-
// CHECK: call swiftcc void @g([[INT]] 1, %swift.type** [[METADATA_PACK_PTR]], i8*** [[WTABLE_PACK_ADDR]])
38+
// CHECK: [[WTABLE_PACK_PTR:%[^,]+]] = bitcast [1 x i8**]* [[WTABLE_PACK]] to i8***
39+
// CHECK: [[HEAPIFIED_WTABLE_PACK_PTR:%[^%]+]] = call swiftcc i8*** @swift_allocateWitnessTablePack(i8*** [[WTABLE_PACK_PTR]], i64 1)
40+
// CHECK: call swiftcc void @g([[INT]] 1, %swift.type** [[HEAPIFIED_METADATA_PACK_PTR]], i8*** [[HEAPIFIED_WTABLE_PACK_PTR]])
3941
sil @c : $() -> () {
4042
%g = function_ref @g : $@convention(thin) <each T : P> () -> ()
4143
apply %g<Pack{S_2}>() : $@convention(thin) <each T : P> () -> ()
@@ -89,9 +91,10 @@ sil @f1c : $<each T : PA where repeat each T.A : P> () -> () {}
8991
// CHECK-SAME: i8*** %"each T.PA",
9092
// CHECK-SAME: i8*** [[ASSOCIATEDTYPES_CONFORMANCES_TO_Q:%[^,]+]])
9193
// CHECK: [[ASSOCIATEDTYPES:%[^,]+]] = alloca %swift.type*, [[INT]] [[SHAPE]]
94+
// CHECK: [[HEAPIFIED_ASSOCIATEDTYPES:%[^,]+]] = call swiftcc %swift.type** @swift_allocateMetadataPack(%swift.type** [[ASSOCIATEDTYPES]], i64 %0)
9295
// CHECK: call swiftcc void @associatedtype_with_added_conformance_callee(
9396
// CHECK-SAME: [[INT]] [[SHAPE]],
94-
// CHECK-SAME: %swift.type** [[ASSOCIATEDTYPES]],
97+
// CHECK-SAME: %swift.type** [[HEAPIFIED_ASSOCIATEDTYPES]],
9598
// CHECK-SAME: i8*** [[ASSOCIATEDTYPES_CONFORMANCES_TO_Q]])
9699
sil @associatedtype_with_added_conformance : $<each T : PA where repeat each T.A : Q> () -> () {
97100
%callee = function_ref @associatedtype_with_added_conformance_callee : $@convention(thin) <each T : Q> () -> ()
@@ -109,9 +112,10 @@ sil @associatedtype_with_added_conformance_callee : $<each T : Q> () -> () {}
109112
// CHECK-SAME: i8*** %"each T.A.QA",
110113
// CHECK-SAME: i8*** [[ASSOCIATEDTYPES_CONFORMANCES_TO_Q:%[^,]+]])
111114
// CHECK: [[ASSOCIATEDTYPES:%[^,]+]] = alloca %swift.type*, [[INT]] [[SHAPE]]
115+
// CHECK: [[HEAPIFIED_ASSOCIATEDTYPES:%[^,]+]] = call swiftcc %swift.type** @swift_allocateMetadataPack(%swift.type** [[ASSOCIATEDTYPES]], i64 [[SHAPE]])
112116
// CHECK: call swiftcc void @associatedtype_with_added_conformance_2_callee(
113117
// CHECK-SAME: [[INT]] [[SHAPE]],
114-
// CHECK-SAME: %swift.type** [[ASSOCIATEDTYPES]],
118+
// CHECK-SAME: %swift.type** [[HEAPIFIED_ASSOCIATEDTYPES]],
115119
// CHECK-SAME: i8*** [[ASSOCIATEDTYPES_CONFORMANCES_TO_Q]])
116120
sil @associatedtype_with_added_conformance_2 : $<each T : PA where repeat each T.A : QA, repeat each T.A.A : R> () -> () {
117121
%j = function_ref @associatedtype_with_added_conformance_2_callee : $@convention(thin) <each T : R> () -> ()
@@ -127,11 +131,15 @@ sil @associatedtype_with_added_conformance_2_callee : $<each T : R> () -> () {}
127131
// CHECK-SAME: %swift.type** %"each T",
128132
// CHECK-SAME: i8*** %"each T.Q")
129133
// CHECK: [[GEN2_TYPES:%[^,]+]] = alloca %swift.type*, [[INT]] [[SHAPE]]
134+
// CHECK: [[HEAPIFIED_GEN2_TYPES:%[^,]+]] = call swiftcc %swift.type** @swift_allocateMetadataPack(%swift.type** [[GEN2_TYPES]], i64 [[SHAPE]])
135+
// CHECK: [[STORED_STACK_LOC:%[^,]+]] = call i8* @llvm.stacksave()
130136
// CHECK: [[GEN2_CONFORMANCES_TO_Q:%[^,]+]] = alloca i8**, [[INT]] [[SHAPE]]
137+
// CHECK: [[HEAPIFIED_GEN2_CONFORMANCES_TO_Q:%[^%]+]] = call swiftcc i8*** @swift_allocateWitnessTablePack(i8*** [[GEN2_CONFORMANCES_TO_Q]], i64 [[SHAPE]])
138+
// CHECK: call void @llvm.stackrestore(i8* [[STORED_STACK_LOC]])
131139
// CHECK: call swiftcc void @associatedtype_with_forwarded_conformance_1_callee(
132140
// CHECK-SAME: [[INT]] [[SHAPE]],
133-
// CHECK-SAME: %swift.type** [[GEN2_TYPES]],
134-
// CHECK-SAME: i8*** [[GEN2_CONFORMANCES_TO_Q]])
141+
// CHECK-SAME: %swift.type** [[HEAPIFIED_GEN2_TYPES]],
142+
// CHECK-SAME: i8*** [[HEAPIFIED_GEN2_CONFORMANCES_TO_Q]])
135143
sil @associatedtype_with_forwarded_conformance_1 : $<each T : Q> () -> () {
136144
%i = function_ref @associatedtype_with_forwarded_conformance_1_callee : $@convention(thin) <each T : Q> () -> ()
137145
apply %i<Pack{repeat Gen2<each T>}>() : $@convention(thin) <each T : Q> () -> ()
@@ -148,11 +156,15 @@ sil @associatedtype_with_forwarded_conformance_1_callee : $<each T : Q> () -> ()
148156
// CHECK-SAME: i8*** %"each T.PA",
149157
// CHECK-SAME: i8*** %"each T.A.Q")
150158
// CHECK: [[GEN1_TYPES:%[^,]+]] = alloca %swift.type*, [[INT]] [[SHAPE]]
159+
// CHECK: [[HEAPIFIED_GEN1_TYPES:%[^,]+]] = call swiftcc %swift.type** @swift_allocateMetadataPack(%swift.type** [[GEN1_TYPES]], i64 [[SHAPE]])
160+
// CHECK: [[STORED_STACK_LOC:%[^,]+]] = call i8* @llvm.stacksave()
151161
// CHECK: [[GEN1_CONFORMANCES_TO_PA:%[^,]+]] = alloca i8**, [[INT]] [[SHAPE]]
162+
// CHECK: [[HEAPIFIED_GEN1_CONFORMANCES_TO_PA:%[^%]+]] = call swiftcc i8*** @swift_allocateWitnessTablePack(i8*** [[GEN1_CONFORMANCES_TO_PA]], i64 [[SHAPE]])
163+
// CHECK: call void @llvm.stackrestore(i8* [[STORED_STACK_LOC]])
152164
// CHECK: call swiftcc void @generictype_with_forwarded_conformance_2_callee(
153165
// CHECK-SAME: [[INT]] [[SHAPE]],
154-
// CHECK-SAME: %swift.type** [[GEN1_TYPES]],
155-
// CHECK-SAME: i8*** [[GEN1_CONFORMANCES_TO_PA]],
166+
// CHECK-SAME: %swift.type** [[HEAPIFIED_GEN1_TYPES]],
167+
// CHECK-SAME: i8*** [[HEAPIFIED_GEN1_CONFORMANCES_TO_PA]],
156168
// CHECK-SAME: i8*** %"each T.A.Q")
157169
sil @generictype_with_forwarded_conformance_2 : $<each T : PA where repeat each T.A : Q>() -> () {
158170
%callee = function_ref @generictype_with_forwarded_conformance_2_callee : $@convention(thin) <each T : PA where repeat each T.A : Q> () -> ()
@@ -169,11 +181,15 @@ sil @generictype_with_forwarded_conformance_2_callee : $<each T : PA where repea
169181
// CHECK-SAME: i8*** %"each T.PA",
170182
// CHECK-SAME: i8*** %"each T.A.Q")
171183
// CHECK: [[GEN1_GEN1_TYPES:%[^,]+]] = alloca %swift.type*, [[INT]] [[SHAPE]]
184+
// CHECK: [[HEAPIFIED_GEN1_GEN1_TYPES:%[^%]+]] = call swiftcc %swift.type** @swift_allocateMetadataPack(%swift.type** [[GEN1_GEN1_TYPES]], i64 [[SHAPE]])
185+
// CHECK: [[STORED_STACK_LOC:%[^,]+]] = call i8* @llvm.stacksave()
172186
// CHECK: [[GEN1_GEN1_CONFORMANCES_TO_PA:%[^,]+]] = alloca i8**, [[INT]] [[SHAPE]]
187+
// CHECK: [[HEAPIFIED_GEN1_GEN1_CONFORMANCES_TO_PA:%[^%]+]] = call swiftcc i8*** @swift_allocateWitnessTablePack(i8*** [[GEN1_GEN1_CONFORMANCES_TO_PA]], i64 [[SHAPE]])
188+
// CHECK: call void @llvm.stackrestore(i8* [[STORED_STACK_LOC]])
173189
// CHECK: call swiftcc void @generic_with_forwarded_conformance_3_callee(
174190
// CHECK-SAME: [[INT]] [[SHAPE]],
175-
// CHECK-SAME: %swift.type** [[GEN1_GEN1_TYPES]],
176-
// CHECK-SAME: i8*** [[GEN1_GEN1_CONFORMANCES_TO_PA]],
191+
// CHECK-SAME: %swift.type** [[HEAPIFIED_GEN1_GEN1_TYPES]],
192+
// CHECK-SAME: i8*** [[HEAPIFIED_GEN1_GEN1_CONFORMANCES_TO_PA]],
177193
// CHECK-SAME: i8*** %"each T.A.Q")
178194
sil @generic_with_forwarded_conformance_3 : $<each T : PA where repeat each T.A : Q> () -> () {
179195
%callee = function_ref @generic_with_forwarded_conformance_3_callee : $@convention(thin) <each T : PA where repeat each T.A : Q> () -> ()
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// RUN: %target-run-simple-swift(-parse-sil)
2+
// RUN: %target-swift-frontend -parse-sil -emit-ir -primary-file %s | %IRGenFileCheck %s
3+
4+
// REQUIRES: executable_test
5+
6+
// Allocate metadata packs on the stack in a loop. If these packs weren't
7+
// deallocated, the stack would be exhausted.
8+
9+
import Builtin
10+
import Swift
11+
12+
struct S {}
13+
14+
sil [ossa] @main : $@convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 {
15+
bb0(%0 : $Int32, %1 : $UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>):
16+
%looper = function_ref @looper : $@convention(thin) <each T_1, each T_2> () -> ()
17+
apply %looper<Pack{S, S, S}, Pack{S, S}>() : $@convention(thin) <each T_1, each T_2> () -> ()
18+
19+
// If the stack were exhausted while looping, the apply of %looper would crash
20+
// and execution would never reach this point.
21+
22+
%out_literal = integer_literal $Builtin.Int32, 0
23+
%out = struct $Int32 (%out_literal : $Builtin.Int32)
24+
return %out : $Int32
25+
}
26+
27+
sil @callee : $@convention(thin) <each T> () -> () {
28+
%retval = tuple ()
29+
return %retval : $()
30+
}
31+
32+
// CHECK-LABEL: define {{.*}}@looper(
33+
// CHECK-SAME: [[INT]] %0, [[INT]] %1, %swift.type** %"each T_1", %swift.type** %"each T_2") {{.*}} {
34+
// CHECK: [[ENTRY:entry]]:
35+
// CHECK: br label %[[HEADER:[^,]+]]
36+
// CHECK: [[HEADER]]:
37+
// CHECK: [[PREVIOUS:%[^,]+]] = phi i64 [ 10000000, %[[ENTRY]] ], [ [[REMAINING:%[^,]+]], %{{[^,]+}} ]
38+
// CHECK: [[COMBINED_PACK_SIZE:%[^,]+]] = add [[INT]] %0, %1
39+
// CHECK: [[STACK_BEFORE_FIRST_ALLOCA:%[^,]+]] = call i8* @llvm.stacksave()
40+
// CHECK: [[FIRST_ALLOCA_METDATA_PACK:%[^,]+]] = alloca %swift.type*, [[INT]] [[COMBINED_PACK_SIZE]]
41+
// CHECK: [[FIRST_HEAPIFIED_METADATA_PACK:%[^,]+]] = call swiftcc %swift.type** @swift_allocateMetadataPack(%swift.type** [[FIRST_ALLOCA_METDATA_PACK]], [[INT]] [[COMBINED_PACK_SIZE]])
42+
// CHECK: call void @llvm.stackrestore(i8* [[STACK_BEFORE_FIRST_ALLOCA]])
43+
// CHECK: call swiftcc void @callee([[INT]] [[COMBINED_PACK_SIZE]], %swift.type** [[FIRST_HEAPIFIED_METADATA_PACK]])
44+
// CHECK: [[COMBINED_PACK_SIZE_2:%[^,]+]] = add [[INT]] %1, %0
45+
// CHECK: [[STACK_BEFORE_SECOND_ALLOCA:%[^,]+]] = call i8* @llvm.stacksave()
46+
// CHECK: [[SECOND_ALLOCA_METDATA_PACK:%[^,]+]] = alloca %swift.type*, [[INT]] [[COMBINED_PACK_SIZE_2]]
47+
// CHECK: [[SECOND_HEAPIFIED_METADATA_PACK:%[^,]+]] = call swiftcc %swift.type** @swift_allocateMetadataPack(%swift.type** [[SECOND_ALLOCA_METDATA_PACK]], [[INT]] [[COMBINED_PACK_SIZE_2]])
48+
// CHECK: call void @llvm.stackrestore(i8* [[STACK_BEFORE_SECOND_ALLOCA]])
49+
// CHECK: call swiftcc void @callee([[INT]] [[COMBINED_PACK_SIZE_2]], %swift.type** [[SECOND_HEAPIFIED_METADATA_PACK]])
50+
// CHECK: [[REMAINING_AND_OVERFLOW:%[^,]+]] = call { i64, i1 } @llvm.ssub.with.overflow.i64(i64 [[PREVIOUS]], i64 1)
51+
// CHECK: [[REMAINING]] = extractvalue { i64, i1 } [[REMAINING_AND_OVERFLOW]], 0
52+
// CHECK: [[IS_ZERO:%[^,]+]] = icmp eq i64 [[REMAINING]], 0
53+
// CHECK: br i1 [[IS_ZERO]], label %[[EXIT:[^,]+]], label %[[BACKEDGE:[^,]+]]
54+
// CHECK: [[BACKEDGE]]:
55+
// CHECK: br label %[[HEADER]]
56+
// CHECK: [[EXIT]]:
57+
// CHECK: ret void
58+
// CHECK: }
59+
sil @looper : $@convention(thin) <each T_1, each T_2> () -> () {
60+
entry:
61+
%callee = function_ref @callee : $@convention(thin) <each T> () -> ()
62+
%initial = integer_literal $Builtin.Int64, 10000000
63+
br header(%initial : $Builtin.Int64)
64+
header(%previous : $Builtin.Int64):
65+
apply %callee<Pack{repeat each T_1, repeat each T_2}>() : $@convention(thin) <each T> () -> ()
66+
apply %callee<Pack{repeat each T_2, repeat each T_1}>() : $@convention(thin) <each T> () -> ()
67+
%offset = integer_literal $Builtin.Int64, 1
68+
%flag = integer_literal $Builtin.Int1, -1
69+
%remainingAndOverflow = builtin "ssub_with_overflow_Int64"(%previous : $Builtin.Int64, %offset : $Builtin.Int64, %flag : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1)
70+
%remaining = tuple_extract %remainingAndOverflow : $(Builtin.Int64, Builtin.Int1), 0
71+
%zero = integer_literal $Builtin.Int64, 0
72+
%isZero = builtin "cmp_eq_Int64"(%remaining : $Builtin.Int64, %zero : $Builtin.Int64) : $Builtin.Int1
73+
cond_br %isZero, exit, backedge
74+
backedge:
75+
br header(%remaining : $Builtin.Int64)
76+
exit:
77+
%retval = tuple ()
78+
return %retval : $()
79+
}

0 commit comments

Comments
 (0)