Skip to content

Commit daa9b16

Browse files
committed
Fix DCE for ownership forwarding instructions
DCE deletes ownership forwarding instructions when it doesn’t have useful users. It inserts destroy_value/end_borrow for its operands to compensate their lifetimes. DCE also deletes branches when its successor blocks does not have useful instructions. It deletes blocks and creates a jump to the nearest post dominating block. When DCE needs to delete a forwarding instruction in a dead block, it cannot just create lifetime ends of its operands at its position. Use LifetimeCompletion utility in such cases. rdar://140428721
1 parent adf1eae commit daa9b16

File tree

2 files changed

+112
-0
lines changed

2 files changed

+112
-0
lines changed

lib/SILOptimizer/Transforms/DeadCodeElimination.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
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"
2627
#include "swift/SILOptimizer/Analysis/DeadEndBlocksAnalysis.h"
2728
#include "swift/SILOptimizer/PassManager/Passes.h"
@@ -130,6 +131,7 @@ class DCE {
130131
DominanceInfo *DT;
131132
DeadEndBlocks *deadEndBlocks;
132133
llvm::DenseMap<SILBasicBlock *, ControllingInfo> ControllingInfoMap;
134+
llvm::SmallVector<SILValue> valuesToComplete;
133135

134136
// Maps instructions which produce a failing condition (like overflow
135137
// builtins) to the actual cond_fail instructions which handle the failure.
@@ -631,6 +633,14 @@ void DCE::endLifetimeOfLiveValue(Operand *op, SILInstruction *insertPt) {
631633
}
632634

633635
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+
634644
SILBuilderWithScope builder(insertPt);
635645
if (value->getOwnershipKind() == OwnershipKind::Owned) {
636646
builder.createDestroyValue(RegularLocation::getAutoGeneratedLocation(),
@@ -777,6 +787,12 @@ bool DCE::removeDead() {
777787
}
778788
}
779789

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

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)