jdk-24/test/hotspot/jtreg/compiler/loopopts/TestDeadIrreducibleLoops.jasm
Emanuel Peter ac7119f0d5 8280126: C2: detect and remove dead irreducible loops
Reviewed-by: kvn, chagedorn, thartmann
2023-02-08 07:45:09 +00:00

1497 lines
36 KiB
Plaintext

/*
* Copyright (c) 2023, 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 TestDeadIrreducibleLoops
{
public Method "<init>":"()V"
stack 2 locals 1
{
aload_0;
invokespecial Method java/lang/Object."<init>":"()V";
return;
}
static Method test_001:"(IIII)I"
stack 20 locals 20
{
// Irreducible loop with 3 Regions, 2 are entries, 1 is not entry
iconst_0;
istore 10;
iload_0;
ifeq LEND; // runtime check, skip all code
iload_1;
ifeq ENTRY1; // irreducible entry
goto ENTRY2;
ENTRY1:
// 43 Region - irreducible-entry
iload 3;
ifeq L1;
iinc 10, 1;
ENTRY2:
// 44 Region - irreducible-entry
iinc 10, 2;
L1:
// 60 Region - irreducible (but not entry)
// can be loop-head, if build_loop_tree
// first reaches ENTRY2
iinc 10, 4;
iload_2;
ifeq ENTRY1; // loop-end
LEND:
iload 10;
ireturn;
}
static Method test_002:"(I)V"
stack 10 locals 10
{
// split_fall_in splits up an irreducible-entry Region
iconst_0;
istore 1;
iload 0;
ifle L2;
L1:
// bci:8
// 30 Region (tagged irreducible at parsing)
iload 0;
ifne L3;
L2:
// bci:13
// 29 Region (tagged irreducible at parsing)
// 100 Region
// 129 Region (produced in split_fall_in, must be tagged irreducible)
// 134 Loop
goto L1;
L3:
iload 1;
ifgt L1;
return;
}
static Method test_003:"(I)I"
stack 5 locals 25
{
// Cut off both entries to irreducible loop at the same time:
// LOOP_y (empty_loop) collapses -> cut off both entries to irreducible LOOP_3
// LOOP_3 should be removed during IGVN
iconst_m1;
istore 12;
// empty loop, where var[20] counts to 0
// and var[21] counts to 10001
ldc 10001;
istore 20;
iconst_0;
istore 21;
LOOP_Y:
iinc 20, -1;
iinc 21, 1;
iload 20;
ifgt LOOP_Y;
// once the empty_loop above collapses, we see this is true
iload 21;
ldc 10001;
if_icmpeq LEND;
iload_0;
ldc 1;
iand;
ifeq LOOP_3c; // second entry
// first entry
LOOP_3a:
iinc 12, 11;
iload 12;
ifge LOOP_3c; // skip
LOOP_3b:
iinc 12, 7;
LOOP_3c:
iinc 12, 3;
iload 12;
ldc 1001;
if_icmpne LOOP_3a; // loop
LEND:
iload 12;
ireturn;
}
static Method test_004:"(Ljava/lang/Object;)Ljava/lang/Object;"
stack 10 locals 10
{
// When we detect irreducible loops, we add more Phi nodes
// This test generates dead code, where we create a dead-loop
// of Phi nodes. Phi nodes are considered dead-loop safe,
// so they should be handled gracefully.
// This is a regression test for the faulty "sanity" assert
// in PhiNode::merge_through_phi. Instead of asserting,
// we now just abort the optimization.
iconst_1;
istore 5;
LOOP:
iconst_0;
ifge HEAD;
goto LOOP;
HEAD:
iload 5;
ifge LCMP;
iload 5;
iflt L29;
L30:
iload 5;
iflt BOTTOM;
L29:
iload 5;
ifeq L30;
BOTTOM:
goto HEAD;
LCMP:
aload_0;
areturn;
}
static Method test_005:"(II)V"
stack 20 locals 20
{
// Triggers compile bailout: bad CFG: both infinite and irreducible
iload_0;
ifeq LEND; // runtime check, avoid infinte loop below
iconst_0;
istore 10;
iload_1;
ifeq ENTRY2;
ENTRY1:
iinc 10, 1;
ENTRY2:
iinc 10, 2;
goto ENTRY1; // backedge
LEND:
return;
}
static Method test_006:"(I)I"
stack 5 locals 25
{
// check that disconnected irreducible loop collapses instantly
// and does not create data dead-loop with iinc / AddI
iconst_m1;
istore 12;
// empty loop, where var[20] counts to 0
// and var[21] counts to 10001
ldc 10001;
istore 20;
iconst_0;
istore 21;
LOOP_Y:
iinc 20, -1;
iinc 21, 1;
iload 20;
ifgt LOOP_Y;
// once the empty_loop above collapses, we see this is true
iload 21;
ldc 10001;
if_icmpeq LEND;
// second entry
iload_0;
ldc 1;
iand;
ifgt LOOP_3d;
// first entry
LOOP_3a:
iload 12;
ifge LOOP_3d;
LOOP_3b:
iload_0; // eventually, we get TOP and things die from the inside out
ldc 2;
if_icmplt LOOP_3b;
iinc 12, 1; // the problematic AddI
goto LOOP_3a;
LOOP_3d:
iload 12;
ldc 1001;
if_icmpne LOOP_3a;
LEND:
iload_0;
ireturn;
}
static Method test_007:"(III)V"
stack 20 locals 40
{
// Irreducible entry Regions lose all loop-internal control
// Once empty_loop collapses, we never loop-back to
// ENTRY1 nor ENTRY2. SKIP1 and SKIP2 become the new
// irreducible loop entries.
iload_0;
ifeq LEND; // runtime check, avoid code below
// empty loop, where var[20] counts to 0
// and var[21] counts to 10001
ldc 10001;
istore 20;
iconst_0;
istore 21;
EMPTY_LOOP:
iinc 20, -1;
iinc 21, 1;
iload 20;
ifgt EMPTY_LOOP;
iconst_0;
istore 30; // x = 0
iload_1;
ifeq ENTRY1;
goto ENTRY2; // the order here is arbitrary
ENTRY1:
iinc 30, 1; // x += 1
SKIP1:
ldc 10001;
iload 21;
if_icmpeq SKIP2; // always true after empty_loop collapses
ENTRY2:
iinc 30, 32; // x += 2
SKIP2:
iload_2;
ifeq LEND; // loop-exit
ldc 10001;
iload 21;
if_icmpeq SKIP1; // always true after empty_loop collapses
goto ENTRY1; // backedge
LEND:
return;
}
static Method test_008:"(III)V"
stack 20 locals 20
{
// Same as test_008, but ENTRY1 and ENTRY2 already
// lose internal loop control during parsing,
// and SKIP1 and SKIP2 are new entry Regions.
iload_0;
ifeq LEND; // runtime check, skip code below
iconst_0;
istore 10; // x = 0
iload_1;
ifeq ENTRY2;
goto ENTRY1; // the order here is arbitrary
ENTRY1:
iinc 10, 1; // x += 1
SKIP1:
iconst_0;
ifeq SKIP2; // always true
ENTRY2:
iinc 10, 32; // x += 2
SKIP2:
iload_2;
ifeq LEND; // loop-exit
iconst_0;
ifeq SKIP1; // always true
goto ENTRY1; // backedge
LEND:
return;
}
static Method test_009:"(IIIIIII)V"
stack 20 locals 40
{
// same as test_007, except extra ifs in ENTRY1 and ENTRY2
// once ENTRY1 and ENTRY2 lose "backedges",
// the ELSE1 and ELSE2 sections are no longer in the irreducible loop
// and SKIP1 and SKIP2 become the new loop entries
iload 0;
ifeq LEND; // runtime check, avoid code below
// empty loop, where var[20] counts to 0
// and var[21] counts to 10001
ldc 10001;
istore 20;
iconst_0;
istore 21;
EMPTY_LOOP:
iinc 20, -1;
iinc 21, 1;
iload 20;
ifgt EMPTY_LOOP;
iconst_0;
istore 30; // x = 0
iload 1;
ifeq ENTRY1;
goto ENTRY2; // the order here is arbitrary
ENTRY1:
iinc 30, 1; // x += 1
iload 2;
ifeq ELSE1;
iinc 30, 2; // x += 2
iload 3;
ifeq ELSE1;
iinc 30, 4; // x += 4
ELSE1:
iinc 30, 8; // x += 8
SKIP1:
ldc 10001;
iload 21;
if_icmpeq SKIP2; // always true after empty_loop collapses
ENTRY2:
iinc 30, 16; // x += 16
iload 4;
ifeq ELSE2;
iinc 30, 32; // x += 32
iload 5;
ifeq ELSE2;
iinc 30, 64; // x += 64
ELSE2:
iinc 30, 128; // x += 128
SKIP2:
iload 6;
ifeq LEND; // loop-exit
ldc 10001;
iload 21;
if_icmpeq SKIP1; // always true after empty_loop collapses
goto ENTRY1; // backedge
LEND:
return;
}
static Method test_010:"(IIIII)V"
stack 10 locals 5
{
// outer: irreducible, inner: reducible loop
// ENTRY1 is loop-head for both
// test that is_in_irreducible_loop walks up to outermost loop with that loop-head
iload_0;
ifeq LEND; // runtime check, avoid code below
iload 4;
ifeq SYMMETRY;
iload_1;
ifeq ENTRY1;
goto ENTRY2;
ENTRY1:
// loop-head
iload_2;
ifeq ENTRY1; // backedge of reducible loop (inner)
ENTRY2:
// second-entry block
iload_3;
ifeq LEND;
goto ENTRY1; // backedge of irreducible loop (outer)
SYMMETRY: // same as ENTRY1 / ENTRY2
iload_1;
ifeq ENTRY4; // but these are swapped
goto ENTRY3;
ENTRY3:
// loop-head
iload_2;
ifeq ENTRY3; // backedge of reducible loop (inner)
ENTRY4:
// second-entry block
iload_3;
ifeq LEND;
goto ENTRY3; // backedge of irreducible loop (outer)
LEND:
return;
}
static Method test_011:"(IIIII)V"
stack 20 locals 20
{
// If we define irreducible-entry as the Block / Region
// that is either the head of the (outermost) irreducible loop,
// or the location where we found a secondary entry to the loop,
// we find that this definition depends on the order of the
// DF traversal.
// (backtrack, edge 0 -> 29, normal forward edge)
//
// bci-order 1:
// 0, 29, 4, 11, 24 (backedge to 11), 16, 21 (backedge to 11),
// 8 (second entry to 16, make 11 irreducible loop head)
//
// bci-order 2:
// 0, 4, 8, 16, 21, 11 (backedge to 16), 24 (backedge to 11), 29
// (backtrack, find edge from 16 -> 24, second entry to 24,
// 16 is irreducible loop head)
// (backtrack, find edge from 4 -> 11, second entry to 11,
// 16 is again irreducible loop head)
// (backtrack, edge 0 -> 29, normal forward edge)
//
// Note: in order 2, bci:24 is a entry, but not for order 1.
// This makes asserts that check the consistency of entries
// difficult, if not impossible.
// bci: 0
iload_0;
ifeq LEND; // runtime check, avoid code below
// bci: 4
iload_1;
ifeq ENTRY1;
// bci: 8
goto ENTRY2;
ENTRY1:
// bci: 11
iload 2;
ifeq BOTTOM;
ENTRY2:
// bci: 16
iload 3;
ifeq BOTTOM;
// bci: 21
goto ENTRY1;
BOTTOM:
// bci: 24
iload 4;
ifeq ENTRY1;
LEND:
// bci: 29
return;
}
static Method test_012a:"(IIIIIIII)V"
stack 20 locals 20
{
// reducible loop inside irreducible loop
// block numbers give order that leads to only
// ENTRY1 and ENTRY2 being irreducible loop entries
// block 0
iload_0;
ifeq LEND; // runtime check, avoid code below
// block 2
iload_1;
ifeq ENTRY1;
// block 12
goto ENTRY2;
ENTRY1:
// block 3
iload 2;
ifeq BOTTOM1;
// block 8
goto ENTRY2;
ENTRY2:
// block 9
iload 3;
ifeq BOTTOM1;
// block 10
iload 7;
ifeq LEND;
// block 11
goto ENTRY1;
BOTTOM1:
// region must be marked as irreducible
// it is loop-head of irreducible loop, but also
// itself in the irreducible loop that surrounds it
// there is also a traversal that makes this a
// irreducible loop entry:
// 0, 2, 12, 9, 10, 11, 3, 8 (-> backedge to 9)
// 4 (-> backedge to 3), 5, 7 (->backedge to 4),
// 1, 6 (-> backedge to 5, -> backedge to 3) ... backtrack all the way to 9
// -> irreducible entry edge to 4
// Since this kind of block / region can be an irreducible loop
// entry, we should mark the block / region as in the irreducible loop
// this block is split
// block 4 (in: 3 7 9, out: 5 3)
// block 6 (in: 5, out: 5 3)
iload 4;
ifeq ENTRY1;
BOTTOM2:
// block 5
iload 5;
ifeq BOTTOM1;
// block 7
iload 6;
ifeq BOTTOM1;
LEND:
// block 1
return;
}
static Method test_012b:"(IIIII)V"
stack 20 locals 20
{
// reducible loop inside irreducible loop
// this nested loop is an infinite loop (no exit)
iload_0;
ifeq LEND; // runtime check, avoid code below
iload_1;
ifeq ENTRY1;
goto ENTRY2;
ENTRY1:
iload 2;
ifeq BOTTOM;
goto ENTRY2;
ENTRY2:
iload 3;
ifeq BOTTOM;
goto ENTRY1;
BOTTOM:
// this must still be marked as in irreducible loop from above,
// even though it is the head of a reducible loop
iload 4;
ifeq ENTRY1;
goto BOTTOM; // reducible loop
LEND:
return;
}
static Method test_013:"(IIIIIIIII)V"
stack 20 locals 40
{
// Irreducible loop ENTRY1 / ENTRY2, eventually collapses
// Reducible loops LOOP1 / LOOP2 inside irreducible loop
// Irreducible loop BOTTOM, with backedge to ENTRY1 (eventually collapses)
iload_0;
ifeq LEND; // runtime check, avoid code below
// empty loop
ldc 10001;
istore 20;
iconst_0;
istore 21;
EMPTY_LOOP:
iinc 20, -1;
iinc 21, 1;
iload 21;
ldc 10001;
if_icmplt EMPTY_LOOP;
// var[20] == 0
iconst_1;
istore 30; // for LOOP1, LOOP2
iload_1;
ifeq ENTRY1;
goto ENTRY2;
ENTRY1:
iload 20;
ifeq LOOP1;
goto ENTRY2; // removed by empty_loop
ENTRY2:
iload 20;
ifeq LOOP2;
goto ENTRY1; // removed by empty_loop
LOOP1:
iload 30;
ldc 2;
imul;
istore 30;
iload 30;
ldc 10000;
if_icmple LOOP1;
goto BOTTOM1;
LOOP2:
iload 30;
ldc 2;
imul;
istore 30;
iload 30;
ldc 10000;
if_icmple LOOP2;
goto BOTTOM2;
BOTTOM1:
iload 3;
ifeq BOTTOM2;
iload 4;
ifeq BOTTOM3;
iload 20;
ifne ENTRY1; // removed by empty_loop
goto LEND;
BOTTOM2:
iload 5;
ifeq BOTTOM3;
iload 6;
ifeq BOTTOM1;
goto LEND;
BOTTOM3:
iload 7;
ifeq BOTTOM1;
iload 8;
ifeq BOTTOM2;
goto LEND;
LEND:
return;
}
static Method test_014a:"(III)V"
stack 20 locals 40
{
// Irreducible loop that becomes normal loop
// and is then removed as empty loop (#2)
// which finally takes out ENTRY3 / ENTRY4
//
iload_0;
ifeq LEND; // runtime check, avoid code below
// empty_loop #1
ldc 10001;
istore 20;
iconst_0;
istore 21;
EMPTY_LOOP:
iinc 20, -1;
iinc 21, 1;
iload 21;
ldc 10001;
if_icmplt EMPTY_LOOP;
// var[20] == 0 // empty_loop (#1)
// variables for ENTRY1 / ENTRY2
// when path to ENTRY2 collapses,
// the loop becomes reducible and
// can be removed as empty_loop (#2)
iconst_0;
istore 30;
ldc 20002;
istore 31;
iload 20;
ifeq ENTRY1;
goto ENTRY2; // removed by empty_loop (#1)
ENTRY1:
iinc 30, 1;
ENTRY2:
iinc 31, -1;
iload 30;
ldc 20002;
if_icmplt ENTRY1;
// var[31] == 0 // empty_loop (#2)
iload 31;
ifeq LEND; // always taken due to empty_loop (#2)
iload_1;
ifeq ENTRY3;
goto ENTRY4;
// irreducible loop at the end
// expected to be removed after empty_loop (#2) collapses
ENTRY3:
iload_2;
ifeq LEND;
ENTRY4:
goto ENTRY3;
LEND:
return;
}
static Method test_014b:"(III)V"
stack 200 locals 200
{
// Sequence of these loops:
// Irreducible with 2 entries.
// One entry collapses, turning the irreducible loop
// into an empty_loop. This collapses one entry of
// the next loop. This cascades until all loops are
// removed.
iload_0;
ifeq LEND; // runtime check, avoid code below
// setting up all variables for the loops below
iconst_0;
istore 100;
ldc 10001;
istore 101;
iconst_0;
istore 102;
ldc 10001;
istore 103;
iconst_0;
istore 104;
ldc 10001;
istore 105;
iconst_0;
istore 106;
ldc 10001;
istore 107;
iconst_0;
istore 108;
ldc 10001;
istore 109;
iconst_0;
istore 110;
ldc 10001;
istore 111;
iconst_0;
istore 112;
ldc 10001;
istore 113;
iconst_0;
istore 114;
ldc 10001;
istore 115;
iconst_0; // collapse during parsing
ifeq ENTRY00;
goto ENTRY01;
ENTRY00:
iinc 100, 1;
ENTRY01:
iinc 101, -1;
iload 100;
ldc 10001;
if_icmplt ENTRY00;
// var[101] == 0 // empty_loop (#1)
iload 101; // from last empty_loop
ifeq ENTRY02;
goto ENTRY03;
ENTRY02:
iinc 102, 1;
ENTRY03:
iinc 103, -1;
iload 102;
ldc 10001;
if_icmplt ENTRY02;
// var[103] == 0 // empty_loop (#2)
iload 103; // from last empty_loop
ifeq ENTRY04;
goto ENTRY05;
ENTRY04:
iinc 104, 1;
ENTRY05:
iinc 105, -1;
iload 104;
ldc 10001;
if_icmplt ENTRY04;
// var[105] == 0 // empty_loop (#3)
iload 105; // from last empty_loop
ifeq ENTRY06;
goto ENTRY07;
ENTRY06:
iinc 106, 1;
ENTRY07:
iinc 107, -1;
iload 106;
ldc 10001;
if_icmplt ENTRY06;
// var[107] == 0 // empty_loop (#4)
iload 107; // from last empty_loop
ifeq ENTRY08;
goto ENTRY09;
ENTRY08:
iinc 108, 1;
ENTRY09:
iinc 109, -1;
iload 108;
ldc 10001;
if_icmplt ENTRY08;
// var[109] == 0 // empty_loop (#5)
iload 109; // from last empty_loop
ifeq ENTRY10;
goto ENTRY11;
ENTRY10:
iinc 110, 1;
ENTRY11:
iinc 111, -1;
iload 110;
ldc 10001;
if_icmplt ENTRY10;
// var[111] == 0 // empty_loop (#6)
iload 111; // from last empty_loop
ifeq ENTRY12;
goto ENTRY13;
ENTRY12:
iinc 112, 1;
ENTRY13:
iinc 113, -1;
iload 112;
ldc 10001;
if_icmplt ENTRY12;
// var[113] == 0 // empty_loop (#7)
iload 113; // from last empty_loop
ifeq ENTRY14;
goto ENTRY15;
ENTRY14:
iinc 114, 1;
ENTRY15:
iinc 115, -1;
iload 114;
ldc 10001;
if_icmplt ENTRY14;
// var[115] == 0 // empty_loop (#8)
// final loop, removed after last empty_loop collapses
iload 115;
ifeq LEND;
iload_1;
ifeq ENTRY3;
goto ENTRY4;
ENTRY3:
iload_2;
ifeq LEND;
ENTRY4:
goto ENTRY3;
LEND:
return;
}
static Method test_015a:"(I)I"
stack 20 locals 40
{
// Irreducible loop that loses second entry already during parsing
// and later becomes counted loop
iconst_0;
istore 30;
iconst_1;
istore 31;
ldc 0;
ifeq ENTRY1;
goto ENTRY2; // removed during parsing
ENTRY1:
iinc 30, 1; // trip count
ENTRY2:
iload 31;
ldc 3; // compute pow(3,x)
imul;
istore 31;
iload 30;
iload 0;
if_icmplt ENTRY1;
LEND:
iload 31;
ireturn;
}
static Method test_015b:"(I)I"
stack 20 locals 40
{
// Similar as test_015a, but the irreducible loop only loses the
// second entry during loop-opts (empty_loop), and the now
// reducible loop does not become a CountedLoop any more.
iconst_0;
istore 30;
iconst_1;
istore 31;
// empty_loop
ldc 10001;
istore 20;
iconst_0;
istore 21;
EMPTY_LOOP:
iinc 20, -1;
iinc 21, 1;
iload 21;
ldc 10001;
if_icmplt EMPTY_LOOP;
// var[20] == 0 // empty_loop (#1)
iload 20;
ifeq ENTRY1;
goto ENTRY2; // removed by empty_loop
ENTRY1:
iinc 30, 1; // trip count
ENTRY2:
iload 31;
ldc 3; // compute pow(3,x)
imul;
istore 31;
iload 30;
iload 0;
if_icmplt ENTRY1;
LEND:
iload 31;
ireturn;
}
static Method test_016:"(III)V"
stack 200 locals 300
{
// Similar to test_014b.
// Same sequence of irreducible loops collapsing to
// empty_loops, collapsing and cascading to the next
// loop.
// In addition: each of the the loops in that sequence
// controls an entry to a final big irreducible loop,
// which slowly collapses, losing entry after entry.
iload_0;
ifeq LEND; // runtime check, avoid code below
// setting up all variables for the loops below
iconst_0;
istore 100;
ldc 10001;
istore 101;
iconst_0;
istore 102;
ldc 10001;
istore 103;
iconst_0;
istore 104;
ldc 10001;
istore 105;
iconst_0;
istore 106;
ldc 10001;
istore 107;
iconst_0;
istore 108;
ldc 10001;
istore 109;
iconst_0;
istore 110;
ldc 10001;
istore 111;
iconst_0;
istore 112;
ldc 10001;
istore 113;
iconst_0;
istore 114;
ldc 10001;
istore 115;
iconst_0; // collapse during parsing
ifeq ENTRY00;
goto ENTRY01;
ENTRY00:
iinc 100, 1;
ENTRY01:
iinc 101, -1;
iload 100;
ldc 10001;
if_icmplt ENTRY00;
// var[101] == 0 // empty_loop (#1)
iload 101; // from last empty_loop
ifeq ENTRY02;
goto ENTRY03;
ENTRY02:
iinc 102, 1;
ENTRY03:
iinc 103, -1;
iload 102;
ldc 10001;
if_icmplt ENTRY02;
// var[103] == 0 // empty_loop (#2)
iload 103; // from last empty_loop
ifeq ENTRY04;
goto ENTRY05;
ENTRY04:
iinc 104, 1;
ENTRY05:
iinc 105, -1;
iload 104;
ldc 10001;
if_icmplt ENTRY04;
// var[105] == 0 // empty_loop (#3)
iload 105; // from last empty_loop
ifeq ENTRY06;
goto ENTRY07;
ENTRY06:
iinc 106, 1;
ENTRY07:
iinc 107, -1;
iload 106;
ldc 10001;
if_icmplt ENTRY06;
// var[107] == 0 // empty_loop (#4)
iload 107; // from last empty_loop
ifeq ENTRY08;
goto ENTRY09;
ENTRY08:
iinc 108, 1;
ENTRY09:
iinc 109, -1;
iload 108;
ldc 10001;
if_icmplt ENTRY08;
// var[109] == 0 // empty_loop (#5)
iload 109; // from last empty_loop
ifeq ENTRY10;
goto ENTRY11;
ENTRY10:
iinc 110, 1;
ENTRY11:
iinc 111, -1;
iload 110;
ldc 10001;
if_icmplt ENTRY10;
// var[111] == 0 // empty_loop (#6)
iload 111; // from last empty_loop
ifeq ENTRY12;
goto ENTRY13;
ENTRY12:
iinc 112, 1;
ENTRY13:
iinc 113, -1;
iload 112;
ldc 10001;
if_icmplt ENTRY12;
// var[113] == 0 // empty_loop (#7)
iload 113; // from last empty_loop
ifeq ENTRY14;
goto ENTRY15;
ENTRY14:
iinc 114, 1;
ENTRY15:
iinc 115, -1;
iload 114;
ldc 10001;
if_icmplt ENTRY14;
// var[115] == 0 // empty_loop (#8)
// final loop, every empty_loop from above
// controls one of the entries
iconst_0;
istore 200;
iload 101;
ifne BOTTOM1;
iload 103;
ifne BOTTOM2;
iload 105;
ifne BOTTOM3;
iload 107;
ifne BOTTOM4;
iload 109;
ifne BOTTOM5;
iload 111;
ifne BOTTOM6;
iload 113;
ifne BOTTOM7;
iload 115;
ifeq LEND;
// finally cut off completely
// trigger irreducible loop removal
iload 1;
ifeq BOTTOM8;
goto BOTTOM0;
BOTTOM0:
iinc 200, 1;
BOTTOM1:
iinc 200, 2;
BOTTOM2:
iinc 200, 4;
BOTTOM3:
iinc 200, 8;
BOTTOM4:
iinc 200, 16;
BOTTOM5:
iinc 200, 32;
BOTTOM6:
iinc 200, 64;
BOTTOM7:
iinc 200, 128;
BOTTOM8:
iload 200;
ldc 30003;
if_icmpgt LEND;
goto BOTTOM1;
LEND:
return;
}
static Method test_017:"(III)V"
stack 20 locals 20
{
// Triggers partial_peel and strip-mining for a loop
// where the head was marked is_in_irreducible_loop
iload 2;
ifeq LEND; // skip code
iload 1;
ifgt L2;
L1:
nop;
L2:
iinc 1, 1;
iload 1;
ifgt L1;
iload 0;
ifne LEND;
goto L2;
LEND:
return;
}
static Method test_018:"(I)V"
stack 20 locals 20
{
// ciTypeFlow: infinite loop has no parent loop
iload_0;
ifeq LEND; // skip code
LOOP:
goto LOOP; // infinite loop
LEND:
return;
}
static Method test_019:"(IIII)V"
stack 20 locals 20
{
// may triggers split_flow_path, because of that aconst_null
iload_0;
ifeq LEND; // skip code
aconst_null; // this has a strange side-effect
goto LOOP3;
LOOP1:
nop;
LOOP2:
iload 1;
ifne LOOP1;
LOOP3:
iload 2;
ifge LOOP2;
LOOP4:
iload 3;
ifle LOOP1;
iconst_m1;
iflt LOOP2;
goto LOOP4;
LEND:
return;
}
static Method test_020:"(IIIII)V"
stack 20 locals 40
{
// Get infinite loop at some point that has no NeverBranch node
iload_0;
ifeq LEND; // skip
iconst_0;
istore 20;
LOOP1:
iload 1;
ifeq LOOP3;
LOOP2:
iconst_0;
ifne LEND;
LOOP3:
iload 20;
istore 30; // old
iload 2;
iflt LOOP4;
iconst_1;
istore 20; // overwrite new
iload 30;
iload 3;
if_icmpgt LOOP1;
goto LOOP3;
LOOP4:
iload 4;
iflt LOOP2;
goto LOOP4;
LEND:
return;
}
static Method test_021:"(IIIIII)V"
stack 20 locals 20
{
// Produces a graph where one node is originally located inside
// a reducible loop, but later that loop collapses, and exposes
// the node to the outerloop, which is irreducible.
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;
}
static Method test_022a:"(IIII)V"
stack 20 locals 10
{
// see test_022b for explanation
iload_0;
ifeq LEND;
aconst_null;
astore 9;
iconst_1;
ifeq ENTRY1; // eventually collapses
goto ENTRY2;
ENTRY1:
iconst_0;
ifeq LOOP;
ENTRY2:
iload 1;
ifge LOOP;
goto ENTRY1;
LOOP:
// head is split -> new irreducible loop
aload 9;
pop;
iconst_0;
iflt LOOP;
aconst_null;
astore 9;
iload 2;
ifeq LEND;
goto LOOP;
LEND:
return;
}
static Method test_022b:"(II)V"
stack 20 locals 20
{
// Triggered split_flow_path for a reducible loop that had multiple fall-in
// edges. The fall-in edges were split over two Phis/Regions, creating a new
// undetected irreducible loop. This only seems to happen when there are other
// irreducible loops present, as it changes the merge-order during parsing.
// If there are only reducible loops present, we merge the fall-in in a region
// prior to the loop-head, as far as I understand.
iload_0;
ifeq LEND; // skip
aconst_null;
astore 9;
iload 1;
ifeq OTHER;
LOOP:
iconst_0;
iflt LEND; // false - old exit?
aload 9;
pop;
iconst_0;
ifne LOOP; // false
goto LOOP;
OTHER:
iconst_m1;
ifeq ENTRY1; // false
goto ENTRY2;
ENTRY1:
iconst_0;
ifeq LOOP; // true
ENTRY2:
goto ENTRY1;
LEND:
return;
}
static Method test_023:"(I)V"
stack 20 locals 20
{
iload_0;
ifeq LEND;
iconst_0;
istore 7;
iconst_0;
ifne L4;
L2:
nop;
L4:
iload 7;
ifeq L12;
L12:
iconst_0;
ifeq L2;
goto L12;
LEND:
return;
}
static Method test_024_inline:"(I)I"
stack 20 locals 10
{
iload_0;
ldc 3;
irem;
ifeq SKIP; // if (v % 3 == 0)
// (v % 5)
iload_0;
ldc 5;
irem;
istore_0;
goto LEND;
SKIP:
// (v % 7)
iload_0;
ldc 7;
irem;
istore_0;
goto LEND;
LEND:
iload_0;
ireturn;
}
static Method test_024:"()I"
stack 20 locals 10
{
// Outer loop, irreducible inside, and inline call
// Test that regions in inline are also handled as
// they are nested in the irreducible loop
iconst_0;
istore 1; // i = 0
iconst_0;
istore 3; // x = 0
LOOP:
iconst_0;
istore 2; // j = 0
iload 1;
ldc 2;
irem;
ifeq ENTRY1; // if (i % 2 == 0)
goto ENTRY2;
ENTRY1:
iinc 2, 1; // j++
ENTRY2:
iload 2;
invokestatic Method test_024_inline:"(I)I";
iload 3;
iadd;
istore 3;
iload 2;
ldc 1000;
if_icmplt ENTRY1; // while (j < 1000)
iinc 1, 1; // i++
iload 1;
ldc 10000;
if_icmplt LOOP; // while (i < 10000)
LEND:
iload 3;
ireturn;
}
}