Merge "Change register allocator to deal better with unconstrained uses."
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 33dc79a..a30f574 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
@@ -567,18 +567,18 @@
         active.add(argumentInterval);
       } else {
         // Treat the argument interval as spilled which will require a load to a different
-        // register for all usages.
+        // register for all register-constrained usages.
         if (argumentInterval.getUses().size() > 1) {
           LiveIntervalsUse use = argumentInterval.firstUseWithConstraint();
           if (use != null) {
             LiveIntervals split;
-            if (argumentInterval.getUses().size() == 2) {
-              // If there is only one real use (definition plus one real use), split before
+            if (argumentInterval.numberOfUsesWithConstraint() == 1) {
+              // If there is only one register-constrained use, split before
               // that one use.
               split = argumentInterval.splitBefore(use.getPosition());
             } else {
-              // If there are multiple real users, split right after the definition to make it
-              // more likely that arguments get in usable registers from the start.
+              // If there are multiple register-constrained users, split right after the definition
+              // to make it more likely that arguments get in usable registers from the start.
               split = argumentInterval
                   .splitBefore(argumentInterval.getValue().definition.getNumber() + 1);
             }
@@ -1004,7 +1004,24 @@
         // argument reuse disallowed.
         return false;
       }
-      allocateBlockedRegister(unhandledInterval);
+      // If the first use for these intervals is unconstrained, just spill this interval instead
+      // of finding another candidate to spill via allocateBlockedRegister.
+      if (!unhandledInterval.getUses().first().hasConstraint()) {
+        int nextConstrainedPosition = unhandledInterval.firstUseWithConstraint().getPosition();
+        int register;
+        // Arguments are always in the argument registers, so for arguments just use that register
+        // for the unconstrained prefix. For everything else, get a spill register.
+        if (unhandledInterval.isArgumentInterval()) {
+          register = unhandledInterval.getSplitParent().getRegister();
+        } else {
+          register = getSpillRegister(unhandledInterval);
+        }
+        LiveIntervals split = unhandledInterval.splitBefore(nextConstrainedPosition);
+        assignRegisterToUnhandledInterval(unhandledInterval, needsRegisterPair, register);
+        unhandled.add(split);
+      } else {
+        allocateBlockedRegister(unhandledInterval);
+      }
     } else if (largestFreePosition >= unhandledInterval.getEnd()) {
       // Free for the entire interval. Allocate the register.
       assignRegisterToUnhandledInterval(unhandledInterval, needsRegisterPair, candidate);
@@ -1016,8 +1033,7 @@
       }
       // The candidate is free for the beginning of an interval. We split the interval
       // and use the register for as long as we can.
-      int splitPosition = largestFreePosition;
-      LiveIntervals split = unhandledInterval.splitBefore(splitPosition);
+      LiveIntervals split = unhandledInterval.splitBefore(largestFreePosition);
       assert split != unhandledInterval;
       assignRegisterToUnhandledInterval(unhandledInterval, needsRegisterPair, candidate);
       unhandled.add(split);
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/LiveIntervals.java b/src/main/java/com/android/tools/r8/ir/regalloc/LiveIntervals.java
index cf44137..f01ed3a 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/LiveIntervals.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/LiveIntervals.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.ir.regalloc;
 
+import static com.android.tools.r8.dex.Constants.U16BIT_MAX;
 import static com.android.tools.r8.ir.regalloc.LinearScanRegisterAllocator.NO_REGISTER;
 
 import com.android.tools.r8.dex.Constants;
@@ -29,7 +30,7 @@
   private boolean spilled = false;
 
   // Only registers up to and including the registerLimit are allowed for this interval.
-  private int registerLimit = Constants.U16BIT_MAX;
+  private int registerLimit = U16BIT_MAX;
 
   // Max register used for any of the non-spilled splits for these live intervals or for any of the
   // live intervals that this live interval is connected to by phi moves. This is used to
@@ -331,7 +332,7 @@
 
   public LiveIntervalsUse firstUseWithConstraint() {
     for (LiveIntervalsUse use : uses) {
-      if (use.getLimit() < Constants.U16BIT_MAX) {
+      if (use.hasConstraint()) {
         return use;
       }
     }
@@ -386,13 +387,14 @@
   }
 
   private void recomputeLimit() {
-    registerLimit = Constants.U16BIT_MAX;
+    registerLimit = U16BIT_MAX;
     for (LiveIntervalsUse use : uses) {
       updateRegisterConstraint(use.getLimit());
     }
   }
 
   public LiveIntervals getSplitCovering(int instructionNumber) {
+    assert getSplitParent() == this;
     // Check if this interval itself is covering the instruction.
     if (getStart() <= instructionNumber && getEnd() > instructionNumber) {
       return this;
@@ -417,6 +419,20 @@
     return null;
   }
 
+  public boolean isConstantNumberInterval() {
+    return value.definition != null && value.definition.isConstNumber();
+  }
+
+  public int numberOfUsesWithConstraint() {
+    int count = 0;
+    for (LiveIntervalsUse use : getUses()) {
+      if (use.hasConstraint()) {
+        count++;
+      }
+    }
+    return count;
+  }
+
   @Override
   public String toString() {
     StringBuilder builder = new StringBuilder();
@@ -468,8 +484,4 @@
       splitChild.print(printer, number + delta, number);
     }
   }
-
-  public boolean isConstantNumberInterval() {
-    return value.definition != null && value.definition.isConstNumber();
-  }
-}
\ No newline at end of file
+}
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/LiveIntervalsUse.java b/src/main/java/com/android/tools/r8/ir/regalloc/LiveIntervalsUse.java
index fd37af8..a602134 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/LiveIntervalsUse.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/LiveIntervalsUse.java
@@ -3,6 +3,8 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.ir.regalloc;
 
+import static com.android.tools.r8.dex.Constants.U16BIT_MAX;
+
 public class LiveIntervalsUse implements Comparable<LiveIntervalsUse> {
   private int position;
   private int limit;
@@ -41,4 +43,8 @@
     }
     return limit - o.limit;
   }
+
+  public boolean hasConstraint() {
+    return limit < U16BIT_MAX;
+  }
 }