diff --git a/lib/SILOptimizer/SemanticARC/CopyValueOpts.cpp b/lib/SILOptimizer/SemanticARC/CopyValueOpts.cpp index d8b4fb90d9fc2..6cdbe18af023b 100644 --- a/lib/SILOptimizer/SemanticARC/CopyValueOpts.cpp +++ b/lib/SILOptimizer/SemanticARC/CopyValueOpts.cpp @@ -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() diff --git a/test/SILOptimizer/semantic-arc-opts-lifetime-joining.sil b/test/SILOptimizer/semantic-arc-opts-lifetime-joining.sil index 87904acdd0d96..e13ebfe30c66c 100644 --- a/test/SILOptimizer/semantic-arc-opts-lifetime-joining.sil +++ b/test/SILOptimizer/semantic-arc-opts-lifetime-joining.sil @@ -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 @@ -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 { case none @@ -883,3 +889,34 @@ bb3(%result : @owned $FakeOptional): dealloc_stack %allocStack : $*Builtin.NativeObject return %result : $FakeOptional } + +// 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 +}