Aart Bik | c8e93c7 | 2017-05-10 10:49:22 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2017 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | /** |
| 18 | * Tests for MIN/MAX vectorization. |
| 19 | */ |
| 20 | public class Main { |
| 21 | |
| 22 | /// CHECK-START: void Main.doitMin(double[], double[], double[]) loop_optimization (before) |
| 23 | /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none |
| 24 | /// CHECK-DAG: <<Get1:d\d+>> ArrayGet loop:<<Loop>> outer_loop:none |
| 25 | /// CHECK-DAG: <<Get2:d\d+>> ArrayGet loop:<<Loop>> outer_loop:none |
| 26 | /// CHECK-DAG: <<Min:d\d+>> InvokeStaticOrDirect [<<Get1>>,<<Get2>>] intrinsic:MathMinDoubleDouble loop:<<Loop>> outer_loop:none |
| 27 | /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Min>>] loop:<<Loop>> outer_loop:none |
| 28 | // |
| 29 | // TODO x86: 0.0 vs -0.0? |
Goran Jakovljevic | 8fea1e1 | 2017-06-06 13:28:42 +0200 | [diff] [blame] | 30 | // TODO MIPS64: min(x, NaN)? |
Aart Bik | c8e93c7 | 2017-05-10 10:49:22 -0700 | [diff] [blame] | 31 | // |
| 32 | /// CHECK-START-ARM64: void Main.doitMin(double[], double[], double[]) loop_optimization (after) |
| 33 | /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none |
| 34 | /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none |
| 35 | /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none |
| 36 | /// CHECK-DAG: <<Min:d\d+>> VecMin [<<Get1>>,<<Get2>>] loop:<<Loop>> outer_loop:none |
| 37 | /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<Min>>] loop:<<Loop>> outer_loop:none |
| 38 | private static void doitMin(double[] x, double[] y, double[] z) { |
| 39 | int min = Math.min(x.length, Math.min(y.length, z.length)); |
| 40 | for (int i = 0; i < min; i++) { |
| 41 | x[i] = Math.min(y[i], z[i]); |
| 42 | } |
| 43 | } |
| 44 | |
| 45 | /// CHECK-START: void Main.doitMax(double[], double[], double[]) loop_optimization (before) |
| 46 | /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none |
| 47 | /// CHECK-DAG: <<Get1:d\d+>> ArrayGet loop:<<Loop>> outer_loop:none |
| 48 | /// CHECK-DAG: <<Get2:d\d+>> ArrayGet loop:<<Loop>> outer_loop:none |
| 49 | /// CHECK-DAG: <<Max:d\d+>> InvokeStaticOrDirect [<<Get1>>,<<Get2>>] intrinsic:MathMaxDoubleDouble loop:<<Loop>> outer_loop:none |
| 50 | /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Max>>] loop:<<Loop>> outer_loop:none |
| 51 | // |
Aart Bik | 304c8a5 | 2017-05-23 11:01:13 -0700 | [diff] [blame] | 52 | // TODO x86: 0.0 vs -0.0? |
Goran Jakovljevic | 8fea1e1 | 2017-06-06 13:28:42 +0200 | [diff] [blame] | 53 | // TODO MIPS64: max(x, NaN)? |
Aart Bik | c8e93c7 | 2017-05-10 10:49:22 -0700 | [diff] [blame] | 54 | // |
| 55 | /// CHECK-START-ARM64: void Main.doitMax(double[], double[], double[]) loop_optimization (after) |
| 56 | /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none |
| 57 | /// CHECK-DAG: <<Get1:d\d+>> VecLoad loop:<<Loop>> outer_loop:none |
| 58 | /// CHECK-DAG: <<Get2:d\d+>> VecLoad loop:<<Loop>> outer_loop:none |
| 59 | /// CHECK-DAG: <<Max:d\d+>> VecMax [<<Get1>>,<<Get2>>] loop:<<Loop>> outer_loop:none |
| 60 | /// CHECK-DAG: VecStore [{{l\d+}},<<Phi>>,<<Max>>] loop:<<Loop>> outer_loop:none |
| 61 | private static void doitMax(double[] x, double[] y, double[] z) { |
| 62 | int min = Math.min(x.length, Math.min(y.length, z.length)); |
| 63 | for (int i = 0; i < min; i++) { |
| 64 | x[i] = Math.max(y[i], z[i]); |
| 65 | } |
| 66 | } |
| 67 | |
| 68 | public static void main(String[] args) { |
| 69 | double[] interesting = { |
| 70 | -0.0f, |
| 71 | +0.0f, |
| 72 | -1.0f, |
| 73 | +1.0f, |
| 74 | -3.14f, |
| 75 | +3.14f, |
| 76 | -100.0f, |
| 77 | +100.0f, |
| 78 | -4444.44f, |
| 79 | +4444.44f, |
| 80 | Double.MIN_NORMAL, |
| 81 | Double.MIN_VALUE, |
| 82 | Double.MAX_VALUE, |
| 83 | Double.NEGATIVE_INFINITY, |
| 84 | Double.POSITIVE_INFINITY, |
| 85 | Double.NaN |
| 86 | }; |
| 87 | // Initialize cross-values for the interesting values. |
| 88 | int total = interesting.length * interesting.length; |
| 89 | double[] x = new double[total]; |
| 90 | double[] y = new double[total]; |
| 91 | double[] z = new double[total]; |
| 92 | int k = 0; |
| 93 | for (int i = 0; i < interesting.length; i++) { |
| 94 | for (int j = 0; j < interesting.length; j++) { |
| 95 | x[k] = 0; |
| 96 | y[k] = interesting[i]; |
| 97 | z[k] = interesting[j]; |
| 98 | k++; |
| 99 | } |
| 100 | } |
| 101 | |
| 102 | // And test. |
| 103 | doitMin(x, y, z); |
| 104 | for (int i = 0; i < total; i++) { |
| 105 | double expected = Math.min(y[i], z[i]); |
| 106 | expectEquals(expected, x[i]); |
| 107 | } |
| 108 | doitMax(x, y, z); |
| 109 | for (int i = 0; i < total; i++) { |
| 110 | double expected = Math.max(y[i], z[i]); |
| 111 | expectEquals(expected, x[i]); |
| 112 | } |
| 113 | |
| 114 | System.out.println("passed"); |
| 115 | } |
| 116 | |
| 117 | private static void expectEquals(double expected, double result) { |
| 118 | // Tests the bits directly. This distinguishes correctly between +0.0 |
| 119 | // and -0.0 and returns a canonical representation for all NaN. |
| 120 | long expected_bits = Double.doubleToLongBits(expected); |
| 121 | long result_bits = Double.doubleToLongBits(result); |
| 122 | if (expected_bits != result_bits) { |
| 123 | throw new Error("Expected: " + expected + |
| 124 | "(0x" + Long.toHexString(expected_bits) + "), found: " + result + |
| 125 | "(0x" + Long.toHexString(result_bits) + ")"); |
| 126 | } |
| 127 | } |
| 128 | } |