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);
}
}