Merge "Ensure that there are materializing instructions before long add/sub operations."
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index b116e65..d7f1fa8 100644
--- a/src/main/java/com/android/tools/r8/Version.java
+++ b/src/main/java/com/android/tools/r8/Version.java
@@ -11,7 +11,7 @@
 
   // This field is accessed from release scripts using simple pattern matching.
   // Therefore, changing this field could break our release scripts.
-  public static final String LABEL = "v1.2.14-dev";
+  public static final String LABEL = "v1.2.15-dev";
 
   private Version() {
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java b/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
index fb75931..d59df07 100644
--- a/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
+++ b/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
@@ -48,10 +48,7 @@
       assert instruction.getBlock() == this;
       assert !instruction.isArgument() || argumentsAllowed;
       assert !instruction.isDebugLocalRead() || !instruction.getDebugValues().isEmpty();
-      // TODO(b/79186787): Ensure DEX backend inserts Move *after* arguments.
-      if (!(instruction.isArgument()
-          || instruction.isMove()
-          || instruction.isDebugLocalsChange())) {
+      if (!instruction.isArgument()) {
         argumentsAllowed = 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 d264385..e9504cd 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
@@ -103,7 +103,7 @@
   }
 
   protected int argumentRegisterValue(int i, DexBuilder builder) {
-    assert needsRangedInvoke();
+    assert needsRangedInvoke(builder);
     if (i < arguments().size()) {
       // If argument values flow into ranged invokes, all the ranged invoke arguments
       // are arguments to this method in order. Therefore, we use the incoming registers
@@ -116,7 +116,7 @@
   }
 
   protected int fillArgumentRegisters(DexBuilder builder, int[] registers) {
-    assert !needsRangedInvoke();
+    assert !needsRangedInvoke(builder);
     int i = 0;
     for (Value value : arguments()) {
       int register = builder.allocatedRegister(value, getNumber());
@@ -198,12 +198,25 @@
     return true;
   }
 
-  protected boolean needsRangedInvoke() {
+  protected boolean needsRangedInvoke(DexBuilder builder) {
+    if (requiredArgumentRegisters() > 5) {
+      // No way around using an invoke-range instruction.
+      return true;
+    }
     // By using an invoke-range instruction when there is only one argument, we avoid having to
     // satisfy the constraint that the argument register(s) must fit in 4 bits.
-    return arguments().size() == 1
-        || requiredArgumentRegisters() > 5
-        || argumentsAreConsecutiveInputArguments();
+    boolean registersGuaranteedToBeConsecutive =
+        arguments().size() == 1 || argumentsAreConsecutiveInputArguments();
+    if (!registersGuaranteedToBeConsecutive) {
+      // No way that we will need an invoke-range.
+      return false;
+    }
+    // If we could use an invoke-range instruction, but all the registers fit in 4 bits, then we
+    // use a non-range invoke.
+    assert argumentsConsecutive(builder);
+    int registerStart = builder.argumentOrAllocateRegister(arguments().get(0), getNumber());
+    int registerEnd = registerStart + requiredArgumentRegisters() - 1;
+    return registerEnd > Constants.U4BIT_MAX;
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeCustom.java b/src/main/java/com/android/tools/r8/ir/code/InvokeCustom.java
index 9d95514..0579362 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeCustom.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeCustom.java
@@ -54,7 +54,7 @@
     com.android.tools.r8.code.Instruction instruction;
     int argumentRegisters = requiredArgumentRegisters();
     builder.requestOutgoingRegisters(argumentRegisters);
-    if (needsRangedInvoke()) {
+    if (needsRangedInvoke(builder)) {
       assert argumentsConsecutive(builder);
       int firstRegister = argumentRegisterValue(0, builder);
       instruction = new InvokeCustomRange(firstRegister, argumentRegisters, getCallSite());
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java b/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java
index 1c4a1d7..b343de7 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java
@@ -52,7 +52,7 @@
     com.android.tools.r8.code.Instruction instruction;
     int argumentRegisters = requiredArgumentRegisters();
     builder.requestOutgoingRegisters(argumentRegisters);
-    if (needsRangedInvoke()) {
+    if (needsRangedInvoke(builder)) {
       assert argumentsConsecutive(builder);
       int firstRegister = argumentRegisterValue(0, builder);
       instruction = new InvokeDirectRange(firstRegister, argumentRegisters, getInvokedMethod());
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeInterface.java b/src/main/java/com/android/tools/r8/ir/code/InvokeInterface.java
index 61eb906..ff8f0d0 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeInterface.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeInterface.java
@@ -46,7 +46,7 @@
     com.android.tools.r8.code.Instruction instruction;
     int argumentRegisters = requiredArgumentRegisters();
     builder.requestOutgoingRegisters(argumentRegisters);
-    if (needsRangedInvoke()) {
+    if (needsRangedInvoke(builder)) {
       assert argumentsConsecutive(builder);
       int firstRegister = argumentRegisterValue(0, builder);
       instruction = new InvokeInterfaceRange(firstRegister, argumentRegisters, getInvokedMethod());
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeNewArray.java b/src/main/java/com/android/tools/r8/ir/code/InvokeNewArray.java
index 3be2e10..96680b3 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeNewArray.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeNewArray.java
@@ -56,7 +56,7 @@
     com.android.tools.r8.code.Instruction instruction;
     int argumentRegisters = requiredArgumentRegisters();
     builder.requestOutgoingRegisters(argumentRegisters);
-    if (needsRangedInvoke()) {
+    if (needsRangedInvoke(builder)) {
       assert argumentsConsecutive(builder);
       int firstRegister = argumentRegisterValue(0, builder);
       instruction = new FilledNewArrayRange(firstRegister, argumentRegisters, type);
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokePolymorphic.java b/src/main/java/com/android/tools/r8/ir/code/InvokePolymorphic.java
index 5ac7239..d280dfe 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokePolymorphic.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokePolymorphic.java
@@ -60,7 +60,7 @@
     com.android.tools.r8.code.Instruction instruction;
     int argumentRegisters = requiredArgumentRegisters();
     builder.requestOutgoingRegisters(argumentRegisters);
-    if (needsRangedInvoke()) {
+    if (needsRangedInvoke(builder)) {
       assert argumentsConsecutive(builder);
       int firstRegister = argumentRegisterValue(0, builder);
       instruction = new InvokePolymorphicRange(
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java b/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java
index 12db6d5..94df8d3 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java
@@ -53,7 +53,7 @@
     com.android.tools.r8.code.Instruction instruction;
     int argumentRegisters = requiredArgumentRegisters();
     builder.requestOutgoingRegisters(argumentRegisters);
-    if (needsRangedInvoke()) {
+    if (needsRangedInvoke(builder)) {
       assert argumentsConsecutive(builder);
       int firstRegister = argumentRegisterValue(0, builder);
       instruction = new InvokeStaticRange(firstRegister, argumentRegisters, getInvokedMethod());
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeSuper.java b/src/main/java/com/android/tools/r8/ir/code/InvokeSuper.java
index 2691069..e5bd604 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeSuper.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeSuper.java
@@ -58,7 +58,7 @@
     com.android.tools.r8.code.Instruction instruction;
     int argumentRegisters = requiredArgumentRegisters();
     builder.requestOutgoingRegisters(argumentRegisters);
-    if (needsRangedInvoke()) {
+    if (needsRangedInvoke(builder)) {
       assert argumentsConsecutive(builder);
       int firstRegister = argumentRegisterValue(0, builder);
       instruction = new InvokeSuperRange(firstRegister, argumentRegisters, getInvokedMethod());
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java b/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java
index 4ad7a79..d104270 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java
@@ -46,7 +46,7 @@
     com.android.tools.r8.code.Instruction instruction;
     int argumentRegisters = requiredArgumentRegisters();
     builder.requestOutgoingRegisters(argumentRegisters);
-    if (needsRangedInvoke()) {
+    if (needsRangedInvoke(builder)) {
       assert argumentsConsecutive(builder);
       int firstRegister = argumentRegisterValue(0, builder);
       instruction = new InvokeVirtualRange(firstRegister, argumentRegisters, getInvokedMethod());
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 769c281..de85da5 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
@@ -125,7 +125,9 @@
   // Mapping from basic blocks to the set of values live at entry to that basic block.
   private Map<BasicBlock, Set<Value>> liveAtEntrySets;
   // The value of the first argument, or null if the method has no arguments.
-  private Value firstArgumentValue;
+  protected Value firstArgumentValue;
+  // The value of the last argument, or null if the method has no arguments.
+  private Value lastArgumentValue;
 
   // The set of registers that are free for allocation.
   private TreeSet<Integer> freeRegisters = new TreeSet<>();
@@ -2511,7 +2513,8 @@
       Invoke invoke, PriorityQueue<Move> insertAtDefinition, InstructionListIterator insertAt) {
     Move move = insertAtDefinition.poll();
     // Rewind instruction iterator to the position where the first move needs to be inserted.
-    Instruction previousDefinition = move.src().definition;
+    Instruction previousDefinition =
+        move.src().isArgument() ? lastArgumentValue.definition : move.src().definition;
     while (insertAt.peekPrevious() != previousDefinition) {
       insertAt.previous();
     }
@@ -2519,7 +2522,8 @@
     insertAt.add(move);
     while (!insertAtDefinition.isEmpty()) {
       move = insertAtDefinition.poll();
-      Instruction currentDefinition = move.src().definition;
+      Instruction currentDefinition =
+          move.src().isArgument() ? lastArgumentValue.definition : move.src().definition;
       assert currentDefinition.getNumber() >= previousDefinition.getNumber();
       if (currentDefinition.getNumber() > previousDefinition.getNumber()) {
         // Move the instruction iterator forward to where this move needs to be inserted.
@@ -2572,6 +2576,7 @@
         last.getLiveIntervals().link(next.getLiveIntervals());
         last = next;
       }
+      lastArgumentValue = last;
     }
   }
 
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 3401b17..1ea788d 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
@@ -10,6 +10,7 @@
 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 java.util.Collection;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -119,17 +120,33 @@
    */
   public int scheduleAndInsertMoves(int tempRegister) {
     for (BasicBlock block : code.blocks) {
-      InstructionListIterator it = block.listIterator();
-      while (it.hasNext()) {
-        Instruction instruction = it.next();
+      InstructionListIterator insertAt = block.listIterator();
+      if (block == code.blocks.getFirst()) {
+        // Move insertAt iterator to the first non-argument, such that moves for the arguments will
+        // be inserted after the last argument.
+        while (insertAt.hasNext() && insertAt.peekNext().isArgument()) {
+          insertAt.next();
+        }
+        // Generate moves for each argument.
+        for (Value argumentValue = allocator.firstArgumentValue;
+            argumentValue != null;
+            argumentValue = argumentValue.getNextConsecutive()) {
+          Instruction instruction = argumentValue.definition;
+          int number = instruction.getNumber();
+          if (needsMovesBeforeInstruction(number)) {
+            scheduleMovesBeforeInstruction(tempRegister, instruction, insertAt);
+          }
+        }
+      }
+
+      while (insertAt.hasNext()) {
+        Instruction instruction = insertAt.peekNext();
+        assert !instruction.isArgument();
         int number = instruction.getNumber();
         if (needsMovesBeforeInstruction(number)) {
-          // Move back so moves are inserted before the instruction.
-          it.previous();
-          scheduleMovesBeforeInstruction(tempRegister, number, it);
-          // Move past the instruction again.
-          it.next();
+          scheduleMovesBeforeInstruction(tempRegister, instruction, insertAt);
         }
+        insertAt.next();
       }
     }
     return usedTempRegisters;
@@ -218,14 +235,15 @@
   }
 
   private void scheduleMovesBeforeInstruction(
-      int tempRegister, int instruction, InstructionListIterator insertAt) {
+      int tempRegister, Instruction instruction, InstructionListIterator insertAt) {
+    int number = instruction.getNumber();
 
     Position position;
     if (insertAt.hasPrevious() && insertAt.peekPrevious().isMoveException()) {
       position = insertAt.peekPrevious().getPosition();
     } else {
       Instruction next = insertAt.peekNext();
-      assert next.getNumber() == instruction;
+      assert next.getNumber() == number || instruction.isArgument();
       position = next.getPosition();
       if (position.isNone() && next.isGoto()) {
         position = next.asGoto().getTarget().getPosition();
@@ -234,17 +252,17 @@
 
     // Spill and restore moves for the incoming edge.
     Set<SpillMove> inMoves =
-        instructionToInMoves.computeIfAbsent(instruction - 1, (k) -> new LinkedHashSet<>());
+        instructionToInMoves.computeIfAbsent(number - 1, (k) -> new LinkedHashSet<>());
     removeArgumentRestores(inMoves);
 
     // Spill and restore moves for the outgoing edge.
     Set<SpillMove> outMoves =
-        instructionToOutMoves.computeIfAbsent(instruction - 1, (k) -> new LinkedHashSet<>());
+        instructionToOutMoves.computeIfAbsent(number - 1, (k) -> new LinkedHashSet<>());
     removeArgumentRestores(outMoves);
 
     // Get the phi moves for this instruction and schedule them with the out going spill moves.
     Set<SpillMove> phiMoves =
-        instructionToPhiMoves.computeIfAbsent(instruction - 1, (k) -> new LinkedHashSet<>());
+        instructionToPhiMoves.computeIfAbsent(number - 1, (k) -> new LinkedHashSet<>());
 
     // Remove/rewrite moves that we can guarantee will not be needed.
     pruneParallelMoveSets(inMoves, outMoves, phiMoves);
diff --git a/src/test/java/com/android/tools/r8/bridgeremoval/B77836766.java b/src/test/java/com/android/tools/r8/bridgeremoval/B77836766.java
index 5c4a79e..5ec1bce 100644
--- a/src/test/java/com/android/tools/r8/bridgeremoval/B77836766.java
+++ b/src/test/java/com/android/tools/r8/bridgeremoval/B77836766.java
@@ -10,7 +10,7 @@
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.ToolHelper.ProcessResult;
-import com.android.tools.r8.code.InvokeVirtualRange;
+import com.android.tools.r8.code.InvokeVirtual;
 import com.android.tools.r8.code.ReturnVoid;
 import com.android.tools.r8.graph.DexCode;
 import com.android.tools.r8.jasmin.JasminBuilder;
@@ -144,20 +144,16 @@
         cls2Subject.method("void", "foo", ImmutableList.of("java.lang.Integer"));
     assertThat(fooInCls2, isPresent());
     DexCode code = fooInCls2.getMethod().getCode().asDexCode();
-    checkInstructions(code, ImmutableList.of(
-        InvokeVirtualRange.class,
-        ReturnVoid.class));
-    InvokeVirtualRange invoke = (InvokeVirtualRange) code.instructions[0];
+    checkInstructions(code, ImmutableList.of(InvokeVirtual.class, ReturnVoid.class));
+    InvokeVirtual invoke = (InvokeVirtual) code.instructions[0];
     assertEquals(absSubject.getDexClass().type, invoke.getMethod().getHolder());
 
     MethodSubject fooInCls1 =
         cls1Subject.method("void", "foo", ImmutableList.of("java.lang.String"));
     assertThat(fooInCls1, isPresent());
     code = fooInCls1.getMethod().getCode().asDexCode();
-    checkInstructions(code, ImmutableList.of(
-        InvokeVirtualRange.class,
-        ReturnVoid.class));
-    invoke = (InvokeVirtualRange) code.instructions[0];
+    checkInstructions(code, ImmutableList.of(InvokeVirtual.class, ReturnVoid.class));
+    invoke = (InvokeVirtual) code.instructions[0];
     assertEquals(absSubject.getDexClass().type, invoke.getMethod().getHolder());
   }
 
@@ -254,20 +250,16 @@
         cls2Subject.method("void", "bar", ImmutableList.of("java.lang.String"));
     assertThat(barInCls2, isPresent());
     DexCode code = barInCls2.getMethod().getCode().asDexCode();
-    checkInstructions(code, ImmutableList.of(
-        InvokeVirtualRange.class,
-        ReturnVoid.class));
-    InvokeVirtualRange invoke = (InvokeVirtualRange) code.instructions[0];
+    checkInstructions(code, ImmutableList.of(InvokeVirtual.class, ReturnVoid.class));
+    InvokeVirtual invoke = (InvokeVirtual) code.instructions[0];
     assertEquals(baseSubject.getDexClass().type, invoke.getMethod().getHolder());
 
     MethodSubject fooInCls1 =
         cls1Subject.method("void", "foo", ImmutableList.of("java.lang.Integer"));
     assertThat(fooInCls1, isPresent());
     code = fooInCls1.getMethod().getCode().asDexCode();
-    checkInstructions(code, ImmutableList.of(
-        InvokeVirtualRange.class,
-        ReturnVoid.class));
-    invoke = (InvokeVirtualRange) code.instructions[0];
+    checkInstructions(code, ImmutableList.of(InvokeVirtual.class, ReturnVoid.class));
+    invoke = (InvokeVirtual) code.instructions[0];
     assertEquals(baseSubject.getDexClass().type, invoke.getMethod().getHolder());
   }
 
@@ -352,10 +344,8 @@
         subSubject.method("void", "bar", ImmutableList.of("java.lang.String"));
     assertThat(barInSub, isPresent());
     DexCode code = barInSub.getMethod().getCode().asDexCode();
-    checkInstructions(code, ImmutableList.of(
-        InvokeVirtualRange.class,
-        ReturnVoid.class));
-    InvokeVirtualRange invoke = (InvokeVirtualRange) code.instructions[0];
+    checkInstructions(code, ImmutableList.of(InvokeVirtual.class, ReturnVoid.class));
+    InvokeVirtual invoke = (InvokeVirtual) code.instructions[0];
     assertEquals(baseSubject.getDexClass().type, invoke.getMethod().getHolder());
   }
 
@@ -428,10 +418,8 @@
         baseSubject.method("void", "bar", ImmutableList.of("java.lang.String"));
     assertThat(barInSub, isPresent());
     DexCode code = barInSub.getMethod().getCode().asDexCode();
-    checkInstructions(code, ImmutableList.of(
-        InvokeVirtualRange.class,
-        ReturnVoid.class));
-    InvokeVirtualRange invoke = (InvokeVirtualRange) code.instructions[0];
+    checkInstructions(code, ImmutableList.of(InvokeVirtual.class, ReturnVoid.class));
+    InvokeVirtual invoke = (InvokeVirtual) code.instructions[0];
     assertEquals(baseSubject.getDexClass().type, invoke.getMethod().getHolder());
   }
 
diff --git a/src/test/java/com/android/tools/r8/compatproguard/ForNameTest.java b/src/test/java/com/android/tools/r8/compatproguard/ForNameTest.java
index f790f6d..5ef5830 100644
--- a/src/test/java/com/android/tools/r8/compatproguard/ForNameTest.java
+++ b/src/test/java/com/android/tools/r8/compatproguard/ForNameTest.java
@@ -8,7 +8,7 @@
 import static org.junit.Assert.assertTrue;
 
 import com.android.tools.r8.code.ConstString;
-import com.android.tools.r8.code.InvokeStaticRange;
+import com.android.tools.r8.code.InvokeStatic;
 import com.android.tools.r8.code.ReturnVoid;
 import com.android.tools.r8.graph.DexCode;
 import com.android.tools.r8.smali.SmaliBuilder;
@@ -50,7 +50,7 @@
     assertTrue(code.instructions[0] instanceof ConstString);
     ConstString constString = (ConstString) code.instructions[0];
     assertNotEquals(BOO, constString.getString().toString());
-    assertTrue(code.instructions[1] instanceof InvokeStaticRange);
+    assertTrue(code.instructions[1] instanceof InvokeStatic);
     assertTrue(code.instructions[2] instanceof ReturnVoid);
   }
 
@@ -81,7 +81,7 @@
     assertTrue(code.instructions[0] instanceof ConstString);
     ConstString constString = (ConstString) code.instructions[0];
     assertEquals(BOO, constString.getString().toString());
-    assertTrue(code.instructions[1] instanceof InvokeStaticRange);
+    assertTrue(code.instructions[1] instanceof InvokeStatic);
     assertTrue(code.instructions[2] instanceof ReturnVoid);
   }
 
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/CheckCastRemovalTest.java b/src/test/java/com/android/tools/r8/ir/optimize/CheckCastRemovalTest.java
index 690a9b1..1f7c990 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/CheckCastRemovalTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/CheckCastRemovalTest.java
@@ -14,8 +14,8 @@
 import com.android.tools.r8.code.Const4;
 import com.android.tools.r8.code.ConstString;
 import com.android.tools.r8.code.IgetObject;
-import com.android.tools.r8.code.InvokeDirectRange;
-import com.android.tools.r8.code.InvokeVirtualRange;
+import com.android.tools.r8.code.InvokeDirect;
+import com.android.tools.r8.code.InvokeVirtual;
 import com.android.tools.r8.code.NewArray;
 import com.android.tools.r8.code.NewInstance;
 import com.android.tools.r8.code.ReturnVoid;
@@ -57,7 +57,7 @@
 
     checkInstructions(
         method.getCode().asDexCode(),
-        ImmutableList.of(NewInstance.class, InvokeDirectRange.class, ReturnVoid.class));
+        ImmutableList.of(NewInstance.class, InvokeDirect.class, ReturnVoid.class));
 
     checkRuntime(builder, app, CLASS_NAME);
   }
@@ -96,7 +96,7 @@
 
     checkInstructions(
         method.getCode().asDexCode(),
-        ImmutableList.of(NewInstance.class, InvokeDirectRange.class, ReturnVoid.class));
+        ImmutableList.of(NewInstance.class, InvokeDirect.class, ReturnVoid.class));
 
     checkRuntime(builder, app, CLASS_NAME);
   }
@@ -137,8 +137,7 @@
     DexCode code = method.getCode().asDexCode();
     checkInstructions(
         code,
-        ImmutableList.of(
-            NewInstance.class, InvokeDirectRange.class, CheckCast.class, ReturnVoid.class));
+        ImmutableList.of(NewInstance.class, InvokeDirect.class, CheckCast.class, ReturnVoid.class));
     CheckCast cast = (CheckCast) code.instructions[2];
     assertEquals("C", cast.getType().toString());
 
@@ -184,7 +183,7 @@
             Const4.class,
             AputObject.class,
             AgetObject.class,
-            InvokeVirtualRange.class,
+            InvokeVirtual.class,
             ReturnVoid.class));
 
     checkRuntime(builder, app, CLASS_NAME);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/MemberValuePropagationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/MemberValuePropagationTest.java
index 488b545..e8f2a2a 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/MemberValuePropagationTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/MemberValuePropagationTest.java
@@ -13,7 +13,6 @@
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.code.Const4;
 import com.android.tools.r8.code.InvokeDirect;
-import com.android.tools.r8.code.InvokeDirectRange;
 import com.android.tools.r8.code.IputObject;
 import com.android.tools.r8.code.NewInstance;
 import com.android.tools.r8.code.ReturnVoid;
@@ -62,7 +61,7 @@
             DexEncodedMethod encodedMethod = methodSubject.getMethod();
             DexCode code = encodedMethod.getCode().asDexCode();
             assertEquals(4, code.instructions.length);
-            assertTrue(code.instructions[0] instanceof InvokeDirectRange);
+            assertTrue(code.instructions[0] instanceof InvokeDirect);
             assertTrue(code.instructions[1] instanceof NewInstance);
             assertTrue(code.instructions[2] instanceof InvokeDirect);
             assertTrue(code.instructions[3] instanceof ReturnVoid);
@@ -91,7 +90,7 @@
             DexEncodedMethod encodedMethod = methodSubject.getMethod();
             DexCode code = encodedMethod.getCode().asDexCode();
             assertEquals(5, code.instructions.length);
-            assertTrue(code.instructions[0] instanceof InvokeDirectRange);
+            assertTrue(code.instructions[0] instanceof InvokeDirect);
             assertTrue(code.instructions[1] instanceof NewInstance);
             assertTrue(code.instructions[2] instanceof InvokeDirect);
             assertTrue(code.instructions[3] instanceof IputObject);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/R8InliningTest.java b/src/test/java/com/android/tools/r8/ir/optimize/R8InliningTest.java
index d51d5c3..5dc7f23 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/R8InliningTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/R8InliningTest.java
@@ -18,7 +18,7 @@
 import com.android.tools.r8.code.IfEqz;
 import com.android.tools.r8.code.Iget;
 import com.android.tools.r8.code.Instruction;
-import com.android.tools.r8.code.InvokeVirtualRange;
+import com.android.tools.r8.code.InvokeVirtual;
 import com.android.tools.r8.code.MoveResult;
 import com.android.tools.r8.code.MulInt2Addr;
 import com.android.tools.r8.code.PackedSwitch;
@@ -186,7 +186,7 @@
         ImmutableList.of(
             Iget.class,
             // TODO(b/70572176): below two could be replaced with Iget via inlining
-            InvokeVirtualRange.class,
+            InvokeVirtual.class,
             MoveResult.class,
             AddInt2Addr.class,
             Return.class));
@@ -197,11 +197,7 @@
     checkInstructions(
         code,
         ImmutableList.of(
-            InvokeVirtualRange.class,
-            MoveResult.class,
-            Iget.class,
-            AddInt2Addr.class,
-            Return.class));
+            InvokeVirtual.class, MoveResult.class, Iget.class, AddInt2Addr.class, Return.class));
 
     m = clazz.method("int", "notInlinableDueToMissingNpe", ImmutableList.of("inlining.A"));
     assertTrue(m.isPresent());
@@ -220,7 +216,7 @@
         code,
         ImmutableList.of(
             IfEqz.class,
-            InvokeVirtualRange.class,
+            InvokeVirtual.class,
             MoveResult.class,
             Goto.class,
             Iget.class,
@@ -255,7 +251,7 @@
             IfEqz.class,
             // TODO(b/70794661): below two could be replaced with Iget via inlining if access
             // modification is allowed.
-            InvokeVirtualRange.class,
+            InvokeVirtual.class,
             MoveResult.class,
             Goto.class,
             Const4.class,
@@ -267,7 +263,7 @@
     code = m.getMethod().getCode().asDexCode();
     ImmutableList.Builder<Class<? extends Instruction>> builder = ImmutableList.builder();
     // Enum#ordinal
-    builder.add(InvokeVirtualRange.class);
+    builder.add(InvokeVirtual.class);
     builder.add(MoveResult.class);
     builder.add(PackedSwitch.class);
     for (int i = 0; i < 4; ++i) {
@@ -278,7 +274,7 @@
     builder.add(IfEqz.class);
     builder.add(IfEqz.class);
     // TODO(b/70794661): below two could be replaced with Iget via inlining
-    builder.add(InvokeVirtualRange.class);
+    builder.add(InvokeVirtual.class);
     builder.add(MoveResult.class);
     builder.add(MulInt2Addr.class);
     builder.add(Return.class);
diff --git a/src/test/java/com/android/tools/r8/naming/IdentifierNameStringMarkerTest.java b/src/test/java/com/android/tools/r8/naming/IdentifierNameStringMarkerTest.java
index 80e4f17..982e935 100644
--- a/src/test/java/com/android/tools/r8/naming/IdentifierNameStringMarkerTest.java
+++ b/src/test/java/com/android/tools/r8/naming/IdentifierNameStringMarkerTest.java
@@ -12,9 +12,8 @@
 import com.android.tools.r8.code.Const4;
 import com.android.tools.r8.code.ConstClass;
 import com.android.tools.r8.code.ConstString;
-import com.android.tools.r8.code.InvokeDirectRange;
+import com.android.tools.r8.code.InvokeDirect;
 import com.android.tools.r8.code.InvokeStatic;
-import com.android.tools.r8.code.InvokeStaticRange;
 import com.android.tools.r8.code.InvokeVirtual;
 import com.android.tools.r8.code.IputObject;
 import com.android.tools.r8.code.NewArray;
@@ -64,7 +63,7 @@
     checkInstructions(
         code,
         ImmutableList.of(
-            InvokeDirectRange.class, ConstString.class, IputObject.class, ReturnVoid.class));
+            InvokeDirect.class, ConstString.class, IputObject.class, ReturnVoid.class));
     ConstString constString = (ConstString) code.instructions[1];
     assertEquals(BOO, constString.getString().toString());
   }
@@ -96,7 +95,7 @@
     checkInstructions(
         code,
         ImmutableList.of(
-            InvokeDirectRange.class,
+            InvokeDirect.class,
             SgetObject.class,
             ConstString.class,
             InvokeVirtual.class,
@@ -138,7 +137,7 @@
     checkInstructions(
         code,
         ImmutableList.of(
-            InvokeDirectRange.class,
+            InvokeDirect.class,
             SgetObject.class,
             ConstString.class,
             InvokeVirtual.class,
@@ -374,7 +373,7 @@
     checkInstructions(
         code,
         ImmutableList.of(
-            InvokeDirectRange.class,
+            InvokeDirect.class,
             ConstString.class,
             ConstString.class,
             InvokeStatic.class,
@@ -416,12 +415,12 @@
     checkInstructions(
         code,
         ImmutableList.of(
-            InvokeDirectRange.class,
+            InvokeDirect.class,
             SgetObject.class,
             ConstString.class,
             InvokeVirtual.class,
             ConstString.class,
-            InvokeStaticRange.class,
+            InvokeStatic.class,
             ReturnVoid.class));
     ConstString constString = (ConstString) code.instructions[2];
     assertEquals(BOO, constString.getString().toString());
@@ -462,12 +461,12 @@
     checkInstructions(
         code,
         ImmutableList.of(
-            InvokeDirectRange.class,
+            InvokeDirect.class,
             SgetObject.class,
             ConstString.class,
             InvokeVirtual.class,
             ConstString.class,
-            InvokeStaticRange.class,
+            InvokeStatic.class,
             ReturnVoid.class));
     ConstString constString = (ConstString) code.instructions[2];
     assertEquals(BOO, constString.getString().toString());
@@ -516,7 +515,7 @@
     checkInstructions(
         code,
         ImmutableList.of(
-            InvokeDirectRange.class,
+            InvokeDirect.class,
             ConstClass.class,
             ConstString.class,
             InvokeStatic.class,
@@ -566,7 +565,7 @@
     checkInstructions(
         code,
         ImmutableList.of(
-            InvokeDirectRange.class,
+            InvokeDirect.class,
             ConstClass.class,
             ConstString.class,
             InvokeStatic.class,
@@ -623,7 +622,7 @@
     checkInstructions(
         code,
         ImmutableList.of(
-            InvokeDirectRange.class,
+            InvokeDirect.class,
             ConstClass.class,
             Const4.class,
             NewArray.class,
@@ -684,7 +683,7 @@
     checkInstructions(
         code,
         ImmutableList.of(
-            InvokeDirectRange.class,
+            InvokeDirect.class,
             ConstClass.class,
             Const4.class,
             NewArray.class,
diff --git a/src/test/java/com/android/tools/r8/regress/B76025099.java b/src/test/java/com/android/tools/r8/regress/B76025099.java
index 160febd..0a0e861 100644
--- a/src/test/java/com/android/tools/r8/regress/B76025099.java
+++ b/src/test/java/com/android/tools/r8/regress/B76025099.java
@@ -13,7 +13,7 @@
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.ToolHelper.ProcessResult;
 import com.android.tools.r8.VmTestRunner;
-import com.android.tools.r8.code.InvokeDirectRange;
+import com.android.tools.r8.code.InvokeDirect;
 import com.android.tools.r8.code.IputObject;
 import com.android.tools.r8.code.ReturnVoid;
 import com.android.tools.r8.graph.DexCode;
@@ -110,11 +110,8 @@
     MethodSubject init = impl.init(ImmutableList.of("java.lang.String"));
     assertThat(init, isPresent());
     DexCode dexCode = init.getMethod().getCode().asDexCode();
-    checkInstructions(dexCode, ImmutableList.of(
-        InvokeDirectRange.class,
-        IputObject.class,
-        ReturnVoid.class
-    ));
+    checkInstructions(
+        dexCode, ImmutableList.of(InvokeDirect.class, IputObject.class, ReturnVoid.class));
     IputObject iput = (IputObject) dexCode.instructions[1];
     DexField fld = iput.getField();
     assertEquals("name", fld.name.toString());
diff --git a/src/test/java/com/android/tools/r8/regress/b78493232/Regress78493232Utils.java b/src/test/java/com/android/tools/r8/regress/b78493232/Regress78493232Utils.java
index 40d979e..ff7da8f 100644
--- a/src/test/java/com/android/tools/r8/regress/b78493232/Regress78493232Utils.java
+++ b/src/test/java/com/android/tools/r8/regress/b78493232/Regress78493232Utils.java
@@ -9,6 +9,14 @@
 
 public class Regress78493232Utils {
 
+  public static void println(String msg) {
+    System.out.println(msg);
+  }
+
+  public static void println(int msg) {
+    System.out.println(msg);
+  }
+
   private static void printByteArray(byte[] array) {
     List<String> strings = new ArrayList<>(array.length);
     for (byte b : array) {
diff --git a/src/test/java/com/android/tools/r8/shaking/proxy/ProxiesTest.java b/src/test/java/com/android/tools/r8/shaking/proxy/ProxiesTest.java
index 6c0bfe7..8e39b67 100644
--- a/src/test/java/com/android/tools/r8/shaking/proxy/ProxiesTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/proxy/ProxiesTest.java
@@ -11,8 +11,8 @@
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.code.Instruction;
-import com.android.tools.r8.code.InvokeInterfaceRange;
-import com.android.tools.r8.code.InvokeVirtualRange;
+import com.android.tools.r8.code.InvokeInterface;
+import com.android.tools.r8.code.InvokeVirtual;
 import com.android.tools.r8.graph.DexCode;
 import com.android.tools.r8.graph.invokesuper.Consumer;
 import com.android.tools.r8.naming.MemberNaming.MethodSignature;
@@ -92,9 +92,9 @@
 
   private void noInterfaceKept(DexInspector inspector) {
     // Indirectly assert that method is inlined into x, y and z.
-    assertEquals(1, countInstructionInX(inspector, InvokeInterfaceRange.class));
-    assertEquals(1, countInstructionInY(inspector, InvokeInterfaceRange.class));
-    assertEquals(1, countInstructionInZ(inspector, InvokeVirtualRange.class));
+    assertEquals(1, countInstructionInX(inspector, InvokeInterface.class));
+    assertEquals(1, countInstructionInY(inspector, InvokeInterface.class));
+    assertEquals(1, countInstructionInZ(inspector, InvokeVirtual.class));
   }
 
   @Test
@@ -106,11 +106,11 @@
 
   private void baseInterfaceKept(DexInspector inspector) {
     // Indirectly assert that method is not inlined into x.
-    assertEquals(3, countInstructionInX(inspector, InvokeInterfaceRange.class));
+    assertEquals(3, countInstructionInX(inspector, InvokeInterface.class));
     // Indirectly assert that method is inlined into y and z.
-    assertEquals(1, countInstructionInY(inspector, InvokeInterfaceRange.class));
-    assertEquals(1, countInstructionInZ(inspector, InvokeVirtualRange.class));
-    assertEquals(1, countInstructionInZSubClass(inspector, InvokeVirtualRange.class));
+    assertEquals(1, countInstructionInY(inspector, InvokeInterface.class));
+    assertEquals(1, countInstructionInZ(inspector, InvokeVirtual.class));
+    assertEquals(1, countInstructionInZSubClass(inspector, InvokeVirtual.class));
   }
 
   @Test
@@ -126,11 +126,11 @@
 
   private void subInterfaceKept(DexInspector inspector) {
     // Indirectly assert that method is not inlined into x or y.
-    assertEquals(3, countInstructionInX(inspector, InvokeInterfaceRange.class));
-    assertEquals(3, countInstructionInY(inspector, InvokeInterfaceRange.class));
+    assertEquals(3, countInstructionInX(inspector, InvokeInterface.class));
+    assertEquals(3, countInstructionInY(inspector, InvokeInterface.class));
     // Indirectly assert that method is inlined into z.
-    assertEquals(1, countInstructionInZ(inspector, InvokeVirtualRange.class));
-    assertEquals(1, countInstructionInZSubClass(inspector, InvokeVirtualRange.class));
+    assertEquals(1, countInstructionInZ(inspector, InvokeVirtual.class));
+    assertEquals(1, countInstructionInZSubClass(inspector, InvokeVirtual.class));
   }
 
   @Test
@@ -148,10 +148,10 @@
 
   private void classKept(DexInspector inspector) {
     // Indirectly assert that method is not inlined into x, y or z.
-    assertEquals(3, countInstructionInX(inspector, InvokeInterfaceRange.class));
-    assertEquals(3, countInstructionInY(inspector, InvokeInterfaceRange.class));
-    assertEquals(3, countInstructionInZ(inspector, InvokeVirtualRange.class));
-    assertEquals(3, countInstructionInZSubClass(inspector, InvokeVirtualRange.class));
+    assertEquals(3, countInstructionInX(inspector, InvokeInterface.class));
+    assertEquals(3, countInstructionInY(inspector, InvokeInterface.class));
+    assertEquals(3, countInstructionInZ(inspector, InvokeVirtual.class));
+    assertEquals(3, countInstructionInZSubClass(inspector, InvokeVirtual.class));
   }
 
   @Test
diff --git a/src/test/java/com/android/tools/r8/smali/IfSimplificationTest.java b/src/test/java/com/android/tools/r8/smali/IfSimplificationTest.java
index f8aae30..162db06 100644
--- a/src/test/java/com/android/tools/r8/smali/IfSimplificationTest.java
+++ b/src/test/java/com/android/tools/r8/smali/IfSimplificationTest.java
@@ -14,7 +14,7 @@
 import com.android.tools.r8.code.IfLez;
 import com.android.tools.r8.code.IfLtz;
 import com.android.tools.r8.code.IfNez;
-import com.android.tools.r8.code.InvokeVirtualRange;
+import com.android.tools.r8.code.InvokeVirtual;
 import com.android.tools.r8.code.Return;
 import com.android.tools.r8.code.ReturnObject;
 import com.android.tools.r8.graph.DexCode;
@@ -391,7 +391,7 @@
     );
     DexCode code = method.getCode().asDexCode();
     assertEquals(3, code.instructions.length);
-    assertTrue(code.instructions[0] instanceof InvokeVirtualRange);
+    assertTrue(code.instructions[0] instanceof InvokeVirtual);
     assertTrue(code.instructions[1] instanceof Const4);
     assertEquals(0, ((Const4) code.instructions[1]).B);
     assertTrue(code.instructions[2] instanceof ReturnObject);
diff --git a/src/test/java/com/android/tools/r8/smali/OutlineTest.java b/src/test/java/com/android/tools/r8/smali/OutlineTest.java
index 5b6f61f..eb66c51 100644
--- a/src/test/java/com/android/tools/r8/smali/OutlineTest.java
+++ b/src/test/java/com/android/tools/r8/smali/OutlineTest.java
@@ -18,7 +18,6 @@
 import com.android.tools.r8.code.InvokeStatic;
 import com.android.tools.r8.code.InvokeStaticRange;
 import com.android.tools.r8.code.InvokeVirtual;
-import com.android.tools.r8.code.InvokeVirtualRange;
 import com.android.tools.r8.code.MoveResult;
 import com.android.tools.r8.code.MoveResultWide;
 import com.android.tools.r8.code.Return;
@@ -557,7 +556,7 @@
         InvokeStatic invoke = (InvokeStatic) mainCode.instructions[4];
         assertTrue(isOutlineMethodName(invoke.getMethod().qualifiedName()));
       } else if (i == 3) {
-        InvokeStaticRange invoke = (InvokeStaticRange) mainCode.instructions[1];
+        InvokeStatic invoke = (InvokeStatic) mainCode.instructions[1];
         assertTrue(isOutlineMethodName(invoke.getMethod().qualifiedName()));
       } else {
         assert i == 4 || i == 5;
@@ -852,7 +851,7 @@
     List<DexType> r = new ArrayList<>();
     for (int i = 0; i < clazz.getDexClass().directMethods().length; i++) {
       if (clazz.getDexClass().directMethods()[i].getCode().asDexCode().instructions[0]
-          instanceof InvokeVirtualRange) {
+          instanceof InvokeVirtual) {
         r.add(clazz.getDexClass().directMethods()[i].method.proto.returnType);
       }
     }
@@ -1098,9 +1097,9 @@
     DexEncodedMethod method = getMethod(processedApplication, signature);
     DexCode code = method.getCode().asDexCode();
     assertEquals(2, code.instructions.length);
-    assertTrue(code.instructions[0] instanceof InvokeStaticRange);
+    assertTrue(code.instructions[0] instanceof InvokeStatic);
     assertTrue(code.instructions[1] instanceof ReturnObject);
-    InvokeStaticRange invoke = (InvokeStaticRange) code.instructions[0];
+    InvokeStatic invoke = (InvokeStatic) code.instructions[0];
     assertEquals(firstOutlineMethodName(), invoke.getMethod().qualifiedName());
 
     // Run code and check result.
@@ -1302,9 +1301,9 @@
     DexEncodedMethod method = getMethod(processedApplication, signature);
     DexCode code = method.getCode().asDexCode();
     assertEquals(2, code.instructions.length);
-    assertTrue(code.instructions[0] instanceof InvokeStaticRange);
+    assertTrue(code.instructions[0] instanceof InvokeStatic);
     assertTrue(code.instructions[1] instanceof ReturnVoid);
-    InvokeStaticRange invoke = (InvokeStaticRange) code.instructions[0];
+    InvokeStatic invoke = (InvokeStatic) code.instructions[0];
     assertEquals(firstOutlineMethodName(), invoke.getMethod().qualifiedName());
 
     // Run code and check result.