Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -626,9 +626,13 @@ extension InteriorUseWalker: OwnershipUseVisitor {
if value.type.isTrivial(in: function) {
return .continueWalk
}
guard value.type.isEscapable(in: function) else {
guard value.mayEscape else {
// Non-escapable dependent values can be lifetime-extended by copying, which is not handled by
// InteriorUseWalker. LifetimeDependenceDefUseWalker does this.
// InteriorUseWalker. LifetimeDependenceDefUseWalker does this. Alternatively, we could continue to `walkDownUses`
// but later recognize a copy of a `mayEscape` value to be a pointer escape at that point.
//
// This includes partial_apply [on_stack] which can currently be copied. Although a better solution would be to
// make copying an on-stack closure illegal SIL.
return pointerEscapingUse(of: operand)
}
if useVisitor(operand) == .abortWalk {
Expand Down
31 changes: 31 additions & 0 deletions test/SILOptimizer/mandatory-destroy-hoisting.sil
Original file line number Diff line number Diff line change
Expand Up @@ -319,8 +319,11 @@ bb0(%0 : @owned $String):
return %r
}

// TODO: If InteriorLiveness handles `partial_apply [on_stack]`, then the destroy can be hoisted.
//
// CHECK-LABEL: sil [ossa] @partial_apply :
// CHECK: destroy_value %1
// CHECK-NEXT: debug_step
// CHECK-NEXT: destroy_value %0
// CHECK: } // end sil function 'partial_apply'
sil [ossa] @partial_apply : $@convention(thin) (@owned String) -> () {
Expand Down Expand Up @@ -445,3 +448,31 @@ bb0:
%r = tuple ()
return %r
}

sil @closure1 : $@convention(thin) (@guaranteed C) -> ()

// rdar165850554: InteriorUseDefWalker must consider copies of an on-stack partial apply when computing liveness of the
// borrowed operand.

// CHECK-LABEL: sil private [ossa] @test_closure_copy :
// CHECK: %1 = copy_value %0
// CHECK: debug_step
// CHECK-NEXT: destroy_value %1
// CHECK-LABEL: } // end sil function 'test_closure_copy'
sil private [ossa] @test_closure_copy : $@convention(thin) (@owned C) -> () {
bb0(%0 : @owned $C):
// create a non-lexical value to trigger mandatory destroy hoisting
%1 = copy_value %0
%2 = function_ref @closure1 : $@convention(thin) (@guaranteed C) -> ()
%3 = partial_apply [callee_guaranteed] [on_stack] %2(%1) : $@convention(thin) (@guaranteed C) -> ()
%4 = copy_value %3
// force a pointer-escape
%5 = unchecked_bitwise_cast %4 to $@noescape @callee_guaranteed () -> ()
destroy_value %3
destroy_value %0
destroy_value %4
debug_step
destroy_value %1
%10 = tuple ()
return %10
}