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  * Functional tests for SIMD vectorization.
19  */
20 public class SimdLong {
21 
22   static long[] a;
23 
24   //
25   // Arithmetic operations.
26   //
27 
28   /// CHECK-START: void SimdLong.add(long) loop_optimization (before)
29   /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
30   /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
31   //
32   /// CHECK-START-ARM64: void SimdLong.add(long) loop_optimization (after)
33   /// CHECK-DAG: VecLoad  loop:<<Loop:B\d+>> outer_loop:none
34   /// CHECK-DAG: VecAdd   loop:<<Loop>>      outer_loop:none
35   /// CHECK-DAG: VecStore loop:<<Loop>>      outer_loop:none
add(long x)36   static void add(long x) {
37     for (int i = 0; i < 128; i++)
38       a[i] += x;
39   }
40 
41   /// CHECK-START: void SimdLong.sub(long) loop_optimization (before)
42   /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
43   /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
44   //
45   /// CHECK-START-ARM64: void SimdLong.sub(long) loop_optimization (after)
46   /// CHECK-DAG: VecLoad  loop:<<Loop:B\d+>> outer_loop:none
47   /// CHECK-DAG: VecSub   loop:<<Loop>>      outer_loop:none
48   /// CHECK-DAG: VecStore loop:<<Loop>>      outer_loop:none
sub(long x)49   static void sub(long x) {
50     for (int i = 0; i < 128; i++)
51       a[i] -= x;
52   }
53 
54   /// CHECK-START: void SimdLong.mul(long) loop_optimization (before)
55   /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
56   /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
57   //
58   //  Not directly supported for longs.
59   //
60   /// CHECK-START-ARM64: void SimdLong.mul(long) loop_optimization (after)
61   /// CHECK-NOT: VecMul
mul(long x)62   static void mul(long x) {
63     for (int i = 0; i < 128; i++)
64       a[i] *= x;
65   }
66 
67   /// CHECK-START: void SimdLong.div(long) loop_optimization (before)
68   /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
69   /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
70   //
71   /// CHECK-START: void SimdLong.div(long) loop_optimization (after)
72   /// CHECK-NOT: VecDiv
73   //
74   //  Not supported on any architecture.
75   //
div(long x)76   static void div(long x) {
77     for (int i = 0; i < 128; i++)
78       a[i] /= x;
79   }
80 
81   /// CHECK-START: void SimdLong.neg() loop_optimization (before)
82   /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
83   /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
84   //
85   /// CHECK-START-ARM64: void SimdLong.neg() loop_optimization (after)
86   /// CHECK-DAG: VecLoad  loop:<<Loop:B\d+>> outer_loop:none
87   /// CHECK-DAG: VecNeg   loop:<<Loop>>      outer_loop:none
88   /// CHECK-DAG: VecStore loop:<<Loop>>      outer_loop:none
neg()89   static void neg() {
90     for (int i = 0; i < 128; i++)
91       a[i] = -a[i];
92   }
93 
94   /// CHECK-START: void SimdLong.not() loop_optimization (before)
95   /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
96   /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
97   //
98   /// CHECK-START-ARM64: void SimdLong.not() loop_optimization (after)
99   /// CHECK-DAG: VecLoad  loop:<<Loop:B\d+>> outer_loop:none
100   /// CHECK-DAG: VecNot   loop:<<Loop>>      outer_loop:none
101   /// CHECK-DAG: VecStore loop:<<Loop>>      outer_loop:none
not()102   static void not() {
103     for (int i = 0; i < 128; i++)
104       a[i] = ~a[i];
105   }
106 
107   /// CHECK-START: void SimdLong.shl4() loop_optimization (before)
108   /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
109   /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
110   //
111   /// CHECK-START-ARM64: void SimdLong.shl4() loop_optimization (after)
112   /// CHECK-DAG: VecLoad  loop:<<Loop:B\d+>> outer_loop:none
113   /// CHECK-DAG: VecShl   loop:<<Loop>>      outer_loop:none
114   /// CHECK-DAG: VecStore loop:<<Loop>>      outer_loop:none
shl4()115   static void shl4() {
116     for (int i = 0; i < 128; i++)
117       a[i] <<= 4;
118   }
119 
120   /// CHECK-START: void SimdLong.sar2() loop_optimization (before)
121   /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
122   /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
123   //
124   /// CHECK-START-ARM64: void SimdLong.sar2() loop_optimization (after)
125   /// CHECK-DAG: VecLoad  loop:<<Loop:B\d+>> outer_loop:none
126   /// CHECK-DAG: VecShr   loop:<<Loop>>      outer_loop:none
127   /// CHECK-DAG: VecStore loop:<<Loop>>      outer_loop:none
sar2()128   static void sar2() {
129     for (int i = 0; i < 128; i++)
130       a[i] >>= 2;
131   }
132 
133   /// CHECK-START: void SimdLong.shr2() loop_optimization (before)
134   /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> outer_loop:none
135   /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
136   //
137   /// CHECK-START-ARM64: void SimdLong.shr2() loop_optimization (after)
138   /// CHECK-DAG: VecLoad  loop:<<Loop:B\d+>> outer_loop:none
139   /// CHECK-DAG: VecUShr  loop:<<Loop>>      outer_loop:none
140   /// CHECK-DAG: VecStore loop:<<Loop>>      outer_loop:none
shr2()141   static void shr2() {
142     for (int i = 0; i < 128; i++)
143       a[i] >>>= 2;
144   }
145 
146   //
147   // Shift sanity.
148   //
149 
150   // Expose constants to optimizing compiler, but not to front-end.
$opt$inline$IntConstant64()151   public static int $opt$inline$IntConstant64()       { return 64; }
$opt$inline$IntConstant65()152   public static int $opt$inline$IntConstant65()       { return 65; }
$opt$inline$IntConstantMinus254()153   public static int $opt$inline$IntConstantMinus254() { return -254; }
154 
155   /// CHECK-START: void SimdLong.shr64() instruction_simplifier$after_inlining (before)
156   /// CHECK-DAG: <<Dist:i\d+>> IntConstant 64                        loop:none
157   /// CHECK-DAG: <<Get:j\d+>>  ArrayGet                              loop:<<Loop:B\d+>> outer_loop:none
158   /// CHECK-DAG: <<UShr:j\d+>> UShr [<<Get>>,<<Dist>>]               loop:<<Loop>>      outer_loop:none
159   /// CHECK-DAG:               ArraySet [{{l\d+}},{{i\d+}},<<UShr>>] loop:<<Loop>>      outer_loop:none
160   //
161   /// CHECK-START: void SimdLong.shr64() instruction_simplifier$after_inlining (after)
162   /// CHECK-DAG: <<Get:j\d+>> ArrayGet                             loop:<<Loop:B\d+>> outer_loop:none
163   /// CHECK-DAG:              ArraySet [{{l\d+}},{{i\d+}},<<Get>>] loop:<<Loop>>      outer_loop:none
164   //
165   /// CHECK-START-ARM64: void SimdLong.shr64() loop_optimization (after)
166   /// CHECK-DAG: <<Get:d\d+>> VecLoad                              loop:<<Loop:B\d+>> outer_loop:none
167   /// CHECK-DAG:              VecStore [{{l\d+}},{{i\d+}},<<Get>>] loop:<<Loop>>      outer_loop:none
shr64()168   static void shr64() {
169     // TODO: remove a[i] = a[i] altogether?
170     for (int i = 0; i < 128; i++)
171       a[i] >>>= $opt$inline$IntConstant64();  // 0, since & 63
172   }
173 
174   /// CHECK-START: void SimdLong.shr65() instruction_simplifier$after_inlining (before)
175   /// CHECK-DAG: <<Dist:i\d+>> IntConstant 65                        loop:none
176   /// CHECK-DAG: <<Get:j\d+>>  ArrayGet                              loop:<<Loop:B\d+>> outer_loop:none
177   /// CHECK-DAG: <<UShr:j\d+>> UShr [<<Get>>,<<Dist>>]               loop:<<Loop>>      outer_loop:none
178   /// CHECK-DAG:               ArraySet [{{l\d+}},{{i\d+}},<<UShr>>] loop:<<Loop>>      outer_loop:none
179   //
180   /// CHECK-START: void SimdLong.shr65() instruction_simplifier$after_inlining (after)
181   /// CHECK-DAG: <<Dist:i\d+>> IntConstant 1                         loop:none
182   /// CHECK-DAG: <<Get:j\d+>>  ArrayGet                              loop:<<Loop:B\d+>> outer_loop:none
183   /// CHECK-DAG: <<UShr:j\d+>> UShr [<<Get>>,<<Dist>>]               loop:<<Loop>>      outer_loop:none
184   /// CHECK-DAG:               ArraySet [{{l\d+}},{{i\d+}},<<UShr>>] loop:<<Loop>>      outer_loop:none
185   //
186   /// CHECK-START-ARM64: void SimdLong.shr65() loop_optimization (after)
187   /// CHECK-DAG: <<Dist:i\d+>> IntConstant 1                         loop:none
188   /// CHECK-DAG: <<Get:d\d+>>  VecLoad                               loop:<<Loop:B\d+>> outer_loop:none
189   /// CHECK-DAG: <<UShr:d\d+>> VecUShr [<<Get>>,<<Dist>>]            loop:<<Loop>>      outer_loop:none
190   /// CHECK-DAG:               VecStore [{{l\d+}},{{i\d+}},<<UShr>>] loop:<<Loop>>      outer_loop:none
shr65()191   static void shr65() {
192     for (int i = 0; i < 128; i++)
193       a[i] >>>= $opt$inline$IntConstant65();  // 1, since & 63
194   }
195 
196   /// CHECK-START: void SimdLong.shrMinus254() instruction_simplifier$after_inlining (before)
197   /// CHECK-DAG: <<Dist:i\d+>> IntConstant -254                      loop:none
198   /// CHECK-DAG: <<Get:j\d+>>  ArrayGet                              loop:<<Loop:B\d+>> outer_loop:none
199   /// CHECK-DAG: <<UShr:j\d+>> UShr [<<Get>>,<<Dist>>]               loop:<<Loop>>      outer_loop:none
200   /// CHECK-DAG:               ArraySet [{{l\d+}},{{i\d+}},<<UShr>>] loop:<<Loop>>      outer_loop:none
201   //
202   /// CHECK-START: void SimdLong.shrMinus254() instruction_simplifier$after_inlining (after)
203   /// CHECK-DAG: <<Dist:i\d+>> IntConstant 2                         loop:none
204   /// CHECK-DAG: <<Get:j\d+>>  ArrayGet                              loop:<<Loop:B\d+>> outer_loop:none
205   /// CHECK-DAG: <<UShr:j\d+>> UShr [<<Get>>,<<Dist>>]               loop:<<Loop>>      outer_loop:none
206   /// CHECK-DAG:               ArraySet [{{l\d+}},{{i\d+}},<<UShr>>] loop:<<Loop>>      outer_loop:none
207   //
208   /// CHECK-START-ARM64: void SimdLong.shrMinus254() loop_optimization (after)
209   /// CHECK-DAG: <<Dist:i\d+>> IntConstant 2                         loop:none
210   /// CHECK-DAG: <<Get:d\d+>>  VecLoad                               loop:<<Loop:B\d+>> outer_loop:none
211   /// CHECK-DAG: <<UShr:d\d+>> VecUShr [<<Get>>,<<Dist>>]            loop:<<Loop>>      outer_loop:none
212   /// CHECK-DAG:               VecStore [{{l\d+}},{{i\d+}},<<UShr>>] loop:<<Loop>>      outer_loop:none
shrMinus254()213   static void shrMinus254() {
214     for (int i = 0; i < 128; i++)
215       a[i] >>>= $opt$inline$IntConstantMinus254();  // 2, since & 63
216   }
217 
218   //
219   // Loop bounds.
220   //
221 
bounds()222   static void bounds() {
223     for (int i = 1; i < 127; i++)
224       a[i] += 11;
225   }
226 
227   //
228   // Test Driver.
229   //
230 
main()231   public static void main() {
232     // Set up.
233     a = new long[128];
234     for (int i = 0; i < 128; i++) {
235       a[i] = i;
236     }
237     // Arithmetic operations.
238     add(2L);
239     for (int i = 0; i < 128; i++) {
240       expectEquals(i + 2, a[i], "add");
241     }
242     sub(2L);
243     for (int i = 0; i < 128; i++) {
244       expectEquals(i, a[i], "sub");
245     }
246     mul(2L);
247     for (int i = 0; i < 128; i++) {
248       expectEquals(i + i, a[i], "mul");
249     }
250     div(2L);
251     for (int i = 0; i < 128; i++) {
252       expectEquals(i, a[i], "div");
253     }
254     neg();
255     for (int i = 0; i < 128; i++) {
256       expectEquals(-i, a[i], "neg");
257     }
258     // Loop bounds.
259     bounds();
260     expectEquals(0, a[0], "bounds0");
261     for (int i = 1; i < 127; i++) {
262       expectEquals(11 - i, a[i], "bounds");
263     }
264     expectEquals(-127, a[127], "bounds127");
265     // Shifts.
266     for (int i = 0; i < 128; i++) {
267       a[i] = 0xffffffffffffffffL;
268     }
269     shl4();
270     for (int i = 0; i < 128; i++) {
271       expectEquals(0xfffffffffffffff0L, a[i], "shl4");
272     }
273     sar2();
274     for (int i = 0; i < 128; i++) {
275       expectEquals(0xfffffffffffffffcL, a[i], "sar2");
276     }
277     shr2();
278     for (int i = 0; i < 128; i++) {
279       expectEquals(0x3fffffffffffffffL, a[i], "shr2");
280     }
281     shr64();
282     for (int i = 0; i < 128; i++) {
283       expectEquals(0x3fffffffffffffffL, a[i], "shr64");
284     }
285     shr65();
286     for (int i = 0; i < 128; i++) {
287       expectEquals(0x1fffffffffffffffL, a[i], "shr65");
288     }
289     shrMinus254();
290     for (int i = 0; i < 128; i++) {
291       expectEquals(0x07ffffffffffffffL, a[i], "shrMinus254");
292     }
293     // Bit-wise not operator.
294     not();
295     for (int i = 0; i < 128; i++) {
296       expectEquals(0xf800000000000000L, a[i], "not");
297     }
298     // Done.
299     System.out.println("SimdLong passed");
300   }
301 
expectEquals(long expected, long result, String action)302   private static void expectEquals(long expected, long result, String action) {
303     if (expected != result) {
304       throw new Error("Expected: " + expected + ", found: " + result + " for " + action);
305     }
306   }
307 }
308