Skip to content

Commit e987c92

Browse files
authored
Merge pull request #85855 from eeckstein/fix-silcombine
DeadCodeElimination,SILCombine: don't insert destroys for removed values in dead-end blocks
2 parents 4419ce5 + c0017a2 commit e987c92

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
@@ -203,6 +203,7 @@ class DCE {
203203

204204
void markValueLive(SILValue V);
205205
void markInstructionLive(SILInstruction *Inst);
206+
void markOwnedDeadValueLive(SILValue v);
206207
void markTerminatorArgsLive(SILBasicBlock *Pred, SILBasicBlock *Succ,
207208
size_t ArgIndex);
208209
void markControllingTerminatorsLive(SILBasicBlock *Block);
@@ -265,6 +266,20 @@ void DCE::markInstructionLive(SILInstruction *Inst) {
265266
Worklist.push_back(Inst);
266267
}
267268

269+
void DCE::markOwnedDeadValueLive(SILValue v) {
270+
if (v->getOwnershipKind() == OwnershipKind::Owned) {
271+
// When an owned value has no lifetime ending uses it means that it is in a
272+
// dead-end region. We must not remove and inserting compensating destroys
273+
// for it because that would potentially destroy the value too early.
274+
// TODO: we can remove this once we have complete OSSA lifetimes
275+
for (Operand *use : v->getUses()) {
276+
if (use->isLifetimeEnding())
277+
return;
278+
}
279+
markValueLive(v);
280+
}
281+
}
282+
268283
/// Gets the producing instruction of a cond_fail condition. Currently these
269284
/// are overflow builtins but may be extended to other instructions in the
270285
/// future.
@@ -331,6 +346,9 @@ void DCE::markLive() {
331346
// to be live in the sense that they are not trivially something we
332347
// can delete by examining only that instruction.
333348
for (auto &BB : *F) {
349+
for (SILArgument *arg : BB.getArguments()) {
350+
markOwnedDeadValueLive(arg);
351+
}
334352
for (auto &I : BB) {
335353
switch (I.getKind()) {
336354
case SILInstructionKind::CondFailInst: {
@@ -395,6 +413,9 @@ void DCE::markLive() {
395413
default:
396414
if (seemsUseful(&I))
397415
markInstructionLive(&I);
416+
for (SILValue result : I.getResults()) {
417+
markOwnedDeadValueLive(result);
418+
}
398419
}
399420
}
400421
}

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) () -> ()
@@ -534,3 +535,32 @@ bb2:
534535
%17 = tuple ()
535536
return %17
536537
}
538+
539+
// CHECK-LABEL: sil [ossa] @dont_insert_destroy_for_uninitialized_object :
540+
// CHECK-NOT: destroy_value
541+
// CHECK-LABEL: } // end sil function 'dont_insert_destroy_for_uninitialized_object'
542+
sil [ossa] @dont_insert_destroy_for_uninitialized_object : $@convention(thin) () -> () {
543+
bb0:
544+
%0 = alloc_ref $D // D might not be initialized due to dead-end loop -> will lead to crash if it is destroyed here
545+
%1 = upcast %0 to $C
546+
br bb1
547+
548+
bb1:
549+
br bb1
550+
}
551+
552+
// CHECK-LABEL: sil [ossa] @dont_insert_arg_destroy_for_uninitialized_object :
553+
// CHECK-NOT: destroy_value
554+
// CHECK-LABEL: } // end sil function 'dont_insert_arg_destroy_for_uninitialized_object'
555+
sil [ossa] @dont_insert_arg_destroy_for_uninitialized_object : $@convention(thin) () -> () {
556+
bb0:
557+
%0 = alloc_ref $D // D might not be initialized due to dead-end loop -> will lead to crash if it is destroyed here
558+
br bb1(%0)
559+
560+
bb1(%2 : @owned $D):
561+
br bb2
562+
563+
bb2:
564+
br bb2
565+
}
566+
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)