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:-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 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 }