Skip to content

Commit 2b09547

Browse files
committed
[semantic-arc-opts] Use the LiveRange abstraction to find destroys instead of iterating over direct uses so we handle forwarding uses.
Previously, we were incorrectly handling these test cases since we weren't properly finding destroys through forwarding instructions. I fixed that in a previous commit by changing the code here to only support load [copy] without forwarding instructions. In this commit, I change the code to instead use the LiveRange abstraction. The LiveRange abstraction already knows how to find destroys through forwarding instructions and has this destroy array already computed for us! So we get better runtime performance of code (due to the better opt) and better compile time (since we aren't computing the destroy list twice)! rdar://58289320
1 parent 7c7cf13 commit 2b09547

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)