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,ARM64}: void HaddOther.test_no_hadd_sum_casted_plus_const(short[], short[], short[]) loop_optimization (after)
103   /// CHECK: VecAdd
104   /// CHECK: VecHalvingAdd
test_no_hadd_sum_casted_plus_const(short[] a, short[] b, short[] out)105   private static void test_no_hadd_sum_casted_plus_const(short[] a, short[] b, short[] out) {
106     int min_length = Math.min(out.length, Math.min(a.length, b.length));
107     for (int i = 0; i < min_length; i++) {
108       out[i] = (short) (((short) (a[i] + b[i]) + 1) >> 1);
109     }
110   }
111 
main()112   public static void main() {
113     short[] sA = new short[M];
114     short[] sB = new short[M];
115     short[] sOut = new short[M];
116     int[] iA = new int[M];
117     int[] iB = new int[M];
118     int[] iOut = new int[M];
119 
120     // Some interesting values.
121     short[] interesting = {
122       (short) 0x0000,
123       (short) 0x0001,
124       (short) 0x0002,
125       (short) 0x1234,
126       (short) 0x8000,
127       (short) 0x8001,
128       (short) 0x7fff,
129       (short) 0xffff
130     };
131     // Initialize cross-values to test all cases, and also
132     // set up some extra values to exercise the cleanup loop.
133     for (int i = 0; i < M; i++) {
134       sA[i] = (short) i;
135       sB[i] = interesting[i & 7];
136       iA[i] = i;
137       iB[i] = interesting[i & 7];
138     }
139 
140     test_no_hadd_short2short(sA, sOut);
141     for (int i = 0; i < M; i++) {
142       short e = (short) (sA[i] >> 1);
143       expectEquals(e, sOut[i]);
144     }
145     test_no_hadd_short2short_logical(sA, sOut);
146     for (int i = 0; i < M; i++) {
147       short e = (short) (sA[i] >>> 1);
148       expectEquals(e, sOut[i]);
149     }
150     test_no_hadd_int2short(iA, sOut);
151     for (int i = 0; i < M; i++) {
152       short e = (short) (iA[i] >> 1);
153       expectEquals(e, sOut[i]);
154     }
155     test_no_hadd_int2int(iA, iOut);
156     for (int i = 0; i < M; i++) {
157       int e = iA[i] >> 1;
158       expectEquals(e, iOut[i]);
159     }
160     test_no_hadd_sum_casted(sA, sB, sOut);
161     for (int i = 0; i < M; i++) {
162       short e = (short) (((short) (sA[i] + sB[i])) >> 1);
163       expectEquals(e, sOut[i]);
164     }
165     test_no_hadd_sum_casted_ints(iA, iB, iOut);
166     for (int i = 0; i < M; i++) {
167       int e = (short) ((short) (iA[i] + iB[i]) >> 1);
168       expectEquals(e, iOut[i]);
169     }
170     test_no_hadd_sum_casted_plus_const(sA, sB, sOut);
171     for (int i = 0; i < M; i++) {
172       short e = (short) (((short) (sA[i] + sB[i]) + 1) >> 1);
173       expectEquals(e, sOut[i]);
174     }
175 
176     System.out.println("HaddOther passed");
177   }
178 
expectEquals(int expected, int result)179   private static void expectEquals(int expected, int result) {
180     if (expected != result) {
181       throw new Error("Expected: " + expected + ", found: " + result);
182     }
183   }
184 }
185