diff graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java @ 9049:6d376d09880b

Make CanonicalizerPhase reentrant.
author Roland Schatz <roland.schatz@oracle.com>
date Fri, 12 Apr 2013 13:50:45 +0200
parents 961ad124cb21
children 908cac5f443c
line wrap: on
line diff
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Fri Apr 12 13:49:29 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Fri Apr 12 13:50:45 2013 +0200
@@ -36,8 +36,9 @@
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.tiers.*;
 
-public class CanonicalizerPhase extends Phase {
+public class CanonicalizerPhase extends BasePhase<PhaseContext> {
 
     private static final int MAX_ITERATION_PER_NODE = 10;
     private static final DebugMetric METRIC_CANONICALIZED_NODES = Debug.metric("CanonicalizedNodes");
@@ -47,155 +48,163 @@
     private static final DebugMetric METRIC_SIMPLIFICATION_CONSIDERED_NODES = Debug.metric("SimplificationConsideredNodes");
     public static final DebugMetric METRIC_GLOBAL_VALUE_NUMBERING_HITS = Debug.metric("GlobalValueNumberingHits");
 
-    private final int newNodesMark;
-    private final Assumptions assumptions;
-    private final MetaAccessProvider runtime;
-    private final CustomCanonicalizer customCanonicalizer;
-    private final Iterable<Node> initWorkingSet;
-
-    private NodeWorkList workList;
-    private Tool tool;
-    private List<Node> snapshotTemp;
-
     public interface CustomCanonicalizer {
 
         ValueNode canonicalize(Node node);
     }
 
-    public CanonicalizerPhase(MetaAccessProvider runtime, Assumptions assumptions) {
-        this(runtime, assumptions, null, 0, null);
-    }
-
-    /**
-     * @param runtime
-     * @param assumptions
-     * @param workingSet the initial working set of nodes on which the canonicalizer works, should
-     *            be an auto-grow node bitmap
-     * @param customCanonicalizer
-     */
-    public CanonicalizerPhase(MetaAccessProvider runtime, Assumptions assumptions, Iterable<Node> workingSet, CustomCanonicalizer customCanonicalizer) {
-        this(runtime, assumptions, workingSet, 0, customCanonicalizer);
-    }
-
-    /**
-     * @param newNodesMark only the {@linkplain Graph#getNewNodes(int) new nodes} specified by this
-     *            mark are processed otherwise all nodes in the graph are processed
-     */
-    public CanonicalizerPhase(MetaAccessProvider runtime, Assumptions assumptions, int newNodesMark, CustomCanonicalizer customCanonicalizer) {
-        this(runtime, assumptions, null, newNodesMark, customCanonicalizer);
-    }
-
-    public CanonicalizerPhase(MetaAccessProvider runtime, Assumptions assumptions, Iterable<Node> workingSet, int newNodesMark, CustomCanonicalizer customCanonicalizer) {
-        this.newNodesMark = newNodesMark;
-        this.assumptions = assumptions;
-        this.runtime = runtime;
-        this.customCanonicalizer = customCanonicalizer;
-        this.initWorkingSet = workingSet;
-        this.snapshotTemp = new ArrayList<>();
-    }
-
     @Override
-    protected void run(StructuredGraph graph) {
-        if (initWorkingSet == null) {
-            workList = graph.createNodeWorkList(newNodesMark == 0, MAX_ITERATION_PER_NODE);
-        } else {
-            workList = graph.createNodeWorkList(false, MAX_ITERATION_PER_NODE);
-            workList.addAll(initWorkingSet);
-        }
-        if (newNodesMark > 0) {
-            workList.addAll(graph.getNewNodes(newNodesMark));
-        }
-        tool = new Tool(workList, runtime, assumptions);
-        processWorkSet(graph);
-    }
-
-    private void processWorkSet(StructuredGraph graph) {
-        graph.trackInputChange(new InputChangedListener() {
-
-            @Override
-            public void inputChanged(Node node) {
-                workList.addAgain(node);
-            }
-        });
-
-        for (Node n : workList) {
-            processNode(n, graph);
-        }
-
-        graph.stopTrackingInputChange();
+    protected void run(StructuredGraph graph, PhaseContext context) {
+        new Instance(context.getRuntime(), context.getAssumptions()).run(graph);
     }
 
-    private void processNode(Node node, StructuredGraph graph) {
-        if (node.isAlive()) {
-            METRIC_PROCESSED_NODES.increment();
+    public static class Instance extends Phase {
+
+        private final int newNodesMark;
+        private final Assumptions assumptions;
+        private final MetaAccessProvider runtime;
+        private final CustomCanonicalizer customCanonicalizer;
+        private final Iterable<Node> initWorkingSet;
+
+        private NodeWorkList workList;
+        private Tool tool;
+        private List<Node> snapshotTemp;
+
+        public Instance(MetaAccessProvider runtime, Assumptions assumptions) {
+            this(runtime, assumptions, null, 0, null);
+        }
 
-            if (tryGlobalValueNumbering(node, graph)) {
-                return;
+        /**
+         * @param runtime
+         * @param assumptions
+         * @param workingSet the initial working set of nodes on which the canonicalizer works,
+         *            should be an auto-grow node bitmap
+         * @param customCanonicalizer
+         */
+        public Instance(MetaAccessProvider runtime, Assumptions assumptions, Iterable<Node> workingSet, CustomCanonicalizer customCanonicalizer) {
+            this(runtime, assumptions, workingSet, 0, customCanonicalizer);
+        }
+
+        /**
+         * @param newNodesMark only the {@linkplain Graph#getNewNodes(int) new nodes} specified by
+         *            this mark are processed otherwise all nodes in the graph are processed
+         */
+        public Instance(MetaAccessProvider runtime, Assumptions assumptions, int newNodesMark, CustomCanonicalizer customCanonicalizer) {
+            this(runtime, assumptions, null, newNodesMark, customCanonicalizer);
+        }
+
+        public Instance(MetaAccessProvider runtime, Assumptions assumptions, Iterable<Node> workingSet, int newNodesMark, CustomCanonicalizer customCanonicalizer) {
+            super("Canonicalizer");
+            this.newNodesMark = newNodesMark;
+            this.assumptions = assumptions;
+            this.runtime = runtime;
+            this.customCanonicalizer = customCanonicalizer;
+            this.initWorkingSet = workingSet;
+            this.snapshotTemp = new ArrayList<>();
+        }
+
+        @Override
+        protected void run(StructuredGraph graph) {
+            if (initWorkingSet == null) {
+                workList = graph.createNodeWorkList(newNodesMark == 0, MAX_ITERATION_PER_NODE);
+            } else {
+                workList = graph.createNodeWorkList(false, MAX_ITERATION_PER_NODE);
+                workList.addAll(initWorkingSet);
             }
-            int mark = graph.getMark();
-            if (!tryKillUnused(node)) {
-                node.inputs().filter(GraphUtil.isFloatingNode()).snapshotTo(snapshotTemp);
-                if (!tryCanonicalize(node, graph)) {
-                    tryInferStamp(node, graph);
-                } else {
-                    for (Node in : snapshotTemp) {
-                        if (in.isAlive() && in.usages().isEmpty()) {
-                            GraphUtil.killWithUnusedFloatingInputs(in);
+            if (newNodesMark > 0) {
+                workList.addAll(graph.getNewNodes(newNodesMark));
+            }
+            tool = new Tool(workList, runtime, assumptions);
+            processWorkSet(graph);
+        }
+
+        private void processWorkSet(StructuredGraph graph) {
+            graph.trackInputChange(new InputChangedListener() {
+
+                @Override
+                public void inputChanged(Node node) {
+                    workList.addAgain(node);
+                }
+            });
+
+            for (Node n : workList) {
+                processNode(n, graph);
+            }
+
+            graph.stopTrackingInputChange();
+        }
+
+        private void processNode(Node node, StructuredGraph graph) {
+            if (node.isAlive()) {
+                METRIC_PROCESSED_NODES.increment();
+
+                if (tryGlobalValueNumbering(node, graph)) {
+                    return;
+                }
+                int mark = graph.getMark();
+                if (!tryKillUnused(node)) {
+                    node.inputs().filter(GraphUtil.isFloatingNode()).snapshotTo(snapshotTemp);
+                    if (!tryCanonicalize(node, graph)) {
+                        tryInferStamp(node, graph);
+                    } else {
+                        for (Node in : snapshotTemp) {
+                            if (in.isAlive() && in.usages().isEmpty()) {
+                                GraphUtil.killWithUnusedFloatingInputs(in);
+                            }
                         }
                     }
+                    snapshotTemp.clear();
                 }
-                snapshotTemp.clear();
-            }
 
-            for (Node newNode : graph.getNewNodes(mark)) {
-                workList.add(newNode);
+                for (Node newNode : graph.getNewNodes(mark)) {
+                    workList.add(newNode);
+                }
             }
         }
-    }
 
-    private static boolean tryKillUnused(Node node) {
-        if (node.isAlive() && GraphUtil.isFloatingNode().apply(node) && node.usages().isEmpty()) {
-            GraphUtil.killWithUnusedFloatingInputs(node);
-            return true;
-        }
-        return false;
-    }
-
-    public static boolean tryGlobalValueNumbering(Node node, StructuredGraph graph) {
-        if (node.getNodeClass().valueNumberable()) {
-            Node newNode = graph.findDuplicate(node);
-            if (newNode != null) {
-                assert !(node instanceof FixedNode || newNode instanceof FixedNode);
-                node.replaceAtUsages(newNode);
-                node.safeDelete();
-                METRIC_GLOBAL_VALUE_NUMBERING_HITS.increment();
-                Debug.log("GVN applied and new node is %1s", newNode);
+        private static boolean tryKillUnused(Node node) {
+            if (node.isAlive() && GraphUtil.isFloatingNode().apply(node) && node.usages().isEmpty()) {
+                GraphUtil.killWithUnusedFloatingInputs(node);
                 return true;
             }
+            return false;
         }
-        return false;
-    }
 
-    public boolean tryCanonicalize(final Node node, final StructuredGraph graph) {
-        boolean result = baseTryCanonicalize(node, graph);
-        if (!result && customCanonicalizer != null) {
-            ValueNode canonical = customCanonicalizer.canonicalize(node);
-            if (canonical == node && customCanonicalizer != null) {
-                canonical = customCanonicalizer.canonicalize(node);
+        public static boolean tryGlobalValueNumbering(Node node, StructuredGraph graph) {
+            if (node.getNodeClass().valueNumberable()) {
+                Node newNode = graph.findDuplicate(node);
+                if (newNode != null) {
+                    assert !(node instanceof FixedNode || newNode instanceof FixedNode);
+                    node.replaceAtUsages(newNode);
+                    node.safeDelete();
+                    METRIC_GLOBAL_VALUE_NUMBERING_HITS.increment();
+                    Debug.log("GVN applied and new node is %1s", newNode);
+                    return true;
+                }
             }
-            result = performReplacement(node, graph, canonical);
+            return false;
         }
-        return result;
-    }
 
-    public boolean baseTryCanonicalize(final Node node, final StructuredGraph graph) {
-        if (node instanceof Canonicalizable) {
-            assert !(node instanceof Simplifiable);
-            METRIC_CANONICALIZATION_CONSIDERED_NODES.increment();
-            return Debug.scope("CanonicalizeNode", node, new Callable<Boolean>() {
+        public boolean tryCanonicalize(final Node node, final StructuredGraph graph) {
+            boolean result = baseTryCanonicalize(node, graph);
+            if (!result && customCanonicalizer != null) {
+                ValueNode canonical = customCanonicalizer.canonicalize(node);
+                if (canonical == node && customCanonicalizer != null) {
+                    canonical = customCanonicalizer.canonicalize(node);
+                }
+                result = performReplacement(node, graph, canonical);
+            }
+            return result;
+        }
 
-                public Boolean call() {
-                    ValueNode canonical = ((Canonicalizable) node).canonical(tool);
+        public boolean baseTryCanonicalize(final Node node, final StructuredGraph graph) {
+            if (node instanceof Canonicalizable) {
+                assert !(node instanceof Simplifiable);
+                METRIC_CANONICALIZATION_CONSIDERED_NODES.increment();
+                return Debug.scope("CanonicalizeNode", node, new Callable<Boolean>() {
+
+                    public Boolean call() {
+                        ValueNode canonical = ((Canonicalizable) node).canonical(tool);
 // @formatter:off
 //     cases:                                           original node:
 //                                         |Floating|Fixed-unconnected|Fixed-connected|
@@ -211,137 +220,139 @@
 //       X: must not happen (checked with assertions)
 // @formatter:on
 
-                    return performReplacement(node, graph, canonical);
-                }
-            });
-        } else if (node instanceof Simplifiable) {
-            Debug.log("Canonicalizer: simplifying %s", node);
-            METRIC_SIMPLIFICATION_CONSIDERED_NODES.increment();
-            Debug.scope("SimplifyNode", node, new Runnable() {
+                        return performReplacement(node, graph, canonical);
+                    }
+                });
+            } else if (node instanceof Simplifiable) {
+                Debug.log("Canonicalizer: simplifying %s", node);
+                METRIC_SIMPLIFICATION_CONSIDERED_NODES.increment();
+                Debug.scope("SimplifyNode", node, new Runnable() {
 
-                public void run() {
-                    ((Simplifiable) node).simplify(tool);
-                }
-            });
+                    public void run() {
+                        ((Simplifiable) node).simplify(tool);
+                    }
+                });
+            }
+            return node.isDeleted();
         }
-        return node.isDeleted();
-    }
 
-    private boolean performReplacement(final Node node, final StructuredGraph graph, ValueNode canonical) {
-        if (canonical == node) {
-            Debug.log("Canonicalizer: work on %s", node);
-            return false;
-        } else {
-            Debug.log("Canonicalizer: replacing %s with %s", node, canonical);
-            METRIC_CANONICALIZED_NODES.increment();
-            if (node instanceof FloatingNode) {
-                if (canonical == null) {
-                    // case 1
-                    graph.removeFloating((FloatingNode) node);
+        private boolean performReplacement(final Node node, final StructuredGraph graph, ValueNode canonical) {
+            if (canonical == node) {
+                Debug.log("Canonicalizer: work on %s", node);
+                return false;
+            } else {
+                Debug.log("Canonicalizer: replacing %s with %s", node, canonical);
+                METRIC_CANONICALIZED_NODES.increment();
+                if (node instanceof FloatingNode) {
+                    if (canonical == null) {
+                        // case 1
+                        graph.removeFloating((FloatingNode) node);
+                    } else {
+                        // case 2
+                        assert !(canonical instanceof FixedNode) || (canonical.predecessor() != null || canonical instanceof StartNode || canonical instanceof MergeNode) : node + " -> " + canonical +
+                                        " : replacement should be floating or fixed and connected";
+                        graph.replaceFloating((FloatingNode) node, canonical);
+                    }
                 } else {
-                    // case 2
-                    assert !(canonical instanceof FixedNode) || (canonical.predecessor() != null || canonical instanceof StartNode || canonical instanceof MergeNode) : node + " -> " + canonical +
-                                    " : replacement should be floating or fixed and connected";
-                    graph.replaceFloating((FloatingNode) node, canonical);
-                }
-            } else {
-                assert node instanceof FixedWithNextNode && node.predecessor() != null : node + " -> " + canonical + " : node should be fixed & connected (" + node.predecessor() + ")";
-                FixedWithNextNode fixedWithNext = (FixedWithNextNode) node;
+                    assert node instanceof FixedWithNextNode && node.predecessor() != null : node + " -> " + canonical + " : node should be fixed & connected (" + node.predecessor() + ")";
+                    FixedWithNextNode fixedWithNext = (FixedWithNextNode) node;
 
-                // When removing a fixed node, new canonicalization opportunities for its successor
-                // may arise
-                assert fixedWithNext.next() != null;
-                tool.addToWorkList(fixedWithNext.next());
+                    // When removing a fixed node, new canonicalization opportunities for its
+// successor
+                    // may arise
+                    assert fixedWithNext.next() != null;
+                    tool.addToWorkList(fixedWithNext.next());
 
-                if (canonical == null) {
-                    // case 3
-                    graph.removeFixed(fixedWithNext);
-                } else if (canonical instanceof FloatingNode) {
-                    // case 4
-                    graph.replaceFixedWithFloating(fixedWithNext, (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(fixedWithNext, (FixedWithNextNode) canonical);
+                    if (canonical == null) {
+                        // case 3
+                        graph.removeFixed(fixedWithNext);
+                    } else if (canonical instanceof FloatingNode) {
+                        // case 4
+                        graph.replaceFixedWithFloating(fixedWithNext, (FloatingNode) canonical);
                     } else {
-                        assert canonical.cfgSuccessors().iterator().hasNext() : "replacement " + canonical + " should have successors";
-                        // case 6
-                        node.replaceAtUsages(canonical);
-                        graph.removeFixed(fixedWithNext);
+                        assert canonical instanceof FixedNode;
+                        if (canonical.predecessor() == null) {
+                            assert !canonical.cfgSuccessors().iterator().hasNext() : "replacement " + canonical + " shouldn't have successors";
+                            // case 5
+                            graph.replaceFixedWithFixed(fixedWithNext, (FixedWithNextNode) canonical);
+                        } else {
+                            assert canonical.cfgSuccessors().iterator().hasNext() : "replacement " + canonical + " should have successors";
+                            // case 6
+                            node.replaceAtUsages(canonical);
+                            graph.removeFixed(fixedWithNext);
+                        }
                     }
                 }
+                return true;
             }
-            return true;
         }
-    }
 
-    /**
-     * Calls {@link ValueNode#inferStamp()} on the node and, if it returns true (which means that
-     * the stamp has changed), re-queues the node's usages . If the stamp has changed then this
-     * method also checks if the stamp now describes a constant integer value, in which case the
-     * node is replaced with a constant.
-     */
-    private void tryInferStamp(Node node, StructuredGraph graph) {
-        if (node.isAlive() && node instanceof ValueNode) {
-            ValueNode valueNode = (ValueNode) node;
-            METRIC_INFER_STAMP_CALLED.increment();
-            if (valueNode.inferStamp()) {
-                METRIC_STAMP_CHANGED.increment();
-                if (valueNode.stamp() instanceof IntegerStamp && valueNode.integerStamp().lowerBound() == valueNode.integerStamp().upperBound()) {
-                    ValueNode replacement = ConstantNode.forIntegerKind(valueNode.kind(), valueNode.integerStamp().lowerBound(), graph);
-                    Debug.log("Canonicalizer: replacing %s with %s (inferStamp)", valueNode, replacement);
-                    valueNode.replaceAtUsages(replacement);
-                } else {
-                    for (Node usage : valueNode.usages()) {
-                        workList.addAgain(usage);
+        /**
+         * Calls {@link ValueNode#inferStamp()} on the node and, if it returns true (which means
+         * that the stamp has changed), re-queues the node's usages . If the stamp has changed then
+         * this method also checks if the stamp now describes a constant integer value, in which
+         * case the node is replaced with a constant.
+         */
+        private void tryInferStamp(Node node, StructuredGraph graph) {
+            if (node.isAlive() && node instanceof ValueNode) {
+                ValueNode valueNode = (ValueNode) node;
+                METRIC_INFER_STAMP_CALLED.increment();
+                if (valueNode.inferStamp()) {
+                    METRIC_STAMP_CHANGED.increment();
+                    if (valueNode.stamp() instanceof IntegerStamp && valueNode.integerStamp().lowerBound() == valueNode.integerStamp().upperBound()) {
+                        ValueNode replacement = ConstantNode.forIntegerKind(valueNode.kind(), valueNode.integerStamp().lowerBound(), graph);
+                        Debug.log("Canonicalizer: replacing %s with %s (inferStamp)", valueNode, replacement);
+                        valueNode.replaceAtUsages(replacement);
+                    } else {
+                        for (Node usage : valueNode.usages()) {
+                            workList.addAgain(usage);
+                        }
                     }
                 }
             }
         }
-    }
 
-    private static final class Tool implements SimplifierTool {
+        private static final class Tool implements SimplifierTool {
 
-        private final NodeWorkList nodeWorkSet;
-        private final MetaAccessProvider runtime;
-        private final Assumptions assumptions;
+            private final NodeWorkList nodeWorkSet;
+            private final MetaAccessProvider runtime;
+            private final Assumptions assumptions;
 
-        public Tool(NodeWorkList nodeWorkSet, MetaAccessProvider runtime, Assumptions assumptions) {
-            this.nodeWorkSet = nodeWorkSet;
-            this.runtime = runtime;
-            this.assumptions = assumptions;
-        }
+            public Tool(NodeWorkList nodeWorkSet, MetaAccessProvider runtime, Assumptions assumptions) {
+                this.nodeWorkSet = nodeWorkSet;
+                this.runtime = runtime;
+                this.assumptions = assumptions;
+            }
 
-        @Override
-        public void deleteBranch(FixedNode branch) {
-            branch.predecessor().replaceFirstSuccessor(branch, null);
-            GraphUtil.killCFG(branch);
-        }
+            @Override
+            public void deleteBranch(FixedNode branch) {
+                branch.predecessor().replaceFirstSuccessor(branch, null);
+                GraphUtil.killCFG(branch);
+            }
 
-        /**
-         * @return an object that can be used for recording assumptions or {@code null} if
-         *         assumptions are not allowed in the current context.
-         */
-        @Override
-        public Assumptions assumptions() {
-            return assumptions;
-        }
+            /**
+             * @return an object that can be used for recording assumptions or {@code null} if
+             *         assumptions are not allowed in the current context.
+             */
+            @Override
+            public Assumptions assumptions() {
+                return assumptions;
+            }
 
-        @Override
-        public MetaAccessProvider runtime() {
-            return runtime;
-        }
+            @Override
+            public MetaAccessProvider runtime() {
+                return runtime;
+            }
 
-        @Override
-        public void addToWorkList(Node node) {
-            nodeWorkSet.addAgain(node);
-        }
+            @Override
+            public void addToWorkList(Node node) {
+                nodeWorkSet.addAgain(node);
+            }
 
-        @Override
-        public void removeIfUnused(Node node) {
-            tryKillUnused(node);
+            @Override
+            public void removeIfUnused(Node node) {
+                tryKillUnused(node);
+            }
         }
     }
 }