Skip to content

Commit cd3765c

Browse files
committed
Reabstract pack values when passing them as arguments
1 parent 4d5f090 commit cd3765c

File tree

2 files changed

+75
-9
lines changed

2 files changed

+75
-9
lines changed

lib/SILGen/SILGenApply.cpp

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3750,18 +3750,17 @@ class ArgEmitter {
37503750
auto expectedEltTy = packTy->getSILElementType(i);
37513751

37523752
bool isPackExpansion = expectedEltTy.is<PackExpansionType>();
3753-
AbstractionPattern origFormalType =
3754-
origExpansionType.getPackExpansionComponentType(isPackExpansion);
37553753

37563754
auto cleanup = CleanupHandle::invalid();
37573755
if (isPackExpansion) {
37583756
cleanup =
3759-
emitPackExpansionIntoPack(std::move(arg), origFormalType,
3757+
emitPackExpansionIntoPack(std::move(arg), origExpansionType,
37603758
expectedEltTy, consumed,
37613759
packAddr, formalPackType, i);
37623760
} else {
37633761
cleanup =
3764-
emitScalarIntoPack(std::move(arg), origFormalType,
3762+
emitScalarIntoPack(std::move(arg),
3763+
origExpansionType.getPackExpansionPatternType(),
37653764
expectedEltTy, consumed,
37663765
packAddr, formalPackType, i);
37673766
}
@@ -3790,7 +3789,7 @@ class ArgEmitter {
37903789
}
37913790

37923791
CleanupHandle emitPackExpansionIntoPack(ArgumentSource &&arg,
3793-
AbstractionPattern origFormalType,
3792+
AbstractionPattern origExpansionType,
37943793
SILType expectedParamType,
37953794
bool consumed,
37963795
SILValue packAddr,
@@ -3857,15 +3856,30 @@ class ArgEmitter {
38573856
auto &eltTL = SGF.getTypeLowering(eltAddr->getType());
38583857

38593858
// Evaluate the pattern expression into that address.
3860-
auto pattern = expansionExpr->getPatternExpr();
3861-
auto init = SGF.useBufferAsTemporary(eltAddr, eltTL);
3862-
SGF.emitExprInto(pattern, init.get());
3859+
auto patternExpr = expansionExpr->getPatternExpr();
3860+
auto bufferInit = SGF.useBufferAsTemporary(eltAddr, eltTL);
3861+
Initialization *innermostInit = bufferInit.get();
3862+
3863+
// Wrap it in a ConversionInitialization if required.
3864+
Optional<ConvertingInitialization> convertingInit;
3865+
auto substPatternType = patternExpr->getType()->getCanonicalType();
3866+
auto loweredPatternTy = SGF.getLoweredRValueType(substPatternType);
3867+
if (loweredPatternTy != expectedElementType.getASTType()) {
3868+
convertingInit.emplace(
3869+
Conversion::getSubstToOrig(
3870+
origExpansionType.getPackExpansionPatternType(),
3871+
substPatternType, expectedElementType),
3872+
SGFContext(innermostInit));
3873+
innermostInit = &*convertingInit;
3874+
}
3875+
3876+
SGF.emitExprInto(patternExpr, innermostInit);
38633877

38643878
// Deactivate any cleanup associated with that value. In later
38653879
// iterations of this loop, we're managing this with our
38663880
// partial-array cleanup; after the loop, we're managing this
38673881
// with our full-tuple cleanup.
3868-
init->getManagedAddress().forward(SGF);
3882+
bufferInit->getManagedAddress().forward(SGF);
38693883

38703884
// Store the element address into the pack.
38713885
SGF.B.createPackElementSet(expansionExpr, eltAddr, packIndex,
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// RUN: %target-swift-emit-silgen -enable-experimental-feature VariadicGenerics %s | %FileCheck %s
2+
// REQUIRES: asserts
3+
4+
func takesVariadicFunction<each T>(function: (repeat each T) -> Int) {}
5+
func takesFunctionPack<each T, R>(functions: repeat ((each T) -> R)) {}
6+
7+
// CHECK-LABEL: sil{{.*}} @$s4main32forwardAndReabstractFunctionPack9functionsySbxXExQp_tRvzlF :
8+
func forwardAndReabstractFunctionPack<each T>(functions: repeat (each T) -> Bool) {
9+
// CHECK: bb0(%0 : $*Pack{repeat @noescape @callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> Bool for <each T>}):
10+
// CHECK: [[ARG_PACK:%.*]] = alloc_pack $Pack{repeat @noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for <each T, Bool>}
11+
// CHECK-NEXT: [[ARG_TUPLE:%.*]] = alloc_stack $(repeat @noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for <each T, Bool>)
12+
// CHECK-NEXT: [[ZERO:%.*]] = integer_literal $Builtin.Word, 0
13+
// CHECK-NEXT: [[ONE:%.*]] = integer_literal $Builtin.Word, 1
14+
// CHECK-NEXT: [[LEN:%.*]] = pack_length $Pack{repeat each T}
15+
// CHECK-NEXT: br bb1([[ZERO]] : $Builtin.Word)
16+
// CHECK: bb1([[IDX:%.*]] : $Builtin.Word)
17+
// CHECK-NEXT: [[IDX_EQ_LEN:%.*]] = builtin "cmp_eq_Word"([[IDX]] : $Builtin.Word, [[LEN]] : $Builtin.Word) : $Builtin.Int1
18+
// CHECK-NEXT: cond_br [[IDX_EQ_LEN]], bb3, bb2
19+
// CHECK: bb2:
20+
// CHECK-NEXT: [[INDEX:%.*]] = dynamic_pack_index [[IDX]] of $Pack{repeat (each T) -> Bool}
21+
// CHECK-NEXT: open_pack_element [[INDEX]] of <each T> at <Pack{repeat each T}>, shape $T, uuid [[UUID:".*"]]
22+
// CHECK-NEXT: [[ARG_TUPLE_ELT_ADDR:%.*]] = tuple_pack_element_addr [[INDEX]] of [[ARG_TUPLE]] :
23+
// Load the parameter function from the parameter pack.
24+
// CHECK-NEXT: [[PARAM_ELT_ADDR:%.*]] = pack_element_get [[INDEX]] of %0 : $*Pack{repeat @noescape @callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> Bool for <each T>} as $*@noescape @callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> Bool for <@pack_element([[UUID]]) T>
25+
// CHECK-NEXT: [[COPY:%.*]] = load [copy] [[PARAM_ELT_ADDR]] :
26+
// Convert that to an unsubstituted type
27+
// CHECK-NEXT: [[COPY_CONVERT:%.*]] = convert_function [[COPY]] : $@noescape @callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> Bool for <@pack_element([[UUID]]) T> to $@noescape @callee_guaranteed (@in_guaranteed @pack_element([[UUID]]) T) -> Bool
28+
// Wrap in the conversion thunk.
29+
// CHECK-NEXT: // function_ref
30+
// CHECK-NEXT: [[THUNK:%.*]] = function_ref @$sxSbIgnd_xSbIegnr_lTR : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0, @guaranteed @noescape @callee_guaranteed (@in_guaranteed τ_0_0) -> Bool) -> @out Bool
31+
// CHECK-NEXT: [[THUNKED:%.*]] = partial_apply [callee_guaranteed] [[THUNK]]<@pack_element([[UUID]]) T>([[COPY_CONVERT]])
32+
// Convert to a substituted type.
33+
// CHECK-NEXT: [[THUNKED_CONVERT:%.*]] = convert_function [[THUNKED]] : $@callee_guaranteed (@in_guaranteed @pack_element([[UUID]]) T) -> @out Bool to $@callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for <@pack_element([[UUID]]) T, Bool>
34+
// Convert to noescape.
35+
// CHECK-NEXT: [[NOESCAPE:%.*]] = convert_escape_to_noescape [not_guaranteed] [[THUNKED_CONVERT]] : $@callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for <@pack_element([[UUID]]) T, Bool> to $@noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for <@pack_element([[UUID]]) T, Bool>
36+
// Store into the tuple and put the tuple address into the argument pack.
37+
// CHECK-NEXT: store [[NOESCAPE]] to [init] [[ARG_TUPLE_ELT_ADDR]] :
38+
// CHECK-NEXT: pack_element_set [[ARG_TUPLE_ELT_ADDR]] : $*@noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for <@pack_element([[UUID]]) T, Bool> into %11 of [[ARG_PACK]] : $*Pack{repeat @noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for <each T, Bool>}
39+
// Destroy the thunked escaping function
40+
// FIXME: does this leave the noescape function dangling??
41+
// CHECK-NEXT: destroy_value [[THUNKED_CONVERT]] :
42+
// CHECK-NEXT: [[NEXT_IDX:%.*]] = builtin "add_Word"([[IDX]] : $Builtin.Word, [[ONE]] : $Builtin.Word) : $Builtin.Word
43+
// CHECK-NEXT: br bb1([[NEXT_IDX]] : $Builtin.Word)
44+
// CHECK: bb3:
45+
// CHECK-NEXT: // function_ref
46+
// CHECK-NEXT: [[FN:%.*]] = function_ref @$s4main17takesFunctionPack9functionsyq_xXExQp_tRvzr0_lF : $@convention(thin) <each τ_0_0, τ_0_1> (@pack_guaranteed Pack{repeat @noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for <each τ_0_0, τ_0_1>}) -> ()
47+
// CHECK-NEXT: apply [[FN]]<Pack{repeat each T}, Bool>([[ARG_PACK]])
48+
// CHECK-NEXT: destroy_addr [[ARG_TUPLE]] :
49+
// CHECK-NEXT: dealloc_stack [[ARG_TUPLE]] :
50+
// CHECK-NEXT: dealloc_pack [[ARG_PACK]] :
51+
takesFunctionPack(functions: repeat each functions)
52+
}

0 commit comments

Comments
 (0)