changeset 4310:72d099e5be61

more CanonicalizerPhase simplifications, added Simplifiable interface
author Lukas Stadler <lukas.stadler@jku.at>
date Wed, 18 Jan 2012 15:09:19 +0100
parents 4a609a685fa4
children 8e2c4affcd51
files graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/CanonicalizerPhase.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/SnippetIntrinsificationPhase.java graal/com.oracle.max.graal.graph/src/com/oracle/max/graal/graph/Node.java graal/com.oracle.max.graal.java/src/com/oracle/max/graal/java/GraphBuilderPhase.java graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/AnchorNode.java graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/BeginNode.java graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/FixedGuardNode.java graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/FrameState.java graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/IfNode.java graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/InvokeNode.java graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/InvokeWithExceptionNode.java graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/PhiNode.java graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/StructuredGraph.java graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/extended/ValueAnchorNode.java graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/java/NewArrayNode.java graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/java/RegisterFinalizerNode.java graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/spi/CanonicalizerTool.java graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/spi/Simplifiable.java graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/spi/SimplifierTool.java
diffstat 19 files changed, 224 insertions(+), 161 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/CanonicalizerPhase.java	Tue Jan 17 19:45:39 2012 +0100
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/CanonicalizerPhase.java	Wed Jan 18 15:09:19 2012 +0100
@@ -26,7 +26,6 @@
 import com.oracle.max.cri.ri.*;
 import com.oracle.max.criutils.*;
 import com.oracle.max.graal.compiler.*;
-import com.oracle.max.graal.compiler.util.*;
 import com.oracle.max.graal.graph.*;
 import com.oracle.max.graal.nodes.*;
 import com.oracle.max.graal.nodes.calc.*;
@@ -73,50 +72,45 @@
 //     cases:                                           original node:
 //                                         |Floating|Fixed-unconnected|Fixed-connected|
 //                                         --------------------------------------------
-//                                     null|   1    |        X        |       1       |
+//                                     null|   1    |        X        |       3       |
 //                                         --------------------------------------------
 //                                 Floating|   2    |        X        |       4       |
 //       canonical node:                   --------------------------------------------
-//                        Fixed-unconnected|   X    |        X        |       3       |
+//                        Fixed-unconnected|   X    |        X        |       5       |
 //                                         --------------------------------------------
-//                          Fixed-connected|   2    |        X        |       4       |
+//                          Fixed-connected|   2    |        X        |       6       |
 //                                         --------------------------------------------
 //       X: must not happen (checked with assertions)
-                if (canonical == null) {
-                    // case 1
-                    node.replaceAtUsages(null);
-                    if (Util.isFixed(node)) {
-                        graph.removeFixed((FixedWithNextNode) node);
+                if (canonical != node) {
+                    if (node instanceof FloatingNode) {
+                        if (canonical == null) {
+                            // case 1
+                            graph.removeFloating((FloatingNode) node);
+                        } else {
+                            // case 2
+                            assert canonical instanceof FloatingNode || (canonical instanceof FixedNode && canonical.predecessor() != null) : node + " -> " + canonical +
+                                            " : replacement should be floating or fixed and connected";
+                            graph.replaceFloating((FloatingNode) node, canonical);
+                        }
                     } else {
-                        graph.removeFloating((FloatingNode) node);
-                    }
-                } else if (canonical != node) {
-                    if (node instanceof FloatingNode) {
-                        // case 2
-                        assert Util.isFloating(canonical) || (Util.isFixed(canonical) && canonical.predecessor() != null) : canonical;
-                        graph.replaceFloating((FloatingNode) node, canonical);
-                    } else {
-                        assert Util.isFixed(node) && node.predecessor() != null : node + " -> " + canonical + " : node should be fixed & connected (" + node.predecessor() + ")";
-                        if (Util.isFixed(canonical) && canonical.predecessor() == null) {
+                        assert node instanceof FixedWithNextNode && node.predecessor() != null : node + " -> " + canonical + " : node should be fixed & connected (" + node.predecessor() + ")";
+                        if (canonical == null) {
                             // case 3
-                            graph.replaceFixedWithFixed((FixedWithNextNode) node, (FixedWithNextNode) canonical);
-                        } else {
+                            graph.removeFixed((FixedWithNextNode) node);
+                        } else if (canonical instanceof FloatingNode) {
                             // case 4
-                            node.replaceAtUsages(canonical);
-                            if (node instanceof FixedWithNextNode) {
+                            graph.replaceFixedWithFloating((FixedWithNextNode) node, (FloatingNode) canonical);
+                        } else {
+                            assert canonical instanceof FixedNode;
+                            if (canonical.predecessor() == null) {
+                                assert !canonical.cfgSuccessors().iterator().hasNext() : "replacement " + canonical + " shouldn't have successors";
+                                // case 5
+                                graph.replaceFixedWithFixed((FixedWithNextNode) node, (FixedWithNextNode) canonical);
+                            } else {
+                                assert canonical.cfgSuccessors().iterator().hasNext() : "replacement " + canonical + " should have successors";
+                                // case 6
+                                node.replaceAtUsages(canonical);
                                 graph.removeFixed((FixedWithNextNode) node);
-                            } else if (node instanceof ControlSplitNode) {
-                                // FIX(ls) is this logic really used? the semantics might be hard to understand...
-                                ControlSplitNode split = (ControlSplitNode) node;
-                                int survivingSuccessor = -1;
-                                for (int i = 0; i < split.blockSuccessorCount(); i++) {
-                                    if (survivingSuccessor == -1 && split.blockSuccessor(i) != null) {
-                                        survivingSuccessor = i;
-                                    } else {
-                                        assert split.blockSuccessor(i) == null;
-                                    }
-                                }
-                                graph.removeSplit(split, survivingSuccessor);
                             }
                         }
                     }
@@ -128,6 +122,8 @@
                         nodeWorkList.replaced(canonical, node, false);
                     }
                 }
+            } else if (node instanceof Simplifiable) {
+                ((Simplifiable) node).simplify(tool);
             }
         }
 
@@ -148,7 +144,7 @@
         }
     }
 
-    private static final class Tool implements CanonicalizerTool {
+    private static final class Tool implements SimplifierTool {
 
         private final NodeWorkList nodeWorkList;
         private final RiRuntime runtime;
@@ -222,8 +218,10 @@
                         FixedNode next = merge.next();
                         merge.setNext(null);
                         pred.replaceFirstSuccessor(replacedSux, next);
-                        if (merge.stateAfter().usages().size() == 1) {
-                            merge.stateAfter().delete();
+                        FrameState stateAfter = merge.stateAfter();
+                        merge.setStateAfter(null);
+                        if (stateAfter.usages().isEmpty()) {
+                            stateAfter.safeDelete();
                         }
                         merge.safeDelete();
                         replacedSux.safeDelete();
@@ -268,5 +266,10 @@
         public RiRuntime runtime() {
             return runtime;
         }
+
+        @Override
+        public void addToWorkList(Node node) {
+            nodeWorkList.add(node);
+        }
     }
 }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/SnippetIntrinsificationPhase.java	Tue Jan 17 19:45:39 2012 +0100
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/SnippetIntrinsificationPhase.java	Wed Jan 18 15:09:19 2012 +0100
@@ -124,15 +124,21 @@
                                 Invoke invokeNode = (Invoke) node;
                                 MethodCallTargetNode callTarget = invokeNode.callTarget();
                                 if (pool.isBoxingMethod(callTarget.targetMethod())) {
+                                    FrameState stateAfter = invokeNode.stateAfter();
+                                    assert stateAfter.usages().size() == 1;
+                                    invokeNode.node().replaceAtUsages(null);
+                                    ValueNode result = callTarget.arguments().get(0);
+                                    StructuredGraph graph = (StructuredGraph) node.graph();
                                     if (invokeNode instanceof InvokeWithExceptionNode) {
                                         // Destroy exception edge & clear stateAfter.
                                         InvokeWithExceptionNode invokeWithExceptionNode = (InvokeWithExceptionNode) invokeNode;
+
                                         invokeWithExceptionNode.killExceptionEdge();
+                                        graph.removeSplit(invokeWithExceptionNode, InvokeWithExceptionNode.NORMAL_EDGE);
+                                    } else {
+                                        graph.removeFixed((InvokeNode) invokeNode);
                                     }
-                                    assert invokeNode.stateAfter().usages().size() == 1;
-                                    invokeNode.stateAfter().delete();
-                                    invokeNode.node().replaceAndDelete(invokeNode.next());
-                                    ValueNode result = callTarget.arguments().get(0);
+                                    stateAfter.safeDelete();
                                     GraphUtil.propagateKill(callTarget);
                                     return result;
                                 }
--- a/graal/com.oracle.max.graal.graph/src/com/oracle/max/graal/graph/Node.java	Tue Jan 17 19:45:39 2012 +0100
+++ b/graal/com.oracle.max.graal.graph/src/com/oracle/max/graal/graph/Node.java	Wed Jan 18 15:09:19 2012 +0100
@@ -311,7 +311,7 @@
         delete();
     }
 
-    public void delete() {
+    private void delete() {
         clearInputs();
         clearSuccessors();
         graph.unregister(this);
--- a/graal/com.oracle.max.graal.java/src/com/oracle/max/graal/java/GraphBuilderPhase.java	Tue Jan 17 19:45:39 2012 +0100
+++ b/graal/com.oracle.max.graal.java/src/com/oracle/max/graal/java/GraphBuilderPhase.java	Wed Jan 18 15:09:19 2012 +0100
@@ -1330,8 +1330,8 @@
                 EndNode loopEntryEnd = begin.forwardEdge();
                 FixedNode beginSucc = begin.next();
                 FrameState stateAfter = begin.stateAfter();
-                stateAfter.delete();
                 begin.safeDelete();
+                stateAfter.safeDelete();
                 loopEntryEnd.replaceAndDelete(beginSucc);
             }
         }
--- a/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/AnchorNode.java	Tue Jan 17 19:45:39 2012 +0100
+++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/AnchorNode.java	Wed Jan 18 15:09:19 2012 +0100
@@ -44,7 +44,7 @@
     @Override
     public ValueNode canonical(CanonicalizerTool tool) {
         if (this.usages().size() == 0 && guards.size() == 0) {
-            return next();
+            return null;
         }
         return this;
     }
--- a/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/BeginNode.java	Tue Jan 17 19:45:39 2012 +0100
+++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/BeginNode.java	Wed Jan 18 15:09:19 2012 +0100
@@ -28,7 +28,7 @@
 import com.oracle.max.graal.nodes.spi.*;
 import com.oracle.max.graal.nodes.type.*;
 
-public class BeginNode extends AbstractStateSplit implements LIRLowerable, Canonicalizable {
+public class BeginNode extends AbstractStateSplit implements LIRLowerable, Simplifiable {
     public BeginNode() {
         super(StampFactory.illegal());
     }
@@ -50,22 +50,23 @@
     }
 
     @Override
-    public ValueNode canonical(CanonicalizerTool tool) {
+    public void simplify(SimplifierTool tool) {
         FixedNode prev = (FixedNode) this.predecessor();
         if (prev == null) {
             // This is the start node.
-            return this;
         } else if (prev instanceof ControlSplitNode) {
             // This begin node is necessary.
-            return this;
         } else {
             // This begin node can be removed and all guards moved up to the preceding begin node.
             Node prevBegin = prev;
             while (!(prevBegin instanceof BeginNode)) {
                 prevBegin = prevBegin.predecessor();
             }
-            this.replaceAtUsages(prevBegin);
-            return next();
+            for (Node usage : usages()) {
+                tool.addToWorkList(usage);
+            }
+            replaceAtUsages(prevBegin);
+            ((StructuredGraph) graph()).removeFixed(this);
         }
     }
 
--- a/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/FixedGuardNode.java	Tue Jan 17 19:45:39 2012 +0100
+++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/FixedGuardNode.java	Wed Jan 18 15:09:19 2012 +0100
@@ -28,7 +28,7 @@
 import com.oracle.max.graal.nodes.spi.*;
 import com.oracle.max.graal.nodes.type.*;
 
-public final class FixedGuardNode extends FixedWithNextNode implements Canonicalizable, Lowerable, LIRLowerable {
+public final class FixedGuardNode extends FixedWithNextNode implements Simplifiable, Lowerable, LIRLowerable {
 
     @Input private final NodeInputList<BooleanNode> conditions;
 
@@ -53,7 +53,7 @@
     }
 
     @Override
-    public ValueNode canonical(CanonicalizerTool tool) {
+    public void simplify(SimplifierTool tool) {
         for (BooleanNode n : conditions.snapshot()) {
             if (n instanceof ConstantNode) {
                 ConstantNode c = (ConstantNode) n;
@@ -61,18 +61,17 @@
                     conditions.remove(n);
                 } else {
                     FixedNode next = this.next();
+                    setNext(graph().add(new DeoptimizeNode(DeoptAction.InvalidateRecompile)));
                     if (next != null) {
                         tool.deleteBranch(next);
                     }
-                    return graph().add(new DeoptimizeNode(DeoptAction.InvalidateRecompile));
+                    return;
                 }
             }
         }
-
         if (conditions.isEmpty()) {
-            return next();
+            ((StructuredGraph) graph()).removeFixed(this);
         }
-        return this;
     }
 
     @Override
--- a/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/FrameState.java	Tue Jan 17 19:45:39 2012 +0100
+++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/FrameState.java	Wed Jan 18 15:09:19 2012 +0100
@@ -476,7 +476,7 @@
         if (!phiNode.isDeleted()) {
             Collection<PhiNode> phiUsages = phiNode.usages().filter(PhiNode.class).snapshot();
             phiNode.replaceAtUsages(null);
-            phiNode.delete();
+            phiNode.safeDelete();
             for (Node n : phiUsages) {
                 deleteInvalidPhi((PhiNode) n);
             }
--- a/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/IfNode.java	Tue Jan 17 19:45:39 2012 +0100
+++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/IfNode.java	Wed Jan 18 15:09:19 2012 +0100
@@ -22,6 +22,9 @@
  */
 package com.oracle.max.graal.nodes;
 
+import java.util.*;
+
+import com.oracle.max.cri.ci.*;
 import com.oracle.max.graal.nodes.spi.*;
 import com.oracle.max.graal.nodes.type.*;
 
@@ -29,7 +32,9 @@
  * The {@code IfNode} represents a branch that can go one of two directions depending on the outcome of a
  * comparison.
  */
-public final class IfNode extends ControlSplitNode implements Canonicalizable, LIRLowerable {
+public final class IfNode extends ControlSplitNode implements Simplifiable, LIRLowerable {
+    public static final int TRUE_EDGE = 0;
+    public static final int FALSE_EDGE = 1;
 
     private static final BeginNode[] EMPTY_IF_SUCCESSORS = new BeginNode[] {null, null};
 
@@ -99,35 +104,76 @@
     }
 
     @Override
-    public ValueNode canonical(CanonicalizerTool tool) {
+    public void simplify(SimplifierTool tool) {
         if (compare() instanceof ConstantNode) {
             ConstantNode c = (ConstantNode) compare();
             if (c.asConstant().asBoolean()) {
                 tool.deleteBranch(falseSuccessor());
-                return trueSuccessor();
+                tool.addToWorkList(trueSuccessor());
+                ((StructuredGraph) graph()).removeSplit(this, TRUE_EDGE);
             } else {
                 tool.deleteBranch(trueSuccessor());
-                return falseSuccessor();
+                tool.addToWorkList(falseSuccessor());
+                ((StructuredGraph) graph()).removeSplit(this, FALSE_EDGE);
+            }
+        } else {
+            if (trueSuccessor().next() instanceof EndNode && falseSuccessor().next() instanceof EndNode) {
+                EndNode trueEnd = (EndNode) trueSuccessor().next();
+                EndNode falseEnd = (EndNode) falseSuccessor().next();
+                MergeNode merge = trueEnd.merge();
+                if (merge == falseEnd.merge() && merge.endCount() == 2) {
+                    Iterator<PhiNode> phis = merge.phis().iterator();
+                    if (!phis.hasNext()) {
+                        // empty if construct with no phis: remove it
+                        removeEmptyIf(tool);
+                    } else {
+                        PhiNode singlePhi = phis.next();
+                        if (!phis.hasNext()) {
+                            // one phi at the merge of an otherwise empty if construct: try to convert into a MaterializeNode
+                            boolean inverted = trueEnd == merge.endAt(FALSE_EDGE);
+                            ValueNode trueValue = singlePhi.valueAt(inverted ? 1 : 0);
+                            ValueNode falseValue = singlePhi.valueAt(inverted ? 0 : 1);
+                            if (trueValue.kind() != falseValue.kind()) {
+                                return;
+                            }
+                            if (trueValue.kind() != CiKind.Int && trueValue.kind() != CiKind.Long) {
+                                return;
+                            }
+                            if (trueValue.isConstant() && falseValue.isConstant()) {
+                                MaterializeNode materialize = MaterializeNode.create(compare(), graph(), (ConstantNode) trueValue, (ConstantNode) falseValue);
+                                ((StructuredGraph) graph()).replaceFloating(singlePhi, materialize);
+                                removeEmptyIf(tool);
+                            }
+                        }
+                    }
+                }
             }
         }
-        if (trueSuccessor().next() instanceof EndNode && falseSuccessor().next() instanceof EndNode) {
-            EndNode trueEnd = (EndNode) trueSuccessor().next();
-            EndNode falseEnd = (EndNode) falseSuccessor().next();
-            MergeNode merge = trueEnd.merge();
-            if (merge == falseEnd.merge() && !merge.phis().iterator().hasNext() && merge.endCount() == 2) {
-                FixedNode next = merge.next();
-                merge.safeDelete();
-                BeginNode falseSuccessor = this.falseSuccessor();
-                BeginNode trueSuccessor = this.trueSuccessor();
-                this.setTrueSuccessor(null);
-                this.setFalseSuccessor(null);
-                trueSuccessor.safeDelete();
-                falseSuccessor.safeDelete();
-                trueEnd.safeDelete();
-                falseEnd.safeDelete();
-                return next;
-            }
-        }
-        return this;
+    }
+
+    private void removeEmptyIf(SimplifierTool tool) {
+        BeginNode trueSuccessor = trueSuccessor();
+        BeginNode falseSuccessor = falseSuccessor();
+        assert trueSuccessor.next() instanceof EndNode && falseSuccessor.next() instanceof EndNode;
+
+        EndNode trueEnd = (EndNode) trueSuccessor.next();
+        EndNode falseEnd = (EndNode) falseSuccessor.next();
+        assert trueEnd.merge() == falseEnd.merge();
+
+        MergeNode merge = trueEnd.merge();
+        assert merge.usages().isEmpty();
+
+        FixedNode next = merge.next();
+        merge.setNext(null);
+        setTrueSuccessor(null);
+        setFalseSuccessor(null);
+        ((FixedWithNextNode) predecessor()).setNext(next);
+        safeDelete();
+        trueSuccessor.safeDelete();
+        falseSuccessor.safeDelete();
+        merge.safeDelete();
+        trueEnd.safeDelete();
+        falseEnd.safeDelete();
+        tool.addToWorkList(next);
     }
 }
--- a/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/InvokeNode.java	Tue Jan 17 19:45:39 2012 +0100
+++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/InvokeNode.java	Wed Jan 18 15:09:19 2012 +0100
@@ -96,14 +96,11 @@
 
     @Override
     public void intrinsify(Node node) {
-        this.callTarget.delete();
+        MethodCallTargetNode call = callTarget;
+        FrameState stateAfter = stateAfter();
         if (node instanceof StateSplit) {
             StateSplit stateSplit = (StateSplit) node;
-            stateSplit.setStateAfter(stateAfter());
-        } else {
-            if (stateAfter().usages().size() == 1) {
-                stateAfter().delete();
-            }
+            stateSplit.setStateAfter(stateAfter);
         }
         if (node == null) {
             assert kind() == CiKind.Void && usages().isEmpty();
@@ -111,5 +108,9 @@
         } else {
             ((StructuredGraph) graph()).replaceFixed(this, node);
         }
+        call.safeDelete();
+        if (stateAfter.usages().isEmpty()) {
+            stateAfter.safeDelete();
+        }
     }
 }
--- a/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/InvokeWithExceptionNode.java	Tue Jan 17 19:45:39 2012 +0100
+++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/InvokeWithExceptionNode.java	Wed Jan 18 15:09:19 2012 +0100
@@ -140,15 +140,12 @@
 
     @Override
     public void intrinsify(Node node) {
-        this.callTarget.delete();
+        MethodCallTargetNode call = callTarget;
+        FrameState state = stateAfter();
         killExceptionEdge();
         if (node instanceof StateSplit) {
             StateSplit stateSplit = (StateSplit) node;
-            stateSplit.setStateAfter(stateAfter());
-        } else {
-            if (stateAfter().usages().size() == 1) {
-                stateAfter().delete();
-            }
+            stateSplit.setStateAfter(state);
         }
         if (node == null) {
             assert kind() == CiKind.Void && usages().isEmpty();
@@ -156,5 +153,9 @@
         } else {
             ((StructuredGraph) graph()).replaceSplit(this, node, NORMAL_EDGE);
         }
+        call.safeDelete();
+        if (state.usages().isEmpty()) {
+            state.safeDelete();
+        }
     }
 }
--- a/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/PhiNode.java	Tue Jan 17 19:45:39 2012 +0100
+++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/PhiNode.java	Wed Jan 18 15:09:19 2012 +0100
@@ -167,66 +167,7 @@
             return singleValue;
         }
 
-        return canonicalizeMaterializationPhi();
-    }
-
-    private ValueNode canonicalizeMaterializationPhi() {
-        if (merge().endCount() != 2 || merge() instanceof LoopBeginNode) {
-            return this;
-        }
-        if (merge().usages().size() > 1) { // TODO(gd) disable canonicalization of multiple conditional while we are not able to fuse them and the potentially leftover If in the backend
-            return this;
-        }
-
-        Node end0 = merge().endAt(0);
-        Node end1 = merge().endAt(1);
-        Node endPred0 = end0.predecessor();
-        Node endPred1 = end1.predecessor();
-        if (!(endPred0 instanceof BeginNode) || !(endPred1 instanceof BeginNode)) {
-            return this;
-        }
-        if (endPred0.predecessor() != endPred1.predecessor() || !(endPred0.predecessor() instanceof IfNode)) {
-            return this;
-        }
-
-        // Get true/false value.
-        IfNode ifNode = (IfNode) endPred0.predecessor();
-        boolean inverted = ifNode.trueSuccessor() == endPred1;
-        ValueNode trueValue = valueAt(inverted ? 1 : 0);
-        ValueNode falseValue = valueAt(inverted ? 0 : 1);
-        if (trueValue.kind() != falseValue.kind()) {
-            return this;
-        }
-
-        // Only allow int constants.
-        if (trueValue.kind() != CiKind.Int || !trueValue.isConstant() || !falseValue.isConstant()) {
-            return this;
-        }
-
-        ConstantNode trueConstantNode = (ConstantNode) trueValue;
-        ConstantNode falseConstantNode = (ConstantNode) falseValue;
-        BooleanNode compare = ifNode.compare();
-        removeIfNode(ifNode);
-        return MaterializeNode.create(compare, ifNode.graph(), trueConstantNode, falseConstantNode);
-    }
-
-    private void removeIfNode(IfNode ifNode) {
-        FixedNode next = merge().next();
-        EndNode end1 = this.merge.endAt(0);
-        EndNode end2 = this.merge.endAt(1);
-        BeginNode trueSuccessor = ifNode.trueSuccessor();
-        BeginNode falseSuccessor = ifNode.falseSuccessor();
-        merge().setNext(null);
-        ifNode.setTrueSuccessor(null);
-        ifNode.setFalseSuccessor(null);
-        ifNode.replaceAndDelete(next);
-        updateUsages(this.merge, null);
-        this.merge.safeDelete();
-        this.merge = null;
-        trueSuccessor.safeDelete();
-        falseSuccessor.safeDelete();
-        end1.safeDelete();
-        end2.safeDelete();
+        return this;
     }
 
     public ValueNode firstValue() {
--- a/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/StructuredGraph.java	Tue Jan 17 19:45:39 2012 +0100
+++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/StructuredGraph.java	Wed Jan 18 15:09:19 2012 +0100
@@ -153,7 +153,7 @@
 
     public void removeFixed(FixedWithNextNode node) {
         assert node != null;
-        assert node.usages().isEmpty();
+        assert node.usages().isEmpty() : node + " " + node.usages();
         FixedNode next = node.next();
         node.setNext(null);
         node.replaceAtPredecessors(next);
--- a/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/extended/ValueAnchorNode.java	Tue Jan 17 19:45:39 2012 +0100
+++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/extended/ValueAnchorNode.java	Wed Jan 18 15:09:19 2012 +0100
@@ -54,17 +54,17 @@
     @Override
     public ValueNode canonical(CanonicalizerTool tool) {
         if (object == null) {
-            return next();
+            return null;
         }
         if (object instanceof ConstantNode) {
-            return next();
+            return null;
         }
         if (object instanceof IntegerDivNode || object instanceof IntegerRemNode) {
             if (((ArithmeticNode) object).y().isConstant()) {
                 CiConstant  constant = ((ArithmeticNode) object).y().asConstant();
                 assert constant.kind == object.kind() : constant.kind + " != " + object.kind();
                 if (constant.asLong() != 0) {
-                    return next();
+                    return null;
                 }
             }
         }
--- a/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/java/NewArrayNode.java	Tue Jan 17 19:45:39 2012 +0100
+++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/java/NewArrayNode.java	Wed Jan 18 15:09:19 2012 +0100
@@ -111,7 +111,7 @@
             if (usage instanceof ArrayLengthNode) {
                 ArrayLengthNode x = (ArrayLengthNode) usage;
                 StructuredGraph graph = (StructuredGraph) node.graph();
-                node.replaceAtUsages(((NewArrayNode) node).dimension(0));
+                x.replaceAtUsages(((NewArrayNode) node).dimension(0));
                 graph.removeFixed(x);
             } else {
                 super.beforeUpdate(node, usage);
--- a/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/java/RegisterFinalizerNode.java	Tue Jan 17 19:45:39 2012 +0100
+++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/java/RegisterFinalizerNode.java	Wed Jan 18 15:09:19 2012 +0100
@@ -71,7 +71,7 @@
         }
 
         if (!needsCheck) {
-            return next();
+            return null;
         }
 
         return this;
--- a/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/spi/CanonicalizerTool.java	Tue Jan 17 19:45:39 2012 +0100
+++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/spi/CanonicalizerTool.java	Wed Jan 18 15:09:19 2012 +0100
@@ -24,11 +24,9 @@
 
 import com.oracle.max.cri.ci.*;
 import com.oracle.max.cri.ri.*;
-import com.oracle.max.graal.nodes.*;
 
 
 public interface CanonicalizerTool {
-    void deleteBranch(FixedNode branch);
     CiTarget target();
     CiAssumptions assumptions();
     RiRuntime runtime();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/spi/Simplifiable.java	Wed Jan 18 15:09:19 2012 +0100
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.max.graal.nodes.spi;
+
+/**
+ * This interface allows nodes to perform more complicated simplifications, in contrast to {@link Canonicalizable},
+ * which supports only replacing the current node.
+ *
+ * Implementors of this interface need to be aware that they need to call {@link SimplifierTool#addToWorkList(com.oracle.max.graal.graph.Node)} for each node that might
+ * be influenced (in terms of simplification and canonicalization) by the actions performed in simplify.
+ */
+public interface Simplifiable {
+
+    void simplify(SimplifierTool tool);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/spi/SimplifierTool.java	Wed Jan 18 15:09:19 2012 +0100
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.max.graal.nodes.spi;
+
+import com.oracle.max.graal.graph.*;
+import com.oracle.max.graal.nodes.*;
+
+
+public interface SimplifierTool extends CanonicalizerTool {
+    void deleteBranch(FixedNode branch);
+    void addToWorkList(Node node);
+}