1 /*
   2  * Copyright (c) 2022, Arm Limited. All rights reserved.
   3  * Copyright (c) 2023, 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 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  * @bug 8289422 8306088 8313720
  35  * @key randomness
  36  * @summary Auto-vectorization enhancement to support vector conditional move.
  37  * @library /test/lib /
  38  * @run driver compiler.c2.irTests.TestVectorConditionalMove
  39  */
  40 
  41 public class TestVectorConditionalMove {
  42     final private static int SIZE = 1024;
  43     private static final Random RANDOM = Utils.getRandomInstance();
  44 
  45     public static void main(String[] args) {
  46         // Cross-product: +-AlignVector and +-UseCompactObjectHeaders
  47         TestFramework.runWithFlags("-XX:+UseCMoveUnconditionally", "-XX:+UseVectorCmov",
  48                                    "-XX:+UnlockExperimentalVMOptions", "-XX:-UseCompactObjectHeaders", "-XX:-AlignVector");
  49         TestFramework.runWithFlags("-XX:+UseCMoveUnconditionally", "-XX:+UseVectorCmov",
  50                                    "-XX:+UnlockExperimentalVMOptions", "-XX:-UseCompactObjectHeaders", "-XX:+AlignVector");
  51         TestFramework.runWithFlags("-XX:+UseCMoveUnconditionally", "-XX:+UseVectorCmov",
  52                                    "-XX:+UnlockExperimentalVMOptions", "-XX:+UseCompactObjectHeaders", "-XX:-AlignVector");
  53         TestFramework.runWithFlags("-XX:+UseCMoveUnconditionally", "-XX:+UseVectorCmov",
  54                                    "-XX:+UnlockExperimentalVMOptions", "-XX:+UseCompactObjectHeaders", "-XX:+AlignVector");
  55     }
  56 
  57     // Compare 2 values, and pick one of them
  58     private float cmoveFloatGT(float a, float b) {
  59         return (a > b) ? a : b;
  60     }
  61 
  62     private float cmoveFloatGTSwap(float a, float b) {
  63         return (b > a) ? a : b;
  64     }
  65 
  66     private float cmoveFloatLT(float a, float b) {
  67         return (a < b) ? a : b;
  68     }
  69 
  70     private float cmoveFloatLTSwap(float a, float b) {
  71         return (b < a) ? a : b;
  72     }
  73 
  74     private float cmoveFloatEQ(float a, float b) {
  75         return (a == b) ? a : b;
  76     }
  77 
  78     private double cmoveDoubleLE(double a, double b) {
  79         return (a <= b) ? a : b;
  80     }
  81 
  82     private double cmoveDoubleLESwap(double a, double b) {
  83         return (b <= a) ? a : b;
  84     }
  85 
  86     private double cmoveDoubleGE(double a, double b) {
  87         return (a >= b) ? a : b;
  88     }
  89 
  90     private double cmoveDoubleGESwap(double a, double b) {
  91         return (b >= a) ? a : b;
  92     }
  93 
  94     private double cmoveDoubleNE(double a, double b) {
  95         return (a != b) ? a : b;
  96     }
  97 
  98     // Extensions: compare 2 values, and pick from 2 consts
  99     private float cmoveFGTforFConst(float a, float b) {
 100         return (a > b) ? 0.1f : -0.1f;
 101     }
 102 
 103     private float cmoveFGEforFConst(float a, float b) {
 104         return (a >= b) ? 0.1f : -0.1f;
 105     }
 106 
 107     private float cmoveFLTforFConst(float a, float b) {
 108         return (a < b) ? 0.1f : -0.1f;
 109     }
 110 
 111     private float cmoveFLEforFConst(float a, float b) {
 112         return (a <= b) ? 0.1f : -0.1f;
 113     }
 114 
 115     private float cmoveFEQforFConst(float a, float b) {
 116         return (a == b) ? 0.1f : -0.1f;
 117     }
 118 
 119     private float cmoveFNEQforFConst(float a, float b) {
 120         return (a != b) ? 0.1f : -0.1f;
 121     }
 122 
 123     private double cmoveDGTforDConst(double a, double b) {
 124         return (a > b) ? 0.1 : -0.1;
 125     }
 126 
 127     private double cmoveDGEforDConst(double a, double b) {
 128         return (a >= b) ? 0.1 : -0.1;
 129     }
 130 
 131     private double cmoveDLTforDConst(double a, double b) {
 132         return (a < b) ? 0.1 : -0.1;
 133     }
 134 
 135     private double cmoveDLEforDConst(double a, double b) {
 136         return (a <= b) ? 0.1 : -0.1;
 137     }
 138 
 139     private double cmoveDEQforDConst(double a, double b) {
 140         return (a == b) ? 0.1 : -0.1;
 141     }
 142 
 143     private double cmoveDNEQforDConst(double a, double b) {
 144         return (a != b) ? 0.1 : -0.1;
 145     }
 146 
 147     // Extension: Compare 2 ILFD values, and pick from 2 ILFD values
 148     private int cmoveIGTforI(int a, int b, int c, int d) {
 149         return (a > b) ? c : d;
 150     }
 151 
 152     private long cmoveIGTforL(int a, int b, long c, long d) {
 153         return (a > b) ? c : d;
 154     }
 155 
 156     private float cmoveIGTforF(int a, int b, float c, float d) {
 157         return (a > b) ? c : d;
 158     }
 159 
 160     private double cmoveIGTforD(int a, int b, double c, double d) {
 161         return (a > b) ? c : d;
 162     }
 163 
 164     private int cmoveLGTforI(long a, long b, int c, int d) {
 165         return (a > b) ? c : d;
 166     }
 167 
 168     private long cmoveLGTforL(long a, long b, long c, long d) {
 169         return (a > b) ? c : d;
 170     }
 171 
 172     private float cmoveLGTforF(long a, long b, float c, float d) {
 173         return (a > b) ? c : d;
 174     }
 175 
 176     private double cmoveLGTforD(long a, long b, double c, double d) {
 177         return (a > b) ? c : d;
 178     }
 179 
 180     private int cmoveFGTforI(float a, float b, int c, int d) {
 181         return (a > b) ? c : d;
 182     }
 183 
 184     private long cmoveFGTforL(float a, float b, long c, long d) {
 185         return (a > b) ? c : d;
 186     }
 187 
 188     private float cmoveFGTforF(float a, float b, float c, float d) {
 189         return (a > b) ? c : d;
 190     }
 191 
 192     private double cmoveFGTforD(float a, float b, double c, double d) {
 193         return (a > b) ? c : d;
 194     }
 195 
 196     private int cmoveDGTforI(double a, double b, int c, int d) {
 197         return (a > b) ? c : d;
 198     }
 199 
 200     private long cmoveDGTforL(double a, double b, long c, long d) {
 201         return (a > b) ? c : d;
 202     }
 203 
 204     private float cmoveDGTforF(double a, double b, float c, float d) {
 205         return (a > b) ? c : d;
 206     }
 207 
 208     private double cmoveDGTforD(double a, double b, double c, double d) {
 209         return (a > b) ? c : d;
 210     }
 211 
 212     // Compare 2 values, and pick one of them
 213     @Test
 214     @IR(counts = {IRNode.LOAD_VECTOR_F, ">0",
 215                   IRNode.VECTOR_MASK_CMP_F, ">0",
 216                   IRNode.VECTOR_BLEND_F, ">0",
 217                   IRNode.STORE_VECTOR, ">0"},
 218         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 219     private static void testCMoveVFGT(float[] a, float[] b, float[] c) {
 220         for (int i = 0; i < a.length; i++) {
 221             c[i] = (a[i] > b[i]) ? a[i] : b[i];
 222         }
 223     }
 224 
 225     @Test
 226     @IR(counts = {IRNode.LOAD_VECTOR_F, ">0",
 227                   IRNode.VECTOR_MASK_CMP_F, ">0",
 228                   IRNode.VECTOR_BLEND_F, ">0",
 229                   IRNode.STORE_VECTOR, ">0"},
 230         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 231     private static void testCMoveVFGTSwap(float[] a, float[] b, float[] c) {
 232         for (int i = 0; i < a.length; i++) {
 233             c[i] = (b[i] > a[i]) ? a[i] : b[i];
 234         }
 235     }
 236 
 237     @Test
 238     @IR(counts = {IRNode.LOAD_VECTOR_F, ">0",
 239                   IRNode.VECTOR_MASK_CMP_F, ">0",
 240                   IRNode.VECTOR_BLEND_F, ">0",
 241                   IRNode.STORE_VECTOR, ">0"},
 242         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 243     private static void testCMoveVFLT(float[] a, float[] b, float[] c) {
 244         for (int i = 0; i < a.length; i++) {
 245             c[i] = (a[i] < b[i]) ? a[i] : b[i];
 246         }
 247     }
 248 
 249     @Test
 250     @IR(counts = {IRNode.LOAD_VECTOR_F, ">0",
 251                   IRNode.VECTOR_MASK_CMP_F, ">0",
 252                   IRNode.VECTOR_BLEND_F, ">0",
 253                   IRNode.STORE_VECTOR, ">0"},
 254         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 255     private static void testCMoveVFLTSwap(float[] a, float[] b, float[] c) {
 256         for (int i = 0; i < a.length; i++) {
 257             c[i] = (b[i] < a[i]) ? a[i] : b[i];
 258         }
 259     }
 260 
 261     @Test
 262     @IR(counts = {IRNode.LOAD_VECTOR_F, ">0",
 263                   IRNode.VECTOR_MASK_CMP_F, ">0",
 264                   IRNode.VECTOR_BLEND_F, ">0",
 265                   IRNode.STORE_VECTOR, ">0"},
 266         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 267     private static void testCMoveVFEQ(float[] a, float[] b, float[] c) {
 268         for (int i = 0; i < a.length; i++) {
 269             c[i] = (a[i] == b[i]) ? a[i] : b[i];
 270         }
 271     }
 272 
 273     @Test
 274     @IR(counts = {IRNode.LOAD_VECTOR_D, ">0",
 275                   IRNode.VECTOR_MASK_CMP_D, ">0",
 276                   IRNode.VECTOR_BLEND_D, ">0",
 277                   IRNode.STORE_VECTOR, ">0"},
 278         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 279     private static void testCMoveVDLE(double[] a, double[] b, double[] c) {
 280         for (int i = 0; i < a.length; i++) {
 281             c[i] = (a[i] <= b[i]) ? a[i] : b[i];
 282         }
 283     }
 284 
 285     @Test
 286     @IR(counts = {IRNode.LOAD_VECTOR_D, ">0",
 287                   IRNode.VECTOR_MASK_CMP_D, ">0",
 288                   IRNode.VECTOR_BLEND_D, ">0",
 289                   IRNode.STORE_VECTOR, ">0"},
 290         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 291     private static void testCMoveVDLESwap(double[] a, double[] b, double[] c) {
 292         for (int i = 0; i < a.length; i++) {
 293             c[i] = (b[i] <= a[i]) ? a[i] : b[i];
 294         }
 295     }
 296 
 297     @Test
 298     @IR(counts = {IRNode.LOAD_VECTOR_D, ">0",
 299                   IRNode.VECTOR_MASK_CMP_D, ">0",
 300                   IRNode.VECTOR_BLEND_D, ">0",
 301                   IRNode.STORE_VECTOR, ">0"},
 302         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 303     private static void testCMoveVDGE(double[] a, double[] b, double[] c) {
 304         for (int i = 0; i < a.length; i++) {
 305             c[i] = (a[i] >= b[i]) ? a[i] : b[i];
 306         }
 307     }
 308 
 309     @Test
 310     @IR(counts = {IRNode.LOAD_VECTOR_D, ">0",
 311                   IRNode.VECTOR_MASK_CMP_D, ">0",
 312                   IRNode.VECTOR_BLEND_D, ">0",
 313                   IRNode.STORE_VECTOR, ">0"},
 314         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 315     private static void testCMoveVDGESwap(double[] a, double[] b, double[] c) {
 316         for (int i = 0; i < a.length; i++) {
 317             c[i] = (b[i] >= a[i]) ? a[i] : b[i];
 318         }
 319     }
 320 
 321     @Test
 322     @IR(counts = {IRNode.LOAD_VECTOR_D, ">0",
 323                   IRNode.VECTOR_MASK_CMP_D, ">0",
 324                   IRNode.VECTOR_BLEND_D, ">0",
 325                   IRNode.STORE_VECTOR, ">0"},
 326         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 327     private static void testCMoveVDNE(double[] a, double[] b, double[] c) {
 328         for (int i = 0; i < a.length; i++) {
 329             c[i] = (a[i] != b[i]) ? a[i] : b[i];
 330         }
 331     }
 332 
 333     // Extensions: compare 2 values, and pick from 2 consts
 334     @Test
 335     @IR(counts = {IRNode.LOAD_VECTOR_F, ">0",
 336                   IRNode.VECTOR_MASK_CMP_F, ">0",
 337                   IRNode.VECTOR_BLEND_F, ">0",
 338                   IRNode.STORE_VECTOR, ">0"},
 339         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 340     private static void testCMoveFGTforFConst(float[] a, float[] b, float[] c) {
 341         for (int i = 0; i < a.length; i++) {
 342             c[i] = (a[i] > b[i]) ? 0.1f : -0.1f;
 343         }
 344     }
 345 
 346     @Test
 347     @IR(counts = {IRNode.LOAD_VECTOR_F, ">0",
 348                   IRNode.VECTOR_MASK_CMP_F, ">0",
 349                   IRNode.VECTOR_BLEND_F, ">0",
 350                   IRNode.STORE_VECTOR, ">0"},
 351         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 352     private static void testCMoveFGEforFConst(float[] a, float[] b, float[] c) {
 353         for (int i = 0; i < a.length; i++) {
 354             c[i] = (a[i] >= b[i]) ? 0.1f : -0.1f;
 355         }
 356     }
 357 
 358     @Test
 359     @IR(counts = {IRNode.LOAD_VECTOR_F, ">0",
 360                   IRNode.VECTOR_MASK_CMP_F, ">0",
 361                   IRNode.VECTOR_BLEND_F, ">0",
 362                   IRNode.STORE_VECTOR, ">0"},
 363         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 364     private static void testCMoveFLTforFConst(float[] a, float[] b, float[] c) {
 365         for (int i = 0; i < a.length; i++) {
 366             c[i] = (a[i] < b[i]) ? 0.1f : -0.1f;
 367         }
 368     }
 369 
 370     @Test
 371     @IR(counts = {IRNode.LOAD_VECTOR_F, ">0",
 372                   IRNode.VECTOR_MASK_CMP_F, ">0",
 373                   IRNode.VECTOR_BLEND_F, ">0",
 374                   IRNode.STORE_VECTOR, ">0"},
 375         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 376     private static void testCMoveFLEforFConst(float[] a, float[] b, float[] c) {
 377         for (int i = 0; i < a.length; i++) {
 378             c[i] = (a[i] <= b[i]) ? 0.1f : -0.1f;
 379         }
 380     }
 381 
 382     @Test
 383     @IR(counts = {IRNode.LOAD_VECTOR_F, ">0",
 384                   IRNode.VECTOR_MASK_CMP_F, ">0",
 385                   IRNode.VECTOR_BLEND_F, ">0",
 386                   IRNode.STORE_VECTOR, ">0"},
 387         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 388     private static void testCMoveFEQforFConst(float[] a, float[] b, float[] c) {
 389         for (int i = 0; i < a.length; i++) {
 390             c[i] = (a[i] == b[i]) ? 0.1f : -0.1f;
 391         }
 392     }
 393 
 394     @Test
 395     @IR(counts = {IRNode.LOAD_VECTOR_F, ">0",
 396                   IRNode.VECTOR_MASK_CMP_F, ">0",
 397                   IRNode.VECTOR_BLEND_F, ">0",
 398                   IRNode.STORE_VECTOR, ">0"},
 399         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 400     private static void testCMoveFNEQforFConst(float[] a, float[] b, float[] c) {
 401         for (int i = 0; i < a.length; i++) {
 402             c[i] = (a[i] != b[i]) ? 0.1f : -0.1f;
 403         }
 404     }
 405 
 406     @Test
 407     @IR(counts = {IRNode.LOAD_VECTOR_F, ">0",
 408                   IRNode.VECTOR_MASK_CMP_F, ">0",
 409                   IRNode.VECTOR_BLEND_F, ">0",
 410                   IRNode.STORE_VECTOR, ">0"},
 411         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 412     private static void testCMoveFLTforFConstH2(float[] a, float[] b, float[] c) {
 413         for (int i = 0; i < a.length; i+=2) {
 414             c[i+0] = (a[i+0] < b[i+0]) ? 0.1f : -0.1f;
 415             c[i+1] = (a[i+1] < b[i+1]) ? 0.1f : -0.1f;
 416         }
 417     }
 418 
 419     @Test
 420     @IR(counts = {IRNode.LOAD_VECTOR_F, ">0",
 421                   IRNode.VECTOR_MASK_CMP_F, ">0",
 422                   IRNode.VECTOR_BLEND_F, ">0",
 423                   IRNode.STORE_VECTOR, ">0"},
 424         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 425     private static void testCMoveFLEforFConstH2(float[] a, float[] b, float[] c) {
 426         for (int i = 0; i < a.length; i+=2) {
 427             c[i+0] = (a[i+0] <= b[i+0]) ? 0.1f : -0.1f;
 428             c[i+1] = (a[i+1] <= b[i+1]) ? 0.1f : -0.1f;
 429         }
 430     }
 431 
 432     @Test
 433     @IR(counts = {IRNode.LOAD_VECTOR_F, "=0",
 434                   IRNode.VECTOR_MASK_CMP_F, "=0",
 435                   IRNode.VECTOR_BLEND_F, "=0",
 436                   IRNode.STORE_VECTOR, "=0"},
 437         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 438     private static void testCMoveFYYforFConstH2(float[] a, float[] b, float[] c) {
 439         for (int i = 0; i < a.length; i+=2) {
 440             c[i+0] = (a[i+0] <= b[i+0]) ? 0.1f : -0.1f;
 441             c[i+1] = (a[i+1] <  b[i+1]) ? 0.1f : -0.1f;
 442         }
 443     }
 444 
 445     @Test
 446     @IR(counts = {IRNode.LOAD_VECTOR_F, "=0",
 447                   IRNode.VECTOR_MASK_CMP_F, "=0",
 448                   IRNode.VECTOR_BLEND_F, "=0",
 449                   IRNode.STORE_VECTOR, "=0"},
 450         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 451     private static void testCMoveFXXforFConstH2(float[] a, float[] b, float[] c) {
 452         for (int i = 0; i < a.length; i+=2) {
 453             c[i+0] = (a[i+0] <  b[i+0]) ? 0.1f : -0.1f;
 454             c[i+1] = (a[i+1] <= b[i+1]) ? 0.1f : -0.1f;
 455         }
 456     }
 457 
 458     @Test
 459     @IR(counts = {IRNode.LOAD_VECTOR_D, ">0",
 460                   IRNode.VECTOR_MASK_CMP_D, ">0",
 461                   IRNode.VECTOR_BLEND_D, ">0",
 462                   IRNode.STORE_VECTOR, ">0"},
 463         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 464     private static void testCMoveDGTforDConst(double[] a, double[] b, double[] c) {
 465         for (int i = 0; i < a.length; i++) {
 466             c[i] = (a[i] > b[i]) ? 0.1 : -0.1;
 467         }
 468     }
 469 
 470     @Test
 471     @IR(counts = {IRNode.LOAD_VECTOR_D, ">0",
 472                   IRNode.VECTOR_MASK_CMP_D, ">0",
 473                   IRNode.VECTOR_BLEND_D, ">0",
 474                   IRNode.STORE_VECTOR, ">0"},
 475         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 476     private static void testCMoveDGEforDConst(double[] a, double[] b, double[] c) {
 477         for (int i = 0; i < a.length; i++) {
 478             c[i] = (a[i] >= b[i]) ? 0.1 : -0.1;
 479         }
 480     }
 481 
 482     @Test
 483     @IR(counts = {IRNode.LOAD_VECTOR_D, ">0",
 484                   IRNode.VECTOR_MASK_CMP_D, ">0",
 485                   IRNode.VECTOR_BLEND_D, ">0",
 486                   IRNode.STORE_VECTOR, ">0"},
 487         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 488     private static void testCMoveDLTforDConst(double[] a, double[] b, double[] c) {
 489         for (int i = 0; i < a.length; i++) {
 490             c[i] = (a[i] < b[i]) ? 0.1 : -0.1;
 491         }
 492     }
 493 
 494     @Test
 495     @IR(counts = {IRNode.LOAD_VECTOR_D, ">0",
 496                   IRNode.VECTOR_MASK_CMP_D, ">0",
 497                   IRNode.VECTOR_BLEND_D, ">0",
 498                   IRNode.STORE_VECTOR, ">0"},
 499         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 500     private static void testCMoveDLEforDConst(double[] a, double[] b, double[] c) {
 501         for (int i = 0; i < a.length; i++) {
 502             c[i] = (a[i] <= b[i]) ? 0.1 : -0.1;
 503         }
 504     }
 505 
 506     @Test
 507     @IR(counts = {IRNode.LOAD_VECTOR_D, ">0",
 508                   IRNode.VECTOR_MASK_CMP_D, ">0",
 509                   IRNode.VECTOR_BLEND_D, ">0",
 510                   IRNode.STORE_VECTOR, ">0"},
 511         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 512     private static void testCMoveDEQforDConst(double[] a, double[] b, double[] c) {
 513         for (int i = 0; i < a.length; i++) {
 514             c[i] = (a[i] == b[i]) ? 0.1 : -0.1;
 515         }
 516     }
 517 
 518     @Test
 519     @IR(counts = {IRNode.LOAD_VECTOR_D, ">0",
 520                   IRNode.VECTOR_MASK_CMP_D, ">0",
 521                   IRNode.VECTOR_BLEND_D, ">0",
 522                   IRNode.STORE_VECTOR, ">0"},
 523         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 524     private static void testCMoveDNEQforDConst(double[] a, double[] b, double[] c) {
 525         for (int i = 0; i < a.length; i++) {
 526             c[i] = (a[i] != b[i]) ? 0.1 : -0.1;
 527         }
 528     }
 529 
 530     @Test
 531     @IR(counts = {IRNode.LOAD_VECTOR_D, ">0",
 532                   IRNode.VECTOR_MASK_CMP_D, ">0",
 533                   IRNode.VECTOR_BLEND_D, ">0",
 534                   IRNode.STORE_VECTOR, ">0"},
 535         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 536     private static void testCMoveDLTforDConstH2(double[] a, double[] b, double[] c) {
 537         for (int i = 0; i < a.length; i+=2) {
 538             c[i+0] = (a[i+0] < b[i+0]) ? 0.1 : -0.1;
 539             c[i+1] = (a[i+1] < b[i+1]) ? 0.1 : -0.1;
 540         }
 541     }
 542 
 543     @Test
 544     @IR(counts = {IRNode.LOAD_VECTOR_D, ">0",
 545                   IRNode.VECTOR_MASK_CMP_D, ">0",
 546                   IRNode.VECTOR_BLEND_D, ">0",
 547                   IRNode.STORE_VECTOR, ">0"},
 548         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 549     private static void testCMoveDLEforDConstH2(double[] a, double[] b, double[] c) {
 550         for (int i = 0; i < a.length; i+=2) {
 551             c[i+0] = (a[i+0] <= b[i+0]) ? 0.1 : -0.1;
 552             c[i+1] = (a[i+1] <= b[i+1]) ? 0.1 : -0.1;
 553         }
 554     }
 555 
 556     @Test
 557     @IR(counts = {IRNode.LOAD_VECTOR_D, "=0",
 558                   IRNode.VECTOR_MASK_CMP_D, "=0",
 559                   IRNode.VECTOR_BLEND_D, "=0",
 560                   IRNode.STORE_VECTOR, "=0"},
 561         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 562     private static void testCMoveDYYforDConstH2(double[] a, double[] b, double[] c) {
 563         for (int i = 0; i < a.length; i+=2) {
 564             c[i+0] = (a[i+0] <= b[i+0]) ? 0.1 : -0.1;
 565             c[i+1] = (a[i+1] <  b[i+1]) ? 0.1 : -0.1;
 566         }
 567     }
 568 
 569     @Test
 570     @IR(counts = {IRNode.LOAD_VECTOR_D, "=0",
 571                   IRNode.VECTOR_MASK_CMP_D, "=0",
 572                   IRNode.VECTOR_BLEND_D, "=0",
 573                   IRNode.STORE_VECTOR, "=0"},
 574         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 575     private static void testCMoveDXXforDConstH2(double[] a, double[] b, double[] c) {
 576         for (int i = 0; i < a.length; i+=2) {
 577             c[i+0] = (a[i+0] <  b[i+0]) ? 0.1 : -0.1;
 578             c[i+1] = (a[i+1] <= b[i+1]) ? 0.1 : -0.1;
 579         }
 580     }
 581 
 582     // Extension: Compare 2 ILFD values, and pick from 2 ILFD values
 583     // Note:
 584     //   To guarantee that CMove is introduced, I need to perform the loads before the branch. To ensure they
 585     //   do not float down into the branches, I compute a value, and store it to r2 (same as r, except that the
 586     //   compilation does not know that).
 587     //   So far, vectorization only works for CMoveF/D, with same data-width comparison (F/I for F, D/L for D).
 588     @Test
 589     @IR(failOn = {IRNode.STORE_VECTOR})
 590     private static void testCMoveIGTforI(int[] a, int[] b, int[] c, int[] d, int[] r, int[] r2) {
 591         for (int i = 0; i < a.length; i++) {
 592             int cc = c[i];
 593             int dd = d[i];
 594             r2[i] = cc + dd;
 595             r[i] = (a[i] > b[i]) ? cc : dd;
 596         }
 597     }
 598 
 599     @Test
 600     @IR(failOn = {IRNode.STORE_VECTOR})
 601     private static void testCMoveIGTforL(int[] a, int[] b, long[] c, long[] d, long[] r, long[] r2) {
 602         for (int i = 0; i < a.length; i++) {
 603             long cc = c[i];
 604             long dd = d[i];
 605             r2[i] = cc + dd;
 606             r[i] = (a[i] > b[i]) ? cc : dd;
 607         }
 608     }
 609 
 610     @Test
 611     @IR(counts = {IRNode.LOAD_VECTOR_I,     IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0",
 612                   IRNode.LOAD_VECTOR_F,     IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0",
 613                   IRNode.VECTOR_MASK_CMP_I, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0",
 614                   IRNode.VECTOR_BLEND_F,    IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0",
 615                   IRNode.STORE_VECTOR, ">0"},
 616         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 617     private static void testCMoveIGTforF(int[] a, int[] b, float[] c, float[] d, float[] r, float[] r2) {
 618         for (int i = 0; i < a.length; i++) {
 619             float cc = c[i];
 620             float dd = d[i];
 621             r2[i] = cc + dd;
 622             r[i] = (a[i] > b[i]) ? cc : dd;
 623         }
 624     }
 625 
 626     @Test
 627     @IR(failOn = {IRNode.STORE_VECTOR})
 628     private static void testCMoveIGTforD(int[] a, int[] b, double[] c, double[] d, double[] r, double[] r2) {
 629         for (int i = 0; i < a.length; i++) {
 630             double cc = c[i];
 631             double dd = d[i];
 632             r2[i] = cc + dd;
 633             r[i] = (a[i] > b[i]) ? cc : dd;
 634         }
 635     }
 636 
 637     @Test
 638     @IR(failOn = {IRNode.STORE_VECTOR})
 639     private static void testCMoveLGTforI(long[] a, long[] b, int[] c, int[] d, int[] r, int[] r2) {
 640         for (int i = 0; i < a.length; i++) {
 641             int cc = c[i];
 642             int dd = d[i];
 643             r2[i] = cc + dd;
 644             r[i] = (a[i] > b[i]) ? cc : dd;
 645         }
 646     }
 647 
 648     @Test
 649     @IR(failOn = {IRNode.STORE_VECTOR})
 650     private static void testCMoveLGTforL(long[] a, long[] b, long[] c, long[] d, long[] r, long[] r2) {
 651         for (int i = 0; i < a.length; i++) {
 652             long cc = c[i];
 653             long dd = d[i];
 654             r2[i] = cc + dd;
 655             r[i] = (a[i] > b[i]) ? cc : dd;
 656         }
 657     }
 658 
 659     @Test
 660     @IR(failOn = {IRNode.STORE_VECTOR})
 661     private static void testCMoveLGTforF(long[] a, long[] b, float[] c, float[] d, float[] r, float[] r2) {
 662         for (int i = 0; i < a.length; i++) {
 663             float cc = c[i];
 664             float dd = d[i];
 665             r2[i] = cc + dd;
 666             r[i] = (a[i] > b[i]) ? cc : dd;
 667         }
 668     }
 669 
 670     @Test
 671     @IR(counts = {IRNode.LOAD_VECTOR_L,     IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0",
 672                   IRNode.LOAD_VECTOR_D,     IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0",
 673                   IRNode.VECTOR_MASK_CMP_L, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0",
 674                   IRNode.VECTOR_BLEND_D,    IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0",
 675                   IRNode.STORE_VECTOR, ">0"},
 676         applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true"})
 677     // Requires avx2, else L is restricted to 16 byte, and D has 32. That leads to a vector elements mismatch of 2 to 4.
 678     private static void testCMoveLGTforD(long[] a, long[] b, double[] c, double[] d, double[] r, double[] r2) {
 679         for (int i = 0; i < a.length; i++) {
 680             double cc = c[i];
 681             double dd = d[i];
 682             r2[i] = cc + dd;
 683             r[i] = (a[i] > b[i]) ? cc : dd;
 684         }
 685     }
 686 
 687     @Test
 688     @IR(failOn = {IRNode.STORE_VECTOR})
 689     private static void testCMoveFGTforI(float[] a, float[] b, int[] c, int[] d, int[] r, int[] r2) {
 690         for (int i = 0; i < a.length; i++) {
 691             int cc = c[i];
 692             int dd = d[i];
 693             r2[i] = cc + dd;
 694             r[i] = (a[i] > b[i]) ? cc : dd;
 695         }
 696     }
 697 
 698     @Test
 699     @IR(failOn = {IRNode.STORE_VECTOR})
 700     private static void testCMoveFGTforL(float[] a, float[] b, long[] c, long[] d, long[] r, long[] r2) {
 701         for (int i = 0; i < a.length; i++) {
 702             long cc = c[i];
 703             long dd = d[i];
 704             r2[i] = cc + dd;
 705             r[i] = (a[i] > b[i]) ? cc : dd;
 706         }
 707     }
 708 
 709     @Test
 710     @IR(counts = {IRNode.LOAD_VECTOR_F, ">0",
 711                   IRNode.VECTOR_MASK_CMP_F, ">0",
 712                   IRNode.VECTOR_BLEND_F, ">0",
 713                   IRNode.STORE_VECTOR, ">0"},
 714         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 715     private static void testCMoveFGTforF(float[] a, float[] b, float[] c, float[] d, float[] r, float[] r2) {
 716         for (int i = 0; i < a.length; i++) {
 717             float cc = c[i];
 718             float dd = d[i];
 719             r2[i] = cc + dd;
 720             r[i] = (a[i] > b[i]) ? cc : dd;
 721         }
 722     }
 723 
 724     @Test
 725     @IR(failOn = {IRNode.STORE_VECTOR})
 726     private static void testCMoveFGTforD(float[] a, float[] b, double[] c, double[] d, double[] r, double[] r2) {
 727         for (int i = 0; i < a.length; i++) {
 728             double cc = c[i];
 729             double dd = d[i];
 730             r2[i] = cc + dd;
 731             r[i] = (a[i] > b[i]) ? cc : dd;
 732         }
 733     }
 734 
 735     @Test
 736     @IR(failOn = {IRNode.STORE_VECTOR})
 737     private static void testCMoveDGTforI(double[] a, double[] b, int[] c, int[] d, int[] r, int[] r2) {
 738         for (int i = 0; i < a.length; i++) {
 739             int cc = c[i];
 740             int dd = d[i];
 741             r2[i] = cc + dd;
 742             r[i] = (a[i] > b[i]) ? cc : dd;
 743         }
 744     }
 745 
 746     @Test
 747     @IR(failOn = {IRNode.STORE_VECTOR})
 748     private static void testCMoveDGTforL(double[] a, double[] b, long[] c, long[] d, long[] r, long[] r2) {
 749         for (int i = 0; i < a.length; i++) {
 750             long cc = c[i];
 751             long dd = d[i];
 752             r2[i] = cc + dd;
 753             r[i] = (a[i] > b[i]) ? cc : dd;
 754         }
 755     }
 756 
 757     @Test
 758     @IR(failOn = {IRNode.STORE_VECTOR})
 759     private static void testCMoveDGTforF(double[] a, double[] b, float[] c, float[] d, float[] r, float[] r2) {
 760         for (int i = 0; i < a.length; i++) {
 761             float cc = c[i];
 762             float dd = d[i];
 763             r2[i] = cc + dd;
 764             r[i] = (a[i] > b[i]) ? cc : dd;
 765         }
 766     }
 767 
 768     @Test
 769     @IR(counts = {IRNode.LOAD_VECTOR_D, ">0",
 770                   IRNode.VECTOR_MASK_CMP_D, ">0",
 771                   IRNode.VECTOR_BLEND_D, ">0",
 772                   IRNode.STORE_VECTOR, ">0"},
 773         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 774     private static void testCMoveDGTforD(double[] a, double[] b, double[] c, double[] d, double[] r, double[] r2) {
 775         for (int i = 0; i < a.length; i++) {
 776             double cc = c[i];
 777             double dd = d[i];
 778             r2[i] = cc + dd;
 779             r[i] = (a[i] > b[i]) ? cc : dd;
 780         }
 781     }
 782 
 783     // Use some constants in the comparison
 784     @Test
 785     @IR(counts = {IRNode.LOAD_VECTOR_F, ">0",
 786                   IRNode.VECTOR_MASK_CMP_F, ">0",
 787                   IRNode.VECTOR_BLEND_F, ">0",
 788                   IRNode.STORE_VECTOR, ">0"},
 789         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 790     private static void testCMoveFGTforFCmpCon1(float a, float[] b, float[] c, float[] d, float[] r, float[] r2) {
 791         for (int i = 0; i < b.length; i++) {
 792             float cc = c[i];
 793             float dd = d[i];
 794             r2[i] = cc + dd;
 795             r[i] = (a > b[i]) ? cc : dd;
 796         }
 797     }
 798 
 799     @Test
 800     @IR(counts = {IRNode.LOAD_VECTOR_F, ">0",
 801                   IRNode.VECTOR_MASK_CMP_F, ">0",
 802                   IRNode.VECTOR_BLEND_F, ">0",
 803                   IRNode.STORE_VECTOR, ">0"},
 804         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 805     private static void testCMoveFGTforFCmpCon2(float[] a, float b, float[] c, float[] d, float[] r, float[] r2) {
 806         for (int i = 0; i < a.length; i++) {
 807             float cc = c[i];
 808             float dd = d[i];
 809             r2[i] = cc + dd;
 810             r[i] = (a[i] > b) ? cc : dd;
 811         }
 812     }
 813 
 814     // A case that is currently not supported and is not expected to vectorize
 815     @Test
 816     @IR(failOn = {IRNode.STORE_VECTOR})
 817     private static void testCMoveVDUnsupported() {
 818         double[] doublec = new double[SIZE];
 819         int seed = 1001;
 820         for (int i = 0; i < doublec.length; i++) {
 821             doublec[i] = (i % 2 == 0) ? seed + i : seed - i;
 822         }
 823     }
 824 
 825     @Warmup(0)
 826     @Run(test = {"testCMoveVFGT", "testCMoveVFLT","testCMoveVDLE", "testCMoveVDGE", "testCMoveVFEQ", "testCMoveVDNE",
 827                  "testCMoveVFGTSwap", "testCMoveVFLTSwap","testCMoveVDLESwap", "testCMoveVDGESwap",
 828                  "testCMoveFGTforFConst", "testCMoveFGEforFConst", "testCMoveFLTforFConst",
 829                  "testCMoveFLEforFConst", "testCMoveFEQforFConst", "testCMoveFNEQforFConst",
 830                  "testCMoveDGTforDConst", "testCMoveDGEforDConst", "testCMoveDLTforDConst",
 831                  "testCMoveDLEforDConst", "testCMoveDEQforDConst", "testCMoveDNEQforDConst",
 832                  "testCMoveFLTforFConstH2", "testCMoveFLEforFConstH2",
 833                  "testCMoveFYYforFConstH2", "testCMoveFXXforFConstH2",
 834                  "testCMoveDLTforDConstH2", "testCMoveDLEforDConstH2",
 835                  "testCMoveDYYforDConstH2", "testCMoveDXXforDConstH2"})
 836     private void testCMove_runner() {
 837         float[] floata = new float[SIZE];
 838         float[] floatb = new float[SIZE];
 839         float[] floatc = new float[SIZE];
 840         double[] doublea = new double[SIZE];
 841         double[] doubleb = new double[SIZE];
 842         double[] doublec = new double[SIZE];
 843 
 844         init(floata);
 845         init(floatb);
 846         init(doublea);
 847         init(doubleb);
 848 
 849         testCMoveVFGT(floata, floatb, floatc);
 850         testCMoveVDLE(doublea, doubleb, doublec);
 851         for (int i = 0; i < SIZE; i++) {
 852             Asserts.assertEquals(floatc[i], cmoveFloatGT(floata[i], floatb[i]));
 853             Asserts.assertEquals(doublec[i], cmoveDoubleLE(doublea[i], doubleb[i]));
 854         }
 855 
 856         testCMoveVFLT(floata, floatb, floatc);
 857         testCMoveVDGE(doublea, doubleb, doublec);
 858         for (int i = 0; i < SIZE; i++) {
 859             Asserts.assertEquals(floatc[i], cmoveFloatLT(floata[i], floatb[i]));
 860             Asserts.assertEquals(doublec[i], cmoveDoubleGE(doublea[i], doubleb[i]));
 861         }
 862 
 863         // Ensure we frequently have equals
 864         for (int i = 0; i < SIZE; i++) {
 865             if (i % 3 == 0) {
 866                 floatb[i] = floata[i];
 867                 doubleb[i] = doublea[i];
 868             }
 869         }
 870 
 871         testCMoveVFEQ(floata, floatb, floatc);
 872         testCMoveVDNE(doublea, doubleb, doublec);
 873         for (int i = 0; i < SIZE; i++) {
 874             Asserts.assertEquals(floatc[i], cmoveFloatEQ(floata[i], floatb[i]));
 875             Asserts.assertEquals(doublec[i], cmoveDoubleNE(doublea[i], doubleb[i]));
 876         }
 877 
 878         testCMoveVFGTSwap(floata, floatb, floatc);
 879         testCMoveVDLESwap(doublea, doubleb, doublec);
 880         for (int i = 0; i < SIZE; i++) {
 881             Asserts.assertEquals(floatc[i], cmoveFloatGTSwap(floata[i], floatb[i]));
 882             Asserts.assertEquals(doublec[i], cmoveDoubleLESwap(doublea[i], doubleb[i]));
 883         }
 884 
 885         testCMoveVFLTSwap(floata, floatb, floatc);
 886         testCMoveVDGESwap(doublea, doubleb, doublec);
 887         for (int i = 0; i < SIZE; i++) {
 888             Asserts.assertEquals(floatc[i], cmoveFloatLTSwap(floata[i], floatb[i]));
 889             Asserts.assertEquals(doublec[i], cmoveDoubleGESwap(doublea[i], doubleb[i]));
 890         }
 891 
 892         // Extensions: compare 2 values, and pick from 2 consts
 893         testCMoveFGTforFConst(floata, floatb, floatc);
 894         testCMoveDGTforDConst(doublea, doubleb, doublec);
 895         for (int i = 0; i < SIZE; i++) {
 896             Asserts.assertEquals(floatc[i], cmoveFGTforFConst(floata[i], floatb[i]));
 897             Asserts.assertEquals(doublec[i], cmoveDGTforDConst(doublea[i], doubleb[i]));
 898         }
 899 
 900         testCMoveFGEforFConst(floata, floatb, floatc);
 901         testCMoveDGEforDConst(doublea, doubleb, doublec);
 902         for (int i = 0; i < SIZE; i++) {
 903             Asserts.assertEquals(floatc[i], cmoveFGEforFConst(floata[i], floatb[i]));
 904             Asserts.assertEquals(doublec[i], cmoveDGEforDConst(doublea[i], doubleb[i]));
 905         }
 906 
 907         testCMoveFLTforFConst(floata, floatb, floatc);
 908         testCMoveDLTforDConst(doublea, doubleb, doublec);
 909         for (int i = 0; i < SIZE; i++) {
 910             Asserts.assertEquals(floatc[i], cmoveFLTforFConst(floata[i], floatb[i]));
 911             Asserts.assertEquals(doublec[i], cmoveDLTforDConst(doublea[i], doubleb[i]));
 912         }
 913 
 914         testCMoveFLEforFConst(floata, floatb, floatc);
 915         testCMoveDLEforDConst(doublea, doubleb, doublec);
 916         for (int i = 0; i < SIZE; i++) {
 917             Asserts.assertEquals(floatc[i], cmoveFLEforFConst(floata[i], floatb[i]));
 918             Asserts.assertEquals(doublec[i], cmoveDLEforDConst(doublea[i], doubleb[i]));
 919         }
 920 
 921         testCMoveFEQforFConst(floata, floatb, floatc);
 922         testCMoveDEQforDConst(doublea, doubleb, doublec);
 923         for (int i = 0; i < SIZE; i++) {
 924             Asserts.assertEquals(floatc[i], cmoveFEQforFConst(floata[i], floatb[i]));
 925             Asserts.assertEquals(doublec[i], cmoveDEQforDConst(doublea[i], doubleb[i]));
 926         }
 927 
 928         testCMoveFNEQforFConst(floata, floatb, floatc);
 929         testCMoveDNEQforDConst(doublea, doubleb, doublec);
 930         for (int i = 0; i < SIZE; i++) {
 931             Asserts.assertEquals(floatc[i], cmoveFNEQforFConst(floata[i], floatb[i]));
 932             Asserts.assertEquals(doublec[i], cmoveDNEQforDConst(doublea[i], doubleb[i]));
 933         }
 934 
 935         // Hand-unrolled (H2) examples:
 936         testCMoveFLTforFConstH2(floata, floatb, floatc);
 937         testCMoveDLTforDConstH2(doublea, doubleb, doublec);
 938         for (int i = 0; i < SIZE; i++) {
 939             Asserts.assertEquals(floatc[i], cmoveFLTforFConst(floata[i], floatb[i]));
 940             Asserts.assertEquals(doublec[i], cmoveDLTforDConst(doublea[i], doubleb[i]));
 941         }
 942 
 943         testCMoveFLEforFConstH2(floata, floatb, floatc);
 944         testCMoveDLEforDConstH2(doublea, doubleb, doublec);
 945         for (int i = 0; i < SIZE; i++) {
 946             Asserts.assertEquals(floatc[i], cmoveFLEforFConst(floata[i], floatb[i]));
 947             Asserts.assertEquals(doublec[i], cmoveDLEforDConst(doublea[i], doubleb[i]));
 948         }
 949 
 950         testCMoveFYYforFConstH2(floata, floatb, floatc);
 951         testCMoveDYYforDConstH2(doublea, doubleb, doublec);
 952         for (int i = 0; i < SIZE; i+=2) {
 953             Asserts.assertEquals(floatc[i+0], cmoveFLEforFConst(floata[i+0], floatb[i+0]));
 954             Asserts.assertEquals(doublec[i+0], cmoveDLEforDConst(doublea[i+0], doubleb[i+0]));
 955             Asserts.assertEquals(floatc[i+1], cmoveFLTforFConst(floata[i+1], floatb[i+1]));
 956             Asserts.assertEquals(doublec[i+1], cmoveDLTforDConst(doublea[i+1], doubleb[i+1]));
 957         }
 958 
 959         testCMoveFXXforFConstH2(floata, floatb, floatc);
 960         testCMoveDXXforDConstH2(doublea, doubleb, doublec);
 961         for (int i = 0; i < SIZE; i+=2) {
 962             Asserts.assertEquals(floatc[i+0], cmoveFLTforFConst(floata[i+0], floatb[i+0]));
 963             Asserts.assertEquals(doublec[i+0], cmoveDLTforDConst(doublea[i+0], doubleb[i+0]));
 964             Asserts.assertEquals(floatc[i+1], cmoveFLEforFConst(floata[i+1], floatb[i+1]));
 965             Asserts.assertEquals(doublec[i+1], cmoveDLEforDConst(doublea[i+1], doubleb[i+1]));
 966         }
 967     }
 968 
 969     @Warmup(0)
 970     @Run(test = {"testCMoveIGTforI",
 971                  "testCMoveIGTforL",
 972                  "testCMoveIGTforF",
 973                  "testCMoveIGTforD",
 974                  "testCMoveLGTforI",
 975                  "testCMoveLGTforL",
 976                  "testCMoveLGTforF",
 977                  "testCMoveLGTforD",
 978                  "testCMoveFGTforI",
 979                  "testCMoveFGTforL",
 980                  "testCMoveFGTforF",
 981                  "testCMoveFGTforD",
 982                  "testCMoveDGTforI",
 983                  "testCMoveDGTforL",
 984                  "testCMoveDGTforF",
 985                  "testCMoveDGTforD",
 986                  "testCMoveFGTforFCmpCon1",
 987                  "testCMoveFGTforFCmpCon2"})
 988     private void testCMove_runner_two() {
 989         int[] aI = new int[SIZE];
 990         int[] bI = new int[SIZE];
 991         int[] cI = new int[SIZE];
 992         int[] dI = new int[SIZE];
 993         int[] rI = new int[SIZE];
 994         long[] aL = new long[SIZE];
 995         long[] bL = new long[SIZE];
 996         long[] cL = new long[SIZE];
 997         long[] dL = new long[SIZE];
 998         long[] rL = new long[SIZE];
 999         float[] aF = new float[SIZE];
1000         float[] bF = new float[SIZE];
1001         float[] cF = new float[SIZE];
1002         float[] dF = new float[SIZE];
1003         float[] rF = new float[SIZE];
1004         double[] aD = new double[SIZE];
1005         double[] bD = new double[SIZE];
1006         double[] cD = new double[SIZE];
1007         double[] dD = new double[SIZE];
1008         double[] rD = new double[SIZE];
1009 
1010         init(aI);
1011         init(bI);
1012         init(cI);
1013         init(dI);
1014         init(aL);
1015         init(bL);
1016         init(cL);
1017         init(dL);
1018         init(aF);
1019         init(bF);
1020         init(cF);
1021         init(dF);
1022         init(aD);
1023         init(bD);
1024         init(cD);
1025         init(dD);
1026 
1027         testCMoveIGTforI(aI, bI, cI, dI, rI, rI);
1028         for (int i = 0; i < SIZE; i++) {
1029             Asserts.assertEquals(rI[i], cmoveIGTforI(aI[i], bI[i], cI[i], dI[i]));
1030         }
1031 
1032         testCMoveIGTforL(aI, bI, cL, dL, rL, rL);
1033         for (int i = 0; i < SIZE; i++) {
1034             Asserts.assertEquals(rL[i], cmoveIGTforL(aI[i], bI[i], cL[i], dL[i]));
1035         }
1036 
1037         testCMoveIGTforF(aI, bI, cF, dF, rF, rF);
1038         for (int i = 0; i < SIZE; i++) {
1039             Asserts.assertEquals(rF[i], cmoveIGTforF(aI[i], bI[i], cF[i], dF[i]));
1040         }
1041 
1042         testCMoveIGTforD(aI, bI, cD, dD, rD, rD);
1043         for (int i = 0; i < SIZE; i++) {
1044             Asserts.assertEquals(rD[i], cmoveIGTforD(aI[i], bI[i], cD[i], dD[i]));
1045         }
1046 
1047         testCMoveLGTforI(aL, bL, cI, dI, rI, rI);
1048         for (int i = 0; i < SIZE; i++) {
1049             Asserts.assertEquals(rI[i], cmoveLGTforI(aL[i], bL[i], cI[i], dI[i]));
1050         }
1051 
1052         testCMoveLGTforL(aL, bL, cL, dL, rL, rL);
1053         for (int i = 0; i < SIZE; i++) {
1054             Asserts.assertEquals(rL[i], cmoveLGTforL(aL[i], bL[i], cL[i], dL[i]));
1055         }
1056 
1057         testCMoveLGTforF(aL, bL, cF, dF, rF, rF);
1058         for (int i = 0; i < SIZE; i++) {
1059             Asserts.assertEquals(rF[i], cmoveLGTforF(aL[i], bL[i], cF[i], dF[i]));
1060         }
1061 
1062         testCMoveLGTforD(aL, bL, cD, dD, rD, rD);
1063         for (int i = 0; i < SIZE; i++) {
1064             Asserts.assertEquals(rD[i], cmoveLGTforD(aL[i], bL[i], cD[i], dD[i]));
1065         }
1066 
1067         testCMoveFGTforI(aF, bF, cI, dI, rI, rI);
1068         for (int i = 0; i < SIZE; i++) {
1069             Asserts.assertEquals(rI[i], cmoveFGTforI(aF[i], bF[i], cI[i], dI[i]));
1070         }
1071 
1072         testCMoveFGTforL(aF, bF, cL, dL, rL, rL);
1073         for (int i = 0; i < SIZE; i++) {
1074             Asserts.assertEquals(rL[i], cmoveFGTforL(aF[i], bF[i], cL[i], dL[i]));
1075         }
1076 
1077         testCMoveFGTforF(aF, bF, cF, dF, rF, rF);
1078         for (int i = 0; i < SIZE; i++) {
1079             Asserts.assertEquals(rF[i], cmoveFGTforF(aF[i], bF[i], cF[i], dF[i]));
1080         }
1081 
1082         testCMoveFGTforD(aF, bF, cD, dD, rD, rD);
1083         for (int i = 0; i < SIZE; i++) {
1084             Asserts.assertEquals(rD[i], cmoveFGTforD(aF[i], bF[i], cD[i], dD[i]));
1085         }
1086 
1087         testCMoveDGTforI(aD, bD, cI, dI, rI, rI);
1088         for (int i = 0; i < SIZE; i++) {
1089             Asserts.assertEquals(rI[i], cmoveDGTforI(aD[i], bD[i], cI[i], dI[i]));
1090         }
1091 
1092         testCMoveDGTforL(aD, bD, cL, dL, rL, rL);
1093         for (int i = 0; i < SIZE; i++) {
1094             Asserts.assertEquals(rL[i], cmoveDGTforL(aD[i], bD[i], cL[i], dL[i]));
1095         }
1096 
1097         testCMoveDGTforF(aD, bD, cF, dF, rF, rF);
1098         for (int i = 0; i < SIZE; i++) {
1099             Asserts.assertEquals(rF[i], cmoveDGTforF(aD[i], bD[i], cF[i], dF[i]));
1100         }
1101 
1102         testCMoveDGTforD(aD, bD, cD, dD, rD, rD);
1103         for (int i = 0; i < SIZE; i++) {
1104             Asserts.assertEquals(rD[i], cmoveDGTforD(aD[i], bD[i], cD[i], dD[i]));
1105         }
1106 
1107         // Use some constants/invariants in the comparison
1108         testCMoveFGTforFCmpCon1(aF[0], bF, cF, dF, rF, rF);
1109         for (int i = 0; i < SIZE; i++) {
1110             Asserts.assertEquals(rF[i], cmoveFGTforF(aF[0], bF[i], cF[i], dF[i]));
1111         }
1112 
1113         testCMoveFGTforFCmpCon2(aF, bF[0], cF, dF, rF, rF);
1114         for (int i = 0; i < SIZE; i++) {
1115             Asserts.assertEquals(rF[i], cmoveFGTforF(aF[i], bF[0], cF[i], dF[i]));
1116         }
1117     }
1118 
1119     private static void init(int[] a) {
1120         for (int i = 0; i < SIZE; i++) {
1121             a[i] = RANDOM.nextInt();
1122         }
1123     }
1124 
1125     private static void init(long[] a) {
1126         for (int i = 0; i < SIZE; i++) {
1127             a[i] = RANDOM.nextLong();
1128         }
1129     }
1130 
1131     private static void init(float[] a) {
1132         for (int i = 0; i < SIZE; i++) {
1133             a[i] = switch(RANDOM.nextInt() % 20) {
1134                 case 0  -> Float.NaN;
1135                 case 1  -> 0;
1136                 case 2  -> 1;
1137                 case 3  -> Float.POSITIVE_INFINITY;
1138                 case 4  -> Float.NEGATIVE_INFINITY;
1139                 case 5  -> Float.MAX_VALUE;
1140                 case 6  -> Float.MIN_VALUE;
1141                 case 7, 8, 9 -> RANDOM.nextFloat();
1142                 default -> Float.intBitsToFloat(RANDOM.nextInt());
1143             };
1144         }
1145     }
1146 
1147     private static void init(double[] a) {
1148         for (int i = 0; i < SIZE; i++) {
1149             a[i] = switch(RANDOM.nextInt() % 20) {
1150                 case 0  -> Double.NaN;
1151                 case 1  -> 0;
1152                 case 2  -> 1;
1153                 case 3  -> Double.POSITIVE_INFINITY;
1154                 case 4  -> Double.NEGATIVE_INFINITY;
1155                 case 5  -> Double.MAX_VALUE;
1156                 case 6  -> Double.MIN_VALUE;
1157                 case 7, 8, 9 -> RANDOM.nextDouble();
1158                 default -> Double.longBitsToDouble(RANDOM.nextLong());
1159             };
1160         }
1161     }
1162 }