@@ -2383,7 +2383,9 @@ bool swift::isNestedLexicalBeginBorrow(BeginBorrowInst *bbi) {
2383
2383
}
2384
2384
2385
2385
bool swift::isRedundantMoveValue (MoveValueInst *mvi) {
2386
- // Check whether the moved-from value's lifetime and the moved-to value's
2386
+ // Given: %moved_to_value = move_value %original_value
2387
+ //
2388
+ // Check whether the original value's lifetime and the moved-to value's
2387
2389
// lifetime have the same (1) ownership, (2) lexicality, and (3) escaping.
2388
2390
//
2389
2391
// Along the way, also check for cases where they have different values for
@@ -2405,42 +2407,51 @@ bool swift::isRedundantMoveValue(MoveValueInst *mvi) {
2405
2407
2406
2408
// The move doesn't alter constraints: ownership and lexicality match.
2407
2409
2410
+ // Before checking whether escaping matches, check whether the move_value is
2411
+ // redundant regardless on account of how its uses are limited.
2412
+ //
2413
+ // At this point, ownership and lexicality are known to match. If the
2414
+ // original value doesn't escape, then merging the two lifetimes won't make
2415
+ // it harder to optimize the portion of the merged lifetime corresponding to
2416
+ // the moved-to value. If the original's only consuming use is the
2417
+ // move_value, then the original value's lifetime couldn't be shortened
2418
+ // anyway.
2419
+ //
2420
+ // Summary: !escaping(original)
2421
+ // && singleConsumingUser(original) == move
2422
+ // => redundant(mvi)
2423
+ //
2424
+ // Check this in two ways, one cheaper than the other.
2425
+
2426
+ // First, avoid calling hasPointerEscape(original).
2427
+ //
2428
+ // If the original value is not a phi (a phi's incoming values might have
2429
+ // escaping uses) and its only user is the move, then it doesn't escape. Also
2430
+ // if its only user is the move, then its only _consuming_ user is the move.
2408
2431
auto *singleUser =
2409
2432
original->getSingleUse () ? original->getSingleUse ()->getUser () : nullptr ;
2410
2433
if (mvi == singleUser && !SILArgument::asPhi (original)) {
2411
2434
assert (!hasPointerEscape (original));
2412
- // The moved-from value's only use is the move_value, and the moved-from
2413
- // value isn't a phi. So, it doesn't escape. (A phi's incoming values
2414
- // might escape.)
2415
- //
2416
- // Still, no optimization is enabled by separating the two lifetimes.
2417
- // The moved-from value's lifetime could not be shrunk regardless of whether
2418
- // the moved-to value escapes.
2435
+ assert (original->getSingleConsumingUse ()->getUser () == mvi);
2436
+ // - !escaping(original)
2437
+ // - singleConsumingUser(original) == move
2419
2438
return true ;
2420
2439
}
2421
2440
2422
- auto moveHasEscape = hasPointerEscape (mvi);
2441
+ // Second, call hasPointerEscape(original).
2442
+ //
2443
+ // Explicitly check both
2444
+ // - !escaping(original)
2445
+ // - singleConsumingUser(original) == move
2423
2446
auto originalHasEscape = hasPointerEscape (original);
2424
-
2425
- // (3) Escaping matches? (Expensive check, saved for last.)
2426
- if (moveHasEscape != originalHasEscape) {
2427
- if (!originalHasEscape) {
2428
- auto *singleConsumingUser =
2429
- original->getSingleConsumingUse ()
2430
- ? original->getSingleConsumingUse ()->getUser ()
2431
- : nullptr ;
2432
- if (mvi == singleConsumingUser) {
2433
- // The moved-from value's only consuming use is the move_value and it
2434
- // doesn't escape.
2435
- //
2436
- // Although the moved-to value escapes, no optimization is enabled by
2437
- // separating the two lifetimes. The moved-from value's lifetime
2438
- // already couldn't be shrunk.
2439
- return true ;
2440
- }
2441
- }
2442
- return false ;
2447
+ auto *singleConsumingUser = original->getSingleConsumingUse ()
2448
+ ? original->getSingleConsumingUse ()->getUser ()
2449
+ : nullptr ;
2450
+ if (mvi == singleConsumingUser && !originalHasEscape) {
2451
+ return true ;
2443
2452
}
2444
2453
2445
- return true ;
2454
+ // (3) Escaping matches? (Expensive check, saved for last.)
2455
+ auto moveHasEscape = hasPointerEscape (mvi);
2456
+ return moveHasEscape == originalHasEscape;
2446
2457
}
0 commit comments