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 ABS vectorization.
19  */
20 public class Main {
21 
22   private final static boolean isDalvik =
23       System.getProperty("java.vm.name").equals("Dalvik");
24 
25   private static final int SPQUIET = 1 << 22;
26   private static final long DPQUIET = 1L << 51;
27 
28   /// CHECK-START: void Main.doitByte(byte[]) loop_optimization (before)
29   /// CHECK-DAG: Phi       loop:<<Loop:B\d+>> outer_loop:none
30   /// CHECK-DAG: ArrayGet  loop:<<Loop>>      outer_loop:none
31   /// CHECK-DAG: Abs       loop:<<Loop>>      outer_loop:none
32   /// CHECK-DAG: ArraySet  loop:<<Loop>>      outer_loop:none
33   //
34   /// CHECK-START-{ARM,ARM64}: void Main.doitByte(byte[]) loop_optimization (after)
35   /// CHECK-DAG: VecLoad   loop:<<Loop1:B\d+>> outer_loop:none
36   /// CHECK-DAG: VecAbs    loop:<<Loop1>>      outer_loop:none
37   /// CHECK-DAG: VecStore  loop:<<Loop1>>      outer_loop:none
38   /// CHECK-DAG: ArrayGet  loop:<<Loop2:B\d+>> outer_loop:none
39   /// CHECK-DAG: Abs       loop:<<Loop2>>      outer_loop:none
40   /// CHECK-DAG: ArraySet  loop:<<Loop2>>      outer_loop:none
41   //
42   /// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
43   //
doitByte(byte[] x)44   private static void doitByte(byte[] x) {
45     for (int i = 0; i < x.length; i++) {
46       x[i] = (byte) Math.abs(x[i]);
47     }
48   }
49 
50   /// CHECK-START: void Main.doitChar(char[]) loop_optimization (before)
51   /// CHECK-NOT: Abs
52   //
53   /// CHECK-START: void Main.doitChar(char[]) loop_optimization (after)
54   /// CHECK-NOT: VecAbs
doitChar(char[] x)55   private static void doitChar(char[] x) {
56     // Basically a nop due to zero extension.
57     for (int i = 0; i < x.length; i++) {
58       x[i] = (char) Math.abs(x[i]);
59     }
60   }
61 
62   /// CHECK-START: void Main.doitShort(short[]) loop_optimization (before)
63   /// CHECK-DAG: Phi       loop:<<Loop:B\d+>> outer_loop:none
64   /// CHECK-DAG: ArrayGet  loop:<<Loop>>      outer_loop:none
65   /// CHECK-DAG: Abs       loop:<<Loop>>      outer_loop:none
66   /// CHECK-DAG: ArraySet  loop:<<Loop>>      outer_loop:none
67   //
68   /// CHECK-START-{ARM,ARM64}: void Main.doitShort(short[]) loop_optimization (after)
69   /// CHECK-DAG: VecLoad   loop:<<Loop1:B\d+>> outer_loop:none
70   /// CHECK-DAG: VecAbs    loop:<<Loop1>>      outer_loop:none
71   /// CHECK-DAG: VecStore  loop:<<Loop1>>      outer_loop:none
72   /// CHECK-DAG: ArrayGet  loop:<<Loop2:B\d+>> outer_loop:none
73   /// CHECK-DAG: Abs       loop:<<Loop2>>      outer_loop:none
74   /// CHECK-DAG: ArraySet  loop:<<Loop2>>      outer_loop:none
75   //
76   /// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
77   //
doitShort(short[] x)78   private static void doitShort(short[] x) {
79     for (int i = 0; i < x.length; i++) {
80       x[i] = (short) Math.abs(x[i]);
81     }
82   }
83 
84   /// CHECK-START: void Main.doitCastedChar(char[]) loop_optimization (before)
85   /// CHECK-DAG: Phi       loop:<<Loop:B\d+>> outer_loop:none
86   /// CHECK-DAG: ArrayGet  loop:<<Loop>>      outer_loop:none
87   /// CHECK-DAG: Abs       loop:<<Loop>>      outer_loop:none
88   /// CHECK-DAG: ArraySet  loop:<<Loop>>      outer_loop:none
89   //
90   /// CHECK-START-ARM64: void Main.doitCastedChar(char[]) loop_optimization (after)
91   /// CHECK-DAG: VecLoad   loop:<<Loop1:B\d+>> outer_loop:none
92   /// CHECK-DAG: VecAbs    loop:<<Loop1>>      outer_loop:none
93   /// CHECK-DAG: VecStore  loop:<<Loop1>>      outer_loop:none
94   /// CHECK-DAG: ArrayGet  loop:<<Loop2:B\d+>> outer_loop:none
95   /// CHECK-DAG: Abs       loop:<<Loop2>>      outer_loop:none
96   /// CHECK-DAG: ArraySet  loop:<<Loop2>>      outer_loop:none
97   //
98   /// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
99   //
doitCastedChar(char[] x)100   private static void doitCastedChar(char[] x) {
101     for (int i = 0; i < x.length; i++) {
102       x[i] = (char) Math.abs((short) x[i]);
103     }
104   }
105 
106   /// CHECK-START: void Main.doitInt(int[]) loop_optimization (before)
107   /// CHECK-DAG: Phi       loop:<<Loop:B\d+>> outer_loop:none
108   /// CHECK-DAG: ArrayGet  loop:<<Loop>>      outer_loop:none
109   /// CHECK-DAG: Abs       loop:<<Loop>>      outer_loop:none
110   /// CHECK-DAG: ArraySet  loop:<<Loop>>      outer_loop:none
111   //
112   /// CHECK-START-{ARM,ARM64}: void Main.doitInt(int[]) loop_optimization (after)
113   /// CHECK-DAG: VecLoad   loop:<<Loop1:B\d+>> outer_loop:none
114   /// CHECK-DAG: VecAbs    loop:<<Loop1>>      outer_loop:none
115   /// CHECK-DAG: VecStore  loop:<<Loop1>>      outer_loop:none
116   /// CHECK-DAG: ArrayGet  loop:<<Loop2:B\d+>> outer_loop:none
117   /// CHECK-DAG: Abs       loop:<<Loop2>>      outer_loop:none
118   /// CHECK-DAG: ArraySet  loop:<<Loop2>>      outer_loop:none
119   //
120   /// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
121   //
doitInt(int[] x)122   private static void doitInt(int[] x) {
123     for (int i = 0; i < x.length; i++) {
124       x[i] = Math.abs(x[i]);
125     }
126   }
127 
128   /// CHECK-START: void Main.doitLong(long[]) loop_optimization (before)
129   /// CHECK-DAG: Phi       loop:<<Loop:B\d+>> outer_loop:none
130   /// CHECK-DAG: ArrayGet  loop:<<Loop>>      outer_loop:none
131   /// CHECK-DAG: Abs       loop:<<Loop>>      outer_loop:none
132   /// CHECK-DAG: ArraySet  loop:<<Loop>>      outer_loop:none
133   //
134   /// CHECK-START-ARM64: void Main.doitLong(long[]) loop_optimization (after)
135   /// CHECK-DAG: VecLoad   loop:<<Loop1:B\d+>> outer_loop:none
136   /// CHECK-DAG: VecAbs    loop:<<Loop1>>      outer_loop:none
137   /// CHECK-DAG: VecStore  loop:<<Loop1>>      outer_loop:none
138   /// CHECK-DAG: ArrayGet  loop:<<Loop2:B\d+>> outer_loop:none
139   /// CHECK-DAG: Abs       loop:<<Loop2>>      outer_loop:none
140   /// CHECK-DAG: ArraySet  loop:<<Loop2>>      outer_loop:none
141   //
142   /// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
143   //
doitLong(long[] x)144   private static void doitLong(long[] x) {
145     for (int i = 0; i < x.length; i++) {
146       x[i] = Math.abs(x[i]);
147     }
148   }
149 
150   /// CHECK-START: void Main.doitFloat(float[]) loop_optimization (before)
151   /// CHECK-DAG: Phi       loop:<<Loop:B\d+>> outer_loop:none
152   /// CHECK-DAG: ArrayGet  loop:<<Loop>>      outer_loop:none
153   /// CHECK-DAG: Abs       loop:<<Loop>>      outer_loop:none
154   /// CHECK-DAG: ArraySet  loop:<<Loop>>      outer_loop:none
155   //
156   /// CHECK-START-ARM64: void Main.doitFloat(float[]) loop_optimization (after)
157   /// CHECK-DAG: VecLoad   loop:<<Loop1:B\d+>> outer_loop:none
158   /// CHECK-DAG: VecAbs    loop:<<Loop1>>      outer_loop:none
159   /// CHECK-DAG: VecStore  loop:<<Loop1>>      outer_loop:none
160   /// CHECK-DAG: ArrayGet  loop:<<Loop2:B\d+>> outer_loop:none
161   /// CHECK-DAG: Abs       loop:<<Loop2>>      outer_loop:none
162   /// CHECK-DAG: ArraySet  loop:<<Loop2>>      outer_loop:none
163   //
164   /// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
165   //
doitFloat(float[] x)166   private static void doitFloat(float[] x) {
167     for (int i = 0; i < x.length; i++) {
168       x[i] = Math.abs(x[i]);
169     }
170   }
171 
172   /// CHECK-START: void Main.doitDouble(double[]) loop_optimization (before)
173   /// CHECK-DAG: Phi        loop:<<Loop:B\d+>> outer_loop:none
174   /// CHECK-DAG: ArrayGet   loop:<<Loop>>      outer_loop:none
175   /// CHECK-DAG: Abs        loop:<<Loop>>      outer_loop:none
176   /// CHECK-DAG: ArraySet   loop:<<Loop>>      outer_loop:none
177   //
178   /// CHECK-START-ARM64: void Main.doitDouble(double[]) loop_optimization (after)
179   /// CHECK-DAG: VecLoad    loop:<<Loop1:B\d+>> outer_loop:none
180   /// CHECK-DAG: VecAbs     loop:<<Loop1>>      outer_loop:none
181   /// CHECK-DAG: VecStore   loop:<<Loop1>>      outer_loop:none
182   /// CHECK-DAG: ArrayGet   loop:<<Loop2:B\d+>> outer_loop:none
183   /// CHECK-DAG: Abs        loop:<<Loop2>>      outer_loop:none
184   /// CHECK-DAG: ArraySet   loop:<<Loop2>>      outer_loop:none
185   //
186   /// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
187   //
doitDouble(double[] x)188   private static void doitDouble(double[] x) {
189     for (int i = 0; i < x.length; i++) {
190       x[i] = Math.abs(x[i]);
191     }
192   }
193 
main(String[] args)194   public static void main(String[] args) {
195     // Bytes, chars, shorts.
196     byte[] xb = new byte[256];
197     for (int i = 0; i < 256; i++) {
198       xb[i] = (byte) i;
199     }
200     doitByte(xb);
201     for (int i = 0; i < 256; i++) {
202       expectEquals32((byte) Math.abs((byte) i), xb[i]);
203     }
204     char[] xc = new char[1024 * 64];
205     for (int i = 0; i < 1024 * 64; i++) {
206       xc[i] = (char) i;
207     }
208     doitChar(xc);
209     for (int i = 0; i < 1024 * 64; i++) {
210       expectEquals32((char) Math.abs((char) i), xc[i]);
211     }
212     short[] xs = new short[1024 * 64];
213     for (int i = 0; i < 1024 * 64; i++) {
214       xs[i] = (short) i;
215     }
216     doitShort(xs);
217     for (int i = 0; i < 1024 * 64; i++) {
218       expectEquals32((short) Math.abs((short) i), xs[i]);
219     }
220     for (int i = 0; i < 1024 * 64; i++) {
221       xc[i] = (char) i;
222     }
223     doitCastedChar(xc);
224     for (int i = 0; i < 1024 * 64; i++) {
225       expectEquals32((char) Math.abs((short) i), xc[i]);
226     }
227     // Set up minint32, maxint32 and some others.
228     int[] xi = new int[8];
229     xi[0] = 0x80000000;
230     xi[1] = 0x7fffffff;
231     xi[2] = 0x80000001;
232     xi[3] = -13;
233     xi[4] = -1;
234     xi[5] = 0;
235     xi[6] = 1;
236     xi[7] = 999;
237     doitInt(xi);
238     expectEquals32(0x80000000, xi[0]);
239     expectEquals32(0x7fffffff, xi[1]);
240     expectEquals32(0x7fffffff, xi[2]);
241     expectEquals32(13, xi[3]);
242     expectEquals32(1, xi[4]);
243     expectEquals32(0, xi[5]);
244     expectEquals32(1, xi[6]);
245     expectEquals32(999, xi[7]);
246 
247     // Set up minint64, maxint64 and some others.
248     long[] xl = new long[8];
249     xl[0] = 0x8000000000000000L;
250     xl[1] = 0x7fffffffffffffffL;
251     xl[2] = 0x8000000000000001L;
252     xl[3] = -13;
253     xl[4] = -1;
254     xl[5] = 0;
255     xl[6] = 1;
256     xl[7] = 999;
257     doitLong(xl);
258     expectEquals64(0x8000000000000000L, xl[0]);
259     expectEquals64(0x7fffffffffffffffL, xl[1]);
260     expectEquals64(0x7fffffffffffffffL, xl[2]);
261     expectEquals64(13, xl[3]);
262     expectEquals64(1, xl[4]);
263     expectEquals64(0, xl[5]);
264     expectEquals64(1, xl[6]);
265     expectEquals64(999, xl[7]);
266 
267     // Set up float NaN and some others.
268     float[] xf = new float[16];
269     xf[0] = Float.intBitsToFloat(0x7f800001);
270     xf[1] = Float.intBitsToFloat(0x7fa00000);
271     xf[2] = Float.intBitsToFloat(0x7fc00000);
272     xf[3] = Float.intBitsToFloat(0x7fffffff);
273     xf[4] = Float.intBitsToFloat(0xff800001);
274     xf[5] = Float.intBitsToFloat(0xffa00000);
275     xf[6] = Float.intBitsToFloat(0xffc00000);
276     xf[7] = Float.intBitsToFloat(0xffffffff);
277     xf[8] = Float.NEGATIVE_INFINITY;
278     xf[9] = -99.2f;
279     xf[10] = -1.0f;
280     xf[11] = -0.0f;
281     xf[12] = +0.0f;
282     xf[13] = +1.0f;
283     xf[14] = +99.2f;
284     xf[15] = Float.POSITIVE_INFINITY;
285     doitFloat(xf);
286     expectEqualsNaN32(0x7f800001, Float.floatToRawIntBits(xf[0]));
287     expectEqualsNaN32(0x7fa00000, Float.floatToRawIntBits(xf[1]));
288     expectEqualsNaN32(0x7fc00000, Float.floatToRawIntBits(xf[2]));
289     expectEqualsNaN32(0x7fffffff, Float.floatToRawIntBits(xf[3]));
290     expectEqualsNaN32(0x7f800001, Float.floatToRawIntBits(xf[4]));
291     expectEqualsNaN32(0x7fa00000, Float.floatToRawIntBits(xf[5]));
292     expectEqualsNaN32(0x7fc00000, Float.floatToRawIntBits(xf[6]));
293     expectEqualsNaN32(0x7fffffff, Float.floatToRawIntBits(xf[7]));
294     expectEquals32(
295         Float.floatToRawIntBits(Float.POSITIVE_INFINITY),
296         Float.floatToRawIntBits(xf[8]));
297     expectEquals32(
298         Float.floatToRawIntBits(99.2f),
299         Float.floatToRawIntBits(xf[9]));
300     expectEquals32(
301         Float.floatToRawIntBits(1.0f),
302         Float.floatToRawIntBits(xf[10]));
303     expectEquals32(0, Float.floatToRawIntBits(xf[11]));
304     expectEquals32(0, Float.floatToRawIntBits(xf[12]));
305     expectEquals32(
306         Float.floatToRawIntBits(1.0f),
307         Float.floatToRawIntBits(xf[13]));
308     expectEquals32(
309         Float.floatToRawIntBits(99.2f),
310         Float.floatToRawIntBits(xf[14]));
311     expectEquals32(
312         Float.floatToRawIntBits(Float.POSITIVE_INFINITY),
313         Float.floatToRawIntBits(xf[15]));
314 
315     // Set up double NaN and some others.
316     double[] xd = new double[16];
317     xd[0] = Double.longBitsToDouble(0x7ff0000000000001L);
318     xd[1] = Double.longBitsToDouble(0x7ff4000000000000L);
319     xd[2] = Double.longBitsToDouble(0x7ff8000000000000L);
320     xd[3] = Double.longBitsToDouble(0x7fffffffffffffffL);
321     xd[4] = Double.longBitsToDouble(0xfff0000000000001L);
322     xd[5] = Double.longBitsToDouble(0xfff4000000000000L);
323     xd[6] = Double.longBitsToDouble(0xfff8000000000000L);
324     xd[7] = Double.longBitsToDouble(0xffffffffffffffffL);
325     xd[8] = Double.NEGATIVE_INFINITY;
326     xd[9] = -99.2f;
327     xd[10] = -1.0f;
328     xd[11] = -0.0f;
329     xd[12] = +0.0f;
330     xd[13] = +1.0f;
331     xd[14] = +99.2f;
332     xd[15] = Double.POSITIVE_INFINITY;
333     doitDouble(xd);
334     expectEqualsNaN64(0x7ff0000000000001L, Double.doubleToRawLongBits(xd[0]));
335     expectEqualsNaN64(0x7ff4000000000000L, Double.doubleToRawLongBits(xd[1]));
336     expectEqualsNaN64(0x7ff8000000000000L, Double.doubleToRawLongBits(xd[2]));
337     expectEqualsNaN64(0x7fffffffffffffffL, Double.doubleToRawLongBits(xd[3]));
338     expectEqualsNaN64(0x7ff0000000000001L, Double.doubleToRawLongBits(xd[4]));
339     expectEqualsNaN64(0x7ff4000000000000L, Double.doubleToRawLongBits(xd[5]));
340     expectEqualsNaN64(0x7ff8000000000000L, Double.doubleToRawLongBits(xd[6]));
341     expectEqualsNaN64(0x7fffffffffffffffL, Double.doubleToRawLongBits(xd[7]));
342     expectEquals64(
343         Double.doubleToRawLongBits(Double.POSITIVE_INFINITY),
344         Double.doubleToRawLongBits(xd[8]));
345     expectEquals64(
346         Double.doubleToRawLongBits(99.2f),
347         Double.doubleToRawLongBits(xd[9]));
348     expectEquals64(
349         Double.doubleToRawLongBits(1.0f),
350         Double.doubleToRawLongBits(xd[10]));
351     expectEquals64(0, Double.doubleToRawLongBits(xd[11]));
352     expectEquals64(0, Double.doubleToRawLongBits(xd[12]));
353     expectEquals64(
354         Double.doubleToRawLongBits(1.0f),
355         Double.doubleToRawLongBits(xd[13]));
356     expectEquals64(
357         Double.doubleToRawLongBits(99.2f),
358         Double.doubleToRawLongBits(xd[14]));
359     expectEquals64(
360         Double.doubleToRawLongBits(Double.POSITIVE_INFINITY),
361         Double.doubleToRawLongBits(xd[15]));
362 
363     System.out.println("passed");
364   }
365 
expectEquals32(int expected, int result)366   private static void expectEquals32(int expected, int result) {
367     if (expected != result) {
368       throw new Error("Expected: " + expected + ", found: " + result);
369     }
370   }
371 
expectEquals64(long expected, long result)372   private static void expectEquals64(long expected, long result) {
373     if (expected != result) {
374       throw new Error("Expected: " + expected + ", found: " + result);
375     }
376   }
377 
378   // We allow that an expected NaN result has become quiet.
expectEqualsNaN32(int expected, int result)379   private static void expectEqualsNaN32(int expected, int result) {
380     if (expected != result && (expected | SPQUIET) != result) {
381       if (!isDalvik) {
382         // If not on ART, relax the expected value more towards just
383         // "spec compliance" and allow sign bit to remain set for NaN.
384         if (expected == (result & Integer.MAX_VALUE)) {
385           return;
386         }
387       }
388       throw new Error("Expected: 0x" + Integer.toHexString(expected)
389           + ", found: 0x" + Integer.toHexString(result));
390     }
391   }
392 
393   // We allow that an expected NaN result has become quiet.
expectEqualsNaN64(long expected, long result)394   private static void expectEqualsNaN64(long expected, long result) {
395     if (expected != result && (expected | DPQUIET) != result) {
396       if (!isDalvik) {
397         // If not on ART, relax the expected value more towards just
398         // "spec compliance" and allow sign bit to remain set for NaN.
399         if (expected == (result & Long.MAX_VALUE)) {
400           return;
401         }
402       }
403       throw new Error("Expected: 0x" + Long.toHexString(expected)
404           + ", found: 0x" + Long.toHexString(result));
405     }
406   }
407 }
408