summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/optimizing/instruction_simplifier.cc95
-rw-r--r--test/458-checker-instruct-simplification/src/Main.java158
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; }