Esempio n. 1
0
 public static void normalizeLoopBegin(LoopBeginNode begin) {
   // Delete unnecessary loop phi functions, i.e., phi functions where all inputs are either
   // the same or the phi itself.
   for (PhiNode phi : begin.phis().snapshot()) {
     GraphUtil.checkRedundantPhi(phi);
   }
   for (LoopExitNode exit : begin.loopExits()) {
     for (ProxyNode vpn : exit.proxies().snapshot()) {
       GraphUtil.checkRedundantProxy(vpn);
     }
   }
 }
Esempio n. 2
0
 public void reduceTrivialMerge(AbstractMergeNode merge) {
   assert merge.forwardEndCount() == 1;
   assert !(merge instanceof LoopBeginNode) || ((LoopBeginNode) merge).loopEnds().isEmpty();
   for (PhiNode phi : merge.phis().snapshot()) {
     assert phi.valueCount() == 1;
     ValueNode singleValue = phi.valueAt(0);
     phi.replaceAtUsagesAndDelete(singleValue);
   }
   // remove loop exits
   if (merge instanceof LoopBeginNode) {
     ((LoopBeginNode) merge).removeExits();
   }
   AbstractEndNode singleEnd = merge.forwardEndAt(0);
   FixedNode sux = merge.next();
   FrameState stateAfter = merge.stateAfter();
   // evacuateGuards
   merge.prepareDelete((FixedNode) singleEnd.predecessor());
   merge.safeDelete();
   if (stateAfter != null && stateAfter.isAlive() && stateAfter.hasNoUsages()) {
     GraphUtil.killWithUnusedFloatingInputs(stateAfter);
   }
   if (sux == null) {
     singleEnd.replaceAtPredecessor(null);
     singleEnd.safeDelete();
   } else {
     singleEnd.replaceAndDelete(sux);
   }
 }
Esempio n. 3
0
 /**
  * Unlinks a node from all its control flow neighbors and then removes it from its graph. The node
  * must have no {@linkplain Node#usages() usages}.
  *
  * @param node the node to be unlinked and removed
  */
 public void removeFixed(FixedWithNextNode node) {
   assert node != null;
   if (node instanceof AbstractBeginNode) {
     ((AbstractBeginNode) node).prepareDelete();
   }
   assert node.hasNoUsages() : node + " " + node.usages().count() + ", " + node.usages().first();
   GraphUtil.unlinkFixedNode(node);
   node.safeDelete();
 }
Esempio n. 4
0
 public final void clearAllStateAfter() {
   for (Node node : getNodes()) {
     if (node instanceof StateSplit) {
       FrameState stateAfter = ((StateSplit) node).stateAfter();
       if (stateAfter != null) {
         ((StateSplit) node).setStateAfter(null);
         GraphUtil.killWithUnusedFloatingInputs(stateAfter);
       }
     }
   }
 }
Esempio n. 5
0
 public void removeSplitPropagate(
     ControlSplitNode node, AbstractBeginNode survivingSuccessor, SimplifierTool tool) {
   assert node != null;
   assert node.hasNoUsages();
   assert survivingSuccessor != null;
   List<Node> snapshot = node.successors().snapshot();
   node.clearSuccessors();
   node.replaceAtPredecessor(survivingSuccessor);
   node.safeDelete();
   for (Node successor : snapshot) {
     if (successor != null && successor.isAlive()) {
       if (successor != survivingSuccessor) {
         GraphUtil.killCFG(successor, tool);
       }
     }
   }
 }
Esempio n. 6
0
 /**
  * This method performs two kinds of cleanup:
  *
  * <ol>
  *   <li>marking as unreachable certain code-paths, as described in {@link
  *       com.oracle.graal.phases.common.cfs.BaseReduction.PostponedDeopt}
  *   <li>Removing nodes not in use that were added during this phase, as described next.
  * </ol>
  *
  * <p>Methods like {@link
  * com.oracle.graal.phases.common.cfs.FlowUtil#replaceInPlace(com.oracle.graal.graph.Node,
  * com.oracle.graal.graph.Node, com.oracle.graal.graph.Node)} may result in old inputs becoming
  * disconnected from the graph. It's not advisable to {@link
  * com.oracle.graal.nodes.util.GraphUtil#tryKillUnused(com.oracle.graal.graph.Node)} at that
  * moment, because one of the inputs that might get killed is one of {@link #nullConstant}, {@link
  * #falseConstant}, or {@link #trueConstant}; which thus could get killed too early, before
  * another invocation of {@link
  * com.oracle.graal.phases.common.cfs.EquationalReasoner#deverbosify(com.oracle.graal.graph.Node)}
  * needs them. To recap, {@link
  * com.oracle.graal.nodes.util.GraphUtil#tryKillUnused(com.oracle.graal.graph.Node)} also
  * recursively visits the inputs of the its argument.
  *
  * <p>This method goes over all of the nodes that deverbosification might have added, which are
  * either:
  *
  * <ul>
  *   <li>{@link com.oracle.graal.nodes.calc.FloatingNode}, added by {@link
  *       com.oracle.graal.phases.common.cfs.EquationalReasoner#deverbosifyFloatingNode(com.oracle.graal.nodes.calc.FloatingNode)}
  *       ; or
  *   <li>{@link com.oracle.graal.nodes.java.MethodCallTargetNode}, added by {@link
  *       #deverbosifyInputsCopyOnWrite(com.oracle.graal.nodes.java.MethodCallTargetNode)}
  * </ul>
  *
  * Checking if they aren't in use, proceeding to remove them in that case.
  */
 @Override
 public void finished() {
   if (!postponedDeopts.isEmpty()) {
     for (PostponedDeopt postponed : postponedDeopts) {
       postponed.doRewrite(falseConstant);
     }
     new DeadCodeEliminationPhase(Optional).apply(graph);
   }
   for (MethodCallTargetNode mcn : graph.getNodes().filter(MethodCallTargetNode.class)) {
     if (mcn.isAlive() && FlowUtil.lacksUsages(mcn)) {
       mcn.safeDelete();
     }
   }
   for (Node n : graph.getNodes().filter(FloatingNode.class)) {
     GraphUtil.tryKillUnused(n);
   }
   assert !isAliveWithoutUsages(trueConstant);
   assert !isAliveWithoutUsages(falseConstant);
   assert !isAliveWithoutUsages(nullConstant);
   super.finished();
 }
Esempio n. 7
0
 @Test
 public void testValueProxyInputs() {
   StructuredGraph graph = parseEager("testValueProxyInputsSnippet", AllowAssumptions.YES);
   for (FrameState fs : graph.getNodes().filter(FrameState.class).snapshot()) {
     fs.replaceAtUsages(null);
     GraphUtil.killWithUnusedFloatingInputs(fs);
   }
   SchedulePhase schedulePhase = new SchedulePhase(SchedulingStrategy.LATEST);
   schedulePhase.apply(graph);
   ScheduleResult schedule = graph.getLastSchedule();
   NodeMap<Block> nodeToBlock = schedule.getCFG().getNodeToBlock();
   assertTrue(graph.getNodes().filter(LoopExitNode.class).count() == 1);
   LoopExitNode loopExit = graph.getNodes().filter(LoopExitNode.class).first();
   List<Node> list = schedule.nodesFor(nodeToBlock.get(loopExit));
   for (BinaryArithmeticNode<?> node : graph.getNodes().filter(BinaryArithmeticNode.class)) {
     if (!(node instanceof AddNode)) {
       assertTrue(node.toString(), nodeToBlock.get(node) == nodeToBlock.get(loopExit));
       assertTrue(
           list.indexOf(node) + " < " + list.indexOf(loopExit) + ", " + node + ", " + loopExit,
           list.indexOf(node) < list.indexOf(loopExit));
     }
   }
 }
 private static AbstractBeginNode findBeginNode(FixedNode startNode) {
   return GraphUtil.predecessorIterable(startNode).filter(AbstractBeginNode.class).first();
 }
/**
 * This phase will find branches which always end with a {@link DeoptimizeNode} and replace their
 * {@link ControlSplitNode ControlSplitNodes} with {@link FixedGuardNode FixedGuardNodes}.
 *
 * <p>This is useful because {@link FixedGuardNode FixedGuardNodes} will be lowered to {@link
 * GuardNode GuardNodes} which can later be optimized more aggressively than control-flow
 * constructs.
 *
 * <p>This is currently only done for branches that start from a {@link IfNode}. If it encounters a
 * branch starting at an other kind of {@link ControlSplitNode}, it will only bring the {@link
 * DeoptimizeNode} as close to the {@link ControlSplitNode} as possible.
 */
public class ConvertDeoptimizeToGuardPhase extends BasePhase<PhaseContext> {
  private SimplifierTool simplifierTool = GraphUtil.getDefaultSimplifier(null, null, false);

  private static AbstractBeginNode findBeginNode(FixedNode startNode) {
    return GraphUtil.predecessorIterable(startNode).filter(AbstractBeginNode.class).first();
  }

  @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 trySplitFixedGuard(FixedGuardNode fixedGuard, PhaseContext context) {
    LogicNode condition = fixedGuard.condition();
    if (condition instanceof CompareNode) {
      CompareNode compare = (CompareNode) condition;
      ValueNode x = compare.getX();
      ValuePhiNode xPhi = (x instanceof ValuePhiNode) ? (ValuePhiNode) x : null;
      if (x instanceof ConstantNode || xPhi != null) {
        ValueNode y = compare.getY();
        ValuePhiNode yPhi = (y instanceof ValuePhiNode) ? (ValuePhiNode) y : null;
        if (y instanceof ConstantNode || yPhi != null) {
          processFixedGuardAndPhis(fixedGuard, context, compare, x, xPhi, y, yPhi);
        }
      }
    }
  }

  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 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());
      }
    }
  }

  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);
    }
  }
}
  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);
    }
  }
Esempio n. 11
0
 public void replaceFixedWithFloating(FixedWithNextNode node, FloatingNode replacement) {
   assert node != null && replacement != null && node.isAlive() && replacement.isAlive()
       : "cannot replace " + node + " with " + replacement;
   GraphUtil.unlinkFixedNode(node);
   node.replaceAtUsagesAndDelete(replacement);
 }
Esempio n. 12
0
 public void removeIfUnused(Node node) {
   GraphUtil.tryKillUnused(node);
 }
Esempio n. 13
0
 public void deleteBranch(Node branch) {
   branch.predecessor().replaceFirstSuccessor(branch, null);
   GraphUtil.killCFG(branch, this);
 }