Skip to content

Commit 34a2618

Browse files
authored
Merge pull request #77300 from meg-gupta/dcebug2
Fix DCE of load_borrow when it is derived from another borrow scope
2 parents 6aabbb1 + 434461d commit 34a2618

File tree

2 files changed

+108
-39
lines changed

2 files changed

+108
-39
lines changed

lib/SILOptimizer/Transforms/DeadCodeElimination.cpp

Lines changed: 51 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,13 @@
1212

1313
#define DEBUG_TYPE "sil-dce"
1414
#include "swift/Basic/Assertions.h"
15+
#include "swift/SIL/BasicBlockBits.h"
1516
#include "swift/SIL/DebugUtils.h"
17+
#include "swift/SIL/MemAccessUtils.h"
18+
#include "swift/SIL/NodeBits.h"
1619
#include "swift/SIL/OwnershipUtils.h"
1720
#include "swift/SIL/SILArgument.h"
1821
#include "swift/SIL/SILBasicBlock.h"
19-
#include "swift/SIL/BasicBlockBits.h"
20-
#include "swift/SIL/NodeBits.h"
2122
#include "swift/SIL/SILBuilder.h"
2223
#include "swift/SIL/SILFunction.h"
2324
#include "swift/SIL/SILUndef.h"
@@ -158,6 +159,8 @@ class DCE {
158159
bool CallsChanged = false;
159160

160161
bool precomputeControlInfo();
162+
/// Populates borrow dependencies and disables DCE if needed.
163+
void processBorrow(BorrowedValue borrow);
161164
void markLive();
162165
/// Record a reverse dependency from \p from to \p to meaning \p to is live
163166
/// if \p from is also live.
@@ -252,6 +255,49 @@ static BuiltinInst *getProducer(CondFailInst *CFI) {
252255
return nullptr;
253256
}
254257

258+
void DCE::processBorrow(BorrowedValue borrow) {
259+
// Populate guaranteedPhiDependencies for this borrow
260+
findGuaranteedPhiDependencies(borrow);
261+
if (!borrow.hasReborrow()) {
262+
return;
263+
}
264+
265+
// If the borrow was not computed from another
266+
// borrow, return.
267+
SILValue baseValue;
268+
if (auto *beginBorrow = dyn_cast<BeginBorrowInst>(*borrow)) {
269+
auto borrowOp = beginBorrow->getOperand();
270+
if (borrowOp->getOwnershipKind() != OwnershipKind::Guaranteed) {
271+
return;
272+
}
273+
baseValue = borrowOp;
274+
} else {
275+
auto *loadBorrow = cast<LoadBorrowInst>(*borrow);
276+
auto accessBase = AccessBase::compute(loadBorrow->getOperand());
277+
if (!accessBase.isReference()) {
278+
return;
279+
}
280+
baseValue = accessBase.getReference();
281+
}
282+
// If the borrow was computed from another
283+
// borrow, disable DCE of the outer borrow.
284+
// This is because, when a reborrow is dead, DCE has to insert
285+
// end_borrows in predecessor blocks and it cannot yet handle borrow
286+
// nesting.
287+
// TODO: Instead of disabling DCE of outer borrow, consider inserting
288+
// end_borrows inside-out.
289+
SmallVector<SILValue, 4> roots;
290+
findGuaranteedReferenceRoots(baseValue,
291+
/*lookThroughNestedBorrows=*/false, roots);
292+
// Visit the end_borrows of all the borrow scopes that this
293+
// begin_borrow could be borrowing, and mark them live.
294+
for (auto root : roots) {
295+
visitTransitiveEndBorrows(root, [&](EndBorrowInst *endBorrow) {
296+
markInstructionLive(endBorrow);
297+
});
298+
}
299+
}
300+
255301
// Determine which instructions from this function we need to keep.
256302
void DCE::markLive() {
257303
// Find the initial set of instructions in this function that appear
@@ -327,32 +373,12 @@ void DCE::markLive() {
327373
}
328374
case SILInstructionKind::BeginBorrowInst: {
329375
auto *borrowInst = cast<BeginBorrowInst>(&I);
330-
// Populate guaranteedPhiDependencies for this borrowInst
331-
findGuaranteedPhiDependencies(BorrowedValue(borrowInst));
332-
auto disableBorrowDCE = [&](SILValue borrow) {
333-
visitTransitiveEndBorrows(borrow, [&](EndBorrowInst *endBorrow) {
334-
markInstructionLive(endBorrow);
335-
});
336-
};
337-
// If we have a begin_borrow of a @guaranteed operand, disable DCE'ing
338-
// of parent borrow scopes. Dead reborrows needs complex handling, which
339-
// is why it is disabled for now.
340-
if (borrowInst->getOperand()->getOwnershipKind() ==
341-
OwnershipKind::Guaranteed) {
342-
SmallVector<SILValue, 4> roots;
343-
findGuaranteedReferenceRoots(borrowInst->getOperand(),
344-
/*lookThroughNestedBorrows=*/false,
345-
roots);
346-
// Visit the end_borrows of all the borrow scopes that this
347-
// begin_borrow could be borrowing, and mark them live.
348-
for (auto root : roots) {
349-
disableBorrowDCE(root);
350-
}
351-
}
376+
processBorrow(BorrowedValue(borrowInst));
352377
break;
353378
}
354379
case SILInstructionKind::LoadBorrowInst: {
355-
findGuaranteedPhiDependencies(BorrowedValue(cast<LoadBorrowInst>(&I)));
380+
auto *loadBorrowInst = cast<LoadBorrowInst>(&I);
381+
processBorrow(BorrowedValue(loadBorrowInst));
356382
break;
357383
}
358384
default:

test/SILOptimizer/dead_code_elimination_nontrivial_ossa.sil

Lines changed: 57 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -854,20 +854,7 @@ exit(%outer_lifetime_3 : @guaranteed $Klass, %inner_lifetime_2 : @guaranteed $Kl
854854
}
855855

856856
// CHECK-LABEL: sil [ossa] @reborrow_guaranteed_phi2 : {{.*}} {
857-
// CHECK: {{bb[0-9]+}}([[EITHER:%[^,]+]] : @owned $EitherNoneOrAnyObject):
858-
// CHECK: [[BORROW_EITHER:%[^,]+]] = begin_borrow [[EITHER]]
859-
// CHECK: switch_enum [[BORROW_EITHER]] : $EitherNoneOrAnyObject, case #EitherNoneOrAnyObject.none!enumelt: [[NONE_BLOCK:bb[0-9]+]], case #EitherNoneOrAnyObject.any!enumelt: [[SOME_BLOCK:bb[0-9]+]]
860-
// CHECK: [[SOME_BLOCK]]([[PAYLOAD:%[^,]+]] : @guaranteed $AnyObject):
861-
// CHECK: end_borrow [[BORROW_EITHER]]
862-
// CHECK: destroy_value [[EITHER]]
863-
// CHECK: br [[EXIT:bb[0-9]+]]
864-
// CHECK: [[NONE_BLOCK]]:
865-
// CHECK: end_borrow [[BORROW_EITHER]]
866-
// CHECK: destroy_value [[EITHER]]
867-
// CHECK: br [[EXIT]]
868-
// CHECK: [[EXIT]]:
869-
// CHECK: [[RETVAL:%[^,]+]] = tuple ()
870-
// CHECK: return [[RETVAL]]
857+
// CHECK-NOT: switch_enum
871858
// CHECK-LABEL: } // end sil function 'reborrow_guaranteed_phi2'
872859
sil [ossa] @reborrow_guaranteed_phi2 : $@convention(thin) (@owned EitherNoneOrAnyObject) -> () {
873860
entry(%0 : @owned $EitherNoneOrAnyObject):
@@ -952,6 +939,62 @@ bb1(%4 : @guaranteed $Klass, %5 : @guaranteed $Klass):
952939
return %8 : $()
953940
}
954941

942+
class Wrapper {
943+
let val: Klass
944+
}
945+
946+
class DoubleWrapper {
947+
let s: StructWrapper
948+
}
949+
950+
struct StructWrapper {
951+
let val: Klass
952+
}
953+
954+
// CHECK-LABEL: sil [ossa] @reborrow_load_borrow3 : $@convention(method) (@owned Wrapper) -> () {
955+
// CHECK: load_borrow
956+
// CHECK: end_borrow
957+
// CHECK: br bb1
958+
// CHECK-LABEL: } // end sil function 'reborrow_load_borrow3'
959+
sil [ossa] @reborrow_load_borrow3 : $@convention(method) (@owned Wrapper) -> () {
960+
bb0(%0 : @owned $Wrapper):
961+
%1 = begin_borrow %0 : $Wrapper
962+
%2 = ref_element_addr %1 : $Wrapper, #Wrapper.val
963+
%3 = load_borrow %2 : $*Klass
964+
%f = function_ref @use_klass : $@convention(thin) (@guaranteed Klass) -> ()
965+
apply %f(%3) : $@convention(thin) (@guaranteed Klass) -> ()
966+
br bb1(%1 : $Wrapper, %3 : $Klass)
967+
968+
bb1(%4 : @guaranteed $Wrapper, %5 : @guaranteed $Klass):
969+
end_borrow %5 : $Klass
970+
end_borrow %4 : $Wrapper
971+
destroy_value %0 : $Wrapper
972+
%8 = tuple ()
973+
return %8 : $()
974+
}
975+
976+
// CHECK-LABEL: sil [ossa] @reborrow_load_borrow4 : $@convention(method) (@owned DoubleWrapper) -> () {
977+
// CHECK: load_borrow
978+
// CHECK: end_borrow
979+
// CHECK: br bb1
980+
// CHECK-LABEL: } // end sil function 'reborrow_load_borrow4'
981+
sil [ossa] @reborrow_load_borrow4 : $@convention(method) (@owned DoubleWrapper) -> () {
982+
bb0(%0 : @owned $DoubleWrapper):
983+
%1 = begin_borrow %0 : $DoubleWrapper
984+
%2 = ref_element_addr %1 : $DoubleWrapper, #DoubleWrapper.s
985+
%4 = struct_element_addr %2 : $*StructWrapper, #StructWrapper.val
986+
%5 = load_borrow %4 : $*Klass
987+
%f = function_ref @use_klass : $@convention(thin) (@guaranteed Klass) -> ()
988+
apply %f(%5) : $@convention(thin) (@guaranteed Klass) -> ()
989+
br bb1(%1 : $DoubleWrapper, %5 : $Klass)
990+
991+
bb1(%6 : @guaranteed $DoubleWrapper, %7 : @guaranteed $Klass):
992+
end_borrow %7 : $Klass
993+
end_borrow %6 : $DoubleWrapper
994+
destroy_value %0 : $DoubleWrapper
995+
%8 = tuple ()
996+
return %8 : $()
997+
}
955998

956999
// CHECK-LABEL: sil [ossa] @borrow_guaranteed_tuple : {{.*}} {
9571000
// CHECK: {{bb[0-9]+}}([[INSTANCE_1:%[^,]+]] : @owned $Klass, [[INSTANCE_2:%[^,]+]] : @owned $Klass):

0 commit comments

Comments
 (0)