@@ -297,13 +297,28 @@ static void cleanupOperandsBeforeDeletion(SILInstruction *oldValue,
297
297
// directly checking ownership requirements. This does not determine whether the
298
298
// scope of the newValue can be fully extended.
299
299
bool OwnershipRAUWHelper::hasValidRAUWOwnership (SILValue oldValue,
300
- SILValue newValue) {
300
+ SILValue newValue,
301
+ ArrayRef<Operand *> oldUses) {
301
302
auto newOwnershipKind = newValue.getOwnershipKind ();
302
303
303
304
// If the either value is lexical, replacing its uses may result in
304
305
// shortening or lengthening its lifetime in ways that don't respect lexical
305
306
// scope and deinit barriers.
306
- if (oldValue->isLexical () || newValue->isLexical ())
307
+ //
308
+ // Specifically, we have the following cases:
309
+ //
310
+ // +--------+--------+
311
+ // |oldValue|newValue|
312
+ // +--------+--------+
313
+ // | not | not | legal
314
+ // +--------+--------+
315
+ // |lexical | not | illegal
316
+ // +--------+--------+
317
+ // | * |lexical | legal so long as it doesn't extend newValue's lifetime
318
+ // +--------+--------+
319
+ if ((oldValue->isLexical () && !newValue->isLexical ()) ||
320
+ (newValue->isLexical () &&
321
+ !areUsesWithinLexicalValueLifetime (newValue, oldUses)))
307
322
return false ;
308
323
309
324
// If our new kind is ValueOwnershipKind::None, then we are fine. We
@@ -353,20 +368,51 @@ bool OwnershipRAUWHelper::hasValidRAUWOwnership(SILValue oldValue,
353
368
// extend the lifetime of \p oldValue to cover the new uses.
354
369
static bool canFixUpOwnershipForRAUW (SILValue oldValue, SILValue newValue,
355
370
OwnershipFixupContext &context) {
356
- if (!OwnershipRAUWHelper::hasValidRAUWOwnership (oldValue, newValue))
357
- return false ;
371
+ switch (oldValue.getOwnershipKind ()) {
372
+ case OwnershipKind::Guaranteed:
373
+ // Check that the old lifetime can be extended and record the necessary
374
+ // book-keeping in the OwnershipFixupContext.
375
+ context.clear ();
376
+
377
+ // Check that no transitive uses have a PointerEscape, and record the leaf
378
+ // uses for liveness extension.
379
+ if (!findExtendedTransitiveGuaranteedUses (oldValue,
380
+ context.guaranteedUsePoints ))
381
+ return false ;
382
+ return OwnershipRAUWHelper::hasValidRAUWOwnership (
383
+ oldValue, newValue, context.guaranteedUsePoints );
384
+ default : {
385
+ SmallVector<Operand *, 8 > ownedUsePoints;
386
+ // If newValue is lexical, find the uses of oldValue so that it can be
387
+ // determined whether the replacement would illegally extend the lifetime
388
+ // of newValue.
389
+ if (newValue->isLexical () &&
390
+ !findUsesOfSimpleValue (oldValue, &ownedUsePoints))
391
+ return false ;
392
+ return OwnershipRAUWHelper::hasValidRAUWOwnership (oldValue, newValue,
393
+ ownedUsePoints);
394
+ }
395
+ }
396
+ }
397
+
398
+ bool swift::areUsesWithinLexicalValueLifetime (SILValue value,
399
+ ArrayRef<Operand *> uses) {
400
+ assert (value->isLexical ());
358
401
359
- if (oldValue.getOwnershipKind () != OwnershipKind::Guaranteed)
402
+ // The lexical lifetime of a function argument is the whole body of the
403
+ // function.
404
+ if (isa<SILFunctionArgument>(value))
360
405
return true ;
361
406
362
- // Check that the old lifetime can be extended and record the necessary
363
- // book-keeping in the OwnershipFixupContext.
364
- context.clear ();
407
+ if (auto borrowedValue = BorrowedValue (value)) {
408
+ PrunedLiveness liveness;
409
+ auto *function = value->getFunction ();
410
+ borrowedValue.computeLiveness (liveness);
411
+ DeadEndBlocks deadEndBlocks (function);
412
+ return liveness.areUsesWithinBoundary (uses, &deadEndBlocks);
413
+ }
365
414
366
- // Check that no transitive uses have a PointerEscape, and record the leaf
367
- // uses for liveness extension.
368
- return findExtendedTransitiveGuaranteedUses (oldValue,
369
- context.guaranteedUsePoints );
415
+ return false ;
370
416
}
371
417
372
418
// ===----------------------------------------------------------------------===//
@@ -1118,7 +1164,9 @@ SILValue OwnershipRAUWPrepare::prepareReplacement(SILValue newValue) {
1118
1164
if (oldValue->use_empty ())
1119
1165
return newValue;
1120
1166
1121
- assert (OwnershipRAUWHelper::hasValidRAUWOwnership (oldValue, newValue) &&
1167
+ assert (
1168
+ OwnershipRAUWHelper::hasValidRAUWOwnership (oldValue, newValue,
1169
+ ctx.guaranteedUsePoints ) &&
1122
1170
" Should have checked if can perform this operation before calling it?!" );
1123
1171
// If our new value is just none, we can pass anything to it so just RAUW
1124
1172
// and return.
@@ -1576,7 +1624,10 @@ OwnershipReplaceSingleUseHelper::OwnershipReplaceSingleUseHelper(
1576
1624
1577
1625
// Otherwise, lets check if we can perform this RAUW operation. If we can't,
1578
1626
// set ctx to nullptr to invalidate the helper and return.
1579
- if (!OwnershipRAUWHelper::hasValidRAUWOwnership (use->get (), newValue)) {
1627
+ SmallVector<Operand *, 1 > oldUses;
1628
+ oldUses.push_back (use);
1629
+ if (!OwnershipRAUWHelper::hasValidRAUWOwnership (use->get (), newValue,
1630
+ oldUses)) {
1580
1631
invalidate ();
1581
1632
return ;
1582
1633
}
0 commit comments