|
85 | 85 | import org.graalvm.compiler.nodes.calc.IntegerEqualsNode;
|
86 | 86 | import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
|
87 | 87 | import org.graalvm.compiler.nodes.cfg.HIRBlock;
|
| 88 | +import org.graalvm.compiler.nodes.extended.CaptureStateBeginNode; |
88 | 89 | import org.graalvm.compiler.nodes.extended.GuardingNode;
|
89 | 90 | import org.graalvm.compiler.nodes.extended.IntegerSwitchNode;
|
90 | 91 | import org.graalvm.compiler.nodes.extended.LoadHubNode;
|
@@ -226,11 +227,46 @@ public static class MoveGuardsUpwards implements ControlFlowGraph.RecursiveVisit
|
226 | 227 |
|
227 | 228 | HIRBlock anchorBlock;
|
228 | 229 |
|
| 230 | + /** |
| 231 | + * Guards cannot be moved above CaptureStateBeginNodes in order to ensure deoptimizations |
| 232 | + * are always attached to valid FrameStates. |
| 233 | + */ |
| 234 | + private static boolean disallowUpwardGuardMovement(HIRBlock b) { |
| 235 | + return b.getBeginNode() instanceof CaptureStateBeginNode; |
| 236 | + } |
| 237 | + |
229 | 238 | @Override
|
230 | 239 | @SuppressWarnings("try")
|
231 | 240 | public HIRBlock enter(HIRBlock b) {
|
232 | 241 | HIRBlock oldAnchorBlock = anchorBlock;
|
233 |
| - if (b.getDominator() == null || b.getDominator().getPostdominator() != b) { |
| 242 | + /* |
| 243 | + * The goal of this pass is to move guards upward while not introducing the guards on |
| 244 | + * new paths. At all points the anchorBlock must set so the following two invariants |
| 245 | + * hold: |
| 246 | + * |
| 247 | + * (1) The anchorBlock dominates the current block. |
| 248 | + * |
| 249 | + * (2) The current block post-dominates the anchorBlock. |
| 250 | + * |
| 251 | + * Note blocks are traversed in dominator tree order. |
| 252 | + * |
| 253 | + * anchorBlock must be set to the current block if: |
| 254 | + * |
| 255 | + * (1) The current block does not have a dominator (i.e., this is the start of a new |
| 256 | + * dominator tree walk). |
| 257 | + * |
| 258 | + * (2) The immediate dominator of current block is not post-dominated by this block. Due |
| 259 | + * to using a dominator tree traversal, this is equivalent to ensuring the current block |
| 260 | + * post-dominates the anchorBlock. |
| 261 | + * |
| 262 | + * (3) Guards are not allowed to move above this block. The can happen when dominator |
| 263 | + * blocks can have invalid FrameStates, such as when the block start is a |
| 264 | + * CaptureStateBeginNode. |
| 265 | + */ |
| 266 | + boolean updateAnchorBlock = b.getDominator() == null || |
| 267 | + b.getDominator().getPostdominator() != b || |
| 268 | + disallowUpwardGuardMovement(b); |
| 269 | + if (updateAnchorBlock) { |
234 | 270 | // New anchor.
|
235 | 271 | anchorBlock = b;
|
236 | 272 | }
|
@@ -271,52 +307,51 @@ public HIRBlock enter(HIRBlock b) {
|
271 | 307 | * successors are loop exits, even of potentially different loops. Thus, we need
|
272 | 308 | * to ensure we see all possible loop exits involved for all loops.
|
273 | 309 | */
|
274 |
| - LoopExitNode trueSuccLex = trueSuccessor instanceof LoopExitNode ? (LoopExitNode) trueSuccessor : null; |
275 |
| - LoopExitNode falseSuccLex = falseSuccessor instanceof LoopExitNode ? (LoopExitNode) falseSuccessor : null; |
276 | 310 | EconomicSet<LoopExitNode> allLoopsAllExits = null;
|
277 |
| - if (trueSuccLex != null) { |
| 311 | + if (trueSuccessor instanceof LoopExitNode successor) { |
278 | 312 | if (allLoopsAllExits == null) {
|
279 | 313 | allLoopsAllExits = EconomicSet.create();
|
280 | 314 | }
|
281 |
| - allLoopsAllExits.addAll(trueSuccLex.loopBegin().loopExits()); |
282 |
| - allLoopsAllExits.remove(trueSuccLex); |
| 315 | + allLoopsAllExits.addAll(successor.loopBegin().loopExits()); |
| 316 | + allLoopsAllExits.remove(successor); |
283 | 317 | }
|
284 |
| - if (falseSuccLex != null) { |
| 318 | + if (falseSuccessor instanceof LoopExitNode successor) { |
285 | 319 | if (allLoopsAllExits == null) {
|
286 | 320 | allLoopsAllExits = EconomicSet.create();
|
287 | 321 | }
|
288 |
| - allLoopsAllExits.addAll(falseSuccLex.loopBegin().loopExits()); |
289 |
| - allLoopsAllExits.remove(falseSuccLex); |
| 322 | + allLoopsAllExits.addAll(successor.loopBegin().loopExits()); |
| 323 | + allLoopsAllExits.remove(successor); |
290 | 324 | }
|
291 | 325 | if (allLoopsAllExits == null || allLoopsAllExits.isEmpty()) {
|
292 |
| - for (GuardNode guard : falseSuccessor.guards().snapshot()) { |
293 |
| - GuardNode otherGuard = trueGuards.get(guard.getCondition()); |
294 |
| - if (otherGuard != null && guard.isNegated() == otherGuard.isNegated()) { |
295 |
| - Speculation speculation = otherGuard.getSpeculation(); |
| 326 | + for (GuardNode falseGuard : falseSuccessor.guards().snapshot()) { |
| 327 | + GuardNode trueGuard = trueGuards.get(falseGuard.getCondition()); |
| 328 | + if (trueGuard != null && falseGuard.isNegated() == trueGuard.isNegated()) { |
| 329 | + Speculation speculation = trueGuard.getSpeculation(); |
296 | 330 | if (speculation == null) {
|
297 |
| - speculation = guard.getSpeculation(); |
298 |
| - } else if (guard.getSpeculation() != null && guard.getSpeculation() != speculation) { |
| 331 | + speculation = falseGuard.getSpeculation(); |
| 332 | + } else if (falseGuard.getSpeculation() != null && falseGuard.getSpeculation() != speculation) { |
299 | 333 | // Cannot optimize due to different speculations.
|
300 | 334 | continue;
|
301 | 335 | }
|
302 |
| - try (DebugCloseable closeable = guard.withNodeSourcePosition()) { |
303 |
| - StructuredGraph graph = guard.graph(); |
304 |
| - GuardNode newlyCreatedGuard = new GuardNode(guard.getCondition(), anchorBlock.getBeginNode(), guard.getReason(), guard.getAction(), guard.isNegated(), speculation, |
305 |
| - guard.getNoDeoptSuccessorPosition()); |
| 336 | + try (DebugCloseable closeable = falseGuard.withNodeSourcePosition()) { |
| 337 | + StructuredGraph graph = falseGuard.graph(); |
| 338 | + GuardNode newlyCreatedGuard = new GuardNode(falseGuard.getCondition(), anchorBlock.getBeginNode(), falseGuard.getReason(), falseGuard.getAction(), |
| 339 | + falseGuard.isNegated(), speculation, |
| 340 | + falseGuard.getNoDeoptSuccessorPosition()); |
306 | 341 | GuardNode newGuard = node.graph().unique(newlyCreatedGuard);
|
307 |
| - if (otherGuard.isAlive()) { |
| 342 | + if (trueGuard.isAlive()) { |
308 | 343 | if (trueSuccessor instanceof LoopExitNode && beginNode.graph().isBeforeStage(StageFlag.VALUE_PROXY_REMOVAL)) {
|
309 |
| - otherGuard.replaceAndDelete(ProxyNode.forGuard(newGuard, (LoopExitNode) trueSuccessor)); |
| 344 | + trueGuard.replaceAndDelete(ProxyNode.forGuard(newGuard, (LoopExitNode) trueSuccessor)); |
310 | 345 | } else {
|
311 |
| - otherGuard.replaceAndDelete(newGuard); |
| 346 | + trueGuard.replaceAndDelete(newGuard); |
312 | 347 | }
|
313 | 348 | }
|
314 | 349 | if (falseSuccessor instanceof LoopExitNode && beginNode.graph().isBeforeStage(StageFlag.VALUE_PROXY_REMOVAL)) {
|
315 |
| - guard.replaceAndDelete(ProxyNode.forGuard(newGuard, (LoopExitNode) falseSuccessor)); |
| 350 | + falseGuard.replaceAndDelete(ProxyNode.forGuard(newGuard, (LoopExitNode) falseSuccessor)); |
316 | 351 | } else {
|
317 |
| - guard.replaceAndDelete(newGuard); |
| 352 | + falseGuard.replaceAndDelete(newGuard); |
318 | 353 | }
|
319 |
| - graph.getOptimizationLog().report(ConditionalEliminationPhase.class, "GuardCombination", guard); |
| 354 | + graph.getOptimizationLog().report(ConditionalEliminationPhase.class, "GuardCombination", falseGuard); |
320 | 355 | }
|
321 | 356 | }
|
322 | 357 | }
|
|
0 commit comments