Skip to content

Commit 4f5b7d4

Browse files
Merge pull request #65164 from nate-chandler/rdar108014714
[SemanticARCOpts] Don't shorten owned lexical values lifetimes through deinit barriers.
2 parents f2cfada + a4ac481 commit 4f5b7d4

File tree

2 files changed

+70
-0
lines changed

2 files changed

+70
-0
lines changed

lib/SILOptimizer/SemanticARC/CopyValueOpts.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "SemanticARCOptVisitor.h"
2525
#include "swift/Basic/Defer.h"
2626
#include "swift/SIL/LinearLifetimeChecker.h"
27+
#include "swift/SIL/MemAccessUtils.h"
2728
#include "swift/SIL/OwnershipUtils.h"
2829
#include "swift/SIL/Projection.h"
2930

@@ -392,6 +393,20 @@ static bool tryJoinIfDestroyConsumingUseInSameBlock(
392393
return true;
393394
}
394395

396+
// The lifetime of the original ends after the lifetime of the copy. If the
397+
// original is lexical, its lifetime must not be shortened through deinit
398+
// barriers.
399+
if (cvi->getOperand()->isLexical()) {
400+
// At this point, visitedInsts contains all the instructions between the
401+
// consuming use of the copy and the destroy. If any of those instructions
402+
// is a deinit barrier, it would be illegal to shorten the original lexical
403+
// value's lifetime to end at that consuming use. Bail if any are.
404+
if (llvm::any_of(visitedInsts, [](auto *inst) {
405+
return mayBeDeinitBarrierNotConsideringSideEffects(inst);
406+
}))
407+
return false;
408+
}
409+
395410
// If we reached this point, isUseBetweenInstAndBlockEnd succeeded implying
396411
// that we found destroy_value to be after our consuming use. Noting that
397412
// additionally, the routine places all instructions in between consuming use

test/SILOptimizer/semantic-arc-opts-lifetime-joining.sil

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,13 @@ struct NativeObjectWrapper {
116116

117117
sil @owned_user_object_pair : $@convention(thin) (@owned NativeObjectPair) -> ()
118118

119+
class X {}
120+
struct S {}
121+
122+
sil @getX : $@convention(thin) () -> @owned X
123+
sil @getS : $@convention(thin) (@owned X) -> @out S
124+
sil @loadWeakX_from : $@convention(thin) (@in_guaranteed S) -> @owned FakeOptional<X>
125+
119126
///////////
120127
// Tests //
121128
///////////
@@ -923,3 +930,51 @@ bb0:
923930
destroy_value %0 : ${ var Bool }
924931
return %11 : $Bool
925932
}
933+
934+
// Don't do this optimization:
935+
// Eliminate copy of lexical value which ends after lifetime of copy IF there
936+
// may be deinit barriers between the final consume and the copy.
937+
//
938+
// CHECK-LABEL: sil [ossa] @testDestroyedLexicalValue : {{.*}} {
939+
// CHECK: [[GET:%[^,]+]] = function_ref @getX
940+
// CHECK: [[X:%[^,]+]] = apply [[GET]]()
941+
// CHECK: [[MX:%[^,]+]] = move_value [lexical] [[X]]
942+
// CHECK: destroy_value [[MX]] : $X
943+
// CHECK-LABEL: } // end sil function 'testDestroyedLexicalValue'
944+
sil [ossa] @testDestroyedLexicalValue : $@convention(thin) () -> @owned FakeOptional<X> {
945+
bb0:
946+
%getX = function_ref @getX : $@convention(thin) () -> @owned X
947+
%x = apply %getX() : $@convention(thin) () -> @owned X
948+
%mx = move_value [lexical] %x : $X
949+
%a = alloc_stack [lexical] $S, let, name "s"
950+
%c = copy_value %mx : $X
951+
%getS = function_ref @getS : $@convention(thin) (@owned X) -> @out S
952+
%s = apply %getS(%a, %c) : $@convention(thin) (@owned X) -> @out S
953+
%loadWeakX_from = function_ref @loadWeakX_from : $@convention(thin) (@in_guaranteed S) -> @owned FakeOptional<X>
954+
%o = apply %loadWeakX_from(%a) : $@convention(thin) (@in_guaranteed S) -> @owned FakeOptional<X>
955+
// ^^^^^ Deinit barrier
956+
destroy_addr %a : $*S
957+
dealloc_stack %a : $*S
958+
destroy_value %mx : $X
959+
return %o : $FakeOptional<X>
960+
}
961+
962+
// CHECK-LABEL: sil [ossa] @testDestroyedLexicalValueNoBarriers : {{.*}} {
963+
// CHECK-NOT: destroy_value
964+
// CHECK-LABEL: } // end sil function 'testDestroyedLexicalValueNoBarriers'
965+
sil [ossa] @testDestroyedLexicalValueNoBarriers : $@convention(thin) () -> () {
966+
bb0:
967+
%getX = function_ref @getX : $@convention(thin) () -> @owned X
968+
%x = apply %getX() : $@convention(thin) () -> @owned X
969+
%mx = move_value [lexical] %x : $X
970+
%a = alloc_stack [lexical] $S, let, name "s"
971+
%c = copy_value %mx : $X
972+
%getS = function_ref @getS : $@convention(thin) (@owned X) -> @out S
973+
%s = apply %getS(%a, %c) : $@convention(thin) (@owned X) -> @out S
974+
destroy_addr %a : $*S
975+
dealloc_stack %a : $*S
976+
destroy_value %mx : $X
977+
%r = tuple ()
978+
return %r : $()
979+
}
980+

0 commit comments

Comments
 (0)