Skip to content

Commit a4a10a5

Browse files
committed
Update DCE for @guaranteed forwarding phi support
1 parent 5b40ba7 commit a4a10a5

File tree

2 files changed

+107
-56
lines changed

2 files changed

+107
-56
lines changed

lib/SILOptimizer/Transforms/DeadCodeElimination.cpp

Lines changed: 33 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ static bool seemsUseful(SILInstruction *I) {
5050
// side-effects, they can be DCE'ed if they do not have useful
5151
// dependencies/reverse dependencies
5252
if (isa<BeginAccessInst>(I) || isa<CopyValueInst>(I) ||
53-
isa<DestroyValueInst>(I) || isa<EndLifetimeInst>(I))
53+
isa<DestroyValueInst>(I) || isa<EndLifetimeInst>(I) ||
54+
isa<EndBorrowInst>(I))
5455
return false;
5556

5657
// A load [copy] is okay to be DCE'ed if there are no useful dependencies
@@ -125,13 +126,12 @@ class DCE {
125126
llvm::DenseMap<SILValue, SmallPtrSet<SILInstruction *, 4>>
126127
ReverseDependencies;
127128

128-
// reborrowDependencies tracks the dependency of a reborrowed phiArg with its
129-
// renamed base value.
130-
// A reborrowed phiArg may have a new base value, if it's original base value
131-
// was also passed as a branch operand. The renamed base value should then be
132-
// live if the reborrow phiArg was also live.
129+
// guaranteedPhiDependencies tracks the dependency of a reborrowed phiArg with
130+
// its renamed base value. A reborrowed phiArg may have a new base value, if
131+
// it's original base value was also passed as a branch operand. The renamed
132+
// base value should then be live if the reborrow phiArg was also live.
133133
using BaseValueSet = SmallPtrSet<SILValue, 8>;
134-
llvm::DenseMap<SILPhiArgument *, BaseValueSet> reborrowDependencies;
134+
llvm::DenseMap<SILPhiArgument *, BaseValueSet> guaranteedPhiDependencies;
135135

136136
/// Tracks if the pass changed branches.
137137
bool BranchesChanged = false;
@@ -143,9 +143,9 @@ class DCE {
143143
/// Record a reverse dependency from \p from to \p to meaning \p to is live
144144
/// if \p from is also live.
145145
void addReverseDependency(SILValue from, SILInstruction *to);
146-
/// Starting from \p borrowInst find all reborrow dependency of its reborrows
147-
/// with their renamed base values.
148-
void findReborrowDependencies(BeginBorrowInst *borrowInst);
146+
/// Starting from \p borrow find all reborrow and guaranteed phi dependencies
147+
/// along with their base values.
148+
void findGuaranteedPhiDependencies(BorrowedValue borrow);
149149
bool removeDead();
150150

151151
void computeLevelNumbers(PostDomTreeNode *root);
@@ -288,7 +288,6 @@ void DCE::markLive() {
288288
auto *borrowInst = cast<BeginBorrowInst>(&I);
289289
if (borrowInst->getOperand()->getOwnershipKind() ==
290290
OwnershipKind::Guaranteed) {
291-
markInstructionLive(borrowInst);
292291
// Visit the end_borrows of all the borrow scopes that this
293292
// begin_borrow could be borrowing.
294293
SmallVector<SILValue, 4> roots;
@@ -301,8 +300,8 @@ void DCE::markLive() {
301300
}
302301
continue;
303302
}
304-
// Populate reborrowDependencies for this borrow
305-
findReborrowDependencies(borrowInst);
303+
// Populate guaranteedPhiDependencies for this borrow
304+
findGuaranteedPhiDependencies(BorrowedValue(borrowInst));
306305
// Don't optimize a borrow scope if it is lexical or has a pointer
307306
// escape.
308307
if (borrowInst->isLexical() ||
@@ -315,6 +314,10 @@ void DCE::markLive() {
315314
}
316315
break;
317316
}
317+
case SILInstructionKind::LoadBorrowInst: {
318+
findGuaranteedPhiDependencies(BorrowedValue(cast<LoadBorrowInst>(&I)));
319+
break;
320+
}
318321
default:
319322
if (seemsUseful(&I))
320323
markInstructionLive(&I);
@@ -337,19 +340,23 @@ void DCE::addReverseDependency(SILValue from, SILInstruction *to) {
337340
ReverseDependencies[from].insert(to);
338341
}
339342

340-
void DCE::findReborrowDependencies(BeginBorrowInst *borrowInst) {
341-
LLVM_DEBUG(llvm::dbgs() << "Finding reborrow dependencies of " << borrowInst
342-
<< "\n");
343-
BorrowingOperand initialScopedOperand(&borrowInst->getOperandRef());
344-
auto visitReborrowBaseValuePair = [&](SILPhiArgument *phiArg,
345-
SILValue baseValue) {
346-
reborrowDependencies[phiArg].insert(baseValue);
343+
void DCE::findGuaranteedPhiDependencies(BorrowedValue borrow) {
344+
assert(borrow.kind == BorrowedValueKind::BeginBorrow ||
345+
borrow.kind == BorrowedValueKind::LoadBorrow);
346+
LLVM_DEBUG(llvm::dbgs() << "Finding @guaranteed phi dependencies of "
347+
<< borrow << "\n");
348+
auto visitDependentPhiBaseValuePair = [&](SILPhiArgument *phiArg,
349+
SILValue baseValue) {
350+
guaranteedPhiDependencies[phiArg].insert(baseValue);
347351
};
348-
// Find all reborrow dependencies starting from \p borrowInst and populate
349-
// them in reborrowDependencies
350-
findTransitiveReborrowBaseValuePairs(initialScopedOperand,
351-
borrowInst->getOperand(),
352-
visitReborrowBaseValuePair);
352+
// Find all dependencies starting from \p borrowInst and populate
353+
// them in guaranteedPhiDependencies
354+
if (borrow.kind == BorrowedValueKind::BeginBorrow) {
355+
visitExtendedReborrowPhiBaseValuePairs(cast<BeginBorrowInst>(borrow.value),
356+
visitDependentPhiBaseValuePair);
357+
}
358+
visitExtendedGuaranteedForwardingPhiBaseValuePairs(
359+
borrow, visitDependentPhiBaseValuePair);
353360
}
354361

355362
// Mark as live the terminator argument at index ArgIndex in Pred that
@@ -429,7 +436,7 @@ void DCE::propagateLiveBlockArgument(SILArgument *Arg) {
429436
}
430437

431438
if (auto *phi = dyn_cast<SILPhiArgument>(Arg)) {
432-
for (auto depVal : reborrowDependencies.lookup(phi)) {
439+
for (auto depVal : guaranteedPhiDependencies.lookup(phi)) {
433440
markValueLive(depVal);
434441
}
435442
}

test/SILOptimizer/dead_code_elimination_nontrivial_ossa.sil

Lines changed: 74 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,14 @@ case none
2323
case some(T)
2424
}
2525

26+
struct Wrapper1 {
27+
var val1: Wrapper2
28+
}
29+
30+
struct Wrapper2 {
31+
var val2: Klass
32+
}
33+
2634
sil [ossa] @$testtryapplyklassgen : $@convention(thin) () -> (@owned Klass, @error any Error)
2735
sil [ossa] @$use_klass1 : $@convention(thin) (@owned Klass) -> ()
2836
sil [ossa] @$use_klass2 : $@convention(thin) (@guaranteed Klass) -> ()
@@ -728,17 +736,10 @@ bb3(%original : @owned $Klass, %lifetime : @guaranteed $Klass):
728736

729737
// CHECK-LABEL: sil [ossa] @borrow_none : {{.*}} {
730738
// CHECK: {{bb[0-9]+}}:
731-
// CHECK: [[INSTANCE:%[^,]+]] = enum $FakeOptional<Klass>, #FakeOptional.none!enumelt
732-
// CHECK: switch_enum [[INSTANCE]] : $FakeOptional<Klass>, case #FakeOptional.some!enumelt: [[WORK:bb[0-9]+]], case #FakeOptional.none!enumelt: [[TO_EXIT:bb[0-9]+]], forwarding: @guaranteed
733-
// CHECK: [[TO_EXIT]]:
734-
// CHECK: br [[EXIT:bb[0-9]+]]
735-
// CHECK: [[WORK]]([[PAYLOAD:%[^,]+]] : @guaranteed $Klass):
736-
// CHECK: [[LIFETIME:%[^,]+]] = begin_borrow [[PAYLOAD]]
737-
// CHECK: end_borrow [[LIFETIME]]
738-
// CHECK: br [[EXIT]]
739+
// CHECK-NEXT: br [[EXIT:bb[0-9]+]]
739740
// CHECK: [[EXIT]]:
740-
// CHECK: [[RETVAL:%[^,]+]] = tuple ()
741-
// CHECK: return [[RETVAL]] : $()
741+
// CHECK-NEXT: [[RETVAL:%[^,]+]] = tuple ()
742+
// CHECK-NEXT: return [[RETVAL]] : $()
742743
// CHECK-LABEL: } // end sil function 'borrow_none'
743744
sil [ossa] @borrow_none : $@convention(thin) () -> () {
744745
entry:
@@ -810,8 +811,6 @@ exit(%outer_lifetime_3 : @guaranteed $Klass, %inner_lifetime_2 : @guaranteed $Kl
810811
// CHECK: [[BORROW_EITHER:%[^,]+]] = begin_borrow [[EITHER]]
811812
// CHECK: switch_enum [[BORROW_EITHER]] : $EitherNoneOrAnyObject, case #EitherNoneOrAnyObject.none!enumelt: [[NONE_BLOCK:bb[0-9]+]], case #EitherNoneOrAnyObject.any!enumelt: [[SOME_BLOCK:bb[0-9]+]]
812813
// CHECK: [[SOME_BLOCK]]([[PAYLOAD:%[^,]+]] : @guaranteed $AnyObject):
813-
// CHECK: [[LIFETIME:%[^,]+]] = begin_borrow [[PAYLOAD]]
814-
// CHECK: end_borrow [[LIFETIME]]
815814
// CHECK: end_borrow [[BORROW_EITHER]]
816815
// CHECK: destroy_value [[EITHER]]
817816
// CHECK: br [[EXIT:bb[0-9]+]]
@@ -845,6 +844,18 @@ exit:
845844
return %retval : $()
846845
}
847846

847+
sil [ossa] @reborrowed_guaranteed_phi3 : $@convention(thin) (@owned Klass) -> () {
848+
entry(%instance : @owned $Klass):
849+
%outer_lifetime_1 = begin_borrow %instance : $Klass
850+
%inner_lifetime_1 = begin_borrow %outer_lifetime_1 : $Klass
851+
br exit(%inner_lifetime_1 : $Klass)
852+
exit(%inner_lifetime_2 : @guaranteed $Klass):
853+
end_borrow %inner_lifetime_2 : $Klass
854+
end_borrow %outer_lifetime_1 : $Klass
855+
destroy_value %instance : $Klass
856+
%retval = tuple ()
857+
return %retval : $()
858+
}
848859
// CHECK-LABEL: sil [ossa] @reborrow_load_borrow : {{.*}} {
849860
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : $*Klass):
850861
// CHECK: [[LIFETIME:%[^,]+]] = load_borrow [[INSTANCE]]
@@ -890,13 +901,7 @@ bb1(%4 : @guaranteed $Klass, %5 : @guaranteed $Klass):
890901

891902
// CHECK-LABEL: sil [ossa] @borrow_guaranteed_tuple : {{.*}} {
892903
// CHECK: {{bb[0-9]+}}([[INSTANCE_1:%[^,]+]] : @owned $Klass, [[INSTANCE_2:%[^,]+]] : @owned $Klass):
893-
// CHECK: [[LIFETIME_1_1:%[^,]+]] = begin_borrow [[INSTANCE_1]]
894-
// CHECK: [[LIFETIME_2_1:%[^,]+]] = begin_borrow [[INSTANCE_2]]
895-
// CHECK: br [[EXIT:bb[0-9]+]]([[LIFETIME_1_1]] : $Klass, [[LIFETIME_2_1]] : $Klass)
896-
// CHECK: [[EXIT]]([[LIFETIME_1_2:%[^,]+]] : @guaranteed $Klass, [[LIFETIME_2_2:%[^,]+]] : @guaranteed $Klass):
897-
// CHECK: end_borrow [[LIFETIME_2_2]]
898904
// CHECK: destroy_value [[INSTANCE_2]]
899-
// CHECK: end_borrow [[LIFETIME_1_2]]
900905
// CHECK: destroy_value [[INSTANCE_1]]
901906
// CHECK: [[RETVAL:%[^,]+]] = tuple ()
902907
// CHECK: return [[RETVAL]] : $()
@@ -906,10 +911,8 @@ entry(%instance_1 : @owned $Klass, %instance_2 : @owned $Klass):
906911
%lifetime_1_1 = begin_borrow %instance_1 : $Klass
907912
%lifetime_2_1 = begin_borrow %instance_2 : $Klass
908913
%tuple = tuple $(Klass, Klass) (%lifetime_1_1, %lifetime_2_1)
909-
%tuple_lifetime_1 = begin_borrow %tuple : $(Klass, Klass)
910-
br exit(%lifetime_1_1 : $Klass, %lifetime_2_1 : $Klass, %tuple_lifetime_1 : $(Klass, Klass))
911-
exit(%lifetime_1_2 : @guaranteed $Klass, %lifetime_2_2 : @guaranteed $Klass, %tuple_lifetime_2 : @guaranteed $(Klass, Klass)):
912-
end_borrow %tuple_lifetime_2 : $(Klass, Klass)
914+
br exit(%lifetime_1_1 : $Klass, %lifetime_2_1 : $Klass, %tuple : $(Klass, Klass))
915+
exit(%lifetime_1_2 : @guaranteed $Klass, %lifetime_2_2 : @guaranteed $Klass, %tuple_2 : @guaranteed $(Klass, Klass)):
913916
end_borrow %lifetime_2_2 : $Klass
914917
destroy_value %instance_2 : $Klass
915918
end_borrow %lifetime_1_2 : $Klass
@@ -920,10 +923,6 @@ exit(%lifetime_1_2 : @guaranteed $Klass, %lifetime_2_2 : @guaranteed $Klass, %tu
920923

921924
// CHECK-LABEL: sil [ossa] @borrow_guaranteed_struct : {{.*}} {
922925
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @owned $Klass):
923-
// CHECK: [[LIFETIME:%[^,]+]] = begin_borrow [[INSTANCE]]
924-
// CHECK: br bb1([[LIFETIME]] : $Klass)
925-
// CHECK: bb1([[LIFETIME_2:%[^,]+]] : @guaranteed $Klass):
926-
// CHECK: end_borrow [[LIFETIME_2]]
927926
// CHECK: destroy_value [[INSTANCE]]
928927
// CHECK: [[RETVAL:%[^,]+]] = tuple ()
929928
// CHECK: return [[RETVAL]] : $()
@@ -932,10 +931,8 @@ sil [ossa] @borrow_guaranteed_struct : $@convention(thin) (@owned Klass) -> () {
932931
entry(%instance_1 : @owned $Klass):
933932
%lifetime_1 = begin_borrow %instance_1 : $Klass
934933
%struct = struct $NonTrivialStruct (%lifetime_1 : $Klass)
935-
%struct_lifetime_1 = begin_borrow %struct : $NonTrivialStruct
936-
br exit(%lifetime_1 : $Klass, %struct_lifetime_1 : $NonTrivialStruct)
937-
exit(%lifetime_2 : @guaranteed $Klass, %struct_lifetime_2 : @guaranteed $NonTrivialStruct):
938-
end_borrow %struct_lifetime_2 : $NonTrivialStruct
934+
br exit(%lifetime_1 : $Klass, %struct : $NonTrivialStruct)
935+
exit(%lifetime_2 : @guaranteed $Klass, %struct_2 : @guaranteed $NonTrivialStruct):
939936
end_borrow %lifetime_2 : $Klass
940937
destroy_value %instance_1 : $Klass
941938
%retval = tuple ()
@@ -998,3 +995,50 @@ bb1(%21 : $@noescape @callee_guaranteed () -> (), %22 : @guaranteed $@callee_gua
998995
%28 = tuple ()
999996
return %28: $()
1000997
}
998+
999+
sil @use_klass : $@convention(thin) (@guaranteed Klass) -> ()
1000+
1001+
sil [ossa] @test_forwarded_phi4 : $@convention(thin) (@owned Wrapper1) -> () {
1002+
bb0(%0 : @owned $Wrapper1):
1003+
%outer = begin_borrow %0 : $Wrapper1
1004+
br bb1
1005+
1006+
bb1:
1007+
%ex1 = struct_extract %outer : $Wrapper1, #Wrapper1.val1
1008+
br bb2(%ex1 : $Wrapper2, %outer : $Wrapper1)
1009+
1010+
bb2(%phi1 : @guaranteed $Wrapper2, %phi2 : @guaranteed $Wrapper1):
1011+
%ex2 = struct_extract %phi1 : $Wrapper2, #Wrapper2.val2
1012+
br bb3(%ex2 : $Klass, %phi2 : $Wrapper1)
1013+
1014+
bb3(%phi3 : @guaranteed $Klass, %phi4 : @guaranteed $Wrapper1):
1015+
%f = function_ref @use_klass : $@convention(thin) (@guaranteed Klass) -> ()
1016+
apply %f(%phi3) : $@convention(thin) (@guaranteed Klass) -> ()
1017+
end_borrow %phi4 : $Wrapper1
1018+
destroy_value %0 : $Wrapper1
1019+
%9999 = tuple()
1020+
return %9999 : $()
1021+
}
1022+
1023+
sil [ossa] @test_loadborrow_dep : $@convention(thin) (@in Wrapper1) -> () {
1024+
bb0(%0 : $*Wrapper1):
1025+
%outer = load_borrow %0 : $*Wrapper1
1026+
br bb1
1027+
1028+
bb1:
1029+
%ex1 = struct_extract %outer : $Wrapper1, #Wrapper1.val1
1030+
br bb2(%ex1 : $Wrapper2, %outer : $Wrapper1)
1031+
1032+
bb2(%phi1 : @guaranteed $Wrapper2, %phi2 : @guaranteed $Wrapper1):
1033+
%ex2 = struct_extract %phi1 : $Wrapper2, #Wrapper2.val2
1034+
br bb3(%ex2 : $Klass, %phi2 : $Wrapper1)
1035+
1036+
bb3(%phi3 : @guaranteed $Klass, %phi4 : @guaranteed $Wrapper1):
1037+
%f = function_ref @use_klass : $@convention(thin) (@guaranteed Klass) -> ()
1038+
apply %f(%phi3) : $@convention(thin) (@guaranteed Klass) -> ()
1039+
end_borrow %phi4 : $Wrapper1
1040+
destroy_addr %0 : $*Wrapper1
1041+
%9999 = tuple()
1042+
return %9999 : $()
1043+
}
1044+

0 commit comments

Comments
 (0)