Skip to content

Commit 6bc42ac

Browse files
authored
Merge pull request #29034 from gottesmm/swift-5.2-branch-rdar58289320
[5.2][semantic-arc-opts] When performing load [copy] -> load_borrow on classes, do not ignore forwarding uses.
2 parents bbbb9f1 + fac7bd2 commit 6bc42ac

File tree

2 files changed

+92
-16
lines changed

2 files changed

+92
-16
lines changed

lib/SILOptimizer/Mandatory/SemanticARCOpts.cpp

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,25 @@ STATISTIC(NumLoadCopyConvertedToLoadBorrow,
4141
// Utility
4242
//===----------------------------------------------------------------------===//
4343

44+
static bool isConsumingOwnedUse(Operand *use) {
45+
assert(use->get().getOwnershipKind() == ValueOwnershipKind::Owned);
46+
47+
if (use->isTypeDependent())
48+
return false;
49+
50+
// We know that a copy_value produces an @owned value. Look through all of
51+
// our uses and classify them as either invalidating or not
52+
// invalidating. Make sure that all of the invalidating ones are
53+
// destroy_value since otherwise the live_range is not complete.
54+
auto map = use->getOwnershipKindMap();
55+
auto constraint = map.getLifetimeConstraint(ValueOwnershipKind::Owned);
56+
return constraint == UseLifetimeConstraint::MustBeInvalidated;
57+
}
58+
59+
//===----------------------------------------------------------------------===//
60+
// Live Range Modeling
61+
//===----------------------------------------------------------------------===//
62+
4463
/// Return true if v only has invalidating uses that are destroy_value. Such an
4564
/// owned value is said to represent a dead "live range".
4665
///
@@ -757,11 +776,20 @@ class StorageGuaranteesLoadVisitor
757776

758777
SmallVector<BranchPropagatedUser, 4> valueDestroys;
759778
for (auto *use : Load->getUses()) {
760-
if (isa<DestroyValueInst>(use->getUser())) {
761-
valueDestroys.emplace_back(use);
779+
// If this load is not consuming, skip it.
780+
if (!isConsumingOwnedUse(use)) {
781+
continue;
782+
}
783+
784+
// Otherwise, if this isn't a destroy_value, we have a consuming use we
785+
// don't understand. Return conservatively that this memory location may
786+
// not be guaranteed.
787+
if (!isa<DestroyValueInst>(use->getUser())) {
788+
return answer(true);
762789
}
790+
valueDestroys.emplace_back(use);
763791
}
764-
792+
765793
SmallPtrSet<SILBasicBlock *, 4> visitedBlocks;
766794

767795
LinearLifetimeChecker checker(visitedBlocks, ARCOpt.getDeadEndBlocks());

test/SILOptimizer/semantic-arc-opts.sil

Lines changed: 61 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ import Builtin
99
//////////////////
1010

1111
enum MyNever {}
12+
enum FakeOptional<T> {
13+
case none
14+
case some(T)
15+
}
1216

1317
sil @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
1418
sil @owned_user : $@convention(thin) (@owned Builtin.NativeObject) -> ()
@@ -24,6 +28,7 @@ sil @get_nativeobject_pair : $@convention(thin) () -> @owned NativeObjectPair
2428

2529
class Klass {}
2630
sil @guaranteed_klass_user : $@convention(thin) (@guaranteed Klass) -> ()
31+
sil @guaranteed_fakeoptional_klass_user : $@convention(thin) (@guaranteed FakeOptional<Klass>) -> ()
2732

2833
struct MyInt {
2934
var value: Builtin.Int32
@@ -40,11 +45,6 @@ struct StructMemberTest {
4045
var t : (Builtin.Int32, AnotherStruct)
4146
}
4247

43-
enum FakeOptional<T> {
44-
case none
45-
case some(T)
46-
}
47-
4848
class ClassLet {
4949
@_hasStorage let aLet: Klass
5050
@_hasStorage var aVar: Klass
@@ -589,6 +589,52 @@ bb0(%x : @owned $ClassLet):
589589
return undef : $()
590590
}
591591

592+
// We do not support this today, but we will once forwarding is ignored when
593+
// checking if the load [copy] is a dead live range.
594+
//
595+
// CHECK-LABEL: sil [ossa] @dont_copy_let_properties_with_borrowed_base_that_dominates_projtestcase :
596+
// CHECK: load [copy]
597+
// CHECK: } // end sil function 'dont_copy_let_properties_with_borrowed_base_that_dominates_projtestcase'
598+
sil [ossa] @dont_copy_let_properties_with_borrowed_base_that_dominates_projtestcase : $@convention(thin) (@owned ClassLet) -> () {
599+
bb0(%x : @owned $ClassLet):
600+
%f = function_ref @black_hole : $@convention(thin) (@guaranteed Klass) -> ()
601+
602+
%a = begin_borrow %x : $ClassLet
603+
%p = ref_element_addr %a : $ClassLet, #ClassLet.aLetTuple
604+
%v = load [copy] %p : $*(Klass, Klass)
605+
(%v1, %v2) = destructure_tuple %v : $(Klass, Klass)
606+
apply %f(%v1) : $@convention(thin) (@guaranteed Klass) -> ()
607+
apply %f(%v2) : $@convention(thin) (@guaranteed Klass) -> ()
608+
destroy_value %v1 : $Klass
609+
destroy_value %v2 : $Klass
610+
end_borrow %a : $ClassLet
611+
destroy_value %x : $ClassLet
612+
613+
return undef : $()
614+
}
615+
616+
// We do not support this today, but we will once forwarding is ignored when
617+
// checking if the load [copy] is a dead live range.
618+
//
619+
// CHECK-LABEL: sil [ossa] @dont_copy_let_properties_with_borrowed_base_that_dominates_projtestcase_2 :
620+
// CHECK: load [copy]
621+
// CHECK: } // end sil function 'dont_copy_let_properties_with_borrowed_base_that_dominates_projtestcase_2'
622+
sil [ossa] @dont_copy_let_properties_with_borrowed_base_that_dominates_projtestcase_2 : $@convention(thin) (@owned ClassLet) -> () {
623+
bb0(%x : @owned $ClassLet):
624+
%f = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
625+
626+
%a = begin_borrow %x : $ClassLet
627+
%p = ref_element_addr %a : $ClassLet, #ClassLet.aLet
628+
%v = load [copy] %p : $*Klass
629+
%v_cast = unchecked_ref_cast %v : $Klass to $Builtin.NativeObject
630+
apply %f(%v_cast) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
631+
destroy_value %v_cast : $Builtin.NativeObject
632+
end_borrow %a : $ClassLet
633+
destroy_value %x : $ClassLet
634+
635+
return undef : $()
636+
}
637+
592638
// CHECK-LABEL: sil [ossa] @dont_copy_let_properties_with_multi_borrowed_base_that_dominates
593639
// CHECK: [[OUTER:%.*]] = begin_borrow
594640
// CHECK-NEXT: ref_element_addr
@@ -662,7 +708,7 @@ bb0(%x : @owned $ClassLet):
662708
return undef : $()
663709
}
664710

665-
// CHECK-LABEL: sil [ossa] @do_or_dont_copy_let_properties_with_multi_borrowed_base_when_it_dominates
711+
// CHECK-LABEL: sil [ossa] @do_or_dont_copy_let_properties_with_multi_borrowed_base_when_it_dominates_2 :
666712
// CHECK: [[OUTER:%.*]] = begin_borrow
667713
// CHECK-NEXT: ref_element_addr
668714
// CHECK-NEXT: [[INNER:%.*]] = load_borrow
@@ -672,12 +718,15 @@ bb0(%x : @owned $ClassLet):
672718
// CHECK-NEXT: begin_borrow
673719
// CHECK-NEXT: ref_element_addr
674720
// CHECK-NEXT: load [copy]
675-
// CHECK-NEXT: apply
676721
// CHECK-NEXT: end_borrow
677722
// CHECK-NEXT: destroy_value
723+
// CHECK-NEXT: // function_ref
724+
// CHECK-NEXT: function_ref
725+
// CHECK-NEXT: enum
678726
// CHECK-NEXT: apply
679727
// CHECK-NEXT: destroy_value
680-
sil [ossa] @do_or_dont_copy_let_properties_with_multi_borrowed_base_when_it_dominates : $@convention(thin) (@owned ClassLet) -> () {
728+
// CHECK: } // end sil function 'do_or_dont_copy_let_properties_with_multi_borrowed_base_when_it_dominates_2'
729+
sil [ossa] @do_or_dont_copy_let_properties_with_multi_borrowed_base_when_it_dominates_2 : $@convention(thin) (@owned ClassLet) -> () {
681730
bb0(%x : @owned $ClassLet):
682731
%f = function_ref @black_hole : $@convention(thin) (@guaranteed Klass) -> ()
683732

@@ -693,18 +742,17 @@ bb0(%x : @owned $ClassLet):
693742
%b = begin_borrow %x : $ClassLet
694743
%q = ref_element_addr %b : $ClassLet, #ClassLet.aLet
695744
%w = load [copy] %q : $*Klass
696-
%d = begin_borrow %w : $Klass
697-
apply %f(%d) : $@convention(thin) (@guaranteed Klass) -> ()
698745

699746
// End the lifetime of the base object first...
700747
end_borrow %b : $ClassLet
701748
destroy_value %x : $ClassLet
702749

703750
// ...then end the lifetime of the copy.
704-
apply %f(%d) : $@convention(thin) (@guaranteed Klass) -> ()
751+
%f2 = function_ref @guaranteed_fakeoptional_klass_user : $@convention(thin) (@guaranteed FakeOptional<Klass>) -> ()
752+
%w2 = enum $FakeOptional<Klass>, #FakeOptional.some!enumelt.1, %w : $Klass
753+
apply %f2(%w2) : $@convention(thin) (@guaranteed FakeOptional<Klass>) -> ()
705754

706-
end_borrow %d : $Klass
707-
destroy_value %w : $Klass
755+
destroy_value %w2 : $FakeOptional<Klass>
708756

709757
return undef : $()
710758
}

0 commit comments

Comments
 (0)