changeset 15006:e60ea0bf468d

remove StampFactory.dependency/extension/condition
author Lukas Stadler <lukas.stadler@oracle.com>
date Mon, 07 Apr 2014 11:32:08 +0200
parents 9fa900dd3f96
children 9a73164832a9
files graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SnippetAnchorNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SnippetLocationProxyNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractBeginNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractFixedGuardNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/CallTargetNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConditionAnchorNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardPhiNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardProxyNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryPhiNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryProxyNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ConstantLocationNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/NullCheckNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorIdNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/GenericStamp.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampFactory.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java
diffstat 23 files changed, 105 insertions(+), 261 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SnippetAnchorNode.java	Mon Apr 07 11:32:08 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SnippetAnchorNode.java	Mon Apr 07 11:32:08 2014 +0200
@@ -32,7 +32,7 @@
 public final class SnippetAnchorNode extends FixedWithNextNode implements Simplifiable, GuardingNode {
 
     public SnippetAnchorNode() {
-        super(StampFactory.dependency());
+        super(StampFactory.object());
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SnippetLocationProxyNode.java	Mon Apr 07 11:32:08 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SnippetLocationProxyNode.java	Mon Apr 07 11:32:08 2014 +0200
@@ -29,13 +29,13 @@
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.type.*;
 
-@NodeInfo(allowedUsageTypes = {InputType.Association})
+@NodeInfo(allowedUsageTypes = {InputType.Association, InputType.Value})
 public final class SnippetLocationProxyNode extends FloatingNode implements Canonicalizable {
 
     @Input(InputType.Unchecked) private ValueNode location;
 
     public SnippetLocationProxyNode(ValueNode location) {
-        super(StampFactory.extension());
+        super(StampFactory.object());
         this.location = location;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractBeginNode.java	Mon Apr 07 11:32:08 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractBeginNode.java	Mon Apr 07 11:32:08 2014 +0200
@@ -53,7 +53,7 @@
     }
 
     protected AbstractBeginNode() {
-        super(StampFactory.dependency());
+        super(StampFactory.forVoid());
     }
 
     protected AbstractBeginNode(Stamp stamp) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractFixedGuardNode.java	Mon Apr 07 11:32:08 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractFixedGuardNode.java	Mon Apr 07 11:32:08 2014 +0200
@@ -46,7 +46,7 @@
     }
 
     protected AbstractFixedGuardNode(LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, boolean negated) {
-        super(StampFactory.dependency());
+        super(StampFactory.forVoid());
         this.action = action;
         this.negated = negated;
         this.condition = condition;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java	Mon Apr 07 11:32:08 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java	Mon Apr 07 11:32:08 2014 +0200
@@ -27,6 +27,6 @@
 public final class BeginNode extends AbstractBeginNode {
 
     public BeginNode() {
-        super(StampFactory.dependency());
+        super(StampFactory.forVoid());
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/CallTargetNode.java	Mon Apr 07 11:32:08 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/CallTargetNode.java	Mon Apr 07 11:32:08 2014 +0200
@@ -34,12 +34,12 @@
     @Input private final NodeInputList<ValueNode> arguments;
 
     public CallTargetNode(ValueNode[] arguments) {
-        super(StampFactory.extension());
+        super(StampFactory.forVoid());
         this.arguments = new NodeInputList<>(this, arguments);
     }
 
     public CallTargetNode(List<ValueNode> arguments) {
-        super(StampFactory.extension());
+        super(StampFactory.forVoid());
         this.arguments = new NodeInputList<>(this, arguments);
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConditionAnchorNode.java	Mon Apr 07 11:32:08 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConditionAnchorNode.java	Mon Apr 07 11:32:08 2014 +0200
@@ -39,7 +39,7 @@
     }
 
     public ConditionAnchorNode(LogicNode condition, boolean negated) {
-        super(StampFactory.dependency());
+        super(StampFactory.forVoid());
         this.negated = negated;
         this.condition = condition;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java	Mon Apr 07 11:32:08 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java	Mon Apr 07 11:32:08 2014 +0200
@@ -50,7 +50,7 @@
     private boolean negated;
 
     public GuardNode(LogicNode condition, GuardingNode anchor, DeoptimizationReason reason, DeoptimizationAction action, boolean negated, Constant speculation) {
-        super(StampFactory.dependency(), anchor);
+        super(StampFactory.forVoid(), anchor);
         this.condition = condition;
         this.reason = reason;
         this.action = action;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardPhiNode.java	Mon Apr 07 11:32:08 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardPhiNode.java	Mon Apr 07 11:32:08 2014 +0200
@@ -32,7 +32,7 @@
     @Input(InputType.Guard) final NodeInputList<ValueNode> values = new NodeInputList<>(this);
 
     public GuardPhiNode(MergeNode merge) {
-        super(StampFactory.dependency(), merge);
+        super(StampFactory.forVoid(), merge);
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardProxyNode.java	Mon Apr 07 11:32:08 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardProxyNode.java	Mon Apr 07 11:32:08 2014 +0200
@@ -31,7 +31,7 @@
     @Input(InputType.Guard) private ValueNode value;
 
     public GuardProxyNode(ValueNode value, AbstractBeginNode proxyPoint) {
-        super(StampFactory.dependency(), proxyPoint);
+        super(StampFactory.forVoid(), proxyPoint);
         this.value = value;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java	Mon Apr 07 11:32:08 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java	Mon Apr 07 11:32:08 2014 +0200
@@ -145,7 +145,7 @@
 
     @Override
     public void intrinsify(Node node) {
-        assert !(node instanceof ValueNode) || (((ValueNode) node).getKind() == Kind.Void) == (getKind() == Kind.Void);
+        assert !(node instanceof ValueNode) || node.isAllowedUsageType(InputType.Value) == isAllowedUsageType(InputType.Value) : "replacing " + this + " with " + node;
         CallTargetNode call = callTarget;
         FrameState stateAfter = stateAfter();
         if (node instanceof StateSplit) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicNode.java	Mon Apr 07 11:32:08 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicNode.java	Mon Apr 07 11:32:08 2014 +0200
@@ -32,7 +32,7 @@
 public abstract class LogicNode extends FloatingNode {
 
     public LogicNode() {
-        super(StampFactory.condition());
+        super(StampFactory.forVoid());
     }
 
     public static LogicNode and(LogicNode a, LogicNode b, double shortCircuitProbability) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryPhiNode.java	Mon Apr 07 11:32:08 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryPhiNode.java	Mon Apr 07 11:32:08 2014 +0200
@@ -37,7 +37,7 @@
     private final LocationIdentity locationIdentity;
 
     public MemoryPhiNode(MergeNode merge, LocationIdentity locationIdentity) {
-        super(StampFactory.dependency(), merge);
+        super(StampFactory.forVoid(), merge);
         this.locationIdentity = locationIdentity;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryProxyNode.java	Mon Apr 07 11:32:08 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryProxyNode.java	Mon Apr 07 11:32:08 2014 +0200
@@ -35,7 +35,7 @@
     private final LocationIdentity identity;
 
     public MemoryProxyNode(ValueNode value, AbstractBeginNode exit, LocationIdentity identity) {
-        super(StampFactory.dependency(), exit);
+        super(StampFactory.forVoid(), exit);
         this.value = value;
         assert value instanceof MemoryNode;
         this.identity = identity;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java	Mon Apr 07 11:32:08 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java	Mon Apr 07 11:32:08 2014 +0200
@@ -54,7 +54,7 @@
     }
 
     private AddLocationNode(ValueNode x, ValueNode y) {
-        super(StampFactory.extension());
+        super(StampFactory.forVoid());
         this.x = x;
         this.y = y;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ConstantLocationNode.java	Mon Apr 07 11:32:08 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ConstantLocationNode.java	Mon Apr 07 11:32:08 2014 +0200
@@ -43,7 +43,7 @@
     }
 
     private ConstantLocationNode(LocationIdentity identity, Kind kind, long displacement) {
-        super(StampFactory.extension());
+        super(StampFactory.forVoid());
         assert kind != Kind.Illegal && kind != Kind.Void;
         this.valueKind = kind;
         this.locationIdentity = identity;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java	Mon Apr 07 11:32:08 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java	Mon Apr 07 11:32:08 2014 +0200
@@ -66,7 +66,7 @@
     }
 
     public IndexedLocationNode(LocationIdentity identity, Kind kind, long displacement, ValueNode index, int indexScaling) {
-        super(StampFactory.extension());
+        super(StampFactory.forVoid());
         assert kind != Kind.Illegal && kind != Kind.Void;
         this.valueKind = kind;
         this.locationIdentity = identity;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/NullCheckNode.java	Mon Apr 07 11:32:08 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/NullCheckNode.java	Mon Apr 07 11:32:08 2014 +0200
@@ -31,7 +31,7 @@
     @Input private ValueNode object;
 
     public NullCheckNode(ValueNode object) {
-        super(StampFactory.dependency());
+        super(StampFactory.forVoid());
         this.object = object;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java	Mon Apr 07 11:32:08 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java	Mon Apr 07 11:32:08 2014 +0200
@@ -39,7 +39,7 @@
     @Input(InputType.Guard) private ValueNode anchored;
 
     public ValueAnchorNode(ValueNode value) {
-        super(StampFactory.dependency());
+        super(StampFactory.forVoid());
         this.anchored = value;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorIdNode.java	Mon Apr 07 11:32:08 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorIdNode.java	Mon Apr 07 11:32:08 2014 +0200
@@ -38,7 +38,7 @@
     private int lockDepth;
 
     public MonitorIdNode(int lockDepth) {
-        super(StampFactory.dependency());
+        super(StampFactory.forVoid());
         this.lockDepth = lockDepth;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/GenericStamp.java	Mon Apr 07 11:32:08 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,133 +0,0 @@
-/*
- * Copyright (c) 2012, 2014, 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.graal.nodes.type;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.spi.*;
-
-public final class GenericStamp extends Stamp {
-
-    public enum GenericStampType {
-        Dependency,
-        Extension,
-        Condition
-    }
-
-    private final GenericStampType type;
-
-    protected GenericStamp(GenericStampType type) {
-        this.type = type;
-    }
-
-    public GenericStampType type() {
-        return type;
-    }
-
-    @Override
-    public Stamp unrestricted() {
-        return this;
-    }
-
-    @Override
-    public Kind getStackKind() {
-        return Kind.Illegal;
-    }
-
-    @Override
-    public PlatformKind getPlatformKind(LIRTypeTool tool) {
-        throw GraalInternalError.shouldNotReachHere(type + " stamp has no value");
-    }
-
-    @Override
-    public ResolvedJavaType javaType(MetaAccessProvider metaAccess) {
-        throw GraalInternalError.shouldNotReachHere(type + " stamp has no Java type");
-    }
-
-    @Override
-    public String toString() {
-        return type.toString();
-    }
-
-    @Override
-    public boolean alwaysDistinct(Stamp other) {
-        return false;
-    }
-
-    @Override
-    public Stamp meet(Stamp other) {
-        if (!(other instanceof GenericStamp) || ((GenericStamp) other).type != type) {
-            return illegal();
-        }
-        return this;
-    }
-
-    @Override
-    public Stamp join(Stamp other) {
-        if (!(other instanceof GenericStamp) || ((GenericStamp) other).type != type) {
-            return illegal();
-        }
-        return this;
-    }
-
-    @Override
-    public boolean isCompatible(Stamp stamp) {
-        if (this == stamp) {
-            return true;
-        }
-        if (stamp instanceof GenericStamp) {
-            GenericStamp other = (GenericStamp) stamp;
-            return type == other.type;
-        }
-        return false;
-    }
-
-    @Override
-    public int hashCode() {
-        return 31 + ((type == null) ? 0 : type.hashCode());
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (obj == null || getClass() != obj.getClass()) {
-            return false;
-        }
-        if (type != ((GenericStamp) obj).type) {
-            return false;
-        }
-        return true;
-    }
-
-    @Override
-    public Stamp illegal() {
-        return IllegalStamp.getInstance();
-    }
-
-    @Override
-    public boolean isLegal() {
-        return true;
-    }
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampFactory.java	Mon Apr 07 11:32:08 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampFactory.java	Mon Apr 07 11:32:08 2014 +0200
@@ -24,7 +24,6 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.type.GenericStamp.GenericStampType;
 
 public class StampFactory {
 
@@ -35,9 +34,6 @@
     private static final Stamp objectStamp = new ObjectStamp(null, false, false, false);
     private static final Stamp objectNonNullStamp = new ObjectStamp(null, false, true, false);
     private static final Stamp objectAlwaysNullStamp = new ObjectStamp(null, false, false, true);
-    private static final Stamp dependencyStamp = new GenericStamp(GenericStampType.Dependency);
-    private static final Stamp extensionStamp = new GenericStamp(GenericStampType.Extension);
-    private static final Stamp conditionStamp = new GenericStamp(GenericStampType.Condition);
     private static final Stamp nodeIntrinsicStamp = new ObjectStamp(null, false, false, false);
     private static final Stamp positiveInt = forInteger(Kind.Int, 0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE);
 
@@ -111,18 +107,6 @@
         return forKind(Kind.Int);
     }
 
-    public static Stamp dependency() {
-        return dependencyStamp;
-    }
-
-    public static Stamp extension() {
-        return extensionStamp;
-    }
-
-    public static Stamp condition() {
-        return conditionStamp;
-    }
-
     public static Stamp positiveInt() {
         return positiveInt;
     }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java	Mon Apr 07 11:32:08 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java	Mon Apr 07 11:32:08 2014 +0200
@@ -30,6 +30,8 @@
 import com.oracle.graal.graph.Graph.DuplicationReplacement;
 import com.oracle.graal.graph.Graph.Mark;
 import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.NodeClass.NodeClassIterator;
+import com.oracle.graal.graph.NodeClass.Position;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.VirtualState.NodeClosure;
 import com.oracle.graal.nodes.extended.*;
@@ -453,20 +455,16 @@
         /**
          * Expands the set of nodes to be duplicated by looking at a number of conditions:
          * <ul>
-         * <li>{@link ValueNode}s that have usages on the outside need to be replaced with phis for
-         * the outside usages.</li>
-         * <li>Non-{@link ValueNode} nodes that have outside usages (frame states, virtual object
-         * states, ...) need to be cloned immediately for the outside usages.</li>
-         * <li>Nodes that have a {@link StampFactory#extension()} or
-         * {@link StampFactory#condition()} stamp need to be cloned immediately for the outside
-         * usages.</li>
+         * <li>Inputs of type {@link InputType#Value} into the duplicated set will be rerouted to a
+         * new phi node.</li>
+         * <li>Inputs of type {@link InputType#Association}, {@link InputType#Condition} and
+         * {@link InputType#State} into the duplicated set will be rerouted to a duplicated version
+         * of the inside node.</li>
          * <li>Dependencies into the duplicated nodes will be replaced with dependencies on the
          * merge.</li>
-         * <li>Outside non-{@link ValueNode}s with usages within the duplicated set of nodes need to
-         * also be duplicated.</li>
-         * <li>Outside {@link ValueNode}s with {@link StampFactory#extension()} or
-         * {@link StampFactory#condition()} stamps that have usages within the duplicated set of
-         * nodes need to also be duplicated.</li>
+         * <li>Inputs of type {@link InputType#Association}, {@link InputType#Condition} and
+         * {@link InputType#State} to outside the duplicated set will cause the outside node to be
+         * pulled into the duplicated set.</li>
          * </ul>
          *
          * @param duplicatedNodes The set of duplicated nodes that will be modified (expanded).
@@ -479,91 +477,86 @@
 
             while (!worklist.isEmpty()) {
                 Node duplicated = worklist.remove();
-                if (hasUsagesOutside(duplicated, duplicatedNodes)) {
-                    boolean cloneForOutsideUsages = false;
-                    if (duplicated instanceof ValueNode) {
-                        ValueNode node = (ValueNode) duplicated;
-                        if (node.stamp() == StampFactory.dependency()) {
-                            // re-route dependencies to the merge
-                            replaceUsagesOutside(node, newBottomMerge, duplicatedNodes);
-                            // TODO(ls) maybe introduce phis for dependencies
-                        } else if (node.stamp() == StampFactory.extension() || node.stamp() == StampFactory.condition()) {
-                            cloneForOutsideUsages = true;
-                        } else {
-                            // introduce a new phi
-                            PhiNode newPhi = bottomPhis.get(node);
-                            if (newPhi == null) {
-                                newPhi = graph.addWithoutUnique(new ValuePhiNode(node.stamp().unrestricted(), newBottomMerge));
-                                bottomPhis.put(node, newPhi);
-                                newPhi.addInput(node);
+                processUsages(duplicated, duplicatedNodes, newBottomMerge, worklist);
+                processInputs(duplicated, duplicatedNodes, worklist);
+            }
+        }
+
+        private void processUsages(Node duplicated, HashSet<Node> duplicatedNodes, MergeNode newBottomMerge, Deque<Node> worklist) {
+            HashSet<Node> unique = new HashSet<>();
+            duplicated.usages().snapshotTo(unique);
+            Node newOutsideClone = null;
+            for (Node usage : unique) {
+                if (!duplicatedNodes.contains(usage)) {
+                    NodeClassIterator iter = usage.inputs().iterator();
+                    while (iter.hasNext()) {
+                        Position pos = iter.nextPosition();
+                        if (pos.get(usage) == duplicated) {
+                            switch (pos.getInputType(usage)) {
+                                case Association:
+                                case Condition:
+                                case State:
+                                    // clone the offending node to the outside
+                                    if (newOutsideClone == null) {
+                                        newOutsideClone = duplicated.copyWithInputs();
+                                        // this might cause other nodes to have outside usages
+                                        for (Node input : newOutsideClone.inputs()) {
+                                            if (duplicatedNodes.contains(input)) {
+                                                worklist.add(input);
+                                            }
+                                        }
+                                    }
+                                    pos.set(usage, newOutsideClone);
+                                    break;
+                                case Guard:
+                                case Anchor:
+                                    // re-route dependencies to the merge
+                                    pos.set(usage, newBottomMerge);
+                                    break;
+                                case Value:
+                                    // introduce a new phi
+                                    ValueNode node = (ValueNode) duplicated;
+                                    PhiNode newPhi = bottomPhis.get(node);
+                                    if (newPhi == null) {
+                                        newPhi = graph.addWithoutUnique(new ValuePhiNode(node.stamp().unrestricted(), newBottomMerge));
+                                        bottomPhis.put(node, newPhi);
+                                        newPhi.addInput(node);
+                                    }
+                                    pos.set(usage, newPhi);
+                                    break;
+                                default:
+                                    throw GraalInternalError.shouldNotReachHere();
                             }
-                            replaceUsagesOutside(node, newPhi, duplicatedNodes);
-                        }
-                    } else {
-                        cloneForOutsideUsages = true;
-                    }
-                    if (cloneForOutsideUsages) {
-                        // clone the offending node to the outside
-                        Node newOutsideClone = duplicated.copyWithInputs();
-                        replaceUsagesOutside(duplicated, newOutsideClone, duplicatedNodes);
-                        // this might cause other nodes to have outside usages, we need to look at
-                        // those as well
-                        for (Node input : newOutsideClone.inputs()) {
-                            if (duplicatedNodes.contains(input)) {
-                                worklist.add(input);
-                            }
-                        }
-                    }
-                }
-                // check if this node has an input that lies outside and cannot be shared
-                for (Node input : duplicated.inputs()) {
-                    if (!duplicatedNodes.contains(input)) {
-                        boolean duplicateInput = false;
-                        if (input instanceof VirtualState) {
-                            duplicateInput = true;
-                        } else if (input instanceof ValueNode) {
-                            Stamp inputStamp = ((ValueNode) input).stamp();
-                            if (inputStamp == StampFactory.extension() || inputStamp == StampFactory.condition()) {
-                                duplicateInput = true;
-                            }
-                        }
-                        if (duplicateInput) {
-                            duplicatedNodes.add(input);
-                            worklist.add(input);
                         }
                     }
                 }
             }
         }
 
-        /**
-         * Checks if the given node has usages that are not within the given set of nodes.
-         *
-         * @param node The node whose usages are checked.
-         * @param nodeSet The set of nodes that are considered to be "within".
-         * @return true if the given node has usages on the outside, false otherwise.
-         */
-        private static boolean hasUsagesOutside(Node node, HashSet<Node> nodeSet) {
-            for (Node usage : node.usages()) {
-                if (!nodeSet.contains(usage)) {
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        /**
-         * Replaces the given node with the given replacement at all usages that are not within the
-         * given set of nodes.
-         *
-         * @param node The node to be replaced at outside usages.
-         * @param replacement The node that replaced the given node at outside usages.
-         * @param nodeSet The set of nodes that are considered to be "within".
-         */
-        private static void replaceUsagesOutside(Node node, Node replacement, HashSet<Node> nodeSet) {
-            for (Node usage : node.usages().snapshot()) {
-                if (!nodeSet.contains(usage)) {
-                    usage.replaceFirstInput(node, replacement);
+        private void processInputs(Node duplicated, HashSet<Node> duplicatedNodes, Deque<Node> worklist) {
+            // check if this node has an input that lies outside and cannot be shared
+            NodeClassIterator iter = duplicated.inputs().iterator();
+            while (iter.hasNext()) {
+                Position pos = iter.nextPosition();
+                Node input = pos.get(duplicated);
+                if (input != null && !duplicatedNodes.contains(input)) {
+                    switch (pos.getInputType(duplicated)) {
+                        case Association:
+                        case Condition:
+                        case State:
+                            if (input != merge) {
+                                duplicatedNodes.add(input);
+                                worklist.add(input);
+                            }
+                            break;
+                        case Guard:
+                        case Anchor:
+                        case Value:
+                            // no change needed
+                            break;
+                        default:
+                            throw GraalInternalError.shouldNotReachHere();
+                    }
                 }
             }
         }