Enabled nested min-max SIMDization for narrower operands.
Bug: b/74026074
Test: test-art-host,target
Change-Id: Ic6ee31be6192fb2b3bae3be8986da261a744be07
diff --git a/compiler/optimizing/loop_optimization.cc b/compiler/optimizing/loop_optimization.cc
index 71e24de..b41b659 100644
--- a/compiler/optimizing/loop_optimization.cc
+++ b/compiler/optimizing/loop_optimization.cc
@@ -153,6 +153,18 @@
return false;
}
}
+ // A MIN-MAX on narrower operands qualifies as well
+ // (returning the operator itself).
+ if (instruction->IsMin() || instruction->IsMax()) {
+ HBinaryOperation* min_max = instruction->AsBinaryOperation();
+ DCHECK(min_max->GetType() == DataType::Type::kInt32 ||
+ min_max->GetType() == DataType::Type::kInt64);
+ if (IsSignExtensionAndGet(min_max->InputAt(0), type, operand) &&
+ IsSignExtensionAndGet(min_max->InputAt(1), type, operand)) {
+ *operand = min_max;
+ return true;
+ }
+ }
return false;
}
@@ -216,6 +228,18 @@
return false;
}
}
+ // A MIN-MAX on narrower operands qualifies as well
+ // (returning the operator itself).
+ if (instruction->IsMin() || instruction->IsMax()) {
+ HBinaryOperation* min_max = instruction->AsBinaryOperation();
+ DCHECK(min_max->GetType() == DataType::Type::kInt32 ||
+ min_max->GetType() == DataType::Type::kInt64);
+ if (IsZeroExtensionAndGet(min_max->InputAt(0), type, operand) &&
+ IsZeroExtensionAndGet(min_max->InputAt(1), type, operand)) {
+ *operand = min_max;
+ return true;
+ }
+ }
return false;
}
diff --git a/test/651-checker-simd-minmax/src/ByteSimdMinMax.java b/test/651-checker-simd-minmax/src/ByteSimdMinMax.java
index b995494..8dacd5d 100644
--- a/test/651-checker-simd-minmax/src/ByteSimdMinMax.java
+++ b/test/651-checker-simd-minmax/src/ByteSimdMinMax.java
@@ -129,7 +129,7 @@
/// CHECK-DAG: <<Cnv:b\d+>> TypeConversion [<<Min>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-{ARM64,MIPS64}: void ByteSimdMinMax.doitMin100(byte[], byte[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,MIPS64}: void ByteSimdMinMax.doitMin100(byte[], byte[]) loop_optimization (after)
/// CHECK-DAG: <<I100:i\d+>> IntConstant 100 loop:none
/// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<I100>>] loop:none
/// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
@@ -142,6 +142,38 @@
}
}
+ /// CHECK-START-{ARM,ARM64,MIPS64}: void ByteSimdMinMax.doitMinMax(byte[], byte[]) loop_optimization (after)
+ /// CHECK-DAG: <<I11:i\d+>> IntConstant -11 loop:none
+ /// CHECK-DAG: <<I23:i\d+>> IntConstant 23 loop:none
+ /// CHECK-DAG: <<Rpl1:d\d+>> VecReplicateScalar [<<I23>>] loop:none
+ /// CHECK-DAG: <<Rpl2:d\d+>> VecReplicateScalar [<<I11>>] loop:none
+ /// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Min:d\d+>> VecMin [<<Get>>,<<Rpl1>>] packed_type:Int8 loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Max:d\d+>> VecMax [<<Min>>,<<Rpl2>>] packed_type:Int8 loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<Max>>] loop:<<Loop>> outer_loop:none
+ private static void doitMinMax(byte[] x, byte[] y) {
+ int n = Math.min(x.length, y.length);
+ for (int i = 0; i < n; i++) {
+ x[i] = (byte) Math.max(-11, Math.min(y[i], 23));
+ }
+ }
+
+ /// CHECK-START-{ARM,ARM64,MIPS64}: void ByteSimdMinMax.doitMinMaxUnsigned(byte[], byte[]) loop_optimization (after)
+ /// CHECK-DAG: <<I11:i\d+>> IntConstant 11 loop:none
+ /// CHECK-DAG: <<I23:i\d+>> IntConstant 23 loop:none
+ /// CHECK-DAG: <<Rpl1:d\d+>> VecReplicateScalar [<<I23>>] loop:none
+ /// CHECK-DAG: <<Rpl2:d\d+>> VecReplicateScalar [<<I11>>] loop:none
+ /// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Min:d\d+>> VecMin [<<Get>>,<<Rpl1>>] packed_type:Uint8 loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Max:d\d+>> VecMax [<<Min>>,<<Rpl2>>] packed_type:Uint8 loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<Max>>] loop:<<Loop>> outer_loop:none
+ private static void doitMinMaxUnsigned(byte[] x, byte[] y) {
+ int n = Math.min(x.length, y.length);
+ for (int i = 0; i < n; i++) {
+ x[i] = (byte) Math.max(11, Math.min(y[i] & 0xff, 23));
+ }
+ }
+
public static void main() {
// Initialize cross-values for all possible values.
int total = 256 * 256;
@@ -184,6 +216,18 @@
byte expected = (byte) Math.min(y[i], 100);
expectEquals(expected, x[i]);
}
+ doitMinMax(x, y);
+ for (int i = 0; i < total; i++) {
+ int s = y[i];
+ byte expected = (byte) (s < -11 ? -11 : (s > 23 ? 23 : s));
+ expectEquals(expected, x[i]);
+ }
+ doitMinMaxUnsigned(x, y);
+ for (int i = 0; i < total; i++) {
+ int u = y[i] & 0xff;
+ byte expected = (byte) (u < 11 ? 11 : (u > 23 ? 23 : u));
+ expectEquals(expected, x[i]);
+ }
System.out.println("ByteSimdMinMax passed");
}
diff --git a/test/651-checker-simd-minmax/src/ShortSimdMinMax.java b/test/651-checker-simd-minmax/src/ShortSimdMinMax.java
index aae7891..9075d80 100644
--- a/test/651-checker-simd-minmax/src/ShortSimdMinMax.java
+++ b/test/651-checker-simd-minmax/src/ShortSimdMinMax.java
@@ -129,7 +129,7 @@
/// CHECK-DAG: <<Cnv:s\d+>> TypeConversion [<<Min>>] loop:<<Loop>> outer_loop:none
/// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none
//
- /// CHECK-START-{ARM64,MIPS64}: void ShortSimdMinMax.doitMin100(short[], short[]) loop_optimization (after)
+ /// CHECK-START-{ARM,ARM64,MIPS64}: void ShortSimdMinMax.doitMin100(short[], short[]) loop_optimization (after)
/// CHECK-DAG: <<I100:i\d+>> IntConstant 100 loop:none
/// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<I100>>] loop:none
/// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
@@ -142,6 +142,38 @@
}
}
+ /// CHECK-START-{ARM,ARM64,MIPS64}: void ShortSimdMinMax.doitMinMax(short[], short[]) loop_optimization (after)
+ /// CHECK-DAG: <<I11:i\d+>> IntConstant -1111 loop:none
+ /// CHECK-DAG: <<I23:i\d+>> IntConstant 2323 loop:none
+ /// CHECK-DAG: <<Rpl1:d\d+>> VecReplicateScalar [<<I23>>] loop:none
+ /// CHECK-DAG: <<Rpl2:d\d+>> VecReplicateScalar [<<I11>>] loop:none
+ /// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Min:d\d+>> VecMin [<<Get>>,<<Rpl1>>] packed_type:Int16 loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Max:d\d+>> VecMax [<<Min>>,<<Rpl2>>] packed_type:Int16 loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<Max>>] loop:<<Loop>> outer_loop:none
+ private static void doitMinMax(short[] x, short[] y) {
+ int n = Math.min(x.length, y.length);
+ for (int i = 0; i < n; i++) {
+ x[i] = (short) Math.max(-1111, Math.min(y[i], 2323));
+ }
+ }
+
+ /// CHECK-START-{ARM,ARM64,MIPS64}: void ShortSimdMinMax.doitMinMaxUnsigned(short[], short[]) loop_optimization (after)
+ /// CHECK-DAG: <<I11:i\d+>> IntConstant 1111 loop:none
+ /// CHECK-DAG: <<I23:i\d+>> IntConstant 2323 loop:none
+ /// CHECK-DAG: <<Rpl1:d\d+>> VecReplicateScalar [<<I23>>] loop:none
+ /// CHECK-DAG: <<Rpl2:d\d+>> VecReplicateScalar [<<I11>>] loop:none
+ /// CHECK-DAG: <<Get:d\d+>> VecLoad loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Min:d\d+>> VecMin [<<Get>>,<<Rpl1>>] packed_type:Uint16 loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: <<Max:d\d+>> VecMax [<<Min>>,<<Rpl2>>] packed_type:Uint16 loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<<Max>>] loop:<<Loop>> outer_loop:none
+ private static void doitMinMaxUnsigned(short[] x, short[] y) {
+ int n = Math.min(x.length, y.length);
+ for (int i = 0; i < n; i++) {
+ x[i] = (short) Math.max(1111, Math.min(y[i] & 0xffff, 2323));
+ }
+ }
+
public static void main() {
short[] interesting = {
(short) 0x0000, (short) 0x0001, (short) 0x007f,
@@ -198,6 +230,18 @@
short expected = (short) Math.min(y[i], 100);
expectEquals(expected, x[i]);
}
+ doitMinMax(x, y);
+ for (int i = 0; i < total; i++) {
+ int s = y[i];
+ short expected = (short) (s < -1111 ? -1111 : (s > 2323 ? 2323 : s));
+ expectEquals(expected, x[i]);
+ }
+ doitMinMaxUnsigned(x, y);
+ for (int i = 0; i < total; i++) {
+ int u = y[i] & 0xffff;
+ short expected = (short) (u < 1111 ? 1111 : (u > 2323 ? 2323 : u));
+ expectEquals(expected, x[i]);
+ }
System.out.println("ShortSimdMinMax passed");
}
diff --git a/test/679-checker-minmax/src/Main.java b/test/679-checker-minmax/src/Main.java
index 4f0261c..e330a53 100644
--- a/test/679-checker-minmax/src/Main.java
+++ b/test/679-checker-minmax/src/Main.java
@@ -20,6 +20,82 @@
public class Main {
//
+ // Direct intrinsics.
+ //
+
+ /// CHECK-START: int Main.minI(int) instruction_simplifier (before)
+ /// CHECK-DAG: <<Par:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Con:i\d+>> IntConstant 20
+ /// CHECK-DAG: <<Min:i\d+>> InvokeStaticOrDirect [<<Par>>,<<Con>>] intrinsic:MathMinIntInt
+ /// CHECK-DAG: Return [<<Min>>]
+ //
+ /// CHECK-START: int Main.minI(int) instruction_simplifier (after)
+ /// CHECK-DAG: <<Par:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Con:i\d+>> IntConstant 20
+ /// CHECK-DAG: <<Min:i\d+>> Min [<<Par>>,<<Con>>]
+ /// CHECK-DAG: Return [<<Min>>]
+ //
+ /// CHECK-START: int Main.minI(int) instruction_simplifier (after)
+ /// CHECK-NOT: InvokeStaticOrDirect
+ public static int minI(int a) {
+ return Math.min(a, 20);
+ }
+
+ /// CHECK-START: long Main.minL(long) instruction_simplifier (before)
+ /// CHECK-DAG: <<Par:j\d+>> ParameterValue
+ /// CHECK-DAG: <<Con:j\d+>> LongConstant 20
+ /// CHECK-DAG: <<Min:j\d+>> InvokeStaticOrDirect [<<Par>>,<<Con>>] intrinsic:MathMinLongLong
+ /// CHECK-DAG: Return [<<Min>>]
+ //
+ /// CHECK-START: long Main.minL(long) instruction_simplifier (after)
+ /// CHECK-DAG: <<Par:j\d+>> ParameterValue
+ /// CHECK-DAG: <<Con:j\d+>> LongConstant 20
+ /// CHECK-DAG: <<Min:j\d+>> Min [<<Par>>,<<Con>>]
+ /// CHECK-DAG: Return [<<Min>>]
+ //
+ /// CHECK-START: long Main.minL(long) instruction_simplifier (after)
+ /// CHECK-NOT: InvokeStaticOrDirect
+ public static long minL(long a) {
+ return Math.min(a, 20L);
+ }
+
+ /// CHECK-START: int Main.maxI(int) instruction_simplifier (before)
+ /// CHECK-DAG: <<Par:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Con:i\d+>> IntConstant 20
+ /// CHECK-DAG: <<Max:i\d+>> InvokeStaticOrDirect [<<Par>>,<<Con>>] intrinsic:MathMaxIntInt
+ /// CHECK-DAG: Return [<<Max>>]
+ //
+ /// CHECK-START: int Main.maxI(int) instruction_simplifier (after)
+ /// CHECK-DAG: <<Par:i\d+>> ParameterValue
+ /// CHECK-DAG: <<Con:i\d+>> IntConstant 20
+ /// CHECK-DAG: <<Max:i\d+>> Max [<<Par>>,<<Con>>]
+ /// CHECK-DAG: Return [<<Max>>]
+ //
+ /// CHECK-START: int Main.maxI(int) instruction_simplifier (after)
+ /// CHECK-NOT: InvokeStaticOrDirect
+ public static int maxI(int a) {
+ return Math.max(a, 20);
+ }
+
+ /// CHECK-START: long Main.maxL(long) instruction_simplifier (before)
+ /// CHECK-DAG: <<Par:j\d+>> ParameterValue
+ /// CHECK-DAG: <<Con:j\d+>> LongConstant 20
+ /// CHECK-DAG: <<Max:j\d+>> InvokeStaticOrDirect [<<Par>>,<<Con>>] intrinsic:MathMaxLongLong
+ /// CHECK-DAG: Return [<<Max>>]
+ //
+ /// CHECK-START: long Main.maxL(long) instruction_simplifier (after)
+ /// CHECK-DAG: <<Par:j\d+>> ParameterValue
+ /// CHECK-DAG: <<Con:j\d+>> LongConstant 20
+ /// CHECK-DAG: <<Max:j\d+>> Max [<<Par>>,<<Con>>]
+ /// CHECK-DAG: Return [<<Max>>]
+ //
+ /// CHECK-START: long Main.maxL(long) instruction_simplifier (after)
+ /// CHECK-NOT: InvokeStaticOrDirect
+ public static long maxL(long a) {
+ return Math.max(a, 20L);
+ }
+
+ //
// Different types.
//
@@ -343,6 +419,14 @@
public static void main(String[] args) {
// Types.
+ expectEquals(10, minI(10));
+ expectEquals(20, minI(25));
+ expectEquals(10L, minL(10L));
+ expectEquals(20L, minL(25L));
+ expectEquals(20, maxI(10));
+ expectEquals(25, maxI(25));
+ expectEquals(20L, maxL(10L));
+ expectEquals(25L, maxL(25L));
expectEquals(10, min1(10, 20));
expectEquals(10, min2(10, 20));
expectEquals(10, min3(10, 20));