From 5aac921bae39686f2edecb5018d87952b0758b25 Mon Sep 17 00:00:00 2001 From: Aart Bik Date: Tue, 3 Apr 2018 14:06:43 -0700 Subject: Enabled nested min-max SIMDization for narrower operands. Bug: b/74026074 Test: test-art-host,target Change-Id: Ic6ee31be6192fb2b3bae3be8986da261a744be07 --- compiler/optimizing/loop_optimization.cc | 24 +++++++ .../src/ByteSimdMinMax.java | 46 +++++++++++- .../src/ShortSimdMinMax.java | 46 +++++++++++- test/679-checker-minmax/src/Main.java | 84 ++++++++++++++++++++++ 4 files changed, 198 insertions(+), 2 deletions(-) diff --git a/compiler/optimizing/loop_optimization.cc b/compiler/optimizing/loop_optimization.cc index 71e24de141..b41b659083 100644 --- a/compiler/optimizing/loop_optimization.cc +++ b/compiler/optimizing/loop_optimization.cc @@ -153,6 +153,18 @@ static bool IsSignExtensionAndGet(HInstruction* instruction, 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 @@ static bool IsZeroExtensionAndGet(HInstruction* instruction, 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 b9954947f7..8dacd5d51e 100644 --- a/test/651-checker-simd-minmax/src/ByteSimdMinMax.java +++ b/test/651-checker-simd-minmax/src/ByteSimdMinMax.java @@ -129,7 +129,7 @@ public class ByteSimdMinMax { /// CHECK-DAG: <> TypeConversion [<>] loop:<> outer_loop:none /// CHECK-DAG: ArraySet [{{l\d+}},<>,<>] 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: <> IntConstant 100 loop:none /// CHECK-DAG: <> VecReplicateScalar [<>] loop:none /// CHECK-DAG: <> VecLoad loop:<> outer_loop:none @@ -142,6 +142,38 @@ public class ByteSimdMinMax { } } + /// CHECK-START-{ARM,ARM64,MIPS64}: void ByteSimdMinMax.doitMinMax(byte[], byte[]) loop_optimization (after) + /// CHECK-DAG: <> IntConstant -11 loop:none + /// CHECK-DAG: <> IntConstant 23 loop:none + /// CHECK-DAG: <> VecReplicateScalar [<>] loop:none + /// CHECK-DAG: <> VecReplicateScalar [<>] loop:none + /// CHECK-DAG: <> VecLoad loop:<> outer_loop:none + /// CHECK-DAG: <> VecMin [<>,<>] packed_type:Int8 loop:<> outer_loop:none + /// CHECK-DAG: <> VecMax [<>,<>] packed_type:Int8 loop:<> outer_loop:none + /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<>] 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: <> IntConstant 11 loop:none + /// CHECK-DAG: <> IntConstant 23 loop:none + /// CHECK-DAG: <> VecReplicateScalar [<>] loop:none + /// CHECK-DAG: <> VecReplicateScalar [<>] loop:none + /// CHECK-DAG: <> VecLoad loop:<> outer_loop:none + /// CHECK-DAG: <> VecMin [<>,<>] packed_type:Uint8 loop:<> outer_loop:none + /// CHECK-DAG: <> VecMax [<>,<>] packed_type:Uint8 loop:<> outer_loop:none + /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<>] 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 @@ public class ByteSimdMinMax { 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 aae78914d8..9075d8007c 100644 --- a/test/651-checker-simd-minmax/src/ShortSimdMinMax.java +++ b/test/651-checker-simd-minmax/src/ShortSimdMinMax.java @@ -129,7 +129,7 @@ public class ShortSimdMinMax { /// CHECK-DAG: <> TypeConversion [<>] loop:<> outer_loop:none /// CHECK-DAG: ArraySet [{{l\d+}},<>,<>] 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: <> IntConstant 100 loop:none /// CHECK-DAG: <> VecReplicateScalar [<>] loop:none /// CHECK-DAG: <> VecLoad loop:<> outer_loop:none @@ -142,6 +142,38 @@ public class ShortSimdMinMax { } } + /// CHECK-START-{ARM,ARM64,MIPS64}: void ShortSimdMinMax.doitMinMax(short[], short[]) loop_optimization (after) + /// CHECK-DAG: <> IntConstant -1111 loop:none + /// CHECK-DAG: <> IntConstant 2323 loop:none + /// CHECK-DAG: <> VecReplicateScalar [<>] loop:none + /// CHECK-DAG: <> VecReplicateScalar [<>] loop:none + /// CHECK-DAG: <> VecLoad loop:<> outer_loop:none + /// CHECK-DAG: <> VecMin [<>,<>] packed_type:Int16 loop:<> outer_loop:none + /// CHECK-DAG: <> VecMax [<>,<>] packed_type:Int16 loop:<> outer_loop:none + /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<>] 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: <> IntConstant 1111 loop:none + /// CHECK-DAG: <> IntConstant 2323 loop:none + /// CHECK-DAG: <> VecReplicateScalar [<>] loop:none + /// CHECK-DAG: <> VecReplicateScalar [<>] loop:none + /// CHECK-DAG: <> VecLoad loop:<> outer_loop:none + /// CHECK-DAG: <> VecMin [<>,<>] packed_type:Uint16 loop:<> outer_loop:none + /// CHECK-DAG: <> VecMax [<>,<>] packed_type:Uint16 loop:<> outer_loop:none + /// CHECK-DAG: VecStore [{{l\d+}},{{i\d+}},<>] 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 @@ public class ShortSimdMinMax { 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 4f0261c0a3..e330a5370e 100644 --- a/test/679-checker-minmax/src/Main.java +++ b/test/679-checker-minmax/src/Main.java @@ -19,6 +19,82 @@ */ public class Main { + // + // Direct intrinsics. + // + + /// CHECK-START: int Main.minI(int) instruction_simplifier (before) + /// CHECK-DAG: <> ParameterValue + /// CHECK-DAG: <> IntConstant 20 + /// CHECK-DAG: <> InvokeStaticOrDirect [<>,<>] intrinsic:MathMinIntInt + /// CHECK-DAG: Return [<>] + // + /// CHECK-START: int Main.minI(int) instruction_simplifier (after) + /// CHECK-DAG: <> ParameterValue + /// CHECK-DAG: <> IntConstant 20 + /// CHECK-DAG: <> Min [<>,<>] + /// CHECK-DAG: Return [<>] + // + /// 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: <> ParameterValue + /// CHECK-DAG: <> LongConstant 20 + /// CHECK-DAG: <> InvokeStaticOrDirect [<>,<>] intrinsic:MathMinLongLong + /// CHECK-DAG: Return [<>] + // + /// CHECK-START: long Main.minL(long) instruction_simplifier (after) + /// CHECK-DAG: <> ParameterValue + /// CHECK-DAG: <> LongConstant 20 + /// CHECK-DAG: <> Min [<>,<>] + /// CHECK-DAG: Return [<>] + // + /// 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: <> ParameterValue + /// CHECK-DAG: <> IntConstant 20 + /// CHECK-DAG: <> InvokeStaticOrDirect [<>,<>] intrinsic:MathMaxIntInt + /// CHECK-DAG: Return [<>] + // + /// CHECK-START: int Main.maxI(int) instruction_simplifier (after) + /// CHECK-DAG: <> ParameterValue + /// CHECK-DAG: <> IntConstant 20 + /// CHECK-DAG: <> Max [<>,<>] + /// CHECK-DAG: Return [<>] + // + /// 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: <> ParameterValue + /// CHECK-DAG: <> LongConstant 20 + /// CHECK-DAG: <> InvokeStaticOrDirect [<>,<>] intrinsic:MathMaxLongLong + /// CHECK-DAG: Return [<>] + // + /// CHECK-START: long Main.maxL(long) instruction_simplifier (after) + /// CHECK-DAG: <> ParameterValue + /// CHECK-DAG: <> LongConstant 20 + /// CHECK-DAG: <> Max [<>,<>] + /// CHECK-DAG: Return [<>] + // + /// 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 class Main { 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)); -- cgit v1.2.3-59-g8ed1b