Skip to content

Commit 7d74a86

Browse files
committed
[Concurrency] Async CC supports witness methods.
Previously, the AsyncContextLayout did not make space for the trailing witness fields (self metadata and self witness table) and the AsyncNativeCCEntryPointArgumentEmission could consequently not vend these fields. Here, the fields are added to the layout.
1 parent eba39cf commit 7d74a86

7 files changed

+337
-24
lines changed

lib/IRGen/GenCall.cpp

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,28 @@ AsyncContextLayout irgen::getAsyncContextLayout(
181181
paramInfos.push_back({ty, parameter.getConvention()});
182182
}
183183

184+
Optional<AsyncContextLayout::TrailingWitnessInfo> trailingWitnessInfo;
185+
if (originalType->getRepresentation() ==
186+
SILFunctionTypeRepresentation::WitnessMethod) {
187+
assert(getTrailingWitnessSignatureLength(IGF.IGM, originalType) == 2);
188+
189+
// First, the Self metadata.
190+
{
191+
auto ty = SILType();
192+
auto &ti = IGF.IGM.getTypeMetadataPtrTypeInfo();
193+
valTypes.push_back(ty);
194+
typeInfos.push_back(&ti);
195+
}
196+
// Then, the Self witness table.
197+
{
198+
auto ty = SILType();
199+
auto &ti = IGF.IGM.getWitnessTablePtrTypeInfo();
200+
valTypes.push_back(ty);
201+
typeInfos.push_back(&ti);
202+
}
203+
trailingWitnessInfo = AsyncContextLayout::TrailingWitnessInfo();
204+
}
205+
184206
// ResultTypes directResults...;
185207
auto directResults = fnConv.getDirectSILResults();
186208
for (auto result : directResults) {
@@ -192,20 +214,20 @@ AsyncContextLayout irgen::getAsyncContextLayout(
192214
directReturnInfos.push_back(result);
193215
}
194216

195-
return AsyncContextLayout(IGF.IGM, LayoutStrategy::Optimal, valTypes,
196-
typeInfos, IGF, originalType, substitutedType,
197-
substitutionMap, std::move(bindings), errorType,
198-
canHaveValidError, paramInfos, indirectReturnInfos,
199-
directReturnInfos, localContextInfo);
217+
return AsyncContextLayout(
218+
IGF.IGM, LayoutStrategy::Optimal, valTypes, typeInfos, IGF, originalType,
219+
substitutedType, substitutionMap, std::move(bindings),
220+
trailingWitnessInfo, errorType, canHaveValidError, paramInfos,
221+
indirectReturnInfos, directReturnInfos, localContextInfo);
200222
}
201223

202224
AsyncContextLayout::AsyncContextLayout(
203225
IRGenModule &IGM, LayoutStrategy strategy, ArrayRef<SILType> fieldTypes,
204226
ArrayRef<const TypeInfo *> fieldTypeInfos, IRGenFunction &IGF,
205227
CanSILFunctionType originalType, CanSILFunctionType substitutedType,
206228
SubstitutionMap substitutionMap, NecessaryBindings &&bindings,
207-
SILType errorType, bool canHaveValidError,
208-
ArrayRef<ArgumentInfo> argumentInfos,
229+
Optional<TrailingWitnessInfo> trailingWitnessInfo, SILType errorType,
230+
bool canHaveValidError, ArrayRef<ArgumentInfo> argumentInfos,
209231
ArrayRef<SILResultInfo> indirectReturnInfos,
210232
ArrayRef<SILResultInfo> directReturnInfos,
211233
Optional<AsyncContextLayout::ArgumentInfo> localContextInfo)
@@ -218,6 +240,7 @@ AsyncContextLayout::AsyncContextLayout(
218240
indirectReturnInfos(indirectReturnInfos.begin(),
219241
indirectReturnInfos.end()),
220242
localContextInfo(localContextInfo), bindings(std::move(bindings)),
243+
trailingWitnessInfo(trailingWitnessInfo),
221244
argumentInfos(argumentInfos.begin(), argumentInfos.end()) {
222245
#ifndef NDEBUG
223246
assert(fieldTypeInfos.size() == fieldTypes.size() &&

lib/IRGen/GenCall.h

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ namespace irgen {
8989
SILType type;
9090
ParameterConvention convention;
9191
};
92+
struct TrailingWitnessInfo {};
9293

9394
private:
9495
enum class FixedIndex : unsigned {
@@ -107,6 +108,7 @@ namespace irgen {
107108
SmallVector<SILResultInfo, 4> indirectReturnInfos;
108109
Optional<ArgumentInfo> localContextInfo;
109110
NecessaryBindings bindings;
111+
Optional<TrailingWitnessInfo> trailingWitnessInfo;
110112
SmallVector<ArgumentInfo, 4> argumentInfos;
111113

112114
unsigned getErrorIndex() { return (unsigned)FixedIndex::Error; }
@@ -125,13 +127,27 @@ namespace irgen {
125127
assert(hasBindings());
126128
return getIndexAfterLocalContext();
127129
}
128-
unsigned getFirstArgumentIndex() {
130+
unsigned getIndexAfterBindings() {
129131
return getIndexAfterLocalContext() + (hasBindings() ? 1 : 0);
130132
}
133+
unsigned getFirstArgumentIndex() { return getIndexAfterBindings(); }
131134
unsigned getIndexAfterArguments() {
132135
return getFirstArgumentIndex() + getArgumentCount();
133136
}
134-
unsigned getFirstDirectReturnIndex() { return getIndexAfterArguments(); }
137+
unsigned getSelfMetadataIndex() {
138+
assert(hasTrailingWitnesses());
139+
return getIndexAfterArguments();
140+
}
141+
unsigned getSelfWitnessTableIndex() {
142+
assert(hasTrailingWitnesses());
143+
return getIndexAfterArguments() + 1;
144+
}
145+
unsigned getIndexAfterTrailingWitnesses() {
146+
return getIndexAfterArguments() + (hasTrailingWitnesses() ? 2 : 0);
147+
}
148+
unsigned getFirstDirectReturnIndex() {
149+
return getIndexAfterTrailingWitnesses();
150+
}
135151

136152
public:
137153
bool canHaveError() { return canHaveValidError; }
@@ -180,24 +196,30 @@ namespace irgen {
180196
index, IGF.IGM.getMaximalTypeExpansionContext());
181197
}
182198
unsigned getArgumentCount() { return argumentInfos.size(); }
199+
bool hasTrailingWitnesses() { return (bool)trailingWitnessInfo; }
200+
ElementLayout getSelfMetadataLayout() {
201+
assert(hasTrailingWitnesses());
202+
return getElement(getSelfMetadataIndex());
203+
}
204+
ElementLayout getSelfWitnessTableLayout() {
205+
return getElement(getSelfWitnessTableIndex());
206+
}
183207

184208
unsigned getDirectReturnCount() { return directReturnInfos.size(); }
185209
ElementLayout getDirectReturnLayout(unsigned index) {
186210
return getElement(getFirstDirectReturnIndex() + index);
187211
}
188212

189-
AsyncContextLayout(IRGenModule &IGM, LayoutStrategy strategy,
190-
ArrayRef<SILType> fieldTypes,
191-
ArrayRef<const TypeInfo *> fieldTypeInfos,
192-
IRGenFunction &IGF, CanSILFunctionType originalType,
193-
CanSILFunctionType substitutedType,
194-
SubstitutionMap substitutionMap,
195-
NecessaryBindings &&bindings, SILType errorType,
196-
bool canHaveValidError,
197-
ArrayRef<ArgumentInfo> argumentInfos,
198-
ArrayRef<SILResultInfo> directReturnInfos,
199-
ArrayRef<SILResultInfo> indirectReturnInfos,
200-
Optional<ArgumentInfo> localContextInfo);
213+
AsyncContextLayout(
214+
IRGenModule &IGM, LayoutStrategy strategy, ArrayRef<SILType> fieldTypes,
215+
ArrayRef<const TypeInfo *> fieldTypeInfos, IRGenFunction &IGF,
216+
CanSILFunctionType originalType, CanSILFunctionType substitutedType,
217+
SubstitutionMap substitutionMap, NecessaryBindings &&bindings,
218+
Optional<TrailingWitnessInfo> trailingWitnessInfo, SILType errorType,
219+
bool canHaveValidError, ArrayRef<ArgumentInfo> argumentInfos,
220+
ArrayRef<SILResultInfo> directReturnInfos,
221+
ArrayRef<SILResultInfo> indirectReturnInfos,
222+
Optional<ArgumentInfo> localContextInfo);
201223
};
202224

203225
AsyncContextLayout getAsyncContextLayout(IRGenFunction &IGF,

lib/IRGen/GenProto.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3098,7 +3098,11 @@ NecessaryBindings NecessaryBindings::computeBindings(
30983098
continue;
30993099

31003100
case MetadataSource::Kind::SelfMetadata:
3101-
bindings.addTypeMetadata(getSubstSelfType(IGM, origType, subs));
3101+
// Async functions pass the SelfMetadata and SelfWitnessTable parameters
3102+
// along explicitly.
3103+
if (forPartialApplyForwarder) {
3104+
bindings.addTypeMetadata(getSubstSelfType(IGM, origType, subs));
3105+
}
31023106
continue;
31033107

31043108
case MetadataSource::Kind::SelfWitnessTable:

lib/IRGen/IRGenSIL.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1257,9 +1257,23 @@ class AsyncNativeCCEntryPointArgumentEmission final
12571257
return explosion.claimNext();
12581258
};
12591259
llvm::Value *getSelfWitnessTable() override {
1260-
llvm_unreachable("unimplemented");
1260+
auto fieldLayout = layout.getSelfWitnessTableLayout();
1261+
Address fieldAddr =
1262+
fieldLayout.project(IGF, dataAddr, /*offsets*/ llvm::None);
1263+
auto &ti = cast<LoadableTypeInfo>(fieldLayout.getType());
1264+
Explosion explosion;
1265+
ti.loadAsTake(IGF, fieldAddr, explosion);
1266+
return explosion.claimNext();
1267+
}
1268+
llvm::Value *getSelfMetadata() override {
1269+
auto fieldLayout = layout.getSelfMetadataLayout();
1270+
Address fieldAddr =
1271+
fieldLayout.project(IGF, dataAddr, /*offsets*/ llvm::None);
1272+
auto &ti = cast<LoadableTypeInfo>(fieldLayout.getType());
1273+
Explosion explosion;
1274+
ti.loadAsTake(IGF, fieldAddr, explosion);
1275+
return explosion.claimNext();
12611276
}
1262-
llvm::Value *getSelfMetadata() override { llvm_unreachable("unimplemented"); }
12631277
llvm::Value *getCoroutineBuffer() override {
12641278
llvm_unreachable("unimplemented");
12651279
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
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 -Xfrontend -enable-experimental-concurrency -parse-sil %s -emit-ir -I %t -L %t -lPrintShim | %FileCheck %s --check-prefix=CHECK-LL
5+
// RUN: %target-build-swift -Xfrontend -enable-experimental-concurrency -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 | %FileCheck %s
8+
9+
// REQUIRES: executable_test
10+
// REQUIRES: swift_test_mode_optimize_none
11+
// UNSUPPORTED: use_os_stdlib
12+
13+
import Builtin
14+
import Swift
15+
import PrintShims
16+
17+
sil public_external @printGeneric : $@convention(thin) <T> (@in_guaranteed T) -> ()
18+
sil public_external @printInt64 : $@convention(thin) (Int64) -> ()
19+
20+
protocol P {
21+
func printMe() async -> Int64
22+
}
23+
24+
struct I : P {
25+
@_hasStorage let int: Int64 { get }
26+
func printMe() async -> Int64
27+
init(int: Int64)
28+
}
29+
30+
// CHECK-LL-LABEL: define hidden swiftcc void @I_printMe(%swift.context* {{%[0-9]*}}) {{#[0-9]*}} {
31+
sil hidden @I_printMe : $@async @convention(method) (I) -> Int64 {
32+
bb0(%self : $I):
33+
%self_addr = alloc_stack $I
34+
store %self to %self_addr : $*I
35+
%printGeneric = function_ref @printGeneric : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> ()
36+
%printGeneric_result = apply %printGeneric<I>(%self_addr) : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> ()
37+
dealloc_stack %self_addr : $*I
38+
%result = struct_extract %self : $I, #I.int
39+
return %result : $Int64
40+
}
41+
42+
// CHECK-LL-LABEL: define internal swiftcc void @I_P_printMe(%swift.context* {{%[0-9]*}}) {{#[0-9]*}} {
43+
sil private [transparent] [thunk] @I_P_printMe : $@async @convention(witness_method: P) (@in_guaranteed I) -> Int64 {
44+
bb0(%self_addr : $*I):
45+
%self = load %self_addr : $*I
46+
%I_printMe = function_ref @I_printMe : $@async @convention(method) (I) -> Int64
47+
%result = apply %I_printMe(%self) : $@async @convention(method) (I) -> Int64
48+
return %result : $Int64
49+
}
50+
51+
sil @main : $@convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 {
52+
bb0(%0 : $Int32, %1 : $UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>):
53+
%i_type = metatype $@thin I.Type
54+
%i_int_literal = integer_literal $Builtin.Int64, 99
55+
%i_int = struct $Int64 (%i_int_literal : $Builtin.Int64)
56+
%i = struct $I (%i_int : $Int64)
57+
%i_addr = alloc_stack $I
58+
store %i to %i_addr : $*I
59+
%P_printMe = witness_method $I, #P.printMe : <Self where Self : P> (Self) -> () async -> Int64 : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> Int64
60+
%result = apply %P_printMe<I>(%i_addr) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> Int64 // CHECK: I(int: 99)
61+
dealloc_stack %i_addr : $*I
62+
%printInt64 = function_ref @printInt64 : $@convention(thin) (Int64) -> ()
63+
%printInt64_result = apply %printInt64(%result) : $@convention(thin) (Int64) -> () // CHECK: 99
64+
65+
%out_literal = integer_literal $Builtin.Int32, 0
66+
%out = struct $Int32 (%out_literal : $Builtin.Int32)
67+
return %out : $Int32
68+
}
69+
70+
sil_witness_table hidden I: P module main {
71+
method #P.printMe: <Self where Self : P> (Self) -> () async -> Int64 : @I_P_printMe
72+
}
73+
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
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 -Xfrontend -enable-experimental-concurrency -parse-sil %s -emit-ir -I %t -L %t -lPrintShim | %FileCheck %s --check-prefix=CHECK-LL
5+
// RUN: %target-build-swift -Xfrontend -enable-experimental-concurrency -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 | %FileCheck %s
8+
9+
// REQUIRES: executable_test
10+
// REQUIRES: swift_test_mode_optimize_none
11+
// UNSUPPORTED: use_os_stdlib
12+
13+
import Builtin
14+
import Swift
15+
import PrintShims
16+
17+
sil public_external @printGeneric : $@convention(thin) <T> (@in_guaranteed T) -> ()
18+
sil public_external @printInt64 : $@convention(thin) (Int64) -> ()
19+
20+
protocol P {
21+
func printMe<T>(_ t: T) async -> (Int64, T)
22+
}
23+
24+
extension P {
25+
func callPrintMe<T>(_ t: T) async -> (Int64, T)
26+
}
27+
28+
struct I : P {
29+
@_hasStorage let int: Int64 { get }
30+
func printMe<T>(_ t: T) async -> (Int64, T)
31+
init(int: Int64)
32+
}
33+
34+
sil hidden @I_printMe : $@convention(method) @async <T> (@in_guaranteed T, I) -> (Int64, @out T) {
35+
bb0(%out_addr : $*T, %in_addr : $*T, %self : $I):
36+
%self_addr = alloc_stack $I
37+
store %self to %self_addr : $*I
38+
%printGeneric = function_ref @printGeneric : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> ()
39+
%printGeneric_result = apply %printGeneric<I>(%self_addr) : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> ()
40+
dealloc_stack %self_addr : $*I
41+
%value = struct_extract %self : $I, #I.int
42+
copy_addr %in_addr to [initialization] %out_addr : $*T
43+
return %value : $Int64
44+
}
45+
46+
// CHECK-LL: define internal swiftcc void @I_P_printMe(%swift.context* {{%[0-9]*}}) {{#[0-9]*}} {
47+
sil private [transparent] [thunk] @I_P_printMe : $@convention(witness_method: P) @async <τ_0_0> (@in_guaranteed τ_0_0, @in_guaranteed I) -> (Int64, @out τ_0_0) {
48+
bb0(%out_addr : $*τ_0_0, %in_addr : $*τ_0_0, %self_addr : $*I):
49+
%self = load %self_addr : $*I
50+
%I_printMe = function_ref @I_printMe : $@convention(method) @async <τ_0_0> (@in_guaranteed τ_0_0, I) -> (Int64, @out τ_0_0)
51+
%result = apply %I_printMe<τ_0_0>(%out_addr, %in_addr, %self) : $@convention(method) @async <τ_0_0> (@in_guaranteed τ_0_0, I) -> (Int64, @out τ_0_0)
52+
return %result : $Int64
53+
}
54+
55+
sil hidden @callPrintMe : $@convention(thin) <T, U where T : P> (@in_guaranteed T, @in_guaranteed U) -> (Int64, @out U) {
56+
bb0(%out_addr : $*U, %self_addr : $*T, %in_addr : $*U):
57+
%I_P_printMe = witness_method $T, #P.printMe : <Self where Self : P><T> (Self) -> (T) async -> (Int64, T) : $@convention(witness_method: P) @async <τ_0_0 where τ_0_0 : P><τ_1_0> (@in_guaranteed τ_1_0, @in_guaranteed τ_0_0) -> (Int64, @out τ_1_0)
58+
%result = apply %I_P_printMe<T, U>(%out_addr, %in_addr, %self_addr) : $@convention(witness_method: P) @async <τ_0_0 where τ_0_0 : P><τ_1_0> (@in_guaranteed τ_1_0, @in_guaranteed τ_0_0) -> (Int64, @out τ_1_0)
59+
return %result : $Int64
60+
}
61+
62+
sil @main : $@convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 {
63+
bb0(%argc : $Int32, %argv : $UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>):
64+
%I_type = metatype $@thin I.Type
65+
%int_literal = integer_literal $Builtin.Int64, 99
66+
%int = struct $Int64 (%int_literal : $Builtin.Int64)
67+
%i = struct $I (%int : $Int64)
68+
%out_addr = alloc_stack $I
69+
%in_addr = alloc_stack $I
70+
store %i to %in_addr : $*I
71+
%i_addr = alloc_stack $I
72+
store %i to %i_addr : $*I
73+
%callPrintMe = function_ref @callPrintMe : $@convention(thin) <τ_0_0, τ_0_1 where τ_0_0 : P> (@in_guaranteed τ_0_0, @in_guaranteed τ_0_1) -> (Int64, @out τ_0_1)
74+
%result = apply %callPrintMe<I, I>(%out_addr, %in_addr, %i_addr) : $@convention(thin) <τ_0_0, τ_0_1 where τ_0_0 : P> (@in_guaranteed τ_0_0, @in_guaranteed τ_0_1) -> (Int64, @out τ_0_1)
75+
dealloc_stack %i_addr : $*I
76+
dealloc_stack %in_addr : $*I
77+
%out = load %out_addr : $*I
78+
dealloc_stack %out_addr : $*I
79+
%printInt64 = function_ref @printInt64 : $@convention(thin) (Int64) -> ()
80+
%printInt64_result = apply %printInt64(%result) : $@convention(thin) (Int64) -> () // CHECK: 99
81+
%out_addr_2 = alloc_stack $I
82+
store %out to %out_addr_2 : $*I
83+
%printGeneric = function_ref @printGeneric : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> ()
84+
%printGeneric_result = apply %printGeneric<I>(%out_addr_2) : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> () // CHECK: I(int: 99)
85+
dealloc_stack %out_addr_2 : $*I
86+
87+
88+
89+
%returnCode_literal = integer_literal $Builtin.Int32, 0
90+
%returnCode = struct $Int32 (%returnCode_literal : $Builtin.Int32)
91+
return %returnCode : $Int32
92+
}
93+
94+
95+
sil_witness_table hidden I: P module main {
96+
method #P.printMe: <Self where Self : P><T> (Self) -> (T) async -> (Int64, T) : @I_P_printMe
97+
}

0 commit comments

Comments
 (0)