1 /*
2  * Copyright (C) 2020 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 public class HaddOther {
18   private static final int N = 2 * 1024;
19   private static final int M = N + 31;
20 
21   //  Should be just shift right, not halving add.
22   //
23   /// CHECK-START-{ARM,ARM64}: void HaddOther.test_no_hadd_short2short(short[], short[]) loop_optimization (after)
24   /// CHECK: VecShr
25 
26   /// CHECK-START-{ARM,ARM64}: void HaddOther.test_no_hadd_short2short(short[], short[]) loop_optimization (after)
27   /// CHECK-NOT: VecHalvingAdd
test_no_hadd_short2short(short[] a, short[] out)28   private static void test_no_hadd_short2short(short[] a, short[] out) {
29     int min_length = Math.min(out.length, a.length);
30     for (int i = 0; i < min_length; i++) {
31       out[i] = (short) (a[i] >> 1);
32     }
33   }
34 
35   //  This loop is not vectorized: shift right with a signed type is not supported.
36   //
37   /// CHECK-START-{ARM,ARM64}: void HaddOther.test_no_hadd_short2short_logical(short[], short[]) loop_optimization (after)
38   /// CHECK-NOT: VecLoad
39   /// CHECK-NOT: VecHalvingAdd
test_no_hadd_short2short_logical(short[] a, short[] out)40   private static void test_no_hadd_short2short_logical(short[] a, short[] out) {
41     int min_length = Math.min(out.length, a.length);
42     for (int i = 0; i < min_length; i++) {
43       out[i] = (short) (a[i] >>> 1);
44     }
45   }
46 
47   //  This loop is not vectorized: mismatched packed type size.
48   //
49   /// CHECK-START-{ARM,ARM64}: void HaddOther.test_no_hadd_int2short(int[], short[]) loop_optimization (after)
50   /// CHECK-NOT: VecLoad
51   /// CHECK-NOT: VecHalvingAdd
test_no_hadd_int2short(int[] a, short[] out)52   private static void test_no_hadd_int2short(int[] a, short[] out) {
53     int min_length = Math.min(out.length, a.length);
54     for (int i = 0; i < min_length; i++) {
55       out[i] = (short) (a[i] >> 1);
56     }
57   }
58 
59   //  Should be just shift right, not halving add.
60   //
61   /// CHECK-START-{ARM,ARM64}: void HaddOther.test_no_hadd_int2int(int[], int[]) loop_optimization (after)
62   /// CHECK: VecShr
63 
64   /// CHECK-START-{ARM,ARM64}: void HaddOther.test_no_hadd_int2int(int[], int[]) loop_optimization (after)
65   /// CHECK-NOT: VecHalvingAdd
test_no_hadd_int2int(int[] a, int[] out)66   private static void test_no_hadd_int2int(int[] a, int[] out) {
67     int min_length = Math.min(out.length, a.length);
68     for (int i = 0; i < min_length; i++) {
69       out[i] = a[i] >> 1;
70     }
71   }
72 
73   //  Should be just add and shift right, not halving add.
74   //
75   /// CHECK-START-{ARM,ARM64}: void HaddOther.test_no_hadd_sum_casted(short[], short[], short[]) loop_optimization (after)
76   /// CHECK: VecAdd
77   /// CHECK: VecShr
78 
79   /// CHECK-START-{ARM,ARM64}: void HaddOther.test_no_hadd_sum_casted(short[], short[], short[]) loop_optimization (after)
80   /// CHECK-NOT: VecHalvingAdd
test_no_hadd_sum_casted(short[] a, short[] b, short[] out)81   private static void test_no_hadd_sum_casted(short[] a, short[] b, short[] out) {
82     int min_length = Math.min(out.length, Math.min(a.length, b.length));
83     for (int i = 0; i < min_length; i++) {
84       out[i] = (short) (((short) (a[i] + b[i])) >> 1);
85     }
86   }
87 
88   //  This loop is not vectorized: mismatched packed type size.
89   //
90   /// CHECK-START-{ARM,ARM64}: void HaddOther.test_no_hadd_sum_casted_ints(int[], int[], int[]) loop_optimization (after)
91   /// CHECK-NOT: VecLoad
92   /// CHECK-NOT: VecHalvingAdd
test_no_hadd_sum_casted_ints(int[] a, int[] b, int[] out)93   private static void test_no_hadd_sum_casted_ints(int[] a, int[] b, int[] out) {
94     int min_length = Math.min(out.length, Math.min(a.length, b.length));
95     for (int i = 0; i < min_length; i++) {
96       out[i] = (short) ((short) (a[i] + b[i]) >> 1);
97     }
98   }
99 
100   //  Should be an add, followed by a halving add.
101   //
102   /// CHECK-START-ARM: void HaddOther.test_no_hadd_sum_casted_plus_const(short[], short[], short[]) loop_optimization (after)
103   /// CHECK: VecAdd
104   /// CHECK: VecHalvingAdd
105   //
106   /// CHECK-START-ARM64: void HaddOther.test_no_hadd_sum_casted_plus_const(short[], short[], short[]) loop_optimization (after)
107   /// CHECK-IF:     hasIsaFeature("sve")
108   //
109   //      HalvingAdd idiom is not supported for SVE.
110   ///     CHECK-NOT: VecHalvingAdd
111   //
112   /// CHECK-ELSE:
113   //
114   ///     CHECK: VecAdd
115   ///     CHECK: VecHalvingAdd
116   //
117   /// CHECK-FI:
test_no_hadd_sum_casted_plus_const(short[] a, short[] b, short[] out)118   private static void test_no_hadd_sum_casted_plus_const(short[] a, short[] b, short[] out) {
119     int min_length = Math.min(out.length, Math.min(a.length, b.length));
120     for (int i = 0; i < min_length; i++) {
121       out[i] = (short) (((short) (a[i] + b[i]) + 1) >> 1);
122     }
123   }
124 
main()125   public static void main() {
126     short[] sA = new short[M];
127     short[] sB = new short[M];
128     short[] sOut = new short[M];
129     int[] iA = new int[M];
130     int[] iB = new int[M];
131     int[] iOut = new int[M];
132 
133     // Some interesting values.
134     short[] interesting = {
135       (short) 0x0000,
136       (short) 0x0001,
137       (short) 0x0002,
138       (short) 0x1234,
139       (short) 0x8000,
140       (short) 0x8001,
141       (short) 0x7fff,
142       (short) 0xffff
143     };
144     // Initialize cross-values to test all cases, and also
145     // set up some extra values to exercise the cleanup loop.
146     for (int i = 0; i < M; i++) {
147       sA[i] = (short) i;
148       sB[i] = interesting[i & 7];
149       iA[i] = i;
150       iB[i] = interesting[i & 7];
151     }
152 
153     test_no_hadd_short2short(sA, sOut);
154     for (int i = 0; i < M; i++) {
155       short e = (short) (sA[i] >> 1);
156       expectEquals(e, sOut[i]);
157     }
158     test_no_hadd_short2short_logical(sA, sOut);
159     for (int i = 0; i < M; i++) {
160       short e = (short) (sA[i] >>> 1);
161       expectEquals(e, sOut[i]);
162     }
163     test_no_hadd_int2short(iA, sOut);
164     for (int i = 0; i < M; i++) {
165       short e = (short) (iA[i] >> 1);
166       expectEquals(e, sOut[i]);
167     }
168     test_no_hadd_int2int(iA, iOut);
169     for (int i = 0; i < M; i++) {
170       int e = iA[i] >> 1;
171       expectEquals(e, iOut[i]);
172     }
173     test_no_hadd_sum_casted(sA, sB, sOut);
174     for (int i = 0; i < M; i++) {
175       short e = (short) (((short) (sA[i] + sB[i])) >> 1);
176       expectEquals(e, sOut[i]);
177     }
178     test_no_hadd_sum_casted_ints(iA, iB, iOut);
179     for (int i = 0; i < M; i++) {
180       int e = (short) ((short) (iA[i] + iB[i]) >> 1);
181       expectEquals(e, iOut[i]);
182     }
183     test_no_hadd_sum_casted_plus_const(sA, sB, sOut);
184     for (int i = 0; i < M; i++) {
185       short e = (short) (((short) (sA[i] + sB[i]) + 1) >> 1);
186       expectEquals(e, sOut[i]);
187     }
188 
189     System.out.println("HaddOther passed");
190   }
191 
expectEquals(int expected, int result)192   private static void expectEquals(int expected, int result) {
193     if (expected != result) {
194       throw new Error("Expected: " + expected + ", found: " + result);
195     }
196   }
197 }
198