8297642: PhaseIdealLoop::only_has_infinite_loops must detect all loops that never lead to termination
Reviewed-by: thartmann, roland
This commit is contained in:
parent
fc52f21f9a
commit
d562d3fcbe
@ -4190,45 +4190,40 @@ bool PhaseIdealLoop::process_expensive_nodes() {
|
||||
}
|
||||
|
||||
#ifdef ASSERT
|
||||
// Goes over all children of the root of the loop tree, collects all controls for the loop and its inner loops then
|
||||
// checks whether any control is a branch out of the loop and if it is, whether it's not a NeverBranch.
|
||||
// Goes over all children of the root of the loop tree. Check if any of them have a path
|
||||
// down to Root, that does not go via a NeverBranch exit.
|
||||
bool PhaseIdealLoop::only_has_infinite_loops() {
|
||||
ResourceMark rm;
|
||||
Unique_Node_List worklist;
|
||||
// start traversal at all loop heads of first-level loops
|
||||
for (IdealLoopTree* l = _ltree_root->_child; l != NULL; l = l->_next) {
|
||||
Unique_Node_List wq;
|
||||
Node* head = l->_head;
|
||||
assert(head->is_Region(), "");
|
||||
for (uint i = 1; i < head->req(); ++i) {
|
||||
Node* in = head->in(i);
|
||||
if (get_loop(in) != _ltree_root) {
|
||||
wq.push(in);
|
||||
worklist.push(head);
|
||||
}
|
||||
}
|
||||
for (uint i = 0; i < wq.size(); ++i) {
|
||||
Node* c = wq.at(i);
|
||||
if (c == head) {
|
||||
continue;
|
||||
} else if (c->is_Region()) {
|
||||
for (uint j = 1; j < c->req(); ++j) {
|
||||
wq.push(c->in(j));
|
||||
}
|
||||
} else {
|
||||
wq.push(c->in(0));
|
||||
}
|
||||
}
|
||||
assert(wq.member(head), "");
|
||||
for (uint i = 0; i < wq.size(); ++i) {
|
||||
Node* c = wq.at(i);
|
||||
if (c->is_MultiBranch()) {
|
||||
for (DUIterator_Fast jmax, j = c->fast_outs(jmax); j < jmax; j++) {
|
||||
Node* u = c->fast_out(j);
|
||||
assert(u->is_CFG(), "");
|
||||
if (!wq.member(u) && c->Opcode() != Op_NeverBranch) {
|
||||
// BFS traversal down the CFG, except through NeverBranch exits
|
||||
for (uint i = 0; i < worklist.size(); ++i) {
|
||||
Node* n = worklist.at(i);
|
||||
assert(n->is_CFG(), "only traverse CFG");
|
||||
if (n->is_Root()) {
|
||||
// Found root -> there was an exit!
|
||||
return false;
|
||||
} else if (n->Opcode() == Op_NeverBranch) {
|
||||
// Only follow the loop-internal projection, not the NeverBranch exit
|
||||
ProjNode* proj = n->as_Multi()->proj_out_or_null(0);
|
||||
assert(proj != nullptr, "must find loop-internal projection of NeverBranch");
|
||||
worklist.push(proj);
|
||||
} else {
|
||||
// Traverse all CFG outputs
|
||||
for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
|
||||
Node* use = n->fast_out(i);
|
||||
if (use->is_CFG()) {
|
||||
worklist.push(use);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// No exit found for any loop -> all are infinite
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. 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 TestOnlyInfiniteLoops
|
||||
{
|
||||
public Method "<init>":"()V"
|
||||
stack 2 locals 1
|
||||
{
|
||||
aload_0;
|
||||
invokespecial Method java/lang/Object."<init>":"()V";
|
||||
return;
|
||||
}
|
||||
|
||||
static Method test_simple:"(III)I"
|
||||
stack 200 locals 10
|
||||
{
|
||||
// Nested infinite loop, where inner loop eventually
|
||||
// looses exit to outer loop. Then, the inner loop
|
||||
// floats outside the inner loop. The entry from
|
||||
// outer to inner loop now becomes an exit for the
|
||||
// outer loop, where it now enters the next loop, that
|
||||
// used to be the inner loop.
|
||||
iconst_0;
|
||||
istore 9;
|
||||
|
||||
iload 0;
|
||||
ifeq LEND; // skip
|
||||
|
||||
LOOP1:
|
||||
iload 1;
|
||||
ifeq LOOP1; // dominates
|
||||
LOOP2:
|
||||
// SKIP: prevent loop-exit from becoming zero-trip guard
|
||||
iload 2;
|
||||
ifeq SKIP;
|
||||
iinc 9, 1;
|
||||
SKIP:
|
||||
iload 1;
|
||||
ifeq LOOP1; // is dominated
|
||||
goto LOOP2;
|
||||
|
||||
LEND:
|
||||
iload 9;
|
||||
ireturn;
|
||||
}
|
||||
static Method test_irreducible:"(IIII)V"
|
||||
stack 200 locals 200
|
||||
{
|
||||
iload_0;
|
||||
ifeq LEND; // skip
|
||||
|
||||
L1:
|
||||
iload 1;
|
||||
ifgt MERGE;
|
||||
L2:
|
||||
iload 2;
|
||||
ifge MERGE;
|
||||
goto L1;
|
||||
|
||||
MERGE:
|
||||
nop;
|
||||
LOOP:
|
||||
iload 3;
|
||||
ifle L2;
|
||||
iconst_0; // always true
|
||||
ifeq LOOP;
|
||||
iconst_0; // always true
|
||||
ifeq LOOP;
|
||||
INFTY:
|
||||
goto INFTY; // infinite loop
|
||||
|
||||
LEND:
|
||||
return;
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. 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 8297642
|
||||
* @compile TestOnlyInfiniteLoops.jasm
|
||||
* @summary Nested irreducible loops, where the inner loop floats out of the outer
|
||||
* @run main/othervm
|
||||
* -XX:CompileCommand=compileonly,TestOnlyInfiniteLoops::test*
|
||||
* -XX:-TieredCompilation -Xcomp
|
||||
* TestOnlyInfiniteLoopsMain
|
||||
*
|
||||
* @test
|
||||
* @bug 8297642
|
||||
* @compile TestOnlyInfiniteLoops.jasm
|
||||
* @summary Nested irreducible loops, where the inner loop floats out of the outer
|
||||
* @run main/othervm
|
||||
* -XX:CompileCommand=compileonly,TestOnlyInfiniteLoops::test*
|
||||
* -XX:-TieredCompilation -Xcomp
|
||||
* -XX:PerMethodTrapLimit=0
|
||||
* TestOnlyInfiniteLoopsMain
|
||||
*/
|
||||
|
||||
public class TestOnlyInfiniteLoopsMain {
|
||||
public static void main(String[] args) {
|
||||
TestOnlyInfiniteLoops t = new TestOnlyInfiniteLoops();
|
||||
System.out.println("test_simple");
|
||||
t.test_simple(0, 0, 0);
|
||||
System.out.println("test_irreducible");
|
||||
t.test_irreducible(0, 0, 0, 0);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user