Skip to content

Commit 073f4e2

Browse files
committed
[InstDeleter] Keep dead owned move-only values.
Deleting instructions which produce such values could result in shortening the lifetime of a move-only value. This is illegal because according to language rules, the lifetime of move-only values is fixed. rdar://114351349
1 parent 056b494 commit 073f4e2

File tree

2 files changed

+63
-1
lines changed

2 files changed

+63
-1
lines changed

lib/SILOptimizer/Utils/InstructionDeleter.cpp

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13+
#include "swift/SILOptimizer/Utils/InstructionDeleter.h"
1314
#include "swift/SIL/SILFunction.h"
15+
#include "swift/SIL/Test.h"
1416
#include "swift/SILOptimizer/Utils/ConstExpr.h"
1517
#include "swift/SILOptimizer/Utils/DebugOptUtils.h"
16-
#include "swift/SILOptimizer/Utils/InstructionDeleter.h"
1718
#include "swift/SILOptimizer/Utils/InstOptUtils.h"
1819

1920
using namespace swift;
@@ -60,6 +61,21 @@ static bool isScopeAffectingInstructionDead(SILInstruction *inst,
6061
if (!hasOnlyEndOfScopeOrEndOfLifetimeUses(inst)) {
6162
return false;
6263
}
64+
65+
// If inst has any owned move-only value as a result, deleting it may shorten
66+
// that value's lifetime which is illegal according to language rules.
67+
//
68+
// In particular, this check is needed before returning true when
69+
// getSingleValueCopyOrCast returns true. That function returns true for
70+
// move_value instructions. And `move_value %moveOnlyValue` must not be
71+
// deleted.
72+
for (auto result : inst->getResults()) {
73+
if (result->getType().isPureMoveOnly() &&
74+
result->getOwnershipKind() == OwnershipKind::Owned) {
75+
return false;
76+
}
77+
}
78+
6379
// If inst is a copy or beginning of scope, inst is dead, since we know that
6480
// it is used only in a destroy_value or end-of-scope instruction.
6581
if (getSingleValueCopyOrCast(inst))
@@ -289,6 +305,22 @@ bool InstructionDeleter::deleteIfDead(SILInstruction *inst, bool fixLifetime) {
289305
return false;
290306
}
291307

308+
namespace swift::test {
309+
// Arguments:
310+
// - instruction: the instruction to delete
311+
// Dumps:
312+
// - the function
313+
static FunctionTest DeleterDeleteIfDeadTest(
314+
"deleter-delete-if-dead", [](auto &function, auto &arguments, auto &test) {
315+
auto *inst = arguments.takeInstruction();
316+
InstructionDeleter deleter;
317+
llvm::dbgs() << "Deleting-if-dead " << *inst;
318+
auto deleted = deleter.deleteIfDead(inst);
319+
llvm::dbgs() << "deleteIfDead returned " << deleted << "\n";
320+
function.dump();
321+
});
322+
} // namespace swift::test
323+
292324
void InstructionDeleter::forceDeleteAndFixLifetimes(SILInstruction *inst) {
293325
SILFunction *fun = inst->getFunction();
294326
bool preserveDebugInfo =
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// RUN: %target-sil-opt -test-runner %s -o /dev/null 2>&1 | %FileCheck %s
2+
3+
struct MOS : ~Copyable {}
4+
5+
sil @getMOS : $() -> (@owned MOS)
6+
sil @barrier : $() -> ()
7+
8+
// CHECK-LABEL: begin running test {{.*}} on dontDeleteDeadMoveOnlyValue
9+
// CHECK: Deleting-if-dead {{.*}} move_value
10+
// CHECK: deleteIfDead returned 0
11+
// CHECK-LABEL: sil [ossa] @dontDeleteDeadMoveOnlyValue : {{.*}} {
12+
// CHECK: [[GET:%[^,]+]] = function_ref @getMOS
13+
// CHECK: [[BARRIER:%[^,]+]] = function_ref @barrier
14+
// CHECK: [[MOS:%[^,]+]] = apply [[GET]]()
15+
// CHECK: [[MOV:%[^,]+]] = move_value [[MOS]]
16+
// CHECK: apply [[BARRIER]]()
17+
// CHECK: destroy_value [[MOV]]
18+
// CHECK-LABEL: } // end sil function 'dontDeleteDeadMoveOnlyValue'
19+
// CHECK-LABEL: end running test {{.*}} on dontDeleteDeadMoveOnlyValue
20+
sil [ossa] @dontDeleteDeadMoveOnlyValue : $() -> () {
21+
%get = function_ref @getMOS : $@convention(thin) () -> (@owned MOS)
22+
%barrier = function_ref @barrier : $@convention(thin) () -> ()
23+
%mos = apply %get() : $@convention(thin) () -> (@owned MOS)
24+
test_specification "deleter-delete-if-dead @instruction"
25+
%mov = move_value %mos : $MOS
26+
apply %barrier() : $@convention(thin) () -> ()
27+
destroy_value %mov : $MOS
28+
%retval = tuple ()
29+
return %retval : $()
30+
}

0 commit comments

Comments
 (0)