diff options
-rw-r--r-- | compiler/optimizing/instruction_simplifier.cc | 31 | ||||
-rw-r--r-- | test/679-checker-minmax/expected.txt | 1 | ||||
-rw-r--r-- | test/679-checker-minmax/info.txt | 1 | ||||
-rw-r--r-- | test/679-checker-minmax/src/Main.java | 159 |
4 files changed, 189 insertions, 3 deletions
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc index 34837700a2..2b6f90540f 100644 --- a/compiler/optimizing/instruction_simplifier.cc +++ b/compiler/optimizing/instruction_simplifier.cc @@ -854,11 +854,29 @@ static HInstruction* NewIntegralAbs(ArenaAllocator* allocator, HInstruction* cursor) { DataType::Type type = x->GetType(); DCHECK(type == DataType::Type::kInt32 || type == DataType::Type::kInt64); - HAbs* abs = new (allocator) HAbs(type, x, x->GetDexPc()); + HAbs* abs = new (allocator) HAbs(type, x, cursor->GetDexPc()); cursor->GetBlock()->InsertInstructionBefore(abs, cursor); return abs; } +// Constructs a new MIN/MAX(x, y) node in the HIR. +static HInstruction* NewIntegralMinMax(ArenaAllocator* allocator, + HInstruction* x, + HInstruction* y, + HInstruction* cursor, + bool is_min) { + DataType::Type type = x->GetType(); + DCHECK(type == DataType::Type::kInt32 || type == DataType::Type::kInt64); + HBinaryOperation* minmax = nullptr; + if (is_min) { + minmax = new (allocator) HMin(type, x, y, cursor->GetDexPc()); + } else { + minmax = new (allocator) HMax(type, x, y, cursor->GetDexPc()); + } + cursor->GetBlock()->InsertInstructionBefore(minmax, cursor); + return minmax; +} + // Returns true if operands a and b consists of widening type conversions // (either explicit or implicit) to the given to_type. static bool AreLowerPrecisionArgs(DataType::Type to_type, HInstruction* a, HInstruction* b) { @@ -924,8 +942,15 @@ void InstructionSimplifierVisitor::VisitSelect(HSelect* select) { // Test if both values are same-typed int or long. if (t_type == f_type && (t_type == DataType::Type::kInt32 || t_type == DataType::Type::kInt64)) { - // Try to replace typical integral ABS constructs. - if (true_value->IsNeg()) { + // 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 (true_value->IsNeg()) { HInstruction* negated = true_value->InputAt(0); if ((cmp == kCondLT || cmp == kCondLE) && (a == negated && a == false_value && IsInt64Value(b, 0))) { diff --git a/test/679-checker-minmax/expected.txt b/test/679-checker-minmax/expected.txt new file mode 100644 index 0000000000..b0aad4deb5 --- /dev/null +++ b/test/679-checker-minmax/expected.txt @@ -0,0 +1 @@ +passed diff --git a/test/679-checker-minmax/info.txt b/test/679-checker-minmax/info.txt new file mode 100644 index 0000000000..4f7b9f52c5 --- /dev/null +++ b/test/679-checker-minmax/info.txt @@ -0,0 +1 @@ +Functional tests on detecting min/max. diff --git a/test/679-checker-minmax/src/Main.java b/test/679-checker-minmax/src/Main.java new file mode 100644 index 0000000000..d016de6686 --- /dev/null +++ b/test/679-checker-minmax/src/Main.java @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Functional tests for detecting min/max. + */ +public class Main { + + /// CHECK-START: int Main.min1(int, int) instruction_simplifier$after_inlining (before) + /// CHECK-DAG: <<Cnd:z\d+>> GreaterThanOrEqual [<<Op1:i\d+>>,<<Op2:i\d+>>] + /// CHECK-DAG: <<Sel:i\d+>> Select [<<Op1>>,<<Op2>>,<<Cnd>>] + /// CHECK-DAG: Return [<<Sel>>] + // + /// CHECK-START: int Main.min1(int, int) instruction_simplifier$after_inlining (after) + /// CHECK-DAG: <<Min:i\d+>> Min + /// CHECK-DAG: Return [<<Min>>] + // + /// CHECK-START: int Main.min1(int, int) instruction_simplifier$after_inlining (after) + /// CHECK-NOT: Select + public static int min1(int a, int b) { + return a < b ? a : b; + } + + /// CHECK-START: int Main.min2(int, int) instruction_simplifier$after_inlining (before) + /// CHECK-DAG: <<Cnd:z\d+>> GreaterThan [<<Op1:i\d+>>,<<Op2:i\d+>>] + /// CHECK-DAG: <<Sel:i\d+>> Select [<<Op1>>,<<Op2>>,<<Cnd>>] + /// CHECK-DAG: Return [<<Sel>>] + // + /// CHECK-START: int Main.min2(int, int) instruction_simplifier$after_inlining (after) + /// CHECK-DAG: <<Min:i\d+>> Min + /// CHECK-DAG: Return [<<Min>>] + // + /// CHECK-START: int Main.min2(int, int) instruction_simplifier$after_inlining (after) + /// CHECK-NOT: Select + public static int min2(int a, int b) { + return a <= b ? a : b; + } + + /// CHECK-START: int Main.min3(int, int) instruction_simplifier$after_inlining (before) + /// CHECK-DAG: <<Cnd:z\d+>> LessThanOrEqual [<<Op1:i\d+>>,<<Op2:i\d+>>] + /// CHECK-DAG: <<Sel:i\d+>> Select [<<Op2>>,<<Op1>>,<<Cnd>>] + /// CHECK-DAG: Return [<<Sel>>] + // + /// CHECK-START: int Main.min3(int, int) instruction_simplifier$after_inlining (after) + /// CHECK-DAG: <<Min:i\d+>> Min + /// CHECK-DAG: Return [<<Min>>] + // + /// CHECK-START: int Main.min3(int, int) instruction_simplifier$after_inlining (after) + /// CHECK-NOT: Select + public static int min3(int a, int b) { + return a > b ? b : a; + } + + /// CHECK-START: int Main.min4(int, int) instruction_simplifier$after_inlining (before) + /// CHECK-DAG: <<Cnd:z\d+>> LessThan [<<Op1:i\d+>>,<<Op2:i\d+>>] + /// CHECK-DAG: <<Sel:i\d+>> Select [<<Op2>>,<<Op1>>,<<Cnd>>] + /// CHECK-DAG: Return [<<Sel>>] + // + /// CHECK-START: int Main.min4(int, int) instruction_simplifier$after_inlining (after) + /// CHECK-DAG: <<Min:i\d+>> Min + /// CHECK-DAG: Return [<<Min>>] + // + /// CHECK-START: int Main.min4(int, int) instruction_simplifier$after_inlining (after) + /// CHECK-NOT: Select + public static int min4(int a, int b) { + return a >= b ? b : a; + } + + /// CHECK-START: int Main.max1(int, int) instruction_simplifier$after_inlining (before) + /// CHECK-DAG: <<Cnd:z\d+>> GreaterThanOrEqual [<<Op1:i\d+>>,<<Op2:i\d+>>] + /// CHECK-DAG: <<Sel:i\d+>> Select [<<Op2>>,<<Op1>>,<<Cnd>>] + /// CHECK-DAG: Return [<<Sel>>] + // + /// CHECK-START: int Main.max1(int, int) instruction_simplifier$after_inlining (after) + /// CHECK-DAG: <<Max:i\d+>> Max + /// CHECK-DAG: Return [<<Max>>] + // + /// CHECK-START: int Main.max1(int, int) instruction_simplifier$after_inlining (after) + /// CHECK-NOT: Select + public static int max1(int a, int b) { + return a < b ? b : a; + } + + /// CHECK-START: int Main.max2(int, int) instruction_simplifier$after_inlining (before) + /// CHECK-DAG: <<Cnd:z\d+>> GreaterThan [<<Op1:i\d+>>,<<Op2:i\d+>>] + /// CHECK-DAG: <<Sel:i\d+>> Select [<<Op2>>,<<Op1>>,<<Cnd>>] + /// CHECK-DAG: Return [<<Sel>>] + // + /// CHECK-START: int Main.max2(int, int) instruction_simplifier$after_inlining (after) + /// CHECK-DAG: <<Max:i\d+>> Max + /// CHECK-DAG: Return [<<Max>>] + // + /// CHECK-START: int Main.max2(int, int) instruction_simplifier$after_inlining (after) + /// CHECK-NOT: Select + public static int max2(int a, int b) { + return a <= b ? b : a; + } + + /// CHECK-START: int Main.max3(int, int) instruction_simplifier$after_inlining (before) + /// CHECK-DAG: <<Cnd:z\d+>> LessThanOrEqual [<<Op1:i\d+>>,<<Op2:i\d+>>] + /// CHECK-DAG: <<Sel:i\d+>> Select [<<Op1>>,<<Op2>>,<<Cnd>>] + /// CHECK-DAG: Return [<<Sel>>] + // + /// CHECK-START: int Main.max3(int, int) instruction_simplifier$after_inlining (after) + /// CHECK-DAG: <<Max:i\d+>> Max + /// CHECK-DAG: Return [<<Max>>] + // + /// CHECK-START: int Main.max3(int, int) instruction_simplifier$after_inlining (after) + /// CHECK-NOT: Select + public static int max3(int a, int b) { + return a > b ? a : b; + } + + /// CHECK-START: int Main.max4(int, int) instruction_simplifier$after_inlining (before) + /// CHECK-DAG: <<Cnd:z\d+>> LessThan [<<Op1:i\d+>>,<<Op2:i\d+>>] + /// CHECK-DAG: <<Sel:i\d+>> Select [<<Op1>>,<<Op2>>,<<Cnd>>] + /// CHECK-DAG: Return [<<Sel>>] + // + /// CHECK-START: int Main.max4(int, int) instruction_simplifier$after_inlining (after) + /// CHECK-DAG: <<Max:i\d+>> Max + /// CHECK-DAG: Return [<<Max>>] + // + /// CHECK-START: int Main.max4(int, int) instruction_simplifier$after_inlining (after) + /// CHECK-NOT: Select + public static int max4(int a, int b) { + return a >= b ? a : b; + } + + public static void main(String[] args) { + expectEquals(10, min1(10, 20)); + expectEquals(10, min2(10, 20)); + expectEquals(10, min3(10, 20)); + expectEquals(10, min4(10, 20)); + expectEquals(20, max1(10, 20)); + expectEquals(20, max2(10, 20)); + expectEquals(20, max3(10, 20)); + expectEquals(20, max4(10, 20)); + System.out.println("passed"); + } + + private static void expectEquals(int expected, int result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } +} |