@@ -2383,12 +2383,15 @@ bool swift::isNestedLexicalBeginBorrow(BeginBorrowInst *bbi) {
23832383}
23842384
23852385bool 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
23872389 // lifetime have the same (1) ownership, (2) lexicality, and (3) escaping.
23882390 //
23892391 // Along the way, also check for cases where they have different values for
23902392 // those characteristics but it doesn't matter because of how limited the uses
2391- // of the original value are (for now, whether the move is the only use).
2393+ // of the original value are (for now, whether the move is the only consuming
2394+ // use).
23922395
23932396 auto original = mvi->getOperand ();
23942397
@@ -2405,42 +2408,51 @@ bool swift::isRedundantMoveValue(MoveValueInst *mvi) {
24052408
24062409 // The move doesn't alter constraints: ownership and lexicality match.
24072410
2411+ // Before checking whether escaping matches, check whether the move_value is
2412+ // redundant regardless on account of how its uses are limited.
2413+ //
2414+ // At this point, ownership and lexicality are known to match. If the
2415+ // original value doesn't escape, then merging the two lifetimes won't make
2416+ // it harder to optimize the portion of the merged lifetime corresponding to
2417+ // the moved-to value. If the original's only consuming use is the
2418+ // move_value, then the original value's lifetime couldn't be shortened
2419+ // anyway.
2420+ //
2421+ // Summary: !escaping(original)
2422+ // && singleConsumingUser(original) == move
2423+ // => redundant(mvi)
2424+ //
2425+ // Check this in two ways, one cheaper than the other.
2426+
2427+ // First, avoid calling hasPointerEscape(original).
2428+ //
2429+ // If the original value is not a phi (a phi's incoming values might have
2430+ // escaping uses) and its only user is the move, then it doesn't escape. Also
2431+ // if its only user is the move, then its only _consuming_ user is the move.
24082432 auto *singleUser =
24092433 original->getSingleUse () ? original->getSingleUse ()->getUser () : nullptr ;
24102434 if (mvi == singleUser && !SILArgument::asPhi (original)) {
24112435 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.
2436+ assert (original->getSingleConsumingUse ()->getUser () == mvi);
2437+ // - !escaping(original)
2438+ // - singleConsumingUser(original) == move
24192439 return true ;
24202440 }
24212441
2422- auto moveHasEscape = hasPointerEscape (mvi);
2442+ // Second, call hasPointerEscape(original).
2443+ //
2444+ // Explicitly check both
2445+ // - !escaping(original)
2446+ // - singleConsumingUser(original) == move
24232447 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 ;
2448+ auto *singleConsumingUser = original->getSingleConsumingUse ()
2449+ ? original->getSingleConsumingUse ()->getUser ()
2450+ : nullptr ;
2451+ if (mvi == singleConsumingUser && !originalHasEscape) {
2452+ return true ;
24432453 }
24442454
2445- return true ;
2455+ // (3) Escaping matches? (Expensive check, saved for last.)
2456+ auto moveHasEscape = hasPointerEscape (mvi);
2457+ return moveHasEscape == originalHasEscape;
24462458}
0 commit comments