jdk-24/test/hotspot/jtreg/compiler/loopopts/TestCreateNewIfForPredicateCloning.java

409 lines
17 KiB
Java

/*
* Copyright (c) 2022, 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
* @bug 8290850
* @summary Test cloning of pinned phi input nodes in create_new_if_for_predicate().
* @run main/othervm -Xcomp -XX:CompileCommand=compileonly,compiler.loopopts.TestCreateNewIfForPredicateCloning::*
* compiler.loopopts.TestCreateNewIfForPredicateCloning
*/
package compiler.loopopts;
public class TestCreateNewIfForPredicateCloning {
static int iFld, iFld2, iFld3, nonZero = 2, nonZero2 = 3;
static boolean bFld = true, bFld2 = false;
static int[] iArrFld = new int[100];
public static void main(String[] args) {
try {
testUnswitching();
testLoopPredicatation();
testLoopPredicatationComplex();
testUnswitchingWithPredicates();
testUnswitchingWithPredicatesDiv();
testFuzzer1();
testFuzzer2();
testFuzzer3();
} catch (Exception e) {
// Expected
}
}
// Test case for the already fixed problem in 8271954: Calling create_new_if_for_predicate in
// clone_predicate_to_unswitched_loop(). This does not crash anymore. But still use it as sanity test here with the
// new fix.
static void testUnswitching() {
int x = 3;
// Block to delay precise type information to after CCP.
int limit = 2;
int constantAfterCCP = 2;
for (; limit < 4; limit *= 2);
for (int i = 2; i < limit; i++) {
constantAfterCCP = 6; // Only known to be constant 6 after CCP.
}
for (int i = 51; i > 9; i -= 3) {
if (bFld) {
x *= 6;
}
// (1) after unswitching:
// if (bFld) {...}
// Since we have a back to back if now with the same condition, we can merge them together by using the
// split if optimization. That will create phi nodes for the UCT regions. Whenever we then call
// create_new_if_for_predicate(), we would just reuse the old phi input for the newly create uncommon trap
// projection. This is done when unswitching again to clone the predicates to the fast and slow loop. But
// in the meantime, we have sunk x out of the loop with CastII nodes which are pinned on the old uncommon
// trap projections. Just reusing these data nodes on the new uncommon trap proj leads to a broken graph:
// the LCA of the old and new uncommon projection would be above the early control (control input of the
// CastII nodes).
//
// 8271954 fixes this when calling create_new_if_for_predicate() in
// clone_predicate_to_unswitched_loop().
x -= 5;
for (int j = 1; j < 10; j++) {
if (bFld) { // Unswitching on bFld such that this condition is moved to (1)
continue;
}
x = 34; // Redefine x such that x is only used in UCT before this loop after split if.
int y = 34;
if (constantAfterCCP == 2) {
// Known to be never taken after CCP, so y will always be 34.
y = 35;
}
if (y == iFld) { // Folds to 34 == iFld after CCP and trigger another unswitching
continue;
}
iFld3 = 34; // Just another statement sucht that the second round of unswitching is done
}
}
// This loop is only needed to delay the second round of unswitching for the inner loop above.
for (int i = 0; i < iArrFld.length; i++) {
iArrFld[i] = 3;
}
}
// Similar to testUnswitching() but we are calling create_new_if_for_predicate in Loop Predication for:
// - Creating hoised range check predicate and skeleton predicate
// - Creating invariant check predicate
// which leads to a crash.
static void testLoopPredicatation() {
int x = 3;
// Block to delay precise type information to after CCP.
int limit = 2;
int constantAfterCCP = 2;
for (; limit < 4; limit *= 2);
for (int i = 2; i < limit; i++) {
constantAfterCCP = 6; // Only known to be constant 6 after CCP.
}
for (int i = 51; i > 9; i -= 3) {
if (bFld) {
x *= 6;
}
// (1) after unswitching:
// if (bFld) {...}
// Since we have a back to back if now with the same condition, we can merge them together by using the
// split if optimization. That will create phi nodes for the UCT regions. Whenever we then call
// create_new_if_for_predicate(), we would just reuse the old phi input for the newly create uncommon trap
// projection. This is done when unswitching again to clone the predicates to the fast and slow loop. But
// in the meantime, we have sunk x out of the loop with CastII nodes which are pinned on the old uncommon
// trap projections. Just reusing these data nodes on the new uncommon trap proj leads to a broken graph:
// the LCA of the old and new uncommon projection would be above the early control (control input of the
// CastII nodes).
x -= 5;
for (int j = 1; j < 10; j++) {
if (bFld) { // Unswitching on bFld such that this condition is moved to (1)
continue;
}
x = 34; // Redefine x such that x is only used in UCT before this loop after split if.
int y = iArrFld[j]; // Range check and null check will be hoisted after Unswitching and split if.
}
}
// This loop is only needed to delay the second round of unswitching for the inner loop above.
for (int i = 0; i < iArrFld.length; i++) {
iArrFld[i] = 3;
}
}
// Similar to testLoopPredicatation() but we are adding some computations for x such that we sink more nodes which
// need to be cloned when calling create_new_if_for_predicate().
static void testLoopPredicatationComplex() {
int x = 3;
// Block to delay precise type information to after CCP.
int limit = 2;
int constantAfterCCP = 2;
for (; limit < 4; limit *= 2);
for (int i = 2; i < limit; i++) {
constantAfterCCP = 6; // Only known to be constant 6 after CCP.
}
for (int i = 51; i > 9; i -= 3) {
if (bFld) {
x *= 6;
}
// (1) after unswitching:
// if (bFld) {...}
// Since we have a back to back if now with the same condition, we can merge them together by using the
// split if optimization. That will create phi nodes for the UCT regions. Whenever we then call
// create_new_if_for_predicate(), we would just reuse the old phi input for the newly create uncommon trap
// projection. This is done when unswitching again to clone the predicates to the fast and slow loop. But
// in the meantime, we have sunk x out of the loop with CastII nodes which are pinned on the old uncommon
// trap projections. Just reusing these data nodes on the new uncommon trap proj leads to a broken graph:
// the LCA of the old and new uncommon projection would be above the early control (control input of the
// CastII nodes).
x -= 5;
// Add some more computations such that more nodes are sunk and therefore more nodes need to be cloned in
// create_new_if_for_predicate().
double d1 = 5 + (double) x;
x = (int)((d1 + iFld2) - (d1 + iFld));
d1 = 5 + (double) x;
x = (int)((d1 + iFld2) - (d1 + iFld));
d1 = 5 + (double) x;
x = (int)((d1 + iFld2) - (d1 + iFld));
d1 = 5 + (double) x;
x = (int)((d1 + iFld2) - (d1 + iFld));
d1 = 5 + (double) x;
x = (int)((d1 + iFld2) - (d1 + iFld));
d1 = 5 + (double) x;
x = (int)((d1 + iFld2) - (d1 + iFld));
for (int j = 1; j < 10; j++) {
if (bFld) { // Unswitching on bFld such that this condition is moved to (1)
continue;
}
x = 34; // Redefine x such that x is only used in UCT before this loop after split if.
int y = iArrFld[j]; // Range check and null check will be hoisted after Unswitching and split if.
}
}
// This loop is only needed to delay the second round of unswitching for the inner loop above.
for (int i = 0; i < iArrFld.length; i++) {
iArrFld[i] = 3;
}
}
// Combination of testUnswitching() and testLoopPredicatation(): After creating predicates in loop predication,
// we perform another round of loop unswitching where we additionally call create_new_if_for_predicate in
// clone_skeleton_predicate_for_unswitched_loops() which currently leads to a crash.
static void testUnswitchingWithPredicates() {
int x = 3;
if (iArrFld == null) {
// Makes sure to get rid of null check for iArrFld to only create range check predicate
return;
}
// Block to delay precise type information to after CCP.
int limit = 2;
int constantAfterCCP = 2;
for (; limit < 4; limit *= 2);
for (int i = 2; i < limit; i++) {
constantAfterCCP = 6; // Only known to be constant 6 after CCP.
}
for (int i = 51; i > 9; i -= 3) {
if (bFld) {
x *= 6;
}
// (1) after unswitching:
// if (bFld) {...}
// Since we have a back to back if now with the same condition, we can merge them together by using the
// split if optimization. That will create phi nodes for the UCT regions. Whenever we then call
// create_new_if_for_predicate(), we would just reuse the old phi input for the newly create uncommon trap
// projection. This is done when unswitching again to clone the predicates to the fast and slow loop. But
// in the meantime, we have sunk x out of the loop with CastII nodes which are pinned on the old uncommon
// trap projections. Just reusing these data nodes on the new uncommon trap proj leads to a broken graph:
// the LCA of the old and new uncommon projection would be above the early control (control input of the
// CastII nodes).
x -= 5;
for (int j = 1; j < 10; j++) {
if (bFld) { // Unswitching on bFld such that this condition is moved to (1)
continue;
}
x = 34; // Redefine x such that x is only used in UCT before this loop after split if.
int z = iArrFld[j]; // Range check and null check will be hoisted after Unswitching and split if.
int y = 34;
if (constantAfterCCP == 2) {
// Known to be never taken after CCP, so y will always be 34.
y = 35;
}
if (y == iFld) { // Folds to 34 == iFld after CCP and trigger another unswitching
continue;
}
iFld3 = 34; // Just another statement sucht that the second round of unswitching is done
}
}
// This loop is only needed to delay the second round of unswitching for the inner loop above.
for (int i = 0; i < iArrFld.length; i++) {
iArrFld[i] = 3;
}
}
// Same as testUnswitchingWithPredicates() but with a DivI node which has a control input which needs
// to be rewired as well.
static void testUnswitchingWithPredicatesDiv() {
int x = 3;
if (iArrFld == null) {
// Makes sure to get rid of null check for iArrFld to only create range check predicate
return;
}
// Block to delay precise type information to after CCP.
int limit = 2;
int constantAfterCCP = 2;
for (; limit < 4; limit *= 2);
for (int i = 2; i < limit; i++) {
constantAfterCCP = 6; // Only known to be constant 6 after CCP.
}
for (int i = 51; i > 9; i -= 3) {
if (bFld) {
x *= 6;
}
// (1) after unswitching:
// if (bFld) {...}
// Since we have a back to back if now with the same condition, we can merge them together by using the
// split if optimization. That will create phi nodes for the UCT regions. Whenever we then call
// create_new_if_for_predicate(), we would just reuse the old phi input for the newly create uncommon trap
// projection. This is done when unswitching again to clone the predicates to the fast and slow loop. But
// in the meantime, we have sunk x out of the loop with CastII nodes which are pinned on the old uncommon
// trap projections. Just reusing these data nodes on the new uncommon trap proj leads to a broken graph:
// the LCA of the old and new uncommon projection would be above the early control (control input of the
// CastII nodes).
x -= 5;
double d = 5.5f + (double) x;
int a = (int)d;
x = (a / nonZero) - (a / nonZero2);
for (int j = 1; j < 10; j++) {
if (bFld) { // Unswitching on bFld such that this condition is moved to (1)
continue;
}
x = 34; // Redefine x such that x is only used in UCT before this loop after split if.
int z = iArrFld[j]; // Range check and null check will be hoisted after Unswitching and split if.
int y = 34;
if (constantAfterCCP == 2) {
// Known to be never taken after CCP, so y will always be 34.
y = 35;
}
if (y == iFld) { // Folds to 34 == iFld after CCP and trigger another unswitching
continue;
}
iFld3 = 34; // Just another statement sucht that the second round of unswitching is done
}
}
// This loop is only needed to delay the second round of unswitching for the inner loop above.
for (int i = 0; i < iArrFld.length; i++) {
iArrFld[i] = 3;
}
}
static void testFuzzer1() {
int x = 0;
int[] iArr = new int[400];
boolean b = true;
long[] lArr = new long[400];
for (long l1 : lArr) {
for (int i = 63; i > 1; i -= 3) {
for (int j = 1; j < 4; j++) {
if (!b) {
x -= 5;
}
}
for (int j = 1; j < 4; j++) {
if (!b) {
x = iArr[j];
}
if (i == 0) {
l1 += 5;
}
}
}
}
}
static void testFuzzer2() {
int i, i1, i17 = 6, i18;
short s1;
boolean b2 = true;
float f3;
long lArr[][] = new long[400][];
byte byArrFld[] = new byte[4];
i = 1;
do {
for (i1 = 14; 6 < i1; i1--)
;
i17 -= i18 = 1;
while (i18 < 4) {
i18 <<= i17 = 2;
switch (i1) {
case 114:
s1 = byArrFld[1];
break;
case 116:
lArr[1][i18] = iFld;
if (b2)
continue;
case 118:
f3 = iFld;
}
}
i++;
} while (i < 10000);
}
static void testFuzzer3() {
int x = 8;
int y = 4;
for (int i : iArrFld) {
x += 2;
if (bFld) {
x = 3;
} else {
y = 2;
}
for (int j = 0; j < 10; j++) {
x = 0;
y += 5;
if (!bFld) {
iArrFld[1] = 5;
}
}
}
}
}