8307927: C2: "malformed control flow" with irreducible loop

Reviewed-by: thartmann, epeter
This commit is contained in:
Roland Westrelin 2023-06-29 07:43:46 +00:00
parent be64d3ac3c
commit 690d626995
3 changed files with 189 additions and 49 deletions

View File

@ -3531,13 +3531,13 @@ bool IdealLoopTree::beautify_loops( PhaseIdealLoop *phase ) {
}
//------------------------------allpaths_check_safepts----------------------------
// Allpaths backwards scan from loop tail, terminating each path at first safepoint
// encountered. Helper for check_safepts.
// Allpaths backwards scan. Starting at the head, traversing all backedges, and the body. Terminating each path at first
// safepoint encountered. Helper for check_safepts.
void IdealLoopTree::allpaths_check_safepts(VectorSet &visited, Node_List &stack) {
assert(stack.size() == 0, "empty stack");
stack.push(_tail);
stack.push(_head);
visited.clear();
visited.set(_tail->_idx);
visited.set(_head->_idx);
while (stack.size() > 0) {
Node* n = stack.pop();
if (n->is_Call() && n->as_Call()->guaranteed_safepoint()) {
@ -3545,12 +3545,13 @@ void IdealLoopTree::allpaths_check_safepts(VectorSet &visited, Node_List &stack)
} else if (n->Opcode() == Op_SafePoint) {
if (_phase->get_loop(n) != this) {
if (_required_safept == nullptr) _required_safept = new Node_List();
_required_safept->push(n); // save the one closest to the tail
// save the first we run into on that path: closest to the tail if the head has a single backedge
_required_safept->push(n);
}
// Terminate this path
} else {
uint start = n->is_Region() ? 1 : 0;
uint end = n->is_Region() && !n->is_Loop() ? n->req() : start + 1;
uint end = n->is_Region() && (!n->is_Loop() || n == _head) ? n->req() : start + 1;
for (uint i = start; i < end; i++) {
Node* in = n->in(i);
assert(in->is_CFG(), "must be");
@ -3622,53 +3623,55 @@ void IdealLoopTree::check_safepts(VectorSet &visited, Node_List &stack) {
if (_child) _child->check_safepts(visited, stack);
if (_next) _next ->check_safepts(visited, stack);
if (!_head->is_CountedLoop() && !_has_sfpt && _parent != nullptr && !_irreducible) {
if (!_head->is_CountedLoop() && !_has_sfpt && _parent != nullptr) {
bool has_call = false; // call on dom-path
bool has_local_ncsfpt = false; // ncsfpt on dom-path at this loop depth
Node* nonlocal_ncsfpt = nullptr; // ncsfpt on dom-path at a deeper depth
// Scan the dom-path nodes from tail to head
for (Node* n = tail(); n != _head; n = _phase->idom(n)) {
if (n->is_Call() && n->as_Call()->guaranteed_safepoint()) {
has_call = true;
_has_sfpt = 1; // Then no need for a safept!
break;
} else if (n->Opcode() == Op_SafePoint) {
if (_phase->get_loop(n) == this) {
has_local_ncsfpt = true;
if (!_irreducible) {
// Scan the dom-path nodes from tail to head
for (Node* n = tail(); n != _head; n = _phase->idom(n)) {
if (n->is_Call() && n->as_Call()->guaranteed_safepoint()) {
has_call = true;
_has_sfpt = 1; // Then no need for a safept!
break;
}
if (nonlocal_ncsfpt == nullptr) {
nonlocal_ncsfpt = n; // save the one closest to the tail
}
} else {
IdealLoopTree* nlpt = _phase->get_loop(n);
if (this != nlpt) {
// If at an inner loop tail, see if the inner loop has already
// recorded seeing a call on the dom-path (and stop.) If not,
// jump to the head of the inner loop.
assert(is_member(nlpt), "nested loop");
Node* tail = nlpt->_tail;
if (tail->in(0)->is_If()) tail = tail->in(0);
if (n == tail) {
// If inner loop has call on dom-path, so does outer loop
if (nlpt->_has_sfpt) {
has_call = true;
_has_sfpt = 1;
break;
}
// Skip to head of inner loop
assert(_phase->is_dominator(_head, nlpt->_head), "inner head dominated by outer head");
n = nlpt->_head;
if (_head == n) {
// this and nlpt (inner loop) have the same loop head. This should not happen because
// during beautify_loops we call merge_many_backedges. However, infinite loops may not
// have been attached to the loop-tree during build_loop_tree before beautify_loops,
// but then attached in the build_loop_tree afterwards, and so still have unmerged
// backedges. Check if we are indeed in an infinite subgraph, and terminate the scan,
// since we have reached the loop head of this.
assert(_head->as_Region()->is_in_infinite_subgraph(),
"only expect unmerged backedges in infinite loops");
break;
} else if (n->Opcode() == Op_SafePoint) {
if (_phase->get_loop(n) == this) {
has_local_ncsfpt = true;
break;
}
if (nonlocal_ncsfpt == nullptr) {
nonlocal_ncsfpt = n; // save the one closest to the tail
}
} else {
IdealLoopTree* nlpt = _phase->get_loop(n);
if (this != nlpt) {
// If at an inner loop tail, see if the inner loop has already
// recorded seeing a call on the dom-path (and stop.) If not,
// jump to the head of the inner loop.
assert(is_member(nlpt), "nested loop");
Node* tail = nlpt->_tail;
if (tail->in(0)->is_If()) tail = tail->in(0);
if (n == tail) {
// If inner loop has call on dom-path, so does outer loop
if (nlpt->_has_sfpt) {
has_call = true;
_has_sfpt = 1;
break;
}
// Skip to head of inner loop
assert(_phase->is_dominator(_head, nlpt->_head), "inner head dominated by outer head");
n = nlpt->_head;
if (_head == n) {
// this and nlpt (inner loop) have the same loop head. This should not happen because
// during beautify_loops we call merge_many_backedges. However, infinite loops may not
// have been attached to the loop-tree during build_loop_tree before beautify_loops,
// but then attached in the build_loop_tree afterwards, and so still have unmerged
// backedges. Check if we are indeed in an infinite subgraph, and terminate the scan,
// since we have reached the loop head of this.
assert(_head->as_Region()->is_in_infinite_subgraph(),
"only expect unmerged backedges in infinite loops");
break;
}
}
}
}

View File

@ -0,0 +1,91 @@
/*
* Copyright (c) 2023, Red Hat, Inc. 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.
*/
super public class MalformedControlIrreducibleLoop
version 52:0
{
public Method "<init>":"()V"
stack 1 locals 1
{
aload_0;
invokespecial Method java/lang/Object."<init>":"()V";
return;
}
/* same as:
public static void actualTest(int flag) {
int i = 1;
int j = 1;
if (flag == 2) {
// goto second_entry;
}
loop:
for (;;) {
i = 1;
// second_entry:
do {
if (i == 1) {
continue loop; // goto loop
}
i *= 2;
j *= 2;
} while (j < 2);
break;
}
}
*/
public static Method actualTest:"(I)V"
stack 2 locals 3
{
iconst_1;
istore_1;
iconst_1;
istore_2;
iload_0;
iconst_2;
if_icmpne L11;
L9: stack_frame_type append;
locals_map int, int;
iconst_1;
istore_1;
L11: stack_frame_type same;
iload_1;
iconst_1;
if_icmpeq L9;
L19: stack_frame_type same;
iload_1;
iconst_2;
imul;
istore_1;
iload_2;
iconst_2;
imul;
istore_2;
iload_2;
iconst_2;
if_icmplt L11;
goto L35;
L35: stack_frame_type same;
return;
}
} // end Class TestMalformedControlIrreducibleLoop

View File

@ -0,0 +1,46 @@
/*
* Copyright (c) 2023, Red Hat, Inc. 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 8307927
* @summary C2: "malformed control flow" with irreducible loop
* @compile MalformedControlIrreducibleLoop.jasm
* @run main/othervm -Xcomp -XX:-TieredCompilation -XX:CompileOnly=TestMalformedControlIrreducibleLoop::test TestMalformedControlIrreducibleLoop
*/
public class TestMalformedControlIrreducibleLoop {
public static void main(String[] args) {
new MalformedControlIrreducibleLoop();
test(false);
}
private static void test(boolean flag) {
int i;
for (i = 1; i < 2; i *= 2) {
}
if (flag) {
MalformedControlIrreducibleLoop.actualTest(i);
}
}
}