1 /*
  2  * Copyright (c) 2022, 2023, Arm Limited. All rights reserved.
  3  * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
  4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  5  *
  6  * This code is free software; you can redistribute it and/or modify it
  7  * under the terms of the GNU General Public License version 2 only, as
  8  * published by the Free Software Foundation.
  9  *
 10  * This code is distributed in the hope that it will be useful, but WITHOUT
 11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 13  * version 2 for more details (a copy is included in the LICENSE file that
 14  * accompanied this code).
 15  *
 16  * You should have received a copy of the GNU General Public License version
 17  * 2 along with this work; if not, write to the Free Software Foundation,
 18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 19  *
 20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 21  * or visit www.oracle.com if you need additional information or have any
 22  * questions.
 23  */
 24 
 25 /*
 26  * @test
 27  * @summary Vectorization test on array type conversions
 28  * @library /test/lib /
 29  *
 30  * @build jdk.test.whitebox.WhiteBox
 31  *        compiler.vectorization.runner.VectorizationTestRunner
 32  *
 33  * @requires vm.compiler2.enabled
 34  *
 35  * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
 36  *
 37  * @run main/othervm -Xbootclasspath/a:.
 38  *                   -XX:+UnlockDiagnosticVMOptions
 39  *                   -XX:+WhiteBoxAPI
 40  *                   compiler.vectorization.runner.ArrayTypeConvertTest nCOH_nAV
 41  *
 42  * @run main/othervm -Xbootclasspath/a:.
 43  *                   -XX:+UnlockDiagnosticVMOptions
 44  *                   -XX:+WhiteBoxAPI
 45  *                   compiler.vectorization.runner.ArrayTypeConvertTest nCOH_yAV
 46  *
 47  * @run main/othervm -Xbootclasspath/a:.
 48  *                   -XX:+UnlockDiagnosticVMOptions
 49  *                   -XX:+WhiteBoxAPI
 50  *                   compiler.vectorization.runner.ArrayTypeConvertTest yCOH_nAV
 51  *
 52  * @run main/othervm -Xbootclasspath/a:.
 53  *                   -XX:+UnlockDiagnosticVMOptions
 54  *                   -XX:+WhiteBoxAPI
 55  *                   compiler.vectorization.runner.ArrayTypeConvertTest yCOH_yAV
 56  */
 57 
 58 package compiler.vectorization.runner;
 59 
 60 import compiler.lib.ir_framework.*;
 61 
 62 // Explanation about AlignVector: we require 8-byte alignment of all addresses.
 63 // But the array base offset changes with UseCompactObjectHeaders.
 64 // It should, however, not affect the alignment constraints.
 65 
 66 public class ArrayTypeConvertTest extends VectorizationTestRunner {
 67 
 68     // We must pass the flags directly to the test-VM, and not the driver vm in the @run above.
 69     @Override
 70     protected String[] testVMFlags(String[] args) {
 71         return switch (args[0]) {
 72             case "nCOH_nAV" -> new String[]{"-XX:+UnlockExperimentalVMOptions", "-XX:-UseCompactObjectHeaders", "-XX:-AlignVector"};
 73             case "nCOH_yAV" -> new String[]{"-XX:+UnlockExperimentalVMOptions", "-XX:-UseCompactObjectHeaders", "-XX:+AlignVector"};
 74             case "yCOH_nAV" -> new String[]{"-XX:+UnlockExperimentalVMOptions", "-XX:+UseCompactObjectHeaders", "-XX:-AlignVector"};
 75             case "yCOH_yAV" -> new String[]{"-XX:+UnlockExperimentalVMOptions", "-XX:+UseCompactObjectHeaders", "-XX:+AlignVector"};
 76             default -> { throw new RuntimeException("Test argument not recognized: " + args[0]); }
 77         };
 78     }
 79 
 80     private static final int SIZE = 543;
 81 
 82     private   byte[] bytes;
 83     private  short[] shorts;
 84     private   char[] chars;
 85     private    int[] ints;
 86     private   long[] longs;
 87     private  float[] floats;
 88     private double[] doubles;
 89 
 90     public ArrayTypeConvertTest() {
 91         bytes   = new   byte[SIZE];
 92         shorts  = new  short[SIZE];
 93         chars   = new   char[SIZE];
 94         ints    = new    int[SIZE];
 95         longs   = new   long[SIZE];
 96         floats  = new  float[SIZE];
 97         doubles = new double[SIZE];
 98         for (int i = 0; i < SIZE; i++) {
 99             bytes[i]   = (byte)  (-i / 128);
100             shorts[i]  = (short) (i / 3 - 12345);
101             chars[i]   = (char)  (i * 2);
102             ints[i]    = -22 * i;
103             longs[i]   = -258L * i + 99L;
104             floats[i]  = (float) (i * 2.498f);
105             doubles[i] = -3 * i;
106         }
107     }
108 
109     // ---------------- Integer Extension ----------------
110     @Test
111     @IR(failOn = {IRNode.STORE_VECTOR})
112     // Subword vector casts do not work currently, see JDK-8342095.
113     // Assert the vectorization failure so that we are reminded to update
114     // the test when this limitation is addressed in the future.
115     public int[] signExtension() {
116         int[] res = new int[SIZE];
117         for (int i = 0; i < SIZE; i++) {
118             res[i] = shorts[i];
119         }
120         return res;
121     }
122 
123     @Test
124     @IR(failOn = {IRNode.STORE_VECTOR})
125     // Subword vector casts do not work currently, see JDK-8342095.
126     // Assert the vectorization failure so that we are reminded to update
127     // the test when this limitation is addressed in the future.
128     public int[] zeroExtension() {
129         int[] res = new int[SIZE];
130         for (int i = 0; i < SIZE; i++) {
131             res[i] = chars[i];
132         }
133         return res;
134     }
135 
136     @Test
137     @IR(failOn = {IRNode.STORE_VECTOR})
138     // Subword vector casts do not work currently, see JDK-8342095.
139     // Assert the vectorization failure so that we are reminded to update
140     // the test when this limitation is addressed in the future.
141     public int[] signExtensionFromByte() {
142         int[] res = new int[SIZE];
143         for (int i = 0; i < SIZE; i++) {
144             res[i] = bytes[i];
145         }
146         return res;
147     }
148 
149     // ---------------- Integer Narrow ----------------
150     @Test
151     @IR(failOn = {IRNode.STORE_VECTOR})
152     // Subword vector casts do not work currently, see JDK-8342095.
153     // Assert the vectorization failure so that we are reminded to update
154     // the test when this limitation is addressed in the future.
155     public short[] narrowToSigned() {
156         short[] res = new short[SIZE];
157         for (int i = 0; i < SIZE; i++) {
158             res[i] = (short) ints[i];
159         }
160         return res;
161     }
162 
163     @Test
164     @IR(failOn = {IRNode.STORE_VECTOR})
165     // Subword vector casts do not work currently, see JDK-8342095.
166     // Assert the vectorization failure so that we are reminded to update
167     // the test when this limitation is addressed in the future.
168     public char[] narrowToUnsigned() {
169         char[] res = new char[SIZE];
170         for (int i = 0; i < SIZE; i++) {
171             res[i] = (char) ints[i];
172         }
173         return res;
174     }
175 
176     @Test
177     @IR(failOn = {IRNode.STORE_VECTOR})
178     // Subword vector casts do not work currently, see JDK-8342095.
179     // Assert the vectorization failure so that we are reminded to update
180     // the test when this limitation is addressed in the future.
181     public byte[] NarrowToByte() {
182         byte[] res = new byte[SIZE];
183         for (int i = 0; i < SIZE; i++) {
184             res[i] = (byte) ints[i];
185         }
186         return res;
187     }
188 
189     // ---------------- Convert I/L to F/D ----------------
190     @Test
191     @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx", "true", "rvv", "true"},
192         counts = {IRNode.VECTOR_CAST_I2F, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0"})
193     public float[] convertIntToFloat() {
194         float[] res = new float[SIZE];
195         for (int i = 0; i < SIZE; i++) {
196             res[i] = (float) ints[i];
197         }
198         return res;
199     }
200 
201     @Test
202     @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx", "true", "rvv", "true"},
203         counts = {IRNode.VECTOR_CAST_I2D, IRNode.VECTOR_SIZE + "min(max_int, max_double)", ">0"})
204     public double[] convertIntToDouble() {
205         double[] res = new double[SIZE];
206         for (int i = 0; i < SIZE; i++) {
207             res[i] = (double) ints[i];
208         }
209         return res;
210     }
211 
212     @Test
213     @IR(applyIfCPUFeatureOr = {"sve", "true", "avx512dq", "true", "rvv", "true"},
214         counts = {IRNode.VECTOR_CAST_L2F, IRNode.VECTOR_SIZE + "min(max_long, max_float)", ">0"})
215     public float[] convertLongToFloat() {
216         float[] res = new float[SIZE];
217         for (int i = 0; i < SIZE; i++) {
218             res[i] = (float) longs[i];
219         }
220         return res;
221     }
222 
223     @Test
224     @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx512dq", "true", "rvv", "true"},
225         counts = {IRNode.VECTOR_CAST_L2D, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0"})
226     public double[] convertLongToDouble() {
227         double[] res = new double[SIZE];
228         for (int i = 0; i < SIZE; i++) {
229             res[i] = (double) longs[i];
230         }
231         return res;
232     }
233 
234     // ---------------- Convert Subword-I to F/D ----------------
235     @Test
236     @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx2", "true", "rvv", "true"},
237         counts = {IRNode.VECTOR_CAST_S2F, IRNode.VECTOR_SIZE + "min(max_short, max_float)", ">0"})
238     public float[] convertShortToFloat() {
239         float[] res = new float[SIZE];
240         for (int i = 0; i < SIZE; i++) {
241             res[i] = (float) shorts[i];
242         }
243         return res;
244     }
245 
246     @Test
247     @IR(applyIfCPUFeatureOr = {"sve", "true", "avx2", "true", "rvv", "true"},
248         applyIf = {"MaxVectorSize", ">=32"},
249         counts = {IRNode.VECTOR_CAST_S2D, IRNode.VECTOR_SIZE + "min(max_short, max_double)", ">0"})
250     public double[] convertShortToDouble() {
251         double[] res = new double[SIZE];
252         for (int i = 0; i < SIZE; i++) {
253             res[i] = (double) shorts[i];
254         }
255         return res;
256     }
257 
258     @Test
259     @IR(failOn = {IRNode.STORE_VECTOR})
260     // Subword vector casts do not work currently, see JDK-8342095.
261     // Assert the vectorization failure so that we are reminded to update
262     // the test when this limitation is addressed in the future.
263     public float[] convertCharToFloat() {
264         float[] res = new float[SIZE];
265         for (int i = 0; i < SIZE; i++) {
266             res[i] = (float) chars[i];
267         }
268         return res;
269     }
270 
271     @Test
272     @IR(failOn = {IRNode.STORE_VECTOR})
273     // Subword vector casts do not work currently, see JDK-8342095.
274     // Assert the vectorization failure so that we are reminded to update
275     // the test when this limitation is addressed in the future.
276     public double[] convertCharToDouble() {
277         double[] res = new double[SIZE];
278         for (int i = 0; i < SIZE; i++) {
279             res[i] = (double) chars[i];
280         }
281         return res;
282     }
283 
284     // ---------------- Convert F/D to I/L ----------------
285     @Test
286     @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx", "true", "rvv", "true"},
287         counts = {IRNode.VECTOR_CAST_F2I, IRNode.VECTOR_SIZE + "min(max_float, max_int)", ">0"})
288     public int[] convertFloatToInt() {
289         int[] res = new int[SIZE];
290         for (int i = 0; i < SIZE; i++) {
291             res[i] = (int) floats[i];
292         }
293         return res;
294     }
295 
296     @Test
297     @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx512dq", "true", "rvv", "true"},
298         counts = {IRNode.VECTOR_CAST_F2L, IRNode.VECTOR_SIZE + "min(max_float, max_long)", ">0"})
299     public long[] convertFloatToLong() {
300         long[] res = new long[SIZE];
301         for (int i = 0; i < SIZE; i++) {
302             res[i] = (long) floats[i];
303         }
304         return res;
305     }
306 
307     @Test
308     @IR(applyIfCPUFeatureOr = {"sve", "true", "avx", "true", "rvv", "true"},
309         counts = {IRNode.VECTOR_CAST_D2I, IRNode.VECTOR_SIZE + "min(max_double, max_int)", ">0"})
310     public int[] convertDoubleToInt() {
311         int[] res = new int[SIZE];
312         for (int i = 0; i < SIZE; i++) {
313             res[i] = (int) doubles[i];
314         }
315         return res;
316     }
317 
318     @Test
319     @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx512dq", "true", "rvv", "true"},
320         counts = {IRNode.VECTOR_CAST_D2L, IRNode.VECTOR_SIZE + "min(max_double, max_long)", ">0"})
321     public long[] convertDoubleToLong() {
322         long[] res = new long[SIZE];
323         for (int i = 0; i < SIZE; i++) {
324             res[i] = (long) doubles[i];
325         }
326         return res;
327     }
328 
329     // ---------------- Convert F/D to Subword-I ----------------
330     @Test
331     @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx2", "true", "rvv", "true"},
332         counts = {IRNode.VECTOR_CAST_F2S, IRNode.VECTOR_SIZE + "min(max_float, max_short)", ">0"})
333     public short[] convertFloatToShort() {
334         short[] res = new short[SIZE];
335         for (int i = 0; i < SIZE; i++) {
336             res[i] = (short) floats[i];
337         }
338         return res;
339     }
340 
341     @Test
342     @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx2", "true", "rvv", "true"},
343         counts = {IRNode.VECTOR_CAST_F2S, IRNode.VECTOR_SIZE + "min(max_float, max_char)", ">0"})
344     public char[] convertFloatToChar() {
345         char[] res = new char[SIZE];
346         for (int i = 0; i < SIZE; i++) {
347             res[i] = (char) floats[i];
348         }
349         return res;
350     }
351 
352     @Test
353     @IR(applyIfCPUFeatureOr = {"sve", "true", "avx", "true", "rvv", "true"},
354         applyIf = {"MaxVectorSize", ">=32"},
355         counts = {IRNode.VECTOR_CAST_D2S, IRNode.VECTOR_SIZE + "min(max_double, max_short)", ">0"})
356     public short[] convertDoubleToShort() {
357         short[] res = new short[SIZE];
358         for (int i = 0; i < SIZE; i++) {
359             res[i] = (short) doubles[i];
360         }
361         return res;
362     }
363 
364     @Test
365     @IR(applyIfCPUFeatureOr = {"sve", "true", "avx", "true", "rvv", "true"},
366         applyIf = {"MaxVectorSize", ">=32"},
367         counts = {IRNode.VECTOR_CAST_D2S, IRNode.VECTOR_SIZE + "min(max_double, max_char)", ">0"})
368     public char[] convertDoubleToChar() {
369         char[] res = new char[SIZE];
370         for (int i = 0; i < SIZE; i++) {
371             res[i] = (char) doubles[i];
372         }
373         return res;
374     }
375 
376     // ---------------- Convert Between F & D ----------------
377     @Test
378     @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx", "true", "rvv", "true"},
379         counts = {IRNode.VECTOR_CAST_F2D, IRNode.VECTOR_SIZE + "min(max_float, max_double)", ">0"})
380     public double[] convertFloatToDouble() {
381         double[] res = new double[SIZE];
382         for (int i = 0; i < SIZE; i++) {
383             res[i] = (double) floats[i];
384         }
385         return res;
386     }
387 
388     @Test
389     @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx", "true", "rvv", "true"},
390         counts = {IRNode.VECTOR_CAST_D2F, IRNode.VECTOR_SIZE + "min(max_double, max_float)", ">0"})
391     public float[] convertDoubleToFloat() {
392         float[] res = new float[SIZE];
393         for (int i = 0; i < SIZE; i++) {
394             res[i] = (float) doubles[i];
395         }
396         return res;
397     }
398 }