Skip to content

Commit ba4aa08

Browse files
committed
[IRGen] Emit PAF for generic methods.
Previously, the partial application of a generic method at the receiver would result in the emission of a "simple" partial apply where the receiver was treated as the context and the original function was treated as the function. That was problematic because such partial applications must capture the polymorphic arguments supplied at partial_apply time. Here, a full partial application forwarder is emitted for this case. rdar://76479222
1 parent 6c11713 commit ba4aa08

File tree

2 files changed

+219
-0
lines changed

2 files changed

+219
-0
lines changed

lib/IRGen/IRGenSIL.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3221,6 +3221,13 @@ static bool isSimplePartialApply(IRGenFunction &IGF, PartialApplyInst *i) {
32213221

32223222
if (calleeTy->getRepresentation() != SILFunctionTypeRepresentation::Method)
32233223
return false;
3224+
3225+
// Partially applying a polymorphic function entails capturing its generic
3226+
// arguments (it is not legal to leave any polymorphic arguments unbound)
3227+
// which means that both self and those generic arguments would need to be
3228+
// captured.
3229+
if (calleeTy->isPolymorphic())
3230+
return false;
32243231

32253232
// There should be one applied argument.
32263233
// (This is a bit stricter than necessary, because empty arguments could be
Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift-dylib(%t/%target-library-name(PrintShims)) %S/../Inputs/print-shims.swift -module-name PrintShims -emit-module -emit-module-path %t/PrintShims.swiftmodule
3+
// RUN: %target-codesign %t/%target-library-name(PrintShims)
4+
// RUN: %target-build-swift -g -parse-sil %s -emit-ir -I %t -L %t -lPrintShim | %FileCheck %s --check-prefix=CHECK-LL
5+
// RUN: %target-build-swift -g -parse-sil %s -module-name main -o %t/main -I %t -L %t -lPrintShims %target-rpath(%t)
6+
// RUN: %target-codesign %t/main
7+
// RUN: %target-run %t/main %t/%target-library-name(PrintShims) | %FileCheck %s
8+
9+
// REQUIRES: executable_test
10+
// REQUIRES: swift_test_mode_optimize_none
11+
12+
sil_stage raw
13+
14+
import Builtin
15+
import Swift
16+
import SwiftShims
17+
18+
// CHECK-LL-LABEL: define hidden swiftcc void @call_generic_function
19+
// CHECK-LL: call swiftcc void @"$sTA"
20+
sil hidden [ossa] @call_generic_function : $@convention(thin) <On, T where On : C> (@guaranteed On, @in_guaranteed T) -> @out T {
21+
bb0(%out : $*T, %on_guaranteed : @guaranteed $On, %in : $*T):
22+
%on = copy_value %on_guaranteed : $On
23+
%c = upcast %on : $On to $C
24+
%method = class_method %c : $C, #C.generic_function : <T> (C) -> (T) -> T, $@convention(method) <τ_0_0> (@in_guaranteed τ_0_0, @guaranteed C) -> @out τ_0_0
25+
%closure = partial_apply [callee_guaranteed] %method<T>(%c) : $@convention(method) <τ_1_0> (@in_guaranteed τ_1_0, @guaranteed C) -> @out τ_1_0
26+
%result = apply %closure(%out, %in) : $@callee_guaranteed (@in_guaranteed T) -> @out T
27+
destroy_value %closure : $@callee_guaranteed (@in_guaranteed T) -> @out T
28+
return %result : $()
29+
}
30+
31+
32+
33+
34+
35+
36+
37+
38+
39+
40+
41+
42+
43+
class C {
44+
@_silgen_name("generic_function")
45+
func generic_function<T>(_ t: T) -> T
46+
deinit
47+
init()
48+
}
49+
50+
@_silgen_name("call_generic_function")
51+
func call_generic_function<On, T>(on: On, with t: T) -> T where On : C
52+
53+
@main struct Main {
54+
static func main()
55+
init()
56+
}
57+
58+
59+
sil hidden [ossa] @generic_function : $@convention(method) <T> (@in_guaranteed T, @guaranteed C) -> @out T {
60+
61+
62+
63+
bb0(%0 : $*T, %1 : $*T, %2 : @guaranteed $C):
64+
debug_value_addr %1 : $*T, let, name "t", argno 1
65+
debug_value %2 : $C, let, name "self", argno 2
66+
copy_addr %1 to [initialization] %0 : $*T
67+
%6 = tuple ()
68+
return %6 : $()
69+
}
70+
71+
72+
sil hidden [ossa] @$s4main1CCfd : $@convention(method) (@guaranteed C) -> @owned Builtin.NativeObject {
73+
74+
bb0(%0 : @guaranteed $C):
75+
debug_value %0 : $C, let, name "self", argno 1
76+
%2 = unchecked_ref_cast %0 : $C to $Builtin.NativeObject
77+
%3 = unchecked_ownership_conversion %2 : $Builtin.NativeObject, @guaranteed to @owned
78+
return %3 : $Builtin.NativeObject
79+
}
80+
81+
82+
sil hidden [ossa] @$s4main1CCfD : $@convention(method) (@owned C) -> () {
83+
84+
bb0(%0 : @owned $C):
85+
debug_value %0 : $C, let, name "self", argno 1
86+
87+
%2 = function_ref @$s4main1CCfd : $@convention(method) (@guaranteed C) -> @owned Builtin.NativeObject
88+
%3 = begin_borrow %0 : $C
89+
%4 = apply %2(%3) : $@convention(method) (@guaranteed C) -> @owned Builtin.NativeObject
90+
end_borrow %3 : $C
91+
end_lifetime %0 : $C
92+
%7 = unchecked_ref_cast %4 : $Builtin.NativeObject to $C
93+
dealloc_ref %7 : $C
94+
%9 = tuple ()
95+
return %9 : $()
96+
}
97+
98+
99+
sil hidden [exact_self_class] [ossa] @$s4main1CCACycfC : $@convention(method) (@thick C.Type) -> @owned C {
100+
101+
bb0(%0 : $@thick C.Type):
102+
%1 = alloc_ref $C
103+
104+
%2 = function_ref @$s4main1CCACycfc : $@convention(method) (@owned C) -> @owned C
105+
%3 = apply %2(%1) : $@convention(method) (@owned C) -> @owned C
106+
return %3 : $C
107+
}
108+
109+
110+
sil hidden [ossa] @$s4main1CCACycfc : $@convention(method) (@owned C) -> @owned C {
111+
112+
bb0(%0 : @owned $C):
113+
debug_value %0 : $C, let, name "self", argno 1
114+
%2 = mark_uninitialized [rootself] %0 : $C
115+
%3 = copy_value %2 : $C
116+
destroy_value %2 : $C
117+
return %3 : $C
118+
}
119+
120+
121+
sil hidden [ossa] @$s4main4MainVAAyyFZ : $@convention(method) (@thin Main.Type) -> () {
122+
123+
bb0(%0 : $@thin Main.Type):
124+
debug_value %0 : $@thin Main.Type, let, name "self", argno 1
125+
%2 = metatype $@thick C.Type
126+
127+
%3 = function_ref @$s4main1CCACycfC : $@convention(method) (@thick C.Type) -> @owned C
128+
%4 = apply %3(%2) : $@convention(method) (@thick C.Type) -> @owned C
129+
debug_value %4 : $C, let, name "s"
130+
%6 = integer_literal $Builtin.IntLiteral, 42
131+
%7 = metatype $@thin Int.Type
132+
133+
%8 = function_ref @$sSi22_builtinIntegerLiteralSiBI_tcfC : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int
134+
%9 = apply %8(%6, %7) : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int
135+
debug_value %9 : $Int, let, name "t"
136+
%11 = alloc_stack $Int
137+
%12 = begin_borrow %4 : $C
138+
%13 = alloc_stack $Int
139+
store %9 to [trivial] %13 : $*Int
140+
141+
%15 = function_ref @call_generic_function : $@convention(thin) <τ_0_0, τ_0_1 where τ_0_0 : C> (@guaranteed τ_0_0, @in_guaranteed τ_0_1) -> @out τ_0_1
142+
%16 = apply %15<C, Int>(%11, %12, %13) : $@convention(thin) <τ_0_0, τ_0_1 where τ_0_0 : C> (@guaranteed τ_0_0, @in_guaranteed τ_0_1) -> @out τ_0_1
143+
dealloc_stack %13 : $*Int
144+
end_borrow %12 : $C
145+
%19 = load [trivial] %11 : $*Int
146+
debug_value %19 : $Int, let, name "out"
147+
dealloc_stack %11 : $*Int
148+
%22 = alloc_stack $Int
149+
store %19 to [trivial] %22 : $*Int
150+
151+
%24 = function_ref @printGeneric : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> ()
152+
// CHECK: 42
153+
%25 = apply %24<Int>(%22) : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> ()
154+
dealloc_stack %22 : $*Int
155+
destroy_value %4 : $C
156+
%28 = tuple ()
157+
return %28 : $()
158+
}
159+
160+
161+
sil [transparent] [serialized] @$sSi22_builtinIntegerLiteralSiBI_tcfC : $@convention(method) (Builtin.IntLiteral, @thin Int.Type) -> Int
162+
163+
164+
sil public_external @printGeneric : $@convention(thin) <T> (@in_guaranteed T) -> ()
165+
166+
167+
sil hidden [ossa] @$s4main4MainVACycfC : $@convention(method) (@thin Main.Type) -> Main {
168+
169+
bb0(%0 : $@thin Main.Type):
170+
%1 = alloc_box ${ var Main }, var, name "self"
171+
%2 = mark_uninitialized [rootself] %1 : ${ var Main }
172+
%3 = project_box %2 : ${ var Main }, 0
173+
%4 = load [trivial] %3 : $*Main
174+
destroy_value %2 : ${ var Main }
175+
return %4 : $Main
176+
}
177+
178+
179+
sil hidden [ossa] @$s4main4MainV5$mainyyFZ : $@convention(method) (@thin Main.Type) -> () {
180+
181+
bb0(%0 : $@thin Main.Type):
182+
debug_value %0 : $@thin Main.Type, let, name "self", argno 1
183+
%2 = metatype $@thin Main.Type
184+
185+
%3 = function_ref @$s4main4MainVAAyyFZ : $@convention(method) (@thin Main.Type) -> ()
186+
%4 = apply %3(%2) : $@convention(method) (@thin Main.Type) -> ()
187+
%5 = tuple ()
188+
return %5 : $()
189+
}
190+
191+
192+
193+
sil [ossa] @main : $@convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 {
194+
bb0(%0 : $Int32, %1 : $UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>):
195+
%2 = metatype $@thin Main.Type
196+
197+
%3 = function_ref @$s4main4MainV5$mainyyFZ : $@convention(method) (@thin Main.Type) -> ()
198+
%4 = apply %3(%2) : $@convention(method) (@thin Main.Type) -> ()
199+
%5 = integer_literal $Builtin.Int32, 0
200+
br bb1(%5 : $Builtin.Int32)
201+
202+
203+
bb1(%7 : $Builtin.Int32):
204+
%8 = struct $Int32 (%7 : $Builtin.Int32)
205+
return %8 : $Int32
206+
}
207+
208+
sil_vtable C {
209+
#C.generic_function: <T> (C) -> (T) -> T : @generic_function
210+
#C.init!allocator: (C.Type) -> () -> C : @$s4main1CCACycfC
211+
#C.deinit!deallocator: @$s4main1CCfD
212+
}

0 commit comments

Comments
 (0)