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         applyIfOr = {"UseCompactObjectHeaders", "false", "AlignVector", "false"},
 412         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 413     private static void testCMoveFLTforFConstH2(float[] a, float[] b, float[] c) {
 414         for (int i = 0; i < a.length; i+=2) {
 415             c[i+0] = (a[i+0] < b[i+0]) ? 0.1f : -0.1f;
 416             c[i+1] = (a[i+1] < b[i+1]) ? 0.1f : -0.1f;
 417             // With AlignVector, we need 8-byte alignment of vector loads/stores.
 418             // UseCompactObjectHeaders=false                        UseCompactObjectHeaders=true
 419             // adr = base + 16 + 8*i      ->  always                adr = base + 12 + 8*i      ->  never
 420             // -> vectorize                                         -> no vectorization
 421         }
 422     }
 423 
 424     @Test
 425     @IR(counts = {IRNode.LOAD_VECTOR_F, ">0",
 426                   IRNode.VECTOR_MASK_CMP_F, ">0",
 427                   IRNode.VECTOR_BLEND_F, ">0",
 428                   IRNode.STORE_VECTOR, ">0"},
 429         applyIfOr = {"UseCompactObjectHeaders", "false", "AlignVector", "false"},
 430         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 431     private static void testCMoveFLEforFConstH2(float[] a, float[] b, float[] c) {
 432         for (int i = 0; i < a.length; i+=2) {
 433             c[i+0] = (a[i+0] <= b[i+0]) ? 0.1f : -0.1f;
 434             c[i+1] = (a[i+1] <= b[i+1]) ? 0.1f : -0.1f;
 435             // With AlignVector, we need 8-byte alignment of vector loads/stores.
 436             // UseCompactObjectHeaders=false                        UseCompactObjectHeaders=true
 437             // adr = base + 16 + 8*i      ->  always                adr = base + 12 + 8*i      ->  never
 438             // -> vectorize                                         -> no vectorization
 439         }
 440     }
 441 
 442     @Test
 443     @IR(counts = {IRNode.LOAD_VECTOR_F, "=0",
 444                   IRNode.VECTOR_MASK_CMP_F, "=0",
 445                   IRNode.VECTOR_BLEND_F, "=0",
 446                   IRNode.STORE_VECTOR, "=0"},
 447         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 448     private static void testCMoveFYYforFConstH2(float[] a, float[] b, float[] c) {
 449         for (int i = 0; i < a.length; i+=2) {
 450             c[i+0] = (a[i+0] <= b[i+0]) ? 0.1f : -0.1f;
 451             c[i+1] = (a[i+1] <  b[i+1]) ? 0.1f : -0.1f;
 452         }
 453     }
 454 
 455     @Test
 456     @IR(counts = {IRNode.LOAD_VECTOR_F, "=0",
 457                   IRNode.VECTOR_MASK_CMP_F, "=0",
 458                   IRNode.VECTOR_BLEND_F, "=0",
 459                   IRNode.STORE_VECTOR, "=0"},
 460         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 461     private static void testCMoveFXXforFConstH2(float[] a, float[] b, float[] c) {
 462         for (int i = 0; i < a.length; i+=2) {
 463             c[i+0] = (a[i+0] <  b[i+0]) ? 0.1f : -0.1f;
 464             c[i+1] = (a[i+1] <= b[i+1]) ? 0.1f : -0.1f;
 465         }
 466     }
 467 
 468     @Test
 469     @IR(counts = {IRNode.LOAD_VECTOR_D, ">0",
 470                   IRNode.VECTOR_MASK_CMP_D, ">0",
 471                   IRNode.VECTOR_BLEND_D, ">0",
 472                   IRNode.STORE_VECTOR, ">0"},
 473         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 474     private static void testCMoveDGTforDConst(double[] a, double[] b, double[] c) {
 475         for (int i = 0; i < a.length; i++) {
 476             c[i] = (a[i] > b[i]) ? 0.1 : -0.1;
 477         }
 478     }
 479 
 480     @Test
 481     @IR(counts = {IRNode.LOAD_VECTOR_D, ">0",
 482                   IRNode.VECTOR_MASK_CMP_D, ">0",
 483                   IRNode.VECTOR_BLEND_D, ">0",
 484                   IRNode.STORE_VECTOR, ">0"},
 485         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 486     private static void testCMoveDGEforDConst(double[] a, double[] b, double[] c) {
 487         for (int i = 0; i < a.length; i++) {
 488             c[i] = (a[i] >= b[i]) ? 0.1 : -0.1;
 489         }
 490     }
 491 
 492     @Test
 493     @IR(counts = {IRNode.LOAD_VECTOR_D, ">0",
 494                   IRNode.VECTOR_MASK_CMP_D, ">0",
 495                   IRNode.VECTOR_BLEND_D, ">0",
 496                   IRNode.STORE_VECTOR, ">0"},
 497         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 498     private static void testCMoveDLTforDConst(double[] a, double[] b, double[] c) {
 499         for (int i = 0; i < a.length; i++) {
 500             c[i] = (a[i] < b[i]) ? 0.1 : -0.1;
 501         }
 502     }
 503 
 504     @Test
 505     @IR(counts = {IRNode.LOAD_VECTOR_D, ">0",
 506                   IRNode.VECTOR_MASK_CMP_D, ">0",
 507                   IRNode.VECTOR_BLEND_D, ">0",
 508                   IRNode.STORE_VECTOR, ">0"},
 509         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 510     private static void testCMoveDLEforDConst(double[] a, double[] b, double[] c) {
 511         for (int i = 0; i < a.length; i++) {
 512             c[i] = (a[i] <= b[i]) ? 0.1 : -0.1;
 513         }
 514     }
 515 
 516     @Test
 517     @IR(counts = {IRNode.LOAD_VECTOR_D, ">0",
 518                   IRNode.VECTOR_MASK_CMP_D, ">0",
 519                   IRNode.VECTOR_BLEND_D, ">0",
 520                   IRNode.STORE_VECTOR, ">0"},
 521         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 522     private static void testCMoveDEQforDConst(double[] a, double[] b, double[] c) {
 523         for (int i = 0; i < a.length; i++) {
 524             c[i] = (a[i] == b[i]) ? 0.1 : -0.1;
 525         }
 526     }
 527 
 528     @Test
 529     @IR(counts = {IRNode.LOAD_VECTOR_D, ">0",
 530                   IRNode.VECTOR_MASK_CMP_D, ">0",
 531                   IRNode.VECTOR_BLEND_D, ">0",
 532                   IRNode.STORE_VECTOR, ">0"},
 533         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 534     private static void testCMoveDNEQforDConst(double[] a, double[] b, double[] c) {
 535         for (int i = 0; i < a.length; i++) {
 536             c[i] = (a[i] != b[i]) ? 0.1 : -0.1;
 537         }
 538     }
 539 
 540     @Test
 541     @IR(counts = {IRNode.LOAD_VECTOR_D, ">0",
 542                   IRNode.VECTOR_MASK_CMP_D, ">0",
 543                   IRNode.VECTOR_BLEND_D, ">0",
 544                   IRNode.STORE_VECTOR, ">0"},
 545         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 546     private static void testCMoveDLTforDConstH2(double[] a, double[] b, double[] c) {
 547         for (int i = 0; i < a.length; i+=2) {
 548             c[i+0] = (a[i+0] < b[i+0]) ? 0.1 : -0.1;
 549             c[i+1] = (a[i+1] < b[i+1]) ? 0.1 : -0.1;
 550         }
 551     }
 552 
 553     @Test
 554     @IR(counts = {IRNode.LOAD_VECTOR_D, ">0",
 555                   IRNode.VECTOR_MASK_CMP_D, ">0",
 556                   IRNode.VECTOR_BLEND_D, ">0",
 557                   IRNode.STORE_VECTOR, ">0"},
 558         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 559     private static void testCMoveDLEforDConstH2(double[] a, double[] b, double[] c) {
 560         for (int i = 0; i < a.length; i+=2) {
 561             c[i+0] = (a[i+0] <= b[i+0]) ? 0.1 : -0.1;
 562             c[i+1] = (a[i+1] <= b[i+1]) ? 0.1 : -0.1;
 563         }
 564     }
 565 
 566     @Test
 567     @IR(counts = {IRNode.LOAD_VECTOR_D, "=0",
 568                   IRNode.VECTOR_MASK_CMP_D, "=0",
 569                   IRNode.VECTOR_BLEND_D, "=0",
 570                   IRNode.STORE_VECTOR, "=0"},
 571         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 572     private static void testCMoveDYYforDConstH2(double[] a, double[] b, double[] c) {
 573         for (int i = 0; i < a.length; i+=2) {
 574             c[i+0] = (a[i+0] <= b[i+0]) ? 0.1 : -0.1;
 575             c[i+1] = (a[i+1] <  b[i+1]) ? 0.1 : -0.1;
 576         }
 577     }
 578 
 579     @Test
 580     @IR(counts = {IRNode.LOAD_VECTOR_D, "=0",
 581                   IRNode.VECTOR_MASK_CMP_D, "=0",
 582                   IRNode.VECTOR_BLEND_D, "=0",
 583                   IRNode.STORE_VECTOR, "=0"},
 584         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 585     private static void testCMoveDXXforDConstH2(double[] a, double[] b, double[] c) {
 586         for (int i = 0; i < a.length; i+=2) {
 587             c[i+0] = (a[i+0] <  b[i+0]) ? 0.1 : -0.1;
 588             c[i+1] = (a[i+1] <= b[i+1]) ? 0.1 : -0.1;
 589         }
 590     }
 591 
 592     // Extension: Compare 2 ILFD values, and pick from 2 ILFD values
 593     // Note:
 594     //   To guarantee that CMove is introduced, I need to perform the loads before the branch. To ensure they
 595     //   do not float down into the branches, I compute a value, and store it to r2 (same as r, except that the
 596     //   compilation does not know that).
 597     //   So far, vectorization only works for CMoveF/D, with same data-width comparison (F/I for F, D/L for D).
 598     @Test
 599     @IR(failOn = {IRNode.STORE_VECTOR})
 600     private static void testCMoveIGTforI(int[] a, int[] b, int[] c, int[] d, int[] r, int[] r2) {
 601         for (int i = 0; i < a.length; i++) {
 602             int cc = c[i];
 603             int dd = d[i];
 604             r2[i] = cc + dd;
 605             r[i] = (a[i] > b[i]) ? cc : dd;
 606         }
 607     }
 608 
 609     @Test
 610     @IR(failOn = {IRNode.STORE_VECTOR})
 611     private static void testCMoveIGTforL(int[] a, int[] b, long[] c, long[] d, long[] r, long[] r2) {
 612         for (int i = 0; i < a.length; i++) {
 613             long cc = c[i];
 614             long dd = d[i];
 615             r2[i] = cc + dd;
 616             r[i] = (a[i] > b[i]) ? cc : dd;
 617         }
 618     }
 619 
 620     @Test
 621     @IR(counts = {IRNode.LOAD_VECTOR_I,     IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0",
 622                   IRNode.LOAD_VECTOR_F,     IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0",
 623                   IRNode.VECTOR_MASK_CMP_I, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0",
 624                   IRNode.VECTOR_BLEND_F,    IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0",
 625                   IRNode.STORE_VECTOR, ">0"},
 626         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 627     private static void testCMoveIGTforF(int[] a, int[] b, float[] c, float[] d, float[] r, float[] r2) {
 628         for (int i = 0; i < a.length; i++) {
 629             float cc = c[i];
 630             float dd = d[i];
 631             r2[i] = cc + dd;
 632             r[i] = (a[i] > b[i]) ? cc : dd;
 633         }
 634     }
 635 
 636     @Test
 637     @IR(failOn = {IRNode.STORE_VECTOR})
 638     private static void testCMoveIGTforD(int[] a, int[] b, double[] c, double[] d, double[] r, double[] r2) {
 639         for (int i = 0; i < a.length; i++) {
 640             double cc = c[i];
 641             double dd = d[i];
 642             r2[i] = cc + dd;
 643             r[i] = (a[i] > b[i]) ? cc : dd;
 644         }
 645     }
 646 
 647     @Test
 648     @IR(failOn = {IRNode.STORE_VECTOR})
 649     private static void testCMoveLGTforI(long[] a, long[] b, int[] c, int[] d, int[] r, int[] r2) {
 650         for (int i = 0; i < a.length; i++) {
 651             int cc = c[i];
 652             int dd = d[i];
 653             r2[i] = cc + dd;
 654             r[i] = (a[i] > b[i]) ? cc : dd;
 655         }
 656     }
 657 
 658     @Test
 659     @IR(failOn = {IRNode.STORE_VECTOR})
 660     private static void testCMoveLGTforL(long[] a, long[] b, long[] c, long[] d, long[] r, long[] r2) {
 661         for (int i = 0; i < a.length; i++) {
 662             long cc = c[i];
 663             long dd = d[i];
 664             r2[i] = cc + dd;
 665             r[i] = (a[i] > b[i]) ? cc : dd;
 666         }
 667     }
 668 
 669     @Test
 670     @IR(failOn = {IRNode.STORE_VECTOR})
 671     private static void testCMoveLGTforF(long[] a, long[] b, float[] c, float[] d, float[] r, float[] r2) {
 672         for (int i = 0; i < a.length; i++) {
 673             float cc = c[i];
 674             float dd = d[i];
 675             r2[i] = cc + dd;
 676             r[i] = (a[i] > b[i]) ? cc : dd;
 677         }
 678     }
 679 
 680     @Test
 681     @IR(counts = {IRNode.LOAD_VECTOR_L,     IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0",
 682                   IRNode.LOAD_VECTOR_D,     IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0",
 683                   IRNode.VECTOR_MASK_CMP_L, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0",
 684                   IRNode.VECTOR_BLEND_D,    IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0",
 685                   IRNode.STORE_VECTOR, ">0"},
 686         applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true"})
 687     // Requires avx2, else L is restricted to 16 byte, and D has 32. That leads to a vector elements mismatch of 2 to 4.
 688     private static void testCMoveLGTforD(long[] a, long[] b, double[] c, double[] d, double[] r, double[] r2) {
 689         for (int i = 0; i < a.length; i++) {
 690             double cc = c[i];
 691             double dd = d[i];
 692             r2[i] = cc + dd;
 693             r[i] = (a[i] > b[i]) ? cc : dd;
 694         }
 695     }
 696 
 697     @Test
 698     @IR(failOn = {IRNode.STORE_VECTOR})
 699     private static void testCMoveFGTforI(float[] a, float[] b, int[] c, int[] d, int[] r, int[] r2) {
 700         for (int i = 0; i < a.length; i++) {
 701             int cc = c[i];
 702             int dd = d[i];
 703             r2[i] = cc + dd;
 704             r[i] = (a[i] > b[i]) ? cc : dd;
 705         }
 706     }
 707 
 708     @Test
 709     @IR(failOn = {IRNode.STORE_VECTOR})
 710     private static void testCMoveFGTforL(float[] a, float[] b, long[] c, long[] d, long[] r, long[] r2) {
 711         for (int i = 0; i < a.length; i++) {
 712             long cc = c[i];
 713             long dd = d[i];
 714             r2[i] = cc + dd;
 715             r[i] = (a[i] > b[i]) ? cc : dd;
 716         }
 717     }
 718 
 719     @Test
 720     @IR(counts = {IRNode.LOAD_VECTOR_F, ">0",
 721                   IRNode.VECTOR_MASK_CMP_F, ">0",
 722                   IRNode.VECTOR_BLEND_F, ">0",
 723                   IRNode.STORE_VECTOR, ">0"},
 724         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 725     private static void testCMoveFGTforF(float[] a, float[] b, float[] c, float[] d, float[] r, float[] r2) {
 726         for (int i = 0; i < a.length; i++) {
 727             float cc = c[i];
 728             float dd = d[i];
 729             r2[i] = cc + dd;
 730             r[i] = (a[i] > b[i]) ? cc : dd;
 731         }
 732     }
 733 
 734     @Test
 735     @IR(failOn = {IRNode.STORE_VECTOR})
 736     private static void testCMoveFGTforD(float[] a, float[] b, double[] c, double[] d, double[] r, double[] r2) {
 737         for (int i = 0; i < a.length; i++) {
 738             double cc = c[i];
 739             double dd = d[i];
 740             r2[i] = cc + dd;
 741             r[i] = (a[i] > b[i]) ? cc : dd;
 742         }
 743     }
 744 
 745     @Test
 746     @IR(failOn = {IRNode.STORE_VECTOR})
 747     private static void testCMoveDGTforI(double[] a, double[] b, int[] c, int[] d, int[] r, int[] r2) {
 748         for (int i = 0; i < a.length; i++) {
 749             int cc = c[i];
 750             int dd = d[i];
 751             r2[i] = cc + dd;
 752             r[i] = (a[i] > b[i]) ? cc : dd;
 753         }
 754     }
 755 
 756     @Test
 757     @IR(failOn = {IRNode.STORE_VECTOR})
 758     private static void testCMoveDGTforL(double[] a, double[] b, long[] c, long[] d, long[] r, long[] r2) {
 759         for (int i = 0; i < a.length; i++) {
 760             long cc = c[i];
 761             long dd = d[i];
 762             r2[i] = cc + dd;
 763             r[i] = (a[i] > b[i]) ? cc : dd;
 764         }
 765     }
 766 
 767     @Test
 768     @IR(failOn = {IRNode.STORE_VECTOR})
 769     private static void testCMoveDGTforF(double[] a, double[] b, float[] c, float[] d, float[] r, float[] r2) {
 770         for (int i = 0; i < a.length; i++) {
 771             float cc = c[i];
 772             float dd = d[i];
 773             r2[i] = cc + dd;
 774             r[i] = (a[i] > b[i]) ? cc : dd;
 775         }
 776     }
 777 
 778     @Test
 779     @IR(counts = {IRNode.LOAD_VECTOR_D, ">0",
 780                   IRNode.VECTOR_MASK_CMP_D, ">0",
 781                   IRNode.VECTOR_BLEND_D, ">0",
 782                   IRNode.STORE_VECTOR, ">0"},
 783         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 784     private static void testCMoveDGTforD(double[] a, double[] b, double[] c, double[] d, double[] r, double[] r2) {
 785         for (int i = 0; i < a.length; i++) {
 786             double cc = c[i];
 787             double dd = d[i];
 788             r2[i] = cc + dd;
 789             r[i] = (a[i] > b[i]) ? cc : dd;
 790         }
 791     }
 792 
 793     // Use some constants in the comparison
 794     @Test
 795     @IR(counts = {IRNode.LOAD_VECTOR_F, ">0",
 796                   IRNode.VECTOR_MASK_CMP_F, ">0",
 797                   IRNode.VECTOR_BLEND_F, ">0",
 798                   IRNode.STORE_VECTOR, ">0"},
 799         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 800     private static void testCMoveFGTforFCmpCon1(float a, float[] b, float[] c, float[] d, float[] r, float[] r2) {
 801         for (int i = 0; i < b.length; i++) {
 802             float cc = c[i];
 803             float dd = d[i];
 804             r2[i] = cc + dd;
 805             r[i] = (a > b[i]) ? cc : dd;
 806         }
 807     }
 808 
 809     @Test
 810     @IR(counts = {IRNode.LOAD_VECTOR_F, ">0",
 811                   IRNode.VECTOR_MASK_CMP_F, ">0",
 812                   IRNode.VECTOR_BLEND_F, ">0",
 813                   IRNode.STORE_VECTOR, ">0"},
 814         applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"})
 815     private static void testCMoveFGTforFCmpCon2(float[] a, float b, float[] c, float[] d, float[] r, float[] r2) {
 816         for (int i = 0; i < a.length; i++) {
 817             float cc = c[i];
 818             float dd = d[i];
 819             r2[i] = cc + dd;
 820             r[i] = (a[i] > b) ? cc : dd;
 821         }
 822     }
 823 
 824     // A case that is currently not supported and is not expected to vectorize
 825     @Test
 826     @IR(failOn = {IRNode.STORE_VECTOR})
 827     private static void testCMoveVDUnsupported() {
 828         double[] doublec = new double[SIZE];
 829         int seed = 1001;
 830         for (int i = 0; i < doublec.length; i++) {
 831             doublec[i] = (i % 2 == 0) ? seed + i : seed - i;
 832         }
 833     }
 834 
 835     @Warmup(0)
 836     @Run(test = {"testCMoveVFGT", "testCMoveVFLT","testCMoveVDLE", "testCMoveVDGE", "testCMoveVFEQ", "testCMoveVDNE",
 837                  "testCMoveVFGTSwap", "testCMoveVFLTSwap","testCMoveVDLESwap", "testCMoveVDGESwap",
 838                  "testCMoveFGTforFConst", "testCMoveFGEforFConst", "testCMoveFLTforFConst",
 839                  "testCMoveFLEforFConst", "testCMoveFEQforFConst", "testCMoveFNEQforFConst",
 840                  "testCMoveDGTforDConst", "testCMoveDGEforDConst", "testCMoveDLTforDConst",
 841                  "testCMoveDLEforDConst", "testCMoveDEQforDConst", "testCMoveDNEQforDConst",
 842                  "testCMoveFLTforFConstH2", "testCMoveFLEforFConstH2",
 843                  "testCMoveFYYforFConstH2", "testCMoveFXXforFConstH2",
 844                  "testCMoveDLTforDConstH2", "testCMoveDLEforDConstH2",
 845                  "testCMoveDYYforDConstH2", "testCMoveDXXforDConstH2"})
 846     private void testCMove_runner() {
 847         float[] floata = new float[SIZE];
 848         float[] floatb = new float[SIZE];
 849         float[] floatc = new float[SIZE];
 850         double[] doublea = new double[SIZE];
 851         double[] doubleb = new double[SIZE];
 852         double[] doublec = new double[SIZE];
 853 
 854         init(floata);
 855         init(floatb);
 856         init(doublea);
 857         init(doubleb);
 858 
 859         testCMoveVFGT(floata, floatb, floatc);
 860         testCMoveVDLE(doublea, doubleb, doublec);
 861         for (int i = 0; i < SIZE; i++) {
 862             Asserts.assertEquals(floatc[i], cmoveFloatGT(floata[i], floatb[i]));
 863             Asserts.assertEquals(doublec[i], cmoveDoubleLE(doublea[i], doubleb[i]));
 864         }
 865 
 866         testCMoveVFLT(floata, floatb, floatc);
 867         testCMoveVDGE(doublea, doubleb, doublec);
 868         for (int i = 0; i < SIZE; i++) {
 869             Asserts.assertEquals(floatc[i], cmoveFloatLT(floata[i], floatb[i]));
 870             Asserts.assertEquals(doublec[i], cmoveDoubleGE(doublea[i], doubleb[i]));
 871         }
 872 
 873         // Ensure we frequently have equals
 874         for (int i = 0; i < SIZE; i++) {
 875             if (i % 3 == 0) {
 876                 floatb[i] = floata[i];
 877                 doubleb[i] = doublea[i];
 878             }
 879         }
 880 
 881         testCMoveVFEQ(floata, floatb, floatc);
 882         testCMoveVDNE(doublea, doubleb, doublec);
 883         for (int i = 0; i < SIZE; i++) {
 884             Asserts.assertEquals(floatc[i], cmoveFloatEQ(floata[i], floatb[i]));
 885             Asserts.assertEquals(doublec[i], cmoveDoubleNE(doublea[i], doubleb[i]));
 886         }
 887 
 888         testCMoveVFGTSwap(floata, floatb, floatc);
 889         testCMoveVDLESwap(doublea, doubleb, doublec);
 890         for (int i = 0; i < SIZE; i++) {
 891             Asserts.assertEquals(floatc[i], cmoveFloatGTSwap(floata[i], floatb[i]));
 892             Asserts.assertEquals(doublec[i], cmoveDoubleLESwap(doublea[i], doubleb[i]));
 893         }
 894 
 895         testCMoveVFLTSwap(floata, floatb, floatc);
 896         testCMoveVDGESwap(doublea, doubleb, doublec);
 897         for (int i = 0; i < SIZE; i++) {
 898             Asserts.assertEquals(floatc[i], cmoveFloatLTSwap(floata[i], floatb[i]));
 899             Asserts.assertEquals(doublec[i], cmoveDoubleGESwap(doublea[i], doubleb[i]));
 900         }
 901 
 902         // Extensions: compare 2 values, and pick from 2 consts
 903         testCMoveFGTforFConst(floata, floatb, floatc);
 904         testCMoveDGTforDConst(doublea, doubleb, doublec);
 905         for (int i = 0; i < SIZE; i++) {
 906             Asserts.assertEquals(floatc[i], cmoveFGTforFConst(floata[i], floatb[i]));
 907             Asserts.assertEquals(doublec[i], cmoveDGTforDConst(doublea[i], doubleb[i]));
 908         }
 909 
 910         testCMoveFGEforFConst(floata, floatb, floatc);
 911         testCMoveDGEforDConst(doublea, doubleb, doublec);
 912         for (int i = 0; i < SIZE; i++) {
 913             Asserts.assertEquals(floatc[i], cmoveFGEforFConst(floata[i], floatb[i]));
 914             Asserts.assertEquals(doublec[i], cmoveDGEforDConst(doublea[i], doubleb[i]));
 915         }
 916 
 917         testCMoveFLTforFConst(floata, floatb, floatc);
 918         testCMoveDLTforDConst(doublea, doubleb, doublec);
 919         for (int i = 0; i < SIZE; i++) {
 920             Asserts.assertEquals(floatc[i], cmoveFLTforFConst(floata[i], floatb[i]));
 921             Asserts.assertEquals(doublec[i], cmoveDLTforDConst(doublea[i], doubleb[i]));
 922         }
 923 
 924         testCMoveFLEforFConst(floata, floatb, floatc);
 925         testCMoveDLEforDConst(doublea, doubleb, doublec);
 926         for (int i = 0; i < SIZE; i++) {
 927             Asserts.assertEquals(floatc[i], cmoveFLEforFConst(floata[i], floatb[i]));
 928             Asserts.assertEquals(doublec[i], cmoveDLEforDConst(doublea[i], doubleb[i]));
 929         }
 930 
 931         testCMoveFEQforFConst(floata, floatb, floatc);
 932         testCMoveDEQforDConst(doublea, doubleb, doublec);
 933         for (int i = 0; i < SIZE; i++) {
 934             Asserts.assertEquals(floatc[i], cmoveFEQforFConst(floata[i], floatb[i]));
 935             Asserts.assertEquals(doublec[i], cmoveDEQforDConst(doublea[i], doubleb[i]));
 936         }
 937 
 938         testCMoveFNEQforFConst(floata, floatb, floatc);
 939         testCMoveDNEQforDConst(doublea, doubleb, doublec);
 940         for (int i = 0; i < SIZE; i++) {
 941             Asserts.assertEquals(floatc[i], cmoveFNEQforFConst(floata[i], floatb[i]));
 942             Asserts.assertEquals(doublec[i], cmoveDNEQforDConst(doublea[i], doubleb[i]));
 943         }
 944 
 945         // Hand-unrolled (H2) examples:
 946         testCMoveFLTforFConstH2(floata, floatb, floatc);
 947         testCMoveDLTforDConstH2(doublea, doubleb, doublec);
 948         for (int i = 0; i < SIZE; i++) {
 949             Asserts.assertEquals(floatc[i], cmoveFLTforFConst(floata[i], floatb[i]));
 950             Asserts.assertEquals(doublec[i], cmoveDLTforDConst(doublea[i], doubleb[i]));
 951         }
 952 
 953         testCMoveFLEforFConstH2(floata, floatb, floatc);
 954         testCMoveDLEforDConstH2(doublea, doubleb, doublec);
 955         for (int i = 0; i < SIZE; i++) {
 956             Asserts.assertEquals(floatc[i], cmoveFLEforFConst(floata[i], floatb[i]));
 957             Asserts.assertEquals(doublec[i], cmoveDLEforDConst(doublea[i], doubleb[i]));
 958         }
 959 
 960         testCMoveFYYforFConstH2(floata, floatb, floatc);
 961         testCMoveDYYforDConstH2(doublea, doubleb, doublec);
 962         for (int i = 0; i < SIZE; i+=2) {
 963             Asserts.assertEquals(floatc[i+0], cmoveFLEforFConst(floata[i+0], floatb[i+0]));
 964             Asserts.assertEquals(doublec[i+0], cmoveDLEforDConst(doublea[i+0], doubleb[i+0]));
 965             Asserts.assertEquals(floatc[i+1], cmoveFLTforFConst(floata[i+1], floatb[i+1]));
 966             Asserts.assertEquals(doublec[i+1], cmoveDLTforDConst(doublea[i+1], doubleb[i+1]));
 967         }
 968 
 969         testCMoveFXXforFConstH2(floata, floatb, floatc);
 970         testCMoveDXXforDConstH2(doublea, doubleb, doublec);
 971         for (int i = 0; i < SIZE; i+=2) {
 972             Asserts.assertEquals(floatc[i+0], cmoveFLTforFConst(floata[i+0], floatb[i+0]));
 973             Asserts.assertEquals(doublec[i+0], cmoveDLTforDConst(doublea[i+0], doubleb[i+0]));
 974             Asserts.assertEquals(floatc[i+1], cmoveFLEforFConst(floata[i+1], floatb[i+1]));
 975             Asserts.assertEquals(doublec[i+1], cmoveDLEforDConst(doublea[i+1], doubleb[i+1]));
 976         }
 977     }
 978 
 979     @Warmup(0)
 980     @Run(test = {"testCMoveIGTforI",
 981                  "testCMoveIGTforL",
 982                  "testCMoveIGTforF",
 983                  "testCMoveIGTforD",
 984                  "testCMoveLGTforI",
 985                  "testCMoveLGTforL",
 986                  "testCMoveLGTforF",
 987                  "testCMoveLGTforD",
 988                  "testCMoveFGTforI",
 989                  "testCMoveFGTforL",
 990                  "testCMoveFGTforF",
 991                  "testCMoveFGTforD",
 992                  "testCMoveDGTforI",
 993                  "testCMoveDGTforL",
 994                  "testCMoveDGTforF",
 995                  "testCMoveDGTforD",
 996                  "testCMoveFGTforFCmpCon1",
 997                  "testCMoveFGTforFCmpCon2"})
 998     private void testCMove_runner_two() {
 999         int[] aI = new int[SIZE];
1000         int[] bI = new int[SIZE];
1001         int[] cI = new int[SIZE];
1002         int[] dI = new int[SIZE];
1003         int[] rI = new int[SIZE];
1004         long[] aL = new long[SIZE];
1005         long[] bL = new long[SIZE];
1006         long[] cL = new long[SIZE];
1007         long[] dL = new long[SIZE];
1008         long[] rL = new long[SIZE];
1009         float[] aF = new float[SIZE];
1010         float[] bF = new float[SIZE];
1011         float[] cF = new float[SIZE];
1012         float[] dF = new float[SIZE];
1013         float[] rF = new float[SIZE];
1014         double[] aD = new double[SIZE];
1015         double[] bD = new double[SIZE];
1016         double[] cD = new double[SIZE];
1017         double[] dD = new double[SIZE];
1018         double[] rD = new double[SIZE];
1019 
1020         init(aI);
1021         init(bI);
1022         init(cI);
1023         init(dI);
1024         init(aL);
1025         init(bL);
1026         init(cL);
1027         init(dL);
1028         init(aF);
1029         init(bF);
1030         init(cF);
1031         init(dF);
1032         init(aD);
1033         init(bD);
1034         init(cD);
1035         init(dD);
1036 
1037         testCMoveIGTforI(aI, bI, cI, dI, rI, rI);
1038         for (int i = 0; i < SIZE; i++) {
1039             Asserts.assertEquals(rI[i], cmoveIGTforI(aI[i], bI[i], cI[i], dI[i]));
1040         }
1041 
1042         testCMoveIGTforL(aI, bI, cL, dL, rL, rL);
1043         for (int i = 0; i < SIZE; i++) {
1044             Asserts.assertEquals(rL[i], cmoveIGTforL(aI[i], bI[i], cL[i], dL[i]));
1045         }
1046 
1047         testCMoveIGTforF(aI, bI, cF, dF, rF, rF);
1048         for (int i = 0; i < SIZE; i++) {
1049             Asserts.assertEquals(rF[i], cmoveIGTforF(aI[i], bI[i], cF[i], dF[i]));
1050         }
1051 
1052         testCMoveIGTforD(aI, bI, cD, dD, rD, rD);
1053         for (int i = 0; i < SIZE; i++) {
1054             Asserts.assertEquals(rD[i], cmoveIGTforD(aI[i], bI[i], cD[i], dD[i]));
1055         }
1056 
1057         testCMoveLGTforI(aL, bL, cI, dI, rI, rI);
1058         for (int i = 0; i < SIZE; i++) {
1059             Asserts.assertEquals(rI[i], cmoveLGTforI(aL[i], bL[i], cI[i], dI[i]));
1060         }
1061 
1062         testCMoveLGTforL(aL, bL, cL, dL, rL, rL);
1063         for (int i = 0; i < SIZE; i++) {
1064             Asserts.assertEquals(rL[i], cmoveLGTforL(aL[i], bL[i], cL[i], dL[i]));
1065         }
1066 
1067         testCMoveLGTforF(aL, bL, cF, dF, rF, rF);
1068         for (int i = 0; i < SIZE; i++) {
1069             Asserts.assertEquals(rF[i], cmoveLGTforF(aL[i], bL[i], cF[i], dF[i]));
1070         }
1071 
1072         testCMoveLGTforD(aL, bL, cD, dD, rD, rD);
1073         for (int i = 0; i < SIZE; i++) {
1074             Asserts.assertEquals(rD[i], cmoveLGTforD(aL[i], bL[i], cD[i], dD[i]));
1075         }
1076 
1077         testCMoveFGTforI(aF, bF, cI, dI, rI, rI);
1078         for (int i = 0; i < SIZE; i++) {
1079             Asserts.assertEquals(rI[i], cmoveFGTforI(aF[i], bF[i], cI[i], dI[i]));
1080         }
1081 
1082         testCMoveFGTforL(aF, bF, cL, dL, rL, rL);
1083         for (int i = 0; i < SIZE; i++) {
1084             Asserts.assertEquals(rL[i], cmoveFGTforL(aF[i], bF[i], cL[i], dL[i]));
1085         }
1086 
1087         testCMoveFGTforF(aF, bF, cF, dF, rF, rF);
1088         for (int i = 0; i < SIZE; i++) {
1089             Asserts.assertEquals(rF[i], cmoveFGTforF(aF[i], bF[i], cF[i], dF[i]));
1090         }
1091 
1092         testCMoveFGTforD(aF, bF, cD, dD, rD, rD);
1093         for (int i = 0; i < SIZE; i++) {
1094             Asserts.assertEquals(rD[i], cmoveFGTforD(aF[i], bF[i], cD[i], dD[i]));
1095         }
1096 
1097         testCMoveDGTforI(aD, bD, cI, dI, rI, rI);
1098         for (int i = 0; i < SIZE; i++) {
1099             Asserts.assertEquals(rI[i], cmoveDGTforI(aD[i], bD[i], cI[i], dI[i]));
1100         }
1101 
1102         testCMoveDGTforL(aD, bD, cL, dL, rL, rL);
1103         for (int i = 0; i < SIZE; i++) {
1104             Asserts.assertEquals(rL[i], cmoveDGTforL(aD[i], bD[i], cL[i], dL[i]));
1105         }
1106 
1107         testCMoveDGTforF(aD, bD, cF, dF, rF, rF);
1108         for (int i = 0; i < SIZE; i++) {
1109             Asserts.assertEquals(rF[i], cmoveDGTforF(aD[i], bD[i], cF[i], dF[i]));
1110         }
1111 
1112         testCMoveDGTforD(aD, bD, cD, dD, rD, rD);
1113         for (int i = 0; i < SIZE; i++) {
1114             Asserts.assertEquals(rD[i], cmoveDGTforD(aD[i], bD[i], cD[i], dD[i]));
1115         }
1116 
1117         // Use some constants/invariants in the comparison
1118         testCMoveFGTforFCmpCon1(aF[0], bF, cF, dF, rF, rF);
1119         for (int i = 0; i < SIZE; i++) {
1120             Asserts.assertEquals(rF[i], cmoveFGTforF(aF[0], bF[i], cF[i], dF[i]));
1121         }
1122 
1123         testCMoveFGTforFCmpCon2(aF, bF[0], cF, dF, rF, rF);
1124         for (int i = 0; i < SIZE; i++) {
1125             Asserts.assertEquals(rF[i], cmoveFGTforF(aF[i], bF[0], cF[i], dF[i]));
1126         }
1127     }
1128 
1129     private static void init(int[] a) {
1130         for (int i = 0; i < SIZE; i++) {
1131             a[i] = RANDOM.nextInt();
1132         }
1133     }
1134 
1135     private static void init(long[] a) {
1136         for (int i = 0; i < SIZE; i++) {
1137             a[i] = RANDOM.nextLong();
1138         }
1139     }
1140 
1141     private static void init(float[] a) {
1142         for (int i = 0; i < SIZE; i++) {
1143             a[i] = switch(RANDOM.nextInt() % 20) {
1144                 case 0  -> Float.NaN;
1145                 case 1  -> 0;
1146                 case 2  -> 1;
1147                 case 3  -> Float.POSITIVE_INFINITY;
1148                 case 4  -> Float.NEGATIVE_INFINITY;
1149                 case 5  -> Float.MAX_VALUE;
1150                 case 6  -> Float.MIN_VALUE;
1151                 case 7, 8, 9 -> RANDOM.nextFloat();
1152                 default -> Float.intBitsToFloat(RANDOM.nextInt());
1153             };
1154         }
1155     }
1156 
1157     private static void init(double[] a) {
1158         for (int i = 0; i < SIZE; i++) {
1159             a[i] = switch(RANDOM.nextInt() % 20) {
1160                 case 0  -> Double.NaN;
1161                 case 1  -> 0;
1162                 case 2  -> 1;
1163                 case 3  -> Double.POSITIVE_INFINITY;
1164                 case 4  -> Double.NEGATIVE_INFINITY;
1165                 case 5  -> Double.MAX_VALUE;
1166                 case 6  -> Double.MIN_VALUE;
1167                 case 7, 8, 9 -> RANDOM.nextDouble();
1168                 default -> Double.longBitsToDouble(RANDOM.nextLong());
1169             };
1170         }
1171     }
1172 }