diff --git a/lib/SILOptimizer/SemanticARC/CopyValueOpts.cpp b/lib/SILOptimizer/SemanticARC/CopyValueOpts.cpp index 76ff604e398fd..deb83ed71c791 100644 --- a/lib/SILOptimizer/SemanticARC/CopyValueOpts.cpp +++ b/lib/SILOptimizer/SemanticARC/CopyValueOpts.cpp @@ -503,6 +503,13 @@ static bool tryJoinIfDestroyConsumingUseInSameBlock( if (visitedInsts.count(use->getUser())) return false; + // If the cvi's operand value has a non-consuming use in the same + // instruction which consumes the copy, bailout. NOTE: + // isUseBetweenInstAndBlockEnd does not check this. + if (user == singleCVIConsumingUse->getUser()) { + return false; + } + // Ok, we have a use that isn't in our visitedInsts region. That being said, // we may still have a use that introduces a new BorrowScope onto our // copy_value's operand that overlaps with our forwarding value region. In @@ -513,7 +520,7 @@ static bool tryJoinIfDestroyConsumingUseInSameBlock( // we need to only find scopes that end within the region in between the // singleConsumingUse (the original forwarded use) and the destroy_value. In // such a case, we must bail! - if (auto operand = BorrowingOperand(use)) + if (auto operand = BorrowingOperand(use)) { if (!operand.visitScopeEndingUses([&](Operand *endScopeUse) { // Return false if we did see the relevant end scope instruction // in the block. That means that we are going to exit early and @@ -521,6 +528,7 @@ static bool tryJoinIfDestroyConsumingUseInSameBlock( return !visitedInsts.count(endScopeUse->getUser()); })) return false; + } } // Ok, we now know that we can eliminate this value. diff --git a/test/SILOptimizer/semantic-arc-opts-lifetime-joining.sil b/test/SILOptimizer/semantic-arc-opts-lifetime-joining.sil index 479da2e0c6a2c..1e1a7c0c55b4a 100644 --- a/test/SILOptimizer/semantic-arc-opts-lifetime-joining.sil +++ b/test/SILOptimizer/semantic-arc-opts-lifetime-joining.sil @@ -975,3 +975,42 @@ bb0: return %r : $() } +sil @consume_and_borrow : $@convention(thin) (@owned Klass, @guaranteed Klass) -> () +sil @borrow : $@convention(thin) (@guaranteed Klass) -> () +sil @consume : $@convention(thin) (@owned Klass) -> () +sil @get_klass : $@convention(thin) () -> @owned Klass + +// CHECK-LABEL: sil hidden [ossa] @borrow_and_consume_copyable_test1 : +// CHECK-NOT: copy_value +// CHECK-LABEL: } // end sil function 'borrow_and_consume_copyable_test1' +sil hidden [ossa] @borrow_and_consume_copyable_test1 : $@convention(thin) () -> () { +bb0: + %0 = function_ref @get_klass : $@convention(thin) () -> @owned Klass + %1 = apply %0() : $@convention(thin) () -> @owned Klass + %2 = move_value [var_decl] %1 + %3 = copy_value %2 + %4 = function_ref @borrow : $@convention(thin) (@guaranteed Klass) -> () + %5 = apply %4(%2) : $@convention(thin) (@guaranteed Klass) -> () + %6 = function_ref @consume : $@convention(thin) (@owned Klass) -> () + %7 = apply %6(%3) : $@convention(thin) (@owned Klass) -> () + destroy_value %2 + %9 = tuple () + return %9 +} + +// CHECK-LABEL: sil hidden [ossa] @borrow_and_consume_copyable_test2 : +// CHECK: copy_value +// CHECK-LABEL: } // end sil function 'borrow_and_consume_copyable_test2' +sil hidden [ossa] @borrow_and_consume_copyable_test2 : $@convention(thin) () -> () { +bb0: + %0 = function_ref @get_klass : $@convention(thin) () -> @owned Klass + %1 = apply %0() : $@convention(thin) () -> @owned Klass + %2 = move_value [var_decl] %1 + %3 = copy_value %2 + %4 = function_ref @consume_and_borrow : $@convention(thin) (@owned Klass, @guaranteed Klass) -> () + %5 = apply %4(%3, %2) : $@convention(thin) (@owned Klass, @guaranteed Klass) -> () + destroy_value %2 + %7 = tuple () + return %7 +} +