jdk/test/hotspot/jtreg/compiler/predicates/assertion/TestAssertionPredicates.java

2281 lines
85 KiB
Java

/*
* Copyright (c) 2025, 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 8288981 8350579 8350577
* @summary Test all possible cases in which Assertion Predicates are required such that the graph is not left in a
* broken state to trigger assertions. Additional tests ensure the correctness of the implementation.
* All tests additionally -XX:+AbortVMOnCompilationFailure which would catch bad graphs as a result of missing
or wrong Assertion Predicates where we simply bail out of C2 compilation.
* @run main/othervm -Xbatch
* -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure
* -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::*
* -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::*
* -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode
* compiler.predicates.assertion.TestAssertionPredicates Xbatch
*/
/*
* @test id=NoTieredCompilation
* @bug 8288981 8350579 8350577
* @run main/othervm -Xbatch -XX:-TieredCompilation
* -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure
* -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::*
* -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::*
* -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode
* compiler.predicates.assertion.TestAssertionPredicates NoTieredCompilation
*/
/*
* @test id=Xcomp
* @bug 8288981 8350579 8350577
* @run main/othervm -Xcomp
* -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure
* -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::*
* -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::*
* -XX:CompileCommand=inline,compiler.predicates.assertion.TestAssertionPredicates::inline
* -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode
* compiler.predicates.assertion.TestAssertionPredicates Xcomp
*/
/*
* @test id=XcompNoTiered
* @bug 8288981 8350577
* @run main/othervm -Xcomp -XX:-TieredCompilation
* -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure
* -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::*
* -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::*
* -XX:CompileCommand=inline,compiler.predicates.assertion.TestAssertionPredicates::inline
* -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode
* compiler.predicates.assertion.TestAssertionPredicates XcompNoTiered
*/
/*
* @test id=LoopMaxUnroll0
* @bug 8288981 8350579 8350577
* @requires vm.compiler2.enabled
* @run main/othervm -Xcomp -XX:LoopMaxUnroll=0
* -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure
* -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::*
* -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::*
* -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode
* compiler.predicates.assertion.TestAssertionPredicates LoopMaxUnroll0
*/
/*
* @test id=LoopMaxUnroll2
* @bug 8288981 8350577
* @requires vm.compiler2.enabled
* @run main/othervm -Xcomp -XX:LoopMaxUnroll=2
* -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure
* -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::*
* -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::*
* -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode
* compiler.predicates.assertion.TestAssertionPredicates LoopMaxUnroll2
*/
/*
* @test id=LoopUnrollLimit40
* @bug 8288981 8350577
* @requires vm.compiler2.enabled
* @run main/othervm -Xcomp -XX:LoopUnrollLimit=40
* -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure
* -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::*
* -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::*
* -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode
* compiler.predicates.assertion.TestAssertionPredicates LoopUnrollLimit40
*/
/*
* @test id=LoopUnrollLimit150
* @bug 8288981 8350577
* @requires vm.compiler2.enabled
* @run main/othervm -Xcomp -XX:LoopUnrollLimit=150
* -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure
* -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::*
* -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::*
* -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode
* compiler.predicates.assertion.TestAssertionPredicates LoopUnrollLimit150
*/
/*
* @test id=UseProfiledLoopPredicateFalse
* @bug 8288981 8350577
* @requires vm.compiler2.enabled
* @run main/othervm -Xcomp -XX:-UseProfiledLoopPredicate
* -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure
* -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::*
* -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::*
* -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode
* compiler.predicates.assertion.TestAssertionPredicates NoProfiledLoopPredicate
*/
/*
* @test id=DataUpdate
* @key randomness
* @bug 8288981 8350577
* @requires vm.compiler2.enabled
* @run main/othervm -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:+StressGCM -XX:+AbortVMOnCompilationFailure
* -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::*
* -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::*
* -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode
* compiler.predicates.assertion.TestAssertionPredicates DataUpdate
*/
/*
* @test id=DataUpdateZGC
* @key randomness
* @bug 8288981 8350577 0360510
* @requires vm.compiler2.enabled
* @requires vm.gc.Z
* @run main/othervm -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:+StressGCM -XX:+AbortVMOnCompilationFailure -XX:+UseZGC
* -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::*
* -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::*
* -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode
* compiler.predicates.assertion.TestAssertionPredicates DataUpdate
*/
/*
* @test id=CloneDown
* @bug 8288981 8350577
* @requires vm.compiler2.enabled
* @run main/othervm -Xcomp -XX:-BlockLayoutByFrequency -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure
* -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::*
* -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::*
* -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode
* compiler.predicates.assertion.TestAssertionPredicates CloneDown
*/
/*
* @test id=StressXcomp
* @key randomness
* @bug 8288981 8350579 8350577
* @requires vm.compiler2.enabled
* @run main/othervm -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:+StressIGVN -XX:+StressGCM -XX:+AbortVMOnCompilationFailure
* -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::*
* -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::*
* -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode
* compiler.predicates.assertion.TestAssertionPredicates Stress
*/
/*
* @test id=StressXbatch
* @key randomness
* @bug 8288981 8350579 8350577
* @requires vm.compiler2.enabled
* @run main/othervm -Xbatch -XX:+UnlockDiagnosticVMOptions -XX:+StressIGVN -XX:+StressGCM -XX:+AbortVMOnCompilationFailure
* -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::*
* -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::*
* -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode
* compiler.predicates.assertion.TestAssertionPredicates Stress
*/
/*
* @test id=StressXcompMaxUnroll0
* @key randomness
* @bug 8288981 8356084
* @requires vm.compiler2.enabled
* @run main/othervm -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:+StressGCM -XX:+AbortVMOnCompilationFailure
* -XX:LoopMaxUnroll=0 -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode
* -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::*
* -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::*
* compiler.predicates.assertion.TestAssertionPredicates StressXcompMaxUnroll0
*/
/*
* @test id=NoLoopPredicationXcomp
* @bug 8288981 8350577
* @requires vm.compiler2.enabled
* @run main/othervm -Xcomp -XX:-UseLoopPredicate
* -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure
* -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::*
* -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::*
* -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode
* compiler.predicates.assertion.TestAssertionPredicates NoLoopPredication
*/
/*
* @test id=NoLoopPredicationXbatch
* @bug 8288981 8350579 8350577
* @requires vm.compiler2.enabled
* @run main/othervm -Xbatch -XX:-UseLoopPredicate
* -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure
* -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::*
* -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::*
* -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode
* compiler.predicates.assertion.TestAssertionPredicates NoLoopPredication
*/
/*
* @test id=NoFlags
* @bug 8288981 8350579 8350577
* @run main compiler.predicates.assertion.TestAssertionPredicates NoFlags
*/
package compiler.predicates.assertion;
public class TestAssertionPredicates {
static int[] iArrShort = new int[10];
static int[] iArr = new int[200];
static int[] iArr2 = new int[200];
static int[] iArr3 = new int[300];
static int[] iArrNull = null;
static int[][] iArr2D = new int[10][10];
static short[] sArr = new short[10];
static float[] fArr = new float[10];
static float[][] fArr2D = new float[10][10];
static boolean flag, flag2, flagTrue = true;
static boolean flagFalse, flagFalse2;
static int iFld = 34;
static int iFld2, iFld3;
static int two = 2;
static long lFld, lFldOne = 1;
static float fFld;
static short sFld;
static short five = 5;
static byte byFld;
volatile byte byFldVol;
static class Foo {
int iFld;
}
static Foo foo = new Foo();
static int fooArrSize = 10000001;
public static void main(String[] args) {
switch (args[0]) {
case "Xbatch" -> {
for (int i = 0; i < 10000; i++) {
flag = !flag;
testTemplateAssertionPredicateNotRemovedHalt();
testTemplateAssertionPredicateNotRemovedMalformedGraph();
test8305428();
test8305428No2();
}
}
case "NoTieredCompilation" -> {
for (int i = 0; i < 1000; i++) {
test8320920();
test8332501();
}
}
case "NoProfiledLoopPredicate" -> testWithPartialPeelingFirst();
case "LoopMaxUnroll0" -> {
testPeeling();
testPeelingTwice();
testPeelingThreeTimes();
testUnswitchingThenPeeling();
testPeelingThenUnswitchingThenPeeling();
testPeelingThenUnswitchingThenPeelingThenPreMainPost();
testDyingRuntimePredicate();
testDyingNegatedRuntimePredicate();
}
case "LoopMaxUnroll2" -> {
testPeelMainLoopAfterUnrollingThenPreMainPost();
testPeelMainLoopAfterUnrolling2();
}
case "LoopUnrollLimit40" -> testPeelMainLoopAfterUnrollingThenPreMainPostThenUnrolling();
case "LoopUnrollLimit150" -> {
testUnrolling8();
testUnrolling16();
testPeelingUnrolling16();
}
case "Xcomp" -> {
testPreMainPost();
testUnrolling2();
testUnrolling4();
testPeelingThenPreMainPost();
testUnswitchingThenPeelingThenPreMainPost();
testDyingInitializedAssertionPredicate();
test8288981();
test8288941();
testRemovingParsePredicatesThenMissingTemplates();
iFld = -1;
test8292507();
TestAssertionPredicates t = new TestAssertionPredicates();
t.test8296077();
test8308504No2();
test8307131();
test8308392No1();
iFld = -50000;
test8308392No2();
test8308392No3();
test8308392No4();
test8308392No5();
test8308392No6();
test8308392No7();
iFld = 0;
test8308392No8();
runTest8308392No9();
test8308392No10();
testSplitIfCloneDownWithOpaqueAssertionPredicate();
}
case "XcompNoTiered" -> {
TestAssertionPredicates t = new TestAssertionPredicates();
for (int i = 0; i < 10; i++) {
t.test8308504();
test8308504No2();
}
}
case "DataUpdate", "StressXcompMaxUnroll0" -> {
for (int i = 0; i < 10; i++) {
// The following tests create large arrays. Limit the number of invocations to reduce the time spent.
flag = !flag;
testDataUpdateUnswitchingPeelingUnroll();
testDataUpdateUnswitchUnroll();
testDataUpdateUnroll();
testDataUpdatePeelingUnroll();
testPeelingThreeTimesDataUpdate();
}
}
case "CloneDown" -> {
for (int i = 0; i < 100; i++) {
// The following tests create large arrays. Limit the number of invocations to reduce the time spent.
testTrySplitUpNonOpaqueExpressionNode();
testTrySplitUpOpaqueLoopInit();
}
}
case "NoLoopPredication", "NoFlags", "Stress" -> {
runAllFastTests();
}
default -> throw new RuntimeException("invalid arg");
}
}
// Runs almost all tests except for the heavy ones like the testData*() tests.
static void runAllFastTests() {
for (int i = 0; i < 10000; i++) {
testPeeling();
testPeelingTwice();
testPeelingThreeTimes();
testUnswitchingThenPeeling();
testPeelingThenUnswitchingThenPeeling();
testPeelingThenUnswitchingThenPeelingThenPreMainPost();
testDyingRuntimePredicate();
testDyingNegatedRuntimePredicate();
testPeelMainLoopAfterUnrollingThenPreMainPost();
testPeelMainLoopAfterUnrolling2();
testUnrolling8();
testUnrolling16();
testPeelingUnrolling16();
testPreMainPost();
testUnrolling2();
testUnrolling4();
testPeelingThenPreMainPost();
testUnswitchingThenPeelingThenPreMainPost();
testDyingInitializedAssertionPredicate();
test8288981();
test8288941();
testRemovingParsePredicatesThenMissingTemplates();
iFld = -1;
test8292507();
test8307131();
test8308392No1();
iFld = -50000;
test8308392No2();
test8308392No3();
test8308392No4();
test8308392No5();
test8308392No6();
test8308392No7();
iFld = 0;
test8308392No8();
runTest8308392No9();
test8308392No10();
testSplitIfCloneDownWithOpaqueAssertionPredicate();
testTemplateAssertionPredicateNotRemovedHalt();
testTemplateAssertionPredicateNotRemovedMalformedGraph();
testDyingRuntimePredicate();
testDyingNegatedRuntimePredicate();
testDyingInitializedAssertionPredicate();
test8305428();
test8305428No2();
test8320920();
test8332501();
test8308504();
test8308504No2();
testBackToBackLoopLimitCheckPredicate();
testTrySplitUpNonOpaqueExpressionNode();
testTrySplitUpOpaqueLoopInit();
}
}
// -Xcomp -XX:CompileCommand=compileonly,Test*::*
static void testPreMainPost() {
int x = 0;
for (int i = 1; i > five; i -= 2) {
x = iArr[i];
if (x == i) {
iFld = 34;
}
}
}
// -Xcomp -XX:CompileCommand=compileonly,Test*::*
static void testUnrolling2() {
for (int i = 3; i > five; i -= 2) {
int x = 0;
x = iArr[i];
if (x == i) {
iFld = 34;
}
}
}
// -Xcomp -XX:CompileCommand=compileonly,Test*::*
static void testUnrolling4() {
int x = 0;
for (int i = 7; i > five; i -= 2) {
x = iArr[i];
if (x == i) {
iFld = 34;
}
}
}
// -Xcomp -XX:LoopUnrollLimit=150 -XX:CompileCommand=compileonly,Test*::*
static void testUnrolling8() {
int x = 0;
for (int i = 15; i > five; i -= 2) {
x = iArr[i];
if (x == i) {
iFld = 34;
}
}
}
// -Xcomp -XX:LoopUnrollLimit=150 -XX:CompileCommand=compileonly,Test*::*
static void testUnrolling16() {
int x = 0;
for (int i = 31; i > five; i -= 2) {
x = iArr[i];
if (x == i) {
iFld = 34;
}
}
}
// -Xcomp -XX:LoopUnrollLimit=150 -XX:CompileCommand=compileonly,Test*::*
// Loop is first peeled and then unrolled.
static void testPeelingUnrolling16() {
int three = 0;
int limit = 2;
long l1 = 34L;
long l2 = 35L;
long l3 = 36L;
long l4 = 37L;
for (; limit < 4; limit *= 2);
for (int i = 2; i < limit; i++) {
three = 33;
}
for (int i = 33; i > five; i -= 2) {
int x = iArr[i];
if (x == i) {
iFld += 34;
}
if (i > three) {
// DivLs add 30 to the loop body count and we hit LoopUnrollLimit.
// After CCP, these statements are folded away and we can unroll this loop.
l1 /= lFld;
l2 /= lFld;
l3 /= lFld;
l4 /= lFld;
}
if (flag) {
return;
}
}
}
// -Xcomp -XX:LoopMaxUnroll=0 -XX:CompileCommand=compileonly,Test*::*
static void testPeeling() {
for (int i = 1; i > five; i -= 2) {
int arrLoad = iArr[i];
if (flag) {
return;
}
if (arrLoad == i) {
iFld = 34;
}
}
}
// -Xcomp -XX:LoopMaxUnroll=0 -XX:CompileCommand=compileonly,Test*::*
private static void testPeelingTwice() {
for (int i = 3; i > five; i -= 2) {
int arrLoad = iArr[i];
if (flag) {
iFld2 = 3;
return;
}
if (i < 2 && flag2) {
return;
}
if (arrLoad == i) {
iFld = 34;
}
}
}
// -Xcomp -XX:LoopMaxUnroll=0 -XX:CompileCommand=compileonly,Test*::*
private static void testPeelingThreeTimes() {
for (int i = 5; i > five; i -= 2) {
int arrLoad = iArr[i];
if (iFld2 == 4) {
iFld2 = 20;
return;
}
if (i < 4 && iFld2 == 3) {
iFld2 = 42;
return;
}
if (i < 2 && iFld2 == 2) {
iFld2 = 52;
return;
}
if (arrLoad == i) {
iFld = 34;
}
}
}
// -Xcomp -XX:LoopMaxUnroll=0 -XX:CompileCommand=compileonly,Test*::*
static void testUnswitchingThenPeeling() {
for (int i = 1; i > five; i -= 2) {
iFld = iArr[i];
if (flag2) {
iFld2 = 24;
}
if (flag) {
return;
}
if (iFld == i) {
iFld = 34;
}
}
}
// -Xcomp -XX:CompileCommand=compileonly,Test*::test* -XX:LoopMaxUnroll=0
static void testPeelingThenUnswitchingThenPeeling() {
int zero = 34;
int limit = 2;
for (; limit < 4; limit *= 2);
for (int i = 2; i < limit; i++) {
zero = 0;
}
for (int i = 3; i > five; i -= 2) {
iFld = iArr[i];
if (iFld == i) {
fFld = 324;
}
if (flag) { // 1) Triggers loop peeling
return;
}
int k = iFld2 + i * zero; // loop variant before CCP
if (k == 34) { // 2) After CCP loop invariant -> triggers loop unswitching
iFld = 3;
} else {
iFld = iArr2[i]; // 3) After loop unswitching, triggers loop peeling again.
}
}
}
// -Xcomp -XX:CompileCommand=compileonly,Test*::test* -XX:LoopMaxUnroll=0
static void testPeelingThenUnswitchingThenPeelingThenPreMainPost() {
int zero = 34;
int limit = 2;
for (; limit < 4; limit *= 2);
for (int i = 2; i < limit; i++) {
zero = 0;
}
for (int i = 5; i > five; i -= 2) {
iFld = iArr[i];
if (iFld == i) {
fFld = 324;
}
if (flag) { // 1) Triggers loop peeling
return;
}
int k = iFld2 + i * zero; // loop variant before CCP
if (k == 34) { // 2) After CCP loop invariant -> triggers loop unswitching
iFld = 3;
} else {
iFld = iArr2[i]; // 3) After loop unswitching, triggers loop peeling again, then pre/main/post
}
}
}
// -Xcomp -XX:CompileCommand=compileonly,Test*::*
static void testPeelingThenPreMainPost() {
int three = 0;
int limit = 2;
long l1 = 34L;
long l2 = 35L;
for (; limit < 4; limit *= 2);
for (int i = 2; i < limit; i++) {
three = 3;
}
for (int i = 3; i > five; i -= 2) {
iFld = iArr[i];
if (iFld == i) {
iFld = 34;
}
if (i > three) {
// DivLs add 30 to the loop body count and we hit LoopUnrollLimit.
// After CCP, these statements are folded away and we can unroll this loop.
l1 /= lFld;
l2 /= lFld;
}
if (flag) {
return;
}
}
}
// -Xcomp -XX:CompileCommand=compileonly,Test*::*
static void testUnswitchingThenPeelingThenPreMainPost() {
int three = 0;
int limit = 2;
long l1 = 34L;
long l2 = 35L;
for (; limit < 4; limit *= 2);
for (int i = 2; i < limit; i++) {
three = 3;
}
for (int i = 3; i > five; i -= 2) {
iFld = iArr[i];
if (iFld == i) {
iFld = 34;
}
if (i > three) {
// DivLs add 30 to the loop body count and we hit LoopUnrollLimit.
// After CCP, these statements are folded away and we can unroll this loop.
l1 /= lFld;
l2 /= lFld;
}
if (flag2) {
iFld2 = 34;
}
if (flag) {
return;
}
}
}
// -XX:-UseProfiledLoopPredicate -Xcomp -XX:CompileCommand=compileonly,Test*::test*
static void testWithPartialPeelingFirst() {
int i = 3;
if (i > five) {
while (true) {
// Found as loop head in ciTypeFlow, but both path 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) {
}
// Loop exit test.
if (i <= five) {
break;
}
// <-- Partial Peeling CUT -->
// Safepoint
iFld = iArr[i];
if (iFld == i) {
fFld = 324;
}
i--;
}
}
}
// -Xcomp -XX:CompileCommand=compileonly,Test*::test* -XX:LoopUnrollLimit=40
static void testPeelMainLoopAfterUnrollingThenPreMainPostThenUnrolling() {
int zero = 34;
int limit = 2;
for (; limit < 4; limit *= 2);
for (int i = 2; i < limit; i++) {
zero = 0;
}
// 1) Pre/Main/Post
// 2) Unroll
// 3) Peel main loop
// 4) Pre/Main/Post peeled main loop
// 5) Unroll new main loop
for (int i = 13; i > five; i -= 2) {
iFld = iArr[i];
if (iFld == i) {
fFld = 324;
}
if (i < 13) { // Always true and folded in main loop because of executing pre-loop at least once -> i = [min_short..11]
int k = iFld2 + i * zero; // Loop variant before CCP
if (k == 40) { // After CCP: Loop Invariant -> Triggers Loop Peeling of main loop
return;
}
}
}
}
// -Xcomp -XX:CompileCommand=compileonly,Test*::test* -XX:LoopMaxUnroll=2
static void testPeelMainLoopAfterUnrollingThenPreMainPost() {
int zero = 34;
int limit = 2;
for (; limit < 4; limit *= 2);
for (int i = 2; i < limit; i++) {
zero = 0;
}
for (int i = 9; i > five; i -= 2) {
iFld = iArr[i];
if (iFld == i) {
fFld = 324;
}
if (i < 9) { // Always true and folded in main loop because of executing pre-loop at least once -> i = [min_short..7]
int k = iFld2 + i * zero; // Loop variant before CCP
if (k == 40) { // 2) After CCP: Loop Invariant -> Triggers Loop Peeling of main loop
return;
} else {
iFld3 = iArr2[i]; // After Peeling Main Loop: Check can be eliminated with Range Check Elimination -> 3) apply Pre/Main/Post and then 4) Range Check Elimination
}
}
}
}
// -Xcomp -XX:CompileCommand=compileonly,Test*::test* -XX:LoopMaxUnroll=2
static void testPeelMainLoopAfterUnrolling2() {
int zero = 34;
int limit = 2;
for (; limit < 4; limit *= 2);
for (int i = 2; i < limit; i++) {
zero = 0;
}
for (int i = 7; i > five; i -= 2) {
iFld = iArr[i];
if (iFld == i) {
fFld = 324;
}
if (i < 7) { // Always true and folded in main loop because of executing pre-loop at least once -> i = [min_short..5]
int k = iFld2 + i * zero; // Loop variant before CCP
if (k == 40) { // 2) After CCP: Loop Invariant -> Triggers Loop Peeling of main loop
return;
}
}
}
}
// Corresponds to JDK-8305428.
// -Xbatch -XX:CompileCommand=compileonly,Test*::*
public static void testTemplateAssertionPredicateNotRemovedHalt() {
int one = 34;
int limit = 2;
for (; limit < 4; limit *= 2);
for (int i = 2; i < limit; i++) {
one = 1;
}
int i = 80;
// 1) Found to be a counted loop with a limit between 1 and 34 (C2 only knows after CCP that 'one'
// is the constant 1).
// 2b) Two Hoisted Range Check Predicates.
// Two Template Assertion Predicates but triggering this bug, we only need to focus on one:
// Init Value: OpaqueLoopInit(0) <u iArrShort.length
// 4) After CCP, we know that this loop only runs for one iteration. The backedge is never taken
// and the CountedLoopNode can be folded away during IGVN.
// The Parse Predicates together with the Template Assertion Predicate from 2b) now end up
// above the partially peeled inner loop.
for (int j = 0; j < one; j++) {
// 3) Apply Partial Peeling which gives us the following loop:
// for (i = 80; i >= 5; i--) { fFld += 34; }
// Note that this loop does not have any Parse Predicates above its loop entry.
// 5) This loop is converted to a counted loop.
// 6) We pre-main-post this loop and update the Template Assertion Predicate for the main-loop
// The problem now is, that we use the init value of this loop which is completely
// unrelated to the init value of the outer loop for which this Tempalte Asseriton Predicate
// was originally created! We get the following wrong Template Assertion Predicate for the
// init value:
// OpaqueLoopInit(79) <u iArrShort.length
// From that we create a wrong Initialized Assertion Predicate:
// 79 <u iArrShort.length
// During runtime, we know the length:
// 79 <u iArrShort.length = 10
// And the Initialized Assertion Predidate fails. We execute the corresponding Halt node
// and the VM crashes.
while (true) {
// 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) {
}
// Loop exit test.
if (i < 5) {
break;
}
// <-- Partial Peeling CUT -->
// Safepoint
fFld += 34; // Make sure loop not empty.
i--;
}
// 2a) Loop Predication hoists this check out of the loop with two Hoisted Range Check
// Predicates and two Template Assertion Predicates at 2b).
iArrShort[j] = 3;
}
}
// Corresponds to JDK-8305428 but with different manifestation (malformed graph).
// -Xbatch -XX:CompileCommand=compileonly,Test*::*
public static void testTemplateAssertionPredicateNotRemovedMalformedGraph() {
int zero = 34;
int limit = 2;
for (; limit < 4; limit *= 2);
for (int i = 2; i < limit; i++) {
zero = 1;
}
int i = 80;
for (int j = 0; j < zero; j++) {
while (true) {
// 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) {
}
// Loop exit test.
if (i < -5) {
break;
}
// <-- Partial Peeling CUT -->
// Safepoint
fFld = iArr2[i+5];
i--;
}
iArr[j] = 3;
}
}
/*
* Some tests catching some issues while adding the new implementation.
*/
// Initialized Assertion Predicate with ConI as bool node is not recognized, and we miss to remove a Template
// Assertion Predicate from which we later create a wrong Initialized Assertion Predicate (for wrong loop).
static void testDyingInitializedAssertionPredicate() {
boolean b = false;
int i4, i6, i7 = 14, i8, iArr[][] = new int[10][10];
for (int i = 0; i < iArr.length; i++) {
inline(iArr[i]);
}
for (i4 = 7; i4 < 10; i4++) {
iArr2[1] += 5;
}
for (i6 = 100; i6 > 4; --i6) {
i8 = 1;
while (++i8 < 6) {
sArr[i8] = 3;
i7 += i8 + i8;
iArr2[i8] -= 34;
}
}
}
public static void inline(int[] a) {
for (int i = 0; i < a.length; i++) {
a[i] = 4;
}
}
static void testDyingRuntimePredicate() {
int zero = 34;
int[] iArrLoc = new int[100];
int limit = 2;
int loopInit = -10;
int four = -10;
for (; limit < 4; limit *= 2);
for (int i = 2; i < limit; i++) {
zero = 0;
loopInit = 99;
four = 4;
}
// Template + Hoisted Range Check Predicate for iArr[i]. Hoisted Invariant Check Predicate IC for iArr3[index].
// After CCP: ConI for IC and uncommon proj already killed -> IGVN will fold this away. But Predicate logic
// need to still recognize this predicate to find the Template above to kill it. If we don't do it, then it
// will end up at loop below and peeling will clone the template and create a completely wrong Initialized
// Assertion Predicate, killing some parts of the graph and leaving us with a broken graph.
for (int i = loopInit; i < 100; i++) {
iArr[i] = 34;
iArrLoc[four] = 34;
}
int i = -10;
while (true) {
// 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 (zero * i == 34) {
iFld2 = 23;
} else {
iFld = 2;
}
// Loop exit test.
if (i >= -2) {
break;
}
// <-- Partial Peeling CUT -->
// Safepoint
if (zero * i + five == 0) {
return;
}
iFld2 = 34;
i++;
}
}
static void testDyingNegatedRuntimePredicate() {
int zero = 34;
int[] iArrLoc = new int[100];
int limit = 2;
int loopInit = -10;
int four = -10;
for (; limit < 4; limit *= 2);
for (int i = 2; i < limit; i++) {
zero = 0;
loopInit = 99;
four = 4;
}
// Template + Hoisted Range Check Predicate for iArr[i]. Hoisted Invariant Check Predicate IC for iArr3[index].
// After CCP: ConI for IC and uncommon proj already killed -> IGVN will fold this away. But Predicate logic
// need to still recognize this predicate to find the Template above to kill it. If we don't do it, then it
// will end up at loop below and peeling will clone the template and create a completely wrong Initialized
// Assertion Predicate, killing some parts of the graph and leaving us with a broken graph.
for (int i = loopInit; i < 100; i++) {
iArr[i] = 34;
if (-3 > loopInit) {
// Negated Hoisted Invariant Check Predicate.
iArrLoc[101] = 34; // Always out of bounds and will be a range_check trap in the graph.
}
}
int i = -10;
while (true) {
// 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 (zero * i == 34) {
iFld2 = 23;
} else {
iFld = 2;
}
// Loop exit test.
if (i >= -2) {
break;
}
// <-- Partial Peeling CUT -->
// Safepoint
if (zero * i + five == 0) {
return;
}
iFld2 = 34;
i++;
}
}
/*
* Tests to verify correct data dependencies update when splitting loops for which we created Hoisted Predicates.
* If they are not updated correctly, we could wrongly execute an out-of-bounds load resulting in a segfault.
*/
// -Xcomp -XX:CompileCommand=compileonly,Test*::test* -XX:+StressGCM -XX:CompileCommand=dontinline,*::dontInline
static void testDataUpdateUnswitchingPeelingUnroll() {
long l1 = 34L;
long l2 = 566L;
int hundred = 0;
for (int i = 0; i < 8; i++) {
if ((i % 2) == 0) {
hundred = 100;
}
}
Foo[] fooArr;
int limit;
if (flag) {
limit = 3;
fooArr = new Foo[20000001];
} else {
limit = 5;
fooArr = new Foo[40000001];
}
for (int i = 0; i < limit; i++) {
fooArr[10000000 * i] = foo;
}
// 10) This loop is not optimized in any way because we have a call inside the loop. This loop is only required
// to trigger a crash.
// 11) During GCM with StressGCM, we could schedule the LoadN from the main loop before checking if we should
// enter the main loop. When 'flag' is true, we only have an array of size 20000001. We then perform
// the LoadN[3*10000000] and crash when the memory is unmapped.
for (float f = 0; f < 1.6f; f += 0.5f) {
// 2) Loop is unswitched
// 4) Both loop are peeled (we focus on one of those since both are almost identical except for the
// unswitched condition):
// Peeled iteration [i = 0]
// Loop [i = 1..4, stride = 1]
// 5) Loop unroll policy now returns true.
// Peeled iteration [i = 0]
// - Loop is pre-main-posted
// Loop-pre[i = 1..4, stride = 1]
// Loop-main[i = 2..4, stride = 1]
// Loop-post[i = 2..4, stride = 1]
// - Loop is unrolled once
// Loop-pre[i = 1..4, stride = 1]
// Loop-main[i = 2..4, stride = 2]
// Loop-post[i = 2..4, stride = 1]
// 6) During IGVN, we find that the backedge is never taken for main loop (we would over-iteratre) and it
// collapses to a single iteration.
// 7) After loop opts, the pre-loop is removed.
for (int i = 0; i < limit; i++) {
// 1) Hoisted with a Hoisted Range Check Predicate
// 8) The 'i = 1' value is propagated to the single main loop iteration and we have the following
// fixed-index accesses:
// LoadN[2*10000000];
// LoadN[3*10000000];
// 9) Without explicitly pinning the LoadN from the main loop at the main loop entry (i.e. below the
// zero trip guard), they are still pinned below the Hoisted Range Check Predicate before the loop.
fooArr[i * 10000000].iFld += 34;
if (flagFalse) {
return; //Enables peeling
}
// 3) hundred only known to be 100 after second loop opts -> becomes dead.
// The expense statements are folded away and we can unroll this loop because we are below the
// LoopUnrollLimit again.
if (i > hundred) {
// DivLs add 30 to the loop body count and we hit LoopUnrollLimit -> loop not unrolled
l1 /= lFld;
l2 /= lFld;
}
if (flagFalse2) { // Loop invariant -> enables Loop Unswitching
iFld += 34;
}
}
dontInline(); // Ensure that float loop is not peeled
}
}
// -Xcomp -XX:CompileCommand=compileonly,Test*::test* -XX:+StressGCM -XX:CompileCommand=dontinline,*::dontInline
static void testDataUpdateUnswitchUnroll() {
long l1 = 34L;
long l2 = 566L;
int hundred = 0;
for (int i = 0; i < 4; i++) {
if ((i % 2) == 0) {
hundred = 100;
}
}
Foo[] fooArr;
int limit;
if (flag) {
limit = 2;
fooArr = new Foo[10000001];
} else {
limit = 3;
fooArr = new Foo[20000001];
}
for (int i = 0; i < limit; i++) {
fooArr[10000000 * i] = foo;
}
// 9) This loop is not optimized in any way because we have a call inside the loop. This loop is only required
// to trigger a crash.
// 10) During GCM with StressGCM, we could schedule the LoadN from the main loop before checking if we should
// enter the main loop. When 'flag' is true, we only have an array of size 10000001. We then perform
// the LoadN[2*10000000] and crash when the memory is unmapped.
for (float f = 0; f < 1.6f; f += 0.5f) {
// 2) Loop is unswitched
// 4) Loop unroll policy now returns true.
// - Loop is pre-main-posted
// Loop-pre[i = 0..2, stride = 1]
// Loop-main[i = 1..2, stride = 1]
// Loop-post[i = 1..2, stride = 1]
// - Loop is unrolled once
// Loop-pre[i = 0..2, stride = 1]
// Loop-main[i = 1..2, stride = 2]
// Loop-post[i = 1..2, stride = 1]
// 5) During IGVN, we find that the backedge is never taken for main loop and it collapses to a single
// iteration.
// 6) After loop opts, the pre-loop is removed.
for (int i = 0; i < limit; i++) {
// 1) Hoisted with a Hoisted Range Check Predicate
// 7) The 'i = 1' value is propagated to the single main loop iteration and we have the following
// fixed-index accesses:
// LoadN[1*10000000];
// LoadN[2*10000000];
// 8) Without explicitly pinning the LoadN from the main loop at the main loop entry (i.e. below the
// zero trip guard), they are still pinned below the Hoisted Range Check Predicate before the loop.
fooArr[i * 10000000].iFld += 34;
// 3) hundred only known to be 100 after second loop opts -> becomes dead.
// The expense statements are folded away and we can unroll this loop because we are below the
// LoopUnrollLimit again.
if (i > hundred) {
// DivLs add 30 to the loop body count and we hit LoopUnrollLimit -> loop not unrolled
l1 /= lFld;
l2 /= lFld;
}
if (flag) { // invariant -> enabled Loop Unswitching
iFld = 34;
}
}
dontInline(); // Ensure that float loop is not peeled
}
}
// -Xcomp -XX:CompileCommand=compileonly,Test*::test* -XX:+StressGCM -XX:CompileCommand=dontinline,*::dontInline
static void testDataUpdateUnroll() {
long l1 = 34L;
long l2 = 566L;
int hundred = 0;
for (int i = 0; i < 4; i++) {
if ((i % 2) == 0) {
hundred = 100;
}
}
Foo[] fooArr;
int limit;
if (flag) {
limit = 2;
fooArr = new Foo[10000001];
} else {
limit = 3;
fooArr = new Foo[20000001];
}
for (int i = 0; i < limit; i++) {
fooArr[10000000 * i] = foo;
}
// 8) This loop is not optimized in any way because we have a call inside the loop. This loop is only required
// to trigger a crash.
// 9) During GCM with StressGCM, we could schedule the LoadN from the main loop before checking if we should
// enter the main loop. When 'flag' is true, we only have an array of size 10000001. We then perform
// the LoadN[2*10000000] and crash when the memory is unmapped.
for (float f = 0; f < 1.6f; f += 0.5f) {
// 3) Loop unroll policy now returns true.
// - Loop is pre-main-posted
// Loop-pre[i = 0..2, stride = 1]
// Loop-main[i = 1..2, stride = 1]
// Loop-post[i = 1..2, stride = 1]
// - Loop is unrolled once
// Loop-pre[i = 0..2, stride = 1]
// Loop-main[i = 1..2, stride = 2]
// Loop-post[i = 1..2, stride = 1]
// 4) During IGVN, we find that the backedge is never taken for main loop and it collapses to a single
// iteration.
// 5) After loop opts, the pre-loop is removed.
for (int i = 0; i < limit; i++) {
// 1) Hoisted with a Hoisted Range Check Predicate
// 6) The 'i = 1' value is propagated to the single main loop iteration and we have the following
// fixed-index accesses:
// LoadN[1*10000000];
// LoadN[2*10000000];
// 7) Without explicitly pinning the LoadN from the main loop at the main loop entry (i.e. below the
// zero trip guard), they are still pinned below the Hoisted Range Check Predicate before the loop.
fooArr[i * 10000000].iFld += 34;
// 2) hundred only known to be 100 after second loop opts -> becomes dead.
// The expense statements are folded away and we can unroll this loop because we are below the
// LoopUnrollLimit again.
if (i > hundred) {
// DivLs add 30 to the loop body count and we hit LoopUnrollLimit -> loop not unrolled
l1 /= lFld;
l2 /= lFld;
}
}
dontInline(); // Ensure that float loop is not peeled
}
}
// -Xcomp -XX:CompileCommand=compileonly,Test*::test* -XX:+StressGCM -XX:CompileCommand=dontinline,*::dontInline
static void testDataUpdatePeelingUnroll() {
long l1 = 34L;
long l2 = 566L;
int hundred = 0;
for (int i = 0; i < 4; i++) {
if ((i % 2) == 0) {
hundred = 100;
}
}
Foo[] fooArr;
int limit;
if (flag) {
limit = 3;
fooArr = new Foo[20000001];
} else {
limit = 5;
fooArr = new Foo[40000001];
}
for (int i = 0; i < limit; i++) {
fooArr[10000000 * i] = foo;
}
// 9) This loop is not optimized in any way because we have a call inside the loop. This loop is only required
// to trigger a crash.
// 10) During GCM with StressGCM, we could schedule the LoadN from the main loop before checking if we should
// enter the main loop. When 'flag' is true, we only have an array of size 20000001. We then perform
// the LoadN[3*10000000] and crash when the memory is unmapped.
for (float f = 0; f < 1.6f; f += 0.5f) {
// 2) Loop is peeled:
// Peeled iteration [i = 0]
// Loop [i = 1..4, stride = 1]
// 4) Loop unroll policy now returns true.
// Peeled iteration [i = 0]
// - Loop is pre-main-posted
// Loop-pre[i = 1..4, stride = 1]
// Loop-main[i = 2..4, stride = 1]
// Loop-post[i = 2..4, stride = 1]
// - Loop is unrolled once
// Loop-pre[i = 1..4, stride = 1]
// Loop-main[i = 2..4, stride = 2]
// Loop-post[i = 2..4, stride = 1]
// 5) During IGVN, we find that the backedge is never taken for main loop (we would over-iteratre) and it
// collapses to a single iteration.
// 6) After loop opts, the pre-loop is removed.
for (int i = 0; i < limit; i++) {
// 1) Hoisted with a Hoisted Range Check Predicate
// 7) The 'i = 1' value is propagated to the single main loop iteration and we have the following
// fixed-index accesses:
// LoadN[2*10000000];
// LoadN[3*10000000];
// 8) Without explicitly pinning the LoadN from the main loop at the main loop entry (i.e. below the
// zero trip guard), they are still pinned below the Hoisted Range Check Predicate before the loop.
fooArr[i * 10000000].iFld += 34;
if (flagFalse) {
return; // Enables peeling
}
// 3) hundred only known to be 100 after second loop opts -> becomes dead.
// The expense statements are folded away and we can unroll this loop because we are below the
// LoopUnrollLimit again.
if (i > hundred) {
// DivLs add 30 to the loop body count and we hit LoopUnrollLimit -> loop not unrolled
l1 /= lFld;
l2 /= lFld;
}
}
dontInline(); // Ensure that float loop is not peeled
}
}
// -Xcomp -XX:LoopMaxUnroll=0 -XX:+StressGCM -XX:CompileCommand=compileonly,Test*::*
private static void testPeelingThreeTimesDataUpdate() {
Foo[] fooArr = new Foo[fooArrSize];
for (int i = 0; i < two; i++) {
fooArr[10000000 * i] = foo;
}
int x = 0;
// 2) The Hoisted Range Check Predicate is accompanied by two Template Assertion Predicates. The LoadN node,
// previously pinned at the hoisted range check, is now pinned at the Template Assertion Predicate. Note
// that the LoadN is still inside the loop body.
// 3) The loop is now peeled 3 times which also peels 3 loads from 'fooArr' out of the loop:
// // Peeled section from 1st Loop Peeling
// ...
// LoadN[0]
// ...
// <loop entry guard>
// // Peeled section from 2nd Loop Peeling
// ...
// LoadN[10000000]
// Initialized Assertion Predicate (***)
// <loop entry guard>
// // Peeled section from 3rd Loop Peeling
// ...
// LoadN[20000000]
// ...
// Initialized Assertion Predicate
// <loop entry guard>
// Template Assertion Predicate
// Initialized Assertion Predicate
// Loop:
// LoadN[i*10000000]
//
// To avoid that the peeled LoadN nodes float above the corresponding loop entry guards, we need to pin them
// below. That is done by updating the dependency of the peeled LoadN to the new Template Assertion Predicate.
// This is currently broken: We wrongly set the dependency to the Initialized Assertion Predicate instead of the
// Template Assertion Predicate. We can then no longer find the dependency and miss to update it in the next
// Loop Peeling application. As a result, all the LoadN pile up at the originally added Initialized Assertion
// Predicate of the first Loop Peeling application at (***).
//
// With GCM, we could schedule LoadN[20000000] at (***), before the loop entry corresponding loop entry guard
// for this load. We then crash during runtime because we are accessing an out-of-range index. The fix is to
// properly update the data dependencies to the Template Assertion Predicates and not the Initialized Assertion
// Predicates.
for (int i = 0; i < two; i++) {
// 1) Hoisted with a Hoisted Range Check Predicate
x += fooArr[i * 10000000].iFld;
if (iFld2 == 4) {
return;
}
if (i > 0 && iFld2 == 3) {
iFld2 = 42;
return;
}
if (i > 1 && iFld2 == 2) {
return;
}
}
}
/*
* Tests collected in JBS and duplicated issues
*/
// -Xbatch -XX:CompileCommand=compileonly,Test*::*
static void test8305428() {
int j = 1;
do {
for (int k = 270; k > 1; --k) {
iFld++;
}
switch (j) {
case 1:
switch (92) {
case 92:
flag = flag;
}
case 2:
iArr[j] = 3;
}
} while (++j < 100);
}
// -Xbatch -XX:CompileCommand=compileonly,Test*::*
static void test8305428No2() {
int i = 1;
do {
for (int j = 103; j > 1; --j) {
iArr[i] = iArr[j / 34];
}
for (int j = 103; j > 4; j -= 3) {
switch (i % 9) {
case 0:
case 2:
case 3:
iArr[i - 1] = 34;
case 8:
}
}
} while (++i < 99);
}
static void test8320920() {
int i = 1;
do {
for (int j = 83; j > i; j--) {
iFld = 3;
}
for (int j = 5; j < 83; j++) {
for (int k = i; k < 2; k++)
;
}
iArr3[i - 1] = 34;
} while (++i < 300);
}
static void test8332501() {
int i = 1;
do {
for (int j = 108; j > 1; j -= 2) {
fFld += j;
}
for (int j = 3; 108 > j; j++) {
for (int k = 2; k > i; --k) {
}
}
iArr[i] = 34;
} while (++i < 150);
}
// -Xcomp -XX:CompileCommand=compileonly,Test*::*
static void test8288981() {
int x = 1;
// Sufficiently many iterations to trigger OSR
for (int j = 0; j < 50_000; j++) {
for (int i = 1; i > x; --i) {
float v = fArr[0] + fFld;
fArr2D[i + 1][x] = v;
iFld += v;
}
}
}
// -Xcomp -XX:CompileCommand=compileonly,Test*::*
static void test8292507() {
int i = iFld, j, iArr[] = new int[40];
while (i > 0) {
for (j = i; 1 > j; ++j) {
try {
iArr[j] = 0;
iArr[1] = iFld = 0;
} catch (ArithmeticException a_e) {
}
switch (i) {
case 4:
case 43:
iFld2 = j;
}
}
}
}
// -Xcomp -XX:CompileCommand=compileonly,Test*::*
static void test8307131() {
int i21 = 6, i, i23 = 3, y, iArr2[] = new int[40];
for (i = 50000; 3 < i; i--) {
for (y = 2; y > i; y--) {
try {
i21 = i23 / 416 / iArr2[y];
} catch (ArithmeticException a_e) {
}
i23 -= 3;
}
}
i21 -= 2;
}
void test8296077() {
int i4 = 4, iArr1[] = new int[10];
float f2;
for (f2 = 7; f2 > 4; --f2) {}
float f4 = five;
while (f4 < 50000) {
for (int i7 = (int) f4; 1 > i7; i7++) {
iArr1[i7] = 5;
if (i4 != 0) {
return;
}
byFldVol = 2;
try {
iArr1[(int) f4] = i4 = iArr1[(int) f4 + 1] % iArr1[(int) f2];
} catch (ArithmeticException a_e) {
}
}
f4++;
}
}
static void test8308392No1() {
int i10, i16;
try {
for (i10 = 61; i10 < 50000 ; i10++) {
for (i16 = 2; i16 > i10; i16--) {
sFld *= iArr2D[i16][i16] = byFld *= sFld;
}
}
} catch (NegativeArraySizeException exc3) {
}
}
static void test8308392No2() {
try {
int j, k, i19 = 8;
for (int i = 0; i < 10; i++) {
for (j = 2; j < 3; ) {
if (flagTrue) {
iFld++;
iFld2 = 34 / iFld; // Will eventually divide by zero and break infinite loop.
}
for (k = 2; k > j; --k) {
i19 *= fArr2D[k][j] += i;
}
}
}
} catch (ArithmeticException e) {
// Expected
}
}
static void test8308392No3() {
int i18, i19, i21, i22 = 1, iArr2[][] = new int[40][];
double dArr[] = new double[40];
i18 = 1;
for (i19 = 5; i19 < 50000; i19++) {
for (i21 = i18; i21 < 4; ++i21) {
switch (i19) {
case 4:
iArr2[i21 - 1][i18] = 3;
try {
iFld = 2 % iFld;
iFld = i22;
} catch (ArithmeticException a_e) {
}
break;
case 45:
i22 += dArr[i22];
}
}
}
}
static void test8308392No4() {
int i20, i22 = 6, i25;
for (i20 = 50000; i20 > 3; i20--) {
for (i25 = 1; i25 > i22; i25--) {
iArr2D[i25 + 1][i22] += fFld -= iFld;
}
}
}
static void test8308392No5() {
float f1;
int i20, i23, i25 = 5, i26 = 4, i27;
long lArr[][] = new long[10][10];
for (f1 = 40; f1 > 3; --f1) {
for (i20 = 2; 11 > i20; i20++) {
for (i23 = 1; i23 < 11; ) {
i23++;
for (i27 = (int) f1; i27 < 1; ++i27) {
iFld = 3;
lArr[i27][i25] = 5;
if (flag) {
i26 += i25;
}
}
}
}
}
}
static void test8308392No6() {
int i, i1, i2, i23 = 7, i24;
double dArr1[][] = new double[10][];
boolean bArr[] = new boolean[10];
for (i = 9; i < 88; i++) {
i2 = 1;
do {
i1 = Short.reverseBytes((short) 0);
for (i24 = 1; i2 < i24; --i24) {
i1 %= dArr1[i24 + 1][i];
switch (i23) {
case 0:
bArr[i] = false;
}
}
i2++;
} while (i2 < 50000);
}
}
static void test8308392No7() {
int i16 = 2, i17 = 1, i18, i20, i21, i23;
double d2 = 86.53938;
long lArr[][] = new long[10][];
for (i18 = 1; i18 < 10; i18++) {
i20 = 1;
while (i20 < 5000) {
for (i21 = i23 = 1; i23 > i20; --i23) {
d2 *= i16 >>= lArr[i23 + 1][i20] >>= i17;
}
i20++;
}
}
}
static void test8308392No8() {
int i21, i22, i25 = 1, i26 = 032, i28;
i21 = iFld;
while (--i21 > 0) {
for (i22 = 2; i22 < 71; i22++) {
for (i28 = 2; i28 > i21; --i28) {
i25 %= i26;
iArr2D[i28][1] ^= 5;
}
}
i21--;
}
}
static void runTest8308392No9() {
try {
test8308392No9();
} catch (ArithmeticException | ArrayIndexOutOfBoundsException e) {
// Expected.
}
}
static void test8308392No9() {
for (int i20 = 60; ; i20--) {
for (int i22 = 2; i22 > i20; --i22) {
fFld += 5;
iFld = iFld / 9 / iArr[i22];
}
}
}
static void test8308392No10() {
int i14, i16 = -27148, i18, i21;
for (i14 = 21; i16 < 9; ++i16) {
for (i18 = 2; i14 < i18; i18--) {
iArr2D[i18][i18] -= lFld = i18;
}
for (i21 = 1; i21 < 2; i21++) {}
}
}
// -Xcomp -XX:-TieredCompilation
static void test8308504() {
int iArr[][] = new int[400][400];
for (int i16 = 294; i16 > 6; --i16) {
for (int i21 = 1; i21 < 87; ++i21) {
for (int i23 = 2; i23 > i21; i23--) {
switch (118) {
case 118:
iFld *= 3.4f;
iArr[i23][i16] *= 5;
}
}
}
}
System.nanoTime(); // Unloaded, triggers deopt
}
// -Xcomp -XX:-TieredCompilation
static void test8308504No2() {
int iArr[][] = new int[400][400];
for (int i = 294; i > 6; i--) {
for (int j = 1; j < 87; j++) {
for (int k = 2; k > j; k--) {
iFld *= 3.4f;
iArr[k][i] *= 5;
}
}
}
Math.pow(2, 3); // Unloaded, triggers deopt
}
static void testSplitIfCloneDownWithOpaqueAssertionPredicate() {
int p = 0, j;
if (flag) {
iArr[3] = 3;
dontInline();
}
int i = 1;
while (++i < 4) {
if (flag) {
p = 8;
}
iArr[i - 1] = 4;
for (j = 1; j < 3; ++j) {
iArr[j] = 34;
}
}
long n = p;
}
static void testTrySplitUpNonOpaqueExpressionNode() {
int zero = 34;
int limit = 2;
for (; limit < 4; limit *= 2);
for (int i = 2; i < limit; i++) {
flag = !flag;
flag2 = !flag2;
iFld = flag ? 50 : -50;
zero = 0;
}
for (int t = 0; t < 100; t++) {
// 4) Graph looks like this now:
// Split If is applied because the graph has the following shape:
//
// Region # **REGION**
// |
// NULL Phi[new int[100], iArr2] # 'iArr'
// \ /
// CmpU \
// | |
// Bool | # Hoisted NullCheck from 2b)
// | |
// If /
//
//
// We find that we can split the If through the Region because we have a Phi input for the condition CmpU
//
// 5) We apply Split-If to split the If through the region. This requires that we also handle all the Phi nodes
// belonging to the region to split through. We need to empty the block ('--- BLOCK start/end ---') by
// checking all users of the Phi* node. This is done removing all user of the
// phi nodes belonging to the Region to split the If through. phi nodes.
// This requires that we split up all users of the phi recursively through the phi. The new users of the Phis
// are then revisited again since Split-If is applied iteratively for all nodes. We stop the "splitting up"
// when a user of a Phi node has its get_ctrl() at a different node than the region to split through.
//
// We have the following graph before Split If:
//
// Region # **REGION**
// |
// Phi
// |
// LoadUB # 'flag2'loaded either from the merged memory state of the region
// |
// CmpI
// |
// Bool
// |
// CmoveI # From 1)
// |
// ConvI2L
// |
// AddL # First node part of Template Assertion Predicate expression of 3b).
// |
// CmpUL
// |
// OpaqueTemplateAssertionPredicate
//
// 6) We start applying Split If and iteratively split users of Phi nodes up. We find that all nodes including
// the AddL, can be split through the new phis because they have their get_ctrl() set to the REGION.
// Why isnt the control of the AddL not set to the latest control (which we usually do when having the
// same loop depth) at 3b) where the Template Assertion Predicate Expression node belongs to?
// The reason is that during build_loop_late_post_work(), we skip all predicates to not interfere with
// Loop Predication, including the NullCheck from 2b) . Thus, we move late control up to REGION because the
// if/else is already removed with a CMove in 1).
//
// 7) When splitting the AddL node, have the following graph:
//
// Region # **REGION**
// |
// | OpaqueLoopInit
// | |
// Phi ConvI2L
// \ /
// AddL
//
// We find that it's part of a Template Assertion Predicate Expression. We do not want to split such a node
// to not introduce a Phi node within the expression which would mess with pattern matching to find the
// OpaqueLoop* nodes from the Template Assertion Predicate If. As a solution, we "clone down" the Template
// Assertion Predicate Expression by creating a clone of the entire Template Assertion Predicate Expression.
// We then feed the Phi for the new Region, after splitting the If, into the AddL as part of the
// Template Assertion Predicate Expression.
//
// Note: When trying to split AddL, we first try to split its inputs, i.e. ConvI2L. But ConvI2L has its
// get_ctrl() outside of the outer "for (t = ...)" loop because the OpaqueLoopInit node has a constant
// as input and thus build_loop_late_post_work() will make sure that late control does not have a
// deeper nesting than early. In testTrySplitUpOpaqueLoopInit(), we remove the outer loop and
// therefore try to split up the OpaqueLoopInit node first which will initiate the "clone down".
int[] iArr;
if (flag) {
iArr = new int[100];
} else {
dontInline();
iArr = iArr2;
}
// **REGION**
// - Phi[new int[100], iArr2] = Phi[DecodeN[int:100], DecodeN[n>=0]] # 'iArr'
// - Phi[flag, flag] # 'flag' -> once loaded from the if-branch and once from the else-branch related memory
// --- BLOCK start ---
// 1) Replaced with CMove:
// a = CMove(flag, 3, 4)
//
// Note: Even though we run with -Xcomp where we don't know the frequency, we still cmove because of
// -XX:-BlockLayoutByFrequency
int a;
if (flag2) {
a = 4;
} else {
a = 3;
}
// --- BLOCK end ---
// 2b) Hoisted Check Predicate: NullCheck(iArr)
// 3b) Hoisted Check Predicate: RangeCheck(iArr) + TAPs(iArr)
for (int i = 0; i < 100; i++) {
// 2a) Null check hoisted with a Hoisted Check Predicate -> put at 2b)
// 3a) Range check hoisted with a Hoisted Check Predicate + Template Assertion Predicates -> put at 3b)
iArr[i + a] = 34;
// 8) After CCP, we find that this condition equals to "0 < iFld". Since this is loop-invariant and
// a loop-exit, we apply Loop Peeling which verifies that we do not have a Template Assertion
// Predicate with a Phi node.
if (i * zero < iFld) {
return;
}
}
}
}
// Same as test above but this time the "clone down" is initiated when trying to split up an OpaqueLoopInitNode.
static void testTrySplitUpOpaqueLoopInit() {
int zero = 34;
int limit = 2;
for (; limit < 4; limit *= 2);
for (int i = 2; i < limit; i++) {
zero = 0;
}
// 4) Graph looks like this now:
// Split If is applied because the graph has the following shape:
//
// Region # **REGION**
// |
// NULL Phi[new int[100], iArr2] # 'iArr'
// \ /
// CmpU \
// | |
// Bool | # Hoisted NullCheck from 2b)
// | |
// If /
//
//
// We find that we can split the If through the Region because we have a Phi input for the condition CmpU
//
// 5) We apply Split-If to split the If through the region. This requires that we also handle all the Phi nodes
// belonging to the region to split through. We need to empty the block ('--- BLOCK start/end ---') by
// checking all users of the Phi* node. This is done removing all user of the
// phi nodes belonging to the Region to split the If through. phi nodes.
// This requires that we split up all users of the phi recursively through the phi. The new users of the Phis
// are then revisited again since Split-If is applied iteratively for all nodes. We stop the "splitting up"
// when a user of a Phi node has its get_ctrl() at a different node than the region to split through.
//
// We have the following graph before Split If:
//
// Region # **REGION**
// |
// Phi
// |
// LoadUB # 'flag2'loaded either from the merged memory state of the region
// |
// CmpI
// |
// Bool
// |
// CmoveI # From 1)
// |
// ConvI2L
// |
// AddL # First node part of Template Assertion Predicate expression of 3b).
// |
// CmpUL
// |
// OpaqueTemplateAssertionPredicate
//
// 6) We start applying Split If and iteratively split users of Phi nodes up. We find that all nodes including
// the AddL, can be split through the new phis because they have their get_ctrl() set to the REGION.
// Why isnt the control of the AddL not set to the latest control (which we usually do when having the
// same loop depth) at 3b) where the Template Assertion Predicate Expression node belongs to?
// The reason is that during build_loop_late_post_work(), we skip all predicates to not interfere with
// Loop Predication, including the NullCheck from 2b) . Thus, we move late control up to REGION because the
// if/else is already removed with a CMove in 1).
//
// 7) When splitting the AddL node, have the following graph:
//
// Region # **REGION**
// |
// | OpaqueLoopInit
// | |
// Phi ConvI2L
// \ /
// AddL
//
// We find that it's part of a Template Assertion Predicate Expression. We do not want to split such a node
// to not introduce a Phi node within the expression which would mess with pattern matching to find the
// OpaqueLoop* nodes from the Template Assertion Predicate If. As a solution, we "clone down" the Template
// Assertion Predicate Expression by creating a clone of the entire Template Assertion Predicate Expression.
// We then feed the Phi for the new Region, after splitting the If, into the AddL as part of the
// Template Assertion Predicate Expression.
//
// Note: The difference to testTrySplitUpNonOpaqueExpressionNode() above is that when trying to split AddL,
// we first split up its inputs recursively if they also have get_ctrl() at the region to split through.
// This is the case for ConvI2L and OpaqueLoopInit. Therefore, the split of OpaqueLoopInit will
// initiate the "clone down".
int[] iArr;
if (flag) {
iArr = new int[100];
} else {
dontInline();
iArr = iArr2;
}
// **REGION**
// - Phi[new int[100], iArr2] = Phi[DecodeN[int:100], DecodeN[n>=0]] # 'iArr'
// - Phi[flag, flag] # 'flag' -> once loaded from the if-branch and once from the else-branch related memory
// --- BLOCK start ---
// 1) Replaced with CMove:
// a = CMove(flag, 3, 4)
//
// Note: Even though we run with -Xcomp where we don't know the frequency, we still cmove because of
// -XX:-BlockLayoutByFrequency
int a;
if (flag2) {
a = 4;
} else {
a = 3;
}
// --- BLOCK end ---
// 2b) Hoisted Check Predicate: NullCheck(iArr)
// 3b) Hoisted Check Predicate: RangeCheck(iArr) + TAPs(iArr)
for (int i = 0; i < 100; i++) {
// 2a) Null check hoisted with a Hoisted Check Predicate -> put at 2b)
// 3a) Range check hoisted with a Hoisted Check Predicate + Template Assertion Predicates -> put at 3b)
iArr[i + a] = 34;
// 8) After CCP, we find that this condition equals to "0 < iFld". Since this is loop-invariant and
// a loop-exit, we apply Loop Peeling which verifies that we do not have a Template Assertion
// Predicate with a Phi node.
if (i * zero < iFld) {
return;
}
}
}
static void testBackToBackLoopLimitCheckPredicate() {
int i = 34;
if (flag) {}
while (i < 50) {
i++;
}
for (int j = 0; j < 4; j++) {
iArr[j] += 34;
}
}
// -Xcomp -XX:CompileCommand=compileonly,Test*::*
static int test8288941() {
int e = 8, g = 5, j;
int h = 1;
while (++h < 100000) {
for (j = 1; j > h; j--) {
try {
iFld = 0;
g = iArr[1] / e;
} catch (ArithmeticException ae) {
}
iArr[j + 1] = 4;
if (e == 9) {
iFld2 = 3;
}
}
}
return g;
}
// JDK-8288941, -Xcomp -XX:CompileCommand=compileonly,Test::test
static void testRemovingParsePredicatesThenMissingTemplates() {
int one = 34;
int limit = 2;
for (; limit < 4; limit *= 2);
for (int i = 2; i < limit; i++) {
one = 1; // Only known to be 1 after CCP.
}
long l1 = 34L;
long l2 = 566L;
// 10) After IGVN, the StoreF has lost most of its out edges due to the removal of the MergeMems into the UCTs
// of the Parse Predicates.
// 11) policy_maximally_unroll() now returns true and we can maximally unroll this loop.
int j;
for (j = 0; j < 4; j++) {
// 1) StoreF has a huge number of MergeMem uses for the UCTs of all the loops further down. As a result,
// policy_maximally_unroll() will return false because est_loop_unroll_sz() -> est_loop_flow_merge_sz()
// counts all out edges to nodes outside the loop to estimate the cost of merging nodes when cloning the
// loop. This count is larger then the unroll limit and we do not apply MaxUnroll.
// Note: This is a store to a float array to not interfere with the int array store in the next loop below.
fArr[j] = 34;
// 2) DivLs add 30 to the loop body count and we hit LoopUnrollLimit which avoids normal Loop unrolling and
// thus pre/main/post loop creation. Therefore, we currently cannot split this loop in any way.
l1 /= lFldOne;
l2 /= lFldOne;
}
long l3 = 34L;
long l4 = 566L;
// 13) Since the DivL nodes are now removed, the LoopUnrollLimit is not reached and we can finally pre/main/post
// and unroll this loop - with Template Assertion Predicates above but no more Parse Predicates!
// 14) We currently do not clone/update/establish Template Assertion Predicates once Parse Predicates are removed.
// Therefore, we create pre/main/post loops without Template Assertion Predicates and without Initialized
// Assertion Predicates.
int x = 0;
for (int i = 1; i > five; i -= 2) {
// 3) Loop Predication will hoist the range check out of the loop together with a Template Assertion Predicate.
// 15) After pre/main/post: the CastII for the array index get the new iv type [-1..-32767] and is replaced by
// top. Data dies but there is no Intialized Assertion Predicate above the main loop and we are left with
// a broken graph. We assert when running with -XX:+AbortVMOnCompilationFailure due to a malformed graph.
int arrLoad = iArr[i];
if (arrLoad == i) {
iFld = 34;
}
// 4) This check is non-loop invariant, so Loop Unswitching cannot be applied, either.
// 12) After maximally unrolling the loop above, we know that j == 4 and thus "j+(i*-1) = 4+[-1..32767] < 3" is
// always false. The branch is cleaned up in the next IGVN round which also removes the expensive DivL nodes.
if (j+(i*-1) < 3) {
// 5) As above: We hit the LoopUnrollLimit which avoids normal Loop unrolling and thus pre/main/post loop
// creation. Therefore, we currently cannot split this loop in any way.
l3 /= lFldOne;
l4 /= lFldOne;
}
}
// Many non-counted loops that are not optimized but all have Parse Predicates with UCTs + a safepoint in the loop body.
// The StoreF from the loop above will be merged with a MergeMem into all these UCTs.
//
// 6) After CCP, we find that 'one' is 1. Therefore, all loops will only iterate for a single iteration and the loop
// backedges die. These are cleaned up in the next round of IGVN.
// 7) In the next loop opts phase after CCP, we find that all these Parse Predicates above the loops are now useless.
// We mark them as such but will only clean them up in the next round of IGVN.
// 8) Since we do not apply any major loop optimization like loop splitting, we remove the remaining Parse Predicates
// (see "PredicatesOff" when running with -XX:+TraceLoopOpts). We set major progress again to see if we can continue
// to apply more loop optimizations.
// 9) IGVN runs and cleans up all the Parse Predicates and its UCTs.
for (int i = 0; i < one; i++) {
if (i < 2) {
i++;
}
}
for (int i = 0; i < one; i++) {
if (i < 2) {
i++;
}
}
for (int i = 0; i < one; i++) {
if (i < 2) {
i++;
}
}
for (int i = 0; i < one; i++) {
if (i < 2) {
i++;
}
}
for (int i = 0; i < one; i++) {
if (i < 2) {
i++;
}
}
for (int i = 0; i < one; i++) {
if (i < 2) {
i++;
}
}
for (int i = 0; i < one; i++) {
if (i < 2) {
i++;
}
}
for (int i = 0; i < one; i++) {
if (i < 2) {
i++;
}
}
for (int i = 0; i < one; i++) {
if (i < 2) {
i++;
}
}
for (int i = 0; i < one; i++) {
if (i < 2) {
i++;
}
}
for (int i = 0; i < one; i++) {
if (i < 2) {
i++;
}
}
for (int i = 0; i < one; i++) {
if (i < 2) {
i++;
}
}
for (int i = 0; i < one; i++) {
if (i < 2) {
i++;
}
}
for (int i = 0; i < one; i++) {
if (i < 2) {
i++;
}
}
for (int i = 0; i < one; i++) {
if (i < 2) {
i++;
}
}
for (int i = 0; i < one; i++) {
if (i < 2) {
i++;
}
}
for (int i = 0; i < one; i++) {
if (i < 2) {
i++;
}
}
for (int i = 0; i < one; i++) {
if (i < 2) {
i++;
}
}
for (int i = 0; i < one; i++) {
if (i < 2) {
i++;
}
}
for (int i = 0; i < one; i++) {
if (i < 2) {
i++;
}
}
for (int i = 0; i < one; i++) {
if (i < 2) {
i++;
}
}
for (int i = 0; i < one; i++) {
if (i < 2) {
i++;
}
}
for (int i = 0; i < one; i++) {
if (i < 2) {
i++;
}
}
for (int i = 0; i < one; i++) {
if (i < 2) {
i++;
}
}
for (int i = 0; i < one; i++) {
if (i < 2) {
i++;
}
}
for (int i = 0; i < one; i++) {
if (i < 2) {
i++;
}
}
for (int i = 0; i < one; i++) {
if (i < 2) {
i++;
}
}
for (int i = 0; i < one; i++) {
if (i < 2) {
i++;
}
}
}
// Not inlined.
static void dontInline() {
}
}