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 }