Revert "Revert "[optimizing] Replace FP divide by power of 2""

This reverts commit 067cae2c86627d2edcf01b918ee601774bc76aeb.

Change-Id: Iaaa8772500ea7d3dce6ae0829dc0dc3bbc9c14ca
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index 6f227fc..91422fa 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -1459,26 +1459,6 @@
       return InexpensiveConstantInt(value);
     }
 
-    /**
-     * @brief Whether division by the given divisor can be converted to multiply by its reciprocal.
-     * @param divisor A constant divisor bits of float type.
-     * @return Returns true iff, x/divisor == x*(1.0f/divisor), for every float x.
-     */
-    bool CanDivideByReciprocalMultiplyFloat(int32_t divisor) {
-      // True, if float value significand bits are 0.
-      return ((divisor & 0x7fffff) == 0);
-    }
-
-    /**
-     * @brief Whether division by the given divisor can be converted to multiply by its reciprocal.
-     * @param divisor A constant divisor bits of double type.
-     * @return Returns true iff, x/divisor == x*(1.0/divisor), for every double x.
-     */
-    bool CanDivideByReciprocalMultiplyDouble(int64_t divisor) {
-      // True, if double value significand bits are 0.
-      return ((divisor & ((UINT64_C(1) << 52) - 1)) == 0);
-    }
-
     // May be optimized by targets.
     virtual void GenMonitorEnter(int opt_flags, RegLocation rl_src);
     virtual void GenMonitorExit(int opt_flags, RegLocation rl_src);
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index 2df7c16..e79d4f4 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -377,15 +377,42 @@
     return;
   }
 
-  if ((input_cst != nullptr) && input_cst->IsMinusOne() &&
-      (Primitive::IsFloatingPointType(type) || Primitive::IsIntOrLongType(type))) {
+  if ((input_cst != nullptr) && input_cst->IsMinusOne()) {
     // Replace code looking like
     //    DIV dst, src, -1
     // with
     //    NEG dst, src
     instruction->GetBlock()->ReplaceAndRemoveInstructionWith(
-        instruction, (new (GetGraph()->GetArena()) HNeg(type, input_other)));
+        instruction, new (GetGraph()->GetArena()) HNeg(type, input_other));
     RecordSimplification();
+    return;
+  }
+
+  if ((input_cst != nullptr) && Primitive::IsFloatingPointType(type)) {
+    // Try replacing code looking like
+    //    DIV dst, src, constant
+    // with
+    //    MUL dst, src, 1 / constant
+    HConstant* reciprocal = nullptr;
+    if (type == Primitive::Primitive::kPrimDouble) {
+      double value = input_cst->AsDoubleConstant()->GetValue();
+      if (CanDivideByReciprocalMultiplyDouble(bit_cast<int64_t, double>(value))) {
+        reciprocal = GetGraph()->GetDoubleConstant(1.0 / value);
+      }
+    } else {
+      DCHECK_EQ(type, Primitive::kPrimFloat);
+      float value = input_cst->AsFloatConstant()->GetValue();
+      if (CanDivideByReciprocalMultiplyFloat(bit_cast<int32_t, float>(value))) {
+        reciprocal = GetGraph()->GetFloatConstant(1.0f / value);
+      }
+    }
+
+    if (reciprocal != nullptr) {
+      instruction->GetBlock()->ReplaceAndRemoveInstructionWith(
+          instruction, new (GetGraph()->GetArena()) HMul(type, input_other, reciprocal));
+      RecordSimplification();
+      return;
+    }
   }
 }
 
diff --git a/runtime/utils.h b/runtime/utils.h
index 853fa08..eaafcf0 100644
--- a/runtime/utils.h
+++ b/runtime/utils.h
@@ -300,6 +300,18 @@
   return CTZ(x);
 }
 
+// Return whether x / divisor == x * (1.0f / divisor), for every float x.
+static constexpr bool CanDivideByReciprocalMultiplyFloat(int32_t divisor) {
+  // True, if the most significant bits of divisor are 0.
+  return ((divisor & 0x7fffff) == 0);
+}
+
+// Return whether x / divisor == x * (1.0 / divisor), for every double x.
+static constexpr bool CanDivideByReciprocalMultiplyDouble(int64_t divisor) {
+  // True, if the most significant bits of divisor are 0.
+  return ((divisor & ((UINT64_C(1) << 52) - 1)) == 0);
+}
+
 template<typename T>
 static constexpr int POPCOUNT(T x) {
   return (sizeof(T) == sizeof(uint32_t))
diff --git a/test/458-checker-instruction-simplification/src/Main.java b/test/458-checker-instruction-simplification/src/Main.java
index 0dbda6b..5d5a6b3 100644
--- a/test/458-checker-instruction-simplification/src/Main.java
+++ b/test/458-checker-instruction-simplification/src/Main.java
@@ -34,6 +34,18 @@
     }
   }
 
+  public static void assertFloatEquals(float expected, float result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  public static void assertDoubleEquals(double expected, double result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
   /**
    * Tiny programs exercising optimizations of arithmetic identities.
    */
@@ -926,6 +938,80 @@
     return !(NegateValue(arg));
   }
 
+  // CHECK-START: float Main.Div2(float) instruction_simplifier (before)
+  // CHECK-DAG:      [[Arg:f\d+]]      ParameterValue
+  // CHECK-DAG:      [[Const2:f\d+]]   FloatConstant 2
+  // CHECK-DAG:      [[Div:f\d+]]      Div [ [[Arg]] [[Const2]] ]
+  // CHECK-DAG:                        Return [ [[Div]] ]
+
+  // CHECK-START: float Main.Div2(float) instruction_simplifier (after)
+  // CHECK-DAG:      [[Arg:f\d+]]      ParameterValue
+  // CHECK-DAG:      [[ConstP5:f\d+]]  FloatConstant 0.5
+  // CHECK-DAG:      [[Mul:f\d+]]      Mul [ [[Arg]] [[ConstP5]] ]
+  // CHECK-DAG:                        Return [ [[Mul]] ]
+
+  // CHECK-START: float Main.Div2(float) instruction_simplifier (after)
+  // CHECK-NOT:                        Div
+
+  public static float Div2(float arg) {
+    return arg / 2.0f;
+  }
+
+  // CHECK-START: double Main.Div2(double) instruction_simplifier (before)
+  // CHECK-DAG:      [[Arg:d\d+]]      ParameterValue
+  // CHECK-DAG:      [[Const2:d\d+]]   DoubleConstant 2
+  // CHECK-DAG:      [[Div:d\d+]]      Div [ [[Arg]] [[Const2]] ]
+  // CHECK-DAG:                        Return [ [[Div]] ]
+
+  // CHECK-START: double Main.Div2(double) instruction_simplifier (after)
+  // CHECK-DAG:      [[Arg:d\d+]]      ParameterValue
+  // CHECK-DAG:      [[ConstP5:d\d+]]  DoubleConstant 0.5
+  // CHECK-DAG:      [[Mul:d\d+]]      Mul [ [[Arg]] [[ConstP5]] ]
+  // CHECK-DAG:                        Return [ [[Mul]] ]
+
+  // CHECK-START: double Main.Div2(double) instruction_simplifier (after)
+  // CHECK-NOT:                        Div
+  public static double Div2(double arg) {
+    return arg / 2.0;
+  }
+
+  // CHECK-START: float Main.DivMP25(float) instruction_simplifier (before)
+  // CHECK-DAG:      [[Arg:f\d+]]      ParameterValue
+  // CHECK-DAG:      [[ConstMP25:f\d+]]   FloatConstant -0.25
+  // CHECK-DAG:      [[Div:f\d+]]      Div [ [[Arg]] [[ConstMP25]] ]
+  // CHECK-DAG:                        Return [ [[Div]] ]
+
+  // CHECK-START: float Main.DivMP25(float) instruction_simplifier (after)
+  // CHECK-DAG:      [[Arg:f\d+]]      ParameterValue
+  // CHECK-DAG:      [[ConstM4:f\d+]]  FloatConstant -4
+  // CHECK-DAG:      [[Mul:f\d+]]      Mul [ [[Arg]] [[ConstM4]] ]
+  // CHECK-DAG:                        Return [ [[Mul]] ]
+
+  // CHECK-START: float Main.DivMP25(float) instruction_simplifier (after)
+  // CHECK-NOT:                        Div
+
+  public static float DivMP25(float arg) {
+    return arg / -0.25f;
+  }
+
+  // CHECK-START: double Main.DivMP25(double) instruction_simplifier (before)
+  // CHECK-DAG:      [[Arg:d\d+]]      ParameterValue
+  // CHECK-DAG:      [[ConstMP25:d\d+]]   DoubleConstant -0.25
+  // CHECK-DAG:      [[Div:d\d+]]      Div [ [[Arg]] [[ConstMP25]] ]
+  // CHECK-DAG:                        Return [ [[Div]] ]
+
+  // CHECK-START: double Main.DivMP25(double) instruction_simplifier (after)
+  // CHECK-DAG:      [[Arg:d\d+]]      ParameterValue
+  // CHECK-DAG:      [[ConstM4:d\d+]]  DoubleConstant -4
+  // CHECK-DAG:      [[Mul:d\d+]]      Mul [ [[Arg]] [[ConstM4]] ]
+  // CHECK-DAG:                        Return [ [[Mul]] ]
+
+  // CHECK-START: double Main.DivMP25(double) instruction_simplifier (after)
+  // CHECK-NOT:                        Div
+  public static double DivMP25(double arg) {
+    return arg / -0.25f;
+  }
+
   public static void main(String[] args) {
     int arg = 123456;
 
@@ -960,7 +1046,6 @@
     assertIntEquals(SubNeg1(arg, arg + 1), -(arg + arg + 1));
     assertIntEquals(SubNeg2(arg, arg + 1), -(arg + arg + 1));
     assertLongEquals(SubNeg3(arg, arg + 1), -(2 * arg + 1));
-
     assertIntEquals(EqualTrueRhs(true), 5);
     assertIntEquals(EqualTrueLhs(true), 5);
     assertIntEquals(EqualFalseRhs(true), 3);
@@ -971,5 +1056,9 @@
     assertIntEquals(NotEqualFalseLhs(true), 5);
     assertBooleanEquals(NotNotBool(true), true);
     assertBooleanEquals(NotNotBool(false), false);
+    assertFloatEquals(Div2(100.0f), 50.0f);
+    assertDoubleEquals(Div2(150.0), 75.0);
+    assertFloatEquals(DivMP25(100.0f), -400.0f);
+    assertDoubleEquals(DivMP25(150.0), -600.0);
   }
 }