diff options
-rw-r--r-- | compiler/optimizing/instruction_simplifier.cc | 95 | ||||
-rw-r--r-- | test/458-checker-instruct-simplification/src/Main.java | 158 |
2 files changed, 207 insertions, 46 deletions
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc index 4a1813266e..0e2a62226f 100644 --- a/compiler/optimizing/instruction_simplifier.cc +++ b/compiler/optimizing/instruction_simplifier.cc @@ -1050,51 +1050,60 @@ void InstructionSimplifierVisitor::VisitSelect(HSelect* select) { HInstruction* b = condition->InputAt(1); DataType::Type t_type = true_value->GetType(); DataType::Type f_type = false_value->GetType(); - // Here we have a <cmp> b ? true_value : false_value. - // Test if both values are compatible integral types (resulting MIN/MAX/ABS - // type will be int or long, like the condition). Replacements are general, - // but assume conditions prefer constants on the right. if (DataType::IsIntegralType(t_type) && DataType::Kind(t_type) == DataType::Kind(f_type)) { - // Allow a < 100 ? max(a, -100) : .. - // or a > -100 ? min(a, 100) : .. - // to use min/max instead of a to detect nested min/max expressions. - HInstruction* new_a = AllowInMinMax(cmp, a, b, true_value); - if (new_a != nullptr) { - a = new_a; - } - // Try to replace typical integral MIN/MAX/ABS constructs. - if ((cmp == kCondLT || cmp == kCondLE || cmp == kCondGT || cmp == kCondGE) && - ((a == true_value && b == false_value) || - (b == true_value && a == false_value))) { - // Found a < b ? a : b (MIN) or a < b ? b : a (MAX) - // or a > b ? a : b (MAX) or a > b ? b : a (MIN). - bool is_min = (cmp == kCondLT || cmp == kCondLE) == (a == true_value); - replace_with = NewIntegralMinMax(GetGraph()->GetAllocator(), a, b, select, is_min); - } else if (((cmp == kCondLT || cmp == kCondLE) && true_value->IsNeg()) || - ((cmp == kCondGT || cmp == kCondGE) && false_value->IsNeg())) { - bool negLeft = (cmp == kCondLT || cmp == kCondLE); - HInstruction* the_negated = negLeft ? true_value->InputAt(0) : false_value->InputAt(0); - HInstruction* not_negated = negLeft ? false_value : true_value; - if (a == the_negated && a == not_negated && IsInt64Value(b, 0)) { - // Found a < 0 ? -a : a - // or a > 0 ? a : -a - // which can be replaced by ABS(a). - replace_with = NewIntegralAbs(GetGraph()->GetAllocator(), a, select); + if (cmp == kCondEQ || cmp == kCondNE) { + // Turns + // * Select[a, b, EQ(a,b)] / Select[a, b, EQ(b,a)] into a + // * Select[a, b, NE(a,b)] / Select[a, b, NE(b,a)] into b + // Note that the order in EQ/NE is irrelevant. + if ((a == true_value && b == false_value) || (a == false_value && b == true_value)) { + replace_with = cmp == kCondEQ ? false_value : true_value; + } + } else { + // Test if both values are compatible integral types (resulting MIN/MAX/ABS + // type will be int or long, like the condition). Replacements are general, + // but assume conditions prefer constants on the right. + + // Allow a < 100 ? max(a, -100) : .. + // or a > -100 ? min(a, 100) : .. + // to use min/max instead of a to detect nested min/max expressions. + HInstruction* new_a = AllowInMinMax(cmp, a, b, true_value); + if (new_a != nullptr) { + a = new_a; } - } else if (true_value->IsSub() && false_value->IsSub()) { - HInstruction* true_sub1 = true_value->InputAt(0); - HInstruction* true_sub2 = true_value->InputAt(1); - HInstruction* false_sub1 = false_value->InputAt(0); - HInstruction* false_sub2 = false_value->InputAt(1); - if ((((cmp == kCondGT || cmp == kCondGE) && - (a == true_sub1 && b == true_sub2 && a == false_sub2 && b == false_sub1)) || - ((cmp == kCondLT || cmp == kCondLE) && - (a == true_sub2 && b == true_sub1 && a == false_sub1 && b == false_sub2))) && - AreLowerPrecisionArgs(t_type, a, b)) { - // Found a > b ? a - b : b - a - // or a < b ? b - a : a - b - // which can be replaced by ABS(a - b) for lower precision operands a, b. - replace_with = NewIntegralAbs(GetGraph()->GetAllocator(), true_value, select); + // Try to replace typical integral MIN/MAX/ABS constructs. + if ((cmp == kCondLT || cmp == kCondLE || cmp == kCondGT || cmp == kCondGE) && + ((a == true_value && b == false_value) || (b == true_value && a == false_value))) { + // Found a < b ? a : b (MIN) or a < b ? b : a (MAX) + // or a > b ? a : b (MAX) or a > b ? b : a (MIN). + bool is_min = (cmp == kCondLT || cmp == kCondLE) == (a == true_value); + replace_with = NewIntegralMinMax(GetGraph()->GetAllocator(), a, b, select, is_min); + } else if (((cmp == kCondLT || cmp == kCondLE) && true_value->IsNeg()) || + ((cmp == kCondGT || cmp == kCondGE) && false_value->IsNeg())) { + bool negLeft = (cmp == kCondLT || cmp == kCondLE); + HInstruction* the_negated = negLeft ? true_value->InputAt(0) : false_value->InputAt(0); + HInstruction* not_negated = negLeft ? false_value : true_value; + if (a == the_negated && a == not_negated && IsInt64Value(b, 0)) { + // Found a < 0 ? -a : a + // or a > 0 ? a : -a + // which can be replaced by ABS(a). + replace_with = NewIntegralAbs(GetGraph()->GetAllocator(), a, select); + } + } else if (true_value->IsSub() && false_value->IsSub()) { + HInstruction* true_sub1 = true_value->InputAt(0); + HInstruction* true_sub2 = true_value->InputAt(1); + HInstruction* false_sub1 = false_value->InputAt(0); + HInstruction* false_sub2 = false_value->InputAt(1); + if ((((cmp == kCondGT || cmp == kCondGE) && + (a == true_sub1 && b == true_sub2 && a == false_sub2 && b == false_sub1)) || + ((cmp == kCondLT || cmp == kCondLE) && + (a == true_sub2 && b == true_sub1 && a == false_sub1 && b == false_sub2))) && + AreLowerPrecisionArgs(t_type, a, b)) { + // Found a > b ? a - b : b - a + // or a < b ? b - a : a - b + // which can be replaced by ABS(a - b) for lower precision operands a, b. + replace_with = NewIntegralAbs(GetGraph()->GetAllocator(), true_value, select); + } } } } diff --git a/test/458-checker-instruct-simplification/src/Main.java b/test/458-checker-instruct-simplification/src/Main.java index 46ac7f04ba..fb3d184203 100644 --- a/test/458-checker-instruct-simplification/src/Main.java +++ b/test/458-checker-instruct-simplification/src/Main.java @@ -2982,6 +2982,144 @@ public class Main { return array[0]; } + // If a == b returns b (which is equal to a) else returns a. This can be simplified to just + // return a. + + /// CHECK-START: int Main.$noinline$returnSecondIfEqualElseFirstInt(int, int) instruction_simplifier$after_gvn (before) + /// CHECK: <<Param1:i\d+>> ParameterValue + /// CHECK: <<Param2:i\d+>> ParameterValue + /// CHECK: <<Select:i\d+>> Select [<<Param2>>,<<Param1>>,<<Cond:z\d+>>] + /// CHECK: <<Return:v\d+>> Return [<<Select>>] + + /// CHECK-START: int Main.$noinline$returnSecondIfEqualElseFirstInt(int, int) instruction_simplifier$after_gvn (after) + /// CHECK: <<Param1:i\d+>> ParameterValue + /// CHECK: <<Param2:i\d+>> ParameterValue + /// CHECK: <<Return:v\d+>> Return [<<Param1>>] + + /// CHECK-START: int Main.$noinline$returnSecondIfEqualElseFirstInt(int, int) instruction_simplifier$after_gvn (after) + /// CHECK-NOT: Select + private static int $noinline$returnSecondIfEqualElseFirstInt(int a, int b) { + return a == b ? b : a; + } + + /// CHECK-START: long Main.$noinline$returnSecondIfEqualElseFirstLong(long, long) instruction_simplifier$after_gvn (before) + /// CHECK: <<Param1:j\d+>> ParameterValue + /// CHECK: <<Param2:j\d+>> ParameterValue + /// CHECK: <<Select:j\d+>> Select [<<Param2>>,<<Param1>>,<<Cond:z\d+>>] + /// CHECK: <<Return:v\d+>> Return [<<Select>>] + + /// CHECK-START: long Main.$noinline$returnSecondIfEqualElseFirstLong(long, long) instruction_simplifier$after_gvn (after) + /// CHECK: <<Param1:j\d+>> ParameterValue + /// CHECK: <<Param2:j\d+>> ParameterValue + /// CHECK: <<Return:v\d+>> Return [<<Param1>>] + + /// CHECK-START: long Main.$noinline$returnSecondIfEqualElseFirstLong(long, long) instruction_simplifier$after_gvn (after) + /// CHECK-NOT: Select + private static long $noinline$returnSecondIfEqualElseFirstLong(long a, long b) { + return a == b ? b : a; + } + + // Note that we do not do the optimization for Float/Double. + + /// CHECK-START: float Main.$noinline$returnSecondIfEqualElseFirstFloat(float, float) instruction_simplifier$after_gvn (before) + /// CHECK: <<Param1:f\d+>> ParameterValue + /// CHECK: <<Param2:f\d+>> ParameterValue + /// CHECK: <<Select:f\d+>> Select [<<Param2>>,<<Param1>>,<<Cond:z\d+>>] + /// CHECK: <<Return:v\d+>> Return [<<Select>>] + + /// CHECK-START: float Main.$noinline$returnSecondIfEqualElseFirstFloat(float, float) disassembly (after) + /// CHECK: <<Param1:f\d+>> ParameterValue + /// CHECK: <<Param2:f\d+>> ParameterValue + /// CHECK: <<Select:f\d+>> Select [<<Param2>>,<<Param1>>,<<Cond:z\d+>>] + /// CHECK: <<Return:v\d+>> Return [<<Select>>] + private static float $noinline$returnSecondIfEqualElseFirstFloat(float a, float b) { + return a == b ? b : a; + } + + /// CHECK-START: double Main.$noinline$returnSecondIfEqualElseFirstDouble(double, double) instruction_simplifier$after_gvn (before) + /// CHECK: <<Param1:d\d+>> ParameterValue + /// CHECK: <<Param2:d\d+>> ParameterValue + /// CHECK: <<Select:d\d+>> Select [<<Param2>>,<<Param1>>,<<Cond:z\d+>>] + /// CHECK: <<Return:v\d+>> Return [<<Select>>] + + /// CHECK-START: double Main.$noinline$returnSecondIfEqualElseFirstDouble(double, double) disassembly (after) + /// CHECK: <<Param1:d\d+>> ParameterValue + /// CHECK: <<Param2:d\d+>> ParameterValue + /// CHECK: <<Select:d\d+>> Select [<<Param2>>,<<Param1>>,<<Cond:z\d+>>] + /// CHECK: <<Return:v\d+>> Return [<<Select>>] + private static double $noinline$returnSecondIfEqualElseFirstDouble(double a, double b) { + return a == b ? b : a; + } + + // If a != b returns b else returns a (which is equal to b). This can be simplified to just + // return b. + + /// CHECK-START: int Main.$noinline$returnSecondIfNotEqualElseFirstInt(int, int) instruction_simplifier$after_gvn (before) + /// CHECK: <<Param1:i\d+>> ParameterValue + /// CHECK: <<Param2:i\d+>> ParameterValue + /// CHECK: <<Select:i\d+>> Select [<<Param2>>,<<Param1>>,<<Cond:z\d+>>] + /// CHECK: <<Return:v\d+>> Return [<<Select>>] + + /// CHECK-START: int Main.$noinline$returnSecondIfNotEqualElseFirstInt(int, int) instruction_simplifier$after_gvn (after) + /// CHECK: <<Param1:i\d+>> ParameterValue + /// CHECK: <<Param2:i\d+>> ParameterValue + /// CHECK: <<Return:v\d+>> Return [<<Param2>>] + + /// CHECK-START: int Main.$noinline$returnSecondIfNotEqualElseFirstInt(int, int) instruction_simplifier$after_gvn (after) + /// CHECK-NOT: Select + private static int $noinline$returnSecondIfNotEqualElseFirstInt(int a, int b) { + return a != b ? b : a; + } + + /// CHECK-START: long Main.$noinline$returnSecondIfNotEqualElseFirstLong(long, long) instruction_simplifier$after_gvn (before) + /// CHECK: <<Param1:j\d+>> ParameterValue + /// CHECK: <<Param2:j\d+>> ParameterValue + /// CHECK: <<Select:j\d+>> Select [<<Param2>>,<<Param1>>,<<Cond:z\d+>>] + /// CHECK: <<Return:v\d+>> Return [<<Select>>] + + /// CHECK-START: long Main.$noinline$returnSecondIfNotEqualElseFirstLong(long, long) instruction_simplifier$after_gvn (after) + /// CHECK: <<Param1:j\d+>> ParameterValue + /// CHECK: <<Param2:j\d+>> ParameterValue + /// CHECK: <<Return:v\d+>> Return [<<Param2>>] + + /// CHECK-START: long Main.$noinline$returnSecondIfNotEqualElseFirstLong(long, long) instruction_simplifier$after_gvn (after) + /// CHECK-NOT: Select + private static long $noinline$returnSecondIfNotEqualElseFirstLong(long a, long b) { + return a != b ? b : a; + } + + // Note that we do not do the optimization for Float/Double. + + /// CHECK-START: float Main.$noinline$returnSecondIfNotEqualElseFirstFloat(float, float) instruction_simplifier$after_gvn (before) + /// CHECK: <<Param1:f\d+>> ParameterValue + /// CHECK: <<Param2:f\d+>> ParameterValue + /// CHECK: <<Select:f\d+>> Select [<<Param2>>,<<Param1>>,<<Cond:z\d+>>] + /// CHECK: <<Return:v\d+>> Return [<<Select>>] + + /// CHECK-START: float Main.$noinline$returnSecondIfNotEqualElseFirstFloat(float, float) disassembly (after) + /// CHECK: <<Param1:f\d+>> ParameterValue + /// CHECK: <<Param2:f\d+>> ParameterValue + /// CHECK: <<Select:f\d+>> Select [<<Param2>>,<<Param1>>,<<Cond:z\d+>>] + /// CHECK: <<Return:v\d+>> Return [<<Select>>] + private static float $noinline$returnSecondIfNotEqualElseFirstFloat(float a, float b) { + return a != b ? b : a; + } + + /// CHECK-START: double Main.$noinline$returnSecondIfNotEqualElseFirstDouble(double, double) instruction_simplifier$after_gvn (before) + /// CHECK: <<Param1:d\d+>> ParameterValue + /// CHECK: <<Param2:d\d+>> ParameterValue + /// CHECK: <<Select:d\d+>> Select [<<Param2>>,<<Param1>>,<<Cond:z\d+>>] + /// CHECK: <<Return:v\d+>> Return [<<Select>>] + + /// CHECK-START: double Main.$noinline$returnSecondIfNotEqualElseFirstDouble(double, double) disassembly (after) + /// CHECK: <<Param1:d\d+>> ParameterValue + /// CHECK: <<Param2:d\d+>> ParameterValue + /// CHECK: <<Select:d\d+>> Select [<<Param2>>,<<Param1>>,<<Cond:z\d+>>] + /// CHECK: <<Return:v\d+>> Return [<<Select>>] + private static double $noinline$returnSecondIfNotEqualElseFirstDouble(double a, double b) { + return a != b ? b : a; + } + public static void main(String[] args) throws Exception { Class smaliTests2 = Class.forName("SmaliTests2"); Method $noinline$XorAllOnes = smaliTests2.getMethod("$noinline$XorAllOnes", int.class); @@ -3194,7 +3332,7 @@ public class Main { assertFloatEquals(floatArg, $noinline$floatSubAddSimplifyRight(floatArg, 654321.125f)); // Sub/Add and Sub/Sub simplifications - int[] int_inputs = {0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE, 42, -9000}; + final int[] int_inputs = {0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE, 42, -9000}; for (int x : int_inputs) { for (int y : int_inputs) { // y - (x + y) = -x @@ -3208,8 +3346,8 @@ public class Main { } } - long[] long_inputs = {0L, 1L, -1L, Long.MIN_VALUE, Long.MAX_VALUE, 0x100000000L, 0x100000001L, - -9000L, 0x0123456789ABCDEFL}; + final long[] long_inputs = {0L, 1L, -1L, Long.MIN_VALUE, Long.MAX_VALUE, 0x100000000L, + 0x100000001L, -9000L, 0x0123456789ABCDEFL}; for (long x : long_inputs) { for (long y : long_inputs) { // y - (x + y) = -x @@ -3321,6 +3459,20 @@ public class Main { assertIntEquals(111, $noinline$redundantAndRegressionNotConstant(-1, 0x6f45)); assertIntEquals(50, $noinline$deadAddAfterUnrollingAndSimplification(new int[] { 0 })); + + for (int x : int_inputs) { + for (int y : int_inputs) { + assertIntEquals(x, $noinline$returnSecondIfEqualElseFirstInt(x, y)); + assertIntEquals(y, $noinline$returnSecondIfNotEqualElseFirstInt(x, y)); + } + } + + for (long x : long_inputs) { + for (long y : long_inputs) { + assertLongEquals(x, $noinline$returnSecondIfEqualElseFirstLong(x, y)); + assertLongEquals(y, $noinline$returnSecondIfNotEqualElseFirstLong(x, y)); + } + } } private static boolean $inline$true() { return true; } |