/* * 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 "":"()V" stack 2 locals 1 { aload_0; invokespecial Method java/lang/Object."":"()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; } }