mirror of
https://github.com/openjdk/jdk.git
synced 2026-01-28 12:09:14 +00:00
8373355: C2: CompileCommand PrintIdealPhase should also print nodes that are not "reachable from below"
Reviewed-by: rcastanedalo, mchevalier, bmaillard
This commit is contained in:
parent
78c2d57259
commit
8402891889
@ -595,7 +595,9 @@ void Compile::print_ideal_ir(const char* phase_name) {
|
||||
if (_output == nullptr) {
|
||||
ss.print_cr("AFTER: %s", phase_name);
|
||||
// Print out all nodes in ascending order of index.
|
||||
root()->dump_bfs(MaxNodeLimit, nullptr, "+S$", &ss);
|
||||
// It is important that we traverse both inputs and outputs of nodes,
|
||||
// so that we reach all nodes that are connected to Root.
|
||||
root()->dump_bfs(MaxNodeLimit, nullptr, "-+S$", &ss);
|
||||
} else {
|
||||
// Dump the node blockwise if we have a scheduling
|
||||
_output->print_scheduling(&ss);
|
||||
|
||||
@ -63,17 +63,29 @@ public class ModDNodeTests {
|
||||
Asserts.assertEQ(unusedResultAfterLoopOpt3(1.1d, 2.2d), 0.d);
|
||||
}
|
||||
|
||||
// Note: we used to check for ConD nodes in the IR. But that is a bit brittle:
|
||||
// Constant nodes can appear during IR transformations, and then lose their outputs.
|
||||
// During IGNV, the constants stay in the graph even if they lose the inputs. But
|
||||
// CCP cleans them out because they are not in the useful set. So for now, we do not
|
||||
// rely on any constant counting, just on counting the operation nodes.
|
||||
|
||||
@Test
|
||||
@IR(failOn = {"drem"}, phase = CompilePhase.BEFORE_MATCHING)
|
||||
@IR(counts = {IRNode.CON_D, "1"})
|
||||
@IR(counts = {IRNode.MOD_D, "2"},
|
||||
phase = CompilePhase.AFTER_PARSING)
|
||||
@IR(counts = {".*CallLeaf.*drem.*", "0"},
|
||||
phase = CompilePhase.BEFORE_MATCHING)
|
||||
public double constant() {
|
||||
// All constants available during parsing
|
||||
return q % 72.0d % 30.0d;
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(failOn = {"drem"}, phase = CompilePhase.BEFORE_MATCHING)
|
||||
@IR(counts = {IRNode.CON_D, "1"})
|
||||
@IR(counts = {IRNode.MOD_D, "1"},
|
||||
phase = CompilePhase.AFTER_PARSING)
|
||||
@IR(counts = {IRNode.MOD_D, "1"},
|
||||
phase = CompilePhase.PHASEIDEALLOOP1) // Only constant fold after some loop opts
|
||||
@IR(counts = {".*CallLeaf.*drem.*", "0"},
|
||||
phase = CompilePhase.BEFORE_MATCHING)
|
||||
public double alsoConstant() {
|
||||
// Make sure value is only available after second loop opts round
|
||||
double val = 0;
|
||||
@ -86,8 +98,12 @@ public class ModDNodeTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(failOn = {"drem"}, phase = CompilePhase.BEFORE_MATCHING)
|
||||
@IR(counts = {IRNode.CON_D, "1"})
|
||||
@IR(counts = {IRNode.MOD_D, "2"},
|
||||
phase = CompilePhase.AFTER_PARSING)
|
||||
@IR(counts = {IRNode.MOD_D, "2"},
|
||||
phase = CompilePhase.PHASEIDEALLOOP1) // Only constant fold after some loop opts
|
||||
@IR(counts = {".*CallLeaf.*drem.*", "0"},
|
||||
phase = CompilePhase.BEFORE_MATCHING)
|
||||
public double nanLeftConstant() {
|
||||
// Make sure value is only available after second loop opts round
|
||||
double val = 134.18d;
|
||||
@ -100,8 +116,12 @@ public class ModDNodeTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(failOn = {"drem"}, phase = CompilePhase.BEFORE_MATCHING)
|
||||
@IR(counts = {IRNode.CON_D, "1"})
|
||||
@IR(counts = {IRNode.MOD_D, "2"},
|
||||
phase = CompilePhase.AFTER_PARSING)
|
||||
@IR(counts = {IRNode.MOD_D, "2"},
|
||||
phase = CompilePhase.PHASEIDEALLOOP1) // Only constant fold after some loop opts
|
||||
@IR(counts = {".*CallLeaf.*drem.*", "0"},
|
||||
phase = CompilePhase.BEFORE_MATCHING)
|
||||
public double nanRightConstant() {
|
||||
// Make sure value is only available after second loop opts round
|
||||
double val = 134.18d;
|
||||
@ -114,29 +134,41 @@ public class ModDNodeTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(counts = {"drem", "1"}, phase = CompilePhase.BEFORE_MATCHING)
|
||||
@IR(counts = {IRNode.CON_D, "1"})
|
||||
@IR(counts = {IRNode.MOD_D, "1"},
|
||||
phase = CompilePhase.AFTER_PARSING)
|
||||
@IR(counts = {".*CallLeaf.*drem.*", "1"},
|
||||
phase = CompilePhase.BEFORE_MATCHING) // no constant folding
|
||||
public double notConstant(double x) {
|
||||
return x % 32.0d;
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(counts = {"drem", "2"}, phase = CompilePhase.BEFORE_MATCHING)
|
||||
@IR(counts = {IRNode.CON_D, "1"})
|
||||
@IR(counts = {IRNode.MOD_D, "2"},
|
||||
phase = CompilePhase.AFTER_PARSING)
|
||||
@IR(counts = {".*CallLeaf.*drem.*", "2"},
|
||||
phase = CompilePhase.BEFORE_MATCHING) // no constant folding
|
||||
public double veryNotConstant(double x, double y) {
|
||||
return x % 32.0d % y;
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(failOn = IRNode.MOD_D, phase = CompilePhase.ITER_GVN1)
|
||||
@IR(counts = {IRNode.MOD_D, "1"}, phase = CompilePhase.AFTER_PARSING)
|
||||
@IR(counts = {IRNode.MOD_D, "1"},
|
||||
phase = CompilePhase.AFTER_PARSING)
|
||||
@IR(counts = {IRNode.MOD_D, "0"},
|
||||
phase = CompilePhase.ITER_GVN1) // IGVN removes unused nodes
|
||||
@IR(counts = {".*CallLeaf.*drem.*", "0"},
|
||||
phase = CompilePhase.BEFORE_MATCHING)
|
||||
public void unusedResult(double x, double y) {
|
||||
double unused = x % y;
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(failOn = IRNode.MOD_D, phase = CompilePhase.ITER_GVN1)
|
||||
@IR(counts = {IRNode.MOD_D, "1"}, phase = CompilePhase.AFTER_PARSING)
|
||||
@IR(counts = {IRNode.MOD_D, "1"},
|
||||
phase = CompilePhase.AFTER_PARSING)
|
||||
@IR(counts = {IRNode.MOD_D, "0"},
|
||||
phase = CompilePhase.ITER_GVN1) // IGVN removes unused nodes
|
||||
@IR(counts = {".*CallLeaf.*drem.*", "0"},
|
||||
phase = CompilePhase.BEFORE_MATCHING)
|
||||
public void repeatedlyUnused(double x, double y) {
|
||||
double unused = 1.d;
|
||||
for (int i = 0; i < 100_000; i++) {
|
||||
@ -149,8 +181,14 @@ public class ModDNodeTests {
|
||||
// and thus a different execution path. In unusedResultAfterLoopOpt1 the modulo is
|
||||
// used in the traps of the parse predicates. In unusedResultAfterLoopOpt2, it is not.
|
||||
@Test
|
||||
@IR(counts = {IRNode.MOD_D, "1"}, phase = CompilePhase.ITER_GVN2)
|
||||
@IR(failOn = IRNode.MOD_D, phase = CompilePhase.BEFORE_MACRO_EXPANSION)
|
||||
@IR(counts = {IRNode.MOD_D, "1"},
|
||||
phase = CompilePhase.AFTER_PARSING)
|
||||
@IR(counts = {IRNode.MOD_D, "1"},
|
||||
phase = CompilePhase.ITER_GVN2)
|
||||
@IR(counts = {IRNode.MOD_D, "0"},
|
||||
phase = CompilePhase.BEFORE_MACRO_EXPANSION)
|
||||
@IR(counts = {".*CallLeaf.*drem.*", "0"},
|
||||
phase = CompilePhase.BEFORE_MATCHING)
|
||||
public double unusedResultAfterLoopOpt1(double x, double y) {
|
||||
double unused = x % y;
|
||||
|
||||
@ -168,8 +206,14 @@ public class ModDNodeTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(counts = {IRNode.MOD_D, "1"}, phase = CompilePhase.AFTER_CLOOPS)
|
||||
@IR(failOn = IRNode.MOD_D, phase = CompilePhase.PHASEIDEALLOOP1)
|
||||
@IR(counts = {IRNode.MOD_D, "1"},
|
||||
phase = CompilePhase.AFTER_PARSING)
|
||||
@IR(counts = {IRNode.MOD_D, "1"},
|
||||
phase = CompilePhase.AFTER_CLOOPS)
|
||||
@IR(counts = {IRNode.MOD_D, "0"},
|
||||
phase = CompilePhase.PHASEIDEALLOOP1)
|
||||
@IR(counts = {".*CallLeaf.*drem.*", "0"},
|
||||
phase = CompilePhase.BEFORE_MATCHING)
|
||||
public double unusedResultAfterLoopOpt2(double x, double y) {
|
||||
int a = 77;
|
||||
int b = 0;
|
||||
@ -187,8 +231,14 @@ public class ModDNodeTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(counts = {IRNode.MOD_D, "2"}, phase = CompilePhase.AFTER_CLOOPS)
|
||||
@IR(failOn = IRNode.MOD_D, phase = CompilePhase.PHASEIDEALLOOP1)
|
||||
@IR(counts = {IRNode.MOD_D, "3"},
|
||||
phase = CompilePhase.AFTER_PARSING)
|
||||
@IR(counts = {IRNode.MOD_D, "2"},
|
||||
phase = CompilePhase.AFTER_CLOOPS) // drop the useless one
|
||||
@IR(counts = {IRNode.MOD_D, "0"},
|
||||
phase = CompilePhase.PHASEIDEALLOOP1) // drop the rest
|
||||
@IR(counts = {".*CallLeaf.*drem.*", "0"},
|
||||
phase = CompilePhase.BEFORE_MATCHING)
|
||||
public double unusedResultAfterLoopOpt3(double x, double y) {
|
||||
double unused = x % y;
|
||||
|
||||
|
||||
@ -63,17 +63,29 @@ public class ModFNodeTests {
|
||||
Asserts.assertEQ(unusedResultAfterLoopOpt3(1.1f, 2.2f), 0.f);
|
||||
}
|
||||
|
||||
// Note: we used to check for ConF nodes in the IR. But that is a bit brittle:
|
||||
// Constant nodes can appear during IR transformations, and then lose their outputs.
|
||||
// During IGNV, the constants stay in the graph even if they lose the inputs. But
|
||||
// CCP cleans them out because they are not in the useful set. So for now, we do not
|
||||
// rely on any constant counting, just on counting the operation nodes.
|
||||
|
||||
@Test
|
||||
@IR(failOn = {"frem"}, phase = CompilePhase.BEFORE_MATCHING)
|
||||
@IR(counts = {IRNode.CON_F, "1"})
|
||||
@IR(counts = {IRNode.MOD_F, "2"},
|
||||
phase = CompilePhase.AFTER_PARSING)
|
||||
@IR(counts = {".*CallLeaf.*frem.*", "0"},
|
||||
phase = CompilePhase.BEFORE_MATCHING)
|
||||
public float constant() {
|
||||
// All constants available during parsing
|
||||
return q % 72.0f % 30.0f;
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(failOn = {"frem"}, phase = CompilePhase.BEFORE_MATCHING)
|
||||
@IR(counts = {IRNode.CON_F, "1"})
|
||||
@IR(counts = {IRNode.MOD_F, "1"},
|
||||
phase = CompilePhase.AFTER_PARSING)
|
||||
@IR(counts = {IRNode.MOD_F, "1"},
|
||||
phase = CompilePhase.PHASEIDEALLOOP1) // Only constant fold after some loop opts
|
||||
@IR(counts = {".*CallLeaf.*frem.*", "0"},
|
||||
phase = CompilePhase.BEFORE_MATCHING)
|
||||
public float alsoConstant() {
|
||||
// Make sure value is only available after second loop opts round
|
||||
float val = 0;
|
||||
@ -86,8 +98,12 @@ public class ModFNodeTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(failOn = {"frem"}, phase = CompilePhase.BEFORE_MATCHING)
|
||||
@IR(counts = {IRNode.CON_F, "1"})
|
||||
@IR(counts = {IRNode.MOD_F, "2"},
|
||||
phase = CompilePhase.AFTER_PARSING)
|
||||
@IR(counts = {IRNode.MOD_F, "2"},
|
||||
phase = CompilePhase.PHASEIDEALLOOP1) // Only constant fold after some loop opts
|
||||
@IR(counts = {".*CallLeaf.*frem.*", "0"},
|
||||
phase = CompilePhase.BEFORE_MATCHING)
|
||||
public float nanLeftConstant() {
|
||||
// Make sure value is only available after second loop opts round
|
||||
float val = 134.18f;
|
||||
@ -100,8 +116,12 @@ public class ModFNodeTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(failOn = {"frem"}, phase = CompilePhase.BEFORE_MATCHING)
|
||||
@IR(counts = {IRNode.CON_F, "1"})
|
||||
@IR(counts = {IRNode.MOD_F, "2"},
|
||||
phase = CompilePhase.AFTER_PARSING)
|
||||
@IR(counts = {IRNode.MOD_F, "2"},
|
||||
phase = CompilePhase.PHASEIDEALLOOP1) // Only constant fold after some loop opts
|
||||
@IR(counts = {".*CallLeaf.*frem.*", "0"},
|
||||
phase = CompilePhase.BEFORE_MATCHING)
|
||||
public float nanRightConstant() {
|
||||
// Make sure value is only available after second loop opts round
|
||||
float val = 134.18f;
|
||||
@ -114,29 +134,41 @@ public class ModFNodeTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(counts = {"frem", "1"}, phase = CompilePhase.BEFORE_MATCHING)
|
||||
@IR(counts = {IRNode.CON_F, "1"})
|
||||
@IR(counts = {IRNode.MOD_F, "1"},
|
||||
phase = CompilePhase.AFTER_PARSING)
|
||||
@IR(counts = {".*CallLeaf.*frem.*", "1"},
|
||||
phase = CompilePhase.BEFORE_MATCHING) // no constant folding
|
||||
public float notConstant(float x) {
|
||||
return x % 32.0f;
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(counts = {"frem", "2"}, phase = CompilePhase.BEFORE_MATCHING)
|
||||
@IR(counts = {IRNode.CON_F, "1"})
|
||||
@IR(counts = {IRNode.MOD_F, "2"},
|
||||
phase = CompilePhase.AFTER_PARSING)
|
||||
@IR(counts = {".*CallLeaf.*frem.*", "2"},
|
||||
phase = CompilePhase.BEFORE_MATCHING) // no constant folding
|
||||
public float veryNotConstant(float x, float y) {
|
||||
return x % 32.0f % y;
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(failOn = IRNode.MOD_F, phase = CompilePhase.ITER_GVN1)
|
||||
@IR(counts = {IRNode.MOD_F, "1"}, phase = CompilePhase.AFTER_PARSING)
|
||||
@IR(counts = {IRNode.MOD_F, "1"},
|
||||
phase = CompilePhase.AFTER_PARSING)
|
||||
@IR(counts = {IRNode.MOD_F, "0"},
|
||||
phase = CompilePhase.ITER_GVN1) // IGVN removes unused nodes
|
||||
@IR(counts = {".*CallLeaf.*frem.*", "0"},
|
||||
phase = CompilePhase.BEFORE_MATCHING)
|
||||
public void unusedResult(float x, float y) {
|
||||
float unused = x % y;
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(failOn = IRNode.MOD_F, phase = CompilePhase.ITER_GVN1)
|
||||
@IR(counts = {IRNode.MOD_F, "1"}, phase = CompilePhase.AFTER_PARSING)
|
||||
@IR(counts = {IRNode.MOD_F, "1"},
|
||||
phase = CompilePhase.AFTER_PARSING)
|
||||
@IR(counts = {IRNode.MOD_F, "0"},
|
||||
phase = CompilePhase.ITER_GVN1) // IGVN removes unused nodes
|
||||
@IR(counts = {".*CallLeaf.*frem.*", "0"},
|
||||
phase = CompilePhase.BEFORE_MATCHING)
|
||||
public void repeatedlyUnused(float x, float y) {
|
||||
float unused = 1.f;
|
||||
for (int i = 0; i < 100_000; i++) {
|
||||
@ -149,8 +181,14 @@ public class ModFNodeTests {
|
||||
// and thus a different execution path. In unusedResultAfterLoopOpt1 the modulo is
|
||||
// used in the traps of the parse predicates. In unusedResultAfterLoopOpt2, it is not.
|
||||
@Test
|
||||
@IR(counts = {IRNode.MOD_F, "1"}, phase = CompilePhase.ITER_GVN2)
|
||||
@IR(failOn = IRNode.MOD_F, phase = CompilePhase.BEFORE_MACRO_EXPANSION)
|
||||
@IR(counts = {IRNode.MOD_F, "1"},
|
||||
phase = CompilePhase.AFTER_PARSING)
|
||||
@IR(counts = {IRNode.MOD_F, "1"},
|
||||
phase = CompilePhase.ITER_GVN2)
|
||||
@IR(counts = {IRNode.MOD_F, "0"},
|
||||
phase = CompilePhase.BEFORE_MACRO_EXPANSION)
|
||||
@IR(counts = {".*CallLeaf.*frem.*", "0"},
|
||||
phase = CompilePhase.BEFORE_MATCHING)
|
||||
public float unusedResultAfterLoopOpt1(float x, float y) {
|
||||
float unused = x % y;
|
||||
|
||||
@ -168,8 +206,14 @@ public class ModFNodeTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(counts = {IRNode.MOD_F, "1"}, phase = CompilePhase.AFTER_CLOOPS)
|
||||
@IR(failOn = IRNode.MOD_F, phase = CompilePhase.PHASEIDEALLOOP1)
|
||||
@IR(counts = {IRNode.MOD_F, "1"},
|
||||
phase = CompilePhase.AFTER_PARSING)
|
||||
@IR(counts = {IRNode.MOD_F, "1"},
|
||||
phase = CompilePhase.AFTER_CLOOPS)
|
||||
@IR(counts = {IRNode.MOD_F, "0"},
|
||||
phase = CompilePhase.PHASEIDEALLOOP1)
|
||||
@IR(counts = {".*CallLeaf.*frem.*", "0"},
|
||||
phase = CompilePhase.BEFORE_MATCHING)
|
||||
public float unusedResultAfterLoopOpt2(float x, float y) {
|
||||
int a = 77;
|
||||
int b = 0;
|
||||
@ -187,8 +231,14 @@ public class ModFNodeTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(counts = {IRNode.MOD_F, "2"}, phase = CompilePhase.AFTER_CLOOPS)
|
||||
@IR(failOn = IRNode.MOD_F, phase = CompilePhase.PHASEIDEALLOOP1)
|
||||
@IR(counts = {IRNode.MOD_F, "3"},
|
||||
phase = CompilePhase.AFTER_PARSING)
|
||||
@IR(counts = {IRNode.MOD_F, "2"},
|
||||
phase = CompilePhase.AFTER_CLOOPS) // drop the useless one
|
||||
@IR(counts = {IRNode.MOD_F, "0"},
|
||||
phase = CompilePhase.PHASEIDEALLOOP1) // drop the rest
|
||||
@IR(counts = {".*CallLeaf.*frem.*", "0"},
|
||||
phase = CompilePhase.BEFORE_MATCHING)
|
||||
public float unusedResultAfterLoopOpt3(float x, float y) {
|
||||
float unused = x % y;
|
||||
|
||||
|
||||
@ -690,16 +690,6 @@ public class IRNode {
|
||||
beforeMatchingNameRegex(CON_L, "ConL");
|
||||
}
|
||||
|
||||
public static final String CON_D = PREFIX + "CON_D" + POSTFIX;
|
||||
static {
|
||||
beforeMatchingNameRegex(CON_D, "ConD");
|
||||
}
|
||||
|
||||
public static final String CON_F = PREFIX + "CON_F" + POSTFIX;
|
||||
static {
|
||||
beforeMatchingNameRegex(CON_F, "ConF");
|
||||
}
|
||||
|
||||
public static final String COUNTED_LOOP = PREFIX + "COUNTED_LOOP" + POSTFIX;
|
||||
static {
|
||||
String regex = START + "CountedLoop\\b" + MID + END;
|
||||
|
||||
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2025, 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.
|
||||
*/
|
||||
|
||||
package ir_framework.tests;
|
||||
|
||||
import compiler.lib.ir_framework.*;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8373355
|
||||
* @summary Test that IR matching happens on the whole graph, not just nodes
|
||||
* that can be found by traversing up from the Root.
|
||||
* @library /test/lib /
|
||||
* @run main ${test.main.class}
|
||||
*/
|
||||
|
||||
public class TestIRFindFromAbove {
|
||||
public static boolean flag = false;
|
||||
public static int fld = 0;
|
||||
|
||||
public static void main(String[] args) {
|
||||
TestFramework.run();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Warmup(0)
|
||||
// Simulate Xcomp with no warmup: ensure the flag branch is not an unstable if
|
||||
// but that we compile the infinite loop.
|
||||
@IR(counts = {IRNode.LOAD_I, "1", IRNode.STORE_I, "1", ".*NeverBranch.*", "0"},
|
||||
phase = CompilePhase.ITER_GVN1)
|
||||
@IR(counts = {IRNode.LOAD_I, "1", IRNode.STORE_I, "1", ".*NeverBranch.*", "1"},
|
||||
phase = CompilePhase.PHASEIDEALLOOP1)
|
||||
public static void test() {
|
||||
if (flag) {
|
||||
// This loop has no exit. So it is at first not connected down to Root.
|
||||
while (true) {
|
||||
// During PHASEIDEALLOOP1, we insert a NeverBranch here, with a fake
|
||||
// exit, that connects the loop down to Root.
|
||||
fld++; // LoadI and StoreI
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user