# HG changeset patch # User Tom Rodriguez # Date 1423767076 28800 # Node ID 2778032e1beb9282d2bd41297c696e5a143d3dd7 # Parent a23984e249d280bb8a71273109a0f14108704d6d Simplify IfNode at Phi to help instanceof code generation diff -r a23984e249d2 -r 2778032e1beb graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java Thu Feb 12 17:15:19 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java Thu Feb 12 10:51:16 2015 -0800 @@ -189,6 +189,10 @@ return; } + if (splitIfAtPhi(tool)) { + return; + } + if (falseSuccessor().hasNoUsages() && (!(falseSuccessor() instanceof LoopExitNode)) && falseSuccessor().next() instanceof IfNode) { AbstractBeginNode intermediateBegin = falseSuccessor(); IfNode nextIf = (IfNode) intermediateBegin.next(); @@ -602,6 +606,137 @@ } /** + * Take an if that is immediately dominated by a merge with a single phi and split off any paths + * where the test would be statically decidable creating a new merge below the approriate side + * of the IfNode. Any undecidable tests will continue to use the original IfNode. + * + * @param tool + */ + @SuppressWarnings("unchecked") + private boolean splitIfAtPhi(SimplifierTool tool) { + if (!(predecessor() instanceof MergeNode)) { + return false; + } + MergeNode merge = (MergeNode) predecessor(); + if (merge.forwardEndCount() == 1) { + // Don't bother. + return false; + } + if (merge.usages().count() != 1 || merge.phis().count() != 1) { + return false; + } + if (merge.stateAfter() != null) { + /* We'll get the chance to simplify this after frame state assignment. */ + return false; + } + PhiNode phi = merge.phis().first(); + if (phi.usages().count() != 1 || condition().usages().count() != 1) { + /* + * For simplicity the below code assumes assumes the phi goes dead at the end so skip + * this case. + */ + return false; + } + + if (condition() instanceof Canonicalizable.Unary) { + Canonicalizable.Unary unary = (Canonicalizable.Unary) condition(); + if (unary.getValue() != phi) { + return false; + } + } else if (condition() instanceof Canonicalizable.Binary) { + Canonicalizable.Binary binary = (Canonicalizable.Binary) condition(); + if (binary.getX() != phi && binary.getY() != phi) { + return false; + } + } else { + return false; + } + + /* + * We could additionally filter for the case that at least some of the Phi inputs or one of + * the condition inputs are constants but there are cases where a non-constant is + * simplifiable, usually where the stamp allows the question to be answered. + */ + + /* Each successor of the if gets a new merge if needed. */ + MergeNode trueMerge = null; + MergeNode falseMerge = null; + assert merge.stateAfter() == null; + + for (AbstractEndNode end : merge.forwardEnds().snapshot()) { + Node value = phi.valueAt(end); + Node result = null; + if (condition() instanceof Canonicalizable.Binary) { + Canonicalizable.Binary compare = (Canonicalizable.Binary) condition; + if (compare.getX() == phi) { + result = compare.canonical(tool, value, compare.getY()); + } else { + result = compare.canonical(tool, compare.getX(), value); + } + } else { + assert condition() instanceof Canonicalizable.Unary; + Canonicalizable.Unary compare = (Canonicalizable.Unary) condition; + result = compare.canonical(tool, value); + } + if (result instanceof LogicConstantNode) { + merge.removeEnd(end); + if (((LogicConstantNode) result).getValue()) { + if (trueMerge == null) { + trueMerge = insertMerge(trueSuccessor()); + } + trueMerge.addForwardEnd(end); + } else { + if (falseMerge == null) { + falseMerge = insertMerge(falseSuccessor()); + } + falseMerge.addForwardEnd(end); + } + } + } + + cleanupMerge(tool, merge); + cleanupMerge(tool, trueMerge); + cleanupMerge(tool, falseMerge); + + return true; + } + + private void cleanupMerge(SimplifierTool tool, MergeNode merge) { + if (merge != null && merge.isAlive()) { + if (merge.forwardEndCount() == 0) { + GraphUtil.killCFG(merge, tool); + } else if (merge.forwardEndCount() == 1) { + graph().reduceTrivialMerge(merge); + } + } + } + + private MergeNode insertMerge(AbstractBeginNode begin) { + MergeNode merge = graph().add(new MergeNode()); + if (!begin.anchored().isEmpty()) { + Object before = null; + before = begin.anchored().snapshot(); + begin.replaceAtUsages(InputType.Guard, merge); + begin.replaceAtUsages(InputType.Anchor, merge); + assert begin.anchored().isEmpty() : before + " " + begin.anchored().snapshot(); + } + + AbstractBeginNode theBegin = begin; + if (begin instanceof LoopExitNode) { + // Insert an extra begin to make it easier. + theBegin = graph().add(new BeginNode()); + begin.replaceAtPredecessor(theBegin); + theBegin.setNext(begin); + } + FixedNode next = theBegin.next(); + next.replaceAtPredecessor(merge); + theBegin.setNext(graph().add(new EndNode())); + merge.addForwardEnd((EndNode) theBegin.next()); + merge.setNext(next); + return merge; + } + + /** * 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: *