Skip to content

Commit 6d54a4a

Browse files
authored
Merge pull request #70616 from atrick/partialapply_cloning
Prevent partial_apply cloning.
2 parents a43a5f7 + 861216c commit 6d54a4a

File tree

3 files changed

+91
-5
lines changed

3 files changed

+91
-5
lines changed

lib/SIL/IR/SILInstruction.cpp

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1391,6 +1391,13 @@ bool SILInstruction::isTriviallyDuplicatable() const {
13911391
if (isAllocatingStack())
13921392
return false;
13931393

1394+
// In OSSA, partial_apply is not considered stack allocating (not handled by
1395+
// stack nesting fixup or verification). Nonetheless, prevent it from being
1396+
// cloned so OSSA lowering can directly convert it to a single allocation.
1397+
if (auto *PA = dyn_cast<PartialApplyInst>(this)) {
1398+
return !PA->isOnStack();
1399+
}
1400+
13941401
if (isa<OpenExistentialAddrInst>(this) || isa<OpenExistentialRefInst>(this) ||
13951402
isa<OpenExistentialMetatypeInst>(this) ||
13961403
isa<OpenExistentialValueInst>(this) || isa<OpenExistentialBoxInst>(this) ||
@@ -1781,8 +1788,23 @@ static bool visitRecursivelyLifetimeEndingUses(
17811788

17821789
// There shouldn't be any dead-end consumptions of a nonescaping
17831790
// partial_apply that don't forward it along, aside from destroy_value.
1784-
assert(use->getUser()->hasResults()
1785-
&& use->getUser()->getNumResults() == 1);
1791+
//
1792+
// On-stack partial_apply cannot be cloned, so it should never be used by a
1793+
// BranchInst.
1794+
//
1795+
// This is a fatal error because it performs SIL verification that is not
1796+
// separately checked in the verifier. It is the only check that verifies
1797+
// the structural requirements of on-stack partial_apply uses.
1798+
auto *user = use->getUser();
1799+
if (user->getNumResults() != 1) {
1800+
llvm::errs() << "partial_apply [on_stack] use:\n";
1801+
user->printInContext(llvm::errs());
1802+
if (isa<BranchInst>(user)) {
1803+
llvm::report_fatal_error("partial_apply [on_stack] cannot be cloned");
1804+
}
1805+
llvm::report_fatal_error("partial_apply [on_stack] must be directly "
1806+
"forwarded to a destroy_value");
1807+
}
17861808
if (!visitRecursivelyLifetimeEndingUses(use->getUser()->getResult(0),
17871809
noUsers, func)) {
17881810
return false;

lib/SILOptimizer/Utils/LoopUtils.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,15 @@ bool swift::canDuplicateLoopInstruction(SILLoop *L, SILInstruction *I) {
251251

252252
return alloc && L->contains(alloc);
253253
}
254+
// In OSSA, partial_apply is not considered stack allocating. Nonetheless,
255+
// prevent it from being cloned so OSSA lowering can directly convert it to a
256+
// single allocation.
257+
if (auto *PA = dyn_cast<PartialApplyInst>(I)) {
258+
if (PA->isOnStack()) {
259+
assert(PA->getFunction()->hasOwnership());
260+
return false;
261+
}
262+
}
254263

255264
// CodeGen can't build ssa for objc methods.
256265
if (auto *Method = dyn_cast<MethodInst>(I)) {

test/SILOptimizer/simplify_cfg_ossa_jump_threading.sil

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-sil-opt -test-runner -sil-infinite-jump-threading-budget %s 2>&1
1+
// RUN: %target-sil-opt -test-runner -sil-infinite-jump-threading-budget %s 2>&1 | %FileCheck %s
22

33
import Builtin
44
import Swift
@@ -105,6 +105,10 @@ bb4:
105105
return %4 : $Builtin.Int1
106106
}
107107

108+
// CHECK-LABEL: sil [ossa] @test_jump_thread_ref_ele_loop : $@convention(thin) () -> () {
109+
// CHECK: begin_borrow
110+
// CHECK: begin_borrow
111+
// CHECK-LABEL: } // end sil function 'test_jump_thread_ref_ele_loop'
108112
sil [ossa] @test_jump_thread_ref_ele_loop : $@convention(thin) () -> () {
109113
bb0:
110114
specify_test "simplify-cfg-try-jump-threading @instruction[3]"
@@ -141,8 +145,8 @@ bb5:
141145
}
142146

143147
// CHECK-LABEL: sil [ossa] @test_jump_thread_checked_cast_value :
144-
// CHECK: select_enum
145-
// CHECK: select_enum
148+
// CHECK: checked_cast_br
149+
// CHECK: checked_cast_br
146150
// CHECK-LABEL: } // end sil function 'test_jump_thread_checked_cast_value'
147151
sil [ossa] @test_jump_thread_checked_cast_value : $@convention(thin) (@owned AnyKlass, @owned AnyKlass) -> () {
148152
bb0(%0 : @owned $AnyKlass, %1 : @owned $AnyKlass):
@@ -174,3 +178,54 @@ bb9:
174178
%999 = tuple ()
175179
return %999 : $()
176180
}
181+
182+
// Partial apply cannot be cloned, even in OSSA. OSSA lowering does
183+
// not know how to allocate for multiple partial applies.
184+
//
185+
// rdar://119768691 (OwnershipModelEliminator triggers assertion when
186+
// lowering certain [on_stack] partial_applys in certain
187+
// circumstances)
188+
189+
sil @test_simple_jump_thread_clone_partial_apply_closure : $@convention(thin) (@inout_aliasable Klass) -> ()
190+
sil @test_simple_jump_thread_clone_partial_apply_take_closure : $@convention(thin) (@noescape @callee_guaranteed () ->()) -> ()
191+
192+
// CHECK-LABEL: sil [ossa] @test_simple_jump_thread_clone_partial_apply : $@convention(thin) (@owned Klass, @inout Klass) -> Builtin.Int1 {
193+
// CHECK: bb{{.*}}(%{{.*}} : @owned $FakeOptional<Klass>):
194+
// CHECK: partial_apply [callee_guaranteed]
195+
// CHECK-NEXT: mark_dependence
196+
// CHECK-NEXT: begin_borrow [lexical]
197+
// CHECK-NOT: partial_apply [callee_guaranted]
198+
// CHECK-NOT: begin_borrow
199+
// CHECK-LABEL: } // end sil function 'test_simple_jump_thread_clone_partial_apply'
200+
sil [ossa] @test_simple_jump_thread_clone_partial_apply : $@convention(thin) (@owned Klass, @inout Klass) -> Builtin.Int1 {
201+
bb0(%0 : @owned $Klass, %1 : $*Klass):
202+
%t = integer_literal $Builtin.Int1, 1
203+
%f = integer_literal $Builtin.Int1, 0
204+
cond_br undef, bb1, bb2
205+
206+
bb1:
207+
specify_test "simplify-cfg-try-jump-threading @instruction[4]"
208+
%2 = enum $FakeOptional<Klass>, #FakeOptional.some!enumelt, %0 : $Klass
209+
br bb3(%2 : $FakeOptional<Klass>)
210+
211+
bb2:
212+
destroy_value %0 : $Klass
213+
%3 = enum $FakeOptional<Klass>, #FakeOptional.none!enumelt
214+
br bb3(%3 : $FakeOptional<Klass>)
215+
216+
bb3(%4 : @owned $FakeOptional<Klass>):
217+
%5 = select_enum %4 : $FakeOptional<Klass>, case #FakeOptional.some!enumelt: %t, case #FakeOptional.none!enumelt: %f : $Builtin.Int1
218+
%6 = function_ref @test_simple_jump_thread_clone_partial_apply_closure : $@convention(thin) (@inout_aliasable Klass) -> ()
219+
%7 = partial_apply [callee_guaranteed] [on_stack] %6(%1) : $@convention(thin) (@inout_aliasable Klass) -> ()
220+
%8 = mark_dependence %7 : $@noescape @callee_guaranteed () ->() on %1 : $*Klass
221+
%9 = begin_borrow [lexical] %8 : $@noescape @callee_guaranteed () ->()
222+
br bb4
223+
224+
bb4:
225+
%func = function_ref @test_simple_jump_thread_clone_partial_apply_take_closure : $@convention(thin) (@noescape @callee_guaranteed () ->()) -> ()
226+
%call = apply %func(%9) : $@convention(thin) (@noescape @callee_guaranteed () ->()) -> ()
227+
end_borrow %9 : $@noescape @callee_guaranteed () ->()
228+
destroy_value %8 : $@noescape @callee_guaranteed () ->()
229+
destroy_value %4 : $FakeOptional<Klass>
230+
return %5 : $Builtin.Int1
231+
}

0 commit comments

Comments
 (0)