Always pick pinned argument register in 4 bit register allocation

Some older Android runtimes expect the receiver `this` to always be present in the incoming argument register. The register allocator therefore extends the live range of the `this` value to cover the entire method.

Due to invoke/range instructions, the live intervals for the `this` value may be split. The split children covering invoke/range instructions are minimal by construction. All the other split children that do not overlap any invoke/range instructions must be assigned the argument's incoming register.

This was already the case in 8 bit and 16 bit register allocation, but the 4 bit register allocation did not cover this case. This meant that in some cases, register allocation would materialize move instructions from the incoming argument register of `this` to a different register, which was effectively unused.

This issue is avoided by ensuring that all split children not covering an invoke/range instruction are assigned the incoming argument register of `this`.

Bug: b/468253695
Change-Id: Ib8c083bc2a5e5b36a02ff9353242fbe4304c2c12
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 0672473..5f19bfb 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
@@ -2056,7 +2056,8 @@
     // avoid move generation for the argument.
     if (isPinnedArgumentRegister(unhandledInterval)) {
       if (registerConstraint == Constants.U16BIT_MAX
-          || (mode.is8Bit() && registerConstraint == Constants.U8BIT_MAX)) {
+          || (mode.is8Bit() && registerConstraint == Constants.U8BIT_MAX)
+          || (mode.is4Bit() && registerConstraint == Constants.U4BIT_MAX)) {
         int argumentRegister = unhandledInterval.getSplitParent().getRegister();
         assignFreeRegisterToUnhandledInterval(unhandledInterval, argumentRegister);
         return true;