Skip to content

Commit 2f7b5e4

Browse files
Merge pull request swiftlang#78529 from nate-chandler/cherrypick/release/6.1/rdar142570727
6.1: [SILCombine] Fix apply(convert_function(@guaranteed)) with an @owned operand.
2 parents 20e30f9 + a9f4a38 commit 2f7b5e4

File tree

4 files changed

+203
-11
lines changed

4 files changed

+203
-11
lines changed

lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp

Lines changed: 52 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,13 @@ SILCombiner::optimizeApplyOfConvertFunctionInst(FullApplySite AI,
149149
if (SubstCalleeTy->hasArchetype() || ConvertCalleeTy->hasArchetype())
150150
return nullptr;
151151

152+
// If we converted from a non-throwing to a throwing function which is
153+
// try_apply'd, rewriting would require changing the CFG. Bail for now.
154+
if (!ConvertCalleeTy->hasErrorResult() && isa<TryApplyInst>(AI)) {
155+
assert(SubstCalleeTy->hasErrorResult());
156+
return nullptr;
157+
}
158+
152159
// Ok, we can now perform our transformation. Grab AI's operands and the
153160
// relevant types from the ConvertFunction function type and AI.
154161
Builder.setCurrentDebugScope(AI.getDebugScope());
@@ -166,14 +173,22 @@ SILCombiner::optimizeApplyOfConvertFunctionInst(FullApplySite AI,
166173
auto newOpParamTypes = convertConventions.getParameterSILTypes(context);
167174

168175
llvm::SmallVector<SILValue, 8> Args;
169-
auto convertOp = [&](SILValue Op, SILType OldOpType, SILType NewOpType) {
176+
llvm::SmallVector<BeginBorrowInst *, 8> Borrows;
177+
auto convertOp = [&](SILValue Op, SILType OldOpType, SILType NewOpType,
178+
OperandOwnership ownership) {
170179
// Convert function takes refs to refs, address to addresses, and leaves
171180
// other types alone.
172181
if (OldOpType.isAddress()) {
173182
assert(NewOpType.isAddress() && "Addresses should map to addresses.");
174183
auto UAC = Builder.createUncheckedAddrCast(AI.getLoc(), Op, NewOpType);
175184
Args.push_back(UAC);
176185
} else if (OldOpType.getASTType() != NewOpType.getASTType()) {
186+
if (Op->getOwnershipKind() == OwnershipKind::Owned &&
187+
!ownership.getOwnershipConstraint().isConsuming()) {
188+
auto borrow = Builder.createBeginBorrow(AI.getLoc(), Op);
189+
Op = borrow;
190+
Borrows.push_back(borrow);
191+
}
177192
auto URC =
178193
Builder.createUncheckedForwardingCast(AI.getLoc(), Op, NewOpType);
179194
Args.push_back(URC);
@@ -187,22 +202,30 @@ SILCombiner::optimizeApplyOfConvertFunctionInst(FullApplySite AI,
187202
auto newRetI = newOpRetTypes.begin();
188203
auto oldRetI = oldOpRetTypes.begin();
189204

205+
auto getCurrentOperand = [&OpI, &AI]() -> Operand & {
206+
return AI.getInstruction()
207+
->getAllOperands()[OpI + ApplyInst::getArgumentOperandNumber()];
208+
};
209+
190210
for (auto e = newOpRetTypes.end(); newRetI != e;
191211
++OpI, ++newRetI, ++oldRetI) {
192-
convertOp(Ops[OpI], *oldRetI, *newRetI);
212+
convertOp(Ops[OpI], *oldRetI, *newRetI,
213+
getCurrentOperand().getOperandOwnership());
193214
}
194215

195216
if (oldIndirectErrorResultType) {
196217
assert(newIndirectErrorResultType);
197-
convertOp(Ops[OpI], oldIndirectErrorResultType, newIndirectErrorResultType);
218+
convertOp(Ops[OpI], oldIndirectErrorResultType, newIndirectErrorResultType,
219+
getCurrentOperand().getOperandOwnership());
198220
++OpI;
199221
}
200222

201223
auto newParamI = newOpParamTypes.begin();
202224
auto oldParamI = oldOpParamTypes.begin();
203225
for (auto e = newOpParamTypes.end(); newParamI != e;
204226
++OpI, ++newParamI, ++oldParamI) {
205-
convertOp(Ops[OpI], *oldParamI, *newParamI);
227+
convertOp(Ops[OpI], *oldParamI, *newParamI,
228+
getCurrentOperand().getOperandOwnership());
206229
}
207230

208231
// Convert the direct results if they changed.
@@ -240,10 +263,22 @@ SILCombiner::optimizeApplyOfConvertFunctionInst(FullApplySite AI,
240263

241264
Builder.createBranch(AI.getLoc(), TAI->getNormalBB(), branchArgs);
242265
}
243-
244-
return Builder.createTryApply(AI.getLoc(), funcOper, SubstitutionMap(), Args,
245-
normalBB, TAI->getErrorBB(),
246-
TAI->getApplyOptions());
266+
267+
Builder.setInsertionPoint(AI.getInstruction());
268+
auto *result = Builder.createTryApply(
269+
AI.getLoc(), funcOper, SubstitutionMap(), Args, normalBB,
270+
TAI->getErrorBB(), TAI->getApplyOptions());
271+
if (!Borrows.empty()) {
272+
Builder.setInsertionPoint(&TAI->getErrorBB()->front());
273+
for (auto *borrow : Borrows) {
274+
Builder.createEndBorrow(AI.getLoc(), borrow);
275+
}
276+
Builder.setInsertionPoint(&TAI->getNormalBB()->front());
277+
for (auto *borrow : Borrows) {
278+
Builder.createEndBorrow(AI.getLoc(), borrow);
279+
}
280+
}
281+
return result;
247282
}
248283

249284
// Match the throwing bit of the underlying function_ref. We assume that if
@@ -262,6 +297,11 @@ SILCombiner::optimizeApplyOfConvertFunctionInst(FullApplySite AI,
262297
Builder.createUncheckedForwardingCast(AI.getLoc(), NAI, oldResultTy);
263298
}
264299

300+
Builder.setInsertionPoint(AI->getNextInstruction());
301+
for (auto *borrow : Borrows) {
302+
Builder.createEndBorrow(AI.getLoc(), borrow);
303+
}
304+
265305
return result;
266306
}
267307

@@ -1623,6 +1663,10 @@ SILInstruction *SILCombiner::visitTryApplyInst(TryApplyInst *AI) {
16231663
if (isa<PartialApplyInst>(AI->getCallee()))
16241664
return nullptr;
16251665

1666+
if (auto *CFI = dyn_cast<ConvertFunctionInst>(AI->getCallee())) {
1667+
return optimizeApplyOfConvertFunctionInst(AI, CFI);
1668+
}
1669+
16261670
// Optimize readonly functions with no meaningful users.
16271671
SILFunction *Fn = AI->getReferencedFunctionOrNull();
16281672
if (Fn && Fn->getEffectsKind() < EffectsKind::ReleaseNone) {

test/SILOptimizer/sil_combine.sil

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1420,7 +1420,9 @@ bb0(%0 : $*@callee_owned (@in ()) -> @out AnotherClass, %1 : $*AnotherClass):
14201420

14211421
sil @convertible_result_with_error : $@convention(thin) () -> (@owned AnotherClass, @error Error)
14221422

1423-
// TODO
1423+
// CHECK-LABEL: sil @peephole_convert_function_result_change_with_error : {{.*}} {
1424+
// CHECK-NOT: convert_function
1425+
// CHECK-LABEL: } // end sil function 'peephole_convert_function_result_change_with_error'
14241426
sil @peephole_convert_function_result_change_with_error : $@convention(thin) () -> () {
14251427
entry:
14261428
%f = function_ref @convertible_result_with_error : $@convention(thin) () -> (@owned AnotherClass, @error Error)

test/SILOptimizer/sil_combine_apply_unit.sil

Lines changed: 145 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,28 @@
1-
// RUN: %target-sil-opt -enable-sil-verify-all %s -test-runner | %FileCheck %s
1+
// RUN: %target-sil-opt \
2+
// RUN: -test-runner %s \
3+
// RUN: -module-name Swift \
4+
// RUN: -enable-sil-verify-all \
5+
// RUN: | %FileCheck %s
26

37
import Builtin
48

9+
enum Optional<T> {
10+
case some(T)
11+
case none
12+
}
13+
14+
protocol Error {}
15+
16+
class C {}
17+
518
struct Input {}
619
struct Output {}
720
enum Nunca {}
821

22+
sil @borrowMaybeC : $@convention(thin) (@guaranteed Optional<C>) -> ()
23+
sil @borrowMaybeC2 : $@convention(thin) (@guaranteed Optional<C>, @guaranteed Optional<C>) -> ()
24+
sil @borrowMaybeCThrowing : $@convention(thin) (@guaranteed Optional<C>) -> (@error Error)
25+
sil @borrowMaybeC2Throwing : $@convention(thin) (@guaranteed Optional<C>, @guaranteed Optional<C>) -> (@error Error)
926
sil @rdar127452206_callee : $@convention(thin) @Sendable @substituted <τ_0_0, τ_0_1, τ_0_2> (@in_guaranteed τ_0_0) -> (@out τ_0_2, @error_indirect τ_0_1) for <Input, Nunca, Output>
1027

1128
// CHECK-LABEL: sil @rdar127452206 : {{.*}} {
@@ -31,4 +48,131 @@ entry(%input : $*Input):
3148
return %retval : $()
3249
}
3350

51+
// CHECK-LABEL: sil [ossa] @convert_function__to_optional__owned_as_guaranteed__1 : {{.*}} {
52+
// CHECK: bb0([[C:%[^,]+]] :
53+
// CHECK: [[BORROW_MAYBE_C:%[^,]+]] = function_ref @borrowMaybeC
54+
// CHECK: [[B:%[^,]+]] = begin_borrow [[C]]
55+
// CHECK: [[MAYBE_B:%[^,]+]] = unchecked_ref_cast [[B]] : $C to $Optional<C>
56+
// CHECK: apply [[BORROW_MAYBE_C]]([[MAYBE_B]])
57+
// CHECK: end_borrow [[B]]
58+
// CHECK: destroy_value [[C]]
59+
// CHECK-LABEL: } // end sil function 'convert_function__to_optional__owned_as_guaranteed__1'
60+
sil [ossa] @convert_function__to_optional__owned_as_guaranteed__1 : $@convention(thin) (@owned C) -> () {
61+
entry(%c : @owned $C):
62+
%borrowMaybeC = function_ref @borrowMaybeC : $@convention(thin) (@guaranteed Optional<C>) -> ()
63+
%borrowC = convert_function %borrowMaybeC : $@convention(thin) (@guaranteed Optional<C>) -> () to $@convention(thin) (@guaranteed C) -> ()
64+
%void = apply %borrowC(%c) : $@convention(thin) (@guaranteed C) -> ()
65+
specify_test "sil_combine_instruction %void"
66+
destroy_value %c : $C
67+
%retval = tuple ()
68+
return %retval : $()
69+
}
70+
71+
// CHECK-LABEL: sil [ossa] @convert_function__to_optional__owned_as_guaranteed__2 : {{.*}} {
72+
// CHECK: bb0(
73+
// CHECK-SAME: [[C:%[^,]+]] :
74+
// CHECK-SAME: [[C2:%[^,]+]] :
75+
// CHECK-SAME: ):
76+
// CHECK: [[BORROW_MAYBE_C2:%[^,]+]] = function_ref @borrowMaybeC2
77+
// CHECK: [[B:%[^,]+]] = begin_borrow [[C]]
78+
// CHECK: [[MAYBE_B:%[^,]+]] = unchecked_ref_cast [[B]] : $C to $Optional<C>
79+
// CHECK: [[B2:%[^,]+]] = begin_borrow [[C2]]
80+
// CHECK: [[MAYBE_B2:%[^,]+]] = unchecked_ref_cast [[B2]] : $C to $Optional<C>
81+
// CHECK: apply [[BORROW_MAYBE_C2]]([[MAYBE_B]], [[MAYBE_B2]])
82+
// CHECK: end_borrow [[B]]
83+
// CHECK: end_borrow [[B2]]
84+
// CHECK: destroy_value [[C]]
85+
// CHECK: destroy_value [[C2]]
86+
// CHECK-LABEL: } // end sil function 'convert_function__to_optional__owned_as_guaranteed__2'
87+
sil [ossa] @convert_function__to_optional__owned_as_guaranteed__2 : $@convention(thin) (@owned C, @owned C) -> () {
88+
entry(%c : @owned $C, %c2 : @owned $C):
89+
%borrowMaybeC2 = function_ref @borrowMaybeC2 : $@convention(thin) (@guaranteed Optional<C>, @guaranteed Optional<C>) -> ()
90+
%borrowC2 = convert_function %borrowMaybeC2 : $@convention(thin) (@guaranteed Optional<C>, @guaranteed Optional<C>) -> () to $@convention(thin) (@guaranteed C, @guaranteed C) -> ()
91+
%void = apply %borrowC2(%c, %c2) : $@convention(thin) (@guaranteed C, @guaranteed C) -> ()
92+
specify_test "sil_combine_instruction %void"
93+
destroy_value %c : $C
94+
destroy_value %c2 : $C
95+
%retval = tuple ()
96+
return %retval : $()
97+
}
98+
99+
// CHECK-LABEL: sil [ossa] @convert_function__to_optional__owned_as_guaranteed__3 : {{.*}} {
100+
// CHECK: bb0([[C:%[^,]+]] :
101+
// CHECK: [[BORROW_MAYBE_C:%[^,]+]] = function_ref @borrowMaybeCThrowing
102+
// CHECK: [[B:%[^,]+]] = begin_borrow [[C]]
103+
// CHECK: [[MAYBE_B:%[^,]+]] = unchecked_ref_cast [[B]] : $C to $Optional<C>
104+
// CHECK: try_apply [[BORROW_MAYBE_C]]([[MAYBE_B]])
105+
// CHECK: normal [[SUCCESS:bb[0-9]+]]
106+
// CHECK: error [[FAILURE:bb[0-9]+]]
107+
// CHECK: [[SUCCESS]]
108+
// CHECK: end_borrow [[B]]
109+
// CHECK: destroy_value [[C]]
110+
// CHECK: [[FAILURE]]([[ERROR:%[^,]+]] :
111+
// CHECK: end_borrow [[B]]
112+
// CHECK: destroy_value [[C]]
113+
// CHECK: throw [[ERROR]]
114+
// CHECK-LABEL: } // end sil function 'convert_function__to_optional__owned_as_guaranteed__3'
115+
sil [ossa] @convert_function__to_optional__owned_as_guaranteed__3 : $@convention(thin) (@owned C) -> (@error Error) {
116+
entry(%c : @owned $C):
117+
%borrowMaybeC = function_ref @borrowMaybeCThrowing : $@convention(thin) (@guaranteed Optional<C>) -> (@error Error)
118+
%borrowC = convert_function %borrowMaybeC : $@convention(thin) (@guaranteed Optional<C>) -> (@error Error) to $@convention(thin) (@guaranteed C) -> (@error Error)
119+
specify_test "sil_combine_instruction @instruction"
120+
try_apply %borrowC(%c) : $@convention(thin) (@guaranteed C) -> (@error Error),
121+
normal success,
122+
error failure
123+
124+
success(%void : $()):
125+
destroy_value %c : $C
126+
%retval = tuple ()
127+
return %retval : $()
128+
129+
failure(%error : @owned $Error):
130+
destroy_value %c : $C
131+
throw %error : $Error
132+
}
34133

134+
// CHECK-LABEL: sil [ossa] @convert_function__to_optional__owned_as_guaranteed__4 : {{.*}} {
135+
// CHECK: bb0(
136+
// CHECK-SAME: [[C:%[^,]+]] :
137+
// CHECK-SAME: [[C2:%[^,]+]] :
138+
// CHECK-SAME: ):
139+
// CHECK: [[BORROW_MAYBE_C2:%[^,]+]] = function_ref @borrowMaybeC2Throwing
140+
// CHECK: [[B:%[^,]+]] = begin_borrow [[C]]
141+
// CHECK: [[MAYBE_B:%[^,]+]] = unchecked_ref_cast [[B]] : $C to $Optional<C>
142+
// CHECK: [[B2:%[^,]+]] = begin_borrow [[C2]]
143+
// CHECK: [[MAYBE_B2:%[^,]+]] = unchecked_ref_cast [[B2]] : $C to $Optional<C>
144+
// CHECK: try_apply [[BORROW_MAYBE_C2]]([[MAYBE_B]], [[MAYBE_B2]])
145+
// CHECK: normal [[SUCCESS:bb[0-9]+]]
146+
// CHECK: error [[FAILURE:bb[0-9]+]]
147+
// CHECK: [[SUCCESS]]
148+
// CHECK: end_borrow [[B]]
149+
// CHECK: end_borrow [[B2]]
150+
// CHECK: destroy_value [[C]]
151+
// CHECK: destroy_value [[C2]]
152+
// CHECK: [[FAILURE]]([[ERROR:%[^,]+]] :
153+
// CHECK: end_borrow [[B]]
154+
// CHECK: end_borrow [[B2]]
155+
// CHECK: destroy_value [[C]]
156+
// CHECK: destroy_value [[C2]]
157+
// CHECK: throw [[ERROR]]
158+
// CHECK-LABEL: } // end sil function 'convert_function__to_optional__owned_as_guaranteed__4'
159+
sil [ossa] @convert_function__to_optional__owned_as_guaranteed__4 : $@convention(thin) (@owned C, @owned C) -> (@error Error) {
160+
entry(%c : @owned $C, %c2 : @owned $C):
161+
%borrowMaybeC2 = function_ref @borrowMaybeC2Throwing : $@convention(thin) (@guaranteed Optional<C>, @guaranteed Optional<C>) -> (@error Error)
162+
%borrowC2 = convert_function %borrowMaybeC2 : $@convention(thin) (@guaranteed Optional<C>, @guaranteed Optional<C>) -> (@error Error) to $@convention(thin) (@guaranteed C, @guaranteed C) -> (@error Error)
163+
specify_test "sil_combine_instruction @instruction"
164+
try_apply %borrowC2(%c, %c2) : $@convention(thin) (@guaranteed C, @guaranteed C) -> (@error Error),
165+
normal success,
166+
error failure
167+
168+
success(%void : $()):
169+
destroy_value %c : $C
170+
destroy_value %c2 : $C
171+
%retval = tuple ()
172+
return %retval : $()
173+
174+
failure(%error : @owned $Error):
175+
destroy_value %c : $C
176+
destroy_value %c2 : $C
177+
throw %error : $Error
178+
}

test/SILOptimizer/sil_combine_ossa.sil

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1745,7 +1745,9 @@ bb0(%0 : $*@callee_owned (@in ()) -> @out AnotherClass, %1 : $*AnotherClass):
17451745

17461746
sil @convertible_result_with_error : $@convention(thin) () -> (@owned AnotherClass, @error Error)
17471747

1748-
// TODO
1748+
// CHECK-LABEL: sil [ossa] @peephole_convert_function_result_change_with_error : {{.*}} {
1749+
// CHECK-NOT: convert_function
1750+
// CHECK-LABEL: } // end sil function 'peephole_convert_function_result_change_with_error'
17491751
sil [ossa] @peephole_convert_function_result_change_with_error : $@convention(thin) () -> () {
17501752
entry:
17511753
%f = function_ref @convertible_result_with_error : $@convention(thin) () -> (@owned AnotherClass, @error Error)

0 commit comments

Comments
 (0)