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:-UseCompactObjectHeaders", "-XX:-AlignVector");
49 TestFramework.runWithFlags("-XX:+UseCMoveUnconditionally", "-XX:+UseVectorCmov",
50 "-XX:-UseCompactObjectHeaders", "-XX:+AlignVector");
51 TestFramework.runWithFlags("-XX:+UseCMoveUnconditionally", "-XX:+UseVectorCmov",
52 "-XX:+UseCompactObjectHeaders", "-XX:-AlignVector");
53 TestFramework.runWithFlags("-XX:+UseCMoveUnconditionally", "-XX:+UseVectorCmov",
54 "-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 }