Skip to content

Commit 5dca697

Browse files
committed
[CanonicalizeBorrowScope] Look through moves.
When encountering inside a borrow scope a non-lexical move_value or a move_value [lexical] where the borrowed value is itself already lexical, delete the move_value and regard its uses as uses of the moved-from value.
1 parent 11b76da commit 5dca697

File tree

3 files changed

+91
-2
lines changed

3 files changed

+91
-2
lines changed

lib/SILOptimizer/UtilityPasses/UnitTestRunner.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,23 @@ struct CanonicalizeOSSALifetimeTest : UnitTest {
393393
}
394394
};
395395

396+
// Arguments:
397+
// - SILValue: value to canonicalize
398+
// Dumps:
399+
// - function after value canonicalization
400+
struct CanonicalizeBorrowScopeTest : UnitTest {
401+
CanonicalizeBorrowScopeTest(UnitTestRunner *pass) : UnitTest(pass) {}
402+
void invoke(Arguments &arguments) override {
403+
auto value = arguments.takeValue();
404+
auto borrowedValue = BorrowedValue(value);
405+
assert(borrowedValue && "specified value isn't a BorrowedValue!?");
406+
InstructionDeleter deleter;
407+
CanonicalizeBorrowScope canonicalizer(deleter);
408+
canonicalizer.canonicalizeBorrowScope(borrowedValue);
409+
getFunction()->dump();
410+
}
411+
};
412+
396413
// Arguments:
397414
// - instruction
398415
// Dumps:
@@ -616,6 +633,8 @@ void UnitTestRunner::withTest(StringRef name, Doit doit) {
616633

617634
// Alphabetical mapping from string to unit test subclass.
618635
ADD_UNIT_TEST_SUBCLASS("canonicalize-ossa-lifetime", CanonicalizeOSSALifetimeTest)
636+
ADD_UNIT_TEST_SUBCLASS("canonicalize-borrow-scope",
637+
CanonicalizeBorrowScopeTest)
619638
ADD_UNIT_TEST_SUBCLASS("dump-function", DumpFunction)
620639
ADD_UNIT_TEST_SUBCLASS("find-borrow-introducers", FindBorrowIntroducers)
621640
ADD_UNIT_TEST_SUBCLASS("find-enclosing-defs", FindEnclosingDefsTest)

lib/SILOptimizer/Utils/CanonicalizeBorrowScope.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -224,21 +224,32 @@ bool CanonicalizeBorrowScope::visitBorrowScopeUses(SILValue innerValue,
224224
// Gather the uses before updating any of them.
225225
// 'value' may be deleted in this loop after rewriting its last use.
226226
// 'use' may become invalid after processing its user.
227+
227228
SmallVector<Operand *, 4> uses(value->getUses());
228-
for (Operand *use : uses) {
229+
for (auto index = 0; index < uses.size(); ++index) {
230+
auto *use = uses[index];
229231
auto *user = use->getUser();
230232
// Incidental uses, such as debug_value may be deleted before they can be
231233
// processed. Their user will now be nullptr. This means that value
232234
// is dead, so just bail.
233235
if (!user)
234236
break;
235237

236-
// Recurse through copies.
238+
// Recurse through copies and moves.
237239
if (auto *copy = dyn_cast<CopyValueInst>(user)) {
238240
if (!isPersistentCopy(copy)) {
239241
defUseWorklist.insert(copy);
240242
continue;
241243
}
244+
} else if (auto *move = dyn_cast<MoveValueInst>(user)) {
245+
if (!move->isLexical() || innerValue->isLexical()) {
246+
for (auto *moveUse : move->getUses()) {
247+
uses.push_back(moveUse);
248+
}
249+
move->replaceAllUsesWith(move->getOperand());
250+
deleter.forceDelete(move);
251+
continue;
252+
}
242253
}
243254
// Note: debug_value uses are handled like normal uses here. If they are
244255
// inner uses, they remain. If they are outer uses, then they will be
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// RUN: %target-sil-opt -unit-test-runner %s -o /dev/null 2>&1 | %FileCheck %s
2+
3+
import Builtin
4+
5+
typealias AnyObject = Builtin.AnyObject
6+
7+
struct Unmanaged<Instance> where Instance : AnyObject {
8+
unowned(unsafe) var _value: @sil_unmanaged Instance
9+
}
10+
11+
// CHECK-LABEL: begin {{.*}} on copy_and_move_argument: canonicalize-borrow-scope
12+
// CHECK-LABEL: sil [ossa] @copy_and_move_argument : {{.*}} {
13+
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] :
14+
// CHECK: [[UNMANAGED:%[^,]+]] = ref_to_unmanaged [[INSTANCE]]
15+
// CHECK: [[RETVAL:%[^,]+]] = struct $Unmanaged<Instance> ([[UNMANAGED]] : $@sil_unmanaged Instance)
16+
// CHECK: return [[RETVAL]]
17+
// CHECK-LABEL: } // end sil function 'copy_and_move_argument'
18+
// CHECK-LABEL: end {{.*}} on copy_and_move_argument: canonicalize-borrow-scope
19+
sil [ossa] @copy_and_move_argument : $@convention(thin) <Instance where Instance : AnyObject> (@guaranteed Instance) -> Unmanaged<Instance> {
20+
bb0(%instance : @guaranteed $Instance):
21+
test_specification "canonicalize-borrow-scope @argument"
22+
%copy_1 = copy_value %instance : $Instance
23+
%copy_2 = copy_value %copy_1 : $Instance
24+
%move = move_value %copy_2 : $Instance
25+
%copy_3 = copy_value %move : $Instance
26+
%copy_4 = copy_value %copy_3 : $Instance
27+
%unmanaged = ref_to_unmanaged %copy_4 : $Instance to $@sil_unmanaged Instance
28+
destroy_value %copy_4 : $Instance
29+
destroy_value %copy_3 : $Instance
30+
destroy_value %move : $Instance
31+
destroy_value %copy_1 : $Instance
32+
%retval = struct $Unmanaged<Instance> (%unmanaged : $@sil_unmanaged Instance)
33+
return %retval : $Unmanaged<Instance>
34+
}
35+
36+
// CHECK-LABEL: begin {{.*}} on copy_and_move_lexical_argument: canonicalize-borrow-scope
37+
// CHECK-LABEL: sil [ossa] @copy_and_move_lexical_argument : {{.*}} {
38+
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] :
39+
// CHECK: [[UNMANAGED:%[^,]+]] = ref_to_unmanaged [[INSTANCE]]
40+
// CHECK: [[RETVAL:%[^,]+]] = struct $Unmanaged<Instance> ([[UNMANAGED]] : $@sil_unmanaged Instance)
41+
// CHECK: return [[RETVAL]]
42+
// CHECK-LABEL: } // end sil function 'copy_and_move_lexical_argument'
43+
// CHECK-LABEL: end {{.*}} on copy_and_move_lexical_argument: canonicalize-borrow-scope
44+
sil [ossa] @copy_and_move_lexical_argument : $@convention(thin) <Instance where Instance : AnyObject> (@guaranteed Instance) -> Unmanaged<Instance> {
45+
bb0(%instance : @guaranteed $Instance):
46+
test_specification "canonicalize-borrow-scope @argument"
47+
%copy_1 = copy_value %instance : $Instance
48+
%copy_2 = copy_value %copy_1 : $Instance
49+
%move = move_value [lexical] %copy_2 : $Instance
50+
%copy_3 = copy_value %move : $Instance
51+
%copy_4 = copy_value %copy_3 : $Instance
52+
%unmanaged = ref_to_unmanaged %copy_4 : $Instance to $@sil_unmanaged Instance
53+
destroy_value %copy_4 : $Instance
54+
destroy_value %copy_3 : $Instance
55+
destroy_value %move : $Instance
56+
destroy_value %copy_1 : $Instance
57+
%retval = struct $Unmanaged<Instance> (%unmanaged : $@sil_unmanaged Instance)
58+
return %retval : $Unmanaged<Instance>
59+
}

0 commit comments

Comments
 (0)