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
6 changes: 6 additions & 0 deletions lib/SILOptimizer/SemanticARC/CopyValueOpts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,12 @@ static bool tryJoinIfDestroyConsumingUseInSameBlock(
}))
return false;
}
// Check whether the uses considered immediately above are all effectively
// instantaneous uses. Pointer escapes propagate values ways that may not be
// discoverable.
if (hasPointerEscape(operand)) {
return false;
}

// Ok, we now know that we can eliminate this value.
LLVM_DEBUG(llvm::dbgs()
Expand Down
39 changes: 38 additions & 1 deletion test/SILOptimizer/semantic-arc-opts-lifetime-joining.sil
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// RUN: %target-sil-opt -module-name Swift -enable-sil-verify-all -semantic-arc-opts -sil-semantic-arc-peepholes-lifetime-joining %s | %FileCheck %s
// REQUIRES: swift_stdlib_asserts

// NOTE: Some of our tests here depend on borrow elimination /not/ running!
// Please do not add it to clean up the IR like we did in
Expand All @@ -15,6 +14,13 @@ import Builtin

typealias AnyObject = Builtin.AnyObject

struct Bool {
var value : Builtin.Int1
}

sil @closureCapturesBool : $@convention(thin) (@guaranteed { var Bool }) -> ()
sil @closureArgumentEscapes : $@convention(thin) (@owned @callee_guaranteed () -> ()) -> ()

enum MyNever {}
enum FakeOptional<T> {
case none
Expand Down Expand Up @@ -883,3 +889,34 @@ bb3(%result : @owned $FakeOptional<Builtin.NativeObject>):
dealloc_stack %allocStack : $*Builtin.NativeObject
return %result : $FakeOptional<Builtin.NativeObject>
}

// Don't do this optimization:
// Eliminate borrowed copy with useless lifetime:
// %5 = copy_value %0 : ${ var Bool }
//
// CHECK: sil hidden [ossa] @testCapturedSingleDestroyCopy : $@convention(thin) () -> Bool {
// CHECK: load [trivial] %{{.*}} : $*Bool
// CHECK: destroy_value %0 : ${ var Bool }
sil hidden [ossa] @testCapturedSingleDestroyCopy : $@convention(thin) () -> Bool {
bb0:
// var test = false
%0 = alloc_box ${ var Bool }, var, name "test"
%1 = project_box %0 : ${ var Bool }, 0
%2 = integer_literal $Builtin.Int1, 0
%3 = struct $Bool (%2 : $Builtin.Int1)
store %3 to [trivial] %1 : $*Bool

// capture test in an escaping closure
%5 = copy_value %0 : ${ var Bool }
%6 = function_ref @closureCapturesBool : $@convention(thin) (@guaranteed { var Bool }) -> ()
%7 = partial_apply [callee_guaranteed] %6(%5) : $@convention(thin) (@guaranteed { var Bool }) -> ()
%8 = function_ref @closureArgumentEscapes : $@convention(thin) (@owned @callee_guaranteed () -> ()) -> ()
%9 = apply %8(%7) : $@convention(thin) (@owned @callee_guaranteed () -> ()) -> ()

// return test
%10 = begin_access [read] [dynamic] %1 : $*Bool
%11 = load [trivial] %10 : $*Bool
end_access %10 : $*Bool
destroy_value %0 : ${ var Bool }
return %11 : $Bool
}