Skip to content

Commit c220020

Browse files
authored
Merge pull request #85944 from eeckstein/fix-silcombine-6.3
[6.3] DeadCodeElimination,SILCombine: don't insert destroys for removed values in dead-end blocks
2 parents 1e2afbe + 1897745 commit c220020

File tree

5 files changed

+105
-8
lines changed

5 files changed

+105
-8
lines changed

lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1561,14 +1561,6 @@ SILInstruction *SILCombiner::legacyVisitApplyInst(ApplyInst *AI) {
15611561
}
15621562

15631563
if (SF) {
1564-
if (SF->hasSemanticsAttr(semantics::ARRAY_UNINITIALIZED)) {
1565-
UserListTy Users;
1566-
// If the uninitialized array is only written into then it can be removed.
1567-
if (recursivelyCollectARCUsers(Users, AI)) {
1568-
if (eraseApply(AI, Users))
1569-
return nullptr;
1570-
}
1571-
}
15721564
if (SF->hasSemanticsAttr(semantics::ARRAY_GET_CONTIGUOUSARRAYSTORAGETYPE)) {
15731565
auto silTy = AI->getType();
15741566
auto storageTy = AI->getType().getASTType();

lib/SILOptimizer/Transforms/DeadCodeElimination.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ class DCE {
206206

207207
void markValueLive(SILValue V);
208208
void markInstructionLive(SILInstruction *Inst);
209+
void markOwnedDeadValueLive(SILValue v);
209210
void markTerminatorArgsLive(SILBasicBlock *Pred, SILBasicBlock *Succ,
210211
size_t ArgIndex);
211212
void markControllingTerminatorsLive(SILBasicBlock *Block);
@@ -268,6 +269,20 @@ void DCE::markInstructionLive(SILInstruction *Inst) {
268269
Worklist.push_back(Inst);
269270
}
270271

272+
void DCE::markOwnedDeadValueLive(SILValue v) {
273+
if (v->getOwnershipKind() == OwnershipKind::Owned) {
274+
// When an owned value has no lifetime ending uses it means that it is in a
275+
// dead-end region. We must not remove and inserting compensating destroys
276+
// for it because that would potentially destroy the value too early.
277+
// TODO: we can remove this once we have complete OSSA lifetimes
278+
for (Operand *use : v->getUses()) {
279+
if (use->isLifetimeEnding())
280+
return;
281+
}
282+
markValueLive(v);
283+
}
284+
}
285+
271286
/// Gets the producing instruction of a cond_fail condition. Currently these
272287
/// are overflow builtins but may be extended to other instructions in the
273288
/// future.
@@ -334,6 +349,9 @@ void DCE::markLive() {
334349
// to be live in the sense that they are not trivially something we
335350
// can delete by examining only that instruction.
336351
for (auto &BB : *F) {
352+
for (SILArgument *arg : BB.getArguments()) {
353+
markOwnedDeadValueLive(arg);
354+
}
337355
for (auto &I : BB) {
338356
switch (I.getKind()) {
339357
case SILInstructionKind::CondFailInst: {
@@ -414,6 +432,9 @@ void DCE::markLive() {
414432
default:
415433
if (seemsUseful(&I))
416434
markInstructionLive(&I);
435+
for (SILValue result : I.getResults()) {
436+
markOwnedDeadValueLive(result);
437+
}
417438
}
418439
}
419440
}

test/SILOptimizer/dead_code_elimination_ossa.sil

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ public struct S {
1212
typealias Int1 = Builtin.Int1
1313

1414
class C {}
15+
class D: C {}
1516

1617
sil @getC : $@convention(thin) () -> @owned C
1718
sil @barrier : $@convention(thin) () -> ()
@@ -538,3 +539,32 @@ bb2:
538539
%17 = tuple ()
539540
return %17
540541
}
542+
543+
// CHECK-LABEL: sil [ossa] @dont_insert_destroy_for_uninitialized_object :
544+
// CHECK-NOT: destroy_value
545+
// CHECK-LABEL: } // end sil function 'dont_insert_destroy_for_uninitialized_object'
546+
sil [ossa] @dont_insert_destroy_for_uninitialized_object : $@convention(thin) () -> () {
547+
bb0:
548+
%0 = alloc_ref $D // D might not be initialized due to dead-end loop -> will lead to crash if it is destroyed here
549+
%1 = upcast %0 to $C
550+
br bb1
551+
552+
bb1:
553+
br bb1
554+
}
555+
556+
// CHECK-LABEL: sil [ossa] @dont_insert_arg_destroy_for_uninitialized_object :
557+
// CHECK-NOT: destroy_value
558+
// CHECK-LABEL: } // end sil function 'dont_insert_arg_destroy_for_uninitialized_object'
559+
sil [ossa] @dont_insert_arg_destroy_for_uninitialized_object : $@convention(thin) () -> () {
560+
bb0:
561+
%0 = alloc_ref $D // D might not be initialized due to dead-end loop -> will lead to crash if it is destroyed here
562+
br bb1(%0)
563+
564+
bb1(%2 : @owned $D):
565+
br bb2
566+
567+
bb2:
568+
br bb2
569+
}
570+
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// RUN: %target-run-simple-swift(-O -Xllvm -sil-disable-pass=deadobject-elim) | %FileCheck %s
2+
3+
// REQUIRES: executable_test
4+
5+
#if canImport(Darwin)
6+
import Darwin
7+
#elseif canImport(Glibc)
8+
import Glibc
9+
#elseif os(WASI)
10+
import WASILibc
11+
#elseif canImport(Android)
12+
import Android
13+
#elseif os(Windows)
14+
import CRT
15+
#else
16+
#error("Unsupported platform")
17+
#endif
18+
19+
@inline(never)
20+
public func hiddenExit() {
21+
// CHECK: okay
22+
print("okay")
23+
exit(0)
24+
}
25+
26+
func foo() -> Never {
27+
while true {
28+
hiddenExit()
29+
}
30+
}
31+
32+
func bar(_ x: Any...) {
33+
}
34+
35+
bar(foo())

test/SILOptimizer/sil_combine_apply.sil

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1037,3 +1037,22 @@ bb3:
10371037
%rv = tuple()
10381038
return %rv : $()
10391039
}
1040+
1041+
1042+
sil [_semantics "array.uninitialized"] [ossa] @adoptStorage : $@convention(thin) (@owned _ContiguousArrayStorage<Any>, Int) -> (@owned Array<Any>, UnsafeMutablePointer<Any>)
1043+
1044+
// CHECK-LABEL: sil [ossa] @dont_remove_dead_adopt_storage :
1045+
// CHECK-NOT: destroy_value
1046+
// CHECK-LABEL: } // end sil function 'dont_remove_dead_adopt_storage'
1047+
sil [ossa] @dont_remove_dead_adopt_storage : $@convention(thin) (Int) -> () {
1048+
bb0(%0 : $Int):
1049+
%1 = integer_literal $Builtin.Word, 1
1050+
%2 = alloc_ref [tail_elems $Any * %1] $_ContiguousArrayStorage<Any>
1051+
%3 = function_ref @adoptStorage : $@convention(thin) (@owned _ContiguousArrayStorage<Any>, Int) -> (@owned Array<Any>, UnsafeMutablePointer<Any>)
1052+
%4 = apply %3(%2, %0) : $@convention(thin) (@owned _ContiguousArrayStorage<Any>, Int) -> (@owned Array<Any>, UnsafeMutablePointer<Any>)
1053+
// Array buffer is not initialized due to dead-end loop -> will lead to crash if buffer is destroyed here
1054+
br bb1
1055+
bb1:
1056+
br bb1
1057+
}
1058+

0 commit comments

Comments
 (0)