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);
+    }
+  }
+}