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 // This means it affects 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         applyIfOr = {"AlignVector", "false", "UseCompactObjectHeaders", "false"},
238         counts = {IRNode.VECTOR_CAST_S2F, IRNode.VECTOR_SIZE + "min(max_short, max_float)", ">0"})
239     public float[] convertShortToFloat() {
240         float[] res = new float[SIZE];
241         for (int i = 0; i < SIZE; i++) {
242             res[i] = (float) shorts[i];
243             // AlignVector=true requires that all vector load/store are 8-byte aligned.
244             // F_adr = base + UNSAFE.ARRAY_FLOAT_BASE_OFFSET + 4*i
245             //                = 16 (UseCompactObjectHeaders=false)    -> i % 2 = 0
246             //                = 12 (UseCompactObjectHeaders=true )    -> i % 2 = 1
247             // S_adr = base + UNSAFE.ARRAY_SHORT_BASE_OFFSET + 2*i
248             //                = 16 (UseCompactObjectHeaders=false)    -> i % 4 = 0  -> can align both
249             //                = 12 (UseCompactObjectHeaders=true )    -> i % 4 = 2  -> cannot align both
250         }
251         return res;
252     }
253 
254     @Test
255     @IR(applyIfCPUFeatureOr = {"sve", "true", "avx2", "true", "rvv", "true"},
256         applyIf = {"MaxVectorSize", ">=32"},
257         counts = {IRNode.VECTOR_CAST_S2D, IRNode.VECTOR_SIZE + "min(max_short, max_double)", ">0"})
258     public double[] convertShortToDouble() {
259         double[] res = new double[SIZE];
260         for (int i = 0; i < SIZE; i++) {
261             res[i] = (double) shorts[i];
262         }
263         return res;
264     }
265 
266     @Test
267     @IR(failOn = {IRNode.STORE_VECTOR})
268     // Subword vector casts do not work currently, see JDK-8342095.
269     // Assert the vectorization failure so that we are reminded to update
270     // the test when this limitation is addressed in the future.
271     public float[] convertCharToFloat() {
272         float[] res = new float[SIZE];
273         for (int i = 0; i < SIZE; i++) {
274             res[i] = (float) chars[i];
275         }
276         return res;
277     }
278 
279     @Test
280     @IR(failOn = {IRNode.STORE_VECTOR})
281     // Subword vector casts do not work currently, see JDK-8342095.
282     // Assert the vectorization failure so that we are reminded to update
283     // the test when this limitation is addressed in the future.
284     public double[] convertCharToDouble() {
285         double[] res = new double[SIZE];
286         for (int i = 0; i < SIZE; i++) {
287             res[i] = (double) chars[i];
288         }
289         return res;
290     }
291 
292     // ---------------- Convert F/D to I/L ----------------
293     @Test
294     @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx", "true", "rvv", "true"},
295         counts = {IRNode.VECTOR_CAST_F2I, IRNode.VECTOR_SIZE + "min(max_float, max_int)", ">0"})
296     public int[] convertFloatToInt() {
297         int[] res = new int[SIZE];
298         for (int i = 0; i < SIZE; i++) {
299             res[i] = (int) floats[i];
300         }
301         return res;
302     }
303 
304     @Test
305     @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx512dq", "true", "rvv", "true"},
306         counts = {IRNode.VECTOR_CAST_F2L, IRNode.VECTOR_SIZE + "min(max_float, max_long)", ">0"})
307     public long[] convertFloatToLong() {
308         long[] res = new long[SIZE];
309         for (int i = 0; i < SIZE; i++) {
310             res[i] = (long) floats[i];
311         }
312         return res;
313     }
314 
315     @Test
316     @IR(applyIfCPUFeatureOr = {"sve", "true", "avx", "true", "rvv", "true"},
317         counts = {IRNode.VECTOR_CAST_D2I, IRNode.VECTOR_SIZE + "min(max_double, max_int)", ">0"})
318     public int[] convertDoubleToInt() {
319         int[] res = new int[SIZE];
320         for (int i = 0; i < SIZE; i++) {
321             res[i] = (int) doubles[i];
322         }
323         return res;
324     }
325 
326     @Test
327     @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx512dq", "true", "rvv", "true"},
328         counts = {IRNode.VECTOR_CAST_D2L, IRNode.VECTOR_SIZE + "min(max_double, max_long)", ">0"})
329     public long[] convertDoubleToLong() {
330         long[] res = new long[SIZE];
331         for (int i = 0; i < SIZE; i++) {
332             res[i] = (long) doubles[i];
333         }
334         return res;
335     }
336 
337     // ---------------- Convert F/D to Subword-I ----------------
338     @Test
339     @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx2", "true", "rvv", "true"},
340         applyIfOr = {"AlignVector", "false", "UseCompactObjectHeaders", "false"},
341         counts = {IRNode.VECTOR_CAST_F2S, IRNode.VECTOR_SIZE + "min(max_float, max_short)", ">0"})
342     public short[] convertFloatToShort() {
343         short[] res = new short[SIZE];
344         for (int i = 0; i < SIZE; i++) {
345             res[i] = (short) floats[i];
346             // AlignVector=true requires that all vector load/store are 8-byte aligned.
347             // F_adr = base + UNSAFE.ARRAY_FLOAT_BASE_OFFSET + 4*i
348             //                = 16 (UseCompactObjectHeaders=false)    -> i % 2 = 0
349             //                = 12 (UseCompactObjectHeaders=true )    -> i % 2 = 1
350             // S_adr = base + UNSAFE.ARRAY_SHORT_BASE_OFFSET + 2*i
351             //                = 16 (UseCompactObjectHeaders=false)    -> i % 4 = 0  -> can align both
352             //                = 12 (UseCompactObjectHeaders=true )    -> i % 4 = 2  -> cannot align both
353         }
354         return res;
355     }
356 
357     @Test
358     @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx2", "true", "rvv", "true"},
359         applyIfOr = {"AlignVector", "false", "UseCompactObjectHeaders", "false"},
360         counts = {IRNode.VECTOR_CAST_F2S, IRNode.VECTOR_SIZE + "min(max_float, max_char)", ">0"})
361     public char[] convertFloatToChar() {
362         char[] res = new char[SIZE];
363         for (int i = 0; i < SIZE; i++) {
364             res[i] = (char) floats[i];
365             // AlignVector=true requires that all vector load/store are 8-byte aligned.
366             // F_adr = base + UNSAFE.ARRAY_FLOAT_BASE_OFFSET + 4*i
367             //                = 16 (UseCompactObjectHeaders=false)    -> i % 2 = 0
368             //                = 12 (UseCompactObjectHeaders=true )    -> i % 2 = 1
369             // S_adr = base + UNSAFE.ARRAY_SHORT_BASE_OFFSET + 2*i
370             //                = 16 (UseCompactObjectHeaders=false)    -> i % 4 = 0  -> can align both
371             //                = 12 (UseCompactObjectHeaders=true )    -> i % 4 = 2  -> cannot align both
372         }
373         return res;
374     }
375 
376     @Test
377     @IR(applyIfCPUFeatureOr = {"sve", "true", "avx", "true", "rvv", "true"},
378         applyIf = {"MaxVectorSize", ">=32"},
379         counts = {IRNode.VECTOR_CAST_D2S, IRNode.VECTOR_SIZE + "min(max_double, max_short)", ">0"})
380     public short[] convertDoubleToShort() {
381         short[] res = new short[SIZE];
382         for (int i = 0; i < SIZE; i++) {
383             res[i] = (short) doubles[i];
384         }
385         return res;
386     }
387 
388     @Test
389     @IR(applyIfCPUFeatureOr = {"sve", "true", "avx", "true", "rvv", "true"},
390         applyIf = {"MaxVectorSize", ">=32"},
391         counts = {IRNode.VECTOR_CAST_D2S, IRNode.VECTOR_SIZE + "min(max_double, max_char)", ">0"})
392     public char[] convertDoubleToChar() {
393         char[] res = new char[SIZE];
394         for (int i = 0; i < SIZE; i++) {
395             res[i] = (char) doubles[i];
396         }
397         return res;
398     }
399 
400     // ---------------- Convert Between F & D ----------------
401     @Test
402     @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx", "true", "rvv", "true"},
403         counts = {IRNode.VECTOR_CAST_F2D, IRNode.VECTOR_SIZE + "min(max_float, max_double)", ">0"})
404     public double[] convertFloatToDouble() {
405         double[] res = new double[SIZE];
406         for (int i = 0; i < SIZE; i++) {
407             res[i] = (double) floats[i];
408         }
409         return res;
410     }
411 
412     @Test
413     @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx", "true", "rvv", "true"},
414         counts = {IRNode.VECTOR_CAST_D2F, IRNode.VECTOR_SIZE + "min(max_double, max_float)", ">0"})
415     public float[] convertDoubleToFloat() {
416         float[] res = new float[SIZE];
417         for (int i = 0; i < SIZE; i++) {
418             res[i] = (float) doubles[i];
419         }
420         return res;
421     }
422 }