1 /*
2 * Copyright (c) 2022, 2023, Arm Limited. All rights reserved.
3 * Copyright (c) 2024, 2026, 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 * @bug 8183390 8340010 8342095
28 * @summary Vectorization test on array type conversions
29 * @library /test/lib /
30 *
31 * @build jdk.test.whitebox.WhiteBox
32 * compiler.vectorization.runner.VectorizationTestRunner
33 *
34 * @requires vm.compiler2.enabled
35 *
36 * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
37 *
38 * @run main/othervm -Xbootclasspath/a:.
39 * -XX:+UnlockDiagnosticVMOptions
40 * -XX:+WhiteBoxAPI
41 * compiler.vectorization.runner.ArrayTypeConvertTest nCOH_nAV
42 *
43 * @run main/othervm -Xbootclasspath/a:.
44 * -XX:+UnlockDiagnosticVMOptions
45 * -XX:+WhiteBoxAPI
46 * compiler.vectorization.runner.ArrayTypeConvertTest nCOH_yAV
47 *
48 * @run main/othervm -Xbootclasspath/a:.
49 * -XX:+UnlockDiagnosticVMOptions
50 * -XX:+WhiteBoxAPI
51 * compiler.vectorization.runner.ArrayTypeConvertTest yCOH_nAV
52 *
53 * @run main/othervm -Xbootclasspath/a:.
54 * -XX:+UnlockDiagnosticVMOptions
55 * -XX:+WhiteBoxAPI
56 * compiler.vectorization.runner.ArrayTypeConvertTest yCOH_yAV
57 */
58
59 package compiler.vectorization.runner;
60
61 import compiler.lib.ir_framework.*;
62
63 // Explanation about AlignVector: we require 8-byte alignment of all addresses.
64 // But the array base offset changes with UseCompactObjectHeaders.
65 // It should, however, not affect the alignment constraints.
66
67 public class ArrayTypeConvertTest extends VectorizationTestRunner {
68
69 // We must pass the flags directly to the test-VM, and not the driver vm in the @run above.
70 @Override
71 protected String[] testVMFlags(String[] args) {
72 return switch (args[0]) {
73 case "nCOH_nAV" -> new String[]{"-XX:-UseCompactObjectHeaders", "-XX:-AlignVector"};
74 case "nCOH_yAV" -> new String[]{"-XX:-UseCompactObjectHeaders", "-XX:+AlignVector"};
75 case "yCOH_nAV" -> new String[]{"-XX:+UseCompactObjectHeaders", "-XX:-AlignVector"};
76 case "yCOH_yAV" -> new String[]{"-XX:+UseCompactObjectHeaders", "-XX:+AlignVector"};
77 default -> { throw new RuntimeException("Test argument not recognized: " + args[0]); }
78 };
79 }
80
81 private static final int SIZE = 543;
82
83 private byte[] bytes;
84 private short[] shorts;
85 private char[] chars;
86 private int[] ints;
87 private long[] longs;
88 private float[] floats;
89 private double[] doubles;
90
91 public ArrayTypeConvertTest() {
92 bytes = new byte[SIZE];
93 shorts = new short[SIZE];
94 chars = new char[SIZE];
95 ints = new int[SIZE];
96 longs = new long[SIZE];
97 floats = new float[SIZE];
98 doubles = new double[SIZE];
99 for (int i = 0; i < SIZE; i++) {
100 bytes[i] = (byte) (-i / 128);
101 shorts[i] = (short) (i / 3 - 12345);
102 chars[i] = (char) (i * 2);
103 ints[i] = -22 * i;
104 longs[i] = -258L * i + 99L;
105 floats[i] = (float) (i * 2.498f);
106 doubles[i] = -3 * i;
107 }
108 }
109
110 // ---------------- Integer Extension ----------------
111 @Test
112 @IR(applyIfCPUFeature = { "avx", "true" },
113 applyIfOr = {"AlignVector", "false", "UseCompactObjectHeaders", "false"},
114 counts = { IRNode.VECTOR_CAST_S2I, IRNode.VECTOR_SIZE + "min(max_int, max_short)", ">0" })
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 with char do not work currently, see JDK-8349562.
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(applyIfCPUFeature = { "avx", "true" },
138 applyIfOr = {"AlignVector", "false", "UseCompactObjectHeaders", "false"},
139 counts = { IRNode.VECTOR_CAST_B2I, IRNode.VECTOR_SIZE + "min(max_int, max_byte)", ">0" })
140 public int[] signExtensionFromByte() {
141 int[] res = new int[SIZE];
142 for (int i = 0; i < SIZE; i++) {
143 res[i] = bytes[i];
144 }
145 return res;
146 }
147
148 @Test
149 @IR(applyIfCPUFeature = { "avx", "true" },
150 applyIfOr = {"AlignVector", "false", "UseCompactObjectHeaders", "false"},
151 counts = { IRNode.VECTOR_CAST_B2S, IRNode.VECTOR_SIZE + "min(max_short, max_byte)", ">0" })
152 public short[] signExtensionFromByteToShort() {
153 short[] res = new short[SIZE];
154 for (int i = 0; i < SIZE; i++) {
155 res[i] = bytes[i];
156 }
157 return res;
158 }
159
160 // ---------------- Integer Narrow ----------------
161 @Test
162 @IR(applyIfCPUFeature = { "avx", "true" },
163 applyIfOr = {"AlignVector", "false", "UseCompactObjectHeaders", "false"},
164 counts = { IRNode.VECTOR_CAST_I2S, IRNode.VECTOR_SIZE + "min(max_int, max_short)", ">0" })
165 public short[] narrowToSigned() {
166 short[] res = new short[SIZE];
167 for (int i = 0; i < SIZE; i++) {
168 res[i] = (short) ints[i];
169 }
170 return res;
171 }
172
173 @Test
174 @IR(applyIfCPUFeature = { "avx", "true" },
175 applyIfOr = {"AlignVector", "false", "UseCompactObjectHeaders", "false"},
176 counts = { IRNode.VECTOR_CAST_I2S, IRNode.VECTOR_SIZE + "min(max_int, max_char)", ">0" })
177 public char[] narrowToUnsigned() {
178 char[] res = new char[SIZE];
179 for (int i = 0; i < SIZE; i++) {
180 res[i] = (char) ints[i];
181 }
182 return res;
183 }
184
185 @Test
186 @IR(applyIfCPUFeature = { "avx", "true" },
187 applyIfOr = {"AlignVector", "false", "UseCompactObjectHeaders", "false"},
188 counts = { IRNode.VECTOR_CAST_I2B, IRNode.VECTOR_SIZE + "min(max_int, max_byte)", ">0" })
189 public byte[] narrowToByte() {
190 byte[] res = new byte[SIZE];
191 for (int i = 0; i < SIZE; i++) {
192 res[i] = (byte) ints[i];
193 }
194 return res;
195 }
196
197 @Test
198 @IR(applyIfCPUFeature = { "avx", "true" },
199 applyIfOr = {"AlignVector", "false", "UseCompactObjectHeaders", "false"},
200 counts = { IRNode.VECTOR_CAST_S2B, IRNode.VECTOR_SIZE + "min(max_short, max_byte)", ">0" })
201 public byte[] narrowShortToByte() {
202 byte[] res = new byte[SIZE];
203 for (int i = 0; i < SIZE; i++) {
204 res[i] = (byte) shorts[i];
205 }
206 return res;
207 }
208
209 // ---------------- Convert I/L to F/D ----------------
210 @Test
211 @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx", "true", "rvv", "true"},
212 counts = {IRNode.VECTOR_CAST_I2F, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0"})
213 public float[] convertIntToFloat() {
214 float[] res = new float[SIZE];
215 for (int i = 0; i < SIZE; i++) {
216 res[i] = (float) ints[i];
217 }
218 return res;
219 }
220
221 @Test
222 @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx", "true", "rvv", "true"},
223 counts = {IRNode.VECTOR_CAST_I2D, IRNode.VECTOR_SIZE + "min(max_int, max_double)", ">0"})
224 public double[] convertIntToDouble() {
225 double[] res = new double[SIZE];
226 for (int i = 0; i < SIZE; i++) {
227 res[i] = (double) ints[i];
228 }
229 return res;
230 }
231
232 @Test
233 @IR(applyIfCPUFeatureOr = {"sve", "true", "avx512dq", "true", "rvv", "true"},
234 counts = {IRNode.VECTOR_CAST_L2F, IRNode.VECTOR_SIZE + "min(max_long, max_float)", ">0"})
235 public float[] convertLongToFloat() {
236 float[] res = new float[SIZE];
237 for (int i = 0; i < SIZE; i++) {
238 res[i] = (float) longs[i];
239 }
240 return res;
241 }
242
243 @Test
244 @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx512dq", "true", "rvv", "true"},
245 counts = {IRNode.VECTOR_CAST_L2D, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0"})
246 public double[] convertLongToDouble() {
247 double[] res = new double[SIZE];
248 for (int i = 0; i < SIZE; i++) {
249 res[i] = (double) longs[i];
250 }
251 return res;
252 }
253
254 // ---------------- Convert Subword-I to F/D ----------------
255 @Test
256 @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx2", "true", "rvv", "true"},
257 counts = {IRNode.VECTOR_CAST_S2F, IRNode.VECTOR_SIZE + "min(max_short, max_float)", ">0"})
258 public float[] convertShortToFloat() {
259 float[] res = new float[SIZE];
260 for (int i = 0; i < SIZE; i++) {
261 res[i] = (float) shorts[i];
262 }
263 return res;
264 }
265
266 @Test
267 @IR(applyIfCPUFeature = {"rvv", "true"},
268 applyIf = {"MaxVectorSize", ">=32"},
269 counts = {IRNode.VECTOR_CAST_S2D, IRNode.VECTOR_SIZE + "min(max_short, max_double)", ">0"})
270 @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx", "true"},
271 applyIf = {"MaxVectorSize", ">=16"},
272 counts = {IRNode.VECTOR_CAST_S2D, IRNode.VECTOR_SIZE + "min(max_short, max_double)", ">0"})
273 public double[] convertShortToDouble() {
274 double[] res = new double[SIZE];
275 for (int i = 0; i < SIZE; i++) {
276 res[i] = (double) shorts[i];
277 }
278 return res;
279 }
280
281 @Test
282 @IR(failOn = {IRNode.STORE_VECTOR})
283 // Subword vector casts with char do not work currently, see JDK-8349562.
284 // Assert the vectorization failure so that we are reminded to update
285 // the test when this limitation is addressed in the future.
286 public float[] convertCharToFloat() {
287 float[] res = new float[SIZE];
288 for (int i = 0; i < SIZE; i++) {
289 res[i] = (float) chars[i];
290 }
291 return res;
292 }
293
294 @Test
295 @IR(failOn = {IRNode.STORE_VECTOR})
296 // Subword vector casts with char do not work currently, see JDK-8349562.
297 // Assert the vectorization failure so that we are reminded to update
298 // the test when this limitation is addressed in the future.
299 public double[] convertCharToDouble() {
300 double[] res = new double[SIZE];
301 for (int i = 0; i < SIZE; i++) {
302 res[i] = (double) chars[i];
303 }
304 return res;
305 }
306
307 // ---------------- Convert F/D to I/L ----------------
308 @Test
309 @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx", "true", "avx10_2", "true", "rvv", "true"},
310 counts = {IRNode.VECTOR_CAST_F2I, IRNode.VECTOR_SIZE + "min(max_float, max_int)", "> 0"})
311 @IR(counts = {IRNode.X86_VCAST_F2X, "> 0"},
312 applyIfCPUFeatureAnd = {"avx", "true", "avx10_2", "false"})
313 @IR(counts = {IRNode.X86_VCAST_F2X_AVX10_2, "> 0"},
314 applyIfCPUFeature = {"avx10_2", "true"})
315 public int[] convertFloatToInt() {
316 int[] res = new int[SIZE];
317 for (int i = 0; i < SIZE; i++) {
318 res[i] = (int) floats[i];
319 }
320 return res;
321 }
322
323 @Test
324 @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx512dq", "true", "avx10_2", "true", "rvv", "true"},
325 counts = {IRNode.VECTOR_CAST_F2L, IRNode.VECTOR_SIZE + "min(max_float, max_long)", "> 0"})
326 @IR(counts = {IRNode.X86_VCAST_F2X, "> 0"},
327 applyIfCPUFeatureAnd = {"avx512dq", "true", "avx10_2", "false"})
328 @IR(counts = {IRNode.X86_VCAST_F2X_AVX10_2, "> 0"},
329 applyIfCPUFeature = {"avx10_2", "true"})
330 public long[] convertFloatToLong() {
331 long[] res = new long[SIZE];
332 for (int i = 0; i < SIZE; i++) {
333 res[i] = (long) floats[i];
334 }
335 return res;
336 }
337
338 @Test
339 @IR(applyIfCPUFeatureOr = {"sve", "true", "avx", "true", "avx10_2", "true", "rvv", "true"},
340 counts = {IRNode.VECTOR_CAST_D2I, IRNode.VECTOR_SIZE + "min(max_double, max_int)", "> 0"})
341 @IR(counts = {IRNode.X86_VCAST_D2X, "> 0"},
342 applyIfCPUFeatureAnd = {"avx", "true", "avx10_2", "false"})
343 @IR(counts = {IRNode.X86_VCAST_D2X_AVX10_2, "> 0"},
344 applyIfCPUFeature = {"avx10_2", "true"})
345 public int[] convertDoubleToInt() {
346 int[] res = new int[SIZE];
347 for (int i = 0; i < SIZE; i++) {
348 res[i] = (int) doubles[i];
349 }
350 return res;
351 }
352
353 @Test
354 @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx512dq", "true", "avx10_2", "true", "rvv", "true"},
355 counts = {IRNode.VECTOR_CAST_D2L, IRNode.VECTOR_SIZE + "min(max_double, max_long)", "> 0"})
356 @IR(counts = {IRNode.X86_VCAST_D2X, "> 0"},
357 applyIfCPUFeatureAnd = {"avx512dq", "true", "avx10_2", "false"})
358 @IR(counts = {IRNode.X86_VCAST_D2X_AVX10_2, "> 0"},
359 applyIfCPUFeature = {"avx10_2", "true"})
360 public long[] convertDoubleToLong() {
361 long[] res = new long[SIZE];
362 for (int i = 0; i < SIZE; i++) {
363 res[i] = (long) doubles[i];
364 }
365 return res;
366 }
367
368 // ---------------- Convert F/D to Subword-I ----------------
369 @Test
370 @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx2", "true", "avx10_2", "true", "rvv", "true"},
371 applyIf = {"AlignVector", "false"},
372 counts = {IRNode.VECTOR_CAST_F2S, IRNode.VECTOR_SIZE + "min(max_float, max_short)", "> 0"})
373 @IR(counts = {IRNode.X86_VCAST_F2X, "> 0"},
374 applyIf = {"AlignVector", "false"},
375 applyIfCPUFeatureAnd = {"avx2", "true", "avx10_2", "false"})
376 @IR(counts = {IRNode.X86_VCAST_F2X_AVX10_2, "> 0"},
377 applyIf = {"AlignVector", "false"},
378 applyIfCPUFeature = {"avx10_2", "true"})
379 public short[] convertFloatToShort() {
380 short[] res = new short[SIZE];
381 for (int i = 0; i < SIZE; i++) {
382 res[i] = (short) floats[i];
383 }
384 return res;
385 }
386
387 @Test
388 @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx2", "true", "avx10_2", "true", "rvv", "true"},
389 applyIf = {"AlignVector", "false"},
390 counts = {IRNode.VECTOR_CAST_F2S, IRNode.VECTOR_SIZE + "min(max_float, max_char)", "> 0"})
391 @IR(counts = {IRNode.X86_VCAST_F2X, "> 0"},
392 applyIf = {"AlignVector", "false"},
393 applyIfCPUFeatureAnd = {"avx2", "true", "avx10_2", "false"})
394 @IR(counts = {IRNode.X86_VCAST_F2X_AVX10_2, "> 0"},
395 applyIf = {"AlignVector", "false"},
396 applyIfCPUFeature = {"avx10_2", "true"})
397 public char[] convertFloatToChar() {
398 char[] res = new char[SIZE];
399 for (int i = 0; i < SIZE; i++) {
400 res[i] = (char) floats[i];
401 }
402 return res;
403 }
404
405 @Test
406 @IR(applyIfCPUFeature = {"rvv", "true"},
407 applyIf = {"MaxVectorSize", ">=32"},
408 counts = {IRNode.VECTOR_CAST_D2S, IRNode.VECTOR_SIZE + "min(max_double, max_short)", "> 0"})
409 @IR(applyIfCPUFeatureOr = {"sve", "true", "avx", "true", "avx10_2", "true"},
410 applyIf = {"MaxVectorSize", ">=16"},
411 counts = {IRNode.VECTOR_CAST_D2S, IRNode.VECTOR_SIZE + "min(max_double, max_short)", "> 0"})
412 @IR(counts = {IRNode.X86_VCAST_D2X, "> 0"},
413 applyIf = {"MaxVectorSize", ">=16"},
414 applyIfCPUFeatureAnd = {"avx", "true", "avx10_2", "false"})
415 @IR(counts = {IRNode.X86_VCAST_D2X_AVX10_2, "> 0"},
416 applyIf = {"MaxVectorSize", ">=16"},
417 applyIfCPUFeature = {"avx10_2", "true"})
418 public short[] convertDoubleToShort() {
419 short[] res = new short[SIZE];
420 for (int i = 0; i < SIZE; i++) {
421 res[i] = (short) doubles[i];
422 }
423 return res;
424 }
425
426 @Test
427 @IR(applyIfCPUFeature = {"rvv", "true"},
428 applyIf = {"MaxVectorSize", ">= 32"},
429 counts = {IRNode.VECTOR_CAST_D2S, IRNode.VECTOR_SIZE + "min(max_double, max_char)", "> 0"})
430 @IR(applyIfCPUFeatureOr = {"sve", "true", "avx", "true", "avx10_2", "true"},
431 applyIf = {"MaxVectorSize", ">= 16"},
432 counts = {IRNode.VECTOR_CAST_D2S, IRNode.VECTOR_SIZE + "min(max_double, max_char)", "> 0"})
433 @IR(counts = {IRNode.X86_VCAST_D2X, "> 0"},
434 applyIf = {"MaxVectorSize", ">=16"},
435 applyIfCPUFeatureAnd = {"avx", "true", "avx10_2", "false"})
436 @IR(counts = {IRNode.X86_VCAST_D2X_AVX10_2, "> 0"},
437 applyIf = {"MaxVectorSize", ">=16"},
438 applyIfCPUFeature = {"avx10_2", "true"})
439 public char[] convertDoubleToChar() {
440 char[] res = new char[SIZE];
441 for (int i = 0; i < SIZE; i++) {
442 res[i] = (char) doubles[i];
443 }
444 return res;
445 }
446
447 // ---------------- Convert Between F & D ----------------
448 @Test
449 @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx", "true", "rvv", "true"},
450 counts = {IRNode.VECTOR_CAST_F2D, IRNode.VECTOR_SIZE + "min(max_float, max_double)", ">0"})
451 public double[] convertFloatToDouble() {
452 double[] res = new double[SIZE];
453 for (int i = 0; i < SIZE; i++) {
454 res[i] = (double) floats[i];
455 }
456 return res;
457 }
458
459 @Test
460 @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx", "true", "rvv", "true"},
461 counts = {IRNode.VECTOR_CAST_D2F, IRNode.VECTOR_SIZE + "min(max_double, max_float)", ">0"})
462 public float[] convertDoubleToFloat() {
463 float[] res = new float[SIZE];
464 for (int i = 0; i < SIZE; i++) {
465 res[i] = (float) doubles[i];
466 }
467 return res;
468 }
469 }