ef101f1bf2
Reviewed-by: kvn, thartmann, epeter
328 lines
12 KiB
Java
328 lines
12 KiB
Java
/*
|
|
* Copyright (c) 2024, Oracle 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.
|
|
*/
|
|
|
|
/*
|
|
* @test id=Xbatch
|
|
* @bug 8332920
|
|
* @summary Tests partial peeling at unsigned tests with limit being negative in exit tests "i >u limit".
|
|
* @run main/othervm -Xbatch -XX:-TieredCompilation
|
|
* -XX:CompileOnly=*TestPartialPeel*::original*,*TestPartialPeel*::test*
|
|
* compiler.loopopts.TestPartialPeelAtUnsignedTestsNegativeLimit
|
|
*/
|
|
|
|
/*
|
|
* @test id=Xcomp-run-inline
|
|
* @bug 8332920
|
|
* @summary Tests partial peeling at unsigned tests with limit being negative in exit tests "i >u limit".
|
|
* @run main/othervm -Xcomp -XX:-TieredCompilation
|
|
* -XX:CompileOnly=*TestPartialPeel*::original*,*TestPartialPeel*::run*,*TestPartialPeel*::test*
|
|
* -XX:CompileCommand=inline,*TestPartialPeelAtUnsignedTestsNegativeLimit::test*
|
|
* -XX:CompileCommand=dontinline,*TestPartialPeelAtUnsignedTestsNegativeLimit::check
|
|
* compiler.loopopts.TestPartialPeelAtUnsignedTestsNegativeLimit
|
|
*/
|
|
|
|
/*
|
|
* @test id=Xcomp-compile-test
|
|
* @bug 8332920
|
|
* @summary Tests partial peeling at unsigned tests with limit being negative in exit tests "i >u limit".
|
|
* @run main/othervm -Xcomp -XX:-TieredCompilation -XX:CompileOnly=*TestPartialPeel*::original*,*TestPartialPeel*::test*
|
|
* compiler.loopopts.TestPartialPeelAtUnsignedTestsNegativeLimit
|
|
*/
|
|
|
|
/*
|
|
* @test id=vanilla
|
|
* @bug 8332920
|
|
* @requires vm.flavor == "server" & (vm.opt.TieredStopAtLevel == null | vm.opt.TieredStopAtLevel == 4)
|
|
* @summary Tests partial peeling at unsigned tests with limit being negative in exit tests "i >u limit".
|
|
* Only run this test with C2 since it is time-consuming and only tests a C2 issue.
|
|
* @run main compiler.loopopts.TestPartialPeelAtUnsignedTestsNegativeLimit
|
|
*/
|
|
|
|
package compiler.loopopts;
|
|
|
|
import java.util.Random;
|
|
|
|
import static java.lang.Integer.*;
|
|
|
|
public class TestPartialPeelAtUnsignedTestsNegativeLimit {
|
|
static int iFld = 10000;
|
|
static int iterations = 0;
|
|
static int iFld2;
|
|
static boolean flag;
|
|
final static Random RANDOM = new Random();
|
|
|
|
public static void main(String[] args) {
|
|
compareUnsigned(3, 3); // Load Integer class for -Xcomp
|
|
for (int i = 0; i < 2; i++) {
|
|
if (!originalTest()) {
|
|
throw new RuntimeException("originalTest() failed");
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < 2000; i++) {
|
|
// For profiling
|
|
iFld = -1;
|
|
originalTestVariation1();
|
|
|
|
// Actual run
|
|
iFld = MAX_VALUE - 100_000;
|
|
if (!originalTestVariation1()) {
|
|
throw new RuntimeException("originalTestVariation1() failed");
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < 2000; ++i) {
|
|
// For profiling
|
|
iFld = MAX_VALUE;
|
|
originalTestVariation2();
|
|
|
|
// Actual run
|
|
iFld = MIN_VALUE + 100000;
|
|
if (!originalTestVariation2()) {
|
|
throw new RuntimeException("originalTestVariation2() failed");
|
|
}
|
|
}
|
|
|
|
runWhileLTIncr();
|
|
runWhileLTDecr();
|
|
}
|
|
|
|
// Originally reported simplified regression test with 2 variations (see below).
|
|
public static boolean originalTest() {
|
|
for (int i = MAX_VALUE - 50_000; compareUnsigned(i, -1) < 0; i++) {
|
|
if (compareUnsigned(MIN_VALUE, i) < 0) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public static boolean originalTestVariation1() {
|
|
int a = 0;
|
|
for (int i = iFld; compareUnsigned(i, -1) < 0; ++i) { // i <u -1
|
|
|
|
if (i >= Integer.MIN_VALUE + 1 && i <= 100) { // Transformed to unsigned test.
|
|
return true;
|
|
}
|
|
a *= 23;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public static boolean originalTestVariation2() {
|
|
int a = 0;
|
|
for (int i = iFld; compareUnsigned(i, -1000) < 0; i--) { // i <u -1
|
|
if (compareUnsigned(MAX_VALUE - 20, i) > 0) {
|
|
return true;
|
|
}
|
|
a = i;
|
|
}
|
|
System.out.println(a);
|
|
return false;
|
|
}
|
|
|
|
|
|
public static void testWhileLTIncr(int init, int limit) {
|
|
int i = init;
|
|
while (true) {
|
|
// <Peeled Section>
|
|
|
|
// Found as loop head in ciTypeFlow, but both paths inside loop -> head not cloned.
|
|
// As a result, this head has the safepoint as backedge instead of the loop exit test
|
|
// and we cannot create a counted loop (yet). We first need to partial peel.
|
|
if (flag) {
|
|
}
|
|
|
|
iFld2++;
|
|
|
|
// Loop exit test i >=u limit (i.e. "while (i <u limit)") to partial peel with.
|
|
// insert_cmpi_loop_exit() changes this exit condition into a signed and an unsigned test:
|
|
// i >= limit && i >=u limit
|
|
// where the signed condition can be used as proper loop exit condition for a counted loop
|
|
// (we cannot use an unsigned counted loop exit condition).
|
|
//
|
|
// After Partial Peeling, we have:
|
|
// if (i >= limit) goto Exit
|
|
// Loop:
|
|
// if (i >=u limit) goto Exit
|
|
// ...
|
|
// i++;
|
|
// if (i >= limit) goto Exit
|
|
// goto Loop
|
|
// Exit:
|
|
// ...
|
|
//
|
|
// If init = MAX_VALUE and limit = MIN_VALUE:
|
|
// i >= limit
|
|
// MAX_VALUE >= MIN_VALUE
|
|
// which is true where
|
|
// i >=u limit
|
|
// MAX_VALUE >=u MIN_VALUE
|
|
// MAX_VALUE >=u (uint)(MAX_INT + 1)
|
|
// is false and we wrongly never enter the loop even though we should have.
|
|
// This results in a wrong execution.
|
|
if (compareUnsigned(i, limit) >= 0) {
|
|
return;
|
|
}
|
|
// <-- Partial Peeling CUT -->
|
|
// Safepoint
|
|
// <Unpeeled Section>
|
|
iterations++;
|
|
i++;
|
|
}
|
|
}
|
|
|
|
// Same as testWhileLTIncr() but with decrement instead.
|
|
public static void testWhileLTDecr(int init, int limit) {
|
|
int i = init;
|
|
while (true) {
|
|
if (flag) {
|
|
}
|
|
|
|
// Loop exit test.
|
|
if (compareUnsigned(i, limit) >= 0) { // While (i <u limit)
|
|
return;
|
|
}
|
|
|
|
iterations++;
|
|
i--;
|
|
}
|
|
}
|
|
|
|
public static void runWhileLTIncr() {
|
|
// Currently works:
|
|
testWhileLTIncr(MAX_VALUE, -1);
|
|
check(MIN_VALUE); // MAX_VALUE + 1 iterations
|
|
testWhileLTIncr(-1, 1);
|
|
check(0);
|
|
testWhileLTIncr(0, 0);
|
|
check(0);
|
|
checkIncrWithRandom(0, 0); // Sanity check this method.
|
|
flag = !flag; // Change profiling
|
|
testWhileLTIncr(MAX_VALUE - 2000, MAX_VALUE);
|
|
check(2000);
|
|
testWhileLTIncr(MAX_VALUE - 1990, MAX_VALUE);
|
|
check(1990);
|
|
testWhileLTIncr(MAX_VALUE - 1, MAX_VALUE);
|
|
check(1);
|
|
testWhileLTIncr(MIN_VALUE, MIN_VALUE + 2000);
|
|
check(2000);
|
|
testWhileLTIncr(MIN_VALUE, MIN_VALUE + 1990);
|
|
check(1990);
|
|
testWhileLTIncr(MIN_VALUE, MIN_VALUE + 1);
|
|
check(1);
|
|
|
|
flag = !flag;
|
|
// Overflow currently does not work with negative limit and is fixed with patch:
|
|
testWhileLTIncr(MAX_VALUE, MIN_VALUE);
|
|
check(1);
|
|
testWhileLTIncr(MAX_VALUE - 2000, MIN_VALUE);
|
|
check(2001);
|
|
testWhileLTIncr(MAX_VALUE, MIN_VALUE + 2000);
|
|
check(2001);
|
|
testWhileLTIncr(MAX_VALUE - 2000, MIN_VALUE + 2000);
|
|
check(4001);
|
|
|
|
// Random values
|
|
int init = RANDOM.nextInt(0, MAX_VALUE);
|
|
int limit = RANDOM.nextInt(MIN_VALUE, 0);
|
|
testWhileLTIncr(init, limit);
|
|
checkIncrWithRandom(init, limit);
|
|
}
|
|
|
|
public static void runWhileLTDecr() {
|
|
// Currently works:
|
|
testWhileLTDecr(1, -1);
|
|
check(2);
|
|
testWhileLTDecr(-1, 1);
|
|
check(0);
|
|
testWhileLTDecr(0, 0);
|
|
check(0);
|
|
checkDecrWithRandom(0, 0); // Sanity check this method.
|
|
flag = !flag;
|
|
testWhileLTDecr(MAX_VALUE, MIN_VALUE);
|
|
check(MIN_VALUE); // MAX_VALUE + 1 iterations
|
|
testWhileLTDecr(MAX_VALUE, -1);
|
|
check(MIN_VALUE); // MAX_VALUE + 1 iterations
|
|
testWhileLTDecr(MAX_VALUE, MIN_VALUE);
|
|
check(MIN_VALUE); // MAX_VALUE + 1 iterations
|
|
testWhileLTDecr(MIN_VALUE, 0);
|
|
check(0);
|
|
testWhileLTDecr(MIN_VALUE, 1);
|
|
check(0);
|
|
flag = !flag;
|
|
|
|
// Underflow currently does not work with negative limit and is fixed with patch:
|
|
testWhileLTDecr(MIN_VALUE, -1);
|
|
check(MIN_VALUE + 1); // MAX_VALUE + 2 iterations
|
|
testWhileLTDecr(MIN_VALUE, -2000);
|
|
check(MIN_VALUE + 1); // MAX_VALUE + 2 iterations
|
|
testWhileLTDecr(MIN_VALUE, MIN_VALUE + 1);
|
|
check(MIN_VALUE + 1); // MAX_VALUE + 2 iterations
|
|
testWhileLTDecr(MIN_VALUE + 2000, -1);
|
|
check(MIN_VALUE + 2001); // MAX_VALUE + 2002 iterations
|
|
testWhileLTDecr(MIN_VALUE + 2000, -2000);
|
|
check(MIN_VALUE + 2001); // MAX_VALUE + 2002 iterations
|
|
testWhileLTDecr(MIN_VALUE + 2000, MIN_VALUE + 2001);
|
|
check(MIN_VALUE + 2001); // MAX_VALUE + 2002 iterations
|
|
|
|
// Random values
|
|
int r1 = RANDOM.nextInt(MIN_VALUE, 0);
|
|
int r2 = RANDOM.nextInt(MIN_VALUE, 0);
|
|
int init = Math.min(r1, r2);
|
|
int limit = Math.max(r1, r2);
|
|
testWhileLTDecr(init, limit);
|
|
checkDecrWithRandom(init, limit);
|
|
}
|
|
|
|
static void check(int expectedIterations) {
|
|
if (expectedIterations != iterations) {
|
|
throw new RuntimeException("Expected " + expectedIterations + " iterations but only got " + iterations);
|
|
}
|
|
iterations = 0; // Reset
|
|
}
|
|
|
|
static void checkIncrWithRandom(long init, long limit) {
|
|
long expectedIterations = ((long)(MAX_VALUE) - init) + (limit - (long)MIN_VALUE) + 1;
|
|
if ((int)expectedIterations != iterations) {
|
|
String error = "Expected %d iterations but only got %d, init: %d, limit: %d"
|
|
.formatted(expectedIterations, iterations, init, limit);
|
|
throw new RuntimeException(error);
|
|
}
|
|
iterations = 0; // Reset
|
|
}
|
|
|
|
static void checkDecrWithRandom(long init, long limit) {
|
|
long expectedIterations = init + MIN_VALUE + MAX_VALUE + 2;
|
|
if (init == limit) {
|
|
expectedIterations = 0;
|
|
}
|
|
if ((int)expectedIterations != iterations) {
|
|
String error = "Expected %d iterations but only got %d, init: %d, limit: %d"
|
|
.formatted(expectedIterations, iterations, init, limit);
|
|
throw new RuntimeException(error);
|
|
}
|
|
iterations = 0; // Reset
|
|
}
|
|
}
|