Mercurial > hg > graal-compiler
changeset 22919:6b81cca49187
Fix machinery for elimination of pending tests
author | Tom Rodriguez <tom.rodriguez@oracle.com> |
---|---|
date | Thu, 29 Oct 2015 12:35:30 -0700 |
parents | 6a508ee4c7ef |
children | 85b76567ea2c |
files | graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ConditionalEliminationTest11.java graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ConditionalEliminationTestBase.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizingGuard.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DominatorConditionalEliminationPhase.java |
diffstat | 4 files changed, 211 insertions(+), 88 deletions(-) [+] |
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ConditionalEliminationTest11.java Fri Oct 30 10:46:56 2015 -0700 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ConditionalEliminationTest11.java Thu Oct 29 12:35:30 2015 -0700 @@ -112,34 +112,19 @@ testConditionalElimination("test4Snippet", "referenceSnippet"); } - @SuppressWarnings("all") - public static int reference5Snippet(int a) { - if ((a & 15) == 15) { + public static int test5Snippet(int a) { + if ((a & 5) == 5) { GraalDirectives.deoptimize(); } - if (a > 0) { - a |= 32; + if ((a & 7) != 0) { + return 0; } - return a; + return 1; } - @SuppressWarnings("all") - public static int test5Snippet(int a) { - if ((a & 8) != 8) { - GraalDirectives.deoptimize(); - } - if (a > 0) { - a |= 32; - } - if ((a & 15) == 15) { - GraalDirectives.deoptimize(); - } - return a; - } - - @Ignore @Test public void test5() { + // Shouldn't be possible to optimize this testConditionalElimination("test5Snippet", "test5Snippet"); } @@ -163,7 +148,83 @@ @Test public void test6() { - // Shouldn't be able to optimize this testConditionalElimination("test6Snippet", "reference6Snippet"); } + + public static int test7Snippet(int a) { + if ((a & 15) == 15) { + GraalDirectives.deoptimize(); + } + if ((a & 8) == 8) { + GraalDirectives.deoptimize(); + } + return a; + } + + public static int reference7Snippet(int a) { + if ((a & 8) == 8) { + GraalDirectives.deoptimize(); + } + return a; + } + + @Test + public void test7() { + testConditionalElimination("test7Snippet", "reference7Snippet"); + } + + public static int test8Snippet(int a) { + if ((a & 16) == 16) { + GraalDirectives.deoptimize(); + } + if ((a & 8) != 8) { + GraalDirectives.deoptimize(); + } + if ((a & 44) != 44) { + GraalDirectives.deoptimize(); + } + return a; + } + + public static int reference8Snippet(int a) { + if ((a & 60) != 44) { + GraalDirectives.deoptimize(); + } + return a; + } + + @Ignore("requires merging of bit tests") + @Test + public void test8() { + testConditionalElimination("test8Snippet", "reference8Snippet"); + } + + public static int test9Snippet(int a) { + if ((a & 16) == 16) { + GraalDirectives.deoptimize(); + } + if ((a & 8) != 8) { + GraalDirectives.deoptimize(); + } + if ((a & 44) != 44) { + GraalDirectives.deoptimize(); + } + if (a != 44) { + GraalDirectives.deoptimize(); + } + return a; + } + + public static int reference9Snippet(int a) { + if (a != 44) { + GraalDirectives.deoptimize(); + } + return a; + } + + @Test + public void test9() { + testConditionalElimination("test9Snippet", "reference9Snippet"); + } + }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ConditionalEliminationTestBase.java Fri Oct 30 10:46:56 2015 -0700 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ConditionalEliminationTestBase.java Thu Oct 29 12:35:30 2015 -0700 @@ -32,6 +32,7 @@ import com.oracle.graal.phases.common.CanonicalizerPhase; import com.oracle.graal.phases.common.ConvertDeoptimizeToGuardPhase; import com.oracle.graal.phases.common.DominatorConditionalEliminationPhase; +import com.oracle.graal.phases.common.IterativeConditionalEliminationPhase; import com.oracle.graal.phases.common.LoweringPhase; import com.oracle.graal.phases.schedule.SchedulePhase; import com.oracle.graal.phases.tiers.PhaseContext; @@ -73,7 +74,8 @@ try (Debug.Scope scope = Debug.scope("ConditionalEliminationTest", graph)) { canonicalizer1.apply(graph, context); new ConvertDeoptimizeToGuardPhase().apply(graph, context); - new DominatorConditionalEliminationPhase(true).apply(graph, context); + // new DominatorConditionalEliminationPhase(true).apply(graph, context); + new IterativeConditionalEliminationPhase(canonicalizer, true).apply(graph, context); canonicalizer.apply(graph, context); canonicalizer.apply(graph, context); new ConvertDeoptimizeToGuardPhase().apply(graph, context); @@ -81,7 +83,7 @@ Debug.handle(t); } StructuredGraph referenceGraph = parseEager(referenceSnippet, AllowAssumptions.YES); - try (Debug.Scope scope = Debug.scope("ConditionalEliminationTest.ReferenceGraph", graph)) { + try (Debug.Scope scope = Debug.scope("ConditionalEliminationTest.ReferenceGraph", referenceGraph)) { new ConvertDeoptimizeToGuardPhase().apply(referenceGraph, context); if (applyConditionalEliminationOnReference) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizingGuard.java Fri Oct 30 10:46:56 2015 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizingGuard.java Thu Oct 29 12:35:30 2015 -0700 @@ -45,4 +45,6 @@ JavaConstant getSpeculation(); boolean isNegated(); + + ValueNode asNode(); }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DominatorConditionalEliminationPhase.java Fri Oct 30 10:46:56 2015 -0700 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DominatorConditionalEliminationPhase.java Thu Oct 29 12:35:30 2015 -0700 @@ -55,6 +55,7 @@ import com.oracle.graal.nodes.BinaryOpLogicNode; import com.oracle.graal.nodes.ConditionAnchorNode; import com.oracle.graal.nodes.DeoptimizeNode; +import com.oracle.graal.nodes.DeoptimizingGuard; import com.oracle.graal.nodes.FixedGuardNode; import com.oracle.graal.nodes.FixedNode; import com.oracle.graal.nodes.GuardNode; @@ -138,50 +139,51 @@ } @Override + @SuppressWarnings("try") protected void run(StructuredGraph graph) { - Function<Block, Iterable<? extends Node>> blockToNodes; - Function<Node, Block> nodeToBlock; - Block startBlock; + try (Debug.Scope s = Debug.scope("DominatorConditionalElimination")) { + Function<Block, Iterable<? extends Node>> blockToNodes; + Function<Node, Block> nodeToBlock; + Block startBlock; - if (fullSchedule) { - SchedulePhase schedule = new SchedulePhase(SchedulePhase.SchedulingStrategy.EARLIEST); - schedule.apply(graph); - ControlFlowGraph cfg = schedule.getCFG(); - cfg.computePostdominators(); - blockToNodes = b -> schedule.getBlockToNodesMap().get(b); - nodeToBlock = n -> schedule.getNodeToBlockMap().get(n); - startBlock = cfg.getStartBlock(); - } else { - ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, true, true); - cfg.computePostdominators(); - BlockMap<List<FixedNode>> nodes = new BlockMap<>(cfg); - for (Block b : cfg.getBlocks()) { - ArrayList<FixedNode> curNodes = new ArrayList<>(); - for (FixedNode node : b.getNodes()) { - if (node instanceof AbstractBeginNode || node instanceof FixedGuardNode || node instanceof CheckCastNode || node instanceof ConditionAnchorNode || node instanceof IfNode) { - curNodes.add(node); + if (fullSchedule) { + SchedulePhase schedule = new SchedulePhase(SchedulePhase.SchedulingStrategy.EARLIEST); + schedule.apply(graph); + ControlFlowGraph cfg = schedule.getCFG(); + cfg.computePostdominators(); + blockToNodes = b -> schedule.getBlockToNodesMap().get(b); + nodeToBlock = n -> schedule.getNodeToBlockMap().get(n); + startBlock = cfg.getStartBlock(); + } else { + ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, true, true); + cfg.computePostdominators(); + BlockMap<List<FixedNode>> nodes = new BlockMap<>(cfg); + for (Block b : cfg.getBlocks()) { + ArrayList<FixedNode> curNodes = new ArrayList<>(); + for (FixedNode node : b.getNodes()) { + if (node instanceof AbstractBeginNode || node instanceof FixedGuardNode || node instanceof CheckCastNode || node instanceof ConditionAnchorNode || node instanceof IfNode) { + curNodes.add(node); + } } + nodes.put(b, curNodes); } - nodes.put(b, curNodes); + blockToNodes = b -> nodes.get(b); + nodeToBlock = n -> cfg.blockFor(n); + startBlock = cfg.getStartBlock(); } - blockToNodes = b -> nodes.get(b); - nodeToBlock = n -> cfg.blockFor(n); - startBlock = cfg.getStartBlock(); + + Instance instance = new Instance(graph, blockToNodes, nodeToBlock); + instance.processBlock(startBlock); } - - Instance instance = new Instance(graph, blockToNodes, nodeToBlock); - instance.processBlock(startBlock); } static class PendingTest { private final LogicNode condition; - private final boolean negated; - private final ValueNode guard; + private final DeoptimizingGuard guard; - public PendingTest(LogicNode condition, boolean negated, ValueNode guard) { + public PendingTest(LogicNode condition, DeoptimizingGuard guard) { this.condition = condition; - this.negated = negated; this.guard = guard; } } @@ -348,7 +350,7 @@ Stamp newStampY = binaryOpLogicNode.getSucceedingStampForY(negated); registerNewStamp(y, newStampY, guard, undoOperations); } - if (condition instanceof IntegerEqualsNode && guard instanceof FixedGuardNode && !negated) { + if (condition instanceof IntegerEqualsNode && guard instanceof DeoptimizingGuard && !negated) { if (y.isConstant() && x instanceof AndNode) { AndNode and = (AndNode) x; if (and.getY() == y) { @@ -360,52 +362,66 @@ BinaryOp<Or> op = ArithmeticOpTable.forStamp(x.stamp()).getOr(); IntegerStamp newStampX = (IntegerStamp) op.foldStamp(and.getX().stamp(), y.stamp()); registerNewStamp(and.getX(), newStampX, guard, undoOperations); - foldPendingTest(negated, guard, and.getX(), newStampX); } } } } - pendingTests.push(new PendingTest(condition, negated, guard)); + if (guard instanceof DeoptimizingGuard) { + pendingTests.push(new PendingTest(condition, (DeoptimizingGuard) guard)); + } registerCondition(condition, negated, guard, undoOperations); } - private void foldPendingTest(boolean negated, ValueNode guard, ValueNode originalX, IntegerStamp newStampX) { + private boolean foldPendingTest(DeoptimizingGuard thisGuard, ValueNode original, Stamp newStamp, GuardRewirer rewireGuardFunction) { for (PendingTest pending : pendingTests) { - if (pending.condition instanceof BinaryOpLogicNode) { - TriState result = TriState.UNKNOWN; + TriState result = TriState.UNKNOWN; + if (pending.condition instanceof UnaryOpLogicNode) { + UnaryOpLogicNode unaryLogicNode = (UnaryOpLogicNode) pending.condition; + if (unaryLogicNode.getValue() == original) { + result = unaryLogicNode.tryFold(newStamp); + if (result.isKnown()) { + Debug.log("unary %s %s %1s", result, newStamp, unaryLogicNode); + } + } + } else if (pending.condition instanceof BinaryOpLogicNode) { BinaryOpLogicNode binaryOpLogicNode = (BinaryOpLogicNode) pending.condition; ValueNode x = binaryOpLogicNode.getX(); ValueNode y = binaryOpLogicNode.getY(); - if (binaryOpLogicNode.getX() == originalX) { - result = binaryOpLogicNode.tryFold(newStampX, binaryOpLogicNode.getY().stamp()); + if (binaryOpLogicNode.getX() == original) { + result = binaryOpLogicNode.tryFold(newStamp, binaryOpLogicNode.getY().stamp()); } else if (binaryOpLogicNode instanceof IntegerEqualsNode && y.isConstant() && x instanceof AndNode) { - AndNode and2 = (AndNode) x; - if (and2.getY() == y) { - BinaryOp<And> andOp = ArithmeticOpTable.forStamp(originalX.stamp()).getAnd(); - result = binaryOpLogicNode.tryFold(andOp.foldStamp(newStampX, y.stamp()), y.stamp()); - } - } - /* - * If the failure of the pending guard would also be triggered by the failure of - * this guard, then it's safe to replace the earlier guard with this guard. - */ - if (result.isKnown()) { - if (pending.guard instanceof FixedGuardNode && guard instanceof FixedGuardNode) { - FixedGuardNode fix = (FixedGuardNode) pending.guard; - FixedGuardNode thisGuard = (FixedGuardNode) guard; - if (fix.getAction() == thisGuard.getAction() && fix.getReason() == thisGuard.getReason() && fix.getSpeculation() == thisGuard.getSpeculation()) { - if (pending.negated == negated && result.isTrue() || pending.negated && result.isFalse()) { - assert !negated; - FixedGuardNode newFix = (FixedGuardNode) thisGuard.copyWithInputs(); - guard.graph().replaceFixedWithFixed(fix, newFix); - guard.replaceAtUsages(newFix); - guard.graph().removeFixed(thisGuard); - } - } + AndNode and = (AndNode) x; + if (and.getY() == y && and.getX() == original) { + BinaryOp<And> andOp = ArithmeticOpTable.forStamp(newStamp).getAnd(); + result = binaryOpLogicNode.tryFold(andOp.foldStamp(newStamp, y.stamp()), y.stamp()); } } } + if (result.isKnown()) { + if (foldGuard(thisGuard, pending.guard, result, rewireGuardFunction)) { + return true; + } + } } + return false; + } + + private boolean foldGuard(DeoptimizingGuard thisGuard, DeoptimizingGuard otherGuard, TriState testResult, GuardRewirer rewireGuardFunction) { + if (otherGuard.getAction() == thisGuard.getAction() && otherGuard.getReason() == thisGuard.getReason() && otherGuard.getSpeculation() == thisGuard.getSpeculation()) { + LogicNode condition = (LogicNode) thisGuard.getCondition().copyWithInputs(); + GuardRewirer rewirer = (guard, result) -> { + if (rewireGuardFunction.rewire(guard, result)) { + otherGuard.setCondition(condition, thisGuard.isNegated()); + return true; + } + condition.safeDelete(); + return false; + }; + // Move the later test up + Debug.log("Folding guard %s %s %1s %s %1s %s\n", testResult, otherGuard, otherGuard.getCondition(), thisGuard, thisGuard.getCondition(), thisGuard.asNode().graph()); + return rewireGuards(otherGuard.asNode(), !thisGuard.isNegated(), rewirer); + } + return false; } private void registerCondition(LogicNode condition, boolean negated, ValueNode guard, List<Runnable> undoOperations) { @@ -463,6 +479,10 @@ } private boolean tryProofCondition(LogicNode node, GuardRewirer rewireGuardFunction) { + return tryProofGuardCondition(null, node, rewireGuardFunction); + } + + private boolean tryProofGuardCondition(DeoptimizingGuard thisGuard, LogicNode node, GuardRewirer rewireGuardFunction) { for (InfoElement infoElement : getInfoElements(node)) { Stamp stamp = infoElement.getStamp(); JavaConstant constant = (JavaConstant) stamp.asConstant(); @@ -480,6 +500,13 @@ return rewireGuards(infoElement.getGuard(), result.toBoolean(), rewireGuardFunction); } } + if (thisGuard != null && unaryLogicNode.stamp() instanceof IntegerStamp) { + Stamp newStamp = unaryLogicNode.getSucceedingStampForValue(thisGuard.isNegated()); + if (newStamp != null && foldPendingTest(thisGuard, unaryLogicNode.getValue(), newStamp, rewireGuardFunction)) { + return true; + } + + } } else if (node instanceof BinaryOpLogicNode) { BinaryOpLogicNode binaryOpLogicNode = (BinaryOpLogicNode) node; for (InfoElement infoElement : getInfoElements(binaryOpLogicNode)) { @@ -524,6 +551,37 @@ } } } + if (thisGuard != null && binaryOpLogicNode instanceof IntegerEqualsNode && !thisGuard.isNegated()) { + if (y.isConstant() && x instanceof AndNode) { + AndNode and = (AndNode) x; + if (and.getY() == y) { + /* + * This 'and' proves something about some of the bits in and.getX(). + * It's equivalent to or'ing in the mask value since those values are + * known to be set. + */ + BinaryOp<Or> op = ArithmeticOpTable.forStamp(x.stamp()).getOr(); + IntegerStamp newStampX = (IntegerStamp) op.foldStamp(and.getX().stamp(), y.stamp()); + if (foldPendingTest(thisGuard, and.getX(), newStampX, rewireGuardFunction)) { + return true; + } + } + } + } + if (thisGuard != null) { + if (!x.isConstant()) { + Stamp newStampX = binaryOpLogicNode.getSucceedingStampForX(thisGuard.isNegated()); + if (newStampX != null && foldPendingTest(thisGuard, x, newStampX, rewireGuardFunction)) { + return true; + } + } + if (!y.isConstant()) { + Stamp newStampY = binaryOpLogicNode.getSucceedingStampForY(thisGuard.isNegated()); + if (newStampY != null && foldPendingTest(thisGuard, y, newStampY, rewireGuardFunction)) { + return true; + } + } + } } else if (node instanceof ShortCircuitOrNode) { final ShortCircuitOrNode shortCircuitOrNode = (ShortCircuitOrNode) node; if (this.loopExits.isEmpty()) { @@ -576,7 +634,7 @@ } private void processGuard(GuardNode node, List<Runnable> undoOperations) { - if (!tryProofCondition(node.getCondition(), (guard, result) -> { + if (!tryProofGuardCondition(node, node.getCondition(), (guard, result) -> { if (result != node.isNegated()) { node.replaceAndDelete(guard); } else { @@ -593,7 +651,7 @@ } private void processFixedGuard(FixedGuardNode node, List<Runnable> undoOperations) { - if (!tryProofCondition(node.condition(), (guard, result) -> { + if (!tryProofGuardCondition(node, node.condition(), (guard, result) -> { if (result != node.isNegated()) { node.replaceAtUsages(guard); GraphUtil.unlinkFixedNode(node);