Skip to content

Commit c130451

Browse files
committedJul 19, 2021
8269752: C2: assert(false) failed: Bad graph detected in build_loop_late
Reviewed-by: chagedorn, kvn
1 parent 2dddcce commit c130451

File tree

7 files changed

+107
-24
lines changed

7 files changed

+107
-24
lines changed
 

‎src/hotspot/share/opto/cfgnode.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,15 @@ Node *RegionNode::Ideal(PhaseGVN *phase, bool can_reshape) {
606606
igvn->replace_input_of(outer, LoopNode::LoopBackControl, igvn->C->top());
607607
}
608608
}
609+
if (is_CountedLoop()) {
610+
Node* opaq = as_CountedLoop()->is_canonical_loop_entry();
611+
if (opaq != NULL) {
612+
// This is not a loop anymore. No need to keep the Opaque1 node on the test that guards the loop as it won't be
613+
// subject to further loop opts.
614+
assert(opaq->Opcode() == Op_Opaque1, "");
615+
igvn->replace_node(opaq, opaq->in(1));
616+
}
617+
}
609618
Node *parent_ctrl;
610619
if( cnt == 0 ) {
611620
assert( req() == 1, "no inputs expected" );

‎src/hotspot/share/opto/loopTransform.cpp

+6-4
Original file line numberDiff line numberDiff line change
@@ -1990,10 +1990,10 @@ void PhaseIdealLoop::do_unroll(IdealLoopTree *loop, Node_List &old_new, bool adj
19901990
// Check the shape of the graph at the loop entry. If an inappropriate
19911991
// graph shape is encountered, the compiler bails out loop unrolling;
19921992
// compilation of the method will still succeed.
1993-
if (!is_canonical_loop_entry(loop_head)) {
1993+
opaq = loop_head->is_canonical_loop_entry();
1994+
if (opaq == NULL) {
19941995
return;
19951996
}
1996-
opaq = loop_head->skip_predicates()->in(0)->in(1)->in(1)->in(2);
19971997
// Zero-trip test uses an 'opaque' node which is not shared.
19981998
assert(opaq->outcnt() == 1 && opaq->in(1) == limit, "");
19991999
}
@@ -2608,7 +2608,7 @@ int PhaseIdealLoop::do_range_check(IdealLoopTree *loop, Node_List &old_new) {
26082608
// Check graph shape. Cannot optimize a loop if zero-trip
26092609
// Opaque1 node is optimized away and then another round
26102610
// of loop opts attempted.
2611-
if (!is_canonical_loop_entry(cl)) {
2611+
if (cl->is_canonical_loop_entry() == NULL) {
26122612
return closed_range_checks;
26132613
}
26142614

@@ -2937,7 +2937,9 @@ bool PhaseIdealLoop::multi_version_post_loops(IdealLoopTree *rce_loop, IdealLoop
29372937
}
29382938

29392939
// Find RCE'd post loop so that we can stage its guard.
2940-
if (!is_canonical_loop_entry(legacy_cl)) return multi_version_succeeded;
2940+
if (legacy_cl->is_canonical_loop_entry() == NULL) {
2941+
return multi_version_succeeded;
2942+
}
29412943
Node* ctrl = legacy_cl->in(LoopNode::EntryControl);
29422944
Node* iffm = ctrl->in(0);
29432945

‎src/hotspot/share/opto/loopnode.cpp

+22-16
Original file line numberDiff line numberDiff line change
@@ -2139,9 +2139,10 @@ SafePointNode* CountedLoopNode::outer_safepoint() const {
21392139
}
21402140

21412141
Node* CountedLoopNode::skip_predicates_from_entry(Node* ctrl) {
2142-
while (ctrl != NULL && ctrl->is_Proj() && ctrl->in(0)->is_If() &&
2143-
ctrl->in(0)->as_If()->proj_out(1-ctrl->as_Proj()->_con)->outcnt() == 1 &&
2144-
ctrl->in(0)->as_If()->proj_out(1-ctrl->as_Proj()->_con)->unique_out()->Opcode() == Op_Halt) {
2142+
while (ctrl != NULL && ctrl->is_Proj() && ctrl->in(0) != NULL && ctrl->in(0)->is_If() &&
2143+
(ctrl->in(0)->as_If()->proj_out_or_null(1-ctrl->as_Proj()->_con) == NULL ||
2144+
(ctrl->in(0)->as_If()->proj_out(1-ctrl->as_Proj()->_con)->outcnt() == 1 &&
2145+
ctrl->in(0)->as_If()->proj_out(1-ctrl->as_Proj()->_con)->unique_out()->Opcode() == Op_Halt))) {
21452146
ctrl = ctrl->in(0)->in(0);
21462147
}
21472148

@@ -4920,28 +4921,34 @@ Node* PhaseIdealLoop::compute_lca_of_uses(Node* n, Node* early, bool verify) {
49204921
// loop unswitching, and IGVN, or a combination of them) can freely change
49214922
// the graph's shape. As a result, the graph shape outlined below cannot
49224923
// be guaranteed anymore.
4923-
bool PhaseIdealLoop::is_canonical_loop_entry(CountedLoopNode* cl) {
4924-
if (!cl->is_main_loop() && !cl->is_post_loop()) {
4925-
return false;
4924+
Node* CountedLoopNode::is_canonical_loop_entry() {
4925+
if (!is_main_loop() && !is_post_loop()) {
4926+
return NULL;
49264927
}
4927-
Node* ctrl = cl->skip_predicates();
4928+
Node* ctrl = skip_predicates();
49284929

49294930
if (ctrl == NULL || (!ctrl->is_IfTrue() && !ctrl->is_IfFalse())) {
4930-
return false;
4931+
return NULL;
49314932
}
49324933
Node* iffm = ctrl->in(0);
49334934
if (iffm == NULL || !iffm->is_If()) {
4934-
return false;
4935+
return NULL;
49354936
}
49364937
Node* bolzm = iffm->in(1);
49374938
if (bolzm == NULL || !bolzm->is_Bool()) {
4938-
return false;
4939+
return NULL;
49394940
}
49404941
Node* cmpzm = bolzm->in(1);
49414942
if (cmpzm == NULL || !cmpzm->is_Cmp()) {
4942-
return false;
4943+
return NULL;
49434944
}
4944-
// compares can get conditionally flipped
4945+
4946+
uint input = is_main_loop() ? 2 : 1;
4947+
if (input >= cmpzm->req() || cmpzm->in(input) == NULL) {
4948+
return NULL;
4949+
}
4950+
bool res = cmpzm->in(input)->Opcode() == Op_Opaque1;
4951+
#ifdef ASSERT
49454952
bool found_opaque = false;
49464953
for (uint i = 1; i < cmpzm->req(); i++) {
49474954
Node* opnd = cmpzm->in(i);
@@ -4950,10 +4957,9 @@ bool PhaseIdealLoop::is_canonical_loop_entry(CountedLoopNode* cl) {
49504957
break;
49514958
}
49524959
}
4953-
if (!found_opaque) {
4954-
return false;
4955-
}
4956-
return true;
4960+
assert(found_opaque == res, "wrong pattern");
4961+
#endif
4962+
return res ? cmpzm->in(input) : NULL;
49574963
}
49584964

49594965
//------------------------------get_late_ctrl----------------------------------

‎src/hotspot/share/opto/loopnode.hpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,8 @@ class CountedLoopNode : public BaseCountedLoopNode {
350350
return T_INT;
351351
}
352352

353+
Node* is_canonical_loop_entry();
354+
353355
#ifndef PRODUCT
354356
virtual void dump_spec(outputStream *st) const;
355357
#endif
@@ -931,8 +933,6 @@ class PhaseIdealLoop : public PhaseTransform {
931933

932934
PhaseIterGVN &igvn() const { return _igvn; }
933935

934-
static bool is_canonical_loop_entry(CountedLoopNode* cl);
935-
936936
bool has_node( Node* n ) const {
937937
guarantee(n != NULL, "No Node.");
938938
return _nodes[n->_idx] != NULL;

‎src/hotspot/share/opto/multnode.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ Node *MultiNode::match( const ProjNode *proj, const Matcher *m ) { return proj->
4646
// Get a named projection or null if not found
4747
ProjNode* MultiNode::proj_out_or_null(uint which_proj) const {
4848
assert((Opcode() != Op_If && Opcode() != Op_RangeCheck) || which_proj == (uint)true || which_proj == (uint)false, "must be 1 or 0");
49-
assert((Opcode() != Op_If && Opcode() != Op_RangeCheck) || outcnt() == 2, "bad if #1");
5049
for( DUIterator_Fast imax, i = fast_outs(imax); i < imax; i++ ) {
5150
Node *p = fast_out(i);
5251
if (p->is_Proj()) {
@@ -75,6 +74,7 @@ ProjNode* MultiNode::proj_out_or_null(uint which_proj, bool is_io_use) const {
7574

7675
// Get a named projection
7776
ProjNode* MultiNode::proj_out(uint which_proj) const {
77+
assert((Opcode() != Op_If && Opcode() != Op_RangeCheck) || outcnt() == 2, "bad if #1");
7878
ProjNode* p = proj_out_or_null(which_proj);
7979
assert(p != NULL, "named projection %u not found", which_proj);
8080
return p;

‎src/hotspot/share/opto/superword.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -3604,7 +3604,7 @@ void SuperWord::align_initial_loop_index(MemNode* align_to_ref) {
36043604
CountedLoopEndNode* SuperWord::find_pre_loop_end(CountedLoopNode* cl) const {
36053605
// The loop cannot be optimized if the graph shape at
36063606
// the loop entry is inappropriate.
3607-
if (!PhaseIdealLoop::is_canonical_loop_entry(cl)) {
3607+
if (cl->is_canonical_loop_entry() == NULL) {
36083608
return NULL;
36093609
}
36103610

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
* Copyright (c) 2021, Red Hat, Inc. 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 8269752
27+
* @summary C2: assert(false) failed: Bad graph detected in build_loop_late
28+
*
29+
* @run main/othervm -Xcomp -XX:-TieredCompilation -XX:CompileOnly=TestMainBodyExecutedOnce TestMainBodyExecutedOnce
30+
*
31+
*/
32+
33+
34+
public class TestMainBodyExecutedOnce {
35+
static int N;
36+
static long vMeth_check_sum;
37+
38+
public static void main(String[] strArr) {
39+
TestMainBodyExecutedOnce _instance = new TestMainBodyExecutedOnce();
40+
for (int i = 0; i < 10; i++) {
41+
_instance.test();
42+
}
43+
}
44+
45+
void test() {
46+
vMeth(3);
47+
}
48+
49+
void vMeth(int i2) {
50+
double d = 1.74287;
51+
int i3 = -36665, i4, iArr[] = new int[N];
52+
short s;
53+
long lArr[] = new long[N];
54+
while (++i3 < 132) {
55+
if (i2 != 0) {
56+
vMeth_check_sum += i3;
57+
return;
58+
}
59+
i4 = 1;
60+
while (++i4 < 12) {
61+
i2 += i4;
62+
}
63+
}
64+
vMeth_check_sum += i3;
65+
}
66+
}

0 commit comments

Comments
 (0)
Please sign in to comment.