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 SimdInt {
21 
22   static int[] a;
23 
24   //
25   // Arithmetic operations.
26   //
27 
28   /// CHECK-START: void SimdInt.add(int) 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-{ARM,ARM64}: void SimdInt.add(int) 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(int x)36   static void add(int x) {
37     for (int i = 0; i < 128; i++)
38       a[i] += x;
39   }
40 
41   /// CHECK-START: void SimdInt.sub(int) 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-{ARM,ARM64}: void SimdInt.sub(int) 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(int x)49   static void sub(int x) {
50     for (int i = 0; i < 128; i++)
51       a[i] -= x;
52   }
53 
54   /// CHECK-START: void SimdInt.mul(int) 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   /// CHECK-START-{ARM,ARM64}: void SimdInt.mul(int) loop_optimization (after)
59   /// CHECK-DAG: VecLoad  loop:<<Loop:B\d+>> outer_loop:none
60   /// CHECK-DAG: VecMul   loop:<<Loop>>      outer_loop:none
61   /// CHECK-DAG: VecStore loop:<<Loop>>      outer_loop:none
mul(int x)62   static void mul(int x) {
63     for (int i = 0; i < 128; i++)
64       a[i] *= x;
65   }
66 
67   /// CHECK-START: void SimdInt.div(int) 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 SimdInt.div(int) loop_optimization (after)
72   /// CHECK-NOT: VecDiv
73   //
74   //  Not supported on any architecture.
75   //
div(int x)76   static void div(int x) {
77     for (int i = 0; i < 128; i++)
78       a[i] /= x;
79   }
80 
81   /// CHECK-START: void SimdInt.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-{ARM,ARM64}: void SimdInt.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 SimdInt.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-{ARM,ARM64}: void SimdInt.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 SimdInt.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-{ARM,ARM64}: void SimdInt.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 SimdInt.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-{ARM,ARM64}: void SimdInt.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 SimdInt.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-{ARM,ARM64}: void SimdInt.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 checks.
148   //
149 
150   // Expose constants to optimizing compiler, but not to front-end.
$opt$inline$IntConstant32()151   public static int $opt$inline$IntConstant32()       { return 32; }
$opt$inline$IntConstant33()152   public static int $opt$inline$IntConstant33()       { return 33; }
$opt$inline$IntConstantMinus254()153   public static int $opt$inline$IntConstantMinus254() { return -254; }
154 
155   /// CHECK-START: void SimdInt.shr32() instruction_simplifier$after_inlining (before)
156   /// CHECK-DAG: <<Dist:i\d+>> IntConstant 32                        loop:none
157   /// CHECK-DAG: <<Get:i\d+>>  ArrayGet                              loop:<<Loop:B\d+>> outer_loop:none
158   /// CHECK-DAG: <<UShr:i\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 SimdInt.shr32() instruction_simplifier$after_inlining (after)
162   /// CHECK-DAG: <<Get:i\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-{ARM,ARM64}: void SimdInt.shr32() loop_optimization (after)
166   /// CHECK-IF:     hasIsaFeature("sve")
167   //
168   ///     CHECK-DAG: <<Get:d\d+>> VecLoad                                       loop:<<Loop:B\d+>> outer_loop:none
169   ///     CHECK-DAG:              VecStore [{{l\d+}},{{i\d+}},<<Get>>,{{j\d+}}] loop:<<Loop>>      outer_loop:none
170   //
171   /// CHECK-ELSE:
172   //
173   ///     CHECK-DAG: <<Get:d\d+>> VecLoad                              loop:<<Loop:B\d+>> outer_loop:none
174   ///     CHECK-DAG:              VecStore [{{l\d+}},{{i\d+}},<<Get>>] loop:<<Loop>>      outer_loop:none
175   //
176   /// CHECK-FI:
shr32()177   static void shr32() {
178     // TODO: remove a[i] = a[i] altogether?
179     for (int i = 0; i < 128; i++)
180       a[i] >>>= $opt$inline$IntConstant32();  // 0, since & 31
181   }
182 
183   /// CHECK-START: void SimdInt.shr33() instruction_simplifier$after_inlining (before)
184   /// CHECK-DAG: <<Dist:i\d+>> IntConstant 33                        loop:none
185   /// CHECK-DAG: <<Get:i\d+>>  ArrayGet                              loop:<<Loop:B\d+>> outer_loop:none
186   /// CHECK-DAG: <<UShr:i\d+>> UShr [<<Get>>,<<Dist>>]               loop:<<Loop>>      outer_loop:none
187   /// CHECK-DAG:               ArraySet [{{l\d+}},{{i\d+}},<<UShr>>] loop:<<Loop>>      outer_loop:none
188   //
189   /// CHECK-START: void SimdInt.shr33() instruction_simplifier$after_inlining (after)
190   /// CHECK-DAG: <<Dist:i\d+>> IntConstant 1                         loop:none
191   /// CHECK-DAG: <<Get:i\d+>>  ArrayGet                              loop:<<Loop:B\d+>> outer_loop:none
192   /// CHECK-DAG: <<UShr:i\d+>> UShr [<<Get>>,<<Dist>>]               loop:<<Loop>>      outer_loop:none
193   /// CHECK-DAG:               ArraySet [{{l\d+}},{{i\d+}},<<UShr>>] loop:<<Loop>>      outer_loop:none
194   //
195   /// CHECK-START-{ARM,ARM64}: void SimdInt.shr33() loop_optimization (after)
196   /// CHECK-DAG: <<Dist:i\d+>> IntConstant 1                         loop:none
197   /// CHECK-IF:     hasIsaFeature("sve")
198   //
199   ///     CHECK-DAG: <<Get:d\d+>>  VecLoad                                        loop:<<Loop:B\d+>> outer_loop:none
200   ///     CHECK-DAG: <<UShr:d\d+>> VecUShr [<<Get>>,<<Dist>>,{{j\d+}}]            loop:<<Loop>>      outer_loop:none
201   ///     CHECK-DAG:               VecStore [{{l\d+}},{{i\d+}},<<UShr>>,{{j\d+}}] loop:<<Loop>>      outer_loop:none
202   //
203   /// CHECK-ELSE:
204   //
205   ///     CHECK-DAG: <<Get:d\d+>>  VecLoad                               loop:<<Loop:B\d+>> outer_loop:none
206   ///     CHECK-DAG: <<UShr:d\d+>> VecUShr [<<Get>>,<<Dist>>]            loop:<<Loop>>      outer_loop:none
207   ///     CHECK-DAG:               VecStore [{{l\d+}},{{i\d+}},<<UShr>>] loop:<<Loop>>      outer_loop:none
208   //
209   /// CHECK-FI:
shr33()210   static void shr33() {
211     for (int i = 0; i < 128; i++)
212       a[i] >>>= $opt$inline$IntConstant33();  // 1, since & 31
213   }
214 
215   /// CHECK-START: void SimdInt.shrMinus254() instruction_simplifier$after_inlining (before)
216   /// CHECK-DAG: <<Dist:i\d+>> IntConstant -254                      loop:none
217   /// CHECK-DAG: <<Get:i\d+>>  ArrayGet                              loop:<<Loop:B\d+>> outer_loop:none
218   /// CHECK-DAG: <<UShr:i\d+>> UShr [<<Get>>,<<Dist>>]               loop:<<Loop>>      outer_loop:none
219   /// CHECK-DAG:               ArraySet [{{l\d+}},{{i\d+}},<<UShr>>] loop:<<Loop>>      outer_loop:none
220   //
221   /// CHECK-START: void SimdInt.shrMinus254() instruction_simplifier$after_inlining (after)
222   /// CHECK-DAG: <<Dist:i\d+>> IntConstant 2                         loop:none
223   /// CHECK-DAG: <<Get:i\d+>>  ArrayGet                              loop:<<Loop:B\d+>> outer_loop:none
224   /// CHECK-DAG: <<UShr:i\d+>> UShr [<<Get>>,<<Dist>>]               loop:<<Loop>>      outer_loop:none
225   /// CHECK-DAG:               ArraySet [{{l\d+}},{{i\d+}},<<UShr>>] loop:<<Loop>>      outer_loop:none
226   //
227   /// CHECK-START-{ARM,ARM64}: void SimdInt.shrMinus254() loop_optimization (after)
228   /// CHECK-DAG: <<Dist:i\d+>> IntConstant 2                         loop:none
229   /// CHECK-IF:     hasIsaFeature("sve")
230   //
231   ///     CHECK-DAG: <<Get:d\d+>>  VecLoad                                        loop:<<Loop:B\d+>> outer_loop:none
232   ///     CHECK-DAG: <<UShr:d\d+>> VecUShr [<<Get>>,<<Dist>>,{{j\d+}}]            loop:<<Loop>>      outer_loop:none
233   ///     CHECK-DAG:               VecStore [{{l\d+}},{{i\d+}},<<UShr>>,{{j\d+}}] loop:<<Loop>>      outer_loop:none
234   //
235   /// CHECK-ELSE:
236   //
237   ///     CHECK-DAG: <<Get:d\d+>>  VecLoad                               loop:<<Loop:B\d+>> outer_loop:none
238   ///     CHECK-DAG: <<UShr:d\d+>> VecUShr [<<Get>>,<<Dist>>]            loop:<<Loop>>      outer_loop:none
239   ///     CHECK-DAG:               VecStore [{{l\d+}},{{i\d+}},<<UShr>>] loop:<<Loop>>      outer_loop:none
240   //
241   /// CHECK-FI:
shrMinus254()242   static void shrMinus254() {
243     for (int i = 0; i < 128; i++)
244       a[i] >>>= $opt$inline$IntConstantMinus254();  // 2, since & 31
245   }
246 
247   //
248   // Loop bounds.
249   //
250 
bounds()251   static void bounds() {
252     for (int i = 1; i < 127; i++)
253       a[i] += 11;
254   }
255 
256   //
257   // Test Driver.
258   //
259 
main()260   public static void main() {
261     // Set up.
262     a = new int[128];
263     for (int i = 0; i < 128; i++) {
264       a[i] = i;
265     }
266     // Arithmetic operations.
267     add(2);
268     for (int i = 0; i < 128; i++) {
269       expectEquals(i + 2, a[i], "add");
270     }
271     sub(2);
272     for (int i = 0; i < 128; i++) {
273       expectEquals(i, a[i], "sub");
274     }
275     mul(2);
276     for (int i = 0; i < 128; i++) {
277       expectEquals(i + i, a[i], "mul");
278     }
279     div(2);
280     for (int i = 0; i < 128; i++) {
281       expectEquals(i, a[i], "div");
282     }
283     neg();
284     for (int i = 0; i < 128; i++) {
285       expectEquals(-i, a[i], "neg");
286     }
287     // Loop bounds.
288     bounds();
289     expectEquals(0, a[0], "bounds0");
290     for (int i = 1; i < 127; i++) {
291       expectEquals(11 - i, a[i], "bounds");
292     }
293     expectEquals(-127, a[127], "bounds127");
294     // Shifts.
295     for (int i = 0; i < 128; i++) {
296       a[i] = 0xffffffff;
297     }
298     shl4();
299     for (int i = 0; i < 128; i++) {
300       expectEquals(0xfffffff0, a[i], "shl4");
301     }
302     sar2();
303     for (int i = 0; i < 128; i++) {
304       expectEquals(0xfffffffc, a[i], "sar2");
305     }
306     shr2();
307     for (int i = 0; i < 128; i++) {
308       expectEquals(0x3fffffff, a[i], "shr2");
309     }
310     shr32();
311     for (int i = 0; i < 128; i++) {
312       expectEquals(0x3fffffff, a[i], "shr32");
313     }
314     shr33();
315     for (int i = 0; i < 128; i++) {
316       expectEquals(0x1fffffff, a[i], "shr33");
317     }
318     shrMinus254();
319     for (int i = 0; i < 128; i++) {
320       expectEquals(0x07ffffff, a[i], "shrMinus254");
321     }
322     // Bit-wise not operator.
323     not();
324     for (int i = 0; i < 128; i++) {
325       expectEquals(0xf8000000, a[i], "not");
326     }
327     // Done.
328     System.out.println("SimdInt passed");
329   }
330 
expectEquals(int expected, int result, String action)331   private static void expectEquals(int expected, int result, String action) {
332     if (expected != result) {
333       throw new Error("Expected: " + expected + ", found: " + result + " for " + action);
334     }
335   }
336 }
337