Skip to content

Commit fabda24

Browse files
committed
8296389: C2: PhaseCFG::convert_NeverBranch_to_Goto must handle both orders of successors
Reviewed-by: thartmann, chagedorn
1 parent 6c23b4f commit fabda24

11 files changed

+186
-21
lines changed

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

+1-1
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

+1-1
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

+6-6
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");
@@ -2002,7 +2002,7 @@ Node* ShenandoahIUBarrierNode::Identity(PhaseGVN* phase) {
20022002
static bool has_never_branch(Node* root) {
20032003
for (uint i = 1; i < root->req(); i++) {
20042004
Node* in = root->in(i);
2005-
if (in != NULL && in->Opcode() == Op_Halt && in->in(0)->is_Proj() && in->in(0)->in(0)->Opcode() == Op_NeverBranch) {
2005+
if (in != NULL && in->Opcode() == Op_Halt && in->in(0)->is_Proj() && in->in(0)->in(0)->isNeverBranch()) {
20062006
return true;
20072007
}
20082008
}
@@ -2033,20 +2033,20 @@ void MemoryGraphFixer::collect_memory_nodes() {
20332033
if (in->in(0)->is_Region()) {
20342034
Node* r = in->in(0);
20352035
for (uint j = 1; j < r->req(); j++) {
2036-
assert(r->in(j)->Opcode() != Op_NeverBranch, "");
2036+
assert(!r->in(j)->is_NeverBranch(), "");
20372037
}
20382038
} else {
20392039
Node* proj = in->in(0);
20402040
assert(proj->is_Proj(), "");
20412041
Node* in = proj->in(0);
2042-
assert(in->is_CallStaticJava() || in->Opcode() == Op_NeverBranch || in->Opcode() == Op_Catch || proj->is_IfProj(), "");
2042+
assert(in->is_CallStaticJava() || in->is_NeverBranch() || in->Opcode() == Op_Catch || proj->is_IfProj(), "");
20432043
if (in->is_CallStaticJava()) {
20442044
mem = in->in(TypeFunc::Memory);
20452045
} else if (in->Opcode() == Op_Catch) {
20462046
Node* call = in->in(0)->in(0);
20472047
assert(call->is_Call(), "");
20482048
mem = call->in(TypeFunc::Memory);
2049-
} else if (in->Opcode() == Op_NeverBranch) {
2049+
} else if (in->is_NeverBranch()) {
20502050
mem = collect_memory_for_infinite_loop(in);
20512051
}
20522052
}
@@ -2518,7 +2518,7 @@ void MemoryGraphFixer::fix_mem(Node* ctrl, Node* new_ctrl, Node* mem, Node* mem_
25182518
}
25192519
}
25202520
} else if (!mem_is_valid(m, u) &&
2521-
!(u->Opcode() == Op_CProj && u->in(0)->Opcode() == Op_NeverBranch && u->as_Proj()->_con == 1)) {
2521+
!(u->Opcode() == Op_CProj && u->in(0)->is_NeverBranch() && u->as_Proj()->_con == 1)) {
25222522
uses.push(u);
25232523
}
25242524
}

src/hotspot/share/opto/block.cpp

+7-5
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

+4-1
Original file line numberDiff line numberDiff line change
@@ -591,7 +591,10 @@ class CreateExNode : public TypeNode {
591591
// empty.
592592
class NeverBranchNode : public MultiBranchNode {
593593
public:
594-
NeverBranchNode( Node *ctrl ) : MultiBranchNode(1) { init_req(0,ctrl); }
594+
NeverBranchNode(Node* ctrl) : MultiBranchNode(1) {
595+
init_req(0, ctrl);
596+
init_class_id(Class_NeverBranch);
597+
}
595598
virtual int Opcode() const;
596599
virtual bool pinned() const { return true; };
597600
virtual const Type *bottom_type() const { return TypeTuple::IFBOTH; }

src/hotspot/share/opto/loopPredicate.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1442,7 +1442,7 @@ bool PhaseIdealLoop::loop_predication_impl(IdealLoopTree *loop) {
14421442
}
14431443
LoopNode* head = loop->_head->as_Loop();
14441444

1445-
if (head->unique_ctrl_out()->Opcode() == Op_NeverBranch) {
1445+
if (head->unique_ctrl_out()->is_NeverBranch()) {
14461446
// do nothing for infinite loops
14471447
return false;
14481448
}

src/hotspot/share/opto/loopnode.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -4208,9 +4208,9 @@ bool PhaseIdealLoop::only_has_infinite_loops() {
42084208
if (n->is_Root()) {
42094209
// Found root -> there was an exit!
42104210
return false;
4211-
} else if (n->Opcode() == Op_NeverBranch) {
4211+
} else if (n->is_NeverBranch()) {
42124212
// Only follow the loop-internal projection, not the NeverBranch exit
4213-
ProjNode* proj = n->as_Multi()->proj_out_or_null(0);
4213+
ProjNode* proj = n->as_NeverBranch()->proj_out_or_null(0);
42144214
assert(proj != nullptr, "must find loop-internal projection of NeverBranch");
42154215
worklist.push(proj);
42164216
} else {

src/hotspot/share/opto/loopopts.cpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -792,8 +792,8 @@ static void enqueue_cfg_uses(Node* m, Unique_Node_List& wq) {
792792
for (DUIterator_Fast imax, i = m->fast_outs(imax); i < imax; i++) {
793793
Node* u = m->fast_out(i);
794794
if (u->is_CFG()) {
795-
if (u->Opcode() == Op_NeverBranch) {
796-
u = ((NeverBranchNode*)u)->proj_out(0);
795+
if (u->is_NeverBranch()) {
796+
u = u->as_NeverBranch()->proj_out(0);
797797
enqueue_cfg_uses(u, wq);
798798
} else {
799799
wq.push(u);
@@ -976,7 +976,7 @@ void PhaseIdealLoop::try_move_store_after_loop(Node* n) {
976976
#endif
977977
lca = place_outside_loop(lca, n_loop);
978978
assert(!n_loop->is_member(get_loop(lca)), "control must not be back in the loop");
979-
assert(get_loop(lca)->_nest < n_loop->_nest || lca->in(0)->Opcode() == Op_NeverBranch, "must not be moved into inner loop");
979+
assert(get_loop(lca)->_nest < n_loop->_nest || lca->in(0)->is_NeverBranch(), "must not be moved into inner loop");
980980

981981
// Move store out of the loop
982982
_igvn.replace_node(hook, n->in(MemNode::Memory));
@@ -1181,7 +1181,7 @@ Node* PhaseIdealLoop::place_outside_loop(Node* useblock, IdealLoopTree* loop) co
11811181
Node* dom = idom(useblock);
11821182
if (loop->is_member(get_loop(dom)) ||
11831183
// NeverBranch nodes are not assigned to the loop when constructed
1184-
(dom->Opcode() == Op_NeverBranch && loop->is_member(get_loop(dom->in(0))))) {
1184+
(dom->is_NeverBranch() && loop->is_member(get_loop(dom->in(0))))) {
11851185
break;
11861186
}
11871187
useblock = dom;

src/hotspot/share/opto/node.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -922,6 +922,7 @@ class Node {
922922
DEFINE_CLASS_QUERY(Mul)
923923
DEFINE_CLASS_QUERY(Multi)
924924
DEFINE_CLASS_QUERY(MultiBranch)
925+
DEFINE_CLASS_QUERY(NeverBranch)
925926
DEFINE_CLASS_QUERY(Opaque1)
926927
DEFINE_CLASS_QUERY(OuterStripMinedLoop)
927928
DEFINE_CLASS_QUERY(OuterStripMinedLoopEnd)
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+
}
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)