Skip to content

Commit 750289e

Browse files
authored
Merge pull request #28989 from gottesmm/pr-42b06814f186ae88911b84b21640d36b25c7a1cd
[semantic-arc-opts] When performing load [copy] -> load_borrow on classes, do not ignore forwarding uses.
2 parents 5a582a6 + 23f36a0 commit 750289e

File tree

2 files changed

+95
-15
lines changed

2 files changed

+95
-15
lines changed

lib/SILOptimizer/Mandatory/SemanticARCOpts.cpp

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,25 @@ STATISTIC(NumEliminatedInsts, "number of removed instructions");
3636
STATISTIC(NumLoadCopyConvertedToLoadBorrow,
3737
"number of load_copy converted to load_borrow");
3838

39+
//===----------------------------------------------------------------------===//
40+
// Utility
41+
//===----------------------------------------------------------------------===//
42+
43+
static bool isConsumingOwnedUse(Operand *use) {
44+
assert(use->get().getOwnershipKind() == ValueOwnershipKind::Owned);
45+
46+
if (use->isTypeDependent())
47+
return false;
48+
49+
// We know that a copy_value produces an @owned value. Look through all of
50+
// our uses and classify them as either invalidating or not
51+
// invalidating. Make sure that all of the invalidating ones are
52+
// destroy_value since otherwise the live_range is not complete.
53+
auto map = use->getOwnershipKindMap();
54+
auto constraint = map.getLifetimeConstraint(ValueOwnershipKind::Owned);
55+
return constraint == UseLifetimeConstraint::MustBeInvalidated;
56+
}
57+
3958
//===----------------------------------------------------------------------===//
4059
// Live Range Modeling
4160
//===----------------------------------------------------------------------===//
@@ -775,8 +794,21 @@ class StorageGuaranteesLoadVisitor
775794
std::back_inserter(baseEndBorrows));
776795

777796
SmallVector<SILInstruction *, 4> valueDestroys;
778-
llvm::copy(Load->getUsersOfType<DestroyValueInst>(),
779-
std::back_inserter(valueDestroys));
797+
for (auto *use : Load->getUses()) {
798+
// If this load is not consuming, skip it.
799+
if (!isConsumingOwnedUse(use)) {
800+
continue;
801+
}
802+
803+
// Otherwise, if this isn't a destroy_value, we have a consuming use we
804+
// don't understand. Return conservatively that this memory location may
805+
// not be guaranteed.
806+
auto *user = use->getUser();
807+
if (!isa<DestroyValueInst>(user)) {
808+
return answer(true);
809+
}
810+
valueDestroys.emplace_back(user);
811+
}
780812

781813
SmallPtrSet<SILBasicBlock *, 4> visitedBlocks;
782814
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)