Skip to content

Commit ad79c2b

Browse files
authored
Merge pull request #29002 from gottesmm/pr-ff454301beb141a7a342948592e5c4436ec3b1e2
[semantic-arc-opts] Use the LiveRange abstraction to find destroys instead of iterating over direct uses so we handle forwarding uses.
2 parents bc14367 + 2b09547 commit ad79c2b

File tree

2 files changed

+19
-64
lines changed

2 files changed

+19
-64
lines changed

lib/SILOptimizer/Mandatory/SemanticARCOpts.cpp

Lines changed: 17 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -36,25 +36,6 @@ 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-
5839
//===----------------------------------------------------------------------===//
5940
// Live Range Modeling
6041
//===----------------------------------------------------------------------===//
@@ -325,7 +306,7 @@ struct SemanticARCOptVisitor
325306
FORWARDING_TERM(CondBranch)
326307
#undef FORWARDING_TERM
327308

328-
bool isWrittenTo(LoadInst *li, ArrayRef<SILInstruction *> destroys);
309+
bool isWrittenTo(LoadInst *li, const LiveRange &lr);
329310

330311
bool processWorklist();
331312

@@ -695,22 +676,20 @@ class StorageGuaranteesLoadVisitor
695676
{
696677
// The outer SemanticARCOptVisitor.
697678
SemanticARCOptVisitor &ARCOpt;
698-
699-
// The original load instruction.
700-
LoadInst *Load;
701-
679+
680+
// The live range of the original load.
681+
const LiveRange &liveRange;
682+
702683
// The current address being visited.
703684
SILValue currentAddress;
704685

705686
Optional<bool> isWritten;
706687

707-
ArrayRef<SILInstruction *> destroyValues;
708-
709688
public:
710689
StorageGuaranteesLoadVisitor(SemanticARCOptVisitor &arcOpt, LoadInst *load,
711-
ArrayRef<SILInstruction *> destroyValues)
712-
: ARCOpt(arcOpt), Load(load), currentAddress(load->getOperand()),
713-
destroyValues(destroyValues) {}
690+
const LiveRange &liveRange)
691+
: ARCOpt(arcOpt), liveRange(liveRange),
692+
currentAddress(load->getOperand()) {}
714693

715694
void answer(bool written) {
716695
currentAddress = nullptr;
@@ -793,28 +772,11 @@ class StorageGuaranteesLoadVisitor
793772
llvm::copy(borrowInst->getUsersOfType<EndBorrowInst>(),
794773
std::back_inserter(baseEndBorrows));
795774

796-
SmallVector<SILInstruction *, 4> 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-
}
812-
813775
SmallPtrSet<SILBasicBlock *, 4> visitedBlocks;
814776
LinearLifetimeChecker checker(visitedBlocks, ARCOpt.getDeadEndBlocks());
815777
// Returns true on success. So we invert.
816-
bool foundError =
817-
!checker.validateLifetime(baseObject, baseEndBorrows, valueDestroys);
778+
bool foundError = !checker.validateLifetime(baseObject, baseEndBorrows,
779+
liveRange.getDestroys());
818780
return answer(foundError);
819781
}
820782

@@ -850,9 +812,9 @@ class StorageGuaranteesLoadVisitor
850812
SmallPtrSet<SILBasicBlock *, 4> visitedBlocks;
851813
LinearLifetimeChecker checker(visitedBlocks, ARCOpt.getDeadEndBlocks());
852814
// Returns true on success. So we invert.
853-
bool foundError =
854-
!checker.validateLifetime(stack, destroyAddrs /*consuming users*/,
855-
destroyValues /*non consuming users*/);
815+
bool foundError = !checker.validateLifetime(
816+
stack, destroyAddrs /*consuming users*/,
817+
liveRange.getDestroys() /*non consuming users*/);
856818
return answer(foundError);
857819
}
858820

@@ -866,9 +828,8 @@ class StorageGuaranteesLoadVisitor
866828

867829
} // namespace
868830

869-
bool SemanticARCOptVisitor::isWrittenTo(LoadInst *load,
870-
ArrayRef<SILInstruction *> destroys) {
871-
StorageGuaranteesLoadVisitor visitor(*this, load, destroys);
831+
bool SemanticARCOptVisitor::isWrittenTo(LoadInst *load, const LiveRange &lr) {
832+
StorageGuaranteesLoadVisitor visitor(*this, load, lr);
872833
return visitor.doIt();
873834
}
874835

@@ -892,8 +853,7 @@ bool SemanticARCOptVisitor::visitLoadInst(LoadInst *li) {
892853
// Then check if our address is ever written to. If it is, then we cannot use
893854
// the load_borrow because the stored value may be released during the loaded
894855
// value's live range.
895-
auto destroyValues = lr.getDestroys();
896-
if (isWrittenTo(li, destroyValues))
856+
if (isWrittenTo(li, lr))
897857
return false;
898858

899859
// Ok, we can perform our optimization. Convert the load [copy] into a
@@ -906,6 +866,7 @@ bool SemanticARCOptVisitor::visitLoadInst(LoadInst *li) {
906866
// to find the post-dominating block set of these destroy value to ensure that
907867
// we do not insert multiple end_borrow.
908868
assert(lifetimeFrontier.empty());
869+
auto destroyValues = lr.getDestroys();
909870
ValueLifetimeAnalysis analysis(li, destroyValues);
910871
bool foundCriticalEdges = !analysis.computeFrontier(
911872
lifetimeFrontier, ValueLifetimeAnalysis::DontModifyCFG,

test/SILOptimizer/semantic-arc-opts.sil

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -589,11 +589,8 @@ 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-
//
595592
// CHECK-LABEL: sil [ossa] @dont_copy_let_properties_with_borrowed_base_that_dominates_projtestcase :
596-
// CHECK: load [copy]
593+
// CHECK: load_borrow
597594
// CHECK: } // end sil function 'dont_copy_let_properties_with_borrowed_base_that_dominates_projtestcase'
598595
sil [ossa] @dont_copy_let_properties_with_borrowed_base_that_dominates_projtestcase : $@convention(thin) (@owned ClassLet) -> () {
599596
bb0(%x : @owned $ClassLet):
@@ -613,11 +610,8 @@ bb0(%x : @owned $ClassLet):
613610
return undef : $()
614611
}
615612

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-
//
619613
// CHECK-LABEL: sil [ossa] @dont_copy_let_properties_with_borrowed_base_that_dominates_projtestcase_2 :
620-
// CHECK: load [copy]
614+
// CHECK: load_borrow
621615
// CHECK: } // end sil function 'dont_copy_let_properties_with_borrowed_base_that_dominates_projtestcase_2'
622616
sil [ossa] @dont_copy_let_properties_with_borrowed_base_that_dominates_projtestcase_2 : $@convention(thin) (@owned ClassLet) -> () {
623617
bb0(%x : @owned $ClassLet):

0 commit comments

Comments
 (0)