@@ -96,29 +96,29 @@ bool CanonicalizeBorrowScope::isRewritableOSSAForward(SILInstruction *inst) {
96
96
if (inst->getNumOperands () != 1 )
97
97
return false ;
98
98
99
- if (isa<OwnershipForwardingSingleValueInstruction>(inst) ||
100
- isa<OwnershipForwardingMultipleValueInstruction>(inst)) {
101
- Operand *forwardedOper = &inst->getOperandRef (0 );
102
- // Trivial conversions do not need to be hoisted out of a borrow scope.
103
- auto operOwnership = forwardedOper->getOperandOwnership ();
104
- if (operOwnership == OperandOwnership::TrivialUse)
105
- return false ;
106
- // Don't mess with unowned conversions. They need to be copied immediately.
107
- if (operOwnership != OperandOwnership::GuaranteedForwarding &&
108
- operOwnership != OperandOwnership::ForwardingConsume) {
109
- return false ;
110
- }
111
- assert (operOwnership == OperandOwnership::GuaranteedForwarding ||
112
- operOwnership == OperandOwnership::ForwardingConsume);
113
-
114
- // Filter instructions that belong to a Forwarding*ValueInst mixin but
115
- // cannot be converted to forward owned value (struct_extract).
116
- if (!canOpcodeForwardOwnedValues (forwardedOper))
117
- return false ;
99
+ if (!isa<OwnershipForwardingSingleValueInstruction>(inst) &&
100
+ !isa<OwnershipForwardingMultipleValueInstruction>(inst))
101
+ return false ;
118
102
119
- return true ;
103
+ Operand *forwardedOper = &inst->getOperandRef (0 );
104
+ // Trivial conversions do not need to be hoisted out of a borrow scope.
105
+ auto operOwnership = forwardedOper->getOperandOwnership ();
106
+ if (operOwnership == OperandOwnership::TrivialUse)
107
+ return false ;
108
+ // Don't mess with unowned conversions. They need to be copied immediately.
109
+ if (operOwnership != OperandOwnership::GuaranteedForwarding &&
110
+ operOwnership != OperandOwnership::ForwardingConsume) {
111
+ return false ;
120
112
}
121
- return false ;
113
+ assert (operOwnership == OperandOwnership::GuaranteedForwarding ||
114
+ operOwnership == OperandOwnership::ForwardingConsume);
115
+
116
+ // Filter instructions that belong to a Forwarding*ValueInst mixin but
117
+ // cannot be converted to forward owned value (struct_extract).
118
+ if (!canOpcodeForwardOwnedValues (forwardedOper))
119
+ return false ;
120
+
121
+ return true ;
122
122
}
123
123
124
124
// / Return the root of a borrowed extended lifetime for \p def or invalid.
@@ -218,8 +218,6 @@ SILValue CanonicalizeBorrowScope::findDefInBorrowScope(SILValue value) {
218
218
// /
219
219
// / \p innerValue is either the initial begin_borrow, or a forwarding operation
220
220
// / within the borrow scope.
221
- // /
222
- // / Note: This must always return true when innerValue is a function argument.
223
221
template <typename Visitor>
224
222
bool CanonicalizeBorrowScope::visitBorrowScopeUses (SILValue innerValue,
225
223
Visitor &visitor) {
@@ -277,14 +275,12 @@ bool CanonicalizeBorrowScope::visitBorrowScopeUses(SILValue innerValue,
277
275
case OperandOwnership::PointerEscape:
278
276
// Pointer escapes are only allowed if they use the guaranteed value,
279
277
// which means that the escaped value must be confined to the current
280
- // borrow scope. visitBorrowScopeUses must never return false when
281
- // borrowedValue is a SILFunctionArgument.
278
+ // borrow scope.
282
279
if (use->get ()->getOwnershipKind () != OwnershipKind::Guaranteed &&
283
280
!isa<SILFunctionArgument>(borrowedValue.value )) {
284
281
return false ;
285
282
}
286
283
if (!visitor.visitUse (use)) {
287
- assert (!isa<SILFunctionArgument>(borrowedValue.value ));
288
284
return false ;
289
285
}
290
286
break ;
@@ -293,7 +289,6 @@ bool CanonicalizeBorrowScope::visitBorrowScopeUses(SILValue innerValue,
293
289
case OperandOwnership::ForwardingConsume:
294
290
if (CanonicalizeBorrowScope::isRewritableOSSAForward (user)) {
295
291
if (!visitor.visitForwardingUse (use)) {
296
- assert (!isa<SILFunctionArgument>(borrowedValue.value ));
297
292
return false ;
298
293
}
299
294
break ;
@@ -306,7 +301,6 @@ bool CanonicalizeBorrowScope::visitBorrowScopeUses(SILValue innerValue,
306
301
case OperandOwnership::BitwiseEscape:
307
302
case OperandOwnership::DestroyingConsume:
308
303
if (!visitor.visitUse (use)) {
309
- assert (!isa<SILFunctionArgument>(borrowedValue.value ));
310
304
return false ;
311
305
}
312
306
break ;
@@ -394,7 +388,7 @@ class FindBorrowScopeUses {
394
388
395
389
} // namespace
396
390
397
- // / Erase users from \p outerUseInsts that are not within the borrow scope.
391
+ // / Erase users from \p outerUseInsts that are actually within the borrow scope.
398
392
void CanonicalizeBorrowScope::filterOuterBorrowUseInsts (
399
393
OuterUsers &outerUseInsts) {
400
394
auto *beginBorrow = cast<BeginBorrowInst>(borrowedValue.value );
@@ -451,6 +445,10 @@ class RewriteInnerBorrowUses {
451
445
}
452
446
SILValue def = scope.findDefInBorrowScope (value);
453
447
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
+ }
454
452
// All in-scope consuming uses need a unique copy in the same block.
455
453
auto *copy = dyn_cast<CopyValueInst>(use->get ());
456
454
if (copy && copy->hasOneUse () && copy->getParent () == user->getParent ()) {
@@ -480,7 +478,9 @@ class RewriteInnerBorrowUses {
480
478
if (!hasValueOwnership (result)) {
481
479
continue ;
482
480
}
483
- scope.visitBorrowScopeUses (result, *this );
481
+ if (!scope.visitBorrowScopeUses (result, *this )) {
482
+ return false ;
483
+ }
484
484
}
485
485
// Update this operand bypassing any copies.
486
486
SILValue value = use->get ();
@@ -796,9 +796,7 @@ bool CanonicalizeBorrowScope::consolidateBorrowScope() {
796
796
if (outerUseInsts.empty ()) {
797
797
RewriteInnerBorrowUses innerRewriter (*this );
798
798
beginVisitBorrowScopeUses (); // reset the def/use worklist
799
- bool succeed = visitBorrowScopeUses (borrowedValue.value , innerRewriter);
800
- assert (succeed && " should be filtered by FindBorrowScopeUses" );
801
- return true ;
799
+ return visitBorrowScopeUses (borrowedValue.value , innerRewriter);
802
800
}
803
801
LLVM_DEBUG (llvm::dbgs () << " Outer uses:\n " ;
804
802
for (SILInstruction *inst
@@ -826,11 +824,25 @@ bool CanonicalizeBorrowScope::canonicalizeFunctionArgument(
826
824
RewriteInnerBorrowUses innerRewriter (*this );
827
825
beginVisitBorrowScopeUses (); // reset the def/use worklist
828
826
829
- bool succeed = visitBorrowScopeUses (borrowedValue.value , innerRewriter);
830
- assert (succeed && " must always succeed for function arguments" );
831
- return true ;
827
+ return visitBorrowScopeUses (borrowedValue.value , innerRewriter);
832
828
}
833
829
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
+
834
846
// / Canonicalize a worklist of extended lifetimes. This iterates after rewriting
835
847
// / borrow scopes to handle new outer copies and new owned lifetimes from
836
848
// / forwarding operations.
0 commit comments