Skip to content

Commit 1463911

Browse files
committed
[OSSACanonicalizeGuaranteed] Don't copy MO values.
When visiting a consuming use of a move-only value (which can be produced by a forwarding operation), the inner rewriter must bail out. Otherwise, it would produce a copy of that move-only value. rdar://142520491
1 parent fdf04a3 commit 1463911

File tree

2 files changed

+99
-0
lines changed

2 files changed

+99
-0
lines changed

lib/SILOptimizer/Utils/CanonicalizeBorrowScope.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,10 @@ class RewriteInnerBorrowUses {
445445
}
446446
SILValue def = scope.findDefInBorrowScope(value);
447447
if (use->isConsuming()) {
448+
if (use->get()->getType().isMoveOnly()) {
449+
// Can't produce a copy of a non-copyable value on demand. Bail out.
450+
return false;
451+
}
448452
// All in-scope consuming uses need a unique copy in the same block.
449453
auto *copy = dyn_cast<CopyValueInst>(use->get());
450454
if (copy && copy->hasOneUse() && copy->getParent() == user->getParent()) {
@@ -823,6 +827,22 @@ bool CanonicalizeBorrowScope::canonicalizeFunctionArgument(
823827
return visitBorrowScopeUses(borrowedValue.value, innerRewriter);
824828
}
825829

830+
namespace swift::test {
831+
// Arguments:
832+
// - SILFunctionArgument: function argument to canonicalize
833+
// Dumps:
834+
// - function after argument canonicalization
835+
static FunctionTest CanonicalizeFunctionArgumentTest(
836+
"canonicalize_function_argument",
837+
[](auto &function, auto &arguments, auto &test) {
838+
auto *argument = cast<SILFunctionArgument>(arguments.takeBlockArgument());
839+
InstructionDeleter deleter;
840+
CanonicalizeBorrowScope canonicalizer(&function, deleter);
841+
canonicalizer.canonicalizeFunctionArgument(argument);
842+
function.print(llvm::outs());
843+
});
844+
} // end namespace swift::test
845+
826846
/// Canonicalize a worklist of extended lifetimes. This iterates after rewriting
827847
/// borrow scopes to handle new outer copies and new owned lifetimes from
828848
/// forwarding operations.
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// RUN: %target-sil-opt \
2+
// RUN: -test-runner \
3+
// RUN: -module-name Swift \
4+
// RUN: %s \
5+
// RUN: -o /dev/null \
6+
// RUN: 2>&1 | %FileCheck %s
7+
8+
import Builtin
9+
10+
@_marker protocol Copyable {}
11+
12+
class C {}
13+
struct NC : ~Copyable {
14+
var c: C
15+
}
16+
17+
// CHECK-LABEL: begin running test {{.*}} on consume_move_only
18+
// CHECK-LABEL: sil [ossa] @consume_move_only : {{.*}} {
19+
// CHECK: bb0([[C:%[^,]+]] :
20+
// Necessary copy.
21+
// CHECK: [[COPY:%[^,]+]] = copy_value [[C]]
22+
// CHECK: [[NC:%[^,]+]] = struct $NC ([[COPY]]
23+
// CHECK: apply undef([[NC]])
24+
// CHECK-LABEL: } // end sil function 'consume_move_only'
25+
// CHECK-LABEL: end running test {{.*}} on consume_move_only
26+
sil [ossa] @consume_move_only : $@convention(thin) (@guaranteed C) -> () {
27+
bb0(%c : @guaranteed $C):
28+
specify_test "canonicalize_function_argument @argument"
29+
%copy = copy_value %c
30+
%nc = struct $NC (%copy)
31+
apply undef(%nc) : $@convention(thin) (@owned NC) -> ()
32+
%retval = tuple ()
33+
return %retval
34+
}
35+
36+
// CHECK-LABEL: begin running test {{.*}} on borrow_move_only
37+
// CHECK-LABEL: sil [ossa] @borrow_move_only : {{.*}} {
38+
// CHECK: bb0([[C:%[^,]+]] :
39+
// No copy!
40+
// CHECK: [[NC:%[^,]+]] = struct $NC ([[C]]
41+
// CHECK: apply undef([[NC]])
42+
// CHECK-LABEL: } // end sil function 'borrow_move_only'
43+
// CHECK-LABEL: end running test {{.*}} on borrow_move_only
44+
sil [ossa] @borrow_move_only : $@convention(thin) (@guaranteed C) -> () {
45+
bb0(%c : @guaranteed $C):
46+
specify_test "canonicalize_function_argument @argument"
47+
%copy = copy_value %c
48+
%nc = struct $NC (%copy)
49+
apply undef(%nc) : $@convention(thin) (@guaranteed NC) -> ()
50+
destroy_value %nc
51+
%retval = tuple ()
52+
return %retval
53+
}
54+
55+
// CHECK-LABEL: begin running test {{.*}} on consume_and_borrow_move_only
56+
// CHECK-LABEL: sil [ossa] @consume_and_borrow_move_only : {{.*}} {
57+
// CHECK: bb0([[C:%[^,]+]] :
58+
// No copy!
59+
// CHECK: [[NC1:%[^,]+]] = struct $NC ([[C]]
60+
// CHECK: apply undef([[NC1]])
61+
// Necessary copy.
62+
// CHECK: [[COPY2:%[^,]+]] = copy_value [[C]]
63+
// CHECK: [[NC2:%[^,]+]] = struct $NC ([[COPY2]]
64+
// CHECK: apply undef([[NC2]])
65+
// CHECK-LABEL: } // end sil function 'consume_and_borrow_move_only'
66+
// CHECK-LABEL: end running test {{.*}} on consume_and_borrow_move_only
67+
sil [ossa] @consume_and_borrow_move_only : $@convention(thin) (@guaranteed C) -> () {
68+
bb0(%c : @guaranteed $C):
69+
specify_test "canonicalize_function_argument @argument"
70+
%copy1 = copy_value %c
71+
%nc1 = struct $NC (%copy1)
72+
apply undef(%nc1) : $@convention(thin) (@guaranteed NC) -> ()
73+
destroy_value %nc1
74+
%copy2 = copy_value %c
75+
%nc2 = struct $NC (%copy2)
76+
apply undef(%nc2) : $@convention(thin) (@owned NC) -> ()
77+
%retval = tuple ()
78+
return %retval
79+
}

0 commit comments

Comments
 (0)