Delete dead code in register allocator

This also removes the previous/next consecutive pointers from Value.

Change-Id: Ie0e3a77e21c83250058e0914731ad742e3dc203d
diff --git a/src/main/java/com/android/tools/r8/ir/code/IRCode.java b/src/main/java/com/android/tools/r8/ir/code/IRCode.java
index 631034e..25c51c9 100644
--- a/src/main/java/com/android/tools/r8/ir/code/IRCode.java
+++ b/src/main/java/com/android/tools/r8/ir/code/IRCode.java
@@ -1156,7 +1156,7 @@
   }
 
   public Iterator<Argument> argumentIterator() {
-    return new Iterator<Argument>() {
+    return new Iterator<>() {
 
       private final InstructionIterator instructionIterator = entryBlock().iterator();
       private Argument next = instructionIterator.next().asArgument();
@@ -1178,6 +1178,10 @@
     };
   }
 
+  public Iterable<Argument> arguments() {
+    return () -> argumentIterator();
+  }
+
   public List<Value> collectArguments() {
     return collectArguments(false);
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/Invoke.java b/src/main/java/com/android/tools/r8/ir/code/Invoke.java
index b4dc0ec..b284aa5 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Invoke.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Invoke.java
@@ -241,13 +241,13 @@
     if (arguments().isEmpty()) {
       return false;
     }
-    Value current = getFirstArgument();
-    if (!current.isArgument()) {
+    Argument current = getFirstArgument().getDefinitionOrNull(Instruction::isArgument);
+    if (current == null) {
       return false;
     }
     for (int i = 1; i < arguments().size(); i++) {
-      Value next = getArgument(i);
-      if (current.getNextConsecutive() != next) {
+      Argument next = getArgument(i).getDefinitionOrNull(Instruction::isArgument);
+      if (current.getNext() != next) {
         return false;
       }
       current = next;
diff --git a/src/main/java/com/android/tools/r8/ir/code/Value.java b/src/main/java/com/android/tools/r8/ir/code/Value.java
index b140e11..d782e2b 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Value.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Value.java
@@ -12,7 +12,6 @@
 import static com.android.tools.r8.ir.code.Opcodes.DEX_ITEM_BASED_CONST_STRING;
 import static com.android.tools.r8.ir.code.Opcodes.INSTANCE_OF;
 
-import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
@@ -33,7 +32,6 @@
 import com.android.tools.r8.ir.regalloc.LiveIntervals;
 import com.android.tools.r8.position.MethodPosition;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.IterableUtils;
 import com.android.tools.r8.utils.LongInterval;
 import com.android.tools.r8.utils.ObjectUtils;
@@ -180,8 +178,6 @@
   private LinkedList<Phi> phiUsers = new LinkedList<>();
 
   private Set<Phi> uniquePhiUsers = null;
-  private Value nextConsecutive = null;
-  private Value previousConsecutive = null;
   private LiveIntervals liveIntervals;
   private int needsRegister = -1;
   private boolean isThis = false;
@@ -213,6 +209,14 @@
     return definition;
   }
 
+  @SuppressWarnings({"TypeParameterUnusedInFormals", "unchecked"})
+  public <T extends Instruction> T getDefinitionOrNull(Predicate<Instruction> predicate) {
+    if (definition != null && predicate.test(definition)) {
+      return (T) definition;
+    }
+    return null;
+  }
+
   public boolean hasAliasedValue() {
     return getAliasedValue() != this;
   }
@@ -306,47 +310,6 @@
     end.addDebugValue(this);
   }
 
-  public void linkTo(Value other) {
-    assert nextConsecutive == null || nextConsecutive == other;
-    assert other.previousConsecutive == null || other.previousConsecutive == this;
-    other.previousConsecutive = this;
-    nextConsecutive = other;
-  }
-
-  public void replaceLink(Value newArgument) {
-    assert isLinked();
-    if (previousConsecutive != null) {
-      previousConsecutive.nextConsecutive = newArgument;
-      newArgument.previousConsecutive = previousConsecutive;
-      previousConsecutive = null;
-    }
-    if (nextConsecutive != null) {
-      nextConsecutive.previousConsecutive = newArgument;
-      newArgument.nextConsecutive = nextConsecutive;
-      nextConsecutive = null;
-    }
-  }
-
-  public boolean isLinked() {
-    return nextConsecutive != null || previousConsecutive != null;
-  }
-
-  public Value getStartOfConsecutive() {
-    Value current = this;
-    while (current.getPreviousConsecutive() != null) {
-      current = current.getPreviousConsecutive();
-    }
-    return current;
-  }
-
-  public Value getNextConsecutive() {
-    return nextConsecutive;
-  }
-
-  public Value getPreviousConsecutive() {
-    return previousConsecutive;
-  }
-
   public boolean onlyUsedInBlock(BasicBlock block) {
     if (hasPhiUsers() || hasDebugUsers()) {
       return false;
@@ -783,15 +746,6 @@
     return false;
   }
 
-  public boolean hasRegisterConstraint() {
-    for (Instruction instruction : uniqueUsers()) {
-      if (instruction.maxInValueRegister() != Constants.U16BIT_MAX) {
-        return true;
-      }
-    }
-    return false;
-  }
-
   public boolean isValueOnStack() {
     return false;
   }
@@ -897,11 +851,6 @@
         && getConstInstruction().asConstNumber().getRawValue() == rawValue;
   }
 
-  public boolean isConstBoolean(boolean value) {
-    return isConstNumber()
-        && definition.asConstNumber().getRawValue() == BooleanUtils.longValue(value);
-  }
-
   public boolean isConstZero() {
     return isConstNumber() && definition.asConstNumber().isZero();
   }
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 c66b0eb..185cce6 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
@@ -256,6 +256,11 @@
 
   private final Timing timing;
 
+  Iterable<LiveIntervals> getArgumentLiveIntervals() {
+    return Iterables.transform(
+        code.arguments(), argument -> argument.outValue().getLiveIntervals());
+  }
+
   // Whether or not the code has a move exception instruction. Used to pin the move exception
   // register.
   private boolean hasDedicatedMoveExceptionRegister() {
@@ -352,7 +357,6 @@
   @Override
   public void allocateRegisters() {
     // There are no linked values prior to register allocation.
-    assert noLinkedValues();
     assert code.isConsistentSSA(appView);
     if (this.code.method().accessFlags.isBridge() && implementationIsBridge(this.code)) {
       transformBridgeMethod();
@@ -1011,10 +1015,7 @@
     }
     Reference2IntMap<LiveIntervals> originalRegisterAssignment = new Reference2IntOpenHashMap<>();
     originalRegisterAssignment.defaultReturnValue(NO_REGISTER);
-    for (Value current = firstArgumentValue;
-        current != null;
-        current = current.getNextConsecutive()) {
-      LiveIntervals intervals = current.getLiveIntervals();
+    for (LiveIntervals intervals : getArgumentLiveIntervals()) {
       int conservativeRealRegisterEnd = realRegisterNumberFromAllocated(intervals.getRegisterEnd());
       assert !mode.hasRegisterConstraint(intervals)
           || (mode.is8BitRefinement()
@@ -1145,10 +1146,8 @@
     timing.end();
 
     timing.begin("Argument linked");
-    for (Value argumentValue = firstArgumentValue;
-        argumentValue != null;
-        argumentValue = argumentValue.getNextConsecutive()) {
-      allocateRegistersForInvokeRangeSplits(argumentValue.getLiveIntervals());
+    for (LiveIntervals argumentLiveIntervals : getArgumentLiveIntervals()) {
+      allocateRegistersForInvokeRangeSplits(argumentLiveIntervals);
     }
     timing.end();
 
@@ -1199,18 +1198,14 @@
   }
 
   private void processArgumentLiveIntervals() {
-    for (Value argumentValue = firstArgumentValue;
-        argumentValue != null;
-        argumentValue = argumentValue.getNextConsecutive()) {
-      LiveIntervals argumentInterval = argumentValue.getLiveIntervals();
+    for (LiveIntervals argumentInterval : getArgumentLiveIntervals()) {
       assert argumentInterval.hasRegister();
       argumentInterval.setHandled();
       if (!mode.hasRegisterConstraint(argumentInterval)) {
         // All the argument intervals are active in the beginning and have preallocated registers.
         active.add(argumentInterval);
       } else if (mode.is8BitRefinement()
-          && argumentInterval.getRegister() + argumentValue.requiredRegisters()
-              <= numberOf4BitArgumentRegisters) {
+          && argumentInterval.getRegisterEnd() < numberOf4BitArgumentRegisters) {
         active.add(argumentInterval);
       } else {
         // Treat the argument interval as spilled which will require a load to a different
@@ -1419,10 +1414,7 @@
 
   private boolean verifyRegisterAssignmentNotConflictingWithArgument(LiveIntervals interval) {
     assert interval.hasRegister();
-    for (Value argumentValue = firstArgumentValue;
-        argumentValue != null;
-        argumentValue = argumentValue.getNextConsecutive()) {
-      LiveIntervals argumentIntervals = argumentValue.getLiveIntervals();
+    for (LiveIntervals argumentIntervals : getArgumentLiveIntervals()) {
       assert interval.getSplitParent() == argumentIntervals
           || !isPinnedArgumentRegister(argumentIntervals)
           || !interval.hasConflictingRegisters(argumentIntervals)
@@ -1623,10 +1615,7 @@
         // Exclude the pinned argument registers for which there exists a split that overlaps with
         // one of the inputs to the invoke-range instruction.
         timing.begin("Exclude pinned args");
-        for (Value argument = firstArgumentValue;
-            argument != null;
-            argument = argument.getNextConsecutive()) {
-          LiveIntervals argumentLiveIntervals = argument.getLiveIntervals();
+        for (LiveIntervals argumentLiveIntervals : getArgumentLiveIntervals()) {
           if (isPinnedArgumentRegister(argumentLiveIntervals)
               && liveIntervalsOverlappingAnyOf(argumentLiveIntervals, intervalsList)) {
             excludeRegistersForInterval(argumentLiveIntervals);
@@ -2186,10 +2175,9 @@
         firstArgumentValue.getLiveIntervals().forEachRegister(freePositions::setBlocked);
       }
       // But not any of the other argument registers.
-      for (Value argument = firstArgumentValue;
-          argument != null;
-          argument = argument.getNextConsecutive()) {
-        assert !isPinnedArgumentRegister(argument.getLiveIntervals()) || argument.isThis();
+      for (LiveIntervals argumentIntervals : getArgumentLiveIntervals()) {
+        assert !isPinnedArgumentRegister(argumentIntervals)
+            || argumentIntervals.getValue().isThis();
       }
     } else {
       // Generally argument reuse is not allowed and we block all the argument registers so that
@@ -2202,10 +2190,8 @@
       if (mode.is8BitRefinement()) {
         assert numberOf4BitArgumentRegisters > 0;
         int remainingNumberOf4BitArgumentRegisters = numberOf4BitArgumentRegisters;
-        for (Value argumentValue = firstArgumentValue;
-            argumentValue != null;
-            argumentValue = argumentValue.getNextConsecutive()) {
-          int requiredRegisters = argumentValue.requiredRegisters();
+        for (LiveIntervals argumentLiveIntervals : getArgumentLiveIntervals()) {
+          int requiredRegisters = argumentLiveIntervals.requiredRegisters();
           remainingNumberOf4BitArgumentRegisters -= requiredRegisters;
           if (remainingNumberOf4BitArgumentRegisters < 0) {
             // Block all subsequent argument registers.
@@ -2214,7 +2200,7 @@
           // Block this argument register if there is any overlap between the two live intervals.
           // TODO(b/374266460): Allow using the argument register even when there are overlapping
           //  live intervals.
-          if (argumentValue.getLiveIntervals().anySplitOverlaps(unhandledInterval)) {
+          if (argumentLiveIntervals.anySplitOverlaps(unhandledInterval)) {
             for (int j = 0; j < requiredRegisters; j++) {
               freePositions.setBlocked(i + j);
             }
@@ -2413,10 +2399,8 @@
       return false;
     }
     if (isArgumentRegister(candidate)) {
-      for (Value argument = firstArgumentValue;
-          argument != null;
-          argument = argument.getNextConsecutive()) {
-        if (isPinnedArgument(argument)) {
+      for (LiveIntervals argumentLiveIntervals : getArgumentLiveIntervals()) {
+        if (isPinnedArgumentRegister(argumentLiveIntervals)) {
           return false;
         }
       }
@@ -2860,24 +2844,11 @@
 
   protected void splitOverlappingInactiveIntervals(
       LiveIntervals unhandledInterval, int candidate, boolean candidateIsWide) {
-    List<LiveIntervals> newInactive = new ArrayList<>();
     Iterator<LiveIntervals> inactiveIterator = inactive.iterator();
     while (inactiveIterator.hasNext()) {
       LiveIntervals intervals = inactiveIterator.next();
       if (intervals.usesRegister(candidate, candidateIsWide)
           && intervals.overlaps(unhandledInterval)) {
-        if (intervals.isLinked() && !intervals.isArgumentInterval()) {
-          // If the inactive register is linked but not an argument, it needs to get the
-          // same register again at the next use after the start of the unhandled interval.
-          // If there are no such uses, we can use a different register for the remainder
-          // of the inactive interval and therefore do not have to split here.
-          int nextUsePosition = intervals.firstUseAfter(unhandledInterval.getStart());
-          if (nextUsePosition != Integer.MAX_VALUE) {
-            LiveIntervals split = intervals.splitBefore(nextUsePosition, mode);
-            split.setRegister(intervals.getRegister());
-            newInactive.add(split);
-          }
-        }
         if (intervals.getStart() > unhandledInterval.getStart()) {
           // The inactive live intervals hasn't started yet. Clear the temporary register
           // assignment and move back to unhandled for register reassignment.
@@ -2892,7 +2863,6 @@
         }
       }
     }
-    inactive.addAll(newInactive);
   }
 
   private void spillOverlappingActiveIntervals(
@@ -2939,19 +2909,14 @@
           intervals.setSpilled(true);
         }
         if (splitChild.hasUses()) {
-          if (splitChild.isLinked() && !splitChild.isArgumentInterval()) {
-            // Spilling a value with a pinned register. We need to move back at the next use.
-            LiveIntervals splitOfSplit = splitChild.splitBefore(splitChild.getFirstUse(), mode);
-            splitOfSplit.setRegister(intervals.getRegister());
-            inactive.add(splitOfSplit);
-          } else if (intervals.getValue().isConstNumber()) {
+          if (intervals.getValue().isConstNumber()) {
             // TODO(ager): Do this for all constants. Currently we only rematerialize const
             //  number and therefore we only do it for numbers at this point.
             splitRangesForSpilledConstant(splitChild, registerNumber);
           } else if (intervals.isArgumentInterval()) {
             splitRangesForSpilledArgument(splitChild);
           } else {
-            splitRangesForSpilledInterval(splitChild, registerNumber);
+            splitRangesForSpilledInterval(splitChild);
           }
         }
       }
@@ -2976,21 +2941,11 @@
     }
   }
 
-  private void splitRangesForSpilledInterval(LiveIntervals spilled, int registerNumber) {
+  private void splitRangesForSpilledInterval(LiveIntervals spilled) {
     // Spilling a non-pinned, non-rematerializable value. We use the value in the spill
     // register for as long as possible to avoid further moves.
     assert spilled.isSpilled();
     assert !spilled.getValue().isConstNumber();
-    assert !spilled.isLinked() || spilled.isArgumentInterval();
-    boolean isSpillingToArgumentRegister =
-        spilled.isArgumentInterval() || isArgumentRegister(registerNumber);
-    if (isSpillingToArgumentRegister) {
-      if (mode.is8Bit()) {
-        registerNumber = Constants.U8BIT_MAX;
-      } else {
-        registerNumber = Constants.U16BIT_MAX;
-      }
-    }
     LiveIntervalsUse firstUseWithConstraint = spilled.firstUseWithConstraint(mode);
     if (firstUseWithConstraint != null) {
       int register = spilled.getRegister();
@@ -3015,7 +2970,6 @@
     // as much as possible.
     assert spilled.isSpilled();
     assert spilled.getValue().isConstNumber();
-    assert !spilled.isLinked() || spilled.isArgumentInterval();
     // Do not split range if constant is reused by one of the eleven following instruction.
     int maxGapSize = 11 * INSTRUCTION_NUMBER_DELTA;
     LiveIntervalsUse firstUseWithConstraint = spilled.firstUseWithConstraint(mode);
@@ -3253,19 +3207,7 @@
       instructionNumber = instruction.getNumber();
     }
     if (value.getLiveIntervals() == null) {
-      Value current = value.getStartOfConsecutive();
-      LiveIntervals intervals = new LiveIntervals(current);
-      while (true) {
-        liveIntervals.add(intervals);
-        Value next = current.getNextConsecutive();
-        if (next == null) {
-          break;
-        }
-        LiveIntervals nextIntervals = new LiveIntervals(next);
-        intervals.link(nextIntervals);
-        current = next;
-        intervals = nextIntervals;
-      }
+      liveIntervals.add(new LiveIntervals(value));
     }
     LiveIntervals intervals = value.getLiveIntervals();
     if (firstInstructionInBlock <= instructionNumber &&
@@ -3585,10 +3527,13 @@
 
   private static boolean argumentsAreAlreadyLinked(Invoke invoke) {
     Iterator<Value> it = invoke.arguments().iterator();
-    Value current = it.next();
+    Argument current = it.next().getDefinitionOrNull(Instruction::isArgument);
+    if (current == null) {
+      return false;
+    }
     while (it.hasNext()) {
-      Value next = it.next();
-      if (!current.isLinked() || current.getNextConsecutive() != next) {
+      Argument next = it.next().getDefinitionOrNull(Instruction::isArgument);
+      if (current.getNext() != next) {
         return false;
       }
       current = next;
@@ -3614,7 +3559,6 @@
       Value last = firstArgumentValue = arguments.get(0);
       for (int i = 1; i < arguments.size(); ++i) {
         Value next = arguments.get(i);
-        last.linkTo(next);
         last.getLiveIntervals().link(next.getLiveIntervals());
         last = next;
       }
@@ -3660,12 +3604,9 @@
     if (firstArgumentValue != null) {
       increaseCapacity(numberOfArgumentRegisters - 1, true);
       int register = 0;
-      for (Value current = firstArgumentValue;
-          current != null;
-          current = current.getNextConsecutive()) {
-        LiveIntervals argumentLiveInterval = current.getLiveIntervals();
-        assignRegister(argumentLiveInterval, register);
-        register += current.requiredRegisters();
+      for (LiveIntervals argumentLiveIntervals : getArgumentLiveIntervals()) {
+        assignRegister(argumentLiveIntervals, register);
+        register += argumentLiveIntervals.requiredRegisters();
       }
     }
   }
@@ -3847,22 +3788,6 @@
     return !freeRegisters.contains(register) || (isWide && !freeRegisters.contains(register + 1));
   }
 
-  private boolean noLinkedValues() {
-    for (BasicBlock block : code.blocks) {
-      for (Phi phi : block.getPhis()) {
-        assert phi.getNextConsecutive() == null;
-      }
-      for (Instruction instruction : block.getInstructions()) {
-        for (Value value : instruction.inValues()) {
-          assert value.getNextConsecutive() == null;
-        }
-        assert instruction.outValue() == null ||
-            instruction.outValue().getNextConsecutive() == null;
-      }
-    }
-    return true;
-  }
-
   @Override
   public String toString() {
     StringBuilder builder = new StringBuilder("Live ranges:\n");
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 f423296..75fd057 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
@@ -154,10 +154,6 @@
     next.previousConsecutive = this;
   }
 
-  public boolean isLinked() {
-    return splitParent.previousConsecutive != null || splitParent.nextConsecutive != null;
-  }
-
   public boolean isArgumentInterval() {
     Instruction definition = this.splitParent.value.definition;
     return definition != null && definition.isArgument();
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/SpillMoveSet.java b/src/main/java/com/android/tools/r8/ir/regalloc/SpillMoveSet.java
index 2575d3b..736ed62 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/SpillMoveSet.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/SpillMoveSet.java
@@ -7,12 +7,12 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.ir.analysis.type.Nullability;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
+import com.android.tools.r8.ir.code.Argument;
 import com.android.tools.r8.ir.code.BasicBlock;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.InstructionListIterator;
 import com.android.tools.r8.ir.code.Position;
-import com.android.tools.r8.ir.code.Value;
 import com.android.tools.r8.utils.MapUtils;
 import java.util.Collection;
 import java.util.Collections;
@@ -135,12 +135,9 @@
           insertAt.next();
         }
         // Generate moves for each argument.
-        for (Value argumentValue = allocator.firstArgumentValue;
-            argumentValue != null;
-            argumentValue = argumentValue.getNextConsecutive()) {
-          Instruction instruction = argumentValue.definition;
-          if (needsMovesBeforeInstruction(instruction)) {
-            scheduleMovesBeforeInstruction(tempRegister, instruction, insertAt);
+        for (Argument argument : code.arguments()) {
+          if (needsMovesBeforeInstruction(argument)) {
+            scheduleMovesBeforeInstruction(tempRegister, argument, insertAt);
           }
         }
       }
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/UnsplitArgumentsResult.java b/src/main/java/com/android/tools/r8/ir/regalloc/UnsplitArgumentsResult.java
index 5b0810d..cf78fe1 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/UnsplitArgumentsResult.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/UnsplitArgumentsResult.java
@@ -5,7 +5,6 @@
 
 import static com.android.tools.r8.ir.regalloc.LiveIntervals.NO_REGISTER;
 
-import com.android.tools.r8.ir.code.Value;
 import it.unimi.dsi.fastutil.objects.Reference2IntMap;
 
 public class UnsplitArgumentsResult {
@@ -28,10 +27,8 @@
   // Returns true if any changes were made.
   public boolean revertPartial() {
     boolean changed = false;
-    for (Value argument = allocator.firstArgumentValue;
-        argument != null;
-        argument = argument.getNextConsecutive()) {
-      for (LiveIntervals child : argument.getLiveIntervals().getSplitChildren()) {
+    for (LiveIntervals argumentLiveIntervals : allocator.getArgumentLiveIntervals()) {
+      for (LiveIntervals child : argumentLiveIntervals.getSplitChildren()) {
         changed |= revertPartial(child);
       }
     }