1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
|
/*
* 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();
}
}
|