ART: Delete code optimizing a%1 and a%-1 from InstructionCodeGeneratorARM64

In InstructionWithAbsorbingInputSimplifier there is code optimizing a%1
and a%-1. So the code in InstructionCodeGeneratorARM64 optimizing such
cases can be deleted.

This patch deletes the code from InstructionCodeGeneratorARM64 and adds
additional tests.

Test: 012-math, 014-math3, 411-optimizing-arith, 411-checker-hdiv-hrem-pow2
Test: 701-easy-div-rem, 442-checker-constant-folding
Test: test-art-host, test-art-target
Change-Id: Ib80c0aa4c3e28b07fa79bb43783274c9d7fc456a
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index d1c83ce..02c995a 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -5678,14 +5678,6 @@
   }
 }
 
-void InstructionCodeGeneratorARM64::GenerateIntRemForOneOrMinusOneDenom(HRem *instruction) {
-  int64_t imm = Int64FromLocation(instruction->GetLocations()->InAt(1));
-  DCHECK(imm == 1 || imm == -1) << imm;
-
-  Register out = OutputRegister(instruction);
-  __ Mov(out, 0);
-}
-
 void InstructionCodeGeneratorARM64::GenerateIntRemForConstDenom(HRem *instruction) {
   int64_t imm = Int64FromLocation(instruction->GetLocations()->InAt(1));
 
@@ -5695,10 +5687,12 @@
     return;
   }
 
-  if (imm == 1 || imm == -1) {
-    // TODO: These cases need to be optimized in InstructionSimplifier
-    GenerateIntRemForOneOrMinusOneDenom(instruction);
-  } else if (IsPowerOfTwo(AbsOrMin(imm))) {
+  if (IsPowerOfTwo(AbsOrMin(imm))) {
+    // Cases imm == -1 or imm == 1 are handled in constant folding by
+    // InstructionWithAbsorbingInputSimplifier.
+    // If the cases have survided till code generation they are handled in
+    // GenerateIntRemForPower2Denom becauses -1 and 1 are the power of 2 (2^0).
+    // The correct code is generated for them, just more instructions.
     GenerateIntRemForPower2Denom(instruction);
   } else {
     DCHECK(imm < -2 || imm > 2) << imm;
diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h
index c44fa48..93bab31 100644
--- a/compiler/optimizing/code_generator_arm64.h
+++ b/compiler/optimizing/code_generator_arm64.h
@@ -327,7 +327,6 @@
   void GenerateIntDivForPower2Denom(HDiv *instruction);
   void GenerateIntRem(HRem* instruction);
   void GenerateIntRemForConstDenom(HRem *instruction);
-  void GenerateIntRemForOneOrMinusOneDenom(HRem *instruction);
   void GenerateIntRemForPower2Denom(HRem *instruction);
   void HandleGoto(HInstruction* got, HBasicBlock* successor);
 
diff --git a/test/411-optimizing-arith/src/RemTest.java b/test/411-optimizing-arith/src/RemTest.java
index 1b31f63..287f5d8 100644
--- a/test/411-optimizing-arith/src/RemTest.java
+++ b/test/411-optimizing-arith/src/RemTest.java
@@ -89,6 +89,34 @@
     expectDivisionByZero(5L);
     expectDivisionByZero(Long.MAX_VALUE);
     expectDivisionByZero(Long.MIN_VALUE);
+
+    expectEquals(0, $noinline$RemLoaded1(0));
+    expectEquals(0, $noinline$RemLoaded1(1));
+    expectEquals(0, $noinline$RemLoaded1(-1));
+    expectEquals(0, $noinline$RemLoaded1(12345));
+    expectEquals(0, $noinline$RemLoaded1(Integer.MAX_VALUE));
+    expectEquals(0, $noinline$RemLoaded1(Integer.MIN_VALUE));
+
+    expectEquals(0, $noinline$RemLoadedN1(0));
+    expectEquals(0, $noinline$RemLoadedN1(1));
+    expectEquals(0, $noinline$RemLoadedN1(-1));
+    expectEquals(0, $noinline$RemLoadedN1(12345));
+    expectEquals(0, $noinline$RemLoadedN1(Integer.MAX_VALUE));
+    expectEquals(0, $noinline$RemLoadedN1(Integer.MIN_VALUE));
+
+    expectEquals(0L, $noinline$RemLoaded1(0L));
+    expectEquals(0L, $noinline$RemLoaded1(1L));
+    expectEquals(0L, $noinline$RemLoaded1(-1L));
+    expectEquals(0L, $noinline$RemLoaded1(12345L));
+    expectEquals(0L, $noinline$RemLoaded1(Long.MAX_VALUE));
+    expectEquals(0L, $noinline$RemLoaded1(Long.MIN_VALUE));
+
+    expectEquals(0L, $noinline$RemLoadedN1(0L));
+    expectEquals(0L, $noinline$RemLoadedN1(1L));
+    expectEquals(0L, $noinline$RemLoadedN1(-1L));
+    expectEquals(0L, $noinline$RemLoadedN1(12345L));
+    expectEquals(0L, $noinline$RemLoadedN1(Long.MAX_VALUE));
+    expectEquals(0L, $noinline$RemLoadedN1(Long.MIN_VALUE));
   }
 
   static int $opt$Rem(int a, int b) {
@@ -99,6 +127,26 @@
     return a % 0;
   }
 
+  static int $noinline$RemLoaded1(int a) {
+    int[] v = {25, 1};
+    return a % v[1];
+  }
+
+  static int $noinline$RemLoadedN1(int a) {
+    int [] v = {25, -1};
+    return a % v[1];
+  }
+
+  static long $noinline$RemLoaded1(long a) {
+    long[] v = {25, 1};
+    return a % v[1];
+  }
+
+  static long $noinline$RemLoadedN1(long a) {
+    long [] v = {25, -1};
+    return a % v[1];
+  }
+
   // Modulo by literals != 0 should not generate checks.
   static int $opt$RemConst(int a) {
     return a % 4;
diff --git a/test/442-checker-constant-folding/src/Main.java b/test/442-checker-constant-folding/src/Main.java
index fcc3c1a..3d92943 100644
--- a/test/442-checker-constant-folding/src/Main.java
+++ b/test/442-checker-constant-folding/src/Main.java
@@ -1150,6 +1150,41 @@
     return arg % 1;
   }
 
+  /// CHECK-START: int Main.RemN1(int) constant_folding (before)
+  /// CHECK-DAG:     <<Arg:i\d+>>      ParameterValue
+  /// CHECK-DAG:     <<ConstN1:i\d+>>  IntConstant -1
+  /// CHECK-DAG:     <<Rem:i\d+>>      Rem [<<Arg>>,<<ConstN1>>]
+  /// CHECK-DAG:                       Return [<<Rem>>]
+
+  /// CHECK-START: int Main.RemN1(int) constant_folding (after)
+  /// CHECK-DAG:     <<Const0:i\d+>>   IntConstant 0
+  /// CHECK-DAG:                       Return [<<Const0>>]
+
+  /// CHECK-START: int Main.RemN1(int) constant_folding (after)
+  /// CHECK-NOT:                       Rem
+
+  public static int RemN1(int arg) {
+    return arg % -1;
+  }
+
+  /// CHECK-START: long Main.Rem1(long) constant_folding (before)
+  /// CHECK-DAG:     <<Arg:j\d+>>           ParameterValue
+  /// CHECK-DAG:     <<Const1:j\d+>>        LongConstant 1
+  /// CHECK-DAG:     <<DivZeroCheck:j\d+>>  DivZeroCheck [<<Const1>>]
+  /// CHECK-DAG:     <<Rem:j\d+>>           Rem [<<Arg>>,<<DivZeroCheck>>]
+  /// CHECK-DAG:                            Return [<<Rem>>]
+
+  /// CHECK-START: long Main.Rem1(long) constant_folding (after)
+  /// CHECK-DAG:     <<Const0:j\d+>>        LongConstant 0
+  /// CHECK-DAG:                            Return [<<Const0>>]
+
+  /// CHECK-START: long Main.Rem1(long) constant_folding (after)
+  /// CHECK-NOT:                            Rem
+
+  public static long Rem1(long arg) {
+    return arg % 1;
+  }
+
   /// CHECK-START: long Main.RemN1(long) constant_folding (before)
   /// CHECK-DAG:     <<Arg:j\d+>>           ParameterValue
   /// CHECK-DAG:     <<ConstN1:j\d+>>       LongConstant -1
@@ -1597,7 +1632,26 @@
     assertIntEquals(-1, OrAllOnes(arbitrary));
     assertLongEquals(0, Rem0(arbitrary));
     assertIntEquals(0, Rem1(arbitrary));
+    assertIntEquals(0, Rem1(0));
+    assertIntEquals(0, Rem1(-1));
+    assertIntEquals(0, Rem1(Integer.MAX_VALUE));
+    assertIntEquals(0, Rem1(Integer.MIN_VALUE));
+    assertIntEquals(0, RemN1(arbitrary));
+    assertIntEquals(0, RemN1(0));
+    assertIntEquals(0, RemN1(-1));
+    assertIntEquals(0, RemN1(Integer.MAX_VALUE));
+    assertIntEquals(0, RemN1(Integer.MIN_VALUE));
+    assertIntEquals(0, RemN1(arbitrary));
+    assertLongEquals(0, Rem1((long)arbitrary));
+    assertLongEquals(0, Rem1(0L));
+    assertLongEquals(0, Rem1(-1L));
+    assertLongEquals(0, Rem1(Long.MAX_VALUE));
+    assertLongEquals(0, Rem1(Long.MIN_VALUE));
     assertLongEquals(0, RemN1(arbitrary));
+    assertLongEquals(0, RemN1(0L));
+    assertLongEquals(0, RemN1(-1L));
+    assertLongEquals(0, RemN1(Long.MAX_VALUE));
+    assertLongEquals(0, RemN1(Long.MIN_VALUE));
     assertIntEquals(0, Shl0(arbitrary));
     assertLongEquals(0, ShlLong0WithInt(arbitrary));
     assertLongEquals(0, Shr0(arbitrary));