aefc1560b5
Reviewed-by: kvn, jiefu
226 lines
9.1 KiB
Java
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();
|
|
}
|
|
}
|