Search in sources :

Example 1 with IntegerBelowNode

use of org.graalvm.compiler.nodes.calc.IntegerBelowNode in project graal by oracle.

the class ConditionalEliminationTest14 method test1.

@Test
public void test1() {
    StructuredGraph graph = parseEager("test1Snippet", AllowAssumptions.YES);
    CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
    PhaseContext context = new PhaseContext(getProviders());
    /* Convert the LoadIndexNode to ReadNode with floating guards. */
    new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
    /* Convert the ReadNode to FloatingReadNode. */
    new FloatingReadPhase().apply(graph);
    /* Apply the phase that we want to test. */
    new IterativeConditionalEliminationPhase(canonicalizer, true).apply(graph, context);
    Assert.assertEquals("All guards must be floating", 0, graph.getNodes(FixedGuardNode.TYPE).count());
    Assert.assertEquals("All array accesses must have been lowered", 0, graph.getNodes().filter(LoadIndexedNode.class).count());
    Assert.assertEquals("All reads must be floating", 0, graph.getNodes().filter(ReadNode.class).count());
    Assert.assertEquals("Must have floating reads (3 array accesses, 1 array length)", 4, graph.getNodes().filter(FloatingReadNode.class).count());
    NodeIterable<GuardNode> boundsChecks = graph.getNodes(GuardNode.TYPE).filter(n -> ((GuardNode) n).getReason() == DeoptimizationReason.BoundsCheckException);
    Assert.assertEquals("Must have only 1 bounds check remaining", 1, boundsChecks.count());
    LogicNode condition = boundsChecks.first().getCondition();
    Assert.assertTrue("Bounds check must check for array length 8", condition instanceof IntegerBelowNode && ((IntegerBelowNode) condition).getY().valueEquals(ConstantNode.forInt(8)));
}
Also used : PhaseContext(org.graalvm.compiler.phases.tiers.PhaseContext) IterativeConditionalEliminationPhase(org.graalvm.compiler.phases.common.IterativeConditionalEliminationPhase) StructuredGraph(org.graalvm.compiler.nodes.StructuredGraph) IntegerBelowNode(org.graalvm.compiler.nodes.calc.IntegerBelowNode) LoweringPhase(org.graalvm.compiler.phases.common.LoweringPhase) GuardNode(org.graalvm.compiler.nodes.GuardNode) FixedGuardNode(org.graalvm.compiler.nodes.FixedGuardNode) CanonicalizerPhase(org.graalvm.compiler.phases.common.CanonicalizerPhase) LogicNode(org.graalvm.compiler.nodes.LogicNode) FloatingReadPhase(org.graalvm.compiler.phases.common.FloatingReadPhase) Test(org.junit.Test)

Example 2 with IntegerBelowNode

use of org.graalvm.compiler.nodes.calc.IntegerBelowNode in project graal by oracle.

the class WordOperationPlugin method comparisonOp.

private ValueNode comparisonOp(GraphBuilderContext graph, Condition condition, ValueNode left, ValueNode right) {
    assert left.getStackKind() == wordKind && right.getStackKind() == wordKind;
    CanonicalizedCondition canonical = condition.canonicalize();
    ValueNode a = canonical.mustMirror() ? right : left;
    ValueNode b = canonical.mustMirror() ? left : right;
    CompareNode comparison;
    if (canonical.getCanonicalCondition() == CanonicalCondition.EQ) {
        comparison = new IntegerEqualsNode(a, b);
    } else if (canonical.getCanonicalCondition() == CanonicalCondition.BT) {
        comparison = new IntegerBelowNode(a, b);
    } else {
        assert canonical.getCanonicalCondition() == CanonicalCondition.LT;
        comparison = new IntegerLessThanNode(a, b);
    }
    ConstantNode trueValue = graph.add(forInt(1));
    ConstantNode falseValue = graph.add(forInt(0));
    if (canonical.mustNegate()) {
        ConstantNode temp = trueValue;
        trueValue = falseValue;
        falseValue = temp;
    }
    return graph.add(new ConditionalNode(graph.add(comparison), trueValue, falseValue));
}
Also used : CanonicalizedCondition(org.graalvm.compiler.core.common.calc.Condition.CanonicalizedCondition) ConstantNode(org.graalvm.compiler.nodes.ConstantNode) ConditionalNode(org.graalvm.compiler.nodes.calc.ConditionalNode) CompareNode(org.graalvm.compiler.nodes.calc.CompareNode) IntegerEqualsNode(org.graalvm.compiler.nodes.calc.IntegerEqualsNode) IntegerBelowNode(org.graalvm.compiler.nodes.calc.IntegerBelowNode) ValueNode(org.graalvm.compiler.nodes.ValueNode) IntegerLessThanNode(org.graalvm.compiler.nodes.calc.IntegerLessThanNode)

Example 3 with IntegerBelowNode

use of org.graalvm.compiler.nodes.calc.IntegerBelowNode in project graal by oracle.

the class LoopEx method detectCounted.

public boolean detectCounted() {
    LoopBeginNode loopBegin = loopBegin();
    FixedNode next = loopBegin.next();
    while (next instanceof FixedGuardNode || next instanceof ValueAnchorNode || next instanceof FullInfopointNode) {
        next = ((FixedWithNextNode) next).next();
    }
    if (next instanceof IfNode) {
        IfNode ifNode = (IfNode) next;
        boolean negated = false;
        if (!loopBegin.isLoopExit(ifNode.falseSuccessor())) {
            if (!loopBegin.isLoopExit(ifNode.trueSuccessor())) {
                return false;
            }
            negated = true;
        }
        LogicNode ifTest = ifNode.condition();
        if (!(ifTest instanceof IntegerLessThanNode) && !(ifTest instanceof IntegerEqualsNode)) {
            if (ifTest instanceof IntegerBelowNode) {
                ifTest.getDebug().log("Ignored potential Counted loop at %s with |<|", loopBegin);
            }
            return false;
        }
        CompareNode lessThan = (CompareNode) ifTest;
        Condition condition = null;
        InductionVariable iv = null;
        ValueNode limit = null;
        if (isOutsideLoop(lessThan.getX())) {
            iv = getInductionVariables().get(lessThan.getY());
            if (iv != null) {
                condition = lessThan.condition().asCondition().mirror();
                limit = lessThan.getX();
            }
        } else if (isOutsideLoop(lessThan.getY())) {
            iv = getInductionVariables().get(lessThan.getX());
            if (iv != null) {
                condition = lessThan.condition().asCondition();
                limit = lessThan.getY();
            }
        }
        if (condition == null) {
            return false;
        }
        if (negated) {
            condition = condition.negate();
        }
        boolean oneOff = false;
        switch(condition) {
            case EQ:
                return false;
            case NE:
                {
                    if (!iv.isConstantStride() || Math.abs(iv.constantStride()) != 1) {
                        return false;
                    }
                    IntegerStamp initStamp = (IntegerStamp) iv.initNode().stamp(NodeView.DEFAULT);
                    IntegerStamp limitStamp = (IntegerStamp) limit.stamp(NodeView.DEFAULT);
                    if (iv.direction() == Direction.Up) {
                        if (initStamp.upperBound() > limitStamp.lowerBound()) {
                            return false;
                        }
                    } else if (iv.direction() == Direction.Down) {
                        if (initStamp.lowerBound() < limitStamp.upperBound()) {
                            return false;
                        }
                    } else {
                        return false;
                    }
                    break;
                }
            case LE:
                oneOff = true;
                if (iv.direction() != Direction.Up) {
                    return false;
                }
                break;
            case LT:
                if (iv.direction() != Direction.Up) {
                    return false;
                }
                break;
            case GE:
                oneOff = true;
                if (iv.direction() != Direction.Down) {
                    return false;
                }
                break;
            case GT:
                if (iv.direction() != Direction.Down) {
                    return false;
                }
                break;
            default:
                throw GraalError.shouldNotReachHere();
        }
        counted = new CountedLoopInfo(this, iv, ifNode, limit, oneOff, negated ? ifNode.falseSuccessor() : ifNode.trueSuccessor());
        return true;
    }
    return false;
}
Also used : Condition(org.graalvm.compiler.core.common.calc.Condition) IntegerEqualsNode(org.graalvm.compiler.nodes.calc.IntegerEqualsNode) IntegerBelowNode(org.graalvm.compiler.nodes.calc.IntegerBelowNode) FixedNode(org.graalvm.compiler.nodes.FixedNode) IfNode(org.graalvm.compiler.nodes.IfNode) FixedGuardNode(org.graalvm.compiler.nodes.FixedGuardNode) LoopBeginNode(org.graalvm.compiler.nodes.LoopBeginNode) FullInfopointNode(org.graalvm.compiler.nodes.FullInfopointNode) CompareNode(org.graalvm.compiler.nodes.calc.CompareNode) IntegerStamp(org.graalvm.compiler.core.common.type.IntegerStamp) ValueAnchorNode(org.graalvm.compiler.nodes.extended.ValueAnchorNode) IntegerLessThanNode(org.graalvm.compiler.nodes.calc.IntegerLessThanNode) ValueNode(org.graalvm.compiler.nodes.ValueNode) LogicNode(org.graalvm.compiler.nodes.LogicNode)

Example 4 with IntegerBelowNode

use of org.graalvm.compiler.nodes.calc.IntegerBelowNode in project graal by oracle.

the class IntegerSwitchNode method tryOptimizeEnumSwitch.

/**
 * For switch statements on enum values, the Java compiler has to generate complicated code:
 * because {@link Enum#ordinal()} can change when recompiling an enum, it cannot be used
 * directly as the value that is switched on. An intermediate int[] array, which is initialized
 * once at run time based on the actual {@link Enum#ordinal()} values, is used.
 *
 * The {@link ConstantFieldProvider} of Graal already detects the int[] arrays and marks them as
 * {@link ConstantNode#isDefaultStable() stable}, i.e., the array elements are constant. The
 * code in this method detects array loads from such a stable array and re-wires the switch to
 * use the keys from the array elements, so that the array load is unnecessary.
 */
private boolean tryOptimizeEnumSwitch(SimplifierTool tool) {
    if (!(value() instanceof LoadIndexedNode)) {
        /* Not the switch pattern we are looking for. */
        return false;
    }
    LoadIndexedNode loadIndexed = (LoadIndexedNode) value();
    if (loadIndexed.usages().count() > 1) {
        /*
             * The array load is necessary for other reasons too, so there is no benefit optimizing
             * the switch.
             */
        return false;
    }
    assert loadIndexed.usages().first() == this;
    ValueNode newValue = loadIndexed.index();
    JavaConstant arrayConstant = loadIndexed.array().asJavaConstant();
    if (arrayConstant == null || ((ConstantNode) loadIndexed.array()).getStableDimension() != 1 || !((ConstantNode) loadIndexed.array()).isDefaultStable()) {
        /*
             * The array is a constant that we can optimize. We require the array elements to be
             * constant too, since we put them as literal constants into the switch keys.
             */
        return false;
    }
    Integer optionalArrayLength = tool.getConstantReflection().readArrayLength(arrayConstant);
    if (optionalArrayLength == null) {
        /* Loading a constant value can be denied by the VM. */
        return false;
    }
    int arrayLength = optionalArrayLength;
    Map<Integer, List<Integer>> reverseArrayMapping = new HashMap<>();
    for (int i = 0; i < arrayLength; i++) {
        JavaConstant elementConstant = tool.getConstantReflection().readArrayElement(arrayConstant, i);
        if (elementConstant == null || elementConstant.getJavaKind() != JavaKind.Int) {
            /* Loading a constant value can be denied by the VM. */
            return false;
        }
        int element = elementConstant.asInt();
        /*
             * The value loaded from the array is the old switch key, the index into the array is
             * the new switch key. We build a mapping from the old switch key to new keys.
             */
        reverseArrayMapping.computeIfAbsent(element, e -> new ArrayList<>()).add(i);
    }
    /* Build high-level representation of new switch keys. */
    List<KeyData> newKeyDatas = new ArrayList<>(arrayLength);
    ArrayList<AbstractBeginNode> newSuccessors = new ArrayList<>(blockSuccessorCount());
    for (int i = 0; i < keys.length; i++) {
        List<Integer> newKeys = reverseArrayMapping.get(keys[i]);
        if (newKeys == null || newKeys.size() == 0) {
            /* The switch case is unreachable, we can ignore it. */
            continue;
        }
        /*
             * We do not have detailed profiling information about the individual new keys, so we
             * have to assume they split the probability of the old key.
             */
        double newKeyProbability = keyProbabilities[i] / newKeys.size();
        int newKeySuccessor = addNewSuccessor(keySuccessor(i), newSuccessors);
        for (int newKey : newKeys) {
            newKeyDatas.add(new KeyData(newKey, newKeyProbability, newKeySuccessor));
        }
    }
    int newDefaultSuccessor = addNewSuccessor(defaultSuccessor(), newSuccessors);
    double newDefaultProbability = keyProbabilities[keyProbabilities.length - 1];
    /*
         * We remove the array load, but we still need to preserve exception semantics by keeping
         * the bounds check. Fortunately the array length is a constant.
         */
    LogicNode boundsCheck = graph().unique(new IntegerBelowNode(newValue, ConstantNode.forInt(arrayLength, graph())));
    graph().addBeforeFixed(this, graph().add(new FixedGuardNode(boundsCheck, DeoptimizationReason.BoundsCheckException, DeoptimizationAction.InvalidateReprofile)));
    /*
         * Build the low-level representation of the new switch keys and replace ourself with a new
         * node.
         */
    doReplace(newValue, newKeyDatas, newSuccessors, newDefaultSuccessor, newDefaultProbability);
    /* The array load is now unnecessary. */
    assert loadIndexed.hasNoUsages();
    GraphUtil.removeFixedWithUnusedInputs(loadIndexed);
    return true;
}
Also used : DeoptimizationReason(jdk.vm.ci.meta.DeoptimizationReason) Arrays(java.util.Arrays) ConstantNode(org.graalvm.compiler.nodes.ConstantNode) DeoptimizationAction(jdk.vm.ci.meta.DeoptimizationAction) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) NodeLIRBuilderTool(org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool) SimplifierTool(org.graalvm.compiler.graph.spi.SimplifierTool) IntegerStamp(org.graalvm.compiler.core.common.type.IntegerStamp) StampFactory(org.graalvm.compiler.core.common.type.StampFactory) JavaKind(jdk.vm.ci.meta.JavaKind) NodeClass(org.graalvm.compiler.graph.NodeClass) Map(java.util.Map) LoadIndexedNode(org.graalvm.compiler.nodes.java.LoadIndexedNode) IntegerBelowNode(org.graalvm.compiler.nodes.calc.IntegerBelowNode) NodeInfo(org.graalvm.compiler.nodeinfo.NodeInfo) GraphUtil(org.graalvm.compiler.nodes.util.GraphUtil) NodeView(org.graalvm.compiler.nodes.NodeView) AbstractBeginNode(org.graalvm.compiler.nodes.AbstractBeginNode) FixedGuardNode(org.graalvm.compiler.nodes.FixedGuardNode) PrimitiveStamp(org.graalvm.compiler.core.common.type.PrimitiveStamp) Stamp(org.graalvm.compiler.core.common.type.Stamp) LIRLowerable(org.graalvm.compiler.nodes.spi.LIRLowerable) JavaConstant(jdk.vm.ci.meta.JavaConstant) LogicNode(org.graalvm.compiler.nodes.LogicNode) ValueNode(org.graalvm.compiler.nodes.ValueNode) List(java.util.List) ConstantFieldProvider(org.graalvm.compiler.core.common.spi.ConstantFieldProvider) Simplifiable(org.graalvm.compiler.graph.spi.Simplifiable) Comparator(java.util.Comparator) FixedWithNextNode(org.graalvm.compiler.nodes.FixedWithNextNode) IntegerBelowNode(org.graalvm.compiler.nodes.calc.IntegerBelowNode) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) JavaConstant(jdk.vm.ci.meta.JavaConstant) AbstractBeginNode(org.graalvm.compiler.nodes.AbstractBeginNode) FixedGuardNode(org.graalvm.compiler.nodes.FixedGuardNode) ConstantNode(org.graalvm.compiler.nodes.ConstantNode) LoadIndexedNode(org.graalvm.compiler.nodes.java.LoadIndexedNode) ValueNode(org.graalvm.compiler.nodes.ValueNode) ArrayList(java.util.ArrayList) List(java.util.List) LogicNode(org.graalvm.compiler.nodes.LogicNode)

Example 5 with IntegerBelowNode

use of org.graalvm.compiler.nodes.calc.IntegerBelowNode in project graal by oracle.

the class IfNode method checkForUnsignedCompare.

/**
 * Recognize a couple patterns that can be merged into an unsigned compare.
 *
 * @param tool
 * @return true if a replacement was done.
 */
private boolean checkForUnsignedCompare(SimplifierTool tool) {
    assert trueSuccessor().hasNoUsages() && falseSuccessor().hasNoUsages();
    if (condition() instanceof IntegerLessThanNode) {
        NodeView view = NodeView.from(tool);
        IntegerLessThanNode lessThan = (IntegerLessThanNode) condition();
        Constant y = lessThan.getY().stamp(view).asConstant();
        if (y instanceof PrimitiveConstant && ((PrimitiveConstant) y).asLong() == 0 && falseSuccessor().next() instanceof IfNode) {
            IfNode ifNode2 = (IfNode) falseSuccessor().next();
            if (ifNode2.condition() instanceof IntegerLessThanNode) {
                IntegerLessThanNode lessThan2 = (IntegerLessThanNode) ifNode2.condition();
                AbstractBeginNode falseSucc = ifNode2.falseSuccessor();
                AbstractBeginNode trueSucc = ifNode2.trueSuccessor();
                IntegerBelowNode below = null;
                /*
                     * Convert x >= 0 && x < positive which is represented as !(x < 0) && x <
                     * <positive> into an unsigned compare.
                     */
                if (lessThan2.getX() == lessThan.getX() && lessThan2.getY().stamp(view) instanceof IntegerStamp && ((IntegerStamp) lessThan2.getY().stamp(view)).isPositive() && sameDestination(trueSuccessor(), ifNode2.falseSuccessor)) {
                    below = graph().unique(new IntegerBelowNode(lessThan2.getX(), lessThan2.getY()));
                    // swap direction
                    AbstractBeginNode tmp = falseSucc;
                    falseSucc = trueSucc;
                    trueSucc = tmp;
                } else if (lessThan2.getY() == lessThan.getX() && sameDestination(trueSuccessor(), ifNode2.trueSuccessor)) {
                    /*
                         * Convert x >= 0 && x <= positive which is represented as !(x < 0) &&
                         * !(<positive> > x), into x <| positive + 1. This can only be done for
                         * constants since there isn't a IntegerBelowEqualThanNode but that doesn't
                         * appear to be interesting.
                         */
                    JavaConstant positive = lessThan2.getX().asJavaConstant();
                    if (positive != null && positive.asLong() > 0 && positive.asLong() < positive.getJavaKind().getMaxValue()) {
                        ConstantNode newLimit = ConstantNode.forIntegerStamp(lessThan2.getX().stamp(view), positive.asLong() + 1, graph());
                        below = graph().unique(new IntegerBelowNode(lessThan.getX(), newLimit));
                    }
                }
                if (below != null) {
                    ifNode2.setTrueSuccessor(null);
                    ifNode2.setFalseSuccessor(null);
                    IfNode newIfNode = graph().add(new IfNode(below, falseSucc, trueSucc, 1 - trueSuccessorProbability));
                    // Remove the < 0 test.
                    tool.deleteBranch(trueSuccessor);
                    graph().removeSplit(this, falseSuccessor);
                    // Replace the second test with the new one.
                    ifNode2.predecessor().replaceFirstSuccessor(ifNode2, newIfNode);
                    ifNode2.safeDelete();
                    return true;
                }
            }
        }
    }
    return false;
}
Also used : IntegerBelowNode(org.graalvm.compiler.nodes.calc.IntegerBelowNode) Constant(jdk.vm.ci.meta.Constant) PrimitiveConstant(jdk.vm.ci.meta.PrimitiveConstant) JavaConstant(jdk.vm.ci.meta.JavaConstant) PrimitiveConstant(jdk.vm.ci.meta.PrimitiveConstant) IntegerStamp(org.graalvm.compiler.core.common.type.IntegerStamp) IntegerLessThanNode(org.graalvm.compiler.nodes.calc.IntegerLessThanNode) JavaConstant(jdk.vm.ci.meta.JavaConstant)

Aggregations

IntegerBelowNode (org.graalvm.compiler.nodes.calc.IntegerBelowNode)5 IntegerStamp (org.graalvm.compiler.core.common.type.IntegerStamp)3 FixedGuardNode (org.graalvm.compiler.nodes.FixedGuardNode)3 LogicNode (org.graalvm.compiler.nodes.LogicNode)3 ValueNode (org.graalvm.compiler.nodes.ValueNode)3 IntegerLessThanNode (org.graalvm.compiler.nodes.calc.IntegerLessThanNode)3 JavaConstant (jdk.vm.ci.meta.JavaConstant)2 ConstantNode (org.graalvm.compiler.nodes.ConstantNode)2 CompareNode (org.graalvm.compiler.nodes.calc.CompareNode)2 IntegerEqualsNode (org.graalvm.compiler.nodes.calc.IntegerEqualsNode)2 ArrayList (java.util.ArrayList)1 Arrays (java.util.Arrays)1 Comparator (java.util.Comparator)1 HashMap (java.util.HashMap)1 List (java.util.List)1 Map (java.util.Map)1 Constant (jdk.vm.ci.meta.Constant)1 DeoptimizationAction (jdk.vm.ci.meta.DeoptimizationAction)1 DeoptimizationReason (jdk.vm.ci.meta.DeoptimizationReason)1 JavaKind (jdk.vm.ci.meta.JavaKind)1