Refined recognizing integral MIN-MAX-ABS.
Rationale:
More contextual information is always better.
Bug: b/74026074
Test: test-art-host,target
Change-Id: I670579423a181b6b6baf1db2440fd56a33ce8771
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index 2b6f905..0b2297d 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -852,7 +852,7 @@
static HInstruction* NewIntegralAbs(ArenaAllocator* allocator,
HInstruction* x,
HInstruction* cursor) {
- DataType::Type type = x->GetType();
+ DataType::Type type = DataType::Kind(x->GetType());
DCHECK(type == DataType::Type::kInt32 || type == DataType::Type::kInt64);
HAbs* abs = new (allocator) HAbs(type, x, cursor->GetDexPc());
cursor->GetBlock()->InsertInstructionBefore(abs, cursor);
@@ -865,7 +865,7 @@
HInstruction* y,
HInstruction* cursor,
bool is_min) {
- DataType::Type type = x->GetType();
+ DataType::Type type = DataType::Kind(x->GetType());
DCHECK(type == DataType::Type::kInt32 || type == DataType::Type::kInt64);
HBinaryOperation* minmax = nullptr;
if (is_min) {
@@ -939,9 +939,9 @@
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 same-typed int or long.
- if (t_type == f_type &&
- (t_type == DataType::Type::kInt32 || t_type == DataType::Type::kInt64)) {
+ // Test if both values are compatible integral types (resulting
+ // MIN/MAX/ABS type will be int or long, like the condition).
+ if (DataType::IsIntegralType(t_type) && DataType::Kind(t_type) == DataType::Kind(f_type)) {
// Try to replace typical integral MIN/MAX/ABS constructs.
if ((cmp == kCondLT || cmp == kCondLE || cmp == kCondGT || cmp == kCondGE) &&
((a == true_value && b == false_value) ||
diff --git a/test/679-checker-minmax/src/Main.java b/test/679-checker-minmax/src/Main.java
index d016de6..38085bb 100644
--- a/test/679-checker-minmax/src/Main.java
+++ b/test/679-checker-minmax/src/Main.java
@@ -79,6 +79,51 @@
return a >= b ? b : a;
}
+ /// CHECK-START: int Main.min5(short, short) instruction_simplifier$after_inlining (before)
+ /// CHECK-DAG: <<Cnd:z\d+>> LessThan [<<Op1:s\d+>>,<<Op2:s\d+>>]
+ /// CHECK-DAG: <<Sel:i\d+>> Select [<<Op2>>,<<Op1>>,<<Cnd>>]
+ /// CHECK-DAG: Return [<<Sel>>]
+ //
+ /// CHECK-START: int Main.min5(short, short) instruction_simplifier$after_inlining (after)
+ /// CHECK-DAG: <<Min:i\d+>> Min
+ /// CHECK-DAG: Return [<<Min>>]
+ //
+ /// CHECK-START: int Main.min5(short, short) instruction_simplifier$after_inlining (after)
+ /// CHECK-NOT: Select
+ public static int min5(short a, short b) {
+ return a >= b ? b : a;
+ }
+
+ /// CHECK-START: int Main.min6(byte, byte) instruction_simplifier$after_inlining (before)
+ /// CHECK-DAG: <<Cnd:z\d+>> LessThan [<<Op1:b\d+>>,<<Op2:b\d+>>]
+ /// CHECK-DAG: <<Sel:i\d+>> Select [<<Op2>>,<<Op1>>,<<Cnd>>]
+ /// CHECK-DAG: Return [<<Sel>>]
+ //
+ /// CHECK-START: int Main.min6(byte, byte) instruction_simplifier$after_inlining (after)
+ /// CHECK-DAG: <<Min:i\d+>> Min
+ /// CHECK-DAG: Return [<<Min>>]
+ //
+ /// CHECK-START: int Main.min6(byte, byte) instruction_simplifier$after_inlining (after)
+ /// CHECK-NOT: Select
+ public static int min6(byte a, byte b) {
+ return a >= b ? b : a;
+ }
+
+ /// CHECK-START: long Main.min7(long, long) instruction_simplifier$after_inlining (before)
+ /// CHECK-DAG: <<Cnd:z\d+>> LessThan [<<Op1:j\d+>>,<<Op2:j\d+>>]
+ /// CHECK-DAG: <<Sel:j\d+>> Select [<<Op2>>,<<Op1>>,<<Cnd>>]
+ /// CHECK-DAG: Return [<<Sel>>]
+ //
+ /// CHECK-START: long Main.min7(long, long) instruction_simplifier$after_inlining (after)
+ /// CHECK-DAG: <<Min:j\d+>> Min
+ /// CHECK-DAG: Return [<<Min>>]
+ //
+ /// CHECK-START: long Main.min7(long, long) instruction_simplifier$after_inlining (after)
+ /// CHECK-NOT: Select
+ public static long min7(long a, long 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>>]
@@ -139,15 +184,66 @@
return a >= b ? a : b;
}
+ /// CHECK-START: int Main.max5(short, short) instruction_simplifier$after_inlining (before)
+ /// CHECK-DAG: <<Cnd:z\d+>> LessThan [<<Op1:s\d+>>,<<Op2:s\d+>>]
+ /// CHECK-DAG: <<Sel:i\d+>> Select [<<Op1>>,<<Op2>>,<<Cnd>>]
+ /// CHECK-DAG: Return [<<Sel>>]
+ //
+ /// CHECK-START: int Main.max5(short, short) instruction_simplifier$after_inlining (after)
+ /// CHECK-DAG: <<Max:i\d+>> Max
+ /// CHECK-DAG: Return [<<Max>>]
+ //
+ /// CHECK-START: int Main.max5(short, short) instruction_simplifier$after_inlining (after)
+ /// CHECK-NOT: Select
+ public static int max5(short a, short b) {
+ return a >= b ? a : b;
+ }
+
+ /// CHECK-START: int Main.max6(byte, byte) instruction_simplifier$after_inlining (before)
+ /// CHECK-DAG: <<Cnd:z\d+>> LessThan [<<Op1:b\d+>>,<<Op2:b\d+>>]
+ /// CHECK-DAG: <<Sel:i\d+>> Select [<<Op1>>,<<Op2>>,<<Cnd>>]
+ /// CHECK-DAG: Return [<<Sel>>]
+ //
+ /// CHECK-START: int Main.max6(byte, byte) instruction_simplifier$after_inlining (after)
+ /// CHECK-DAG: <<Max:i\d+>> Max
+ /// CHECK-DAG: Return [<<Max>>]
+ //
+ /// CHECK-START: int Main.max6(byte, byte) instruction_simplifier$after_inlining (after)
+ /// CHECK-NOT: Select
+ public static int max6(byte a, byte b) {
+ return a >= b ? a : b;
+ }
+
+ /// CHECK-START: long Main.max7(long, long) instruction_simplifier$after_inlining (before)
+ /// CHECK-DAG: <<Cnd:z\d+>> LessThan [<<Op1:j\d+>>,<<Op2:j\d+>>]
+ /// CHECK-DAG: <<Sel:j\d+>> Select [<<Op1>>,<<Op2>>,<<Cnd>>]
+ /// CHECK-DAG: Return [<<Sel>>]
+ //
+ /// CHECK-START: long Main.max7(long, long) instruction_simplifier$after_inlining (after)
+ /// CHECK-DAG: <<Max:j\d+>> Max
+ /// CHECK-DAG: Return [<<Max>>]
+ //
+ /// CHECK-START: long Main.max7(long, long) instruction_simplifier$after_inlining (after)
+ /// CHECK-NOT: Select
+ public static long max7(long a, long 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(10, min5((short) 10, (short) 20));
+ expectEquals(10, min6((byte) 10, (byte) 20));
+ expectEquals(10L, min7(10L, 20L));
expectEquals(20, max1(10, 20));
expectEquals(20, max2(10, 20));
expectEquals(20, max3(10, 20));
expectEquals(20, max4(10, 20));
+ expectEquals(20, max5((short) 10, (short) 20));
+ expectEquals(20, max6((byte) 10, (byte) 20));
+ expectEquals(20L, max7(10L, 20L));
System.out.println("passed");
}
@@ -156,4 +252,10 @@
throw new Error("Expected: " + expected + ", found: " + result);
}
}
+
+ private static void expectEquals(long expected, long result) {
+ if (expected != result) {
+ throw new Error("Expected: " + expected + ", found: " + result);
+ }
+ }
}
diff --git a/test/681-checker-abs/expected.txt b/test/681-checker-abs/expected.txt
new file mode 100644
index 0000000..b0aad4d
--- /dev/null
+++ b/test/681-checker-abs/expected.txt
@@ -0,0 +1 @@
+passed
diff --git a/test/681-checker-abs/info.txt b/test/681-checker-abs/info.txt
new file mode 100644
index 0000000..d36e76e
--- /dev/null
+++ b/test/681-checker-abs/info.txt
@@ -0,0 +1 @@
+Functional tests on detecting abs.
diff --git a/test/681-checker-abs/src/Main.java b/test/681-checker-abs/src/Main.java
new file mode 100644
index 0000000..8064b1d
--- /dev/null
+++ b/test/681-checker-abs/src/Main.java
@@ -0,0 +1,184 @@
+/*
+ * 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 abs.
+ */
+public class Main {
+
+ /// CHECK-START: int Main.abs1(int) instruction_simplifier$after_inlining (before)
+ /// CHECK-DAG: <<Par:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Zer:i\d+>> IntConstant 0
+ /// CHECK-DAG: <<Cnd:z\d+>> GreaterThanOrEqual [<<Par>>,<<Zer>>]
+ /// CHECK-DAG: <<Neg:i\d+>> [<<Par>>]
+ /// CHECK-DAG: <<Sel:i\d+>> Select [<<Neg>>,<<Par>>,<<Cnd>>]
+ /// CHECK-DAG: Return [<<Sel>>]
+ //
+ /// CHECK-START: int Main.abs1(int) instruction_simplifier$after_inlining (after)
+ /// CHECK-DAG: <<Par:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Abs:i\d+>> Abs [<<Par>>]
+ /// CHECK-DAG: Return [<<Abs>>]
+ //
+ /// CHECK-START: int Main.abs1(int) instruction_simplifier$after_inlining (after)
+ /// CHECK-NOT: Select
+ public static int abs1(int a) {
+ return a < 0 ? -a : a;
+ }
+
+ /// CHECK-START: int Main.abs2(int) instruction_simplifier$after_inlining (before)
+ /// CHECK-DAG: <<Par:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Zer:i\d+>> IntConstant 0
+ /// CHECK-DAG: <<Cnd:z\d+>> GreaterThan [<<Par>>,<<Zer>>]
+ /// CHECK-DAG: <<Neg:i\d+>> [<<Par>>]
+ /// CHECK-DAG: <<Sel:i\d+>> Select [<<Neg>>,<<Par>>,<<Cnd>>]
+ /// CHECK-DAG: Return [<<Sel>>]
+ //
+ /// CHECK-START: int Main.abs2(int) instruction_simplifier$after_inlining (after)
+ /// CHECK-DAG: <<Par:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Abs:i\d+>> Abs [<<Par>>]
+ /// CHECK-DAG: Return [<<Abs>>]
+ //
+ /// CHECK-START: int Main.abs2(int) instruction_simplifier$after_inlining (after)
+ /// CHECK-NOT: Select
+ public static int abs2(int a) {
+ return a <= 0 ? -a : a;
+ }
+
+ /// CHECK-START: int Main.abs3(int) instruction_simplifier$after_inlining (before)
+ /// CHECK-DAG: <<Par:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Zer:i\d+>> IntConstant 0
+ /// CHECK-DAG: <<Cnd:z\d+>> LessThanOrEqual [<<Par>>,<<Zer>>]
+ /// CHECK-DAG: <<Neg:i\d+>> [<<Par>>]
+ /// CHECK-DAG: <<Sel:i\d+>> Select [<<Par>>,<<Neg>>,<<Cnd>>]
+ /// CHECK-DAG: Return [<<Sel>>]
+ //
+ /// CHECK-START: int Main.abs3(int) instruction_simplifier$after_inlining (after)
+ /// CHECK-DAG: <<Par:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Abs:i\d+>> Abs [<<Par>>]
+ /// CHECK-DAG: Return [<<Abs>>]
+ //
+ /// CHECK-START: int Main.abs3(int) instruction_simplifier$after_inlining (after)
+ /// CHECK-NOT: Select
+ public static int abs3(int a) {
+ return a > 0 ? a : -a;
+ }
+
+ /// CHECK-START: int Main.abs4(int) instruction_simplifier$after_inlining (before)
+ /// CHECK-DAG: <<Par:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Zer:i\d+>> IntConstant 0
+ /// CHECK-DAG: <<Cnd:z\d+>> LessThan [<<Par>>,<<Zer>>]
+ /// CHECK-DAG: <<Neg:i\d+>> [<<Par>>]
+ /// CHECK-DAG: <<Sel:i\d+>> Select [<<Par>>,<<Neg>>,<<Cnd>>]
+ /// CHECK-DAG: Return [<<Sel>>]
+ //
+ /// CHECK-START: int Main.abs4(int) instruction_simplifier$after_inlining (after)
+ /// CHECK-DAG: <<Par:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Abs:i\d+>> Abs [<<Par>>]
+ /// CHECK-DAG: Return [<<Abs>>]
+ //
+ /// CHECK-START: int Main.abs4(int) instruction_simplifier$after_inlining (after)
+ /// CHECK-NOT: Select
+ public static int abs4(int a) {
+ return a >= 0 ? a : -a;
+ }
+
+ /// CHECK-START: int Main.abs5(short) instruction_simplifier$after_inlining (before)
+ /// CHECK-DAG: <<Par:s\d+>> ParameterValue
+ /// CHECK-DAG: <<Zer:i\d+>> IntConstant 0
+ /// CHECK-DAG: <<Cnd:z\d+>> LessThan [<<Par>>,<<Zer>>]
+ /// CHECK-DAG: <<Neg:i\d+>> [<<Par>>]
+ /// CHECK-DAG: <<Sel:i\d+>> Select [<<Par>>,<<Neg>>,<<Cnd>>]
+ /// CHECK-DAG: Return [<<Sel>>]
+ //
+ /// CHECK-START: int Main.abs5(short) instruction_simplifier$after_inlining (after)
+ /// CHECK-DAG: <<Par:s\d+>> ParameterValue
+ /// CHECK-DAG: <<Abs:i\d+>> Abs [<<Par>>]
+ /// CHECK-DAG: Return [<<Abs>>]
+ //
+ /// CHECK-START: int Main.abs5(short) instruction_simplifier$after_inlining (after)
+ /// CHECK-NOT: Select
+ public static int abs5(short a) {
+ return a >= 0 ? a : -a;
+ }
+
+ /// CHECK-START: int Main.abs6(byte) instruction_simplifier$after_inlining (before)
+ /// CHECK-DAG: <<Par:b\d+>> ParameterValue
+ /// CHECK-DAG: <<Zer:i\d+>> IntConstant 0
+ /// CHECK-DAG: <<Cnd:z\d+>> LessThan [<<Par>>,<<Zer>>]
+ /// CHECK-DAG: <<Neg:i\d+>> [<<Par>>]
+ /// CHECK-DAG: <<Sel:i\d+>> Select [<<Par>>,<<Neg>>,<<Cnd>>]
+ /// CHECK-DAG: Return [<<Sel>>]
+ //
+ /// CHECK-START: int Main.abs6(byte) instruction_simplifier$after_inlining (after)
+ /// CHECK-DAG: <<Par:b\d+>> ParameterValue
+ /// CHECK-DAG: <<Abs:i\d+>> Abs [<<Par>>]
+ /// CHECK-DAG: Return [<<Abs>>]
+ //
+ /// CHECK-START: int Main.abs6(byte) instruction_simplifier$after_inlining (after)
+ /// CHECK-NOT: Select
+ public static int abs6(byte a) {
+ return a >= 0 ? a : -a;
+ }
+
+ /// CHECK-START: long Main.abs7(long) instruction_simplifier$after_inlining (before)
+ /// CHECK-DAG: <<Par:j\d+>> ParameterValue
+ /// CHECK-DAG: <<Zer:j\d+>> LongConstant 0
+ /// CHECK-DAG: <<Cnd:z\d+>> LessThan [<<Par>>,<<Zer>>]
+ /// CHECK-DAG: <<Neg:j\d+>> [<<Par>>]
+ /// CHECK-DAG: <<Sel:j\d+>> Select [<<Par>>,<<Neg>>,<<Cnd>>]
+ /// CHECK-DAG: Return [<<Sel>>]
+ //
+ /// CHECK-START: long Main.abs7(long) instruction_simplifier$after_inlining (after)
+ /// CHECK-DAG: <<Par:j\d+>> ParameterValue
+ /// CHECK-DAG: <<Abs:j\d+>> Abs [<<Par>>]
+ /// CHECK-DAG: Return [<<Abs>>]
+ //
+ /// CHECK-START: long Main.abs7(long) instruction_simplifier$after_inlining (after)
+ /// CHECK-NOT: Select
+ public static long abs7(long a) {
+ return a >= 0 ? a : -a;
+ }
+
+ public static void main(String[] args) {
+ expectEquals(10, abs1(-10));
+ expectEquals(20, abs1(20));
+ expectEquals(10, abs2(-10));
+ expectEquals(20, abs2(20));
+ expectEquals(10, abs3(-10));
+ expectEquals(20, abs3(20));
+ expectEquals(10, abs4(-10));
+ expectEquals(20, abs4(20));
+ expectEquals(10, abs4((short) -10));
+ expectEquals(20, abs4((short) 20));
+ expectEquals(10, abs6((byte) -10));
+ expectEquals(20, abs6((byte) 20));
+ expectEquals(10L, abs7(-10L));
+ expectEquals(20L, abs7(20L));
+ System.out.println("passed");
+ }
+
+ private static void expectEquals(int expected, int result) {
+ if (expected != result) {
+ throw new Error("Expected: " + expected + ", found: " + result);
+ }
+ }
+
+ private static void expectEquals(long expected, long result) {
+ if (expected != result) {
+ throw new Error("Expected: " + expected + ", found: " + result);
+ }
+ }
+}