Skip to content

Commit f7d1c59

Browse files
authored
Merge pull request #78053 from meg-gupta/fixdce
Fix DCE for ownership forwarding instructions
2 parents 98c6c9c + daa9b16 commit f7d1c59

File tree

2 files changed

+125
-5
lines changed

2 files changed

+125
-5
lines changed

lib/SILOptimizer/Transforms/DeadCodeElimination.cpp

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@
2222
#include "swift/SIL/SILBuilder.h"
2323
#include "swift/SIL/SILFunction.h"
2424
#include "swift/SIL/SILUndef.h"
25+
#include "swift/SIL/OSSALifetimeCompletion.h"
2526
#include "swift/SILOptimizer/Analysis/DominanceAnalysis.h"
27+
#include "swift/SILOptimizer/Analysis/DeadEndBlocksAnalysis.h"
2628
#include "swift/SILOptimizer/PassManager/Passes.h"
2729
#include "swift/SILOptimizer/PassManager/Transforms.h"
2830
#include "swift/SILOptimizer/Utils/BasicBlockOptUtils.h"
@@ -126,7 +128,10 @@ class DCE {
126128
BasicBlockSet LiveBlocks;
127129
llvm::SmallVector<SILInstruction *, 64> Worklist;
128130
PostDominanceInfo *PDT;
131+
DominanceInfo *DT;
132+
DeadEndBlocks *deadEndBlocks;
129133
llvm::DenseMap<SILBasicBlock *, ControllingInfo> ControllingInfoMap;
134+
llvm::SmallVector<SILValue> valuesToComplete;
130135

131136
// Maps instructions which produce a failing condition (like overflow
132137
// builtins) to the actual cond_fail instructions which handle the failure.
@@ -194,8 +199,10 @@ class DCE {
194199
void endLifetimeOfLiveValue(Operand *op, SILInstruction *insertPt);
195200

196201
public:
197-
DCE(SILFunction *F, PostDominanceInfo *PDT)
198-
: F(F), LiveArguments(F), LiveInstructions(F), LiveBlocks(F), PDT(PDT) {}
202+
DCE(SILFunction *F, PostDominanceInfo *PDT, DominanceInfo *DT,
203+
DeadEndBlocks *deadEndBlocks)
204+
: F(F), LiveArguments(F), LiveInstructions(F), LiveBlocks(F), PDT(PDT),
205+
DT(DT), deadEndBlocks(deadEndBlocks) {}
199206

200207
/// The entry point to the transformation.
201208
bool run() {
@@ -626,6 +633,14 @@ void DCE::endLifetimeOfLiveValue(Operand *op, SILInstruction *insertPt) {
626633
}
627634

628635
assert(op->isLifetimeEnding());
636+
637+
// If DCE is going to delete the block in which we have to insert a
638+
// compensating lifetime end, let complete lifetimes utility handle it.
639+
if (!LiveBlocks.contains(insertPt->getParent())) {
640+
valuesToComplete.push_back(value);
641+
return;
642+
}
643+
629644
SILBuilderWithScope builder(insertPt);
630645
if (value->getOwnershipKind() == OwnershipKind::Owned) {
631646
builder.createDestroyValue(RegularLocation::getAutoGeneratedLocation(),
@@ -772,6 +787,12 @@ bool DCE::removeDead() {
772787
}
773788
}
774789

790+
OSSALifetimeCompletion completion(F, DT, *deadEndBlocks);
791+
for (auto value : valuesToComplete) {
792+
completion.completeOSSALifetime(value,
793+
OSSALifetimeCompletion::Boundary::Liveness);
794+
}
795+
775796
return Changed;
776797
}
777798

@@ -977,8 +998,11 @@ class DCEPass : public SILFunctionTransform {
977998
LLVM_DEBUG(llvm::dbgs() << "*** DCE on function: " << F->getName()
978999
<< " ***\n");
9791000

980-
auto *DA = PM->getAnalysis<PostDominanceAnalysis>();
981-
PostDominanceInfo *PDT = DA->get(F);
1001+
auto *PDA = PM->getAnalysis<PostDominanceAnalysis>();
1002+
PostDominanceInfo *PDT = PDA->get(F);
1003+
1004+
auto *DA = PM->getAnalysis<DominanceAnalysis>();
1005+
auto *DEA = getAnalysis<DeadEndBlocksAnalysis>();
9821006

9831007
// If we have a function that consists of nothing but a
9841008
// structurally infinite loop like:
@@ -987,7 +1011,7 @@ class DCEPass : public SILFunctionTransform {
9871011
if (!PDT->getRootNode())
9881012
return;
9891013

990-
DCE dce(F, PDT);
1014+
DCE dce(F, PDT, DA->get(F), DEA->get(F));
9911015
if (dce.run()) {
9921016
using InvalidationKind = SILAnalysis::InvalidationKind;
9931017
unsigned Inv = InvalidationKind::Instructions;

test/SILOptimizer/dead_code_elimination_nontrivial_ossa.sil

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1280,3 +1280,99 @@ bb2(%phi1 : @guaranteed $NonTrivialStruct, %phi2 : @guaranteed $NonTrivialStruct
12801280
return %9999 : $()
12811281
}
12821282

1283+
// CHECK-LABEL: sil [ossa] @dce_deadterm4 :
1284+
// CHECK-NOT: switch_enum
1285+
// CHECK-LABEL: } // end sil function 'dce_deadterm4'
1286+
sil [ossa] @dce_deadterm4 : $@convention(thin) (@owned FakeOptional<Builtin.NativeObject>) -> () {
1287+
bb0(%0 : @owned $FakeOptional<Builtin.NativeObject>):
1288+
%0a = alloc_stack $FakeOptional<Builtin.NativeObject>
1289+
store %0 to [init] %0a : $*FakeOptional<Builtin.NativeObject>
1290+
%1 = load [take] %0a : $*FakeOptional<Builtin.NativeObject>
1291+
%2 = copy_value %1 : $FakeOptional<Builtin.NativeObject>
1292+
apply undef(%2) : $@convention(thin) (@guaranteed FakeOptional<Builtin.NativeObject>) -> ()
1293+
switch_enum %1 : $FakeOptional<Builtin.NativeObject>, case #FakeOptional.some!enumelt: bb1, case #FakeOptional.none!enumelt: bb2
1294+
1295+
bb1(%3 : @owned $Builtin.NativeObject):
1296+
destroy_value %3 : $Builtin.NativeObject
1297+
br bb3
1298+
1299+
bb2:
1300+
br bb3
1301+
1302+
bb3:
1303+
switch_enum %2 : $FakeOptional<Builtin.NativeObject>, case #FakeOptional.some!enumelt: bb4, case #FakeOptional.none!enumelt: bb5
1304+
1305+
bb4(%4 : @owned $Builtin.NativeObject):
1306+
destroy_value %4 : $Builtin.NativeObject
1307+
br bb6
1308+
1309+
bb5:
1310+
br bb6
1311+
1312+
bb6:
1313+
dealloc_stack %0a : $*FakeOptional<Builtin.NativeObject>
1314+
%9999 = tuple()
1315+
return %9999 : $()
1316+
}
1317+
1318+
// CHECK-LABEL: sil [ossa] @dce_deadterm5 :
1319+
// CHECK: switch_enum
1320+
// CHECK-NOT: switch_enum
1321+
// CHECK-LABEL: } // end sil function 'dce_deadterm5'
1322+
sil [ossa] @dce_deadterm5 : $@convention(thin) (@owned FakeOptional<Builtin.NativeObject>) -> () {
1323+
bb0(%0 : @owned $FakeOptional<Builtin.NativeObject>):
1324+
%0a = alloc_stack $FakeOptional<Builtin.NativeObject>
1325+
store %0 to [init] %0a : $*FakeOptional<Builtin.NativeObject>
1326+
%1 = load [take] %0a : $*FakeOptional<Builtin.NativeObject>
1327+
%2 = copy_value %1 : $FakeOptional<Builtin.NativeObject>
1328+
apply undef(%2) : $@convention(thin) (@guaranteed FakeOptional<Builtin.NativeObject>) -> ()
1329+
switch_enum %1 : $FakeOptional<Builtin.NativeObject>, case #FakeOptional.some!enumelt: bb1, case #FakeOptional.none!enumelt: bb2
1330+
1331+
bb1(%3 : @owned $Builtin.NativeObject):
1332+
destroy_value %3 : $Builtin.NativeObject
1333+
br bb3
1334+
1335+
bb2:
1336+
switch_enum %2 : $FakeOptional<Builtin.NativeObject>, case #FakeOptional.some!enumelt: bb4, case #FakeOptional.none!enumelt: bb5
1337+
1338+
bb3:
1339+
destroy_value %2 : $FakeOptional<Builtin.NativeObject>
1340+
br bb6
1341+
1342+
bb4(%4 : @owned $Builtin.NativeObject):
1343+
destroy_value %4 : $Builtin.NativeObject
1344+
br bb6
1345+
1346+
bb5:
1347+
br bb6
1348+
1349+
bb6:
1350+
dealloc_stack %0a : $*FakeOptional<Builtin.NativeObject>
1351+
%9999 = tuple()
1352+
return %9999 : $()
1353+
}
1354+
1355+
// CHECK-LABEL: sil [ossa] @dce_deadforwarding :
1356+
// CHECK-NOT: cond_br
1357+
// CHECK-LABEL: } // end sil function 'dce_deadforwarding'
1358+
sil [ossa] @dce_deadforwarding : $@convention(thin) (@guaranteed Klass) -> () {
1359+
bb0(%0 : @guaranteed $Klass):
1360+
%1 = copy_value %0 : $Klass
1361+
%func = function_ref @$use_klass2 : $@convention(thin) (@guaranteed Klass) -> ()
1362+
%funcres = apply %func(%1) : $@convention(thin) (@guaranteed Klass) -> ()
1363+
cond_br undef, bb1, bb2
1364+
1365+
bb1:
1366+
%3 = struct $NonTrivialStruct(%1 : $Klass)
1367+
destroy_value %3 : $NonTrivialStruct
1368+
br bb3
1369+
1370+
bb2:
1371+
%4 = struct $NonTrivialStruct(%1 : $Klass)
1372+
destroy_value %4 : $NonTrivialStruct
1373+
br bb3
1374+
1375+
bb3:
1376+
%res = tuple ()
1377+
return %res : $()
1378+
}

0 commit comments

Comments
 (0)