Skip to content

Commit 6e1cd3a

Browse files
Merge pull request #78306 from nate-chandler/rdar141560546
[DCE] Don't complete lifetimes of erased values.
2 parents d3f7369 + 6d9ae19 commit 6e1cd3a

File tree

2 files changed

+78
-22
lines changed

2 files changed

+78
-22
lines changed

lib/SILOptimizer/Transforms/DeadCodeElimination.cpp

+41-16
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

@@ -731,9 +732,23 @@ bool DCE::removeDead() {
731732
endLifetimeOfLiveValue(predOp, insertPt);
732733
}
733734
}
734-
erasePhiArgument(&BB, i, /*cleanupDeadPhiOps=*/true,
735-
InstModCallbacks().onCreateNewInst(
736-
[&](auto *inst) { markInstructionLive(inst); }));
735+
erasePhiArgument(
736+
&BB, i, /*cleanupDeadPhiOps=*/true,
737+
InstModCallbacks()
738+
.onCreateNewInst([&](auto *inst) { markInstructionLive(inst); })
739+
.onDelete([&](auto *inst) {
740+
for (auto result : inst->getResults()) {
741+
result = lookThroughBorrowedFromDef(result);
742+
if (valuesToComplete.count(result)) {
743+
valuesToComplete.erase(result);
744+
}
745+
}
746+
inst->replaceAllUsesOfAllResultsWithUndef();
747+
if (isa<ApplyInst>(inst))
748+
CallsChanged = true;
749+
++NumDeletedInsts;
750+
inst->eraseFromParent();
751+
}));
737752
Changed = true;
738753
BranchesChanged = true;
739754
}
@@ -747,7 +762,8 @@ bool DCE::removeDead() {
747762
// We want to replace dead terminators with unconditional branches to
748763
// the nearest post-dominator that has useful instructions.
749764
if (auto *termInst = dyn_cast<TermInst>(Inst)) {
750-
SILBasicBlock *postDom = nearestUsefulPostDominator(Inst->getParent());
765+
SILBasicBlock *postDom =
766+
nearestUsefulPostDominator(termInst->getParent());
751767
if (!postDom)
752768
continue;
753769

@@ -757,12 +773,13 @@ bool DCE::removeDead() {
757773
}
758774
}
759775
LLVM_DEBUG(llvm::dbgs() << "Replacing branch: ");
760-
LLVM_DEBUG(Inst->dump());
776+
LLVM_DEBUG(termInst->dump());
761777
LLVM_DEBUG(llvm::dbgs()
762778
<< "with jump to: BB" << postDom->getDebugID() << "\n");
763779

764-
replaceBranchWithJump(Inst, postDom);
765-
Inst->eraseFromParent();
780+
replaceBranchWithJump(termInst, postDom);
781+
++NumDeletedInsts;
782+
termInst->eraseFromParent();
766783
BranchesChanged = true;
767784
Changed = true;
768785
continue;
@@ -780,6 +797,12 @@ bool DCE::removeDead() {
780797
}
781798
}
782799
}
800+
for (auto result : Inst->getResults()) {
801+
result = lookThroughBorrowedFromDef(result);
802+
if (valuesToComplete.count(result)) {
803+
valuesToComplete.erase(result);
804+
}
805+
}
783806
Inst->replaceAllUsesOfAllResultsWithUndef();
784807

785808
if (isa<ApplyInst>(Inst))
@@ -792,7 +815,9 @@ bool DCE::removeDead() {
792815

793816
OSSALifetimeCompletion completion(F, DT, *deadEndBlocks);
794817
for (auto value : valuesToComplete) {
795-
completion.completeOSSALifetime(value,
818+
if (!value.has_value())
819+
continue;
820+
completion.completeOSSALifetime(*value,
796821
OSSALifetimeCompletion::Boundary::Liveness);
797822
}
798823

@@ -849,9 +874,9 @@ void DCE::computeLevelNumbers(PostDomTreeNode *root) {
849874
auto entry = workList.pop_back_val();
850875
PostDomTreeNode *node = entry.first;
851876
unsigned level = entry.second;
852-
877+
853878
insertControllingInfo(node->getBlock(), level);
854-
879+
855880
for (PostDomTreeNode *child : *node) {
856881
workList.push_back({child, level + 1});
857882
}

test/SILOptimizer/dead_code_elimination_nontrivial_ossa.sil

+37-6
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)