1 /* 2 * Copyright (c) 2025, Rivos Inc. All rights reserved. 3 * Copyright (c) 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 package compiler.c2.irTests; 26 27 import compiler.lib.ir_framework.*; 28 import java.util.Random; 29 import jdk.test.lib.Asserts; 30 import jdk.test.lib.Utils; 31 32 /* 33 * @test 34 * @key randomness 35 * @summary Test conditional move + compare object. 36 * @library /test/lib / 37 * @run driver ${test.main.class} 38 */ 39 40 public class TestScalarConditionalMoveCmpObj { 41 final private static int SIZE = 1024; 42 private static final Random RANDOM = Utils.getRandomInstance(); 43 44 public static void main(String[] args) { 45 TestFramework.runWithFlags("-XX:+UseCMoveUnconditionally", "-XX:-UseVectorCmov", 46 "-XX:+UnlockExperimentalVMOptions", "-XX:-UseCompactObjectHeaders", "-XX:+UseCompressedOops"); 47 TestFramework.runWithFlags("-XX:+UseCMoveUnconditionally", "-XX:-UseVectorCmov", 48 "-XX:+UnlockExperimentalVMOptions", "-XX:-UseCompactObjectHeaders", "-XX:-UseCompressedOops"); 49 TestFramework.runWithFlags("-XX:+UseCMoveUnconditionally", "-XX:-UseVectorCmov", 50 "-XX:+UnlockExperimentalVMOptions", "-XX:+UseCompactObjectHeaders", "-XX:+UseCompressedOops"); 51 TestFramework.runWithFlags("-XX:+UseCMoveUnconditionally", "-XX:-UseVectorCmov", 52 "-XX:+UnlockExperimentalVMOptions", "-XX:+UseCompactObjectHeaders", "-XX:-UseCompressedOops"); 53 } 54 55 // Object comparison 56 // O for I 57 private int cmoveOEQforI(Object a, Object b, int c, int d) { 58 return (a == b) ? c : d; 59 } 60 61 private int cmoveONEforI(Object a, Object b, int c, int d) { 62 return (a != b) ? c : d; 63 } 64 65 // O for L 66 private long cmoveOEQforL(Object a, Object b, long c, long d) { 67 return (a == b) ? c : d; 68 } 69 70 private long cmoveONEforL(Object a, Object b, long c, long d) { 71 return (a != b) ? c : d; 72 } 73 74 // O for F 75 private float cmoveOEQforF(Object a, Object b, float c, float d) { 76 return (a == b) ? c : d; 77 } 78 79 private float cmoveONEforF(Object a, Object b, float c, float d) { 80 return (a != b) ? c : d; 81 } 82 83 // O for D 84 private double cmoveOEQforD(Object a, Object b, double c, double d) { 85 return (a == b) ? c : d; 86 } 87 88 private double cmoveONEforD(Object a, Object b, double c, double d) { 89 return (a != b) ? c : d; 90 } 91 92 // Tests shows CMoveI is generated, so let @IR verify CMOVE_I. 93 // 94 @Test 95 @IR(failOn = {IRNode.STORE_VECTOR}) 96 @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_P, ">0"}, 97 applyIf = {"UseCompressedOops", "false"}) 98 @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_N, ">0"}, 99 applyIf = {"UseCompressedOops", "true"}) 100 private static void testCMoveOEQforI(Object[] a, Object[] b, int[] c, int[] d, int[] r, int[] r2) { 101 for (int i = 0; i < a.length; i++) { 102 int cc = c[i]; 103 int dd = d[i]; 104 r2[i] = cc + dd; 105 r[i] = (a[i] == b[i]) ? cc : dd; 106 } 107 } 108 109 @Test 110 @IR(failOn = {IRNode.STORE_VECTOR}) 111 @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_P, ">0"}, 112 applyIf = {"UseCompressedOops", "false"}) 113 @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_N, ">0"}, 114 applyIf = {"UseCompressedOops", "true"}) 115 private static void testCMoveONEforI(Object[] a, Object[] b, int[] c, int[] d, int[] r, int[] r2) { 116 for (int i = 0; i < a.length; i++) { 117 int cc = c[i]; 118 int dd = d[i]; 119 r2[i] = cc + dd; 120 r[i] = (a[i] != b[i]) ? cc : dd; 121 } 122 } 123 124 // So far, CMoveL is not guaranteed to be generated, so @IR not verify CMOVE_L. 125 // TODO: enable CMOVE_L verification when it's guaranteed to generate CMOVE_L. 126 // 127 @Test 128 @IR(failOn = {IRNode.STORE_VECTOR}) 129 // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_P, ">0"}, 130 // applyIf = {"UseCompressedOops", "false"}) 131 // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_N, ">0"}, 132 // applyIf = {"UseCompressedOops", "true"}) 133 private static void testCMoveOEQforL(Object[] a, Object[] b, long[] c, long[] d, long[] r, long[] r2) { 134 for (int i = 0; i < a.length; i++) { 135 long cc = c[i]; 136 long dd = d[i]; 137 r2[i] = cc + dd; 138 r[i] = (a[i] == b[i]) ? cc : dd; 139 } 140 } 141 142 @Test 143 @IR(failOn = {IRNode.STORE_VECTOR}) 144 // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_P, ">0"}, 145 // applyIf = {"UseCompressedOops", "false"}) 146 // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_N, ">0"}, 147 // applyIf = {"UseCompressedOops", "true"}) 148 private static void testCMoveONEforL(Object[] a, Object[] b, long[] c, long[] d, long[] r, long[] r2) { 149 for (int i = 0; i < a.length; i++) { 150 long cc = c[i]; 151 long dd = d[i]; 152 r2[i] = cc + dd; 153 r[i] = (a[i] != b[i]) ? cc : dd; 154 } 155 } 156 157 @Test 158 @IR(failOn = {IRNode.STORE_VECTOR}) 159 @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_P, ">0"}, 160 applyIf = {"UseCompressedOops", "false"}) 161 @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_N, ">0"}, 162 applyIf = {"UseCompressedOops", "true"}) 163 private static void testCMoveOEQforF(Object[] a, Object[] b, float[] c, float[] d, float[] r, float[] r2) { 164 for (int i = 0; i < a.length; i++) { 165 float cc = c[i]; 166 float dd = d[i]; 167 r2[i] = cc + dd; 168 r[i] = (a[i] == b[i]) ? cc : dd; 169 } 170 } 171 172 @Test 173 @IR(failOn = {IRNode.STORE_VECTOR}) 174 @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_P, ">0"}, 175 applyIf = {"UseCompressedOops", "false"}) 176 @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_N, ">0"}, 177 applyIf = {"UseCompressedOops", "true"}) 178 private static void testCMoveONEforF(Object[] a, Object[] b, float[] c, float[] d, float[] r, float[] r2) { 179 for (int i = 0; i < a.length; i++) { 180 float cc = c[i]; 181 float dd = d[i]; 182 r2[i] = cc + dd; 183 r[i] = (a[i] != b[i]) ? cc : dd; 184 } 185 } 186 187 @Test 188 @IR(failOn = {IRNode.STORE_VECTOR}) 189 @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_P, ">0"}, 190 applyIf = {"UseCompressedOops", "false"}) 191 @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_N, ">0"}, 192 applyIf = {"UseCompressedOops", "true"}) 193 private static void testCMoveOEQforD(Object[] a, Object[] b, double[] c, double[] d, double[] r, double[] r2) { 194 for (int i = 0; i < a.length; i++) { 195 double cc = c[i]; 196 double dd = d[i]; 197 r2[i] = cc + dd; 198 r[i] = (a[i] == b[i]) ? cc : dd; 199 } 200 } 201 202 @Test 203 @IR(failOn = {IRNode.STORE_VECTOR}) 204 @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_P, ">0"}, 205 applyIf = {"UseCompressedOops", "false"}) 206 @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_N, ">0"}, 207 applyIf = {"UseCompressedOops", "true"}) 208 private static void testCMoveONEforD(Object[] a, Object[] b, double[] c, double[] d, double[] r, double[] r2) { 209 for (int i = 0; i < a.length; i++) { 210 double cc = c[i]; 211 double dd = d[i]; 212 r2[i] = cc + dd; 213 r[i] = (a[i] != b[i]) ? cc : dd; 214 } 215 } 216 217 @Warmup(0) 218 @Run(test = {// Object 219 "testCMoveOEQforI", 220 "testCMoveONEforI", 221 "testCMoveOEQforL", 222 "testCMoveONEforL", 223 "testCMoveOEQforF", 224 "testCMoveONEforF", 225 "testCMoveOEQforD", 226 "testCMoveONEforD", 227 }) 228 private void testCMove_runner_two() { 229 Object[] aO = new Object[SIZE]; 230 Object[] bO = new Object[SIZE]; 231 int[] cI = new int[SIZE]; 232 int[] dI = new int[SIZE]; 233 int[] rI = new int[SIZE]; 234 long[] cL = new long[SIZE]; 235 long[] dL = new long[SIZE]; 236 long[] rL = new long[SIZE]; 237 float[] cF = new float[SIZE]; 238 float[] dF = new float[SIZE]; 239 float[] rF = new float[SIZE]; 240 double[] cD = new double[SIZE]; 241 double[] dD = new double[SIZE]; 242 double[] rD = new double[SIZE]; 243 244 init(aO); 245 shuffle(aO, bO); 246 init(cL); 247 init(dL); 248 init(cF); 249 init(dF); 250 init(cD); 251 init(dD); 252 253 testCMoveOEQforI(aO, bO, cI, dI, rI, rI); 254 for (int i = 0; i < SIZE; i++) { 255 Asserts.assertEquals(rI[i], cmoveOEQforI(aO[i], bO[i], cI[i], dI[i])); 256 } 257 258 testCMoveONEforI(aO, bO, cI, dI, rI, rI); 259 for (int i = 0; i < SIZE; i++) { 260 Asserts.assertEquals(rI[i], cmoveONEforI(aO[i], bO[i], cI[i], dI[i])); 261 } 262 263 testCMoveOEQforL(aO, bO, cL, dL, rL, rL); 264 for (int i = 0; i < SIZE; i++) { 265 Asserts.assertEquals(rL[i], cmoveOEQforL(aO[i], bO[i], cL[i], dL[i])); 266 } 267 268 testCMoveONEforL(aO, bO, cL, dL, rL, rL); 269 for (int i = 0; i < SIZE; i++) { 270 Asserts.assertEquals(rL[i], cmoveONEforL(aO[i], bO[i], cL[i], dL[i])); 271 } 272 273 testCMoveOEQforF(aO, bO, cF, dF, rF, rF); 274 for (int i = 0; i < SIZE; i++) { 275 Asserts.assertEquals(rF[i], cmoveOEQforF(aO[i], bO[i], cF[i], dF[i])); 276 } 277 278 testCMoveONEforF(aO, bO, cF, dF, rF, rF); 279 for (int i = 0; i < SIZE; i++) { 280 Asserts.assertEquals(rF[i], cmoveONEforF(aO[i], bO[i], cF[i], dF[i])); 281 } 282 283 testCMoveOEQforD(aO, bO, cD, dD, rD, rD); 284 for (int i = 0; i < SIZE; i++) { 285 Asserts.assertEquals(rD[i], cmoveOEQforD(aO[i], bO[i], cD[i], dD[i])); 286 } 287 288 testCMoveONEforD(aO, bO, cD, dD, rD, rD); 289 for (int i = 0; i < SIZE; i++) { 290 Asserts.assertEquals(rD[i], cmoveONEforD(aO[i], bO[i], cD[i], dD[i])); 291 } 292 293 } 294 295 private static void init(Object[] a) { 296 for (int i = 0; i < SIZE; i++) { 297 a[i] = new Object(); 298 } 299 } 300 301 private static void shuffle(Object[] a, Object[] b) { 302 for (int i = 0; i < a.length; i++) { 303 b[i] = a[i]; 304 } 305 Random rand = Utils.getRandomInstance(); 306 for (int i = 0; i < SIZE; i++) { 307 if (rand.nextInt(5) == 0) { 308 Object t = b[i]; 309 b[i] = b[SIZE-1-i]; 310 b[SIZE-1-i] = t; 311 } 312 } 313 } 314 315 private static void init(int[] a) { 316 for (int i = 0; i < SIZE; i++) { 317 a[i] = RANDOM.nextInt(); 318 } 319 } 320 321 private static void init(long[] a) { 322 for (int i = 0; i < SIZE; i++) { 323 a[i] = RANDOM.nextLong(); 324 } 325 } 326 327 private static void init(float[] a) { 328 for (int i = 0; i < SIZE; i++) { 329 a[i] = switch(RANDOM.nextInt() % 20) { 330 case 0 -> Float.NaN; 331 case 1 -> 0; 332 case 2 -> 1; 333 case 3 -> Float.POSITIVE_INFINITY; 334 case 4 -> Float.NEGATIVE_INFINITY; 335 case 5 -> Float.MAX_VALUE; 336 case 6 -> Float.MIN_VALUE; 337 case 7, 8, 9 -> RANDOM.nextFloat(); 338 default -> Float.intBitsToFloat(RANDOM.nextInt()); 339 }; 340 } 341 } 342 343 private static void init(double[] a) { 344 for (int i = 0; i < SIZE; i++) { 345 a[i] = switch(RANDOM.nextInt() % 20) { 346 case 0 -> Double.NaN; 347 case 1 -> 0; 348 case 2 -> 1; 349 case 3 -> Double.POSITIVE_INFINITY; 350 case 4 -> Double.NEGATIVE_INFINITY; 351 case 5 -> Double.MAX_VALUE; 352 case 6 -> Double.MIN_VALUE; 353 case 7, 8, 9 -> RANDOM.nextDouble(); 354 default -> Double.longBitsToDouble(RANDOM.nextLong()); 355 }; 356 } 357 } 358 } --- EOF ---