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