jdk-24/test/hotspot/jtreg/compiler/loopopts/TestUnswitchCloneSkeletonPredicates.java
2021-03-29 08:03:47 +00:00

226 lines
9.1 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.
*/
/*
* @test
* @bug 8253644
* @summary Test the complete cloning of skeleton predicates to unswitched loops as done when cloning them to the main loop.
* @run main/othervm -Xcomp -XX:CompileCommand=compileonly,compiler.loopopts.TestUnswitchCloneSkeletonPredicates::*
* compiler.loopopts.TestUnswitchCloneSkeletonPredicates
* @run main/othervm -Xcomp -XX:+IgnoreUnrecognizedVMOptions -XX:-PartialPeelLoop -XX:CompileCommand=compileonly,compiler.loopopts.TestUnswitchCloneSkeletonPredicates::*
* compiler.loopopts.TestUnswitchCloneSkeletonPredicates
* @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-PartialPeelLoop compiler.loopopts.TestUnswitchCloneSkeletonPredicates
*/
package compiler.loopopts;
public class TestUnswitchCloneSkeletonPredicates {
static int x = 0;
static int y = 20;
static int intArr[] = new int[21000];
static int idx = 0;
static boolean bFld = true;
static int iFld = 20;
static int iFld2 = 0 ;
static int iArrFld[] = new int[50];
static float fArrFld[] = new float[50];
// Only triggers with -XX:-PartialPeelLoop
/*
* The inner loop is unswitched on (1) which creates a fast and a slow loop that both have (1) removed and instead
* (1) is executed before the loop at (3). With the SplitIf optimization we find that (3) dominates (2) in both loops.
*
* As a result, we can remove (2) from both loops. This, however, has an influence on how the loop tree is built.
* Before the SplitIf optimization, the loop tree looks like this:
* Loop: N0/N0 has_sfpt
* Loop: N338/N314 limit_check profile_predicated predicated counted [0,100),+1 (2 iters) has_sfpt
* Loop: N459/N458 profile_predicated predicated counted [0,10000),+1 (5271 iters) has_sfpt (slow loop)
* Loop: N343/N267 profile_predicated predicated counted [0,10000),+1 (5271 iters) has_sfpt (fast loop)
*
* Both unswitched loop have a copy of the skeleton predicate If node that share the same Opaque4 node with its inputs.
* The inner loop is never exited normally due to always returning on (4). This means that the branch that exits the
* loop on the loop limit check is never taken and has an uncommon trap. Nevertheless, the loop building algorithm still
* identifies the fast and the slow loop as children of N338 because of the condition (2) over which the loop is left.
* However, after the above mentioned SplitIf optimization the condition (2) is removed from both loops. As a result,
* the slow loops (N459) is always exited immediately (x == 100 holds) because the break is executed on the first
* iteration of the loop. The loop can be removed (but these nodes are still part of the parent loop N338). The fast loop
* (N343), however, is now never exited normally and always returns on the 9800th iteration over (4). The normal loop exit
* over the loop limit check is never taken (uncommon trap). Due to the last loop exit (2) being removed, N343 is no longer
* recognized as a child loop of N338 due to not having a backedge to the parent loop. The loop tree looks like this:
* Loop: N0/N0 has_sfpt
* Loop: N338/N314 limit_check profile_predicated predicated counted [0,100),+1 (2 iters) has_sfpt
* Loop: N343/N267 profile_predicated predicated counted [0,10000),+1 (5274 iters) has_sfpt
*
* As a next step, the original parent loop N338 is peeled. The fast and the slow loop still both share skeleton Opaque4 bool
* nodes with all its inputs nodes up to and including the OpaqueLoopInit/Stride nodes. These skeleton predicates are still there
* even though the slow loop N459 could have been removed (the Opaque4 nodes are only removed after loop opts). Let's look at one
* of the skeleton If nodes for the fast loop that uses such a Opaque4 node. The skeleton 'If' is no longer part of the original
* parent loop and is therefore not peeled. But now we need some phi nodes to select the correct nodes either from the peeled
* iteration or from N338 for this skeleton If of the fast loop. This is done in PhaseIdealLoop::clone_iff() which creates
* a new Opaque4 node together with new Bool and Cmp nodes and then inserts some phi nodes to do the selection.
*
* When afterwards creating pre/main/post loops for the fast loop (N343) that is no child anymore, we find these phi nodes on the
* path to the OpaqueLoopInit/Stride nodes which lets the assertion PhaseIdealLoop::skeleton_predicate_has_opaque() fail. These
* phi nodes on the path to the OpaqueLoopInit/Stride nodes are unexpected.
*
* The solution to this problem is to clone the skeleton predicates completely, including clones of all nodes up to and including
* the OpaqueLoopInit/Stride nodes (similar to what is done when copying skeleton predicates to the main loop) instead of just
* sharing Opaque4 nodes.
*/
public static int test1() {
int i = 0;
while (i < 100) {
int j = 0;
// (3) <new unswitch condition>
while (j < 10000) {
if (x == 100) { // (1) Loop is unswitched on this condition -> condition shared with (2)
y = 34;
}
intArr[idx] = 34;
intArr[2*j + 35] = 45;
if (x == 100) { // (2)
y = 35;
break;
}
if (j == 9800) { // (4)
return 2;
}
j++;
}
i++;
intArr[i] = 45;
}
return y;
}
// Only triggers with -XX:-PartialPeelLoop
public static int test2() {
int i = 0;
while (i < 100) {
int j = 0;
while (j < 10000) {
if (x == 100) {
y = 34;
}
intArr[2*j + 35] = 45;
if (x == 100) {
y = 35;
break;
}
if (j == 9800) {
return 2;
}
j++;
}
i++;
intArr[i] = 45;
}
return y;
}
// Only triggers with -XX:-PartialPeelLoop
public static int test3() {
int i = 0;
while (i < 100) {
int j = 0;
while (j < 10000) {
if (x == 100) {
y = 34;
}
intArr[idx] = 34;
intArr[2*j + 35] = 45;
if (x == 100) {
y = 35;
break;
}
if (j == 9800) {
return 2;
}
j++;
}
i++;
}
return y;
}
// Test that has two loop headers for a single loop (limitation of type flow, see JDK-8255663)
// which also triggers the assertion failure of this bug.
public static void test4() {
int unused = 500; // Required, even though unused
boolean b = true;
int i = 1;
while (++i < 35) {
iArrFld[i] = 6;
switch (iFld2) {
case 40:
if (b) {
continue;
}
b = false;
break;
}
}
}
// Test that has two loop headers for a single loop (limitation of type flow, see JDK-8255663)
// which also triggers the assertion failure of this bug. Only triggers with -XX:-PartialPeelLoop.
public static void test5() {
int j = 50;
int i = 1;
while (++i < 40) {
j = 5;
do {
fArrFld[i] = 46;
iFld = 5;
if (bFld) break;
} while (++j < 5);
j = 2;
do {
try {
iFld = 56;
} catch (ArithmeticException a_e) {}
if (bFld) break;
} while (++j < 2);
}
}
public static void main(String[] strArr) {
for (int i = 0; i < 5000; i++) {
test1();
test2();
test3();
x++;
x = x % 106;
}
test4();
test5();
}
}