diff options
| -rw-r--r-- | compiler/dex/quick/mir_to_lir.h | 20 | ||||
| -rw-r--r-- | compiler/optimizing/instruction_simplifier.cc | 33 | ||||
| -rw-r--r-- | runtime/utils.h | 12 | ||||
| -rw-r--r-- | test/458-checker-instruction-simplification/src/Main.java | 91 |
4 files changed, 132 insertions, 24 deletions
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h index a07274f17e..4fdc7289bf 100644 --- a/compiler/dex/quick/mir_to_lir.h +++ b/compiler/dex/quick/mir_to_lir.h @@ -1467,26 +1467,6 @@ class Mir2Lir { 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 2df7c166d8..e79d4f4bdc 100644 --- a/compiler/optimizing/instruction_simplifier.cc +++ b/compiler/optimizing/instruction_simplifier.cc @@ -377,15 +377,42 @@ void InstructionSimplifierVisitor::VisitDiv(HDiv* instruction) { 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 853fa08251..eaafcf0a64 100644 --- a/runtime/utils.h +++ b/runtime/utils.h @@ -300,6 +300,18 @@ static inline int WhichPowerOf2(T x) { 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 0dbda6b3eb..5d5a6b3627 100644 --- a/test/458-checker-instruction-simplification/src/Main.java +++ b/test/458-checker-instruction-simplification/src/Main.java @@ -34,6 +34,18 @@ public class Main { } } + 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 @@ public class Main { 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 @@ public class Main { 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 @@ public class Main { 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); } } |