diff graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/InstanceOfSnippets.java @ 6653:2d5407ae1ac4

intermediate materialization is now removed during lowering of an InstanceOfNode that has a single usage which is an IfNode in the same block lowered InstanceOfNode snippet graph is shared among similar usages of the InstanceOfNode
author Doug Simon <doug.simon@oracle.com>
date Tue, 30 Oct 2012 23:58:53 +0100
parents efcf6cd16a2f
children 370674104c1c
line wrap: on
line diff
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/InstanceOfSnippets.java	Tue Oct 30 10:45:00 2012 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/InstanceOfSnippets.java	Tue Oct 30 23:58:53 2012 +0100
@@ -25,9 +25,10 @@
 import static com.oracle.graal.hotspot.snippets.CheckCastSnippets.Templates.*;
 import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*;
 import static com.oracle.graal.snippets.Snippet.Varargs.*;
-import static com.oracle.graal.snippets.SnippetTemplate.*;
 import static com.oracle.graal.snippets.SnippetTemplate.Arguments.*;
 
+import java.util.*;
+
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
@@ -185,83 +186,236 @@
             ConstantNode hub = ConstantNode.forObject(type.klassOop(), runtime, instanceOf.graph());
             boolean checkNull = !object.stamp().nonNull();
 
-            for (Node usage : instanceOf.usages().snapshot()) {
-                Arguments arguments = null;
-                Key key = null;
+            List<Node> usages = instanceOf.usages().snapshot();
+            int nUsages = usages.size();
+            Map<MaterializationKey, Materialization> materializations = nUsages == 1 ? null : new HashMap<MaterializationKey, Materialization>(nUsages);
+
+            for (Node usage : usages) {
+                final StructuredGraph graph = (StructuredGraph) usage.graph();
 
-                // instanceof nodes are lowered separately for each usage. To simply graph modifications,
-                // we duplicate the instanceof node for each usage.
-                final InstanceOfNode duplicate = instanceOf.graph().add(new InstanceOfNode(instanceOf.type(), instanceOf.object(), instanceOf.profile()));
-                usage.replaceFirstInput(instanceOf, duplicate);
+                UsageReplacer replacer;
+                MaterializationKey mkey;
+                if (usage instanceof IfNode) {
+                    mkey = new MaterializationKey(ConstantNode.forInt(1, graph), ConstantNode.forInt(0, graph));
+                    replacer = new IfUsageReplacer(materializations, mkey, instanceOf, (IfNode) usage, tool);
+                } else {
+                    assert usage instanceof ConditionalNode : "unexpected usage of " + instanceOf + ": " + usage;
+                    ConditionalNode conditional = (ConditionalNode) usage;
+                    mkey = new MaterializationKey(conditional.trueValue(), conditional.falseValue());
+                    replacer = new ConditionalUsageReplacer(materializations, mkey, instanceOf, conditional);
+                }
 
-                if (usage instanceof IfNode) {
-                    final StructuredGraph graph = (StructuredGraph) usage.graph();
-                    final ValueNode falseValue = ConstantNode.forInt(0, graph);
-                    final ValueNode trueValue = ConstantNode.forInt(1, graph);
-
+                Materialization materialization = materializations == null ? null : materializations.get(mkey);
+                if (materialization != null) {
+                    usage.replaceFirstInput(instanceOf, materialization.condition(mkey));
+                } else {
+                    Arguments arguments;
+                    Key key;
                     if (hintInfo.exact) {
                         HotSpotKlassOop[] hints = createHints(hintInfo);
                         assert hints.length == 1;
                         key = new Key(instanceofExact).add("checkNull", checkNull);
-                        arguments = arguments("object", object).add("exactHub", hints[0]).add("trueValue", trueValue).add("falseValue", falseValue);
+                        arguments = arguments("object", object).add("exactHub", hints[0]).add("trueValue", mkey.trueValue).add("falseValue", mkey.falseValue);
                     } else if (type.isPrimaryType()) {
                         key = new Key(instanceofPrimary).add("checkNull", checkNull).add("superCheckOffset", type.superCheckOffset());
-                        arguments = arguments("hub", hub).add("object", object).add("trueValue", trueValue).add("falseValue", falseValue);
+                        arguments = arguments("hub", hub).add("object", object).add("trueValue", mkey.trueValue).add("falseValue", mkey.falseValue);
                     } else {
                         HotSpotKlassOop[] hints = createHints(hintInfo);
                         key = new Key(instanceofSecondary).add("hints", vargargs(Object.class, hints.length)).add("checkNull", checkNull);
-                        arguments = arguments("hub", hub).add("object", object).add("hints", hints).add("trueValue", trueValue).add("falseValue", falseValue);
-                    }
-
-                    UsageReplacer replacer = new UsageReplacer() {
-                        @Override
-                        public void replace(ValueNode oldNode, ValueNode newNode) {
-                            assert oldNode == duplicate;
-                            newNode.inferStamp();
-                            IntegerEqualsNode condition = graph.add(new IntegerEqualsNode(newNode, trueValue));
-                            oldNode.replaceAtUsages(condition);
-                        }
-                    };
-
-                    SnippetTemplate template = cache.get(key);
-                    template.instantiate(runtime, duplicate, replacer, tool.lastFixedNode(), arguments);
-
-                } else if (usage instanceof ConditionalNode) {
-
-                    ConditionalNode materialize = (ConditionalNode) usage;
-                    materialize.replaceAtUsages(duplicate);
-                    ValueNode falseValue = materialize.falseValue();
-                    ValueNode trueValue = materialize.trueValue();
-
-                    // The materialize node is no longer connected to anyone -> kill it
-                    materialize.clearInputs();
-                    assert materialize.usages().isEmpty();
-                    GraphUtil.killWithUnusedFloatingInputs(materialize);
-
-                    if (hintInfo.exact) {
-                        HotSpotKlassOop[] hints = createHints(hintInfo);
-                        assert hints.length == 1;
-                        key = new Key(instanceofExact).add("checkNull", checkNull);
-                        arguments = arguments("object", object).add("exactHub", hints[0]).add("trueValue", trueValue).add("falseValue", falseValue);
-                    } else if (type.isPrimaryType()) {
-                        key = new Key(instanceofPrimary).add("checkNull", checkNull).add("superCheckOffset", type.superCheckOffset());
-                        arguments = arguments("hub", hub).add("object", object).add("trueValue", trueValue).add("falseValue", falseValue);
-                    } else {
-                        HotSpotKlassOop[] hints = createHints(hintInfo);
-                        key = new Key(instanceofSecondary).add("hints", vargargs(Object.class, hints.length)).add("checkNull", checkNull);
-                        arguments = arguments("hub", hub).add("object", object).add("hints", hints).add("trueValue", trueValue).add("falseValue", falseValue);
+                        arguments = arguments("hub", hub).add("object", object).add("hints", hints).add("trueValue", mkey.trueValue).add("falseValue", mkey.falseValue);
                     }
 
                     SnippetTemplate template = cache.get(key);
-                    template.instantiate(runtime, duplicate, DEFAULT_REPLACER, tool.lastFixedNode(), arguments);
-                } else {
-                    throw new GraalInternalError("Unexpected usage of %s: %s", instanceOf, usage);
+                    template.instantiate(runtime, instanceOf, replacer, tool.lastFixedNode(), arguments);
                 }
             }
 
-            assert !instanceOf.isDeleted();
             assert instanceOf.usages().isEmpty();
-            GraphUtil.killWithUnusedFloatingInputs(instanceOf);
+            if (!instanceOf.isDeleted()) {
+                GraphUtil.killWithUnusedFloatingInputs(instanceOf);
+            }
+        }
+
+        /**
+         * The materialized result of an instanceof snippet.
+         * All usages of an {@link InstanceOfNode} that have the same key can share the result.
+         */
+        static final class Materialization {
+            private final PhiNode phi;
+            private CompareNode condition;
+
+
+            public Materialization(PhiNode phi) {
+                this.phi = phi;
+            }
+
+            CompareNode condition(MaterializationKey key) {
+                if (condition == null) {
+                    StructuredGraph graph = (StructuredGraph) phi.graph();
+                    condition = graph.add(new IntegerEqualsNode(phi, key.trueValue));
+                }
+                return condition;
+            }
+        }
+
+        static final class MaterializationKey {
+            final ValueNode trueValue;
+            final ValueNode falseValue;
+            public MaterializationKey(ValueNode trueValue, ValueNode falseValue) {
+                this.trueValue = trueValue;
+                this.falseValue = falseValue;
+            }
+
+            @Override
+            public int hashCode() {
+                return trueValue.hashCode();
+            }
+
+            @Override
+            public boolean equals(Object obj) {
+                if (obj instanceof MaterializationKey) {
+                    MaterializationKey mk = (MaterializationKey) obj;
+                    return mk.trueValue == trueValue && mk.falseValue == falseValue;
+                }
+                return false;
+            }
+
+            @Override
+            public String toString() {
+                return "[true=" + trueValue + ", false=" + falseValue + "]";
+            }
+        }
+
+        /**
+         * Replaces an {@link IfNode} usage of an {@link InstanceOfNode}.
+         */
+        static final class IfUsageReplacer implements UsageReplacer {
+
+            private final boolean solitaryUsage;
+            private final InstanceOfNode instanceOf;
+            private final IfNode usage;
+            private final Map<MaterializationKey, Materialization> materializations;
+            private final MaterializationKey key;
+            private final boolean sameBlock;
+
+            private IfUsageReplacer(Map<MaterializationKey, Materialization> materializations, MaterializationKey key, InstanceOfNode instanceOf, IfNode usage, LoweringTool tool) {
+                this.materializations = materializations;
+                this.key = key;
+                this.sameBlock = tool.getBlockFor(usage) == tool.getBlockFor(instanceOf);
+                this.solitaryUsage = materializations == null;
+                this.instanceOf = instanceOf;
+                this.usage = usage;
+            }
+
+            @Override
+            public void replace(ValueNode oldNode, ValueNode newNode) {
+                assert newNode instanceof PhiNode;
+                assert oldNode == instanceOf;
+                if (sameBlock && solitaryUsage) {
+                    removeIntermediateMaterialization(newNode);
+                } else {
+                    newNode.inferStamp();
+                    Materialization m = new Materialization((PhiNode) newNode);
+                    if (materializations != null) {
+                        Materialization oldValue = materializations.put(key, m);
+                        assert oldValue == null;
+                    }
+                    usage.replaceFirstInput(oldNode, m.condition(key));
+                }
+            }
+
+            /**
+             * Directly wires the incoming edges of the merge at the end of the snippet to
+             * the outgoing edges of the IfNode that uses the materialized result.
+             */
+            private void removeIntermediateMaterialization(ValueNode newNode) {
+                IfNode ifNode = usage;
+                PhiNode phi = (PhiNode) newNode;
+                MergeNode merge = phi.merge();
+                assert merge.stateAfter() == null;
+
+                List<EndNode> mergePredecessors = merge.cfgPredecessors().snapshot();
+                assert phi.valueCount() == mergePredecessors.size();
+
+                List<EndNode> falseEnds = new ArrayList<>(mergePredecessors.size());
+                List<EndNode> trueEnds = new ArrayList<>(mergePredecessors.size());
+
+                int endIndex = 0;
+                for (EndNode end : mergePredecessors) {
+                    ValueNode endValue = phi.valueAt(endIndex++);
+                    if (endValue == key.trueValue) {
+                        trueEnds.add(end);
+                    } else {
+                        assert endValue == key.falseValue;
+                        falseEnds.add(end);
+                    }
+                }
+
+                BeginNode trueSuccessor = ifNode.trueSuccessor();
+                BeginNode falseSuccessor = ifNode.falseSuccessor();
+                ifNode.setTrueSuccessor(null);
+                ifNode.setFalseSuccessor(null);
+
+                connectEnds(merge, trueEnds, trueSuccessor);
+                connectEnds(merge, falseEnds, falseSuccessor);
+
+                GraphUtil.killCFG(merge);
+                GraphUtil.killCFG(ifNode);
+
+                assert !merge.isAlive() : merge;
+                assert !phi.isAlive() : phi;
+            }
+
+            private static void connectEnds(MergeNode merge, List<EndNode> ends, BeginNode successor) {
+                if (ends.size() == 1) {
+                    EndNode end = ends.get(0);
+                    ((FixedWithNextNode) end.predecessor()).setNext(successor);
+                    merge.removeEnd(end);
+                    GraphUtil.killCFG(end);
+                } else {
+                    assert ends.size() > 1;
+                    MergeNode newMerge = merge.graph().add(new MergeNode());
+
+                    for (EndNode end : ends) {
+                        newMerge.addForwardEnd(end);
+                    }
+                    newMerge.setNext(successor);
+                }
+            }
+        }
+
+        /**
+         * Replaces a {@link ConditionalNode} usage of an {@link InstanceOfNode}.
+         */
+        static final class ConditionalUsageReplacer implements UsageReplacer {
+
+            private final InstanceOfNode instanceOf;
+            private final ConditionalNode usage;
+            private final Map<MaterializationKey, Materialization> materializations;
+            private final MaterializationKey key;
+
+            private ConditionalUsageReplacer(Map<MaterializationKey, Materialization> materializations, MaterializationKey key, InstanceOfNode instanceOf, ConditionalNode usage) {
+                this.materializations = materializations;
+                this.key = key;
+                this.instanceOf = instanceOf;
+                this.usage = usage;
+            }
+
+            @Override
+            public void replace(ValueNode oldNode, ValueNode newNode) {
+                assert newNode instanceof PhiNode;
+                assert oldNode == instanceOf;
+                newNode.inferStamp();
+                if (materializations != null) {
+                    Materialization m = new Materialization((PhiNode) newNode);
+                    Materialization oldValue = materializations.put(key, m);
+                    assert oldValue == null;
+                }
+                usage.replaceAtUsages(newNode);
+                usage.clearInputs();
+                assert usage.usages().isEmpty();
+                GraphUtil.killWithUnusedFloatingInputs(usage);
+            }
         }
     }