jdk-24/test/hotspot/jtreg/compiler/conversions/TestMoveConvI2LOrCastIIThruAddIs.java
2020-12-10 08:09:08 +00:00

203 lines
6.8 KiB
Java

/*
* Copyright (c) 2020, 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.
*/
package compiler.conversions;
import java.util.Objects;
import java.util.Random;
import jdk.test.lib.Asserts;
/*
* @test
* @bug 8254317 8256730
* @requires vm.compiler2.enabled
* @summary Exercises the optimization that moves integer-to-long conversions
* upwards through different shapes of integer addition
* subgraphs. Contains three small functional tests and two stress
* tests that resulted in a compilation time and memory explosion
* before fixing bug 8254317. The stress tests run with -Xbatch to wait
* for C2, so that a timeout or an out-of-memory error is triggered if
* there was an explosion. These tests use a timeout of 30s to catch
* the explosion earlier.
* @library /test/lib /
* @run main/othervm
* compiler.conversions.TestMoveConvI2LOrCastIIThruAddIs functional
* @run main/othervm/timeout=30 -Xbatch
* compiler.conversions.TestMoveConvI2LOrCastIIThruAddIs stress1
* @run main/othervm/timeout=30 -Xbatch
* compiler.conversions.TestMoveConvI2LOrCastIIThruAddIs stress2
* @run main/othervm/timeout=30 -Xbatch
* compiler.conversions.TestMoveConvI2LOrCastIIThruAddIs stress3
* @run main/othervm/timeout=30 -Xbatch
* compiler.conversions.TestMoveConvI2LOrCastIIThruAddIs stress4
*/
public class TestMoveConvI2LOrCastIIThruAddIs {
// Number of repetitions of each test. Should be sufficiently large for the
// method under test to be compiled with C2.
static final int N = 100_000;
// Chain-shaped functional test.
static long testChain(boolean cnd) {
int a = cnd ? 1 : 2;
int b = a + a;
int c = b + b;
int d = c + c;
return d;
}
// Tree-shaped functional test.
static long testTree(boolean cnd) {
int a0 = cnd ? 1 : 2;
int a1 = cnd ? 1 : 2;
int a2 = cnd ? 1 : 2;
int a3 = cnd ? 1 : 2;
int a4 = cnd ? 1 : 2;
int a5 = cnd ? 1 : 2;
int a6 = cnd ? 1 : 2;
int a7 = cnd ? 1 : 2;
int b0 = a0 + a1;
int b1 = a2 + a3;
int b2 = a4 + a5;
int b3 = a6 + a7;
int c0 = b0 + b1;
int c1 = b2 + b3;
int d = c0 + c1;
return d;
}
// DAG-shaped functional test.
static long testDAG(boolean cnd) {
int a0 = cnd ? 1 : 2;
int a1 = cnd ? 1 : 2;
int a2 = cnd ? 1 : 2;
int a3 = cnd ? 1 : 2;
int b0 = a0 + a1;
int b1 = a1 + a2;
int b2 = a2 + a3;
int c0 = b0 + b1;
int c1 = b1 + b2;
int d = c0 + c1;
return d;
}
// Chain-shaped stress test. Before fixing bug 8254317, this test would
// result in an out-of-memory error after minutes running.
static long testStress1(boolean cnd) {
// C2 infers a finite, small value range for a. Note that there are
// different ways to achieve this, for example a might take the value of
// the induction variable in an outer counted loop.
int a = cnd ? 1 : 2;
// C2 fully unrolls this loop, creating a long chain of AddIs.
for (int i = 0; i < 28; i++) {
a = a + a;
}
// C2 places a ConvI2L at the end of the AddI chain.
return a;
}
// DAG-shaped stress test. Before fixing bug 8254317, this test would result
// in an out-of-memory error after minutes running.
static long testStress2(boolean cnd) {
int a = cnd ? 1 : 2;
int b = a;
int c = a + a;
for (int i = 0; i < 20; i++) {
b = b + c;
c = b + c;
}
int d = b + c;
return d;
}
// Same as testStress1 for CastII
static long testStress3(int a) {
Objects.checkIndex(a, 2);
for (int i = 0; i < 28; i++) {
a = a + a;
}
return Objects.checkIndex(a, 2);
}
// Same as testStress2 for CastII
static long testStress4(int a) {
a = Objects.checkIndex(a, 2);
int b = a;
int c = a + a;
for (int i = 0; i < 20; i++) {
b = b + c;
c = b + c;
}
int d = b + c;
return Objects.checkIndex(d, 2);
}
public static void main(String[] args) {
// We use a random number generator to avoid constant propagation in C2
// and produce a variable ("a" in the different tests) with a finite,
// small value range.
Random rnd = new Random();
switch(args[0]) {
case "functional":
// Small, functional tests.
for (int i = 0; i < N; i++) {
boolean cnd = rnd.nextBoolean();
Asserts.assertEQ(testChain(cnd), cnd ? 8L : 16L);
Asserts.assertEQ(testTree(cnd), cnd ? 8L : 16L);
Asserts.assertEQ(testDAG(cnd), cnd ? 8L : 16L);
}
break;
case "stress1":
// Chain-shaped stress test.
for (int i = 0; i < N; i++) {
boolean cnd = rnd.nextBoolean();
Asserts.assertEQ(testStress1(cnd),
cnd ? 268435456L : 536870912L);
}
break;
case "stress2":
// DAG-shaped stress test.
for (int i = 0; i < N; i++) {
boolean cnd = rnd.nextBoolean();
Asserts.assertEQ(testStress2(cnd),
cnd ? 701408733L : 1402817466L);
}
break;
case "stress3":
for (int i = 0; i < N; i++) {
testStress3(0);
}
break;
case "stress4":
// DAG-shaped stress test.
for (int i = 0; i < N; i++) {
testStress4(0);
}
break;
default:
System.out.println("invalid mode");
}
}
}