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
|
/*
* 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 8292088
* @requires vm.compiler2.enabled
* @summary Test that OuterStripMinedLoop and its CountedLoop are both removed after the removal of Opaque1 and 2 nodes
which allows the loop backedge to be optimized out.
* @run main/othervm -XX:LoopMaxUnroll=0 -Xcomp
* -XX:CompileCommand=compileonly,compiler.c2.TestRemoveSingleIterationLoop::test*
* -XX:CompileCommand=dontinline,compiler.c2.TestRemoveSingleIterationLoop::dontInline
* compiler.c2.TestRemoveSingleIterationLoop
* @run main/othervm -XX:LoopMaxUnroll=2 -Xcomp
* -XX:CompileCommand=compileonly,compiler.c2.TestRemoveSingleIterationLoop::test*
* -XX:CompileCommand=dontinline,compiler.c2.TestRemoveSingleIterationLoop::dontInline
* compiler.c2.TestRemoveSingleIterationLoop
*/
package compiler.c2;
public class TestRemoveSingleIterationLoop {
static int N = 400;
static int x = 3;
static int y = 3;
static volatile int[] iArr = new int[N];
public static void main(String[] args) {
testKnownLimit();
testUnknownLimit();
testKnownLimit2();
testFuzzer();
}
// Upper limit is known (i.e. type of iv phi for i is [-9999..499]). Unroll = 0 to trigger.
private static void testKnownLimit() {
int i = -10000;
int limit = 500;
// These two loops are only required to make sure that we only know that 'i' is 5 after the second loop after CCP.
int a = 2;
for (; a < 4; a *= 2);
for (int b = 2; b < a; b++) {
i = 5;
}
if (i < limit + 1) { // Required such that C2 knows that we are always entering the first loop.
// Loop L1
for (; i < limit; i++) {
// IV_PHI_i = iv phi of i for this loop with type:
// - Before CPP: [-10000..499]
// - After CPP: [5..499]
y = 3;
}
int j = 6;
// C2 parses the following loop as:
// Loop head
// body (where we do j--)
// Loop exit check where we already applied j--: j > i - 1
while (j > i - 1) {
// IV_PHI_j = iv phi of j for this loop with type:
// - Before CPP: [-9998..7]
j--;
iArr[23] = 3;
// At this point i = IV_PHI_i + 1 because i was incremented once more before exiting loop L1.
// In PhaseIdealLoop::reorg_offsets(), we identify such direct (pre-incremented) usages of an iv phi and
// add an Opaque2 node to prevent loop-fallout uses. This lowers the register pressure. We replace the
// direct phi usage in CmpI (annotated with types before CCP):
//
// Phi Phi (IV_PHI_i) # [-10000..499]
// | |
// | AddI (+1) # [-9999..500]
// | |
// | Opaque2 # int
// | ====> |
// | AddI (-1) # int
// | |
// | CastII # [-10000..499]
// | |
// CmpI CmpI # j > i - 1 = IV_PHI_j - 1 > CastII (actually IV_PHI_i) = [-10000..5] > [-10000..499]
//
//
// After CCP, the type of the iv phi IV_PHI_i improves to [5..499] while the type of the CastII does not
// because the Opaque2 node blocks the type update. When removing the Opaque2 node, we find that the
// loop only runs for a single time and does not take the backedge:
//
// [-10000..5] > [5..499] is false
//
// However, we only remove Opaque2 nodes in macro expansion where we also adjust the strip mined loop:
// We copy the bool node from the CountedLoopEnd to the OuterStripMinedLoopEnd node and adjust the
// loop exit check of the CountedLoopEnd in such a way that C2 is not able to prove that the loop
// is only run once. But the OuterStripMinedLoop can now be removed due to the removed Opaque2 nodes
// and we end up with a CountedLoop node that is strip mined but has no OuterStripMined loop. This
// results in an assertion failure later when reshaping the graph.
}
}
}
// Upper limit is not known (i.e. type of iv phi for i is [-9999..max-1]). Unroll = 0 to trigger.
private static void testUnknownLimit() {
int i = -10000;
int limit = x;
// These two loops are required to make sure that we only know after CCP that 'i' is 1 after the second loop.
int a = 2;
for (; a < 4; a *= 2);
for (int b = 2; b < a; b++) {
i = 0;
}
if (i + 1 < limit) {
i++;
for (; i < limit; i++) {
y = 3;
}
int t = 2;
while (t > i - 1) {
t--;
iArr[23] = 3;
}
}
}
// Upper limit is known. Unroll = 2 to trigger.
static int testKnownLimit2() {
int i = -10000, j;
int[][] iArr1 = new int[N][N];
// These two loops are required to make sure that we only know after CCP that 'i' is 1 after the second loop.
int a = 2;
for (; a < 4; a *= 2);
for (int b = 2; b < a; b++) {
i = 1;
}
while (++i < 318) {
dontInline();
}
for (j = 6; j > i; j--) {
// Type of i before CCP: -9999..317
// Type of i after CCP: 2..317
iArr[1] = 25327;
}
// This loop is required to trigger the assertion failure.
for (int y = 0; y < iArr1.length; y++) {
dontInline(iArr1[2]);
}
return i;
}
// Reduced original fuzzer test. Unroll = 2 to trigger.
static int testFuzzer() {
int i = 1, j, iArr1[][] = new int[N][N];
while (++i < 318) {
dontInline();
for (j = 5; j > i; j--) {
iArr[1] = 25327;
}
}
// Some more code that is required to trigger the assertion failure.
for (int y = 0; y < iArr1.length; y++) {
dontInline(iArr1[2]);
}
return i;
}
static void dontInline() {}
static void dontInline(int[] iArr) {}
}
|