Skip to content

Commit cc56820

Browse files
committed
8296389: C2: PhaseCFG::convert_NeverBranch_to_Goto must handle both orders of successors
8298568: Fastdebug build fails after JDK-8296389 Reviewed-by: rrich Backport-of: fabda246960cfdfff13c5a87de53d97169248172
1 parent 1d6db44 commit cc56820

11 files changed

+188
-21
lines changed

src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1009,7 +1009,7 @@ void G1BarrierSetC2::verify_gc_barriers(Compile* compile, CompilePhase phase) co
10091009
if (if_ctrl != load_ctrl) {
10101010
// Skip possible CProj->NeverBranch in infinite loops
10111011
if ((if_ctrl->is_Proj() && if_ctrl->Opcode() == Op_CProj)
1012-
&& (if_ctrl->in(0)->is_MultiBranch() && if_ctrl->in(0)->Opcode() == Op_NeverBranch)) {
1012+
&& if_ctrl->in(0)->is_NeverBranch()) {
10131013
if_ctrl = if_ctrl->in(0)->in(0);
10141014
}
10151015
}

src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1028,7 +1028,7 @@ void ShenandoahBarrierSetC2::verify_gc_barriers(Compile* compile, CompilePhase p
10281028
if (if_ctrl != load_ctrl) {
10291029
// Skip possible CProj->NeverBranch in infinite loops
10301030
if ((if_ctrl->is_Proj() && if_ctrl->Opcode() == Op_CProj)
1031-
&& (if_ctrl->in(0)->is_MultiBranch() && if_ctrl->in(0)->Opcode() == Op_NeverBranch)) {
1031+
&& if_ctrl->in(0)->is_NeverBranch()) {
10321032
if_ctrl = if_ctrl->in(0)->in(0);
10331033
}
10341034
}

src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -757,7 +757,7 @@ Node* ShenandoahBarrierC2Support::no_branches(Node* c, Node* dom, bool allow_one
757757
return NodeSentinel; // unsupported
758758
} else if (c->Opcode() == Op_CatchProj) {
759759
return NodeSentinel; // unsupported
760-
} else if (c->Opcode() == Op_CProj && next->Opcode() == Op_NeverBranch) {
760+
} else if (c->Opcode() == Op_CProj && next->is_NeverBranch()) {
761761
return NodeSentinel; // unsupported
762762
} else {
763763
assert(next->unique_ctrl_out() == c, "unsupported branch pattern");
@@ -2125,7 +2125,7 @@ Node* ShenandoahIUBarrierNode::Identity(PhaseGVN* phase) {
21252125
static bool has_never_branch(Node* root) {
21262126
for (uint i = 1; i < root->req(); i++) {
21272127
Node* in = root->in(i);
2128-
if (in != NULL && in->Opcode() == Op_Halt && in->in(0)->is_Proj() && in->in(0)->in(0)->Opcode() == Op_NeverBranch) {
2128+
if (in != NULL && in->Opcode() == Op_Halt && in->in(0)->is_Proj() && in->in(0)->in(0)->is_NeverBranch()) {
21292129
return true;
21302130
}
21312131
}
@@ -2156,20 +2156,20 @@ void MemoryGraphFixer::collect_memory_nodes() {
21562156
if (in->in(0)->is_Region()) {
21572157
Node* r = in->in(0);
21582158
for (uint j = 1; j < r->req(); j++) {
2159-
assert(r->in(j)->Opcode() != Op_NeverBranch, "");
2159+
assert(!r->in(j)->is_NeverBranch(), "");
21602160
}
21612161
} else {
21622162
Node* proj = in->in(0);
21632163
assert(proj->is_Proj(), "");
21642164
Node* in = proj->in(0);
2165-
assert(in->is_CallStaticJava() || in->Opcode() == Op_NeverBranch || in->Opcode() == Op_Catch || proj->is_IfProj(), "");
2165+
assert(in->is_CallStaticJava() || in->is_NeverBranch() || in->Opcode() == Op_Catch || proj->is_IfProj(), "");
21662166
if (in->is_CallStaticJava()) {
21672167
mem = in->in(TypeFunc::Memory);
21682168
} else if (in->Opcode() == Op_Catch) {
21692169
Node* call = in->in(0)->in(0);
21702170
assert(call->is_Call(), "");
21712171
mem = call->in(TypeFunc::Memory);
2172-
} else if (in->Opcode() == Op_NeverBranch) {
2172+
} else if (in->is_NeverBranch()) {
21732173
mem = collect_memory_for_infinite_loop(in);
21742174
}
21752175
}
@@ -2641,7 +2641,7 @@ void MemoryGraphFixer::fix_mem(Node* ctrl, Node* new_ctrl, Node* mem, Node* mem_
26412641
}
26422642
}
26432643
} else if (!mem_is_valid(m, u) &&
2644-
!(u->Opcode() == Op_CProj && u->in(0)->Opcode() == Op_NeverBranch && u->as_Proj()->_con == 1)) {
2644+
!(u->Opcode() == Op_CProj && u->in(0)->is_NeverBranch() && u->as_Proj()->_con == 1)) {
26452645
uses.push(u);
26462646
}
26472647
}

src/hotspot/share/opto/block.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -620,10 +620,13 @@ static bool no_flip_branch(Block *b) {
620620
// fake exit path to infinite loops. At this late stage they need to turn
621621
// into Goto's so that when you enter the infinite loop you indeed hang.
622622
void PhaseCFG::convert_NeverBranch_to_Goto(Block *b) {
623-
// Find true target
624623
int end_idx = b->end_idx();
625-
int idx = b->get_node(end_idx+1)->as_Proj()->_con;
626-
Block *succ = b->_succs[idx];
624+
NeverBranchNode* never_branch = b->get_node(end_idx)->as_NeverBranch();
625+
Block* succ = get_block_for_node(never_branch->proj_out(0)->unique_ctrl_out_or_null());
626+
Block* dead = get_block_for_node(never_branch->proj_out(1)->unique_ctrl_out_or_null());
627+
assert(succ == b->_succs[0] || succ == b->_succs[1], "succ is a successor");
628+
assert(dead == b->_succs[0] || dead == b->_succs[1], "dead is a successor");
629+
627630
Node* gto = _goto->clone(); // get a new goto node
628631
gto->set_req(0, b->head());
629632
Node *bp = b->get_node(end_idx);
@@ -642,7 +645,6 @@ void PhaseCFG::convert_NeverBranch_to_Goto(Block *b) {
642645
}
643646
}
644647
// Kill alternate exit path
645-
Block* dead = b->_succs[1 - idx];
646648
for (j = 1; j < dead->num_preds(); j++) {
647649
if (dead->pred(j)->in(0) == bp) {
648650
break;
@@ -740,7 +742,7 @@ void PhaseCFG::remove_empty_blocks() {
740742
// to give a fake exit path to infinite loops. At this late stage they
741743
// need to turn into Goto's so that when you enter the infinite loop you
742744
// indeed hang.
743-
if (block->get_node(block->end_idx())->Opcode() == Op_NeverBranch) {
745+
if (block->get_node(block->end_idx())->is_NeverBranch()) {
744746
convert_NeverBranch_to_Goto(block);
745747
}
746748

src/hotspot/share/opto/cfgnode.hpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -602,7 +602,10 @@ class CreateExNode : public TypeNode {
602602
// empty.
603603
class NeverBranchNode : public MultiBranchNode {
604604
public:
605-
NeverBranchNode( Node *ctrl ) : MultiBranchNode(1) { init_req(0,ctrl); }
605+
NeverBranchNode(Node* ctrl) : MultiBranchNode(1) {
606+
init_req(0, ctrl);
607+
init_class_id(Class_NeverBranch);
608+
}
606609
virtual int Opcode() const;
607610
virtual bool pinned() const { return true; };
608611
virtual const Type *bottom_type() const { return TypeTuple::IFBOTH; }

src/hotspot/share/opto/loopPredicate.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1433,7 +1433,7 @@ bool PhaseIdealLoop::loop_predication_impl(IdealLoopTree *loop) {
14331433
}
14341434
LoopNode* head = loop->_head->as_Loop();
14351435

1436-
if (head->unique_ctrl_out()->Opcode() == Op_NeverBranch) {
1436+
if (head->unique_ctrl_out()->is_NeverBranch()) {
14371437
// do nothing for infinite loops
14381438
return false;
14391439
}

src/hotspot/share/opto/loopnode.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3711,9 +3711,9 @@ bool PhaseIdealLoop::only_has_infinite_loops() {
37113711
if (n->is_Root()) {
37123712
// Found root -> there was an exit!
37133713
return false;
3714-
} else if (n->Opcode() == Op_NeverBranch) {
3714+
} else if (n->is_NeverBranch()) {
37153715
// Only follow the loop-internal projection, not the NeverBranch exit
3716-
ProjNode* proj = n->as_Multi()->proj_out_or_null(0);
3716+
ProjNode* proj = n->as_NeverBranch()->proj_out_or_null(0);
37173717
assert(proj != nullptr, "must find loop-internal projection of NeverBranch");
37183718
worklist.push(proj);
37193719
} else {

src/hotspot/share/opto/loopopts.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -774,8 +774,8 @@ static void enqueue_cfg_uses(Node* m, Unique_Node_List& wq) {
774774
for (DUIterator_Fast imax, i = m->fast_outs(imax); i < imax; i++) {
775775
Node* u = m->fast_out(i);
776776
if (u->is_CFG()) {
777-
if (u->Opcode() == Op_NeverBranch) {
778-
u = ((NeverBranchNode*)u)->proj_out(0);
777+
if (u->is_NeverBranch()) {
778+
u = u->as_NeverBranch()->proj_out(0);
779779
enqueue_cfg_uses(u, wq);
780780
} else {
781781
wq.push(u);
@@ -958,7 +958,7 @@ void PhaseIdealLoop::try_move_store_after_loop(Node* n) {
958958
#endif
959959
lca = place_outside_loop(lca, n_loop);
960960
assert(!n_loop->is_member(get_loop(lca)), "control must not be back in the loop");
961-
assert(get_loop(lca)->_nest < n_loop->_nest || lca->in(0)->Opcode() == Op_NeverBranch, "must not be moved into inner loop");
961+
assert(get_loop(lca)->_nest < n_loop->_nest || lca->in(0)->is_NeverBranch(), "must not be moved into inner loop");
962962

963963
// Move store out of the loop
964964
_igvn.replace_node(hook, n->in(MemNode::Memory));
@@ -1159,7 +1159,7 @@ Node* PhaseIdealLoop::place_outside_loop(Node* useblock, IdealLoopTree* loop) co
11591159
Node* dom = idom(useblock);
11601160
if (loop->is_member(get_loop(dom)) ||
11611161
// NeverBranch nodes are not assigned to the loop when constructed
1162-
(dom->Opcode() == Op_NeverBranch && loop->is_member(get_loop(dom->in(0))))) {
1162+
(dom->is_NeverBranch() && loop->is_member(get_loop(dom->in(0))))) {
11631163
break;
11641164
}
11651165
useblock = dom;

src/hotspot/share/opto/node.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -914,6 +914,7 @@ class Node {
914914
DEFINE_CLASS_QUERY(Mul)
915915
DEFINE_CLASS_QUERY(Multi)
916916
DEFINE_CLASS_QUERY(MultiBranch)
917+
DEFINE_CLASS_QUERY(NeverBranch)
917918
DEFINE_CLASS_QUERY(Opaque1)
918919
DEFINE_CLASS_QUERY(OuterStripMinedLoop)
919920
DEFINE_CLASS_QUERY(OuterStripMinedLoopEnd)
@@ -1070,6 +1071,8 @@ class Node {
10701071
Node* find_similar(int opc);
10711072

10721073
// Return the unique control out if only one. Null if none or more than one.
1074+
// Placeholder until 8281732 is backported.
1075+
Node* unique_ctrl_out_or_null() const { return unique_ctrl_out(); }
10731076
Node* unique_ctrl_out() const;
10741077

10751078
// Set control or add control as precedence edge
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
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+
super public class TestPhaseCFGNeverBranchToGoto
26+
{
27+
public Method "<init>":"()V"
28+
stack 2 locals 1
29+
{
30+
aload_0;
31+
invokespecial Method java/lang/Object."<init>":"()V";
32+
return;
33+
}
34+
static Method test:"(III)V"
35+
stack 200 locals 200
36+
{
37+
iload 2;
38+
ifeq LEND; // at runtime avoid the infinite-loop
39+
40+
iload 0;
41+
ifeq L20;
42+
goto L10;
43+
L10:
44+
goto L11;
45+
L11:
46+
iinc 0, 1;
47+
iload 1;
48+
ifge L10;
49+
goto L11;
50+
L20:
51+
iload 1;
52+
ifle L21;
53+
goto L10;
54+
L21:
55+
iconst_m1; // eventually false
56+
ifge L11;
57+
goto L20;
58+
59+
LEND:
60+
return;
61+
}
62+
public static Method main:"([Ljava/lang/String;)V"
63+
stack 100 locals 100
64+
{
65+
iconst_0;
66+
iconst_m1;
67+
iconst_0;
68+
invokestatic Method test:"(III)V";
69+
return;
70+
}
71+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
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 8296389
27+
* @summary Peeling of Irreducible loop can lead to NeverBranch being visited from either side
28+
* @run main/othervm -Xcomp -XX:-TieredCompilation -XX:PerMethodTrapLimit=0
29+
* -XX:CompileCommand=compileonly,TestPhaseCFGNeverBranchToGotoMain::test
30+
* TestPhaseCFGNeverBranchToGotoMain
31+
*/
32+
33+
/*
34+
* @test
35+
* @bug 8296389
36+
* @compile TestPhaseCFGNeverBranchToGoto.jasm
37+
* @summary Peeling of Irreducible loop can lead to NeverBranch being visited from either side
38+
* @run main/othervm -Xcomp -XX:-TieredCompilation -XX:PerMethodTrapLimit=0
39+
* -XX:CompileCommand=compileonly,TestPhaseCFGNeverBranchToGoto::test
40+
* TestPhaseCFGNeverBranchToGoto
41+
*/
42+
43+
44+
public class TestPhaseCFGNeverBranchToGotoMain {
45+
public static void main (String[] args) {
46+
test(false, false);
47+
}
48+
49+
public static void test(boolean flag1, boolean flag2) {
50+
if (flag1) { // runtime check, avoid infinite loop
51+
int a = 77;
52+
int b = 0;
53+
do { // empty loop
54+
a--;
55+
b++;
56+
} while (a > 0);
57+
// a == 0, b == 77 - after first loop-opts phase
58+
int p = 0;
59+
for (int i = 0; i < 4; i++) {
60+
if ((i % 2) == 0) {
61+
p = 1;
62+
}
63+
}
64+
// p == 1 - after second loop-opts phase (via unrolling)
65+
// in first loop-opts phase we have 2x unrolling, 4x after second
66+
int x = 1;
67+
if (flag2) {
68+
x = 3;
69+
} // have region here, so that NeverBranch does not get removed
70+
do { // infinite loop
71+
do {
72+
// NeverBranch inserted here, during loop-opts 1
73+
x *= 2;
74+
if (p == 0) { // reason for peeling in loop-opts 1
75+
// after we know that p == 1, we lose this exit
76+
break;
77+
}
78+
// once we know that b == 77, we lose exit
79+
} while (b == 77);
80+
// after we lost both exits above, this loop gets cut off
81+
int y = 5;
82+
do {
83+
y *= 3;
84+
} while (b == 77);
85+
} while (true);
86+
}
87+
}
88+
}

0 commit comments

Comments
 (0)