1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
|
// RUN: %target-swift-emit-silgen %s | %FileCheck %s
func takesVariadicFunction<each T>(function: (repeat each T) -> Int) {}
func takesVariadicOwnedFunction<each T>(function: (repeat __owned each T) -> Int) {}
func takesFunctionPack<each T, R>(functions: repeat ((each T) -> R)) {}
// CHECK-LABEL: sil{{.*}} @$s4main32forwardAndReabstractFunctionPack9functionsySbxXExQp_tRvzlF :
func forwardAndReabstractFunctionPack<each T>(functions: repeat (each T) -> Bool) {
// CHECK: bb0(%0 : $*Pack{repeat @noescape @callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> Bool for <each T>}):
// 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>}
// 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>)
// CHECK-NEXT: [[ZERO:%.*]] = integer_literal $Builtin.Word, 0
// CHECK-NEXT: [[ONE:%.*]] = integer_literal $Builtin.Word, 1
// CHECK-NEXT: [[LEN:%.*]] = pack_length $Pack{repeat each T}
// CHECK-NEXT: br bb1([[ZERO]] : $Builtin.Word)
// CHECK: bb1([[IDX:%.*]] : $Builtin.Word)
// CHECK-NEXT: [[IDX_EQ_LEN:%.*]] = builtin "cmp_eq_Word"([[IDX]] : $Builtin.Word, [[LEN]] : $Builtin.Word) : $Builtin.Int1
// CHECK-NEXT: cond_br [[IDX_EQ_LEN]], bb3, bb2
// CHECK: bb2:
// CHECK-NEXT: [[INDEX:%.*]] = dynamic_pack_index [[IDX]] of $Pack{repeat (each T) -> Bool}
// CHECK-NEXT: open_pack_element [[INDEX]] of <each T> at <Pack{repeat each T}>, shape $each T, uuid [[UUID:".*"]]
// CHECK-NEXT: [[ARG_TUPLE_ELT_ADDR:%.*]] = tuple_pack_element_addr [[INDEX]] of [[ARG_TUPLE]] :
// Load the parameter function from the parameter pack.
// 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]]) each T>
// CHECK-NEXT: [[COPY:%.*]] = load [copy] [[PARAM_ELT_ADDR]] :
// Convert that to an unsubstituted type
// CHECK-NEXT: [[COPY_CONVERT:%.*]] = convert_function [[COPY]] : $@noescape @callee_guaranteed @substituted <τ_0_0> (@in_guaranteed τ_0_0) -> Bool for <@pack_element([[UUID]]) each T> to $@noescape @callee_guaranteed (@in_guaranteed @pack_element([[UUID]]) each T) -> Bool
// Wrap in the conversion thunk.
// CHECK-NEXT: // function_ref
// 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
// CHECK-NEXT: [[THUNKED:%.*]] = partial_apply [callee_guaranteed] [[THUNK]]<@pack_element([[UUID]]) each T>([[COPY_CONVERT]])
// Convert to a substituted type.
// CHECK-NEXT: [[THUNKED_CONVERT:%.*]] = convert_function [[THUNKED]] : $@callee_guaranteed (@in_guaranteed @pack_element([[UUID]]) each T) -> @out Bool to $@callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for <@pack_element([[UUID]]) each T, Bool>
// Convert to noescape.
// 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]]) each T, Bool> to $@noescape @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for <@pack_element([[UUID]]) each T, Bool>
// Store into the tuple and put the tuple address into the argument pack.
// CHECK-NEXT: store [[NOESCAPE]] to [init] [[ARG_TUPLE_ELT_ADDR]] :
// 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]]) each 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>}
// Destroy the thunked escaping function
// FIXME: does this leave the noescape function dangling??
// CHECK-NEXT: destroy_value [[THUNKED_CONVERT]] :
// CHECK-NEXT: [[NEXT_IDX:%.*]] = builtin "add_Word"([[IDX]] : $Builtin.Word, [[ONE]] : $Builtin.Word) : $Builtin.Word
// CHECK-NEXT: br bb1([[NEXT_IDX]] : $Builtin.Word)
// CHECK: bb3:
// CHECK-NEXT: // function_ref
// 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>}) -> ()
// CHECK-NEXT: apply [[FN]]<Pack{repeat each T}, Bool>([[ARG_PACK]])
// CHECK-NEXT: destroy_addr [[ARG_TUPLE]] :
// CHECK-NEXT: dealloc_stack [[ARG_TUPLE]] :
// CHECK-NEXT: dealloc_pack [[ARG_PACK]] :
takesFunctionPack(functions: repeat each functions)
}
// CHECK-LABEL: sil{{.*}} @$s4main22passConcreteToVariadic2fnyS2i_SStXE_tF :
// CHECK: [[COPY:%.*]] = copy_value %0 : $@noescape @callee_guaranteed (Int, @guaranteed String) -> Int
// CHECK: [[THUNK:%.*]] = function_ref @$sSiSSSiIgygd_Si_SSQSiSiIegpd_TR
// CHECK: partial_apply [callee_guaranteed] [[THUNK]]([[COPY]])
func passConcreteToVariadic(fn: (Int, String) -> Int) {
takesVariadicFunction(function: fn)
}
// CHECK-LABEL: sil{{.*}} @$sSiSSSiIgygd_Si_SSQSiSiIegpd_TR :
// CHECK: bb0(%0 : $*Pack{Int, String}, %1 : @guaranteed $@noescape @callee_guaranteed (Int, @guaranteed String) -> Int):
// CHECK-NEXT: [[INT_INDEX:%.*]] = scalar_pack_index 0 of $Pack{Int, String}
// CHECK-NEXT: [[INT_ADDR:%.*]] = pack_element_get [[INT_INDEX]] of %0 : $*Pack{Int, String}
// CHECK-NEXT: [[INT:%.*]] = load [trivial] [[INT_ADDR]] : $*Int
// CHECK-NEXT: [[STRING_INDEX:%.*]] = scalar_pack_index 1 of $Pack{Int, String}
// CHECK-NEXT: [[STRING_ADDR:%.*]] = pack_element_get [[STRING_INDEX]] of %0 : $*Pack{Int, String}
// CHECK-NEXT: [[STRING:%.*]] = load_borrow [[STRING_ADDR]] : $*String
// CHECK-NEXT: [[RESULT:%.*]] = apply %1([[INT]], [[STRING]])
// CHECK-NEXT: end_borrow [[STRING]] : $String
// CHECK-NEXT: return [[RESULT]] : $Int
// FIXME: we aren't preserving that the argument is owned
// CHECK-LABEL: sil{{.*}} @$s4main27passConcreteToOwnedVariadic2fnyS2i_SStXE_tF :
// CHECK: [[COPY:%.*]] = copy_value %0 : $@noescape @callee_guaranteed (Int, @guaranteed String) -> Int
// CHECK: [[THUNK:%.*]] = function_ref @$sSiSSSiIgygd_Si_SSQSiSiIegpd_TR
// CHECK: partial_apply [callee_guaranteed] [[THUNK]]([[COPY]])
func passConcreteToOwnedVariadic(fn: (Int, String) -> Int) {
takesVariadicOwnedFunction(function: fn)
}
// CHECK-LABEL: sil{{.*}} @$s4main29passConcreteClosureToVariadic2fnyS2i_SStXE_tF :
// CHECK: bb0(%0 : @guaranteed $@noescape @callee_guaranteed (Int, @guaranteed String) -> Int)
// CHECK: // function_ref
// CHECK-NEXT: [[CLOSURE:%.*]] = function_ref @$s4main29passConcreteClosureToVariadic2fnyS2i_SStXE_tFS2i_SStXEfU_ : $@convention(thin) @substituted <each τ_0_0> (@pack_guaranteed Pack{repeat each τ_0_0}, @guaranteed @noescape @callee_guaranteed (Int, @guaranteed String) -> Int) -> Int for <Pack{Int, String}>
// CHECK-NEXT: [[T0:%.*]] = copy_value %0 :
// CHECK-NEXT: partial_apply [callee_guaranteed] [[CLOSURE]]([[T0]])
func passConcreteClosureToVariadic(fn: (Int, String) -> Int) {
takesVariadicFunction {x,y in fn(x, y)}
}
// CHECK-LABEL: sil{{.*}} @$s4main29passConcreteClosureToVariadic2fnyS2i_SStXE_tFS2i_SStXEfU_ :
// CHECK: bb0(%0 : $*Pack{Int, String}, %1 : @closureCapture @guaranteed $@noescape @callee_guaranteed (Int, @guaranteed String) -> Int):
// CHECK-NEXT: [[INT_INDEX:%.*]] = scalar_pack_index 0 of $Pack{Int, String}
// CHECK-NEXT: [[INT_ADDR:%.*]] = pack_element_get [[INT_INDEX]] of %0 : $*Pack{Int, String} as $*Int
// CHECK-NEXT: [[X:%.*]] = load [trivial] [[INT_ADDR]] : $*Int
// CHECK-NEXT: debug_value [[X]] : $Int, let, name "x", argno 1
// CHECK-NEXT: [[STRING_INDEX:%.*]] = scalar_pack_index 1 of $Pack{Int, String}
// CHECK-NEXT: [[STRING_ADDR:%.*]] = pack_element_get [[STRING_INDEX]] of %0 : $*Pack{Int, String} as $*String
// CHECK-NEXT: [[Y:%.*]] = load_borrow [[STRING_ADDR]] : $*String
// CHECK-NEXT: debug_value [[Y]] : $String, let, name "y", argno 2
// CHECK: apply {{.*}}([[X]], [[Y]])
// CHECK: end_borrow [[Y]] : $String
/* Doesn't currently type-check
func passConcreteClosureToVariadic2(fn: (Int, String) -> Int, x: Int) {
takesVariadicFunction {y in fn(x, y)}
}
*/
// rdar://109843932
// Test that the path where we emit closures naturally at a
// particular abstraction level correctly handles variadic
// expansion in the result type.
func takeClosureWithVariadicResult<each Argument, each Result>(_: (repeat each Argument) -> (repeat each Result)) {}
// CHECK-LABEL: sil {{.*}}@$s4main30testResultReabstractedEmissionyyFSb_SitSi_SbtXEfU_ :
// CHECK-SAME: $@convention(thin) @substituted <each τ_0_0, each τ_0_1> (@pack_guaranteed Pack{repeat each τ_0_0}) -> @pack_out Pack{repeat each τ_0_1} for <Pack{Int, Bool}, Pack{Bool, Int}>
// CHECK: bb0(%0 : $*Pack{Bool, Int}, %1 : $*Pack{Int, Bool}):
// CHECK-NEXT: [[ARG_INDEX_0:%.*]] = scalar_pack_index 0 of $Pack{Int, Bool}
// CHECK-NEXT: [[ARG_ADDR_0:%.*]] = pack_element_get [[ARG_INDEX_0]] of %1 : $*Pack{Int, Bool} as $*Int
// CHECK-NEXT: [[ARG_0:%.*]] = load [trivial] [[ARG_ADDR_0]] : $*Int
// CHECK-NEXT: debug_value [[ARG_0]] :
// CHECK-NEXT: [[ARG_INDEX_1:%.*]] = scalar_pack_index 1 of $Pack{Int, Bool}
// CHECK-NEXT: [[ARG_ADDR_1:%.*]] = pack_element_get [[ARG_INDEX_1]] of %1 : $*Pack{Int, Bool} as $*Bool
// CHECK-NEXT: [[ARG_1:%.*]] = load [trivial] [[ARG_ADDR_1]] : $*Bool
// CHECK-NEXT: debug_value [[ARG_1]] :
// CHECK-NEXT: [[RET_INDEX_0:%.*]] = scalar_pack_index 0 of $Pack{Bool, Int}
// CHECK-NEXT: [[RET_ADDR_0:%.*]] = pack_element_get [[RET_INDEX_0]] of %0 : $*Pack{Bool, Int} as $*Bool
// CHECK-NEXT: [[RET_INDEX_1:%.*]] = scalar_pack_index 1 of $Pack{Bool, Int}
// CHECK-NEXT: [[RET_ADDR_1:%.*]] = pack_element_get [[RET_INDEX_1]] of %0 : $*Pack{Bool, Int} as $*Int
// CHECK-NEXT: store [[ARG_1]] to [trivial] [[RET_ADDR_0]] : $*Bool
// CHECK-NEXT: store [[ARG_0]] to [trivial] [[RET_ADDR_1]] : $*Int
func testResultReabstractedEmission() {
takeClosureWithVariadicResult {
(a: Int, b: Bool) -> (Bool, Int) in (b, a)
}
}
// CHECK-LABEL: sil {{.*}}@$s4main40testResultReabstractedEmission_vanishingyyFSbSi_SbtXEfU_ :
// CHECK-SAME: $@convention(thin) @substituted <each τ_0_0, each τ_0_1> (@pack_guaranteed Pack{repeat each τ_0_0}) -> @pack_out Pack{repeat each τ_0_1} for <Pack{Int, Bool}, Pack{Bool}>
// CHECK: bb0(%0 : $*Pack{Bool}, %1 : $*Pack{Int, Bool}):
// CHECK-NEXT: [[ARG_INDEX_0:%.*]] = scalar_pack_index 0 of $Pack{Int, Bool}
// CHECK-NEXT: [[ARG_ADDR_0:%.*]] = pack_element_get [[ARG_INDEX_0]] of %1 : $*Pack{Int, Bool} as $*Int
// CHECK-NEXT: [[ARG_0:%.*]] = load [trivial] [[ARG_ADDR_0]] : $*Int
// CHECK-NEXT: debug_value [[ARG_0]] :
// CHECK-NEXT: [[ARG_INDEX_1:%.*]] = scalar_pack_index 1 of $Pack{Int, Bool}
// CHECK-NEXT: [[ARG_ADDR_1:%.*]] = pack_element_get [[ARG_INDEX_1]] of %1 : $*Pack{Int, Bool} as $*Bool
// CHECK-NEXT: [[ARG_1:%.*]] = load [trivial] [[ARG_ADDR_1]] : $*Bool
// CHECK-NEXT: debug_value [[ARG_1]] :
// CHECK-NEXT: [[RET_INDEX_0:%.*]] = scalar_pack_index 0 of $Pack{Bool}
// CHECK-NEXT: [[RET_ADDR_0:%.*]] = pack_element_get [[RET_INDEX_0]] of %0 : $*Pack{Bool} as $*Bool
// CHECK-NEXT: store [[ARG_1]] to [trivial] [[RET_ADDR_0]] : $*Bool
func testResultReabstractedEmission_vanishing() {
takeClosureWithVariadicResult {
(a: Int, b: Bool) -> Bool in b
}
}
|