Skip to content

Commit bfd11fb

Browse files
committed
Merge remote-tracking branch 'origin/main' into rebranch
2 parents cd68190 + 3687ddf commit bfd11fb

File tree

4 files changed

+91
-2
lines changed

4 files changed

+91
-2
lines changed

lib/SILOptimizer/Transforms/CopyPropagation.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -617,7 +617,9 @@ void CopyPropagation::run() {
617617
// Canonicalize all owned defs.
618618
while (!defWorklist.ownedValues.empty()) {
619619
SILValue def = defWorklist.ownedValues.pop_back_val();
620-
canonicalizer.canonicalizeValueLifetime(def);
620+
auto canonicalized = canonicalizer.canonicalizeValueLifetime(def);
621+
if (!canonicalized)
622+
continue;
621623
// Copies of borrowed values may be dead.
622624
if (auto *inst = def->getDefiningInstruction())
623625
deleter.trackIfDead(inst);

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 =

test/SILOptimizer/copy_propagation.sil

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ class C {
1616
var a: Builtin.Int64
1717
}
1818

19+
struct MOS : ~Copyable {
20+
deinit {}
21+
}
22+
1923
sil [ossa] @dummy : $@convention(thin) () -> ()
2024
sil [ossa] @barrier : $@convention(thin) () -> ()
2125
sil [ossa] @getOwnedC : $@convention(thin) () -> (@owned C)
@@ -26,6 +30,7 @@ sil [ossa] @takeOwnedCAndGuaranteedC : $@convention(thin) (@owned C, @guaranteed
2630
sil [ossa] @takeGuaranteedC : $@convention(thin) (@guaranteed C) -> ()
2731
sil [ossa] @borrowB : $@convention(thin) (@guaranteed B) -> ()
2832
sil [ossa] @takeGuaranteedAnyObject : $@convention(thin) (@guaranteed AnyObject) -> ()
33+
sil [ossa] @getMOS : $() -> (@owned MOS)
2934

3035
// -O hoists the destroy
3136
//
@@ -1047,3 +1052,23 @@ entry(%instance : @owned $C):
10471052
%retval = tuple ()
10481053
return %retval : $()
10491054
}
1055+
1056+
// CHECK-LABEL: sil [ossa] @dontShortenDeadMoveOnlyLifetime : {{.*}} {
1057+
// CHECK: [[GET:%[^,]+]] = function_ref @getMOS
1058+
// CHECK: [[BARRIER:%[^,]+]] = function_ref @barrier
1059+
// CHECK: [[MOS:%[^,]+]] = apply [[GET]]()
1060+
// CHECK: [[MOV:%[^,]+]] = move_value [lexical] [[MOS]]
1061+
// CHECK: apply [[BARRIER]]()
1062+
// CHECK: destroy_value [[MOV]]
1063+
// CHECK-LABEL: } // end sil function 'dontShortenDeadMoveOnlyLifetime'
1064+
sil [ossa] @dontShortenDeadMoveOnlyLifetime : $@convention(thin) () -> () {
1065+
%get = function_ref @getMOS : $@convention(thin) () -> (@owned MOS)
1066+
%barrier = function_ref @barrier : $@convention(thin) () -> ()
1067+
%mos = apply %get() : $@convention(thin) () -> (@owned MOS)
1068+
// Note: This must be lexical so that it doesn't get eliminated as redundant.
1069+
%mov = move_value [lexical] %mos : $MOS
1070+
apply %barrier() : $@convention(thin) () -> ()
1071+
destroy_value %mov : $MOS
1072+
%retval = tuple ()
1073+
return %retval : $()
1074+
}
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)