1 /*
2 * Copyright (c) 2022, 2023, Arm Limited. All rights reserved.
3 * Copyright (c) 2024, 2025, 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:-UseCompactObjectHeaders", "-XX:-AlignVector"};
73 case "nCOH_yAV" -> new String[]{"-XX:-UseCompactObjectHeaders", "-XX:+AlignVector"};
74 case "yCOH_nAV" -> new String[]{"-XX:+UseCompactObjectHeaders", "-XX:-AlignVector"};
75 case "yCOH_yAV" -> new String[]{"-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(applyIfCPUFeature = {"rvv", "true"},
248 applyIf = {"MaxVectorSize", ">=32"},
249 counts = {IRNode.VECTOR_CAST_S2D, IRNode.VECTOR_SIZE + "min(max_short, max_double)", ">0"})
250 @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx", "true"},
251 applyIf = {"MaxVectorSize", ">=16"},
252 counts = {IRNode.VECTOR_CAST_S2D, IRNode.VECTOR_SIZE + "min(max_short, max_double)", ">0"})
253 public double[] convertShortToDouble() {
254 double[] res = new double[SIZE];
255 for (int i = 0; i < SIZE; i++) {
256 res[i] = (double) shorts[i];
257 }
258 return res;
259 }
260
261 @Test
262 @IR(failOn = {IRNode.STORE_VECTOR})
263 // Subword vector casts do not work currently, see JDK-8342095.
264 // Assert the vectorization failure so that we are reminded to update
265 // the test when this limitation is addressed in the future.
266 public float[] convertCharToFloat() {
267 float[] res = new float[SIZE];
268 for (int i = 0; i < SIZE; i++) {
269 res[i] = (float) chars[i];
270 }
271 return res;
272 }
273
274 @Test
275 @IR(failOn = {IRNode.STORE_VECTOR})
276 // Subword vector casts do not work currently, see JDK-8342095.
277 // Assert the vectorization failure so that we are reminded to update
278 // the test when this limitation is addressed in the future.
279 public double[] convertCharToDouble() {
280 double[] res = new double[SIZE];
281 for (int i = 0; i < SIZE; i++) {
282 res[i] = (double) chars[i];
283 }
284 return res;
285 }
286
287 // ---------------- Convert F/D to I/L ----------------
288 @Test
289 @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx", "true", "avx10_2", "true", "rvv", "true"},
290 counts = {IRNode.VECTOR_CAST_F2I, IRNode.VECTOR_SIZE + "min(max_float, max_int)", "> 0"})
291 @IR(counts = {IRNode.X86_VCAST_F2X, "> 0"},
292 applyIfCPUFeatureAnd = {"avx", "true", "avx10_2", "false"})
293 @IR(counts = {IRNode.X86_VCAST_F2X_AVX10, "> 0"},
294 applyIfCPUFeature = {"avx10_2", "true"})
295 public int[] convertFloatToInt() {
296 int[] res = new int[SIZE];
297 for (int i = 0; i < SIZE; i++) {
298 res[i] = (int) floats[i];
299 }
300 return res;
301 }
302
303 @Test
304 @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx512dq", "true", "avx10_2", "true", "rvv", "true"},
305 counts = {IRNode.VECTOR_CAST_F2L, IRNode.VECTOR_SIZE + "min(max_float, max_long)", "> 0"})
306 @IR(counts = {IRNode.X86_VCAST_F2X, "> 0"},
307 applyIfCPUFeatureAnd = {"avx512dq", "true", "avx10_2", "false"})
308 @IR(counts = {IRNode.X86_VCAST_F2X_AVX10, "> 0"},
309 applyIfCPUFeature = {"avx10_2", "true"})
310 public long[] convertFloatToLong() {
311 long[] res = new long[SIZE];
312 for (int i = 0; i < SIZE; i++) {
313 res[i] = (long) floats[i];
314 }
315 return res;
316 }
317
318 @Test
319 @IR(applyIfCPUFeatureOr = {"sve", "true", "avx", "true", "avx10_2", "true", "rvv", "true"},
320 counts = {IRNode.VECTOR_CAST_D2I, IRNode.VECTOR_SIZE + "min(max_double, max_int)", "> 0"})
321 @IR(counts = {IRNode.X86_VCAST_D2X, "> 0"},
322 applyIfCPUFeatureAnd = {"avx", "true", "avx10_2", "false"})
323 @IR(counts = {IRNode.X86_VCAST_D2X_AVX10, "> 0"},
324 applyIfCPUFeature = {"avx10_2", "true"})
325 public int[] convertDoubleToInt() {
326 int[] res = new int[SIZE];
327 for (int i = 0; i < SIZE; i++) {
328 res[i] = (int) doubles[i];
329 }
330 return res;
331 }
332
333 @Test
334 @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx512dq", "true", "avx10_2", "true", "rvv", "true"},
335 counts = {IRNode.VECTOR_CAST_D2L, IRNode.VECTOR_SIZE + "min(max_double, max_long)", "> 0"})
336 @IR(counts = {IRNode.X86_VCAST_D2X, "> 0"},
337 applyIfCPUFeatureAnd = {"avx512dq", "true", "avx10_2", "false"})
338 @IR(counts = {IRNode.X86_VCAST_D2X_AVX10, "> 0"},
339 applyIfCPUFeature = {"avx10_2", "true"})
340 public long[] convertDoubleToLong() {
341 long[] res = new long[SIZE];
342 for (int i = 0; i < SIZE; i++) {
343 res[i] = (long) doubles[i];
344 }
345 return res;
346 }
347
348 // ---------------- Convert F/D to Subword-I ----------------
349 @Test
350 @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx2", "true", "avx10_2", "true", "rvv", "true"},
351 applyIf = {"AlignVector", "false"},
352 counts = {IRNode.VECTOR_CAST_F2S, IRNode.VECTOR_SIZE + "min(max_float, max_short)", "> 0"})
353 @IR(counts = {IRNode.X86_VCAST_F2X, "> 0"},
354 applyIf = {"AlignVector", "false"},
355 applyIfCPUFeatureAnd = {"avx2", "true", "avx10_2", "false"})
356 @IR(counts = {IRNode.X86_VCAST_F2X_AVX10, "> 0"},
357 applyIf = {"AlignVector", "false"},
358 applyIfCPUFeature = {"avx10_2", "true"})
359 public short[] convertFloatToShort() {
360 short[] res = new short[SIZE];
361 for (int i = 0; i < SIZE; i++) {
362 res[i] = (short) floats[i];
363 }
364 return res;
365 }
366
367 @Test
368 @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx2", "true", "avx10_2", "true", "rvv", "true"},
369 applyIf = {"AlignVector", "false"},
370 counts = {IRNode.VECTOR_CAST_F2S, IRNode.VECTOR_SIZE + "min(max_float, max_char)", "> 0"})
371 @IR(counts = {IRNode.X86_VCAST_F2X, "> 0"},
372 applyIf = {"AlignVector", "false"},
373 applyIfCPUFeatureAnd = {"avx2", "true", "avx10_2", "false"})
374 @IR(counts = {IRNode.X86_VCAST_F2X_AVX10, "> 0"},
375 applyIf = {"AlignVector", "false"},
376 applyIfCPUFeature = {"avx10_2", "true"})
377 public char[] convertFloatToChar() {
378 char[] res = new char[SIZE];
379 for (int i = 0; i < SIZE; i++) {
380 res[i] = (char) floats[i];
381 }
382 return res;
383 }
384
385 @Test
386 @IR(applyIfCPUFeature = {"rvv", "true"},
387 applyIf = {"MaxVectorSize", ">=32"},
388 counts = {IRNode.VECTOR_CAST_D2S, IRNode.VECTOR_SIZE + "min(max_double, max_short)", "> 0"})
389 @IR(applyIfCPUFeatureOr = {"sve", "true", "avx", "true", "avx10_2", "true"},
390 applyIf = {"MaxVectorSize", ">=16"},
391 counts = {IRNode.VECTOR_CAST_D2S, IRNode.VECTOR_SIZE + "min(max_double, max_short)", "> 0"})
392 @IR(counts = {IRNode.X86_VCAST_D2X, "> 0"},
393 applyIf = {"MaxVectorSize", ">=16"},
394 applyIfCPUFeatureAnd = {"avx", "true", "avx10_2", "false"})
395 @IR(counts = {IRNode.X86_VCAST_D2X_AVX10, "> 0"},
396 applyIf = {"MaxVectorSize", ">=16"},
397 applyIfCPUFeature = {"avx10_2", "true"})
398 public short[] convertDoubleToShort() {
399 short[] res = new short[SIZE];
400 for (int i = 0; i < SIZE; i++) {
401 res[i] = (short) doubles[i];
402 }
403 return res;
404 }
405
406 @Test
407 @IR(applyIfCPUFeature = {"rvv", "true"},
408 applyIf = {"MaxVectorSize", ">= 32"},
409 counts = {IRNode.VECTOR_CAST_D2S, IRNode.VECTOR_SIZE + "min(max_double, max_char)", "> 0"})
410 @IR(applyIfCPUFeatureOr = {"sve", "true", "avx", "true", "avx10_2", "true"},
411 applyIf = {"MaxVectorSize", ">= 16"},
412 counts = {IRNode.VECTOR_CAST_D2S, IRNode.VECTOR_SIZE + "min(max_double, max_char)", "> 0"})
413 @IR(counts = {IRNode.X86_VCAST_D2X, "> 0"},
414 applyIf = {"MaxVectorSize", ">=16"},
415 applyIfCPUFeatureAnd = {"avx", "true", "avx10_2", "false"})
416 @IR(counts = {IRNode.X86_VCAST_D2X_AVX10, "> 0"},
417 applyIf = {"MaxVectorSize", ">=16"},
418 applyIfCPUFeature = {"avx10_2", "true"})
419 public char[] convertDoubleToChar() {
420 char[] res = new char[SIZE];
421 for (int i = 0; i < SIZE; i++) {
422 res[i] = (char) doubles[i];
423 }
424 return res;
425 }
426
427 // ---------------- Convert Between F & D ----------------
428 @Test
429 @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx", "true", "rvv", "true"},
430 counts = {IRNode.VECTOR_CAST_F2D, IRNode.VECTOR_SIZE + "min(max_float, max_double)", ">0"})
431 public double[] convertFloatToDouble() {
432 double[] res = new double[SIZE];
433 for (int i = 0; i < SIZE; i++) {
434 res[i] = (double) floats[i];
435 }
436 return res;
437 }
438
439 @Test
440 @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx", "true", "rvv", "true"},
441 counts = {IRNode.VECTOR_CAST_D2F, IRNode.VECTOR_SIZE + "min(max_double, max_float)", ">0"})
442 public float[] convertDoubleToFloat() {
443 float[] res = new float[SIZE];
444 for (int i = 0; i < SIZE; i++) {
445 res[i] = (float) doubles[i];
446 }
447 return res;
448 }
449 }