Search in sources :

Example 91 with Node

use of org.graalvm.compiler.graph.Node in project graal by oracle.

the class IfNode method removeIntermediateMaterialization.

/**
 * Tries to connect code that initializes a variable directly with the successors of an if
 * construct that switches on the variable. For example, the pseudo code below:
 *
 * <pre>
 * contains(list, e, yes, no) {
 *     if (list == null || e == null) {
 *         condition = false;
 *     } else {
 *         condition = false;
 *         for (i in list) {
 *             if (i.equals(e)) {
 *                 condition = true;
 *                 break;
 *             }
 *         }
 *     }
 *     if (condition) {
 *         return yes;
 *     } else {
 *         return no;
 *     }
 * }
 * </pre>
 *
 * will be transformed into:
 *
 * <pre>
 * contains(list, e, yes, no) {
 *     if (list == null || e == null) {
 *         return no;
 *     } else {
 *         condition = false;
 *         for (i in list) {
 *             if (i.equals(e)) {
 *                 return yes;
 *             }
 *         }
 *         return no;
 *     }
 * }
 * </pre>
 *
 * @return true if a transformation was made, false otherwise
 */
private boolean removeIntermediateMaterialization(SimplifierTool tool) {
    if (!(predecessor() instanceof AbstractMergeNode) || predecessor() instanceof LoopBeginNode) {
        return false;
    }
    AbstractMergeNode merge = (AbstractMergeNode) predecessor();
    if (!(condition() instanceof CompareNode)) {
        return false;
    }
    CompareNode compare = (CompareNode) condition();
    if (compare.getUsageCount() != 1) {
        return false;
    }
    // Only consider merges with a single usage that is both a phi and an operand of the
    // comparison
    NodeIterable<Node> mergeUsages = merge.usages();
    if (mergeUsages.count() != 1) {
        return false;
    }
    Node singleUsage = mergeUsages.first();
    if (!(singleUsage instanceof ValuePhiNode) || (singleUsage != compare.getX() && singleUsage != compare.getY())) {
        return false;
    }
    // Ensure phi is used by at most the comparison and the merge's frame state (if any)
    ValuePhiNode phi = (ValuePhiNode) singleUsage;
    NodeIterable<Node> phiUsages = phi.usages();
    if (phiUsages.count() > 2) {
        return false;
    }
    for (Node usage : phiUsages) {
        if (usage != compare && usage != merge.stateAfter()) {
            return false;
        }
    }
    List<EndNode> mergePredecessors = merge.cfgPredecessors().snapshot();
    assert phi.valueCount() == merge.forwardEndCount();
    Constant[] xs = constantValues(compare.getX(), merge, false);
    Constant[] ys = constantValues(compare.getY(), merge, false);
    if (xs == null || ys == null) {
        return false;
    }
    // Sanity check that both ends are not followed by a merge without frame state.
    if (!checkFrameState(trueSuccessor()) && !checkFrameState(falseSuccessor())) {
        return false;
    }
    List<EndNode> falseEnds = new ArrayList<>(mergePredecessors.size());
    List<EndNode> trueEnds = new ArrayList<>(mergePredecessors.size());
    EconomicMap<AbstractEndNode, ValueNode> phiValues = EconomicMap.create(Equivalence.IDENTITY, mergePredecessors.size());
    AbstractBeginNode oldFalseSuccessor = falseSuccessor();
    AbstractBeginNode oldTrueSuccessor = trueSuccessor();
    setFalseSuccessor(null);
    setTrueSuccessor(null);
    Iterator<EndNode> ends = mergePredecessors.iterator();
    for (int i = 0; i < xs.length; i++) {
        EndNode end = ends.next();
        phiValues.put(end, phi.valueAt(end));
        if (compare.condition().foldCondition(xs[i], ys[i], tool.getConstantReflection(), compare.unorderedIsTrue())) {
            trueEnds.add(end);
        } else {
            falseEnds.add(end);
        }
    }
    assert !ends.hasNext();
    assert falseEnds.size() + trueEnds.size() == xs.length;
    connectEnds(falseEnds, phiValues, oldFalseSuccessor, merge, tool);
    connectEnds(trueEnds, phiValues, oldTrueSuccessor, merge, tool);
    if (this.trueSuccessorProbability == 0.0) {
        for (AbstractEndNode endNode : trueEnds) {
            propagateZeroProbability(endNode);
        }
    }
    if (this.trueSuccessorProbability == 1.0) {
        for (AbstractEndNode endNode : falseEnds) {
            propagateZeroProbability(endNode);
        }
    }
    /*
         * Remove obsolete ends only after processing all ends, otherwise oldTrueSuccessor or
         * oldFalseSuccessor might have been removed if it is a LoopExitNode.
         */
    if (falseEnds.isEmpty()) {
        GraphUtil.killCFG(oldFalseSuccessor);
    }
    if (trueEnds.isEmpty()) {
        GraphUtil.killCFG(oldTrueSuccessor);
    }
    GraphUtil.killCFG(merge);
    assert !merge.isAlive() : merge;
    assert !phi.isAlive() : phi;
    assert !compare.isAlive() : compare;
    assert !this.isAlive() : this;
    return true;
}
Also used : Constant(jdk.vm.ci.meta.Constant) PrimitiveConstant(jdk.vm.ci.meta.PrimitiveConstant) JavaConstant(jdk.vm.ci.meta.JavaConstant) CompareNode(org.graalvm.compiler.nodes.calc.CompareNode) LoadFieldNode(org.graalvm.compiler.nodes.java.LoadFieldNode) NormalizeCompareNode(org.graalvm.compiler.nodes.calc.NormalizeCompareNode) IntegerEqualsNode(org.graalvm.compiler.nodes.calc.IntegerEqualsNode) InstanceOfNode(org.graalvm.compiler.nodes.java.InstanceOfNode) IntegerLessThanNode(org.graalvm.compiler.nodes.calc.IntegerLessThanNode) ConditionalNode(org.graalvm.compiler.nodes.calc.ConditionalNode) IntegerBelowNode(org.graalvm.compiler.nodes.calc.IntegerBelowNode) IsNullNode(org.graalvm.compiler.nodes.calc.IsNullNode) ObjectEqualsNode(org.graalvm.compiler.nodes.calc.ObjectEqualsNode) Node(org.graalvm.compiler.graph.Node) UnboxNode(org.graalvm.compiler.nodes.extended.UnboxNode) ArrayList(java.util.ArrayList) CompareNode(org.graalvm.compiler.nodes.calc.CompareNode) NormalizeCompareNode(org.graalvm.compiler.nodes.calc.NormalizeCompareNode)

Example 92 with Node

use of org.graalvm.compiler.graph.Node in project graal by oracle.

the class IfNode method sameDestination.

/**
 * Check it these two blocks end up at the same place. Meeting at the same merge, or
 * deoptimizing in the same way.
 */
private static boolean sameDestination(AbstractBeginNode succ1, AbstractBeginNode succ2) {
    Node next1 = succ1.next();
    Node next2 = succ2.next();
    if (next1 instanceof EndNode && next2 instanceof EndNode) {
        EndNode end1 = (EndNode) next1;
        EndNode end2 = (EndNode) next2;
        if (end1.merge() == end2.merge()) {
            for (PhiNode phi : end1.merge().phis()) {
                if (phi.valueAt(end1) != phi.valueAt(end2)) {
                    return false;
                }
            }
            // They go to the same MergeNode and merge the same values
            return true;
        }
    } else if (next1 instanceof DeoptimizeNode && next2 instanceof DeoptimizeNode) {
        DeoptimizeNode deopt1 = (DeoptimizeNode) next1;
        DeoptimizeNode deopt2 = (DeoptimizeNode) next2;
        if (deopt1.getReason() == deopt2.getReason() && deopt1.getAction() == deopt2.getAction()) {
            // Same deoptimization reason and action.
            return true;
        }
    } else if (next1 instanceof LoopExitNode && next2 instanceof LoopExitNode) {
        LoopExitNode exit1 = (LoopExitNode) next1;
        LoopExitNode exit2 = (LoopExitNode) next2;
        if (exit1.loopBegin() == exit2.loopBegin() && exit1.stateAfter() == exit2.stateAfter() && exit1.stateAfter() == null && sameDestination(exit1, exit2)) {
            // Exit the same loop and end up at the same place.
            return true;
        }
    } else if (next1 instanceof ReturnNode && next2 instanceof ReturnNode) {
        ReturnNode exit1 = (ReturnNode) next1;
        ReturnNode exit2 = (ReturnNode) next2;
        if (exit1.result() == exit2.result()) {
            // Exit the same loop and end up at the same place.
            return true;
        }
    }
    return false;
}
Also used : CompareNode(org.graalvm.compiler.nodes.calc.CompareNode) LoadFieldNode(org.graalvm.compiler.nodes.java.LoadFieldNode) NormalizeCompareNode(org.graalvm.compiler.nodes.calc.NormalizeCompareNode) IntegerEqualsNode(org.graalvm.compiler.nodes.calc.IntegerEqualsNode) InstanceOfNode(org.graalvm.compiler.nodes.java.InstanceOfNode) IntegerLessThanNode(org.graalvm.compiler.nodes.calc.IntegerLessThanNode) ConditionalNode(org.graalvm.compiler.nodes.calc.ConditionalNode) IntegerBelowNode(org.graalvm.compiler.nodes.calc.IntegerBelowNode) IsNullNode(org.graalvm.compiler.nodes.calc.IsNullNode) ObjectEqualsNode(org.graalvm.compiler.nodes.calc.ObjectEqualsNode) Node(org.graalvm.compiler.graph.Node) UnboxNode(org.graalvm.compiler.nodes.extended.UnboxNode)

Example 93 with Node

use of org.graalvm.compiler.graph.Node in project graal by oracle.

the class AbstractMergeNode method simplify.

/**
 * This simplify method can deal with a null value for tool, so that it can be used outside of
 * canonicalization.
 */
@Override
public void simplify(SimplifierTool tool) {
    FixedNode currentNext = next();
    if (currentNext instanceof AbstractEndNode) {
        AbstractEndNode origLoopEnd = (AbstractEndNode) currentNext;
        AbstractMergeNode merge = origLoopEnd.merge();
        if (merge instanceof LoopBeginNode && !(origLoopEnd instanceof LoopEndNode)) {
            return;
        }
        // anchors are used by phis of the other merge
        if (this.anchored().isNotEmpty()) {
            return;
        }
        if (merge.stateAfter() == null && this.stateAfter() != null) {
            // We hold a state, but the succeeding merge does not => do not combine.
            return;
        }
        for (PhiNode phi : phis()) {
            for (Node usage : phi.usages()) {
                if (!(usage instanceof VirtualState) && !merge.isPhiAtMerge(usage)) {
                    return;
                }
            }
        }
        getDebug().log("Split %s into ends for %s.", this, merge);
        int numEnds = this.forwardEndCount();
        for (int i = 0; i < numEnds - 1; i++) {
            AbstractEndNode end = forwardEndAt(numEnds - 1 - i);
            if (tool != null) {
                tool.addToWorkList(end);
            }
            AbstractEndNode newEnd;
            if (merge instanceof LoopBeginNode) {
                newEnd = graph().add(new LoopEndNode((LoopBeginNode) merge));
            } else {
                EndNode tmpEnd = graph().add(new EndNode());
                merge.addForwardEnd(tmpEnd);
                newEnd = tmpEnd;
            }
            for (PhiNode phi : merge.phis()) {
                ValueNode v = phi.valueAt(origLoopEnd);
                ValueNode newInput;
                if (isPhiAtMerge(v)) {
                    PhiNode endPhi = (PhiNode) v;
                    newInput = endPhi.valueAt(end);
                } else {
                    newInput = v;
                }
                phi.addInput(newInput);
            }
            this.removeEnd(end);
            end.replaceAtPredecessor(newEnd);
            end.safeDelete();
            if (tool != null) {
                tool.addToWorkList(newEnd.predecessor());
            }
        }
        graph().reduceTrivialMerge(this);
    } else if (currentNext instanceof ReturnNode) {
        ReturnNode returnNode = (ReturnNode) currentNext;
        if (anchored().isNotEmpty() || returnNode.getMemoryMap() != null) {
            return;
        }
        List<PhiNode> phis = phis().snapshot();
        for (PhiNode phi : phis) {
            for (Node usage : phi.usages()) {
                if (usage != returnNode && !(usage instanceof FrameState)) {
                    return;
                }
            }
        }
        ValuePhiNode returnValuePhi = returnNode.result() == null || !isPhiAtMerge(returnNode.result()) ? null : (ValuePhiNode) returnNode.result();
        List<EndNode> endNodes = forwardEnds().snapshot();
        for (EndNode end : endNodes) {
            ReturnNode newReturn = graph().add(new ReturnNode(returnValuePhi == null ? returnNode.result() : returnValuePhi.valueAt(end)));
            if (tool != null) {
                tool.addToWorkList(end.predecessor());
            }
            end.replaceAtPredecessor(newReturn);
        }
        GraphUtil.killCFG(this);
        for (EndNode end : endNodes) {
            end.safeDelete();
        }
        for (PhiNode phi : phis) {
            if (tool.allUsagesAvailable() && phi.isAlive() && phi.hasNoUsages()) {
                GraphUtil.killWithUnusedFloatingInputs(phi);
            }
        }
    }
}
Also used : MemoryPhiNode(org.graalvm.compiler.nodes.memory.MemoryPhiNode) MemoryPhiNode(org.graalvm.compiler.nodes.memory.MemoryPhiNode) Node(org.graalvm.compiler.graph.Node) NodeInputList(org.graalvm.compiler.graph.NodeInputList) List(java.util.List)

Example 94 with Node

use of org.graalvm.compiler.graph.Node in project graal by oracle.

the class PartialEscapeBlockState method materializeBefore.

/**
 * Materializes the given virtual object and produces the necessary effects in the effects list.
 * This transitively also materializes all other virtual objects that are reachable from the
 * entries.
 */
public void materializeBefore(FixedNode fixed, VirtualObjectNode virtual, GraphEffectList materializeEffects) {
    PartialEscapeClosure.COUNTER_MATERIALIZATIONS.increment(fixed.getDebug());
    List<AllocatedObjectNode> objects = new ArrayList<>(2);
    List<ValueNode> values = new ArrayList<>(8);
    List<List<MonitorIdNode>> locks = new ArrayList<>();
    List<ValueNode> otherAllocations = new ArrayList<>(2);
    List<Boolean> ensureVirtual = new ArrayList<>(2);
    materializeWithCommit(fixed, virtual, objects, locks, values, ensureVirtual, otherAllocations);
    materializeEffects.addVirtualizationDelta(-(objects.size() + otherAllocations.size()));
    materializeEffects.add("materializeBefore", new Effect() {

        @Override
        public void apply(StructuredGraph graph, ArrayList<Node> obsoleteNodes) {
            for (ValueNode alloc : otherAllocations) {
                ValueNode otherAllocation = graph.addOrUniqueWithInputs(alloc);
                if (otherAllocation instanceof FixedWithNextNode) {
                    graph.addBeforeFixed(fixed, (FixedWithNextNode) otherAllocation);
                } else {
                    assert otherAllocation instanceof FloatingNode;
                }
            }
            if (!objects.isEmpty()) {
                CommitAllocationNode commit;
                if (fixed.predecessor() instanceof CommitAllocationNode) {
                    commit = (CommitAllocationNode) fixed.predecessor();
                } else {
                    commit = graph.add(new CommitAllocationNode());
                    graph.addBeforeFixed(fixed, commit);
                }
                for (AllocatedObjectNode obj : objects) {
                    graph.addWithoutUnique(obj);
                    commit.getVirtualObjects().add(obj.getVirtualObject());
                    obj.setCommit(commit);
                }
                for (ValueNode value : values) {
                    commit.getValues().add(graph.addOrUniqueWithInputs(value));
                }
                for (List<MonitorIdNode> monitorIds : locks) {
                    commit.addLocks(monitorIds);
                }
                commit.getEnsureVirtual().addAll(ensureVirtual);
                assert commit.usages().filter(AllocatedObjectNode.class).count() == commit.getUsageCount();
                List<AllocatedObjectNode> materializedValues = commit.usages().filter(AllocatedObjectNode.class).snapshot();
                for (int i = 0; i < commit.getValues().size(); i++) {
                    if (materializedValues.contains(commit.getValues().get(i))) {
                        commit.getValues().set(i, ((AllocatedObjectNode) commit.getValues().get(i)).getVirtualObject());
                    }
                }
            }
        }
    });
}
Also used : FixedWithNextNode(org.graalvm.compiler.nodes.FixedWithNextNode) AllocatedObjectNode(org.graalvm.compiler.nodes.virtual.AllocatedObjectNode) FixedNode(org.graalvm.compiler.nodes.FixedNode) FloatingNode(org.graalvm.compiler.nodes.calc.FloatingNode) VirtualObjectNode(org.graalvm.compiler.nodes.virtual.VirtualObjectNode) AllocatedObjectNode(org.graalvm.compiler.nodes.virtual.AllocatedObjectNode) CommitAllocationNode(org.graalvm.compiler.nodes.virtual.CommitAllocationNode) ValueNode(org.graalvm.compiler.nodes.ValueNode) MonitorIdNode(org.graalvm.compiler.nodes.java.MonitorIdNode) Node(org.graalvm.compiler.graph.Node) FixedWithNextNode(org.graalvm.compiler.nodes.FixedWithNextNode) ArrayList(java.util.ArrayList) StructuredGraph(org.graalvm.compiler.nodes.StructuredGraph) ValueNode(org.graalvm.compiler.nodes.ValueNode) FloatingNode(org.graalvm.compiler.nodes.calc.FloatingNode) ArrayList(java.util.ArrayList) List(java.util.List) Effect(org.graalvm.compiler.virtual.phases.ea.EffectList.Effect) CommitAllocationNode(org.graalvm.compiler.nodes.virtual.CommitAllocationNode)

Example 95 with Node

use of org.graalvm.compiler.graph.Node in project graal by oracle.

the class VirtualUtil method assertNonReachable.

public static boolean assertNonReachable(StructuredGraph graph, List<Node> obsoleteNodes) {
    // Helper code that determines the paths that keep obsolete nodes alive.
    // Nodes with support for GVN can be kept alive by GVN and are therefore not part of the
    // assertion.
    DebugContext debug = graph.getDebug();
    NodeFlood flood = graph.createNodeFlood();
    EconomicMap<Node, Node> path = EconomicMap.create(Equivalence.IDENTITY);
    flood.add(graph.start());
    for (Node current : flood) {
        if (current instanceof AbstractEndNode) {
            AbstractEndNode end = (AbstractEndNode) current;
            flood.add(end.merge());
            if (!path.containsKey(end.merge())) {
                path.put(end.merge(), end);
            }
        } else {
            for (Node successor : current.successors()) {
                flood.add(successor);
                if (!path.containsKey(successor)) {
                    path.put(successor, current);
                }
            }
        }
    }
    for (Node node : obsoleteNodes) {
        if (node instanceof FixedNode && !node.isDeleted()) {
            assert !flood.isMarked(node) : node;
        }
    }
    for (Node node : graph.getNodes()) {
        if (flood.isMarked(node)) {
            for (Node input : node.inputs()) {
                flood.add(input);
                if (!path.containsKey(input)) {
                    path.put(input, node);
                }
            }
        }
    }
    for (Node current : flood) {
        for (Node input : current.inputs()) {
            flood.add(input);
            if (!path.containsKey(input)) {
                path.put(input, current);
            }
        }
    }
    boolean success = true;
    for (Node node : obsoleteNodes) {
        if (!node.isDeleted() && flood.isMarked(node) && !node.getNodeClass().valueNumberable()) {
            TTY.println("offending node path:");
            Node current = node;
            TTY.print(current.toString());
            while (true) {
                current = path.get(current);
                if (current != null) {
                    TTY.print(" -> " + current.toString());
                    if (current instanceof FixedNode && !obsoleteNodes.contains(current)) {
                        break;
                    }
                }
            }
            success = false;
        }
    }
    if (!success) {
        TTY.println();
        debug.forceDump(graph, "assertNonReachable");
    }
    return success;
}
Also used : FixedNode(org.graalvm.compiler.nodes.FixedNode) AbstractEndNode(org.graalvm.compiler.nodes.AbstractEndNode) Node(org.graalvm.compiler.graph.Node) AbstractEndNode(org.graalvm.compiler.nodes.AbstractEndNode) DebugContext(org.graalvm.compiler.debug.DebugContext) FixedNode(org.graalvm.compiler.nodes.FixedNode) NodeFlood(org.graalvm.compiler.graph.NodeFlood)

Aggregations

Node (org.graalvm.compiler.graph.Node)189 ValueNode (org.graalvm.compiler.nodes.ValueNode)105 FixedNode (org.graalvm.compiler.nodes.FixedNode)91 AbstractMergeNode (org.graalvm.compiler.nodes.AbstractMergeNode)75 FixedWithNextNode (org.graalvm.compiler.nodes.FixedWithNextNode)74 AbstractBeginNode (org.graalvm.compiler.nodes.AbstractBeginNode)73 PhiNode (org.graalvm.compiler.nodes.PhiNode)64 ConstantNode (org.graalvm.compiler.nodes.ConstantNode)61 LoopBeginNode (org.graalvm.compiler.nodes.LoopBeginNode)53 AbstractEndNode (org.graalvm.compiler.nodes.AbstractEndNode)47 StructuredGraph (org.graalvm.compiler.nodes.StructuredGraph)43 FloatingNode (org.graalvm.compiler.nodes.calc.FloatingNode)41 ParameterNode (org.graalvm.compiler.nodes.ParameterNode)38 EndNode (org.graalvm.compiler.nodes.EndNode)37 LoopExitNode (org.graalvm.compiler.nodes.LoopExitNode)37 MethodCallTargetNode (org.graalvm.compiler.nodes.java.MethodCallTargetNode)37 MergeNode (org.graalvm.compiler.nodes.MergeNode)35 ReturnNode (org.graalvm.compiler.nodes.ReturnNode)35 VirtualObjectNode (org.graalvm.compiler.nodes.virtual.VirtualObjectNode)32 LogicNode (org.graalvm.compiler.nodes.LogicNode)31