Skip to content

Commit 1af9977

Browse files
Merge pull request #34200 from nate-chandler/concurrency/irgen/protocol-extension-methods
[Async CC] Support for protocol extension methods.
2 parents d21ff5c + 72051ef commit 1af9977

File tree

5 files changed

+155
-47
lines changed

5 files changed

+155
-47
lines changed

lib/IRGen/GenCall.cpp

Lines changed: 24 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,11 @@ AsyncContextLayout irgen::getAsyncContextLayout(
138138
SILType ty =
139139
IGF.IGM.silConv.getSILType(localContextParameter, substitutedType,
140140
IGF.IGM.getMaximalTypeExpansionContext());
141-
auto &ti = IGF.getTypeInfoForLowered(ty.getASTType());
141+
auto argumentLoweringType =
142+
getArgumentLoweringType(ty.getASTType(), localContextParameter,
143+
/*isNoEscape*/ true);
144+
145+
auto &ti = IGF.getTypeInfoForLowered(argumentLoweringType);
142146
valTypes.push_back(ty);
143147
typeInfos.push_back(&ti);
144148
localContextInfo = {ty, localContextParameter.getConvention()};
@@ -153,7 +157,7 @@ AsyncContextLayout irgen::getAsyncContextLayout(
153157
}
154158

155159
// ArgTypes formalArguments...;
156-
auto bindings = NecessaryBindings::forAsyncFunctionInvocations(
160+
auto bindings = NecessaryBindings::forAsyncFunctionInvocation(
157161
IGF.IGM, originalType, substitutionMap);
158162
if (!bindings.empty()) {
159163
auto bindingsSize = bindings.getBufferSize(IGF.IGM);
@@ -1970,40 +1974,34 @@ class AsyncCallEmission final : public CallEmission {
19701974
llArgs.add(selfValue);
19711975
}
19721976
auto layout = getAsyncContextLayout();
1973-
auto params = fnConv.getParameters();
1974-
for (auto index : indices(params)) {
1975-
Optional<ElementLayout> fieldLayout;
1976-
if (selfValue && index == params.size() - 1) {
1977-
fieldLayout = layout.getLocalContextLayout();
1978-
} else {
1979-
fieldLayout = layout.getArgumentLayout(index);
1980-
}
1977+
for (unsigned index = 0, count = layout.getArgumentCount(); index < count;
1978+
++index) {
1979+
auto fieldLayout = layout.getArgumentLayout(index);
19811980
Address fieldAddr =
1982-
fieldLayout->project(IGF, context, /*offsets*/ llvm::None);
1983-
auto &ti = cast<LoadableTypeInfo>(fieldLayout->getType());
1981+
fieldLayout.project(IGF, context, /*offsets*/ llvm::None);
1982+
auto &ti = cast<LoadableTypeInfo>(fieldLayout.getType());
19841983
ti.initialize(IGF, llArgs, fieldAddr, isOutlined);
19851984
}
1986-
unsigned index = 0;
1987-
for (auto indirectResult : fnConv.getIndirectSILResultTypes(
1988-
IGF.IGM.getMaximalTypeExpansionContext())) {
1989-
(void)indirectResult;
1985+
for (unsigned index = 0, count = layout.getIndirectReturnCount();
1986+
index < count; ++index) {
19901987
auto fieldLayout = layout.getIndirectReturnLayout(index);
19911988
Address fieldAddr =
19921989
fieldLayout.project(IGF, context, /*offsets*/ llvm::None);
19931990
cast<LoadableTypeInfo>(fieldLayout.getType())
19941991
.initialize(IGF, llArgs, fieldAddr, isOutlined);
1995-
++index;
19961992
}
19971993
if (layout.hasBindings()) {
19981994
auto bindingLayout = layout.getBindingsLayout();
19991995
auto bindingsAddr = bindingLayout.project(IGF, context, /*offsets*/ None);
2000-
layout.getBindings().save(IGF, bindingsAddr);
1996+
layout.getBindings().save(IGF, bindingsAddr, llArgs);
1997+
}
1998+
if (selfValue) {
1999+
auto fieldLayout = layout.getLocalContextLayout();
2000+
Address fieldAddr =
2001+
fieldLayout.project(IGF, context, /*offsets*/ llvm::None);
2002+
auto &ti = cast<LoadableTypeInfo>(fieldLayout.getType());
2003+
ti.initialize(IGF, llArgs, fieldAddr, isOutlined);
20012004
}
2002-
// At this point, llArgs contains the arguments that are being passed along
2003-
// via the async context. We can safely drop them on the floor.
2004-
(void)llArgs.claimAll();
2005-
// TODO: Validation: we should be able to check that the contents of llArgs
2006-
// matches what is expected by the layout.
20072005
}
20082006
void emitCallToUnmappedExplosion(llvm::CallInst *call, Explosion &out) override {
20092007
SILFunctionConventions fnConv(getCallee().getSubstFunctionType(),
@@ -2024,15 +2022,14 @@ class AsyncCallEmission final : public CallEmission {
20242022
Explosion nativeExplosion;
20252023
auto layout = getAsyncContextLayout();
20262024
auto dataAddr = layout.emitCastTo(IGF, context);
2027-
int index = layout.getFirstDirectReturnIndex();
2028-
for (auto result : fnConv.getDirectSILResults()) {
2029-
auto &fieldLayout = layout.getElement(index);
2025+
for (unsigned index = 0, count = layout.getDirectReturnCount();
2026+
index < count; ++index) {
2027+
auto fieldLayout = layout.getDirectReturnLayout(index);
20302028
Address fieldAddr =
20312029
fieldLayout.project(IGF, dataAddr, /*offsets*/ llvm::None);
20322030
auto &fieldTI = fieldLayout.getType();
20332031
cast<LoadableTypeInfo>(fieldTI).loadAsTake(IGF, fieldAddr,
20342032
nativeExplosion);
2035-
++index;
20362033
}
20372034

20382035
out = nativeSchema.mapFromNative(IGF.IGM, IGF, nativeExplosion, resultType);

lib/IRGen/GenCall.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,10 @@ namespace irgen {
183183
}
184184

185185
unsigned getFirstDirectReturnIndex() { return getIndexAfterArguments(); }
186+
unsigned getDirectReturnCount() { return directReturnInfos.size(); }
187+
ElementLayout getDirectReturnLayout(unsigned index) {
188+
return getElement(getFirstDirectReturnIndex() + index);
189+
}
186190

187191
AsyncContextLayout(IRGenModule &IGM, LayoutStrategy strategy,
188192
ArrayRef<SILType> fieldTypes,

lib/IRGen/GenProto.cpp

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2728,24 +2728,45 @@ void NecessaryBindings::restore(IRGenFunction &IGF, Address buffer,
27282728
[&](CanType type) { return type;});
27292729
}
27302730

2731+
template <typename Transform>
2732+
static void save(const NecessaryBindings &bindings, IRGenFunction &IGF,
2733+
Address buffer, Transform transform) {
2734+
emitInitOfGenericRequirementsBuffer(
2735+
IGF, bindings.getRequirements().getArrayRef(), buffer,
2736+
[&](GenericRequirement requirement) -> llvm::Value * {
2737+
CanType type = requirement.TypeParameter;
2738+
if (auto protocol = requirement.Protocol) {
2739+
if (auto archetype = dyn_cast<ArchetypeType>(type)) {
2740+
auto wtable =
2741+
emitArchetypeWitnessTableRef(IGF, archetype, protocol);
2742+
return transform(requirement, wtable);
2743+
} else {
2744+
auto conformance = bindings.getConformance(requirement);
2745+
auto wtable = emitWitnessTableRef(IGF, type, conformance);
2746+
return transform(requirement, wtable);
2747+
}
2748+
} else {
2749+
auto metadata = IGF.emitTypeMetadataRef(type);
2750+
return transform(requirement, metadata);
2751+
}
2752+
});
2753+
};
2754+
2755+
void NecessaryBindings::save(IRGenFunction &IGF, Address buffer,
2756+
Explosion &source) const {
2757+
::save(*this, IGF, buffer,
2758+
[&](GenericRequirement requirement,
2759+
llvm::Value *expected) -> llvm::Value * {
2760+
auto *value = source.claimNext();
2761+
assert(value == expected);
2762+
return value;
2763+
});
2764+
}
2765+
27312766
void NecessaryBindings::save(IRGenFunction &IGF, Address buffer) const {
2732-
emitInitOfGenericRequirementsBuffer(IGF, Requirements.getArrayRef(), buffer,
2733-
[&](GenericRequirement requirement) -> llvm::Value* {
2734-
CanType type = requirement.TypeParameter;
2735-
if (auto protocol = requirement.Protocol) {
2736-
if (auto archetype = dyn_cast<ArchetypeType>(type)) {
2737-
auto wtable = emitArchetypeWitnessTableRef(IGF, archetype, protocol);
2738-
return wtable;
2739-
} else {
2740-
auto conformance = getConformance(requirement);
2741-
auto wtable = emitWitnessTableRef(IGF, type, conformance);
2742-
return wtable;
2743-
}
2744-
} else {
2745-
auto metadata = IGF.emitTypeMetadataRef(type);
2746-
return metadata;
2747-
}
2748-
});
2767+
::save(*this, IGF, buffer,
2768+
[](GenericRequirement requirement,
2769+
llvm::Value *value) -> llvm::Value * { return value; });
27492770
}
27502771

27512772
void NecessaryBindings::addTypeMetadata(CanType type) {
@@ -3021,7 +3042,7 @@ void EmitPolymorphicArguments::emit(SubstitutionMap subs,
30213042
}
30223043
}
30233044

3024-
NecessaryBindings NecessaryBindings::forAsyncFunctionInvocations(
3045+
NecessaryBindings NecessaryBindings::forAsyncFunctionInvocation(
30253046
IRGenModule &IGM, CanSILFunctionType origType, SubstitutionMap subs) {
30263047
return computeBindings(IGM, origType, subs,
30273048
false /*forPartialApplyForwarder*/);

lib/IRGen/NecessaryBindings.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
#include "llvm/ADT/SetVector.h"
2626
#include "swift/AST/Types.h"
2727

28+
#include "Explosion.h"
29+
2830
namespace swift {
2931
class CanType;
3032
enum class MetadataState : size_t;
@@ -55,8 +57,8 @@ class NecessaryBindings {
5557
/// Collect the necessary bindings to invoke a function with the given
5658
/// signature.
5759
static NecessaryBindings
58-
forAsyncFunctionInvocations(IRGenModule &IGM, CanSILFunctionType origType,
59-
SubstitutionMap subs);
60+
forAsyncFunctionInvocation(IRGenModule &IGM, CanSILFunctionType origType,
61+
SubstitutionMap subs);
6062
static NecessaryBindings forPartialApplyForwarder(IRGenModule &IGM,
6163
CanSILFunctionType origType,
6264
SubstitutionMap subs,
@@ -94,6 +96,8 @@ class NecessaryBindings {
9496
/// Save the necessary bindings to the given buffer.
9597
void save(IRGenFunction &IGF, Address buffer) const;
9698

99+
void save(IRGenFunction &IGF, Address buffer, Explosion &source) const;
100+
97101
/// Restore the necessary bindings from the given buffer.
98102
void restore(IRGenFunction &IGF, Address buffer, MetadataState state) const;
99103

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
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() -> Int64
22+
}
23+
24+
extension P {
25+
func callPrintMe() async -> Int64
26+
}
27+
28+
struct I : P {
29+
@_hasStorage let int: Int64 { get }
30+
func printMe() -> Int64
31+
init(int: Int64)
32+
}
33+
34+
// CHECK-LL: define hidden swiftcc void @callPrintMe(%swift.context* {{%[0-9]*}}) {{#[0-9]*}} {
35+
sil hidden @callPrintMe : $@async @convention(method) <Self where Self : P> (@in_guaranteed Self) -> Int64 {
36+
bb0(%self : $*Self):
37+
%P_printMe = witness_method $Self, #P.printMe : <Self where Self : P> (Self) -> () -> Int64 : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> Int64
38+
%result = apply %P_printMe<Self>(%self) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> Int64
39+
return %result : $Int64
40+
}
41+
42+
sil hidden @I_printMe : $@convention(method) (I) -> Int64 {
43+
bb0(%self : $I):
44+
%self_addr = alloc_stack $I
45+
store %self to %self_addr : $*I
46+
%printGeneric = function_ref @printGeneric : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> ()
47+
%printGeneric_result = apply %printGeneric<I>(%self_addr) : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> ()
48+
dealloc_stack %self_addr : $*I
49+
%result = struct_extract %self : $I, #I.int
50+
return %result : $Int64
51+
}
52+
53+
sil private [transparent] [thunk] @I_P_printMe : $@convention(witness_method: P) (@in_guaranteed I) -> Int64 {
54+
bb0(%self_addr : $*I):
55+
%self = load %self_addr : $*I
56+
%I_printMe = function_ref @I_printMe : $@convention(method) (I) -> Int64
57+
%result = apply %I_printMe(%self) : $@convention(method) (I) -> Int64
58+
return %result : $Int64
59+
}
60+
61+
sil @main : $@convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 {
62+
bb0(%0 : $Int32, %1 : $UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>):
63+
%i_type = metatype $@thin I.Type
64+
%i_int_literal = integer_literal $Builtin.Int64, 99
65+
%i_int = struct $Int64 (%i_int_literal : $Builtin.Int64)
66+
%i = struct $I (%i_int : $Int64)
67+
%i_addr = alloc_stack $I
68+
store %i to %i_addr : $*I
69+
%callPrintMe = function_ref @callPrintMe : $@async @convention(method) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> Int64
70+
%result = apply %callPrintMe<I>(%i_addr) : $@async @convention(method) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> Int64 // CHECK: I(int: 99)
71+
dealloc_stack %i_addr : $*I
72+
%printInt64 = function_ref @printInt64 : $@convention(thin) (Int64) -> ()
73+
%printInt64_result = apply %printInt64(%result) : $@convention(thin) (Int64) -> () // CHECK: 99
74+
75+
%out_literal = integer_literal $Builtin.Int32, 0
76+
%out = struct $Int32 (%out_literal : $Builtin.Int32)
77+
return %out : $Int32
78+
}
79+
80+
sil_witness_table hidden I: P module main {
81+
method #P.printMe: <Self where Self : P> (Self) -> () -> Int64 : @I_P_printMe
82+
}

0 commit comments

Comments
 (0)