1 /*
  2  * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  */
 23 
 24 package compiler.c2.irTests;
 25 
 26 import jdk.test.lib.Asserts;
 27 import compiler.lib.ir_framework.*;
 28 import java.util.Random;
 29 import jdk.test.lib.Utils;
 30 
 31 /*
 32  * @test
 33  * @bug 8324655 8329797
 34  * @key randomness
 35  * @summary Test that if expressions are properly folded into min/max nodes
 36  * @requires os.arch != "riscv64"
 37  * @library /test/lib /
 38  * @run driver compiler.c2.irTests.TestIfMinMax
 39  */
 40 public class TestIfMinMax {
 41     private static final Random RANDOM = Utils.getRandomInstance();
 42 
 43     public static void main(String[] args) {
 44         TestFramework.run();
 45     }
 46 
 47     @Test
 48     @IR(failOn = { IRNode.IF }, counts = { IRNode.MIN_I, "1" })
 49     public int testMinI1(int a, int b) {
 50         return a < b ? a : b;
 51     }
 52 
 53     @Test
 54     @IR(failOn = { IRNode.IF }, counts = { IRNode.MIN_I, "1" })
 55     public int testMinI2(int a, int b) {
 56         return a > b ? b : a;
 57     }
 58 
 59     @Test
 60     @IR(failOn = { IRNode.IF }, counts = { IRNode.MAX_I, "1" })
 61     public int testMaxI1(int a, int b) {
 62         return a > b ? a : b;
 63     }
 64 
 65     @Test
 66     @IR(failOn = { IRNode.IF }, counts = { IRNode.MAX_I, "1" })
 67     public int testMaxI2(int a, int b) {
 68         return a < b ? b : a;
 69     }
 70 
 71     @Test
 72     @IR(failOn = { IRNode.IF }, counts = { IRNode.MIN_I, "1" })
 73     public int testMinI1E(int a, int b) {
 74         return a <= b ? a : b;
 75     }
 76 
 77     @Test
 78     @IR(failOn = { IRNode.IF }, counts = { IRNode.MIN_I, "1" })
 79     public int testMinI2E(int a, int b) {
 80         return a >= b ? b : a;
 81     }
 82 
 83     @Test
 84     @IR(failOn = { IRNode.IF }, counts = { IRNode.MAX_I, "1" })
 85     public int testMaxI1E(int a, int b) {
 86         return a >= b ? a : b;
 87     }
 88 
 89     @Test
 90     @IR(failOn = { IRNode.IF }, counts = { IRNode.MAX_I, "1" })
 91     public int testMaxI2E(int a, int b) {
 92         return a <= b ? b : a;
 93     }
 94 
 95     @Test
 96     @IR(phase = { CompilePhase.BEFORE_MACRO_EXPANSION }, failOn = { IRNode.IF }, counts = { IRNode.MIN_L, "1" })
 97     public long testMinL1(long a, long b) {
 98         return a < b ? a : b;
 99     }
100 
101     @Test
102     @IR(phase = { CompilePhase.BEFORE_MACRO_EXPANSION }, failOn = { IRNode.IF }, counts = { IRNode.MIN_L, "1" })
103     public long testMinL2(long a, long b) {
104         return a > b ? b : a;
105     }
106 
107     @Test
108     @IR(phase = { CompilePhase.BEFORE_MACRO_EXPANSION }, failOn = { IRNode.IF }, counts = { IRNode.MAX_L, "1" })
109     public long testMaxL1(long a, long b) {
110         return a > b ? a : b;
111     }
112 
113     @Test
114     @IR(phase = { CompilePhase.BEFORE_MACRO_EXPANSION }, failOn = { IRNode.IF }, counts = { IRNode.MAX_L, "1" })
115     public long testMaxL2(long a, long b) {
116         return a < b ? b : a;
117     }
118 
119     @Test
120     @IR(phase = { CompilePhase.BEFORE_MACRO_EXPANSION }, failOn = { IRNode.IF }, counts = { IRNode.MIN_L, "1" })
121     public long testMinL1E(long a, long b) {
122         return a <= b ? a : b;
123     }
124 
125     @Test
126     @IR(phase = { CompilePhase.BEFORE_MACRO_EXPANSION }, failOn = { IRNode.IF }, counts = { IRNode.MIN_L, "1" })
127     public long testMinL2E(long a, long b) {
128         return a >= b ? b : a;
129     }
130 
131     @Test
132     @IR(phase = { CompilePhase.BEFORE_MACRO_EXPANSION }, failOn = { IRNode.IF }, counts = { IRNode.MAX_L, "1" })
133     public long testMaxL1E(long a, long b) {
134         return a >= b ? a : b;
135     }
136 
137     @Test
138     @IR(phase = { CompilePhase.BEFORE_MACRO_EXPANSION }, failOn = { IRNode.IF }, counts = { IRNode.MAX_L, "1" })
139     public long testMaxL2E(long a, long b) {
140         return a <= b ? b : a;
141     }
142 
143     public class Dummy {
144         long l;
145         public Dummy(long l) { this.l = l; }
146     }
147 
148     @Setup
149     Object[] setupDummyArray() {
150         Dummy[] arr = new Dummy[512];
151         for (int i = 0; i < 512; i++) {
152             arr[i] = new Dummy(RANDOM.nextLong());
153         }
154         return new Object[] { arr };
155     }
156 
157     @Test
158     @Arguments(setup = "setupDummyArray")
159     @IR(failOn = { IRNode.MAX_L })
160     public long testMaxLAndBarrierInLoop(Dummy[] arr) {
161         long result = 0;
162         for (int i = 0; i < arr.length; ++i) {
163             result += Math.max(arr[i].l, 1);
164         }
165         return result;
166     }
167 
168     @Test
169     @Arguments(setup = "setupDummyArray")
170     @IR(failOn = { IRNode.MIN_L })
171     public long testMinLAndBarrierInLoop(Dummy[] arr) {
172         long result = 0;
173         for (int i = 0; i < arr.length; ++i) {
174             result += Math.min(arr[i].l, 1);
175         }
176         return result;
177     }
178 
179     @Setup
180     static Object[] setupIntArrays() {
181         int[] a = new int[512];
182         int[] b = new int[512];
183 
184         // Fill from 1 to 50
185         for (int i = 0; i < 50; i++) {
186             a[i] = i + 1;
187             b[i] = 1;
188         }
189 
190         // Fill from -1 to -50
191         for (int i = 50; i < 100; i++) {
192             a[i] = -(i - 49);
193             b[i] = 1;
194         }
195 
196         for (int i = 100; i < 512; i++) {
197             a[i] = RANDOM.nextInt();
198             b[i] = 1;
199         }
200 
201         return new Object[] { a, b };
202     }
203 
204     @Setup
205     static Object[] setupLongArrays() {
206         long[] a = new long[512];
207         long[] b = new long[512];
208 
209         // Fill from 1 to 50
210         for (int i = 0; i < 50; i++) {
211             a[i] = i + 1;
212             b[i] = 1;
213         }
214 
215         // Fill from -1 to -50
216         for (int i = 50; i < 100; i++) {
217             a[i] = -(i - 49);
218             b[i] = 1;
219         }
220 
221         for (int i = 100; i < 512; i++) {
222             a[i] = RANDOM.nextLong();
223             b[i] = 1;
224         }
225 
226         return new Object[] { a, b };
227     }
228 
229     @Test
230     @IR(applyIf = { "SuperWordReductions", "true" },
231         applyIfCPUFeatureOr = { "sse4.1", "true" , "asimd" , "true"},
232         counts = { IRNode.MAX_REDUCTION_V, "> 0" })
233     @Arguments(setup = "setupIntArrays")
234     public Object[] testMaxIntReduction(int[] a, int[] b) {
235         int r = 0;
236         for (int i = 0; i < a.length; i++) {
237             int aI = a[i] * b[i];
238 
239             r = aI > r ? aI : r;
240         }
241 
242         return new Object[] { a, b, r };
243     }
244 
245     @Check(test = "testMaxIntReduction")
246     public void checkTestMaxIntReduction(Object[] vals) {
247         int[] a = (int[]) vals[0];
248         int[] b = (int[]) vals[1];
249         int testRet = (int) vals[2];
250 
251         int r = 0;
252         for (int i = 0; i < a.length; i++) {
253             int aI = a[i] * b[i];
254 
255             r = aI > r ? aI : r;
256         }
257 
258         if (r != testRet) {
259             throw new IllegalStateException("Int max reduction test failed: expected " + testRet + " but got " + r);
260         }
261     }
262 
263     @Test
264     @IR(applyIf = { "SuperWordReductions", "true" },
265         applyIfCPUFeatureOr = { "sse4.1", "true" , "asimd" , "true"},
266         counts = { IRNode.MIN_REDUCTION_V, "> 0" })
267     @Arguments(setup = "setupIntArrays")
268     public Object[] testMinIntReduction(int[] a, int[] b) {
269         int r = 0;
270 
271         for (int i = 0; i < a.length; i++) {
272             int aI = a[i] * b[i];
273 
274             r = aI < r ? aI : r;
275         }
276 
277         return new Object[] { a, b, r };
278     }
279 
280     @Check(test = "testMinIntReduction")
281     public void checkTestMinIntReduction(Object[] vals) {
282         int[] a = (int[]) vals[0];
283         int[] b = (int[]) vals[1];
284         int testRet = (int) vals[2];
285 
286         int r = 0;
287         for (int i = 0; i < a.length; i++) {
288             int aI = a[i] * b[i];
289 
290             r = aI < r ? aI : r;
291         }
292 
293         if (r != testRet) {
294             throw new IllegalStateException("Int min reduction test failed: expected " + testRet + " but got " + r);
295         }
296     }
297 
298     @Test
299     @IR(applyIf = { "SuperWordReductions", "true" },
300         applyIfCPUFeatureOr = { "avx512", "true" },
301         counts = { IRNode.MAX_REDUCTION_V, "> 0" })
302     @Arguments(setup = "setupLongArrays")
303     public Object[] testMaxLongReduction(long[] a, long[] b) {
304         long r = 0;
305 
306         for (int i = 0; i < a.length; i++) {
307             long aI = a[i] * b[i];
308 
309             r = aI > r ? aI : r;
310         }
311 
312         return new Object[] { a, b, r };
313     }
314 
315     @Check(test = "testMaxLongReduction")
316     public void checkTestMaxLongReduction(Object[] vals) {
317         long[] a = (long[]) vals[0];
318         long[] b = (long[]) vals[1];
319         long testRet = (long) vals[2];
320 
321         long r = 0;
322         for (int i = 0; i < a.length; i++) {
323             long aI = a[i] * b[i];
324 
325             r = aI > r ? aI : r;
326         }
327 
328         if (r != testRet) {
329             throw new IllegalStateException("Long max reduction test failed: expected " + testRet + " but got " + r);
330         }
331     }
332 
333     @Test
334     @IR(applyIf = { "SuperWordReductions", "true" },
335         applyIfCPUFeatureOr = { "avx512", "true" },
336         counts = { IRNode.MIN_REDUCTION_V, "> 0" })
337     @Arguments(setup = "setupLongArrays")
338     public Object[] testMinLongReduction(long[] a, long[] b) {
339         long r = 0;
340 
341         for (int i = 0; i < a.length; i++) {
342             long aI = a[i] * b[i];
343 
344             r = aI < r ? aI : r;
345         }
346 
347         return new Object[] { a, b, r };
348     }
349 
350     @Check(test = "testMinLongReduction")
351     public void checkTestMinLongReduction(Object[] vals) {
352         long[] a = (long[]) vals[0];
353         long[] b = (long[]) vals[1];
354         long testRet = (long) vals[2];
355 
356         long r = 0;
357         for (int i = 0; i < a.length; i++) {
358             long aI = a[i] * b[i];
359 
360             r = aI < r ? aI : r;
361         }
362 
363         if (r != testRet) {
364             throw new IllegalStateException("Long min reduction test failed: expected " + testRet + " but got " + r);
365         }
366     }
367 
368     @Test
369     @IR(applyIfCPUFeatureOr = { "sse4.1", "true" , "asimd" , "true"},
370         counts = { IRNode.MAX_VI, "> 0" })
371     @Arguments(setup = "setupIntArrays")
372     public Object[] testMaxIntVector(int[] a, int[] b) {
373         int[] r = new int[a.length];
374 
375         for (int i = 0; i < a.length; i++) {
376             int aI = a[i];
377             int bI = b[i];
378 
379             r[i] = aI > bI ? aI : bI;
380         }
381 
382         return new Object[] { a, b, r };
383     }
384 
385     @Check(test = "testMaxIntVector")
386     public void checkTestMaxIntVector(Object[] vals) {
387         int[] a = (int[]) vals[0];
388         int[] b = (int[]) vals[1];
389         int[] testRet = (int[]) vals[2];
390 
391         for (int i = 0; i < a.length; i++) {
392             int aI = a[i];
393             int bI = b[i];
394 
395             int r = aI > bI ? aI : bI;
396 
397             if (r != testRet[i]) {
398                 throw new IllegalStateException("Int max vectorization test failed: expected " + testRet + " but got " + r);
399             }
400         }
401     }
402 
403     @Test
404     @IR(applyIfCPUFeatureOr = { "sse4.1", "true" , "asimd" , "true"},
405         counts = { IRNode.MIN_VI, "> 0" })
406     @Arguments(setup = "setupIntArrays")
407     public Object[] testMinIntVector(int[] a, int[] b) {
408         int[] r = new int[a.length];
409 
410         for (int i = 0; i < a.length; i++) {
411             int aI = a[i];
412             int bI = b[i];
413 
414             r[i] = aI < bI ? aI : bI;
415         }
416 
417         return new Object[] { a, b, r };
418     }
419 
420     @Check(test = "testMinIntVector")
421     public void checkTestMinIntVector(Object[] vals) {
422         int[] a = (int[]) vals[0];
423         int[] b = (int[]) vals[1];
424         int[] testRet = (int[]) vals[2];
425 
426         for (int i = 0; i < a.length; i++) {
427             int aI = a[i];
428             int bI = b[i];
429 
430             int r = aI < bI ? aI : bI;
431 
432             if (r != testRet[i]) {
433                 throw new IllegalStateException("Int min vectorization test failed: expected " + testRet + " but got " + r);
434             }
435         }
436     }
437 
438     @Test
439     @IR(applyIfCPUFeatureOr = { "sse4.1", "true" , "asimd" , "true"},
440         counts = { IRNode.MAX_VL, "> 0" })
441     @Arguments(setup = "setupLongArrays")
442     public Object[] testMaxLongVector(long[] a, long[] b) {
443         long[] r = new long[a.length];
444 
445         for (int i = 0; i < a.length; i++) {
446             long aI = a[i];
447             long bI = b[i];
448 
449             r[i] = aI > bI ? aI : bI;
450         }
451 
452         return new Object[] { a, b, r };
453     }
454 
455     @Check(test = "testMaxLongVector")
456     public void checkTestMaxLongVector(Object[] vals) {
457         long[] a = (long[]) vals[0];
458         long[] b = (long[]) vals[1];
459         long[] testRet = (long[]) vals[2];
460 
461         for (int i = 0; i < a.length; i++) {
462             long aI = a[i];
463             long bI = b[i];
464 
465             long r = aI > bI ? aI : bI;
466 
467             if (r != testRet[i]) {
468                 throw new IllegalStateException("Long max vectorization test failed: expected " + testRet + " but got " + r);
469             }
470         }
471     }
472 
473     @Test
474     @IR(applyIfCPUFeatureOr = { "sse4.1", "true" , "asimd" , "true"},
475         counts = { IRNode.MIN_VL, "> 0" })
476     @Arguments(setup = "setupLongArrays")
477     public Object[] testMinLongVector(long[] a, long[] b) {
478         long[] r = new long[a.length];
479 
480         for (int i = 0; i < a.length; i++) {
481             long aI = a[i];
482             long bI = b[i];
483 
484             r[i] = aI < bI ? aI : bI;
485         }
486 
487         return new Object[] { a, b, r };
488     }
489 
490     @Check(test = "testMinLongVector")
491     public void checkTestMinLongVector(Object[] vals) {
492         long[] a = (long[]) vals[0];
493         long[] b = (long[]) vals[1];
494         long[] testRet = (long[]) vals[2];
495 
496         for (int i = 0; i < a.length; i++) {
497             long aI = a[i];
498             long bI = b[i];
499 
500             long r = aI < bI ? aI : bI;
501 
502             if (r != testRet[i]) {
503                 throw new IllegalStateException("Long min vectorization test failed: expected " + testRet + " but got " + r);
504             }
505         }
506     }
507 
508     @Run(test = { "testMinI1", "testMinI2", "testMaxI1", "testMaxI2", "testMinI1E", "testMinI2E", "testMaxI1E", "testMaxI2E" })
509     public void runTestIntegers() {
510         testIntegers(10, 20);
511         testIntegers(20, 10);
512         testIntegers(10, 10);
513         testIntegers(Integer.MAX_VALUE, Integer.MIN_VALUE);
514         testIntegers(Integer.MIN_VALUE, Integer.MAX_VALUE);
515         testIntegers(RANDOM.nextInt(), RANDOM.nextInt());
516     }
517 
518     @DontCompile
519     public void testIntegers(int a, int b) {
520         Asserts.assertEQ(a < b ? a : b, testMinI1(a, b));
521         Asserts.assertEQ(a > b ? b : a, testMinI2(a, b));
522         Asserts.assertEQ(a > b ? a : b, testMaxI1(a, b));
523         Asserts.assertEQ(a < b ? b : a, testMaxI2(a, b));
524 
525         Asserts.assertEQ(a <= b ? a : b, testMinI1E(a, b));
526         Asserts.assertEQ(a >= b ? b : a, testMinI2E(a, b));
527         Asserts.assertEQ(a >= b ? a : b, testMaxI1E(a, b));
528         Asserts.assertEQ(a <= b ? b : a, testMaxI2E(a, b));
529     }
530 
531     @Run(test = { "testMinL1", "testMinL2", "testMaxL1", "testMaxL2", "testMinL1E", "testMinL2E", "testMaxL1E", "testMaxL2E" })
532     public void runTestLongs() {
533         testLongs(10, 20);
534         testLongs(20, 10);
535         testLongs(10, 10);
536         testLongs(Integer.MAX_VALUE, Integer.MIN_VALUE);
537         testLongs(Integer.MIN_VALUE, Integer.MAX_VALUE);
538         testLongs(Long.MAX_VALUE, Long.MIN_VALUE);
539         testLongs(Long.MIN_VALUE, Long.MAX_VALUE);
540         testLongs(RANDOM.nextLong(), RANDOM.nextLong());
541     }
542 
543     @DontCompile
544     public void testLongs(long a, long b) {
545         Asserts.assertEQ(a < b ? a : b, testMinL1(a, b));
546         Asserts.assertEQ(a > b ? b : a, testMinL2(a, b));
547         Asserts.assertEQ(a > b ? a : b, testMaxL1(a, b));
548         Asserts.assertEQ(a < b ? b : a, testMaxL2(a, b));
549 
550         Asserts.assertEQ(a <= b ? a : b, testMinL1E(a, b));
551         Asserts.assertEQ(a >= b ? b : a, testMinL2E(a, b));
552         Asserts.assertEQ(a >= b ? a : b, testMaxL1E(a, b));
553         Asserts.assertEQ(a <= b ? b : a, testMaxL2E(a, b));
554     }
555 }