Skip to content

Commit 9f0f1da

Browse files
committed
[6.2] Fix InstructionDeleter for drop_deinit instruction
Currently we delete dead drop_deinit instructions in InstructionDeleter. For address results, we may end up with ownership errors after being promoted to value forms. For value results, fixLifetimes mode of InstructionDeleter will insert an illegal destroy_value rdar://151104993
1 parent 431aeca commit 9f0f1da

File tree

2 files changed

+63
-3
lines changed

2 files changed

+63
-3
lines changed

lib/SILOptimizer/Utils/InstructionDeleter.cpp

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@ static bool isScopeAffectingInstructionDead(SILInstruction *inst,
6363
return false;
6464
}
6565

66+
// Don't delete dead drop_deinit instruction. They are a marker to eliminate
67+
// user-defined deinit and we do not want to lose it.
68+
if (isa<DropDeinitInst>(inst)) {
69+
return false;
70+
}
71+
6672
for (auto result : inst->getResults()) {
6773
// If inst has any owned move-only value as a result, deleting it may
6874
// shorten that value's lifetime which is illegal according to language
@@ -268,9 +274,16 @@ void InstructionDeleter::deleteWithUses(SILInstruction *inst, bool fixLifetimes,
268274
if (fixLifetimes) {
269275
LoadInst *li = nullptr;
270276
if (operand.isConsuming()) {
271-
SILBuilderWithScope builder(inst);
272-
auto *dvi = builder.createDestroyValue(inst->getLoc(), operandValue);
273-
getCallbacks().createdNewInst(dvi);
277+
if (isa<DropDeinitInst>(operandValue)) {
278+
SILBuilderWithScope builder(inst);
279+
auto *eli = builder.createEndLifetime(inst->getLoc(), operandValue);
280+
getCallbacks().createdNewInst(eli);
281+
} else {
282+
SILBuilderWithScope builder(inst);
283+
auto *dvi =
284+
builder.createDestroyValue(inst->getLoc(), operandValue);
285+
getCallbacks().createdNewInst(dvi);
286+
}
274287
} else if ((li = dyn_cast<LoadInst>(inst)) &&
275288
li->getOwnershipQualifier() ==
276289
LoadOwnershipQualifier::Take) {

test/SILOptimizer/drop_deinit_opt.sil

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// RUN: %target-sil-opt %s -early-inline -mem2reg | %FileCheck %s
2+
3+
import Swift
4+
import Builtin
5+
6+
struct FileDescriptor : ~Copyable {
7+
@_hasStorage private var fd: Int { get set }
8+
init(_ fd: Int)
9+
deinit
10+
}
11+
12+
sil hidden [ossa] @fd_close : $@convention(thin) (Int) -> () {
13+
bb0(%0 : $Int):
14+
debug_value %0, let, name "fd", argno 1
15+
%2 = tuple ()
16+
return %2
17+
}
18+
19+
// CHECK-LABEL: sil hidden [ossa] @fd_deinit1 :
20+
// CHECK: drop_deinit
21+
// CHECK-LABEL: } // end sil function 'fd_deinit1'
22+
sil hidden [ossa] @fd_deinit1 : $@convention(method) (@owned FileDescriptor) -> () {
23+
bb0(%0 : @owned $FileDescriptor):
24+
%1 = alloc_stack $FileDescriptor, let, name "self", argno 1
25+
store %0 to [init] %1
26+
%3 = drop_deinit %1
27+
%6 = struct_element_addr %3, #FileDescriptor.fd
28+
%7 = load [trivial] %6
29+
%9 = function_ref @fd_close : $@convention(thin) (Int) -> ()
30+
%10 = apply %9(%7) : $@convention(thin) (Int) -> ()
31+
dealloc_stack %1
32+
%12 = tuple ()
33+
return %12
34+
}
35+
36+
// CHECK-LABEL: sil hidden [ossa] @fd_deinit2 :
37+
// CHECK: end_lifetime
38+
// CHECK-LABEL: } // end sil function 'fd_deinit2'
39+
sil hidden [ossa] @fd_deinit2 : $@convention(method) (@owned FileDescriptor) -> () {
40+
bb0(%0 : @owned $FileDescriptor):
41+
%3 = drop_deinit %0
42+
%6 = destructure_struct %3
43+
%9 = function_ref @fd_close : $@convention(thin) (Int) -> ()
44+
%10 = apply %9(%6) : $@convention(thin) (Int) -> ()
45+
%12 = tuple ()
46+
return %12
47+
}

0 commit comments

Comments
 (0)