8297642: PhaseIdealLoop::only_has_infinite_loops must detect all loops that never lead to termination

Reviewed-by: thartmann, roland
This commit is contained in:
Emanuel Peter 2022-12-08 15:29:26 +00:00
parent fc52f21f9a
commit d562d3fcbe
3 changed files with 175 additions and 31 deletions

View File

@ -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);
}
}
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) {
return false;
}
worklist.push(head);
}
// 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

View File

@ -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;
}
}

View File

@ -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);
}
}