Skip to content

Commit 471e2f1

Browse files
committed
8292088: C2: assert(is_OuterStripMinedLoop()) failed: invalid node class: IfTrue
Reviewed-by: roland, kvn
1 parent a93cf92 commit 471e2f1

File tree

4 files changed

+221
-3
lines changed

4 files changed

+221
-3
lines changed

src/hotspot/share/opto/loopopts.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4100,7 +4100,20 @@ bool PhaseIdealLoop::duplicate_loop_backedge(IdealLoopTree *loop, Node_List &old
41004100
// Reorganize offset computations to lower register pressure. Mostly
41014101
// prevent loop-fallout uses of the pre-incremented trip counter (which are
41024102
// then alive with the post-incremented trip counter forcing an extra
4103-
// register move)
4103+
// register move):
4104+
//
4105+
// iv Phi iv Phi
4106+
// | |
4107+
// | AddI (+stride)
4108+
// | |
4109+
// | Opaque2 # Blocks IGVN from folding these nodes until loop opts are over.
4110+
// | ====> |
4111+
// | AddI (-stride)
4112+
// | |
4113+
// | CastII # Preserve type of iv Phi
4114+
// | |
4115+
// Outside Use Outside Use
4116+
//
41044117
void PhaseIdealLoop::reorg_offsets(IdealLoopTree *loop) {
41054118
// Perform it only for canonical counted loops.
41064119
// Loop's shape could be messed up by iteration_split_impl.

src/hotspot/share/opto/opaquenode.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ bool Opaque1Node::cmp( const Node &n ) const {
3434
}
3535

3636
//------------------------------Identity---------------------------------------
37-
// Do NOT remove the opaque Node until no more loop ops can happen.
37+
// Do NOT remove the opaque node until no more loop opts can happen.
3838
Node* Opaque1Node::Identity(PhaseGVN* phase) {
3939
if (phase->C->post_loop_opts_phase()) {
4040
return in(1);
@@ -54,6 +54,18 @@ Node* Opaque1Node::Identity(PhaseGVN* phase) {
5454
// this kind of a Node, we'll get slightly pessimal, but correct, code. Thus
5555
// it's OK to be slightly sloppy on optimizations here.
5656

57+
// Do NOT remove the opaque node until no more loop opts can happen. Opaque1
58+
// and Opaque2 nodes are removed together in order to optimize loops away
59+
// before macro expansion.
60+
Node* Opaque2Node::Identity(PhaseGVN* phase) {
61+
if (phase->C->post_loop_opts_phase()) {
62+
return in(1);
63+
} else {
64+
phase->C->record_for_post_loop_opts_igvn(this);
65+
}
66+
return this;
67+
}
68+
5769
// Do not allow value-numbering
5870
uint Opaque2Node::hash() const { return NO_HASH; }
5971
bool Opaque2Node::cmp( const Node &n ) const {

src/hotspot/share/opto/opaquenode.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,8 @@ class Opaque2Node : public Node {
8989
C->add_macro_node(this);
9090
}
9191
virtual int Opcode() const;
92-
virtual const Type *bottom_type() const { return TypeInt::INT; }
92+
virtual const Type* bottom_type() const { return TypeInt::INT; }
93+
virtual Node* Identity(PhaseGVN* phase);
9394
};
9495

9596
//------------------------------Opaque3Node------------------------------------
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
/*
2+
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
/*
25+
* @test
26+
* @bug 8292088
27+
* @requires vm.compiler2.enabled
28+
* @summary Test that OuterStripMinedLoop and its CountedLoop are both removed after the removal of Opaque1 and 2 nodes
29+
which allows the loop backedge to be optimized out.
30+
* @run main/othervm -XX:LoopMaxUnroll=0 -Xcomp
31+
* -XX:CompileCommand=compileonly,compiler.c2.TestRemoveSingleIterationLoop::test*
32+
* -XX:CompileCommand=dontinline,compiler.c2.TestRemoveSingleIterationLoop::dontInline
33+
* compiler.c2.TestRemoveSingleIterationLoop
34+
* @run main/othervm -XX:LoopMaxUnroll=2 -Xcomp
35+
* -XX:CompileCommand=compileonly,compiler.c2.TestRemoveSingleIterationLoop::test*
36+
* -XX:CompileCommand=dontinline,compiler.c2.TestRemoveSingleIterationLoop::dontInline
37+
* compiler.c2.TestRemoveSingleIterationLoop
38+
*/
39+
package compiler.c2;
40+
41+
public class TestRemoveSingleIterationLoop {
42+
static int N = 400;
43+
static int x = 3;
44+
static int y = 3;
45+
static volatile int[] iArr = new int[N];
46+
47+
public static void main(String[] args) {
48+
testKnownLimit();
49+
testUnknownLimit();
50+
testKnownLimit2();
51+
testFuzzer();
52+
}
53+
54+
// Upper limit is known (i.e. type of iv phi for i is [-9999..499]). Unroll = 0 to trigger.
55+
private static void testKnownLimit() {
56+
int i = -10000;
57+
int limit = 500;
58+
59+
// These two loops are only required to make sure that we only know that 'i' is 5 after the second loop after CCP.
60+
int a = 2;
61+
for (; a < 4; a *= 2);
62+
for (int b = 2; b < a; b++) {
63+
i = 5;
64+
}
65+
66+
if (i < limit + 1) { // Required such that C2 knows that we are always entering the first loop.
67+
// Loop L1
68+
for (; i < limit; i++) {
69+
// IV_PHI_i = iv phi of i for this loop with type:
70+
// - Before CPP: [-10000..499]
71+
// - After CPP: [5..499]
72+
y = 3;
73+
}
74+
75+
int j = 6;
76+
// C2 parses the following loop as:
77+
// Loop head
78+
// body (where we do j--)
79+
// Loop exit check where we already applied j--: j > i - 1
80+
while (j > i - 1) {
81+
// IV_PHI_j = iv phi of j for this loop with type:
82+
// - Before CPP: [-9998..7]
83+
j--;
84+
iArr[23] = 3;
85+
// At this point i = IV_PHI_i + 1 because i was incremented once more before exiting loop L1.
86+
// In PhaseIdealLoop::reorg_offsets(), we identify such direct (pre-incremented) usages of an iv phi and
87+
// add an Opaque2 node to prevent loop-fallout uses. This lowers the register pressure. We replace the
88+
// direct phi usage in CmpI (annotated with types before CCP):
89+
//
90+
// Phi Phi (IV_PHI_i) # [-10000..499]
91+
// | |
92+
// | AddI (+1) # [-9999..500]
93+
// | |
94+
// | Opaque2 # int
95+
// | ====> |
96+
// | AddI (-1) # int
97+
// | |
98+
// | CastII # [-10000..499]
99+
// | |
100+
// CmpI CmpI # j > i - 1 = IV_PHI_j - 1 > CastII (actually IV_PHI_i) = [-10000..5] > [-10000..499]
101+
//
102+
//
103+
// After CCP, the type of the iv phi IV_PHI_i improves to [5..499] while the type of the CastII does not
104+
// because the Opaque2 node blocks the type update. When removing the Opaque2 node, we find that the
105+
// loop only runs for a single time and does not take the backedge:
106+
//
107+
// [-10000..5] > [5..499] is false
108+
//
109+
// However, we only remove Opaque2 nodes in macro expansion where we also adjust the strip mined loop:
110+
// We copy the bool node from the CountedLoopEnd to the OuterStripMinedLoopEnd node and adjust the
111+
// loop exit check of the CountedLoopEnd in such a way that C2 is not able to prove that the loop
112+
// is only run once. But the OuterStripMinedLoop can now be removed due to the removed Opaque2 nodes
113+
// and we end up with a CountedLoop node that is strip mined but has no OuterStripMined loop. This
114+
// results in an assertion failure later when reshaping the graph.
115+
}
116+
}
117+
}
118+
119+
// Upper limit is not known (i.e. type of iv phi for i is [-9999..max-1]). Unroll = 0 to trigger.
120+
private static void testUnknownLimit() {
121+
int i = -10000;
122+
int limit = x;
123+
124+
// These two loops are required to make sure that we only know after CCP that 'i' is 1 after the second loop.
125+
int a = 2;
126+
for (; a < 4; a *= 2);
127+
for (int b = 2; b < a; b++) {
128+
i = 0;
129+
}
130+
if (i + 1 < limit) {
131+
i++;
132+
for (; i < limit; i++) {
133+
y = 3;
134+
}
135+
int t = 2;
136+
while (t > i - 1) {
137+
t--;
138+
iArr[23] = 3;
139+
}
140+
}
141+
}
142+
143+
// Upper limit is known. Unroll = 2 to trigger.
144+
static int testKnownLimit2() {
145+
int i = -10000, j;
146+
int[][] iArr1 = new int[N][N];
147+
148+
// These two loops are required to make sure that we only know after CCP that 'i' is 1 after the second loop.
149+
int a = 2;
150+
for (; a < 4; a *= 2);
151+
for (int b = 2; b < a; b++) {
152+
i = 1;
153+
}
154+
155+
while (++i < 318) {
156+
dontInline();
157+
}
158+
159+
for (j = 6; j > i; j--) {
160+
// Type of i before CCP: -9999..317
161+
// Type of i after CCP: 2..317
162+
iArr[1] = 25327;
163+
}
164+
165+
// This loop is required to trigger the assertion failure.
166+
for (int y = 0; y < iArr1.length; y++) {
167+
dontInline(iArr1[2]);
168+
}
169+
return i;
170+
}
171+
172+
// Reduced original fuzzer test. Unroll = 2 to trigger.
173+
static int testFuzzer() {
174+
int i = 1, j, iArr1[][] = new int[N][N];
175+
while (++i < 318) {
176+
dontInline();
177+
for (j = 5; j > i; j--) {
178+
iArr[1] = 25327;
179+
}
180+
}
181+
182+
// Some more code that is required to trigger the assertion failure.
183+
for (int y = 0; y < iArr1.length; y++) {
184+
dontInline(iArr1[2]);
185+
}
186+
return i;
187+
}
188+
189+
static void dontInline() {}
190+
191+
static void dontInline(int[] iArr) {}
192+
}

0 commit comments

Comments
 (0)