Spill a valid register when no valid register candidate can be found.

In rare cases, when all registers candidates are used and the
last register candidate is invalid, we would fail instead of
spilling a valid register to use. This change fixes that.

R=sgjesse@google.com

Bug: 70909581
Change-Id: I5e4fb6e7b37e3c6ff0b52e9be6324e6de8df3ccd
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java b/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
index acf4395..45b8055 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
@@ -1348,10 +1348,17 @@
     // free position.
     int candidate = getLargestValidCandidate(
         unhandledInterval, registerConstraint, needsRegisterPair, freePositions, Type.ANY);
-    assert candidate != REGISTER_CANDIDATE_NOT_FOUND;
-    int largestFreePosition = freePositions.get(candidate);
-    if (needsRegisterPair) {
-      largestFreePosition = Math.min(largestFreePosition, freePositions.get(candidate + 1));
+
+    // It is not always possible to find a largest valid candidate. If none of the usable register
+    // are free we typically get the last candidate. However, if that candidate has to be
+    // discarded in order to workaround bugs we get REGISTER_CANDIDATE_NOT_FOUND. In both cases
+    // we need to spill a valid candidate. That path is triggered when largestFreePosition is 0.
+    int largestFreePosition = 0;
+    if (candidate != REGISTER_CANDIDATE_NOT_FOUND) {
+      largestFreePosition = freePositions.get(candidate);
+      if (needsRegisterPair) {
+        largestFreePosition = Math.min(largestFreePosition, freePositions.get(candidate + 1));
+      }
     }
 
     // Determine what to do based on how long the selected candidate is free.
diff --git a/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java b/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
index a410f07..32c0175 100644
--- a/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
@@ -145,10 +145,6 @@
           .put("974-verify-interface-super", AndroidApiLevel.N)
           // Desugaring of interface private methods is not yet supported.
           .put("975-iface-private", AndroidApiLevel.N)
-          // The extended check for overlapping long registers cause this to run out of registers.
-          .put("421-large-frame", AndroidApiLevel.N)
-          // The extended check for overlapping long registers cause this to run out of registers.
-          .put("551-checker-shifter-operand", AndroidApiLevel.N)
           .build();
 
   // Tests that timeout when run with Art.
@@ -839,9 +835,6 @@
           .put("973-default-multidex", beforeAndroidN) // --min-sdk = 24
           .put("974-verify-interface-super", beforeAndroidN) // --min-sdk = 24
           .put("975-iface-private", beforeAndroidN) // --min-sdk = 24
-          // These tests have min-api set to N.
-          .put("421-large-frame", beforeAndroidN) // --min-sdk = 24
-          .put("551-checker-shifter-operand", beforeAndroidN) // --min-sdk = 24
           // Uses dex file version 37 and therefore only runs on Android N and above.
           .put("972-iface-super-multidex",
               TestCondition.match(TestCondition.tools(DexTool.JACK, DexTool.DX),