Implement mayHaveArithmeticOrLogicalBinop()

Bug: 145202413
Change-Id: I08655b15b08243b923f244cdad000da4880522df
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 805aad9..6a130a1 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
@@ -763,7 +763,13 @@
 
   private boolean consistentMetadata() {
     for (Instruction instruction : instructions()) {
-      if (instruction.isCheckCast()) {
+      if (instruction.isAdd()) {
+        assert metadata.mayHaveAdd() && metadata.mayHaveArithmeticOrLogicalBinop()
+            : "IR metadata should indicate that code has an add";
+      } else if (instruction.isAnd()) {
+        assert metadata.mayHaveAnd() && metadata.mayHaveArithmeticOrLogicalBinop()
+            : "IR metadata should indicate that code has an and";
+      } else if (instruction.isCheckCast()) {
         assert metadata.mayHaveCheckCast()
             : "IR metadata should indicate that code has a check-cast";
       } else if (instruction.isConstNumber()) {
@@ -778,6 +784,9 @@
       } else if (instruction.isDexItemBasedConstString()) {
         assert metadata.mayHaveDexItemBasedConstString()
             : "IR metadata should indicate that code has a dex-item-based-const-string";
+      } else if (instruction.isDiv()) {
+        assert metadata.mayHaveDiv() && metadata.mayHaveArithmeticOrLogicalBinop()
+            : "IR metadata should indicate that code has a div";
       } else if (instruction.isInstanceGet()) {
         assert metadata.mayHaveInstanceGet()
             : "IR metadata should indicate that code has an instance-get";
@@ -808,9 +817,24 @@
       } else if (instruction.isInvokeVirtual()) {
         assert metadata.mayHaveInvokeVirtual()
             : "IR metadata should indicate that code has an invoke-virtual";
+      } else if (instruction.isOr()) {
+        assert metadata.mayHaveOr() && metadata.mayHaveArithmeticOrLogicalBinop()
+            : "IR metadata should indicate that code has an or";
       } else if (instruction.isMonitor()) {
         assert metadata.mayHaveMonitorInstruction()
             : "IR metadata should indicate that code has a monitor instruction";
+      } else if (instruction.isMul()) {
+        assert metadata.mayHaveMul() && metadata.mayHaveArithmeticOrLogicalBinop()
+            : "IR metadata should indicate that code has a mul";
+      } else if (instruction.isRem()) {
+        assert metadata.mayHaveRem() && metadata.mayHaveArithmeticOrLogicalBinop()
+            : "IR metadata should indicate that code has a rem";
+      } else if (instruction.isShl()) {
+        assert metadata.mayHaveShl() && metadata.mayHaveArithmeticOrLogicalBinop()
+            : "IR metadata should indicate that code has a shl";
+      } else if (instruction.isShr()) {
+        assert metadata.mayHaveShr() && metadata.mayHaveArithmeticOrLogicalBinop()
+            : "IR metadata should indicate that code has a shr";
       } else if (instruction.isStaticGet()) {
         assert metadata.mayHaveStaticGet()
             : "IR metadata should indicate that code has a static-get";
@@ -820,6 +844,15 @@
       } else if (instruction.isStringSwitch()) {
         assert metadata.mayHaveStringSwitch()
             : "IR metadata should indicate that code has a string-switch";
+      } else if (instruction.isSub()) {
+        assert metadata.mayHaveSub() && metadata.mayHaveArithmeticOrLogicalBinop()
+            : "IR metadata should indicate that code has a sub";
+      } else if (instruction.isUshr()) {
+        assert metadata.mayHaveUshr() && metadata.mayHaveArithmeticOrLogicalBinop()
+            : "IR metadata should indicate that code has an ushr";
+      } else if (instruction.isXor()) {
+        assert metadata.mayHaveXor() && metadata.mayHaveArithmeticOrLogicalBinop()
+            : "IR metadata should indicate that code has an xor";
       }
     }
     return true;
diff --git a/src/main/java/com/android/tools/r8/ir/code/IRMetadata.java b/src/main/java/com/android/tools/r8/ir/code/IRMetadata.java
index f6054e1..c4d55d8 100644
--- a/src/main/java/com/android/tools/r8/ir/code/IRMetadata.java
+++ b/src/main/java/com/android/tools/r8/ir/code/IRMetadata.java
@@ -57,6 +57,14 @@
     second |= metadata.second;
   }
 
+  public boolean mayHaveAdd() {
+    return get(Opcodes.ADD);
+  }
+
+  public boolean mayHaveAnd() {
+    return get(Opcodes.AND);
+  }
+
   public boolean mayHaveCheckCast() {
     return get(Opcodes.CHECK_CAST);
   }
@@ -77,15 +85,19 @@
     return get(Opcodes.DEX_ITEM_BASED_CONST_STRING);
   }
 
+  public boolean mayHaveDiv() {
+    return get(Opcodes.DIV);
+  }
+
   public boolean mayHaveFieldGet() {
     return mayHaveInstanceGet() || mayHaveStaticGet();
   }
 
   public boolean mayHaveFieldInstruction() {
-    assert Opcodes.INSTANCE_GET <= 64;
-    assert Opcodes.INSTANCE_PUT <= 64;
-    assert Opcodes.STATIC_GET <= 64;
-    assert Opcodes.STATIC_PUT <= 64;
+    assert Opcodes.INSTANCE_GET < 64;
+    assert Opcodes.INSTANCE_PUT < 64;
+    assert Opcodes.STATIC_GET < 64;
+    assert Opcodes.STATIC_PUT < 64;
     long mask =
         (1L << Opcodes.INSTANCE_GET)
             | (1L << Opcodes.INSTANCE_PUT)
@@ -126,12 +138,12 @@
 
   @SuppressWarnings("ConstantConditions")
   public boolean mayHaveInvokeMethod() {
-    assert Opcodes.INVOKE_DIRECT <= 64;
-    assert Opcodes.INVOKE_INTERFACE <= 64;
-    assert Opcodes.INVOKE_POLYMORPHIC <= 64;
-    assert Opcodes.INVOKE_STATIC <= 64;
-    assert Opcodes.INVOKE_SUPER <= 64;
-    assert Opcodes.INVOKE_VIRTUAL <= 64;
+    assert Opcodes.INVOKE_DIRECT < 64;
+    assert Opcodes.INVOKE_INTERFACE < 64;
+    assert Opcodes.INVOKE_POLYMORPHIC < 64;
+    assert Opcodes.INVOKE_STATIC < 64;
+    assert Opcodes.INVOKE_SUPER < 64;
+    assert Opcodes.INVOKE_VIRTUAL < 64;
     long mask =
         (1L << Opcodes.INVOKE_DIRECT)
             | (1L << Opcodes.INVOKE_INTERFACE)
@@ -152,10 +164,10 @@
 
   @SuppressWarnings("ConstantConditions")
   public boolean mayHaveInvokeMethodWithReceiver() {
-    assert Opcodes.INVOKE_DIRECT <= 64;
-    assert Opcodes.INVOKE_INTERFACE <= 64;
-    assert Opcodes.INVOKE_SUPER <= 64;
-    assert Opcodes.INVOKE_VIRTUAL <= 64;
+    assert Opcodes.INVOKE_DIRECT < 64;
+    assert Opcodes.INVOKE_INTERFACE < 64;
+    assert Opcodes.INVOKE_SUPER < 64;
+    assert Opcodes.INVOKE_VIRTUAL < 64;
     long mask =
         (1L << Opcodes.INVOKE_DIRECT)
             | (1L << Opcodes.INVOKE_INTERFACE)
@@ -190,6 +202,26 @@
     return get(Opcodes.MONITOR);
   }
 
+  public boolean mayHaveMul() {
+    return get(Opcodes.MUL);
+  }
+
+  public boolean mayHaveOr() {
+    return get(Opcodes.OR);
+  }
+
+  public boolean mayHaveRem() {
+    return get(Opcodes.REM);
+  }
+
+  public boolean mayHaveShl() {
+    return get(Opcodes.SHL);
+  }
+
+  public boolean mayHaveShr() {
+    return get(Opcodes.SHR);
+  }
+
   public boolean mayHaveStaticGet() {
     return get(Opcodes.STATIC_GET);
   }
@@ -202,8 +234,58 @@
     return get(Opcodes.STRING_SWITCH);
   }
 
+  public boolean mayHaveSub() {
+    return get(Opcodes.SUB);
+  }
+
+  public boolean mayHaveUshr() {
+    return get(Opcodes.USHR);
+  }
+
+  public boolean mayHaveXor() {
+    return get(Opcodes.XOR);
+  }
+
   public boolean mayHaveArithmeticOrLogicalBinop() {
-    // TODO(b/7145202413): Implement this.
-    return true;
+    // ArithmeticBinop
+    assert Opcodes.ADD < 64;
+    assert Opcodes.DIV < 64;
+    assert Opcodes.MUL < 64;
+    assert Opcodes.REM < 64;
+    assert Opcodes.SUB < 64;
+    // LogicalBinop
+    assert Opcodes.AND < 64;
+    assert Opcodes.OR < 64;
+    assert Opcodes.SHL < 64;
+    assert Opcodes.SHR < 64;
+    assert Opcodes.USHR >= 64;
+    assert Opcodes.XOR >= 64;
+    long mask =
+        (1L << Opcodes.ADD)
+            | (1L << Opcodes.DIV)
+            | (1L << Opcodes.MUL)
+            | (1L << Opcodes.REM)
+            | (1L << Opcodes.SUB)
+            | (1L << Opcodes.AND)
+            | (1L << Opcodes.OR)
+            | (1L << Opcodes.SHL)
+            | (1L << Opcodes.SHR)
+            | (1L << Opcodes.USHR)
+            | (1L << Opcodes.XOR);
+    long other = (1L << (Opcodes.USHR - 64)) | (1L << (Opcodes.XOR - 64));
+    boolean result = isAnySetInFirst(mask) || isAnySetInSecond(other);
+    assert result
+        == (mayHaveAdd()
+            || mayHaveDiv()
+            || mayHaveMul()
+            || mayHaveRem()
+            || mayHaveSub()
+            || mayHaveAnd()
+            || mayHaveOr()
+            || mayHaveShl()
+            || mayHaveShr()
+            || mayHaveUshr()
+            || mayHaveXor());
+    return result;
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
index d48d1f2..326c17b 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
@@ -3019,7 +3019,7 @@
                 newInstruction.setBlock(phiBlock);
                 // The xor is replacing a phi so it does not have an actual position.
                 newInstruction.setPosition(phiPosition);
-                phiBlock.getInstructions().add(insertIndex, newInstruction);
+                phiBlock.listIterator(code, insertIndex).add(newInstruction);
                 deadPhis++;
               }
             }