src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConvertDeoptimizeToGuardPhase.java
branchniosocketimpl-branch
changeset 57268 adcdd45830a0
parent 57260 bb5198288772
parent 54155 b5a73f22b2bd
child 57270 3519688a4e4d
equal deleted inserted replaced
57260:bb5198288772 57268:adcdd45830a0
     1 /*
       
     2  * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.
       
     8  *
       
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    12  * version 2 for more details (a copy is included in the LICENSE file that
       
    13  * accompanied this code).
       
    14  *
       
    15  * You should have received a copy of the GNU General Public License version
       
    16  * 2 along with this work; if not, write to the Free Software Foundation,
       
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    18  *
       
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    20  * or visit www.oracle.com if you need additional information or have any
       
    21  * questions.
       
    22  */
       
    23 
       
    24 
       
    25 package org.graalvm.compiler.phases.common;
       
    26 
       
    27 import static org.graalvm.compiler.phases.common.DeadCodeEliminationPhase.Optionality.Optional;
       
    28 
       
    29 import java.util.List;
       
    30 
       
    31 import org.graalvm.compiler.core.common.GraalOptions;
       
    32 import org.graalvm.compiler.debug.DebugCloseable;
       
    33 import org.graalvm.compiler.graph.Node;
       
    34 import org.graalvm.compiler.graph.NodeSourcePosition;
       
    35 import org.graalvm.compiler.graph.spi.SimplifierTool;
       
    36 import org.graalvm.compiler.nodeinfo.InputType;
       
    37 import org.graalvm.compiler.nodes.AbstractBeginNode;
       
    38 import org.graalvm.compiler.nodes.AbstractEndNode;
       
    39 import org.graalvm.compiler.nodes.AbstractMergeNode;
       
    40 import org.graalvm.compiler.nodes.ConstantNode;
       
    41 import org.graalvm.compiler.nodes.ControlSplitNode;
       
    42 import org.graalvm.compiler.nodes.DeoptimizeNode;
       
    43 import org.graalvm.compiler.nodes.EndNode;
       
    44 import org.graalvm.compiler.nodes.FixedGuardNode;
       
    45 import org.graalvm.compiler.nodes.FixedNode;
       
    46 import org.graalvm.compiler.nodes.FixedWithNextNode;
       
    47 import org.graalvm.compiler.nodes.GuardNode;
       
    48 import org.graalvm.compiler.nodes.IfNode;
       
    49 import org.graalvm.compiler.nodes.LogicNode;
       
    50 import org.graalvm.compiler.nodes.LoopExitNode;
       
    51 import org.graalvm.compiler.nodes.ProxyNode;
       
    52 import org.graalvm.compiler.nodes.StartNode;
       
    53 import org.graalvm.compiler.nodes.StaticDeoptimizingNode;
       
    54 import org.graalvm.compiler.nodes.StructuredGraph;
       
    55 import org.graalvm.compiler.nodes.ValueNode;
       
    56 import org.graalvm.compiler.nodes.ValuePhiNode;
       
    57 import org.graalvm.compiler.nodes.calc.CompareNode;
       
    58 import org.graalvm.compiler.nodes.spi.LoweringProvider;
       
    59 import org.graalvm.compiler.nodes.util.GraphUtil;
       
    60 import org.graalvm.compiler.phases.BasePhase;
       
    61 import org.graalvm.compiler.phases.tiers.PhaseContext;
       
    62 
       
    63 import jdk.vm.ci.meta.Constant;
       
    64 import jdk.vm.ci.meta.DeoptimizationAction;
       
    65 
       
    66 /**
       
    67  * This phase will find branches which always end with a {@link DeoptimizeNode} and replace their
       
    68  * {@link ControlSplitNode ControlSplitNodes} with {@link FixedGuardNode FixedGuardNodes}.
       
    69  *
       
    70  * This is useful because {@link FixedGuardNode FixedGuardNodes} will be lowered to {@link GuardNode
       
    71  * GuardNodes} which can later be optimized more aggressively than control-flow constructs.
       
    72  *
       
    73  * This is currently only done for branches that start from a {@link IfNode}. If it encounters a
       
    74  * branch starting at an other kind of {@link ControlSplitNode}, it will only bring the
       
    75  * {@link DeoptimizeNode} as close to the {@link ControlSplitNode} as possible.
       
    76  *
       
    77  */
       
    78 public class ConvertDeoptimizeToGuardPhase extends BasePhase<PhaseContext> {
       
    79     @Override
       
    80     @SuppressWarnings("try")
       
    81     protected void run(final StructuredGraph graph, PhaseContext context) {
       
    82         assert graph.hasValueProxies() : "ConvertDeoptimizeToGuardPhase always creates proxies";
       
    83         assert !graph.getGuardsStage().areFrameStatesAtDeopts() : graph.getGuardsStage();
       
    84 
       
    85         for (DeoptimizeNode d : graph.getNodes(DeoptimizeNode.TYPE)) {
       
    86             assert d.isAlive();
       
    87             if (d.getAction() == DeoptimizationAction.None) {
       
    88                 continue;
       
    89             }
       
    90             try (DebugCloseable closable = d.withNodeSourcePosition()) {
       
    91                 propagateFixed(d, d, context != null ? context.getLowerer() : null);
       
    92             }
       
    93         }
       
    94 
       
    95         if (context != null) {
       
    96             for (FixedGuardNode fixedGuard : graph.getNodes(FixedGuardNode.TYPE)) {
       
    97                 try (DebugCloseable closable = fixedGuard.withNodeSourcePosition()) {
       
    98                     trySplitFixedGuard(fixedGuard, context);
       
    99                 }
       
   100             }
       
   101         }
       
   102 
       
   103         new DeadCodeEliminationPhase(Optional).apply(graph);
       
   104     }
       
   105 
       
   106     private void trySplitFixedGuard(FixedGuardNode fixedGuard, PhaseContext context) {
       
   107         LogicNode condition = fixedGuard.condition();
       
   108         if (condition instanceof CompareNode) {
       
   109             CompareNode compare = (CompareNode) condition;
       
   110             ValueNode x = compare.getX();
       
   111             ValuePhiNode xPhi = (x instanceof ValuePhiNode) ? (ValuePhiNode) x : null;
       
   112             if (x instanceof ConstantNode || xPhi != null) {
       
   113                 ValueNode y = compare.getY();
       
   114                 ValuePhiNode yPhi = (y instanceof ValuePhiNode) ? (ValuePhiNode) y : null;
       
   115                 if (y instanceof ConstantNode || yPhi != null) {
       
   116                     processFixedGuardAndPhis(fixedGuard, context, compare, x, xPhi, y, yPhi);
       
   117                 }
       
   118             }
       
   119         }
       
   120     }
       
   121 
       
   122     private void processFixedGuardAndPhis(FixedGuardNode fixedGuard, PhaseContext context, CompareNode compare, ValueNode x, ValuePhiNode xPhi, ValueNode y, ValuePhiNode yPhi) {
       
   123         AbstractBeginNode pred = AbstractBeginNode.prevBegin(fixedGuard);
       
   124         if (pred instanceof AbstractMergeNode) {
       
   125             AbstractMergeNode merge = (AbstractMergeNode) pred;
       
   126             if (xPhi != null && xPhi.merge() != merge) {
       
   127                 return;
       
   128             }
       
   129             if (yPhi != null && yPhi.merge() != merge) {
       
   130                 return;
       
   131             }
       
   132 
       
   133             processFixedGuardAndMerge(fixedGuard, context, compare, x, xPhi, y, yPhi, merge);
       
   134         }
       
   135     }
       
   136 
       
   137     @SuppressWarnings("try")
       
   138     private void processFixedGuardAndMerge(FixedGuardNode fixedGuard, PhaseContext context, CompareNode compare, ValueNode x, ValuePhiNode xPhi, ValueNode y, ValuePhiNode yPhi,
       
   139                     AbstractMergeNode merge) {
       
   140         List<EndNode> mergePredecessors = merge.cfgPredecessors().snapshot();
       
   141         for (int i = 0; i < mergePredecessors.size(); ++i) {
       
   142             AbstractEndNode mergePredecessor = mergePredecessors.get(i);
       
   143             if (!mergePredecessor.isAlive()) {
       
   144                 break;
       
   145             }
       
   146             Constant xs;
       
   147             if (xPhi == null) {
       
   148                 xs = x.asConstant();
       
   149             } else {
       
   150                 xs = xPhi.valueAt(mergePredecessor).asConstant();
       
   151             }
       
   152             Constant ys;
       
   153             if (yPhi == null) {
       
   154                 ys = y.asConstant();
       
   155             } else {
       
   156                 ys = yPhi.valueAt(mergePredecessor).asConstant();
       
   157             }
       
   158             if (xs != null && ys != null && compare.condition().foldCondition(xs, ys, context.getConstantReflection(), compare.unorderedIsTrue()) == fixedGuard.isNegated()) {
       
   159                 try (DebugCloseable position = fixedGuard.withNodeSourcePosition()) {
       
   160                     propagateFixed(mergePredecessor, fixedGuard, context.getLowerer());
       
   161                 }
       
   162             }
       
   163         }
       
   164     }
       
   165 
       
   166     @SuppressWarnings("try")
       
   167     private void propagateFixed(FixedNode from, StaticDeoptimizingNode deopt, LoweringProvider loweringProvider) {
       
   168         Node current = from;
       
   169         while (current != null) {
       
   170             if (GraalOptions.GuardPriorities.getValue(from.getOptions()) && current instanceof FixedGuardNode) {
       
   171                 FixedGuardNode otherGuard = (FixedGuardNode) current;
       
   172                 if (otherGuard.computePriority().isHigherPriorityThan(deopt.computePriority())) {
       
   173                     moveAsDeoptAfter(otherGuard, deopt);
       
   174                     return;
       
   175                 }
       
   176             } else if (current instanceof AbstractBeginNode) {
       
   177                 if (current instanceof AbstractMergeNode) {
       
   178                     AbstractMergeNode mergeNode = (AbstractMergeNode) current;
       
   179                     FixedNode next = mergeNode.next();
       
   180                     while (mergeNode.isAlive()) {
       
   181                         AbstractEndNode end = mergeNode.forwardEnds().first();
       
   182                         propagateFixed(end, deopt, loweringProvider);
       
   183                     }
       
   184                     if (next.isAlive()) {
       
   185                         propagateFixed(next, deopt, loweringProvider);
       
   186                     }
       
   187                     return;
       
   188                 } else if (current.predecessor() instanceof IfNode) {
       
   189                     IfNode ifNode = (IfNode) current.predecessor();
       
   190                     // Prioritize the source position of the IfNode
       
   191                     try (DebugCloseable closable = ifNode.withNodeSourcePosition()) {
       
   192                         StructuredGraph graph = ifNode.graph();
       
   193                         LogicNode conditionNode = ifNode.condition();
       
   194                         boolean negateGuardCondition = current == ifNode.trueSuccessor();
       
   195                         NodeSourcePosition survivingSuccessorPosition = negateGuardCondition ? ifNode.falseSuccessor().getNodeSourcePosition() : ifNode.trueSuccessor().getNodeSourcePosition();
       
   196                         FixedGuardNode guard = graph.add(
       
   197                                         new FixedGuardNode(conditionNode, deopt.getReason(), deopt.getAction(), deopt.getSpeculation(), negateGuardCondition, survivingSuccessorPosition));
       
   198 
       
   199                         FixedWithNextNode pred = (FixedWithNextNode) ifNode.predecessor();
       
   200                         AbstractBeginNode survivingSuccessor;
       
   201                         if (negateGuardCondition) {
       
   202                             survivingSuccessor = ifNode.falseSuccessor();
       
   203                         } else {
       
   204                             survivingSuccessor = ifNode.trueSuccessor();
       
   205                         }
       
   206                         graph.removeSplitPropagate(ifNode, survivingSuccessor);
       
   207 
       
   208                         Node newGuard = guard;
       
   209                         if (survivingSuccessor instanceof LoopExitNode) {
       
   210                             newGuard = ProxyNode.forGuard(guard, (LoopExitNode) survivingSuccessor, graph);
       
   211                         }
       
   212                         survivingSuccessor.replaceAtUsages(InputType.Guard, newGuard);
       
   213 
       
   214                         graph.getDebug().log("Converting deopt on %-5s branch of %s to guard for remaining branch %s.", negateGuardCondition, ifNode, survivingSuccessor);
       
   215                         FixedNode next = pred.next();
       
   216                         pred.setNext(guard);
       
   217                         guard.setNext(next);
       
   218                         SimplifierTool simplifierTool = GraphUtil.getDefaultSimplifier(null, null, null, false, graph.getAssumptions(), graph.getOptions(), loweringProvider);
       
   219                         survivingSuccessor.simplify(simplifierTool);
       
   220                         return;
       
   221                     }
       
   222                 } else if (current.predecessor() == null || current.predecessor() instanceof ControlSplitNode) {
       
   223                     assert current.predecessor() != null || (current instanceof StartNode && current == ((AbstractBeginNode) current).graph().start());
       
   224                     moveAsDeoptAfter((AbstractBeginNode) current, deopt);
       
   225                     return;
       
   226                 }
       
   227             }
       
   228             current = current.predecessor();
       
   229         }
       
   230     }
       
   231 
       
   232     @SuppressWarnings("try")
       
   233     private static void moveAsDeoptAfter(FixedWithNextNode node, StaticDeoptimizingNode deopt) {
       
   234         try (DebugCloseable position = deopt.asNode().withNodeSourcePosition()) {
       
   235             FixedNode next = node.next();
       
   236             if (next != deopt.asNode()) {
       
   237                 node.setNext(node.graph().add(new DeoptimizeNode(deopt.getAction(), deopt.getReason(), deopt.getSpeculation())));
       
   238                 GraphUtil.killCFG(next);
       
   239             }
       
   240         }
       
   241     }
       
   242 }