changeset 10768:058abc2b59a5

Merge
author Lukas Stadler <lukas.stadler@jku.at>
date Mon, 15 Jul 2013 17:54:00 +0200
parents 88d0dc388450 (diff) dd7a8807378b (current diff)
children 395d34c10e26 f0fdbb2b7135
files graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java
diffstat 16 files changed, 194 insertions(+), 59 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ConditionalEliminationTest.java	Mon Jul 15 16:53:35 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ConditionalEliminationTest.java	Mon Jul 15 17:54:00 2013 +0200
@@ -29,6 +29,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.java.MethodCallTargetNode.*;
 import com.oracle.graal.phases.common.*;
 
 /**
@@ -172,4 +173,24 @@
             assertTrue("unexpected constant: " + constant, constant.asConstant().isNull() || constant.asConstant().asInt() > 0);
         }
     }
+
+    public static int testInvokeSnippet(Number n) {
+        if (n instanceof Integer) {
+            return n.intValue();
+        } else {
+            return 1;
+        }
+    }
+
+    @Test
+    public void testInvoke() {
+        test("testInvokeSnippet", new Integer(16));
+        StructuredGraph graph = parse("testInvokeSnippet");
+        new CanonicalizerPhase.Instance(runtime(), null, true).apply(graph);
+        new ConditionalEliminationPhase(runtime()).apply(graph);
+
+        InvokeNode invoke = graph.getNodes(InvokeNode.class).first();
+        assertEquals(InvokeKind.Special, ((MethodCallTargetNode) invoke.callTarget()).invokeKind());
+    }
+
 }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Mon Jul 15 16:53:35 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Mon Jul 15 17:54:00 2013 +0200
@@ -507,6 +507,7 @@
     }
 
     private StructuredGraph parse0(Method m, GraphBuilderConfiguration conf) {
+        assert m.getAnnotation(Test.class) == null : "shouldn't parse method with @Test annotation: " + m;
         ResolvedJavaMethod javaMethod = runtime.lookupJavaMethod(m);
         StructuredGraph graph = new StructuredGraph(javaMethod);
         new GraphBuilderPhase(runtime, conf, OptimisticOptimizations.ALL).apply(graph);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PEAReadEliminationTest.java	Mon Jul 15 16:53:35 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PEAReadEliminationTest.java	Mon Jul 15 17:54:00 2013 +0200
@@ -24,8 +24,6 @@
 
 import static org.junit.Assert.*;
 
-import java.util.concurrent.*;
-
 import org.junit.*;
 
 import com.oracle.graal.api.code.*;
@@ -43,7 +41,7 @@
 
     public static Object staticField;
 
-    public static class TestObject implements Callable<Integer> {
+    public static class TestObject {
 
         public int x;
         public int y;
@@ -52,11 +50,6 @@
             this.x = x;
             this.y = y;
         }
-
-        @Override
-        public Integer call() throws Exception {
-            return x;
-        }
     }
 
     public static class TestObject2 {
@@ -70,6 +63,16 @@
         }
     }
 
+    public static class TestObject3 extends TestObject {
+
+        public int z;
+
+        public TestObject3(int x, int y, int z) {
+            super(x, y);
+            this.z = z;
+        }
+    }
+
     @SuppressWarnings("all")
     public static int testSimpleSnippet(TestObject a) {
         a.x = 2;
@@ -213,6 +216,24 @@
         assertEquals(1, graph.getNodes().filter(StoreFieldNode.class).count());
     }
 
+    public static int testValueProxySnippet(boolean b, TestObject o) {
+        int sum = 0;
+        if (b) {
+            sum += o.x;
+        } else {
+            TestObject3 p = (TestObject3) o;
+            sum += p.x;
+        }
+        sum += o.x;
+        return sum;
+    }
+
+    @Test
+    public void testValueProxy() {
+        processMethod("testValueProxySnippet");
+        assertEquals(2, graph.getNodes().filter(LoadFieldNode.class).count());
+    }
+
     final ReturnNode getReturn(String snippet) {
         processMethod(snippet);
         assertEquals(1, graph.getNodes(ReturnNode.class).count());
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/FixedValueAnchorNode.java	Mon Jul 15 16:53:35 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/FixedValueAnchorNode.java	Mon Jul 15 17:54:00 2013 +0200
@@ -26,7 +26,7 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
-public final class FixedValueAnchorNode extends FixedWithNextNode implements LIRLowerable {
+public final class FixedValueAnchorNode extends FixedWithNextNode implements LIRLowerable, ValueProxy {
 
     @Input private ValueNode object;
 
@@ -53,4 +53,9 @@
         generator.setResult(this, generator.operand(object));
     }
 
+    @Override
+    public ValueNode getOriginalValue() {
+        return object;
+    }
+
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardedValueNode.java	Mon Jul 15 16:53:35 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardedValueNode.java	Mon Jul 15 17:54:00 2013 +0200
@@ -34,7 +34,7 @@
  * 
  * A GuardedValueNode will only go away if its guard is null or {@link StructuredGraph#start()}.
  */
-public class GuardedValueNode extends FloatingGuardedNode implements LIRLowerable, Virtualizable, Node.IterableNodeType, GuardingNode, Canonicalizable {
+public class GuardedValueNode extends FloatingGuardedNode implements LIRLowerable, Virtualizable, Node.IterableNodeType, GuardingNode, Canonicalizable, ValueProxy {
 
     @Input private ValueNode object;
 
@@ -81,4 +81,9 @@
         }
         return this;
     }
+
+    @Override
+    public ValueNode getOriginalValue() {
+        return object;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java	Mon Jul 15 16:53:35 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java	Mon Jul 15 17:54:00 2013 +0200
@@ -34,7 +34,7 @@
  * A node that changes the stamp of its input based on some condition being true.
  */
 @NodeInfo(nameTemplate = "GuardingPi(!={p#negated}) {p#reason/s}")
-public class GuardingPiNode extends FixedWithNextNode implements Lowerable, GuardingNode, Canonicalizable {
+public class GuardingPiNode extends FixedWithNextNode implements Lowerable, GuardingNode, Canonicalizable, ValueProxy {
 
     @Input private ValueNode object;
     @Input private LogicNode condition;
@@ -109,4 +109,9 @@
     public ValueNode asNode() {
         return this;
     }
+
+    @Override
+    public ValueNode getOriginalValue() {
+        return object;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java	Mon Jul 15 16:53:35 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java	Mon Jul 15 17:54:00 2013 +0200
@@ -36,7 +36,7 @@
  * is as narrow or narrower than the PiNode's type. The PiNode, and therefore also the scheduling
  * restriction enforced by the anchor, will go away.
  */
-public class PiNode extends FloatingGuardedNode implements LIRLowerable, Virtualizable, Node.IterableNodeType, GuardingNode, Canonicalizable {
+public class PiNode extends FloatingGuardedNode implements LIRLowerable, Virtualizable, Node.IterableNodeType, GuardingNode, Canonicalizable, ValueProxy {
 
     @Input private ValueNode object;
 
@@ -82,4 +82,9 @@
         }
         return this;
     }
+
+    @Override
+    public ValueNode getOriginalValue() {
+        return object;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ProxyNode.java	Mon Jul 15 16:53:35 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ProxyNode.java	Mon Jul 15 17:54:00 2013 +0200
@@ -27,7 +27,6 @@
 import com.oracle.graal.nodes.PhiNode.PhiType;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * A value proxy that is inserted in the frame state of a loop exit for any value that is created
@@ -35,7 +34,7 @@
  * loop.
  */
 @NodeInfo(nameTemplate = "{p#type/s}Proxy")
-public class ProxyNode extends FloatingNode implements Node.IterableNodeType, ValueNumberable, Canonicalizable, Virtualizable, LIRLowerable {
+public class ProxyNode extends FloatingNode implements Node.IterableNodeType, ValueNumberable, Canonicalizable, Virtualizable, LIRLowerable, ValueProxy {
 
     @Input(notDataflow = true) private AbstractBeginNode proxyPoint;
     @Input private ValueNode value;
@@ -60,11 +59,6 @@
         return updateStamp(value.stamp());
     }
 
-    @Override
-    public Stamp stamp() {
-        return value().stamp();
-    }
-
     public AbstractBeginNode proxyPoint() {
         return proxyPoint;
     }
@@ -116,4 +110,8 @@
         return graph.unique(new ProxyNode(value, exit, PhiType.Memory, location));
     }
 
+    @Override
+    public ValueNode getOriginalValue() {
+        return value;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/TypeProfileProxyNode.java	Mon Jul 15 16:53:35 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/TypeProfileProxyNode.java	Mon Jul 15 17:54:00 2013 +0200
@@ -27,12 +27,11 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * A node that attaches a type profile to a proxied input node.
  */
-public final class TypeProfileProxyNode extends FloatingNode implements Canonicalizable, Node.IterableNodeType {
+public final class TypeProfileProxyNode extends FloatingNode implements Canonicalizable, Node.IterableNodeType, ValueProxy {
 
     @Input private ValueNode object;
     private final JavaTypeProfile profile;
@@ -67,12 +66,7 @@
 
     @Override
     public boolean inferStamp() {
-        return object.inferStamp();
-    }
-
-    @Override
-    public Stamp stamp() {
-        return object.stamp();
+        return updateStamp(object.stamp());
     }
 
     @Override
@@ -130,4 +124,9 @@
         }
         assert graph.getNodes(TypeProfileProxyNode.class).count() == 0;
     }
+
+    @Override
+    public ValueNode getOriginalValue() {
+        return object;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNode.java	Mon Jul 15 16:53:35 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNode.java	Mon Jul 15 17:54:00 2013 +0200
@@ -44,7 +44,7 @@
         this.stamp = stamp;
     }
 
-    public Stamp stamp() {
+    public final Stamp stamp() {
         return stamp;
     }
 
@@ -80,7 +80,7 @@
         return false;
     }
 
-    public Kind kind() {
+    public final Kind kind() {
         return stamp().kind();
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java	Mon Jul 15 16:53:35 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java	Mon Jul 15 17:54:00 2013 +0200
@@ -37,7 +37,7 @@
 /**
  * Implements a type check against a compile-time known type.
  */
-public final class CheckCastNode extends FixedWithNextNode implements Canonicalizable, Lowerable, Node.IterableNodeType, Virtualizable {
+public final class CheckCastNode extends FixedWithNextNode implements Canonicalizable, Lowerable, Node.IterableNodeType, Virtualizable, ValueProxy {
 
     @Input private ValueNode object;
     private final ResolvedJavaType type;
@@ -193,4 +193,9 @@
             }
         }
     }
+
+    @Override
+    public ValueNode getOriginalValue() {
+        return object;
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/ValueProxy.java	Mon Jul 15 17:54:00 2013 +0200
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013, 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.spi;
+
+import com.oracle.graal.nodes.*;
+
+public interface ValueProxy {
+
+    ValueNode getOriginalValue();
+
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Mon Jul 15 16:53:35 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Mon Jul 15 17:54:00 2013 +0200
@@ -30,6 +30,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.spi.*;
 
 public class GraphUtil {
 
@@ -257,14 +258,6 @@
         return null;
     }
 
-    public static ValueNode unProxify(ValueNode proxy) {
-        ValueNode v = proxy;
-        while (v instanceof ProxyNode) {
-            v = ((ProxyNode) v).value();
-        }
-        return v;
-    }
-
     /**
      * Returns a string representation of the given collection of objects.
      * 
@@ -285,16 +278,31 @@
     }
 
     /**
+     * Gets the original value by iterating through all {@link ValueProxy ValueProxies}.
+     * 
+     * @param value The start value.
+     * @return The first non-proxy value encountered.
+     */
+    public static ValueNode unproxify(ValueNode value) {
+        ValueNode result = value;
+        while (result instanceof ValueProxy) {
+            result = ((ValueProxy) result).getOriginalValue();
+        }
+        return result;
+    }
+
+    /**
      * Tries to find an original value of the given node by traversing through proxies and
-     * unambiguous phis.
+     * unambiguous phis. Note that this method will perform an exhaustive search through phis. It is
+     * intended to be used during graph building, when phi nodes aren't yet canonicalized.
      * 
      * @param proxy The node whose original value should be determined.
      */
     public static ValueNode originalValue(ValueNode proxy) {
         ValueNode v = proxy;
         do {
-            if (v instanceof ProxyNode) {
-                v = ((ProxyNode) v).value();
+            if (v instanceof ValueProxy) {
+                v = ((ValueProxy) v).getOriginalValue();
             } else if (v instanceof PhiNode) {
                 v = ((PhiNode) v).singleValue();
             } else {
@@ -308,8 +316,8 @@
             NodeWorkList worklist = proxy.graph().createNodeWorkList();
             worklist.add(proxy);
             for (Node node : worklist) {
-                if (node instanceof ProxyNode) {
-                    worklist.add(((ProxyNode) node).value());
+                if (node instanceof ValueProxy) {
+                    worklist.add(((ValueProxy) node).getOriginalValue());
                 } else if (node instanceof PhiNode) {
                     worklist.addAll(((PhiNode) node).values());
                 } else {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java	Mon Jul 15 16:53:35 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java	Mon Jul 15 17:54:00 2013 +0200
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.phases.common;
 
+import java.lang.reflect.*;
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
@@ -33,6 +34,7 @@
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.java.MethodCallTargetNode.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.*;
@@ -193,16 +195,16 @@
         }
 
         public ResolvedJavaType getNodeType(ValueNode node) {
-            ResolvedJavaType result = knownTypes.get(node);
+            ResolvedJavaType result = knownTypes.get(GraphUtil.unproxify(node));
             return result == null ? node.objectStamp().type() : result;
         }
 
         public boolean isNull(ValueNode value) {
-            return value.objectStamp().alwaysNull() || knownNull.contains(value);
+            return value.objectStamp().alwaysNull() || knownNull.contains(GraphUtil.unproxify(value));
         }
 
         public boolean isNonNull(ValueNode value) {
-            return value.objectStamp().nonNull() || knownNonNull.contains(value);
+            return value.objectStamp().nonNull() || knownNonNull.contains(GraphUtil.unproxify(value));
         }
 
         @Override
@@ -245,25 +247,27 @@
          * to be null, otherwise the value is known to be non-null.
          */
         public void addNullness(boolean isNull, ValueNode value) {
+            ValueNode original = GraphUtil.unproxify(value);
             if (isNull) {
-                if (!isNull(value)) {
+                if (!isNull(original)) {
                     metricNullnessRegistered.increment();
-                    knownNull.add(value);
+                    knownNull.add(original);
                 }
             } else {
-                if (!isNonNull(value)) {
+                if (!isNonNull(original)) {
                     metricNullnessRegistered.increment();
-                    knownNonNull.add(value);
+                    knownNonNull.add(original);
                 }
             }
         }
 
         public void addType(ResolvedJavaType type, ValueNode value) {
-            ResolvedJavaType knownType = getNodeType(value);
+            ValueNode original = GraphUtil.unproxify(value);
+            ResolvedJavaType knownType = getNodeType(original);
             ResolvedJavaType newType = tighten(type, knownType);
 
             if (newType != knownType) {
-                knownTypes.put(value, newType);
+                knownTypes.put(original, newType);
                 metricTypeRegistered.increment();
             }
         }
@@ -575,6 +579,25 @@
                         }
                     }
                 }
+            } else if (node instanceof Invoke) {
+                Invoke invoke = (Invoke) node;
+                if (invoke.callTarget() instanceof MethodCallTargetNode) {
+                    MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
+                    ValueNode receiver = callTarget.receiver();
+                    if (receiver != null && (callTarget.invokeKind() == InvokeKind.Interface || callTarget.invokeKind() == InvokeKind.Virtual)) {
+                        ResolvedJavaType type = state.getNodeType(receiver);
+                        if (type != receiver.objectStamp().type()) {
+                            ResolvedJavaMethod method = type.resolveMethod(callTarget.targetMethod());
+                            if (method != null) {
+                                if ((method.getModifiers() & Modifier.FINAL) != 0 || (type.getModifiers() & Modifier.FINAL) != 0) {
+                                    callTarget.setInvokeKind(InvokeKind.Special);
+                                    callTarget.setTargetMethod(method);
+                                }
+                            }
+                        }
+                    }
+                }
+
             }
         }
     }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationPEClosure.java	Mon Jul 15 16:53:35 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationPEClosure.java	Mon Jul 15 17:54:00 2013 +0200
@@ -34,6 +34,7 @@
 import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.schedule.*;
 import com.oracle.graal.virtual.phases.ea.ReadEliminationPEBlockState.ReadCacheEntry;
 
@@ -54,24 +55,26 @@
         if (!deleted) {
             if (node instanceof LoadFieldNode) {
                 LoadFieldNode load = (LoadFieldNode) node;
-                ValueNode cachedValue = state.getReadCache(load.object(), load.field());
+                ValueNode object = GraphUtil.unproxify(load.object());
+                ValueNode cachedValue = state.getReadCache(object, load.field());
                 if (cachedValue != null) {
                     effects.replaceAtUsages(load, cachedValue);
                     state.addScalarAlias(load, cachedValue);
+                    deleted = true;
                 } else {
-                    state.addReadCache(load.object(), load.field(), load);
+                    state.addReadCache(object, load.field(), load);
                 }
-                deleted = true;
             } else if (node instanceof StoreFieldNode) {
                 StoreFieldNode store = (StoreFieldNode) node;
-                ValueNode cachedValue = state.getReadCache(store.object(), store.field());
+                ValueNode object = GraphUtil.unproxify(store.object());
+                ValueNode cachedValue = state.getReadCache(object, store.field());
 
                 if (state.getScalarAlias(store.value()) == cachedValue) {
                     effects.deleteFixedNode(store);
                     deleted = true;
                 }
                 state.killReadCache(store.field());
-                state.addReadCache(store.object(), store.field(), store.value());
+                state.addReadCache(object, store.field(), store.value());
             } else if (node instanceof MemoryCheckpoint.Single) {
                 METRIC_MEMORYCHECKOINT.increment();
                 LocationIdentity identity = ((MemoryCheckpoint.Single) node).getLocationIdentity();
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java	Mon Jul 15 16:53:35 2013 +0200
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java	Mon Jul 15 17:54:00 2013 +0200
@@ -70,15 +70,20 @@
     @Override
     protected void run(StructuredGraph graph) {
         for (Node n : GraphOrder.forwardGraph(graph)) {
-            if (n instanceof ValueNode) {
+            if (n instanceof ValueNode && !(n instanceof PhiNode && ((PhiNode) n).isLoopPhi())) {
                 ValueNode valueNode = (ValueNode) n;
                 if (isWord(valueNode)) {
                     changeToWord(valueNode);
                 }
             }
         }
+        for (PhiNode phi : graph.getNodes(PhiNode.class)) {
+            if (phi.isLoopPhi() && isWord(phi)) {
+                changeToWord(phi);
+            }
+        }
 
-        // Remove casts between different word types (which are by now no longer have kind Object)
+        // Remove casts between different word types (which by now no longer have kind Object)
         for (CheckCastNode checkCastNode : graph.getNodes().filter(CheckCastNode.class).snapshot()) {
             if (!checkCastNode.isDeleted() && checkCastNode.kind() == wordKind) {
                 checkCastNode.replaceAtUsages(checkCastNode.object());