Skip to content

Commit 6d9ae19

Browse files
committed
[DCE] Don't complete lifetimes of erased values.
DCE may enqueue a value for lifetime completion and later on erase the instruction that defines that value. When erasing an instruction, erase each of its results from the collection of values to complete. rdar://141560546
1 parent f75f12b commit 6d9ae19

File tree

2 files changed

+61
-15
lines changed

2 files changed

+61
-15
lines changed

lib/SILOptimizer/Transforms/DeadCodeElimination.cpp

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,20 @@
1212

1313
#define DEBUG_TYPE "sil-dce"
1414
#include "swift/Basic/Assertions.h"
15+
#include "swift/Basic/BlotSetVector.h"
1516
#include "swift/SIL/BasicBlockBits.h"
1617
#include "swift/SIL/DebugUtils.h"
1718
#include "swift/SIL/MemAccessUtils.h"
1819
#include "swift/SIL/NodeBits.h"
20+
#include "swift/SIL/OSSALifetimeCompletion.h"
1921
#include "swift/SIL/OwnershipUtils.h"
2022
#include "swift/SIL/SILArgument.h"
2123
#include "swift/SIL/SILBasicBlock.h"
2224
#include "swift/SIL/SILBuilder.h"
2325
#include "swift/SIL/SILFunction.h"
2426
#include "swift/SIL/SILUndef.h"
25-
#include "swift/SIL/OSSALifetimeCompletion.h"
26-
#include "swift/SILOptimizer/Analysis/DominanceAnalysis.h"
2727
#include "swift/SILOptimizer/Analysis/DeadEndBlocksAnalysis.h"
28+
#include "swift/SILOptimizer/Analysis/DominanceAnalysis.h"
2829
#include "swift/SILOptimizer/PassManager/Passes.h"
2930
#include "swift/SILOptimizer/PassManager/Transforms.h"
3031
#include "swift/SILOptimizer/Utils/BasicBlockOptUtils.h"
@@ -94,7 +95,7 @@ static bool seemsUseful(SILInstruction *I) {
9495
if (isa<DebugValueInst>(I))
9596
return isa<SILFunctionArgument>(I->getOperand(0))
9697
|| isa<SILUndef>(I->getOperand(0));
97-
98+
9899

99100
// Don't delete allocation instructions in DCE.
100101
if (isa<AllocRefInst>(I) || isa<AllocRefDynamicInst>(I)) {
@@ -131,7 +132,7 @@ class DCE {
131132
DominanceInfo *DT;
132133
DeadEndBlocks *deadEndBlocks;
133134
llvm::DenseMap<SILBasicBlock *, ControllingInfo> ControllingInfoMap;
134-
llvm::SmallVector<SILValue> valuesToComplete;
135+
SmallBlotSetVector<SILValue, 8> valuesToComplete;
135136

136137
// Maps instructions which produce a failing condition (like overflow
137138
// builtins) to the actual cond_fail instructions which handle the failure.
@@ -212,7 +213,7 @@ class DCE {
212213
markLive();
213214
return removeDead();
214215
}
215-
216+
216217
bool mustInvalidateCalls() const { return CallsChanged; }
217218
bool mustInvalidateBranches() const { return BranchesChanged; }
218219
};
@@ -637,7 +638,7 @@ void DCE::endLifetimeOfLiveValue(Operand *op, SILInstruction *insertPt) {
637638
// If DCE is going to delete the block in which we have to insert a
638639
// compensating lifetime end, let complete lifetimes utility handle it.
639640
if (!LiveBlocks.contains(insertPt->getParent())) {
640-
valuesToComplete.push_back(lookThroughBorrowedFromDef(value));
641+
valuesToComplete.insert(lookThroughBorrowedFromDef(value));
641642
return;
642643
}
643644

@@ -736,6 +737,12 @@ bool DCE::removeDead() {
736737
InstModCallbacks()
737738
.onCreateNewInst([&](auto *inst) { markInstructionLive(inst); })
738739
.onDelete([&](auto *inst) {
740+
for (auto result : inst->getResults()) {
741+
result = lookThroughBorrowedFromDef(result);
742+
if (valuesToComplete.count(result)) {
743+
valuesToComplete.erase(result);
744+
}
745+
}
739746
inst->replaceAllUsesOfAllResultsWithUndef();
740747
if (isa<ApplyInst>(inst))
741748
CallsChanged = true;
@@ -790,6 +797,12 @@ bool DCE::removeDead() {
790797
}
791798
}
792799
}
800+
for (auto result : Inst->getResults()) {
801+
result = lookThroughBorrowedFromDef(result);
802+
if (valuesToComplete.count(result)) {
803+
valuesToComplete.erase(result);
804+
}
805+
}
793806
Inst->replaceAllUsesOfAllResultsWithUndef();
794807

795808
if (isa<ApplyInst>(Inst))
@@ -802,7 +815,9 @@ bool DCE::removeDead() {
802815

803816
OSSALifetimeCompletion completion(F, DT, *deadEndBlocks);
804817
for (auto value : valuesToComplete) {
805-
completion.completeOSSALifetime(value,
818+
if (!value.has_value())
819+
continue;
820+
completion.completeOSSALifetime(*value,
806821
OSSALifetimeCompletion::Boundary::Liveness);
807822
}
808823

@@ -859,9 +874,9 @@ void DCE::computeLevelNumbers(PostDomTreeNode *root) {
859874
auto entry = workList.pop_back_val();
860875
PostDomTreeNode *node = entry.first;
861876
unsigned level = entry.second;
862-
877+
863878
insertControllingInfo(node->getBlock(), level);
864-
879+
865880
for (PostDomTreeNode *child : *node) {
866881
workList.push_back({child, level + 1});
867882
}

test/SILOptimizer/dead_code_elimination_nontrivial_ossa.sil

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -514,7 +514,7 @@ bb1(%newborrow : @guaranteed $Klass, %borrow2 : @guaranteed $Klass):
514514
// Here %newborrowo and %newborrowi are both dead phis.
515515
// First end_borrow for the incoming value of %newborrowi is added
516516
// It is non straight forward to find the insert pt for the end_borrow of the incoming value of %newborrowo
517-
// This may not be important once CanonicalizeOSSALifetime supports rewrite of multi-block borrows.
517+
// This may not be important once CanonicalizeOSSALifetime supports rewrite of multi-block borrows.
518518
sil [ossa] @dce_nestedborrowlifetime3 : $@convention(thin) (@guaranteed Klass) -> () {
519519
bb0(%0 : @guaranteed $Klass):
520520
%borrowo = begin_borrow %0 : $Klass
@@ -752,7 +752,7 @@ exit:
752752
sil hidden [ossa] @add_end_borrow_after_destroy_value : $@convention(thin) (Builtin.Int1, @owned Klass, @owned Klass) -> () {
753753
bb0(%condition : $Builtin.Int1, %instance_1 : @owned $Klass, %instance_2 : @owned $Klass):
754754
%lifetime_1 = begin_borrow %instance_1 : $Klass
755-
755+
756756
%copy_1 = copy_value %lifetime_1 : $Klass
757757
%stack_addr = alloc_stack $Klass
758758
store %copy_1 to [init] %stack_addr : $*Klass
@@ -1124,7 +1124,7 @@ sil @use_klass : $@convention(thin) (@guaranteed Klass) -> ()
11241124
sil [ossa] @test_forwarded_phi1 : $@convention(thin) (@owned Wrapper1) -> () {
11251125
bb0(%0 : @owned $Wrapper1):
11261126
%outer = begin_borrow %0 : $Wrapper1
1127-
br bb1
1127+
br bb1
11281128

11291129
bb1:
11301130
%ex1 = struct_extract %outer : $Wrapper1, #Wrapper1.val1
@@ -1144,13 +1144,13 @@ bb3(%phi3 : @guaranteed $Klass, %phi4 : @guaranteed $Wrapper1):
11441144
}
11451145

11461146
// CHECK-LABEL: sil [ossa] @test_forwarded_phi2 :
1147-
// CHECK: br bb3
1147+
// CHECK: br bb3
11481148
// CHECK: end_borrow
11491149
// CHECK-LABEL: } // end sil function 'test_forwarded_phi2'
11501150
sil [ossa] @test_forwarded_phi2 : $@convention(thin) (@owned Wrapper1) -> () {
11511151
bb0(%0 : @owned $Wrapper1):
11521152
%outer = begin_borrow %0 : $Wrapper1
1153-
br bb1
1153+
br bb1
11541154

11551155
bb1:
11561156
br bb2(%outer : $Wrapper1)
@@ -1202,7 +1202,7 @@ bb3(%phi2 : @guaranteed $Klass, %phi3 : @guaranteed $Wrapper1):
12021202
sil [ossa] @test_loadborrow_dep : $@convention(thin) (@in Wrapper1) -> () {
12031203
bb0(%0 : $*Wrapper1):
12041204
%outer = load_borrow %0 : $*Wrapper1
1205-
br bb1
1205+
br bb1
12061206

12071207
bb1:
12081208
%ex1 = struct_extract %outer : $Wrapper1, #Wrapper1.val1
@@ -1411,3 +1411,34 @@ bb5(%16 : @reborrow $FakeOptional<Klass>, %17 : @reborrow $FakeOptional<Klass>):
14111411
return %23
14121412
}
14131413

1414+
struct String {
1415+
var guts: Builtin.AnyObject
1416+
}
1417+
1418+
sil [_semantics "string.makeUTF8"] [ossa] @makeString : $@convention(thin) (Builtin.RawPointer, Builtin.Word) -> @owned String
1419+
1420+
// CHECK-LABEL: sil [ossa] @uncompletedDeadStrings
1421+
// CHECK-NOT: apply
1422+
// CHECK-LABEL: } // end sil function 'uncompletedDeadStrings'
1423+
sil [ossa] @uncompletedDeadStrings : $@convention(thin) () -> () {
1424+
%first_ptr = string_literal utf8 "first"
1425+
%first_len = integer_literal $Builtin.Word, 5
1426+
%makeString = function_ref @makeString : $@convention(thin) (Builtin.RawPointer, Builtin.Word) -> @owned String
1427+
%first = apply %makeString(%first_ptr, %first_len) : $@convention(thin) (Builtin.RawPointer, Builtin.Word) -> @owned String
1428+
cond_br undef, nope, yep
1429+
1430+
nope:
1431+
destroy_value %first
1432+
%second_ptr = string_literal utf8 "second"
1433+
%second_len = integer_literal $Builtin.Word, 6
1434+
%second = apply %makeString(%second_ptr, %second_len) : $@convention(thin) (Builtin.RawPointer, Builtin.Word) -> @owned String
1435+
br this(%second)
1436+
1437+
yep:
1438+
br this(%first)
1439+
1440+
this(%string : @owned $String):
1441+
destroy_value %string
1442+
%retval = tuple ()
1443+
return %retval
1444+
}

0 commit comments

Comments
 (0)