Skip to content

Commit aba4e70

Browse files
Merge pull request #68111 from nate-chandler/cherrypick/release/5.9/rdar114351349
5.9: [InstructionDeleter] Don't delete-as dead instructions which produce owned move-only values.
2 parents ffda803 + ec9adc8 commit aba4e70

File tree

3 files changed

+63
-1
lines changed

3 files changed

+63
-1
lines changed

lib/SILOptimizer/UtilityPasses/UnitTestRunner.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,22 @@ struct PrintTypeLowering : UnitTest {
302302
}
303303
};
304304

305+
// Arguments:
306+
// - instruction: the instruction to delete
307+
// Dumps:
308+
// - the function
309+
struct DeleterDeleteIfDeadTest : UnitTest {
310+
DeleterDeleteIfDeadTest(UnitTestRunner *pass) : UnitTest(pass) {}
311+
void invoke(Arguments &arguments) override {
312+
auto *inst = arguments.takeInstruction();
313+
InstructionDeleter deleter;
314+
llvm::dbgs() << "Deleting-if-dead " << *inst;
315+
auto deleted = deleter.deleteIfDead(inst);
316+
llvm::dbgs() << "deleteIfDead returned " << deleted << "\n";
317+
getFunction()->dump();
318+
}
319+
};
320+
305321
//===----------------------------------------------------------------------===//
306322
// MARK: OSSA Lifetime Unit Tests
307323
//===----------------------------------------------------------------------===//
@@ -975,6 +991,7 @@ void UnitTestRunner::withTest(StringRef name, Doit doit) {
975991
ADD_UNIT_TEST_SUBCLASS("function-get-self-argument-index", FunctionGetSelfArgumentIndex)
976992
ADD_UNIT_TEST_SUBCLASS("has-pointer-escape", OwnershipUtilsHasPointerEscape)
977993
ADD_UNIT_TEST_SUBCLASS("print-type-lowering", PrintTypeLowering)
994+
ADD_UNIT_TEST_SUBCLASS("deleter-delete-if-dead", DeleterDeleteIfDeadTest)
978995
ADD_UNIT_TEST_SUBCLASS("interior-liveness", InteriorLivenessTest)
979996
ADD_UNIT_TEST_SUBCLASS("is-deinit-barrier", IsDeinitBarrierTest)
980997
ADD_UNIT_TEST_SUBCLASS("is-lexical", IsLexicalTest)

lib/SILOptimizer/Utils/InstructionDeleter.cpp

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

13+
#include "swift/SILOptimizer/Utils/InstructionDeleter.h"
1314
#include "swift/SIL/SILFunction.h"
1415
#include "swift/SILOptimizer/Utils/ConstExpr.h"
1516
#include "swift/SILOptimizer/Utils/DebugOptUtils.h"
16-
#include "swift/SILOptimizer/Utils/InstructionDeleter.h"
1717
#include "swift/SILOptimizer/Utils/InstOptUtils.h"
1818

1919
using namespace swift;
@@ -60,6 +60,21 @@ static bool isScopeAffectingInstructionDead(SILInstruction *inst,
6060
if (!hasOnlyEndOfScopeOrEndOfLifetimeUses(inst)) {
6161
return false;
6262
}
63+
64+
// If inst has any owned move-only value as a result, deleting it may shorten
65+
// that value's lifetime which is illegal according to language rules.
66+
//
67+
// In particular, this check is needed before returning true when
68+
// getSingleValueCopyOrCast returns true. That function returns true for
69+
// move_value instructions. And `move_value %moveOnlyValue` must not be
70+
// deleted.
71+
for (auto result : inst->getResults()) {
72+
if (result->getType().isPureMoveOnly() &&
73+
result->getOwnershipKind() == OwnershipKind::Owned) {
74+
return false;
75+
}
76+
}
77+
6378
// If inst is a copy or beginning of scope, inst is dead, since we know that
6479
// it is used only in a destroy_value or end-of-scope instruction.
6580
if (getSingleValueCopyOrCast(inst))
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// RUN: %target-sil-opt -unit-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)