Revert "Use destination registers as temporary registers in move scheduler"

This reverts commit fb5b6dad1e23261f8b70b94e6ea21de4045b335c.

Bug: b/375147902
Change-Id: I4843e1f514ad64106fd0701258a7fe33f18a1ee6
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/RegisterMove.java b/src/main/java/com/android/tools/r8/ir/regalloc/RegisterMove.java
index 70d2ab8..963bc1f 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/RegisterMove.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/RegisterMove.java
@@ -11,7 +11,6 @@
 import it.unimi.dsi.fastutil.ints.Int2IntMap;
 import java.util.Objects;
 import java.util.Set;
-import java.util.function.IntConsumer;
 
 // Register moves used by the spilling register allocator. These are used both for spill and
 // for phi moves and they are moves between actual registers represented by their register number.
@@ -37,22 +36,6 @@
     this.type = type;
   }
 
-  public void forEachDestinationRegister(IntConsumer consumer) {
-    consumer.accept(dst);
-    if (isWide()) {
-      consumer.accept(dst + 1);
-    }
-  }
-
-  public void forEachSourceRegister(IntConsumer consumer) {
-    if (src != NO_REGISTER) {
-      consumer.accept(src);
-      if (isWide()) {
-        consumer.accept(src + 1);
-      }
-    }
-  }
-
   public boolean writes(int register, boolean otherIsWide) {
     if (dst == register) {
       return true;
@@ -66,11 +49,7 @@
     return false;
   }
 
-  public boolean isBlocked(
-      RegisterMoveScheduler scheduler, Set<RegisterMove> moveSet, Int2IntMap valueMap) {
-    if (isDestUsedAsTemporary(scheduler)) {
-      return true;
-    }
+  public boolean isBlocked(Set<RegisterMove> moveSet, Int2IntMap valueMap) {
     for (RegisterMove move : moveSet) {
       if (isIdentical(move) || move.src == NO_REGISTER) {
         continue;
@@ -82,19 +61,10 @@
     return false;
   }
 
-  public boolean isDestUsedAsTemporary(RegisterMoveScheduler scheduler) {
-    return scheduler.activeTempRegisters.contains(dst)
-        || (isWide() && scheduler.activeTempRegisters.contains(dst + 1));
-  }
-
   public boolean isIdentical(RegisterMove move) {
     return ObjectUtils.identical(this, move);
   }
 
-  public boolean isNotIdentical(RegisterMove move) {
-    return !isIdentical(move);
-  }
-
   public boolean isWide() {
     return type.isWidePrimitive();
   }
@@ -143,16 +113,4 @@
     }
     return definition.getNumber() - o.definition.getNumber();
   }
-
-  @Override
-  public String toString() {
-    if (type.isSinglePrimitive()) {
-      return "move " + dst + ", " + src;
-    } else if (type.isWidePrimitive()) {
-      return "move-wide " + dst + ", " + src;
-    } else {
-      assert type.isReferenceType();
-      return "move-object " + dst + ", " + src;
-    }
-  }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/RegisterMoveCycle.java b/src/main/java/com/android/tools/r8/ir/regalloc/RegisterMoveCycle.java
deleted file mode 100644
index a1e986d..0000000
--- a/src/main/java/com/android/tools/r8/ir/regalloc/RegisterMoveCycle.java
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright (c) 2024, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-package com.android.tools.r8.ir.regalloc;
-
-import java.util.TreeSet;
-
-class RegisterMoveCycle {
-
-  private final TreeSet<RegisterMove> moves;
-
-  // Whether the cycle is closed, i.e., the moves in the cycle are only blocked by moves also
-  // present in this cycle.
-  private final boolean closed;
-
-  RegisterMoveCycle(TreeSet<RegisterMove> cycle, boolean closed) {
-    this.moves = cycle;
-    this.closed = closed;
-  }
-
-  public TreeSet<RegisterMove> getMoves() {
-    return moves;
-  }
-
-  public boolean isClosed() {
-    return closed;
-  }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/RegisterMoveCycleDetector.java b/src/main/java/com/android/tools/r8/ir/regalloc/RegisterMoveCycleDetector.java
deleted file mode 100644
index a6b2ad6..0000000
--- a/src/main/java/com/android/tools/r8/ir/regalloc/RegisterMoveCycleDetector.java
+++ /dev/null
@@ -1,138 +0,0 @@
-// Copyright (c) 2024, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-package com.android.tools.r8.ir.regalloc;
-
-import com.android.tools.r8.utils.SetUtils;
-import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
-import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Deque;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.TreeSet;
-
-public class RegisterMoveCycleDetector {
-
-  @SuppressWarnings("MixedMutabilityReturnType")
-  static List<RegisterMoveCycle> getMoveCycles(TreeSet<RegisterMove> moveSet) {
-    if (moveSet.size() <= 1) {
-      return Collections.emptyList();
-    }
-    List<RegisterMoveCycle> moveCycles = new ArrayList<>();
-    Int2ObjectMap<TreeSet<RegisterMove>> readBy = createReadByGraph(moveSet);
-    Set<RegisterMove> finished = new HashSet<>();
-    Deque<RegisterMove> stack = new ArrayDeque<>();
-    TreeSet<RegisterMove> stackSet = new TreeSet<>();
-    for (RegisterMove move : moveSet) {
-      if (finished.contains(move)) {
-        continue;
-      }
-      dfs(move, finished, readBy, stack, stackSet, moveCycles);
-      assert finished.contains(move);
-      assert stack.isEmpty();
-      assert stackSet.isEmpty();
-    }
-    return moveCycles;
-  }
-
-  private static void dfs(
-      RegisterMove move,
-      Set<RegisterMove> finished,
-      Int2ObjectMap<TreeSet<RegisterMove>> readBy,
-      Deque<RegisterMove> stack,
-      TreeSet<RegisterMove> stackSet,
-      List<RegisterMoveCycle> moveCycles) {
-    stack.addLast(move);
-    boolean addedToStack = stackSet.add(move);
-    assert addedToStack;
-    // Explore all outgoing edges. The successors of this move are the moves that read the
-    // destination registers of the current move.
-    for (RegisterMove successor : getSuccessors(move, readBy)) {
-      if (finished.contains(successor)) {
-        // Already fully explored.
-        continue;
-      }
-      if (successor.isIdentical(move)) {
-        // This move is reading/writing overlapping registers (e.g., move-wide 0, 1).
-        continue;
-      }
-      if (stackSet.contains(successor)) {
-        moveCycles.add(extractCycle(stack, successor, readBy));
-      } else {
-        dfs(successor, finished, readBy, stack, stackSet, moveCycles);
-      }
-    }
-    RegisterMove removedFromStack = stack.removeLast();
-    assert removedFromStack.isIdentical(move);
-    boolean removedFromStackSet = stackSet.remove(move);
-    assert removedFromStackSet;
-    boolean markedFinished = finished.add(move);
-    assert markedFinished;
-  }
-
-  // Returns a one-to-many map from registers to the set of moves that read that register.
-  private static Int2ObjectMap<TreeSet<RegisterMove>> createReadByGraph(
-      TreeSet<RegisterMove> moveSet) {
-    Int2ObjectMap<TreeSet<RegisterMove>> readBy = new Int2ObjectOpenHashMap<>();
-    for (RegisterMove move : moveSet) {
-      move.forEachSourceRegister(
-          register -> {
-            if (readBy.containsKey(register)) {
-              readBy.get(register).add(move);
-            } else {
-              readBy.put(register, SetUtils.newTreeSet(move));
-            }
-          });
-    }
-    return readBy;
-  }
-
-  private static Set<RegisterMove> getSuccessors(
-      RegisterMove move, Int2ObjectMap<TreeSet<RegisterMove>> readBy) {
-    TreeSet<RegisterMove> successors = readBy.get(move.dst);
-    if (move.isWide()) {
-      TreeSet<RegisterMove> additionalSuccessors = readBy.get(move.dst + 1);
-      if (successors == null) {
-        successors = additionalSuccessors;
-      } else if (additionalSuccessors != null) {
-        successors = new TreeSet<>(successors);
-        successors.addAll(additionalSuccessors);
-      }
-    }
-    return successors != null ? successors : Collections.emptySet();
-  }
-
-  private static RegisterMoveCycle extractCycle(
-      Deque<RegisterMove> stack,
-      RegisterMove cycleEntry,
-      Int2ObjectMap<TreeSet<RegisterMove>> readBy) {
-    Deque<RegisterMove> cycle = new ArrayDeque<>();
-    while (!cycleEntry.isIdentical(cycle.peekFirst())) {
-      cycle.addFirst(stack.removeLast());
-    }
-    stack.addAll(cycle);
-    TreeSet<RegisterMove> cycleSet = new TreeSet<>(cycle);
-    return new RegisterMoveCycle(cycleSet, isClosedCycle(cycleSet, readBy));
-  }
-
-  private static boolean isClosedCycle(
-      TreeSet<RegisterMove> cycle, Int2ObjectMap<TreeSet<RegisterMove>> readBy) {
-    for (RegisterMove move : cycle) {
-      for (int i = 0; i < move.type.requiredRegisters(); i++) {
-        TreeSet<RegisterMove> successors = readBy.get(move.dst + i);
-        if (successors != null) {
-          for (RegisterMove successor : successors) {
-            if (!cycle.contains(successor)) {
-              return false;
-            }
-          }
-        }
-      }
-    }
-    return true;
-  }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/RegisterMoveScheduler.java b/src/main/java/com/android/tools/r8/ir/regalloc/RegisterMoveScheduler.java
index 43c2ed3..242f2dc 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/RegisterMoveScheduler.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/RegisterMoveScheduler.java
@@ -4,8 +4,6 @@
 package com.android.tools.r8.ir.regalloc;
 
 import static com.android.tools.r8.ir.regalloc.LiveIntervals.NO_REGISTER;
-import static com.android.tools.r8.utils.IntConsumerUtils.emptyIntConsumer;
-import static com.google.common.base.Predicates.not;
 
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
@@ -18,8 +16,6 @@
 import com.android.tools.r8.ir.code.Move;
 import com.android.tools.r8.ir.code.Position;
 import com.android.tools.r8.ir.code.Value;
-import com.android.tools.r8.utils.ObjectUtils;
-import com.google.common.collect.Iterables;
 import it.unimi.dsi.fastutil.ints.Int2IntMap;
 import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
 import it.unimi.dsi.fastutil.ints.IntArraySet;
@@ -30,13 +26,14 @@
 import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Deque;
+import java.util.Iterator;
 import java.util.List;
+import java.util.Set;
 import java.util.TreeSet;
-import java.util.function.IntConsumer;
 
 public class RegisterMoveScheduler {
   // The set of moves to schedule.
-  private final TreeSet<RegisterMove> moveSet = new TreeSet<>();
+  private final Set<RegisterMove> moveSet = new TreeSet<>();
   // Mapping to keep track of which values currently corresponds to each other.
   // This is initially an identity map but changes as we insert moves.
   private final Int2IntMap valueMap = new Int2IntOpenHashMap();
@@ -47,15 +44,8 @@
   // The first available temporary register.
   private final int firstTempRegister;
   private int nextTempRegister;
-  // Free temporary registers that have been allocated by move scheduling.
+  // Free registers.
   private final IntSortedSet freeRegisters = new IntRBTreeSet();
-  // Registers that can be used as temporary registers until they are assigned by a move in the
-  // move set.
-  private final IntSortedSet freeRegistersUntilAssigned = new IntRBTreeSet();
-  // Registers that are the destination register of some move in the move set, but which are
-  // currently being used as a temporary register for another value. Moves in the move set that
-  // write a register in this set are blocked until the temporary registers are released.
-  public final IntSet activeTempRegisters = new IntOpenHashSet();
 
   public RegisterMoveScheduler(
       InstructionListIterator insertAt, int firstTempRegister, Position position) {
@@ -70,19 +60,6 @@
     this(insertAt, firstTempRegister, Position.none());
   }
 
-  private void initializeFreeRegistersUntilAssigned() {
-    // All registers that are assigned by the move set but not read can be used as temporary
-    // registers until they are assigned.
-    assert activeTempRegisters.isEmpty();
-    assert freeRegistersUntilAssigned.isEmpty();
-    for (RegisterMove move : moveSet) {
-      move.forEachDestinationRegister(freeRegistersUntilAssigned::add);
-    }
-    for (RegisterMove move : moveSet) {
-      move.forEachSourceRegister(freeRegistersUntilAssigned::remove);
-    }
-  }
-
   public void addMove(RegisterMove move) {
     moveSet.add(move);
     if (move.src != NO_REGISTER) {
@@ -93,58 +70,53 @@
 
   public void schedule() {
     assert everyDestinationOnlyWrittenOnce();
-    initializeFreeRegistersUntilAssigned();
 
     // Worklist of moves that are ready to be inserted.
     Deque<RegisterMove> worklist = new ArrayDeque<>();
 
-    // If there are destination registers we can use until they are assigned, then instead of
-    // emitting these unblocked moves, we use them as temporary registers to unblock move cycles.
-    List<RegisterMoveCycle> moveCycles = RegisterMoveCycleDetector.getMoveCycles(moveSet);
-    for (RegisterMoveCycle moveCycle : moveCycles) {
-      for (RegisterMove move : moveCycle.getMoves()) {
-        assert move.isBlocked(this, moveSet, valueMap) || !moveSet.contains(move);
-        removeFromFreeRegistersUntilAssigned(move.dst, move.isWide(), emptyIntConsumer());
+    // Initialize worklist with the moves that do not interfere with other moves.
+    Iterator<RegisterMove> iterator = moveSet.iterator();
+    while (iterator.hasNext()) {
+      RegisterMove move = iterator.next();
+      if (!move.isBlocked(moveSet, valueMap)) {
+        worklist.addLast(move);
+        iterator.remove();
       }
-      // If the cycle is not closed then some moves in the cycle are blocked by other moves.
-      // TODO(b/375147902): Try to schedule these other moves before scheduling the cycle to
-      //  unblock the cycle. In JetNews 15% of move cycles are open.
-      if (moveCycle.isClosed()) {
-        assert moveSet.containsAll(moveCycle.getMoves());
-        assert worklist.isEmpty();
-        schedulePartial(moveCycle.getMoves(), worklist);
-      }
-      assert activeTempRegisters.isEmpty();
     }
 
-    // Initialize worklist with the moves that do not interfere with other moves.
-    enqueueUnblockedMoves(worklist);
-    schedulePartial(moveSet, worklist);
-    assert freeRegistersUntilAssigned.isEmpty();
-  }
-
-  private void schedulePartial(
-      TreeSet<RegisterMove> movesToSchedule, Deque<RegisterMove> worklist) {
     // Process the worklist generating moves. If the worklist becomes empty while the move set
     // still contains elements we need to use a temporary to break cycles.
-    while (!worklist.isEmpty() || !movesToSchedule.isEmpty()) {
+    while (!worklist.isEmpty() || !moveSet.isEmpty()) {
       while (!worklist.isEmpty()) {
-        while (!worklist.isEmpty()) {
-          RegisterMove move = worklist.removeFirst();
-          assert !move.isBlocked(this, moveSet, valueMap);
-          createMove(move);
+        RegisterMove move = worklist.removeFirst();
+        assert !move.isBlocked(moveSet, valueMap);
+        // Insert the move.
+        int generatedDest = createMove(move);
+        // Update the value map with the information that dest can be used instead of
+        // src starting now.
+        if (move.src != NO_REGISTER) {
+          valueMap.put(move.src, generatedDest);
         }
-        enqueueUnblockedMoves(worklist, movesToSchedule);
+        // Iterate and find the moves that were blocked because they need to write to
+        // one of the move src. That is now valid because the move src is preserved in dest.
+        iterator = moveSet.iterator();
+        while (iterator.hasNext()) {
+          RegisterMove other = iterator.next();
+          if (!other.isBlocked(moveSet, valueMap)) {
+            worklist.addLast(other);
+            iterator.remove();
+          }
+        }
       }
-      if (!movesToSchedule.isEmpty()) {
+      if (!moveSet.isEmpty()) {
         // The remaining moves are conflicting. Chose a move and unblock it by generating moves to
         // temporary registers for its destination value(s).
-        RegisterMove move = pickMoveToUnblock(movesToSchedule);
+        RegisterMove move = pickMoveToUnblock();
         createMoveDestToTemp(move);
         // TODO(b/375147902): After emitting the newly unblocked move, try to prioritize the moves
         //  that blocked it, so that we free up the temp register, rather than getting overlapping
         //  temporary registers.
-        worklist.add(move);
+        worklist.addLast(move);
       }
     }
   }
@@ -163,7 +135,7 @@
       int moveSrc = valueMap.get(move.src);
       if (moveSrc == src) {
         result.add(move);
-      } else if (move.isWide() && (moveSrc + 1) == src) {
+      } else if (move.type.isWidePrimitive() && (moveSrc + 1) == src) {
         result.add(move);
       } else if (type.isWidePrimitive() && (moveSrc - 1) == src) {
         result.add(move);
@@ -172,7 +144,7 @@
     return result;
   }
 
-  private void createMove(RegisterMove move) {
+  private int createMove(RegisterMove move) {
     Instruction instruction;
     if (move.definition != null) {
       if (move.definition.isArgument()) {
@@ -200,43 +172,7 @@
     }
     instruction.setPosition(position);
     insertAt.add(instruction);
-
-    // Update the value map with the information that dest can be used instead of
-    // src starting now.
-    if (move.src != NO_REGISTER) {
-      valueMap.put(move.src, move.dst);
-    }
-    removeFromFreeRegistersUntilAssigned(move.dst, move.isWide(), emptyIntConsumer());
-  }
-
-  private void enqueueUnblockedMoves(Deque<RegisterMove> worklist) {
-    // Iterate and find the moves that were blocked because they need to write to one of the move
-    // src. That is now valid because the move src is preserved in dest.
-    moveSet.removeIf(
-        move -> {
-          if (move.isBlocked(this, moveSet, valueMap)) {
-            return false;
-          }
-          worklist.addLast(move);
-          return true;
-        });
-  }
-
-  private void enqueueUnblockedMoves(
-      Deque<RegisterMove> worklist, TreeSet<RegisterMove> movesToSchedule) {
-    // Iterate and find the moves that were blocked because they need to write to one of the move
-    // src. That is now valid because the move src is preserved in dest.
-    movesToSchedule.removeIf(
-        move -> {
-          if (move.isBlocked(this, moveSet, valueMap)) {
-            return false;
-          }
-          if (ObjectUtils.notIdentical(moveSet, movesToSchedule)) {
-            moveSet.remove(move);
-          }
-          worklist.addLast(move);
-          return true;
-        });
+    return move.dst;
   }
 
   private void createMoveDestToTemp(RegisterMove move) {
@@ -259,17 +195,15 @@
   }
 
   private int takeFreeRegister(boolean wide) {
-    int register = takeFreeRegisterFrom(freeRegistersUntilAssigned, wide);
-    if (register != NO_REGISTER) {
-      addActiveTempRegisters(register, wide);
-      return register;
-    }
-    register = takeFreeRegisterFrom(freeRegisters, wide);
-    if (register != NO_REGISTER) {
-      return register;
+    for (int freeRegister : freeRegisters) {
+      if (wide && !freeRegisters.remove(freeRegister + 1)) {
+        continue;
+      }
+      freeRegisters.remove(freeRegister);
+      return freeRegister;
     }
     // We don't have a free register.
-    register = allocateExtraRegister();
+    int register = allocateExtraRegister();
     if (!wide) {
       return register;
     }
@@ -280,78 +214,21 @@
     return register;
   }
 
-  private static int takeFreeRegisterFrom(IntSortedSet freeRegisters, boolean wide) {
-    for (int freeRegister : freeRegisters) {
-      if (wide && !freeRegisters.remove(freeRegister + 1)) {
-        continue;
-      }
-      freeRegisters.remove(freeRegister);
-      return freeRegister;
-    }
-    return NO_REGISTER;
-  }
-
-  private void addActiveTempRegisters(int register, boolean wide) {
-    boolean addedRegister = activeTempRegisters.add(register);
-    assert addedRegister;
-    if (wide) {
-      boolean addedHighRegister = activeTempRegisters.add(register + 1);
-      assert addedHighRegister;
-    }
-  }
-
   private void returnTemporaryRegister(int register, boolean wide) {
-    if (returnActiveTempRegister(register, wide)) {
-      addFreeRegistersUntilAssigned(register, wide);
-    } else if (isExtraTemporaryRegister(register)) {
-      returnExtraTemporaryRegister(register, wide);
-    }
-  }
-
-  private boolean returnActiveTempRegister(int register, boolean wide) {
-    boolean removedRegister = activeTempRegisters.remove(register);
-    if (wide) {
-      if (removedRegister) {
-        boolean removedHighRegister = activeTempRegisters.remove(register + 1);
-        assert removedHighRegister;
-      } else {
-        assert !activeTempRegisters.contains(register + 1);
+    // TODO(b/375147902): If we seed the move scheduler with a set of free registers, then this
+    //  should also return non-temporary registers that are below firstTempRegister.
+    if (isTemporaryRegister(register)) {
+      freeRegisters.add(register);
+      if (wide) {
+        assert isTemporaryRegister(register + 1);
+        freeRegisters.add(register + 1);
       }
-    }
-    return removedRegister;
-  }
-
-  private void addFreeRegistersUntilAssigned(int register, boolean wide) {
-    boolean addedRegister = freeRegistersUntilAssigned.add(register);
-    assert addedRegister;
-    if (wide) {
-      boolean addedHighRegister = freeRegistersUntilAssigned.add(register + 1);
-      assert addedHighRegister;
-    }
-  }
-
-  private void returnExtraTemporaryRegister(int register, boolean wide) {
-    assert isExtraTemporaryRegister(register);
-    freeRegisters.add(register);
-    if (wide) {
-      assert isExtraTemporaryRegister(register + 1);
+    } else if (wide && isTemporaryRegister(register + 1)) {
       freeRegisters.add(register + 1);
     }
   }
 
-  private void removeFromFreeRegistersUntilAssigned(
-      int register, boolean wide, IntConsumer changedConsumer) {
-    if (freeRegistersUntilAssigned.remove(register)) {
-      changedConsumer.accept(register);
-    }
-    if (wide) {
-      if (freeRegistersUntilAssigned.remove(register + 1)) {
-        changedConsumer.accept(register + 1);
-      }
-    }
-  }
-
-  private boolean isExtraTemporaryRegister(int register) {
+  private boolean isTemporaryRegister(int register) {
     return register >= firstTempRegister;
   }
 
@@ -367,16 +244,17 @@
     return true;
   }
 
-  private RegisterMove pickMoveToUnblock(TreeSet<RegisterMove> moves) {
+  private RegisterMove pickMoveToUnblock() {
+    Iterator<RegisterMove> iterator = moveSet.iterator();
+    RegisterMove move = null;
     // Pick a non-wide move to unblock if possible.
-    Iterable<RegisterMove> eligible =
-        Iterables.filter(moves, move -> !move.isDestUsedAsTemporary(this));
-    RegisterMove move =
-        Iterables.find(eligible, not(RegisterMove::isWide), eligible.iterator().next());
-    moves.remove(move);
-    if (ObjectUtils.notIdentical(moves, moveSet)) {
-      moveSet.remove(move);
+    while (iterator.hasNext()) {
+      move = iterator.next();
+      if (!move.type.isWidePrimitive()) {
+        break;
+      }
     }
+    iterator.remove();
     return move;
   }
 
diff --git a/src/main/java/com/android/tools/r8/utils/SetUtils.java b/src/main/java/com/android/tools/r8/utils/SetUtils.java
index 7ec47cb..ea46d64 100644
--- a/src/main/java/com/android/tools/r8/utils/SetUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/SetUtils.java
@@ -13,7 +13,6 @@
 import java.util.IdentityHashMap;
 import java.util.LinkedHashSet;
 import java.util.Set;
-import java.util.TreeSet;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.function.Function;
 
@@ -119,12 +118,6 @@
     return builder.build();
   }
 
-  public static <T extends Comparable<T>> TreeSet<T> newTreeSet(T element) {
-    TreeSet<T> result = new TreeSet<>();
-    result.add(element);
-    return result;
-  }
-
   public static <T, S> Set<T> mapIdentityHashSet(Collection<S> set, Function<S, T> fn) {
     Set<T> out = newIdentityHashSet(set.size());
     for (S element : set) {
diff --git a/src/test/java/com/android/tools/r8/ir/regalloc/RegisterMoveSchedulerTest.java b/src/test/java/com/android/tools/r8/ir/regalloc/RegisterMoveSchedulerTest.java
index 2ef7125..8c95f7e 100644
--- a/src/test/java/com/android/tools/r8/ir/regalloc/RegisterMoveSchedulerTest.java
+++ b/src/test/java/com/android/tools/r8/ir/regalloc/RegisterMoveSchedulerTest.java
@@ -388,10 +388,18 @@
     scheduler.addMove(new RegisterMove(0, 3, TypeElement.getLong()));
     scheduler.schedule();
     assertEquals(3, moves.size());
-    assertEquals("42 <- 3", toString(moves.get(0)));
-    assertEquals("2 <- 1", toString(moves.get(1)));
-    assertEquals("0 <- 42", toString(moves.get(2)));
-    assertEquals(2, scheduler.getUsedTempRegisters());
+    Move firstMove = moves.get(0).asMove();
+    Move secondMove = moves.get(1).asMove();
+    Move thirdMove = moves.get(2).asMove();
+    assertEquals(ValueType.LONG, firstMove.outType());
+    assertEquals(ValueType.LONG, secondMove.outType());
+    assertEquals(ValueType.LONG, thirdMove.outType());
+    assertEquals(42, firstMove.dest().asFixedRegisterValue().getRegister());
+    assertEquals(1, firstMove.src().asFixedRegisterValue().getRegister());
+    assertEquals(0, secondMove.dest().asFixedRegisterValue().getRegister());
+    assertEquals(3, secondMove.src().asFixedRegisterValue().getRegister());
+    assertEquals(2, thirdMove.dest().asFixedRegisterValue().getRegister());
+    assertEquals(42, thirdMove.src().asFixedRegisterValue().getRegister());
   }
 
   @Test
@@ -452,13 +460,12 @@
     scheduler.addMove(new RegisterMove(12, 19, TypeElement.getLong()));
     scheduler.schedule();
     // In order to resolve these moves, we need to use two temporary register pairs.
-    assertEquals(5, moves.size());
-    assertEquals("42 <- 13", toString(moves.get(0)));
-    assertEquals("14 <- 11", toString(moves.get(1)));
-    assertEquals("10 <- 17", toString(moves.get(2)));
-    assertEquals("16 <- 42", toString(moves.get(3)));
-    assertEquals("12 <- 19", toString(moves.get(4)));
-    assertEquals(2, scheduler.getUsedTempRegisters());
+    assertEquals(6, moves.size());
+    assertEquals(42, moves.get(0).asMove().dest().asFixedRegisterValue().getRegister());
+    assertEquals(11, moves.get(0).asMove().src().asFixedRegisterValue().getRegister());
+    assertEquals(44, moves.get(1).asMove().dest().asFixedRegisterValue().getRegister());
+    assertEquals(13, moves.get(1).asMove().src().asFixedRegisterValue().getRegister());
+    assertEquals(12, moves.get(2).asMove().dest().asFixedRegisterValue().getRegister());
   }
 
   @Test
@@ -480,13 +487,19 @@
     scheduler.addMove(new RegisterMove(23, 28, TypeElement.getLong()));
     scheduler.schedule();
     // For this example we need recursive unblocking.
-    assertEquals(5, moves.size());
-    assertEquals("42 <- 28", toString(moves.get(0)));
-    assertEquals("29 <- 24", toString(moves.get(1)));
-    assertEquals("23 <- 42", toString(moves.get(2)));
-    assertEquals("28 <- 26", toString(moves.get(3)));
-    assertEquals("26 <- 22", toString(moves.get(4)));
-    assertEquals(2, scheduler.getUsedTempRegisters());
+    assertEquals(6, moves.size());
+    assertEquals(42, moves.get(0).asMove().dest().asFixedRegisterValue().getRegister());
+    assertEquals(26, moves.get(0).asMove().src().asFixedRegisterValue().getRegister());
+    assertEquals(26, moves.get(1).asMove().dest().asFixedRegisterValue().getRegister());
+    assertEquals(22, moves.get(1).asMove().src().asFixedRegisterValue().getRegister());
+    assertEquals(43, moves.get(2).asMove().dest().asFixedRegisterValue().getRegister());
+    assertEquals(28, moves.get(2).asMove().src().asFixedRegisterValue().getRegister());
+    assertEquals(28, moves.get(3).asMove().dest().asFixedRegisterValue().getRegister());
+    assertEquals(42, moves.get(3).asMove().src().asFixedRegisterValue().getRegister());
+    assertEquals(29, moves.get(4).asMove().dest().asFixedRegisterValue().getRegister());
+    assertEquals(24, moves.get(4).asMove().src().asFixedRegisterValue().getRegister());
+    assertEquals(23, moves.get(5).asMove().dest().asFixedRegisterValue().getRegister());
+    assertEquals(43, moves.get(5).asMove().src().asFixedRegisterValue().getRegister());
   }
 
   @Test
@@ -518,12 +531,12 @@
     scheduler.addMove(new RegisterMove(1, 0, TypeElement.getInt()));
     scheduler.addMove(new RegisterMove(2, 3, TypeElement.getInt()));
     scheduler.schedule();
-    // Verify that the temp register has been reused.
-    assertEquals("2 <- 1", toString(moves.get(0)));
-    assertEquals("1 <- 0", toString(moves.get(1)));
-    assertEquals("0 <- 2", toString(moves.get(2)));
-    assertEquals("2 <- 3", toString(moves.get(3)));
-    assertEquals(0, scheduler.getUsedTempRegisters());
+    // TODO(b/375147902): Verify that the temp register has been reused.
+    assertEquals("2 <- 3", toString(moves.get(0)));
+    assertEquals("42 <- 1", toString(moves.get(1)));
+    assertEquals("1 <- 0", toString(moves.get(2)));
+    assertEquals("0 <- 42", toString(moves.get(3)));
+    assertEquals(1, scheduler.getUsedTempRegisters());
   }
 
   @Test
@@ -553,9 +566,9 @@
     scheduler.addMove(new RegisterMove(11, 8, TypeElement.getLong()));
     scheduler.schedule();
     assertEquals(3, moves.size());
-    assertEquals("42 <- 12", toString(moves.get(0)));
-    assertEquals("11 <- 8", toString(moves.get(1)));
-    assertEquals("9 <- 42", toString(moves.get(2)));
+    assertEquals("42 <- 8", toString(moves.get(0)));
+    assertEquals("9 <- 12", toString(moves.get(1)));
+    assertEquals("11 <- 42", toString(moves.get(2)));
     assertEquals(2, scheduler.getUsedTempRegisters());
   }