Skip to content

Commit 16ce05a

Browse files
committed
[GR-59503] Stricter checks for CFG and schedule validity
PullRequest: graal/19225
2 parents e38604e + 3d1f83a commit 16ce05a

File tree

4 files changed

+38
-16
lines changed

4 files changed

+38
-16
lines changed

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/cfg/ControlFlowGraph.java

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -55,6 +55,7 @@
5555
import jdk.graal.compiler.nodes.DeoptimizeNode;
5656
import jdk.graal.compiler.nodes.FixedNode;
5757
import jdk.graal.compiler.nodes.FixedWithNextNode;
58+
import jdk.graal.compiler.nodes.GraphState;
5859
import jdk.graal.compiler.nodes.LoopBeginNode;
5960
import jdk.graal.compiler.nodes.LoopEndNode;
6061
import jdk.graal.compiler.nodes.LoopExitNode;
@@ -333,6 +334,14 @@ private static ControlFlowGraph lookupCached(StructuredGraph graph, boolean modi
333334
return lastCFG;
334335
}
335336
}
337+
if (graph.getLastSchedule() != null && !graph.isAfterStage(GraphState.StageFlag.FINAL_SCHEDULE)) {
338+
/*
339+
* There is no up to date CFG. If there is a current schedule, its CFG must also be out
340+
* of date. So invalidate the schedule. The only exception is during cleanup phases
341+
* after final scheduling, where we don't want to destroy that schedule.
342+
*/
343+
graph.clearLastSchedule();
344+
}
336345
return null;
337346
}
338347

@@ -398,7 +407,7 @@ public EconomicMap<LoopBeginNode, LoopFrequencyData> getLocalLoopFrequencyData()
398407
* will return the updated value. This is useful for phases to record temporary effects of
399408
* transformations on loop frequencies, without having to recompute a CFG.
400409
* </p>
401-
*
410+
* <p>
402411
* The updated frequency is a cached value local to this CFG. It is <em>not</em> persisted in
403412
* the IR graph. Newly computed {@link ControlFlowGraph} instances will recompute a frequency
404413
* from loop exit probabilities, they will not see this locally cached value. Persistent changes
@@ -688,7 +697,7 @@ private boolean verifyRPOInnerLoopsFirst() {
688697
* it is not an endless loop) {@link LoopExitNode}. For every path exiting a loop a
689698
* {@link LoopExitNode} is required. There is one exception to that rule:
690699
* {@link DeoptimizeNode}.
691-
*
700+
* <p>
692701
* Graal does not mandate that a {@link DeoptimizeNode} is preceded by a {@link LoopExitNode}.
693702
* In the following example
694703
*
@@ -699,7 +708,7 @@ private boolean verifyRPOInnerLoopsFirst() {
699708
* }
700709
* }
701710
* </pre>
702-
*
711+
* <p>
703712
* the IR does not have a preceding loop exit node before the deopt node. However, for regular
704713
* control flow sinks (returns, throws, etc) like in the following example
705714
*
@@ -710,9 +719,9 @@ private boolean verifyRPOInnerLoopsFirst() {
710719
* }
711720
* }
712721
* </pre>
713-
*
722+
* <p>
714723
* Graal IR creates a {@link LoopExitNode} before the {@link ReturnNode}.
715-
*
724+
* <p>
716725
* Because of the "imprecision" in the definition a regular basic block exiting a loop and a
717726
* "dominator tree" loop exit are not necessarily the same. If a path after a control flow split
718727
* unconditionally flows into a deopt it is a "dominator loop exit" while a regular loop exit
@@ -810,9 +819,9 @@ private boolean rpoInnerLoopsFirst(Consumer<HIRBlock> perBasicBlockOption, Consu
810819
/**
811820
* Determine if sequential predecessor blocks of this block in a not-fully-canonicalized graph
812821
* exit a loop.
813-
*
822+
* <p>
814823
* Example: Sequential basic block: loop exit -> invoke -> killing begin -> loopend/exit
815-
*
824+
* <p>
816825
* These cases cause problems in the {@link #verifyRPOInnerLoopsFirst()} loop verification of
817826
* inner loop blocks because the granularity of loop ends and exits are not on block boundaries:
818827
* a loop exit block can also be a loop end to an outer loop, which makes verification that the

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/loop/LoopsData.java

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -27,17 +27,19 @@
2727
import java.util.ArrayList;
2828
import java.util.List;
2929

30-
import jdk.graal.compiler.nodes.LoopBeginNode;
31-
import jdk.graal.compiler.nodes.StructuredGraph;
32-
import jdk.graal.compiler.nodes.ValueNode;
33-
import jdk.graal.compiler.nodes.cfg.ControlFlowGraph;
34-
import jdk.graal.compiler.nodes.cfg.HIRBlock;
3530
import org.graalvm.collections.EconomicMap;
3631
import org.graalvm.collections.EconomicSet;
3732
import org.graalvm.collections.Equivalence;
33+
3834
import jdk.graal.compiler.core.common.cfg.CFGLoop;
3935
import jdk.graal.compiler.core.common.util.ReversedList;
4036
import jdk.graal.compiler.debug.DebugContext;
37+
import jdk.graal.compiler.nodes.GraphState;
38+
import jdk.graal.compiler.nodes.LoopBeginNode;
39+
import jdk.graal.compiler.nodes.StructuredGraph;
40+
import jdk.graal.compiler.nodes.ValueNode;
41+
import jdk.graal.compiler.nodes.cfg.ControlFlowGraph;
42+
import jdk.graal.compiler.nodes.cfg.HIRBlock;
4143

4244
/**
4345
* A data structure representing all the information about all loops in the given graph. Data about
@@ -86,7 +88,9 @@ protected LoopsData(final StructuredGraph graph, ControlFlowGraph preComputedCFG
8688
DebugContext debug = graph.getDebug();
8789
if (preComputedCFG == null) {
8890
try (DebugContext.Scope s = debug.scope("ControlFlowGraph")) {
89-
this.cfg = ControlFlowGraph.newBuilder(graph).connectBlocks(true).computeLoops(true).computeDominators(true).computePostdominators(true).computeFrequency(true).build();
91+
boolean backendBlocks = graph.isAfterStage(GraphState.StageFlag.FINAL_SCHEDULE);
92+
this.cfg = ControlFlowGraph.newBuilder(graph).connectBlocks(true).backendBlocks(backendBlocks).computeLoops(true).computeDominators(true).computePostdominators(true).computeFrequency(
93+
true).build();
9094
} catch (Throwable e) {
9195
throw debug.handle(e);
9296
}

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/common/ConditionalEliminationPhase.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -195,7 +195,12 @@ protected void run(StructuredGraph graph, CoreProviders context) {
195195
cfg.visitDominatorTree(new MoveGuardsUpwards(), deferLoopExits);
196196
}
197197
try (DebugContext.Scope scheduleScope = graph.getDebug().scope(SchedulePhase.class)) {
198+
if (!graph.isLastCFGValid()) {
199+
cfg = null;
200+
}
198201
SchedulePhase.run(graph, SchedulePhase.SchedulingStrategy.EARLIEST_WITH_GUARD_ORDER, cfg, context, false);
202+
cfg = graph.getLastCFG();
203+
cfg.computePostdominators();
199204
} catch (Throwable t) {
200205
throw graph.getDebug().handle(t);
201206
}

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/phases/schedule/SchedulePhase.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,10 @@ public Instance(ControlFlowGraph cfg, boolean supportsImplicitNullChecks) {
266266
public void run(StructuredGraph graph, SchedulingStrategy selectedStrategy, boolean immutableGraph) {
267267
if (this.cfg == null) {
268268
this.cfg = ControlFlowGraph.computeForSchedule(graph);
269+
} else {
270+
GraalError.guarantee(this.cfg == graph.getLastCFG() && graph.isLastCFGValid(),
271+
"Cannot compute schedule for stale CFG; given: %s, graph's last CFG is %s, is valid: %s.",
272+
this.cfg, graph.getLastCFG(), graph.isLastCFGValid());
269273
}
270274

271275
NodeMap<HIRBlock> currentNodeMap = graph.createNodeMap();

0 commit comments

Comments
 (0)