jdk-24/test/hotspot/jtreg/compiler/loopopts/parallel_iv/TestParallelIvInIntCountedLoop.java
Kangcheng Xu 80ec552248 8328528: C2 should optimize long-typed parallel iv in an int counted loop
Reviewed-by: roland, chagedorn, thartmann
2024-10-21 14:57:31 +00:00

392 lines
13 KiB
Java

/*
* Copyright (c) 2024 Red Hat and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package compiler.loopopts.parallel_iv;
import compiler.lib.ir_framework.*;
import jdk.test.lib.Asserts;
import jdk.test.lib.Utils;
import java.util.Random;
/**
* @test
* @bug 8328528
* @summary test the long typed parallel iv replacing transformation for int counted loop
* @library /test/lib /
* @requires vm.compiler2.enabled
* @run driver compiler.loopopts.parallel_iv.TestParallelIvInIntCountedLoop
*/
public class TestParallelIvInIntCountedLoop {
private static final Random RNG = Utils.getRandomInstance();
// stride2 must be a multiple of stride and must not overflow for the optimization to work
private static final int STRIDE = RNG.nextInt(1, Integer.MAX_VALUE / 16);
private static final int STRIDE_2 = STRIDE * RNG.nextInt(1, 16);
public static void main(String[] args) {
TestFramework.runWithFlags(
"-XX:+IgnoreUnrecognizedVMOptions", // StressLongCountedLoop is only available in debug builds
"-XX:StressLongCountedLoop=0", // Don't convert int counted loops to long ones
"-XX:PerMethodTrapLimit=100" // allow slow-path loop limit checks
);
}
/*
* The IR framework can only test against static code, and the transformation relies on strides being constants to
* perform constant propagation. Therefore, we have no choice but repeating the same test case multiple times with
* different numbers.
*
* For good measures, randomly initialized static final stride and stride2 is also tested.
*/
// A controlled test making sure a simple non-counted loop can be found by the test framework.
@Test
@Arguments(values = { Argument.NUMBER_42 }) // otherwise a large number may take too long
@IR(counts = { IRNode.COUNTED_LOOP, ">=1" })
private static int testControlledSimpleLoop(int stop) {
int a = 0;
for (int i = 0; i < stop; i++) {
a += i; // cannot be extracted to multiplications
}
return a;
}
@Test
@IR(failOn = { IRNode.COUNTED_LOOP })
private static int testIntCountedLoopWithIntIV(int stop) {
int a = 0;
for (int i = 0; i < stop; i++) {
a += 1;
}
return a;
}
@Run(test = "testIntCountedLoopWithIntIV")
private static void runTestIntCountedLoopWithIntIv() {
int s = RNG.nextInt(0, Integer.MAX_VALUE);
Asserts.assertEQ(s, testIntCountedLoopWithIntIV(s));
}
@Test
@IR(failOn = { IRNode.COUNTED_LOOP })
private static int testIntCountedLoopWithIntIVZero(int stop) {
int a = 0;
for (int i = 0; i < stop; i++) {
a += 0;
}
return a;
}
@Run(test = "testIntCountedLoopWithIntIVZero")
private static void runTestIntCountedLoopWithIntIVZero() {
int s = RNG.nextInt(0, Integer.MAX_VALUE);
Asserts.assertEQ(0, testIntCountedLoopWithIntIVZero(s));
}
@Test
@IR(failOn = { IRNode.COUNTED_LOOP })
private static int testIntCountedLoopWithIntIVMax(int stop) {
int a = 0;
for (int i = 0; i < stop; i++) {
a += Integer.MAX_VALUE;
}
return a;
}
@Run(test = "testIntCountedLoopWithIntIVMax")
private static void runTestIntCountedLoopWithIntIVMax() {
int s = RNG.nextInt(0, Integer.MAX_VALUE);
Asserts.assertEQ(s * Integer.MAX_VALUE, testIntCountedLoopWithIntIVMax(s));
}
@Test
@IR(failOn = { IRNode.COUNTED_LOOP })
private static int testIntCountedLoopWithIntIVMaxMinusOne(int stop) {
int a = 0;
for (int i = 0; i < stop; i++) {
a += Integer.MAX_VALUE - 1;
}
return a;
}
@Run(test = "testIntCountedLoopWithIntIVMaxMinusOne")
private static void runTestIntCountedLoopWithIntIVMaxMinusOne() {
int s = RNG.nextInt(0, Integer.MAX_VALUE);
Asserts.assertEQ(s * (Integer.MAX_VALUE - 1), testIntCountedLoopWithIntIVMaxMinusOne(s));
}
@Test
@IR(failOn = { IRNode.COUNTED_LOOP })
private static int testIntCountedLoopWithIntIVMaxPlusOne(int stop) {
int a = 0;
for (int i = 0; i < stop; i++) {
a += Integer.MAX_VALUE + 1;
}
return a;
}
@Run(test = "testIntCountedLoopWithIntIVMaxPlusOne")
private static void runTestIntCountedLoopWithIntIVMaxPlusOne() {
int s = RNG.nextInt(0, Integer.MAX_VALUE);
Asserts.assertEQ(s * (Integer.MAX_VALUE + 1), testIntCountedLoopWithIntIVMaxPlusOne(s));
}
@Test
@IR(failOn = { IRNode.COUNTED_LOOP })
private static int testIntCountedLoopWithIntIVWithStrideTwo(int stop) {
int a = 0;
for (int i = 0; i < stop; i += 2) {
a += 2; // this stride2 constant must be a multiple of the first stride (i += ...) for optimization
}
return a;
}
@Run(test = "testIntCountedLoopWithIntIVWithStrideTwo")
private static void runTestIntCountedLoopWithIntIVWithStrideTwo() {
// Since we can't easily determine expected values if loop variables overflow when incrementing, we make sure
// `stop` is less than (MAX_VALUE - stride).
int s = RNG.nextInt(0, Integer.MAX_VALUE - 2);
Asserts.assertEQ(Math.ceilDiv(s, 2) * 2, testIntCountedLoopWithIntIVWithStrideTwo(s));
}
@Test
@IR(failOn = { IRNode.COUNTED_LOOP })
private static int testIntCountedLoopWithIntIVWithStrideMinusOne(int stop) {
int a = 0;
for (int i = stop; i > 0; i += -1) {
a += 1;
}
return a;
}
@Run(test = "testIntCountedLoopWithIntIVWithStrideMinusOne")
private static void runTestIntCountedLoopWithIntIVWithStrideMinusOne() {
int s = RNG.nextInt(0, Integer.MAX_VALUE);
Asserts.assertEQ(s, testIntCountedLoopWithIntIVWithStrideMinusOne(s));
}
@Test
@IR(failOn = { IRNode.COUNTED_LOOP })
private static int testIntCountedLoopWithIntIVWithRandomStrides(int stop) {
int a = 0;
for (int i = 0; i < stop; i += STRIDE) {
a += STRIDE_2;
}
return a;
}
@Run(test = "testIntCountedLoopWithIntIVWithRandomStrides")
private static void runTestIntCountedLoopWithIntIVWithRandomStrides() {
// Make sure `stop` is less than (MAX_VALUE - stride) to avoid overflows.
int s = RNG.nextInt(0, Integer.MAX_VALUE - STRIDE);
Asserts.assertEQ(Math.ceilDiv(s, STRIDE) * STRIDE_2, testIntCountedLoopWithIntIVWithRandomStrides(s));
}
@Test
@IR(failOn = { IRNode.COUNTED_LOOP })
private static int testIntCountedLoopWithIntIVWithRandomStridesAndInits(int init, int init2, int stop) {
int a = init;
for (int i = init2; i < stop; i += STRIDE) {
a += STRIDE_2;
}
return a;
}
@Run(test = "testIntCountedLoopWithIntIVWithRandomStridesAndInits")
private static void runTestIntCountedLoopWithIntIVWithRandomStridesAndInits() {
int s = RNG.nextInt(0, Integer.MAX_VALUE - STRIDE);
int init1 = RNG.nextInt();
int init2 = RNG.nextInt(Integer.MIN_VALUE + s + 1, s); // Limit bounds to avoid loop variables from overflowing.
Asserts.assertEQ(Math.ceilDiv((s - init2), STRIDE) * STRIDE_2 + init1,
testIntCountedLoopWithIntIVWithRandomStridesAndInits(init1, init2, s));
}
@Test
@IR(failOn = { IRNode.COUNTED_LOOP })
private static long testIntCountedLoopWithLongIV(int stop) {
long a = 0;
for (int i = 0; i < stop; i++) {
a += 1;
}
return a;
}
@Run(test = "testIntCountedLoopWithLongIV")
private static void runTestIntCountedLoopWithLongIV() {
int s = RNG.nextInt(0, Integer.MAX_VALUE);
Asserts.assertEQ((long) s, testIntCountedLoopWithLongIV(s));
}
@Test
@IR(failOn = { IRNode.COUNTED_LOOP })
private static long testIntCountedLoopWithLongIVZero(int stop) {
long a = 0;
for (int i = 0; i < stop; i++) {
a += 0;
}
return a;
}
@Run(test = "testIntCountedLoopWithLongIVZero")
private static void runTestIntCountedLoopWithLongIVZero() {
int s = RNG.nextInt(0, Integer.MAX_VALUE);
Asserts.assertEQ((long) 0, testIntCountedLoopWithLongIVZero(s));
}
@Test
@IR(failOn = { IRNode.COUNTED_LOOP })
private static long testIntCountedLoopWithLongIVMax(int stop) {
long a = 0;
for (int i = 0; i < stop; i++) {
a += Long.MAX_VALUE;
}
return a;
}
@Run(test = "testIntCountedLoopWithLongIVMax")
private static void runTestIntCountedLoopWithLongIVMax() {
int s = RNG.nextInt(0, Integer.MAX_VALUE);
Asserts.assertEQ((long) s * Long.MAX_VALUE, testIntCountedLoopWithLongIVMax(s));
}
@Test
@IR(failOn = { IRNode.COUNTED_LOOP })
private static long testIntCountedLoopWithLongIVMaxMinusOne(int stop) {
long a = 0;
for (int i = 0; i < stop; i++) {
a += Long.MAX_VALUE - 1;
}
return a;
}
@Run(test = "testIntCountedLoopWithLongIVMaxMinusOne")
private static void runTestIntCountedLoopWithLongIVMaxMinusOne() {
int s = RNG.nextInt(0, Integer.MAX_VALUE);
Asserts.assertEQ((long) s * (Long.MAX_VALUE - 1L), testIntCountedLoopWithLongIVMaxMinusOne(s));
}
@Test
@IR(failOn = { IRNode.COUNTED_LOOP })
private static long testIntCountedLoopWithLongIVMaxPlusOne(int stop) {
long a = 0;
for (int i = 0; i < stop; i++) {
a += Long.MAX_VALUE + 1;
}
return a;
}
@Run(test = "testIntCountedLoopWithLongIVMaxPlusOne")
private static void runTestIntCountedLoopWithLongIVMaxPlusOne() {
int s = RNG.nextInt(0, Integer.MAX_VALUE);
Asserts.assertEQ((long) s * (Long.MAX_VALUE + 1L), testIntCountedLoopWithLongIVMaxPlusOne(s));
}
@Test
@IR(failOn = { IRNode.COUNTED_LOOP })
private static long testIntCountedLoopWithLongIVWithStrideTwo(int stop) {
long a = 0;
for (int i = 0; i < stop; i += 2) {
a += 2;
}
return a;
}
@Run(test = "testIntCountedLoopWithLongIVWithStrideTwo")
private static void runTestIntCountedLoopWithLongIVWithStrideTwo() {
int s = RNG.nextInt(0, Integer.MAX_VALUE - 2);
Asserts.assertEQ(Math.ceilDiv(s, 2L) * 2L, testIntCountedLoopWithLongIVWithStrideTwo(s));
}
@Test
@IR(failOn = { IRNode.COUNTED_LOOP })
private static long testIntCountedLoopWithLongIVWithStrideMinusOne(int stop) {
long a = 0;
for (int i = stop; i > 0; i += -1) {
a += 1;
}
return a;
}
@Run(test = "testIntCountedLoopWithLongIVWithStrideMinusOne")
private static void runTestIntCountedLoopWithLongIVWithStrideMinusOne() {
int s = RNG.nextInt(0, Integer.MAX_VALUE);
Asserts.assertEQ((long) s, testIntCountedLoopWithLongIVWithStrideMinusOne(s));
}
@Test
@IR(failOn = { IRNode.COUNTED_LOOP })
private static long testIntCountedLoopWithLongIVWithRandomStrides(int stop) {
long a = 0;
for (int i = 0; i < stop; i += STRIDE) {
a += STRIDE_2;
}
return a;
}
@Run(test = "testIntCountedLoopWithLongIVWithRandomStrides")
private static void runTestIntCountedLoopWithLongIVWithRandomStrides() {
int s = RNG.nextInt(0, Integer.MAX_VALUE - STRIDE);
Asserts.assertEQ(Math.ceilDiv(s, (long) STRIDE) * (long) STRIDE_2,
testIntCountedLoopWithLongIVWithRandomStrides(s));
}
@Test
@IR(failOn = { IRNode.COUNTED_LOOP })
private static long testIntCountedLoopWithLongIVWithRandomStridesAndInits(long init, int init2, int stop) {
long a = init;
for (int i = init2; i < stop; i += STRIDE) {
a += STRIDE_2;
}
return a;
}
@Run(test = "testIntCountedLoopWithLongIVWithRandomStridesAndInits")
private static void runTestIntCountedLoopWithLongIVWithRandomStridesAndInits() {
int s = RNG.nextInt(0, Integer.MAX_VALUE - STRIDE);
long init1 = RNG.nextLong();
int init2 = RNG.nextInt(Integer.MIN_VALUE + s + 1, s); // Limit bounds to avoid loop variables from overflowing.
Asserts.assertEQ(Math.ceilDiv(((long) s - init2), (long) STRIDE) * (long) STRIDE_2 + init1,
testIntCountedLoopWithLongIVWithRandomStridesAndInits(init1, init2, s));
}
}