private void processFixedGuardAndMerge( FixedGuardNode fixedGuard, PhaseContext context, CompareNode compare, ValueNode x, ValuePhiNode xPhi, ValueNode y, ValuePhiNode yPhi, AbstractMergeNode merge) { List<EndNode> mergePredecessors = merge.cfgPredecessors().snapshot(); for (int i = 0; i < mergePredecessors.size(); ++i) { AbstractEndNode mergePredecessor = mergePredecessors.get(i); if (!mergePredecessor.isAlive()) { break; } Constant xs; if (xPhi == null) { xs = x.asConstant(); } else { xs = xPhi.valueAt(mergePredecessor).asConstant(); } Constant ys; if (yPhi == null) { ys = y.asConstant(); } else { ys = yPhi.valueAt(mergePredecessor).asConstant(); } if (xs != null && ys != null && compare .condition() .foldCondition(xs, ys, context.getConstantReflection(), compare.unorderedIsTrue()) == fixedGuard.isNegated()) { visitDeoptBegin( AbstractBeginNode.prevBegin(mergePredecessor), fixedGuard.getAction(), fixedGuard.getReason(), fixedGuard.getSpeculation(), fixedGuard.graph()); } } }
@Override protected void run(final StructuredGraph graph, PhaseContext context) { assert graph.hasValueProxies() : "ConvertDeoptimizeToGuardPhase always creates proxies"; if (graph.getNodes(DeoptimizeNode.TYPE).isEmpty()) { return; } for (DeoptimizeNode d : graph.getNodes(DeoptimizeNode.TYPE)) { assert d.isAlive(); visitDeoptBegin( AbstractBeginNode.prevBegin(d), d.action(), d.reason(), d.getSpeculation(), graph); } if (context != null) { for (FixedGuardNode fixedGuard : graph.getNodes(FixedGuardNode.TYPE)) { trySplitFixedGuard(fixedGuard, context); } } new DeadCodeEliminationPhase(Optional).apply(graph); }
private void processFixedGuardAndPhis( FixedGuardNode fixedGuard, PhaseContext context, CompareNode compare, ValueNode x, ValuePhiNode xPhi, ValueNode y, ValuePhiNode yPhi) { AbstractBeginNode pred = AbstractBeginNode.prevBegin(fixedGuard); if (pred instanceof AbstractMergeNode) { AbstractMergeNode merge = (AbstractMergeNode) pred; if (xPhi != null && xPhi.merge() != merge) { return; } if (yPhi != null && yPhi.merge() != merge) { return; } processFixedGuardAndMerge(fixedGuard, context, compare, x, xPhi, y, yPhi, merge); } }
private void visitDeoptBegin( AbstractBeginNode deoptBegin, DeoptimizationAction deoptAction, DeoptimizationReason deoptReason, JavaConstant speculation, StructuredGraph graph) { if (deoptBegin.predecessor() instanceof AbstractBeginNode) { /* Walk up chains of LoopExitNodes to the "real" BeginNode that leads to deoptimization. */ visitDeoptBegin( (AbstractBeginNode) deoptBegin.predecessor(), deoptAction, deoptReason, speculation, graph); return; } if (deoptBegin instanceof AbstractMergeNode) { AbstractMergeNode mergeNode = (AbstractMergeNode) deoptBegin; Debug.log("Visiting %s", mergeNode); FixedNode next = mergeNode.next(); while (mergeNode.isAlive()) { AbstractEndNode end = mergeNode.forwardEnds().first(); AbstractBeginNode newBeginNode = findBeginNode(end); visitDeoptBegin(newBeginNode, deoptAction, deoptReason, speculation, graph); } assert next.isAlive(); AbstractBeginNode newBeginNode = findBeginNode(next); visitDeoptBegin(newBeginNode, deoptAction, deoptReason, speculation, graph); return; } else if (deoptBegin.predecessor() instanceof IfNode) { IfNode ifNode = (IfNode) deoptBegin.predecessor(); AbstractBeginNode otherBegin = ifNode.trueSuccessor(); LogicNode conditionNode = ifNode.condition(); FixedGuardNode guard = graph.add( new FixedGuardNode( conditionNode, deoptReason, deoptAction, speculation, deoptBegin == ifNode.trueSuccessor())); FixedWithNextNode pred = (FixedWithNextNode) ifNode.predecessor(); AbstractBeginNode survivingSuccessor; if (deoptBegin == ifNode.trueSuccessor()) { survivingSuccessor = ifNode.falseSuccessor(); } else { survivingSuccessor = ifNode.trueSuccessor(); } graph.removeSplitPropagate(ifNode, survivingSuccessor); Node newGuard = guard; if (survivingSuccessor instanceof LoopExitNode) { newGuard = ProxyNode.forGuard(guard, (LoopExitNode) survivingSuccessor, graph); } survivingSuccessor.replaceAtUsages(InputType.Guard, newGuard); Debug.log( "Converting deopt on %-5s branch of %s to guard for remaining branch %s.", deoptBegin == ifNode.trueSuccessor() ? "true" : "false", ifNode, otherBegin); FixedNode next = pred.next(); pred.setNext(guard); guard.setNext(next); survivingSuccessor.simplify(simplifierTool); return; } // We could not convert the control split - at least cut off control flow after the split. FixedWithNextNode deoptPred = deoptBegin; FixedNode next = deoptPred.next(); if (!(next instanceof DeoptimizeNode)) { DeoptimizeNode newDeoptNode = graph.add(new DeoptimizeNode(deoptAction, deoptReason, speculation)); deoptPred.setNext(newDeoptNode); assert deoptPred == newDeoptNode.predecessor(); GraphUtil.killCFG(next); } }
@Test public void testImplies() { StructuredGraph graph = new StructuredGraph(AllowAssumptions.YES); EndNode trueEnd = graph.add(new EndNode()); EndNode falseEnd = graph.add(new EndNode()); AbstractBeginNode trueBegin = graph.add(new BeginNode()); trueBegin.setNext(trueEnd); AbstractBeginNode falseBegin = graph.add(new BeginNode()); falseBegin.setNext(falseEnd); IfNode ifNode = graph.add(new IfNode(null, trueBegin, falseBegin, 0.5)); graph.start().setNext(ifNode); AbstractMergeNode merge = graph.add(new MergeNode()); merge.addForwardEnd(trueEnd); merge.addForwardEnd(falseEnd); ReturnNode returnNode = graph.add(new ReturnNode(null)); merge.setNext(returnNode); dumpGraph(graph); ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, true, true); List<Block> blocks = cfg.getBlocks(); // check number of blocks assertDeepEquals(4, blocks.size()); // check block - node assignment assertDeepEquals(blocks.get(0), cfg.blockFor(graph.start())); assertDeepEquals(blocks.get(0), cfg.blockFor(ifNode)); assertDeepEquals(blocks.get(1), cfg.blockFor(trueBegin)); assertDeepEquals(blocks.get(1), cfg.blockFor(trueEnd)); assertDeepEquals(blocks.get(2), cfg.blockFor(falseBegin)); assertDeepEquals(blocks.get(2), cfg.blockFor(falseEnd)); assertDeepEquals(blocks.get(3), cfg.blockFor(merge)); assertDeepEquals(blocks.get(3), cfg.blockFor(returnNode)); // check postOrder Iterator<Block> it = cfg.postOrder().iterator(); for (int i = blocks.size() - 1; i >= 0; i--) { assertTrue(it.hasNext()); Block b = it.next(); assertDeepEquals(blocks.get(i), b); } // check dominators assertDominator(blocks.get(0), null); assertDominator(blocks.get(1), blocks.get(0)); assertDominator(blocks.get(2), blocks.get(0)); assertDominator(blocks.get(3), blocks.get(0)); // check dominated assertDominatedSize(blocks.get(0), 3); assertDominatedSize(blocks.get(1), 0); assertDominatedSize(blocks.get(2), 0); assertDominatedSize(blocks.get(3), 0); // check postdominators assertPostdominator(blocks.get(0), blocks.get(3)); assertPostdominator(blocks.get(1), blocks.get(3)); assertPostdominator(blocks.get(2), blocks.get(3)); assertPostdominator(blocks.get(3), null); }
@SuppressWarnings("try") private AnchoringNode process( final Block b, final NodeBitMap activeGuards, final AnchoringNode startAnchor) { final LoweringToolImpl loweringTool = new LoweringToolImpl(context, startAnchor, activeGuards, b.getBeginNode()); // Lower the instructions of this block. List<Node> nodes = schedule.nodesFor(b); for (Node node : nodes) { if (node.isDeleted()) { // This case can happen when previous lowerings deleted nodes. continue; } // Cache the next node to be able to reconstruct the previous of the next node // after lowering. FixedNode nextNode = null; if (node instanceof FixedWithNextNode) { nextNode = ((FixedWithNextNode) node).next(); } else { nextNode = loweringTool.lastFixedNode().next(); } if (node instanceof Lowerable) { Collection<Node> unscheduledUsages = null; assert (unscheduledUsages = getUnscheduledUsages(node)) != null; Mark preLoweringMark = node.graph().getMark(); try (DebugCloseable s = node.graph().withNodeContext(node)) { ((Lowerable) node).lower(loweringTool); } if (loweringTool.guardAnchor.asNode().isDeleted()) { // TODO nextNode could be deleted but this is not currently supported assert nextNode.isAlive(); loweringTool.guardAnchor = AbstractBeginNode.prevBegin(nextNode); } assert checkPostNodeLowering(node, loweringTool, preLoweringMark, unscheduledUsages); } if (!nextNode.isAlive()) { // can happen when the rest of the block is killed by lowering // (e.g. by an unconditional deopt) break; } else { Node nextLastFixed = nextNode.predecessor(); if (!(nextLastFixed instanceof FixedWithNextNode)) { // insert begin node, to have a valid last fixed for next lowerable node. // This is about lowering a FixedWithNextNode to a control split while this // FixedWithNextNode is followed by some kind of BeginNode. // For example the when a FixedGuard followed by a loop exit is lowered to a // control-split + deopt. AbstractBeginNode begin = node.graph().add(new BeginNode()); nextLastFixed.replaceFirstSuccessor(nextNode, begin); begin.setNext(nextNode); nextLastFixed = begin; } loweringTool.setLastFixedNode((FixedWithNextNode) nextLastFixed); } } return loweringTool.getCurrentGuardAnchor(); }