[LIR] Add all arithmetic binary operations.

Bug: b/225838009
Change-Id: I07a33126017af97da28e0a34e64d19445edd66f0
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java b/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java
index 95cdc02..398da41 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java
@@ -120,23 +120,28 @@
   }
 
   public int getAsmOpcode() {
+    return getAsmOpcode(opcode, type);
+  }
+
+  public static int getAsmOpcode(Opcode opcode, NumericType type) {
+    int typeOffset = getAsmOpcodeTypeOffset(type);
     switch (opcode) {
       case Add:
-        return Opcodes.IADD + getAsmOpcodeTypeOffset();
+        return Opcodes.IADD + typeOffset;
       case Sub:
-        return Opcodes.ISUB + getAsmOpcodeTypeOffset();
+        return Opcodes.ISUB + typeOffset;
       case Mul:
-        return Opcodes.IMUL + getAsmOpcodeTypeOffset();
+        return Opcodes.IMUL + typeOffset;
       case Div:
-        return Opcodes.IDIV + getAsmOpcodeTypeOffset();
+        return Opcodes.IDIV + typeOffset;
       case Rem:
-        return Opcodes.IREM + getAsmOpcodeTypeOffset();
+        return Opcodes.IREM + typeOffset;
       default:
         throw new Unreachable("CfArithmeticBinop has unknown opcode " + opcode);
     }
   }
 
-  private int getAsmOpcodeTypeOffset() {
+  private static int getAsmOpcodeTypeOffset(NumericType type) {
     switch (type) {
       case LONG:
         return Opcodes.LADD - Opcodes.IADD;
diff --git a/src/main/java/com/android/tools/r8/ir/code/ArithmeticBinop.java b/src/main/java/com/android/tools/r8/ir/code/ArithmeticBinop.java
index cf6039c..f2aa7cf 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ArithmeticBinop.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ArithmeticBinop.java
@@ -12,6 +12,7 @@
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.ir.conversion.CfBuilder;
 import com.android.tools.r8.ir.conversion.DexBuilder;
+import com.android.tools.r8.lightir.LirBuilder;
 import java.util.function.Function;
 
 public abstract class ArithmeticBinop extends Binop {
@@ -167,4 +168,9 @@
   public void buildCf(CfBuilder builder) {
     builder.add(new CfArithmeticBinop(getCfOpcode(), type), this);
   }
+
+  @Override
+  public void buildLir(LirBuilder<Value, ?> builder) {
+    builder.addArithmeticBinop(getCfOpcode(), type, leftValue(), rightValue());
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/lightir/Lir2IRConverter.java b/src/main/java/com/android/tools/r8/lightir/Lir2IRConverter.java
index ebaa39c..78e84db 100644
--- a/src/main/java/com/android/tools/r8/lightir/Lir2IRConverter.java
+++ b/src/main/java/com/android/tools/r8/lightir/Lir2IRConverter.java
@@ -12,6 +12,7 @@
 import com.android.tools.r8.graph.ProgramMethod;
 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.Add;
 import com.android.tools.r8.ir.code.Argument;
 import com.android.tools.r8.ir.code.ArrayLength;
 import com.android.tools.r8.ir.code.BasicBlock;
@@ -36,14 +37,17 @@
 import com.android.tools.r8.ir.code.InvokeSuper;
 import com.android.tools.r8.ir.code.InvokeVirtual;
 import com.android.tools.r8.ir.code.MoveException;
+import com.android.tools.r8.ir.code.Mul;
 import com.android.tools.r8.ir.code.NewInstance;
 import com.android.tools.r8.ir.code.NumberGenerator;
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.code.Phi;
 import com.android.tools.r8.ir.code.Position;
 import com.android.tools.r8.ir.code.Position.SyntheticPosition;
+import com.android.tools.r8.ir.code.Rem;
 import com.android.tools.r8.ir.code.Return;
 import com.android.tools.r8.ir.code.StaticGet;
+import com.android.tools.r8.ir.code.Sub;
 import com.android.tools.r8.ir.code.Throw;
 import com.android.tools.r8.ir.code.Value;
 import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
@@ -334,10 +338,33 @@
     }
 
     @Override
-    public void onDivInt(EV leftValueIndex, EV rightValueIndex) {
+    public void onAdd(NumericType type, EV leftValueIndex, EV rightValueIndex) {
       Value dest = getOutValueForNextInstruction(TypeElement.getInt());
-      addInstruction(
-          new Div(NumericType.INT, dest, getValue(leftValueIndex), getValue(rightValueIndex)));
+      addInstruction(new Add(type, dest, getValue(leftValueIndex), getValue(rightValueIndex)));
+    }
+
+    @Override
+    public void onSub(NumericType type, EV leftValueIndex, EV rightValueIndex) {
+      Value dest = getOutValueForNextInstruction(TypeElement.getInt());
+      addInstruction(new Sub(type, dest, getValue(leftValueIndex), getValue(rightValueIndex)));
+    }
+
+    @Override
+    public void onMul(NumericType type, EV leftValueIndex, EV rightValueIndex) {
+      Value dest = getOutValueForNextInstruction(TypeElement.getInt());
+      addInstruction(new Mul(type, dest, getValue(leftValueIndex), getValue(rightValueIndex)));
+    }
+
+    @Override
+    public void onDiv(NumericType type, EV leftValueIndex, EV rightValueIndex) {
+      Value dest = getOutValueForNextInstruction(TypeElement.getInt());
+      addInstruction(new Div(type, dest, getValue(leftValueIndex), getValue(rightValueIndex)));
+    }
+
+    @Override
+    public void onRem(NumericType type, EV leftValueIndex, EV rightValueIndex) {
+      Value dest = getOutValueForNextInstruction(TypeElement.getInt());
+      addInstruction(new Rem(type, dest, getValue(leftValueIndex), getValue(rightValueIndex)));
     }
 
     @Override
diff --git a/src/main/java/com/android/tools/r8/lightir/LirBuilder.java b/src/main/java/com/android/tools/r8/lightir/LirBuilder.java
index 37806dd..3edc3c2 100644
--- a/src/main/java/com/android/tools/r8/lightir/LirBuilder.java
+++ b/src/main/java/com/android/tools/r8/lightir/LirBuilder.java
@@ -3,6 +3,8 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.lightir;
 
+import com.android.tools.r8.cf.code.CfArithmeticBinop;
+import com.android.tools.r8.cf.code.CfArithmeticBinop.Opcode;
 import com.android.tools.r8.errors.Unimplemented;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.DebugLocalInfo;
@@ -495,4 +497,13 @@
   public LirBuilder<V, EV> addCmp(NumericType type, Bias bias, V leftValue, V rightValue) {
     return addTwoValueInstruction(getCmpOpcode(type, bias), leftValue, rightValue);
   }
+
+  public LirBuilder<V, EV> addArithmeticBinop(
+      Opcode binop, NumericType type, V leftValue, V rightValue) {
+    // The LIR and CF opcodes are the same values, check that the two endpoints match.
+    assert LirOpcodes.IADD == CfArithmeticBinop.getAsmOpcode(Opcode.Add, NumericType.INT);
+    assert LirOpcodes.DREM == CfArithmeticBinop.getAsmOpcode(Opcode.Rem, NumericType.DOUBLE);
+    int opcode = CfArithmeticBinop.getAsmOpcode(binop, type);
+    return addTwoValueInstruction(opcode, leftValue, rightValue);
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/lightir/LirParsedInstructionCallback.java b/src/main/java/com/android/tools/r8/lightir/LirParsedInstructionCallback.java
index 96cb7ee..3342eed 100644
--- a/src/main/java/com/android/tools/r8/lightir/LirParsedInstructionCallback.java
+++ b/src/main/java/com/android/tools/r8/lightir/LirParsedInstructionCallback.java
@@ -66,6 +66,66 @@
     onInstruction();
   }
 
+  public void onAdd(NumericType type, EV leftValueIndex, EV rightValueIndex) {
+    onInstruction();
+  }
+
+  public void onAddInt(EV leftValueIndex, EV rightValueIndex) {
+    onAdd(NumericType.INT, leftValueIndex, rightValueIndex);
+  }
+
+  public void onAddLong(EV leftValueIndex, EV rightValueIndex) {
+    onAdd(NumericType.LONG, leftValueIndex, rightValueIndex);
+  }
+
+  public void onAddFloat(EV leftValueIndex, EV rightValueIndex) {
+    onAdd(NumericType.FLOAT, leftValueIndex, rightValueIndex);
+  }
+
+  public void onAddDouble(EV leftValueIndex, EV rightValueIndex) {
+    onAdd(NumericType.DOUBLE, leftValueIndex, rightValueIndex);
+  }
+
+  public void onSub(NumericType type, EV leftValueIndex, EV rightValueIndex) {
+    onInstruction();
+  }
+
+  public void onSubInt(EV leftValueIndex, EV rightValueIndex) {
+    onSub(NumericType.INT, leftValueIndex, rightValueIndex);
+  }
+
+  public void onSubLong(EV leftValueIndex, EV rightValueIndex) {
+    onSub(NumericType.LONG, leftValueIndex, rightValueIndex);
+  }
+
+  public void onSubFloat(EV leftValueIndex, EV rightValueIndex) {
+    onSub(NumericType.FLOAT, leftValueIndex, rightValueIndex);
+  }
+
+  public void onSubDouble(EV leftValueIndex, EV rightValueIndex) {
+    onSub(NumericType.DOUBLE, leftValueIndex, rightValueIndex);
+  }
+
+  public void onMul(NumericType type, EV leftValueIndex, EV rightValueIndex) {
+    onInstruction();
+  }
+
+  public void onMulInt(EV leftValueIndex, EV rightValueIndex) {
+    onMul(NumericType.INT, leftValueIndex, rightValueIndex);
+  }
+
+  public void onMulLong(EV leftValueIndex, EV rightValueIndex) {
+    onMul(NumericType.LONG, leftValueIndex, rightValueIndex);
+  }
+
+  public void onMulFloat(EV leftValueIndex, EV rightValueIndex) {
+    onMul(NumericType.FLOAT, leftValueIndex, rightValueIndex);
+  }
+
+  public void onMulDouble(EV leftValueIndex, EV rightValueIndex) {
+    onMul(NumericType.DOUBLE, leftValueIndex, rightValueIndex);
+  }
+
   public void onDiv(NumericType type, EV leftValueIndex, EV rightValueIndex) {
     onInstruction();
   }
@@ -74,6 +134,38 @@
     onDiv(NumericType.INT, leftValueIndex, rightValueIndex);
   }
 
+  public void onDivLong(EV leftValueIndex, EV rightValueIndex) {
+    onDiv(NumericType.LONG, leftValueIndex, rightValueIndex);
+  }
+
+  public void onDivFloat(EV leftValueIndex, EV rightValueIndex) {
+    onDiv(NumericType.FLOAT, leftValueIndex, rightValueIndex);
+  }
+
+  public void onDivDouble(EV leftValueIndex, EV rightValueIndex) {
+    onDiv(NumericType.DOUBLE, leftValueIndex, rightValueIndex);
+  }
+
+  public void onRem(NumericType type, EV leftValueIndex, EV rightValueIndex) {
+    onInstruction();
+  }
+
+  public void onRemInt(EV leftValueIndex, EV rightValueIndex) {
+    onRem(NumericType.INT, leftValueIndex, rightValueIndex);
+  }
+
+  public void onRemLong(EV leftValueIndex, EV rightValueIndex) {
+    onRem(NumericType.LONG, leftValueIndex, rightValueIndex);
+  }
+
+  public void onRemFloat(EV leftValueIndex, EV rightValueIndex) {
+    onRem(NumericType.FLOAT, leftValueIndex, rightValueIndex);
+  }
+
+  public void onRemDouble(EV leftValueIndex, EV rightValueIndex) {
+    onRem(NumericType.DOUBLE, leftValueIndex, rightValueIndex);
+  }
+
   public void onIf(IfType ifKind, int blockIndex, EV valueIndex) {
     onInstruction();
   }
@@ -197,6 +289,90 @@
           onConstInt(value);
           return;
         }
+      case LirOpcodes.IADD:
+        {
+          EV leftValueIndex = getNextValueOperand(view);
+          EV rightValueIndex = getNextValueOperand(view);
+          onAddInt(leftValueIndex, rightValueIndex);
+          return;
+        }
+      case LirOpcodes.LADD:
+        {
+          EV leftValueIndex = getNextValueOperand(view);
+          EV rightValueIndex = getNextValueOperand(view);
+          onAddLong(leftValueIndex, rightValueIndex);
+          return;
+        }
+      case LirOpcodes.FADD:
+        {
+          EV leftValueIndex = getNextValueOperand(view);
+          EV rightValueIndex = getNextValueOperand(view);
+          onAddFloat(leftValueIndex, rightValueIndex);
+          return;
+        }
+      case LirOpcodes.DADD:
+        {
+          EV leftValueIndex = getNextValueOperand(view);
+          EV rightValueIndex = getNextValueOperand(view);
+          onAddDouble(leftValueIndex, rightValueIndex);
+          return;
+        }
+      case LirOpcodes.ISUB:
+        {
+          EV leftValueIndex = getNextValueOperand(view);
+          EV rightValueIndex = getNextValueOperand(view);
+          onSubInt(leftValueIndex, rightValueIndex);
+          return;
+        }
+      case LirOpcodes.LSUB:
+        {
+          EV leftValueIndex = getNextValueOperand(view);
+          EV rightValueIndex = getNextValueOperand(view);
+          onSubLong(leftValueIndex, rightValueIndex);
+          return;
+        }
+      case LirOpcodes.FSUB:
+        {
+          EV leftValueIndex = getNextValueOperand(view);
+          EV rightValueIndex = getNextValueOperand(view);
+          onSubFloat(leftValueIndex, rightValueIndex);
+          return;
+        }
+      case LirOpcodes.DSUB:
+        {
+          EV leftValueIndex = getNextValueOperand(view);
+          EV rightValueIndex = getNextValueOperand(view);
+          onSubDouble(leftValueIndex, rightValueIndex);
+          return;
+        }
+      case LirOpcodes.IMUL:
+        {
+          EV leftValueIndex = getNextValueOperand(view);
+          EV rightValueIndex = getNextValueOperand(view);
+          onMulInt(leftValueIndex, rightValueIndex);
+          return;
+        }
+      case LirOpcodes.LMUL:
+        {
+          EV leftValueIndex = getNextValueOperand(view);
+          EV rightValueIndex = getNextValueOperand(view);
+          onMulLong(leftValueIndex, rightValueIndex);
+          return;
+        }
+      case LirOpcodes.FMUL:
+        {
+          EV leftValueIndex = getNextValueOperand(view);
+          EV rightValueIndex = getNextValueOperand(view);
+          onMulFloat(leftValueIndex, rightValueIndex);
+          return;
+        }
+      case LirOpcodes.DMUL:
+        {
+          EV leftValueIndex = getNextValueOperand(view);
+          EV rightValueIndex = getNextValueOperand(view);
+          onMulDouble(leftValueIndex, rightValueIndex);
+          return;
+        }
       case LirOpcodes.IDIV:
         {
           EV leftValueIndex = getNextValueOperand(view);
@@ -204,6 +380,55 @@
           onDivInt(leftValueIndex, rightValueIndex);
           return;
         }
+      case LirOpcodes.LDIV:
+        {
+          EV leftValueIndex = getNextValueOperand(view);
+          EV rightValueIndex = getNextValueOperand(view);
+          onDivLong(leftValueIndex, rightValueIndex);
+          return;
+        }
+      case LirOpcodes.FDIV:
+        {
+          EV leftValueIndex = getNextValueOperand(view);
+          EV rightValueIndex = getNextValueOperand(view);
+          onDivFloat(leftValueIndex, rightValueIndex);
+          return;
+        }
+      case LirOpcodes.DDIV:
+        {
+          EV leftValueIndex = getNextValueOperand(view);
+          EV rightValueIndex = getNextValueOperand(view);
+          onDivDouble(leftValueIndex, rightValueIndex);
+          return;
+        }
+      case LirOpcodes.IREM:
+        {
+          EV leftValueIndex = getNextValueOperand(view);
+          EV rightValueIndex = getNextValueOperand(view);
+          onRemInt(leftValueIndex, rightValueIndex);
+          return;
+        }
+      case LirOpcodes.LREM:
+        {
+          EV leftValueIndex = getNextValueOperand(view);
+          EV rightValueIndex = getNextValueOperand(view);
+          onRemLong(leftValueIndex, rightValueIndex);
+          return;
+        }
+      case LirOpcodes.FREM:
+        {
+          EV leftValueIndex = getNextValueOperand(view);
+          EV rightValueIndex = getNextValueOperand(view);
+          onRemFloat(leftValueIndex, rightValueIndex);
+          return;
+        }
+      case LirOpcodes.DREM:
+        {
+          EV leftValueIndex = getNextValueOperand(view);
+          EV rightValueIndex = getNextValueOperand(view);
+          onRemDouble(leftValueIndex, rightValueIndex);
+          return;
+        }
       case LirOpcodes.IFNE:
         {
           int blockIndex = view.getNextBlockOperand();