Skip to content

Commit a78acfe

Browse files
committed
Disable handling of nested borrows in DCE
Nested borrow handling can be complex in the presence of reborrows. So it is not handled currently.
1 parent 234d29a commit a78acfe

File tree

4 files changed

+98
-5
lines changed

4 files changed

+98
-5
lines changed

include/swift/SIL/OwnershipUtils.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1009,6 +1009,12 @@ void findTransitiveReborrowBaseValuePairs(
10091009
BorrowingOperand initialScopeOperand, SILValue origBaseValue,
10101010
function_ref<void(SILPhiArgument *, SILValue)> visitReborrowBaseValuePair);
10111011

1012+
/// Given a begin_borrow visit all end_borrow users of the borrow or its
1013+
/// reborrows.
1014+
void visitTransitiveEndBorrows(
1015+
BeginBorrowInst *borrowInst,
1016+
function_ref<void(EndBorrowInst *)> visitEndBorrow);
1017+
10121018
} // namespace swift
10131019

10141020
#endif

lib/SIL/Utils/OwnershipUtils.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1297,3 +1297,25 @@ void swift::findTransitiveReborrowBaseValuePairs(
12971297
});
12981298
}
12991299
}
1300+
1301+
void swift::visitTransitiveEndBorrows(
1302+
BeginBorrowInst *borrowInst,
1303+
function_ref<void(EndBorrowInst *)> visitEndBorrow) {
1304+
SmallSetVector<SILValue, 4> worklist;
1305+
worklist.insert(borrowInst);
1306+
1307+
while (!worklist.empty()) {
1308+
auto val = worklist.pop_back_val();
1309+
for (auto *consumingUse : val->getConsumingUses()) {
1310+
auto *consumingUser = consumingUse->getUser();
1311+
if (auto *branch = dyn_cast<BranchInst>(consumingUser)) {
1312+
auto *succBlock = branch->getSingleSuccessorBlock();
1313+
auto *phiArg = cast<SILPhiArgument>(
1314+
succBlock->getArgument(consumingUse->getOperandNumber()));
1315+
worklist.insert(phiArg);
1316+
} else {
1317+
visitEndBorrow(cast<EndBorrowInst>(consumingUser));
1318+
}
1319+
}
1320+
}
1321+
}

lib/SILOptimizer/Transforms/DeadCodeElimination.cpp

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,10 @@ namespace {
4444
// FIXME: Reconcile the similarities between this and
4545
// isInstructionTriviallyDead.
4646
static bool seemsUseful(SILInstruction *I) {
47-
// Even though begin_access/begin_borrow/destroy_value/copy_value have
48-
// side-effects, they can be DCE'ed if they do not have useful
49-
// dependencies/reverse dependencies
50-
if (isa<BeginAccessInst>(I) || isa<BeginBorrowInst>(I) ||
51-
isa<CopyValueInst>(I) || isa<DestroyValueInst>(I))
47+
// Even though begin_access/destroy_value/copy_value have side-effects, they
48+
// can be DCE'ed if they do not have useful dependencies/reverse dependencies
49+
if (isa<BeginAccessInst>(I) || isa<CopyValueInst>(I) ||
50+
isa<DestroyValueInst>(I))
5251
return false;
5352

5453
// A load [copy] is okay to be DCE'ed if there are no useful dependencies
@@ -266,6 +265,21 @@ void DCE::markLive() {
266265
break;
267266
}
268267
case SILInstructionKind::BeginBorrowInst: {
268+
// Currently we only support borrows of owned values.
269+
// Nested borrow handling can be complex in the presence of reborrows.
270+
// So it is not handled currently.
271+
auto *borrowInst = cast<BeginBorrowInst>(&I);
272+
if (borrowInst->getOperand().getOwnershipKind() !=
273+
OwnershipKind::Owned) {
274+
markInstructionLive(borrowInst);
275+
// Visit all end_borrows and mark them live
276+
auto visitEndBorrow = [&](EndBorrowInst *endBorrow) {
277+
markInstructionLive(endBorrow);
278+
};
279+
visitTransitiveEndBorrows(borrowInst, visitEndBorrow);
280+
continue;
281+
}
282+
// If not populate reborrowDependencies for this borrow
269283
findReborrowDependencies(cast<BeginBorrowInst>(&I));
270284
break;
271285
}

test/SILOptimizer/dead_code_elimination_nontrivial_ossa.sil

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,57 @@ bb1(%newcopy : @owned $Klass, %newborrow1 : @guaranteed $Klass, %newborrow2 : @g
456456
end_borrow %newborrow2 : $Klass
457457
destroy_value %newcopy : $Klass
458458
destroy_value %copy2 : $Klass
459+
%res = tuple ()
460+
return %res : $()
461+
}
462+
463+
// Nested borrows are currently not optimized in DCE
464+
sil [ossa] @dce_nestedborrowlifetime1 : $@convention(thin) (@guaranteed NonTrivialStruct) -> @owned NonTrivialStruct {
465+
bb0(%0 : @guaranteed $NonTrivialStruct):
466+
%borrowo = begin_borrow %0 : $NonTrivialStruct
467+
%borrow = begin_borrow %borrowo : $NonTrivialStruct
468+
br bb1(%borrowo : $NonTrivialStruct, %borrow : $NonTrivialStruct)
469+
470+
bb1(%newborrowo : @guaranteed $NonTrivialStruct, %borrow2 : @guaranteed $NonTrivialStruct):
471+
%newcopy = copy_value %borrow2 : $NonTrivialStruct
472+
end_borrow %borrow2 : $NonTrivialStruct
473+
end_borrow %newborrowo : $NonTrivialStruct
474+
return %newcopy : $NonTrivialStruct
475+
}
476+
477+
sil [ossa] @dce_nestedborrowlifetime2 : $@convention(thin) (@guaranteed Klass) -> () {
478+
bb0(%0 : @guaranteed $Klass):
479+
%borrowo = begin_borrow %0 : $Klass
480+
%borrow = begin_borrow %borrowo : $Klass
481+
%2 = function_ref @$use_klass2 : $@convention(thin) (@guaranteed Klass) -> ()
482+
%3 = apply %2(%borrow) : $@convention(thin) (@guaranteed Klass) -> ()
483+
%5 = apply %2(%borrowo) : $@convention(thin) (@guaranteed Klass) -> ()
484+
br bb1(%borrowo : $Klass, %borrow : $Klass)
485+
486+
bb1(%newborrow : @guaranteed $Klass, %borrow2 : @guaranteed $Klass):
487+
end_borrow %borrow2 : $Klass
488+
end_borrow %newborrow : $Klass
489+
%res = tuple ()
490+
return %res : $()
491+
}
492+
493+
// This test shows it is non trivial to find the insert point of an outer reborrow.
494+
// Here %newborrowo and %newborrowi are both dead phis.
495+
// First end_borrow for the incoming value of %newborrowi is added
496+
// It is non straight forward to find the insert pt for the end_borrow of the incoming value of %newborrowo
497+
// This may not be important once CanonicalizeOSSALifetime supports rewrite of multi-block borrows.
498+
sil [ossa] @dce_nestedborrowlifetime3 : $@convention(thin) (@guaranteed Klass) -> () {
499+
bb0(%0 : @guaranteed $Klass):
500+
%borrowo = begin_borrow %0 : $Klass
501+
%borrow = begin_borrow %borrowo : $Klass
502+
%2 = function_ref @$use_klass2 : $@convention(thin) (@guaranteed Klass) -> ()
503+
%3 = apply %2(%borrow) : $@convention(thin) (@guaranteed Klass) -> ()
504+
%5 = apply %2(%borrowo) : $@convention(thin) (@guaranteed Klass) -> ()
505+
br bb1(%borrow : $Klass, %borrowo : $Klass)
506+
507+
bb1(%newborrowi : @guaranteed $Klass, %newborrowo : @guaranteed $Klass):
508+
end_borrow %newborrowi : $Klass
509+
end_borrow %newborrowo : $Klass
459510
%res = tuple ()
460511
return %res : $()
461512
}

0 commit comments

Comments
 (0)