changeset 23020:4af472d10ad6

merge
author Christian Wimmer <christian.wimmer@oracle.com>
date Wed, 18 Nov 2015 12:01:42 -0800
parents e3bcc6af1bcc (current diff) 2b32ccbf4999 (diff)
children 9f824129d993
files graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopTransformations.java graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopFullUnrollPhase.java graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopPeelingPhase.java graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopSafepointEliminationPhase.java graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopUnswitchingPhase.java graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/ReassociateInvariantPhase.java
diffstat 57 files changed, 1327 insertions(+), 720 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags	Wed Nov 18 12:01:29 2015 -0800
+++ b/.hgtags	Wed Nov 18 12:01:42 2015 -0800
@@ -619,3 +619,4 @@
 efbf340fc7f56e49735111c23cef030413146409 jdk8u45-b13
 3c622007e098d8905d8e0947362a3894a629a5f1 graal-0.8
 3e8357b49024cb168ab5ebd511d8b5c03c068f75 graal-0.9
+795ada9208d8f35991b98bb934f624c70b8a0183 graal-0.10
--- a/CHANGELOG.md	Wed Nov 18 12:01:29 2015 -0800
+++ b/CHANGELOG.md	Wed Nov 18 12:01:42 2015 -0800
@@ -1,12 +1,16 @@
-# GraalVM Changelog
+# Graal Changelog
 
 This changelog summarizes major changes between Graal versions relevant to developers building technology on top of Graal. The main focus is on APIs exported by Graal but other significant performance/stability changes are mentioned as well.
 
 ## `tip`
+...
+
+## Version 0.10
+17-Nov-2015, [Repository Revision](http://hg.openjdk.java.net/graal/graal-compiler/shortlog/graal-0.10)
 * Added experimental Trace Register Allocator.
 * All JVMCI (and HotSpot) code has been moved into a [separate repository](http://hg.openjdk.java.net/graal/graal-jvmci-8/).
 * JVMCI code is now in jdk.vm.ci.* name space.
-* Graal now works on top of a JVMCI enabled JDK9 binary.
+* Graal now passes the gate on top of a JVMCI enabled JDK9 binary.
 * Separate Graal compiler can be specified for Truffle compilation with new `-G:TruffleCompiler` option.
 * Initialization of the Truffle compiler is delayed until first Truffle compilation request.
 
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64MoveFactory.java	Wed Nov 18 12:01:29 2015 -0800
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64MoveFactory.java	Wed Nov 18 12:01:42 2015 -0800
@@ -44,7 +44,7 @@
 import com.oracle.graal.lir.amd64.AMD64Move.MoveToRegOp;
 import com.oracle.graal.lir.framemap.FrameMapBuilder;
 
-public class AMD64MoveFactory extends AMD64MoveFactoryBase {
+public abstract class AMD64MoveFactory extends AMD64MoveFactoryBase {
 
     private final FrameMapBuilder frameMapBuilder;
 
--- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCMoveFactory.java	Wed Nov 18 12:01:29 2015 -0800
+++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCMoveFactory.java	Wed Nov 18 12:01:42 2015 -0800
@@ -106,4 +106,10 @@
                 return false;
         }
     }
+
+    @Override
+    public boolean allowConstantToStackMove(Constant value) {
+        return false;
+    }
+
 }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java	Wed Nov 18 12:01:29 2015 -0800
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java	Wed Nov 18 12:01:42 2015 -0800
@@ -26,6 +26,7 @@
 import org.junit.Ignore;
 import org.junit.Test;
 
+import com.oracle.graal.loop.DefaultLoopPolicies;
 import com.oracle.graal.loop.phases.LoopPeelingPhase;
 import com.oracle.graal.nodes.ReturnNode;
 import com.oracle.graal.nodes.StructuredGraph;
@@ -326,7 +327,7 @@
         canonicalizer.apply(graph, context);
         new InliningPhase(new CanonicalizerPhase()).apply(graph, context);
         if (loopPeeling) {
-            new LoopPeelingPhase().apply(graph);
+            new LoopPeelingPhase(new DefaultLoopPolicies()).apply(graph, context);
         }
         new DeadCodeEliminationPhase().apply(graph);
         canonicalizer.apply(graph, context);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/LoopUnswitchTest.java	Wed Nov 18 12:01:29 2015 -0800
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/LoopUnswitchTest.java	Wed Nov 18 12:01:42 2015 -0800
@@ -28,6 +28,7 @@
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.debug.DebugDumpScope;
 import com.oracle.graal.graph.Node;
+import com.oracle.graal.loop.DefaultLoopPolicies;
 import com.oracle.graal.loop.phases.LoopUnswitchingPhase;
 import com.oracle.graal.nodes.StateSplit;
 import com.oracle.graal.nodes.StructuredGraph;
@@ -128,7 +129,7 @@
         final StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
         final StructuredGraph referenceGraph = parseEager(referenceSnippet, AllowAssumptions.NO);
 
-        new LoopUnswitchingPhase().apply(graph);
+        new LoopUnswitchingPhase(new DefaultLoopPolicies()).apply(graph);
 
         // Framestates create comparison problems
         for (Node stateSplit : graph.getNodes().filterInterface(StateSplit.class)) {
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java	Wed Nov 18 12:01:29 2015 -0800
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java	Wed Nov 18 12:01:42 2015 -0800
@@ -28,6 +28,7 @@
 import org.junit.Test;
 
 import com.oracle.graal.graph.Node;
+import com.oracle.graal.loop.DefaultLoopPolicies;
 import com.oracle.graal.loop.phases.LoopFullUnrollPhase;
 import com.oracle.graal.loop.phases.LoopPeelingPhase;
 import com.oracle.graal.nodes.extended.ValueAnchorNode;
@@ -312,7 +313,7 @@
     @Test
     public void testFullyUnrolledLoop() {
         prepareGraph("testFullyUnrolledLoopSnippet", false);
-        new LoopFullUnrollPhase(new CanonicalizerPhase()).apply(graph, context);
+        new LoopFullUnrollPhase(new CanonicalizerPhase(), new DefaultLoopPolicies()).apply(graph, context);
         new PartialEscapePhase(false, new CanonicalizerPhase()).apply(graph, context);
         Assert.assertEquals(1, returnNodes.size());
         Assert.assertTrue(returnNodes.get(0).result() instanceof AllocatedObjectNode);
@@ -343,7 +344,7 @@
     @Test
     public void testPeeledLoop() {
         prepareGraph("testPeeledLoopSnippet", false);
-        new LoopPeelingPhase().apply(graph);
+        new LoopPeelingPhase(new DefaultLoopPolicies()).apply(graph);
         new SchedulePhase().apply(graph);
     }
 
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java	Wed Nov 18 12:01:29 2015 -0800
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java	Wed Nov 18 12:01:42 2015 -0800
@@ -67,6 +67,7 @@
 import com.oracle.graal.lir.FullInfopointOp;
 import com.oracle.graal.lir.LIRFrameState;
 import com.oracle.graal.lir.LIRInstruction;
+import com.oracle.graal.lir.LIRValueUtil;
 import com.oracle.graal.lir.LabelRef;
 import com.oracle.graal.lir.SimpleInfopointOp;
 import com.oracle.graal.lir.StandardOp.JumpOp;
@@ -81,7 +82,6 @@
 import com.oracle.graal.nodes.AbstractBeginNode;
 import com.oracle.graal.nodes.AbstractEndNode;
 import com.oracle.graal.nodes.AbstractMergeNode;
-import com.oracle.graal.nodes.ConstantNode;
 import com.oracle.graal.nodes.DeoptimizingNode;
 import com.oracle.graal.nodes.DirectCallTargetNode;
 import com.oracle.graal.nodes.FixedNode;
@@ -144,13 +144,6 @@
         nodeMatchRules.lirBuilder = this;
     }
 
-    /**
-     * @return {@code true} if object constant to stack moves are supported.
-     */
-    protected boolean allowObjectConstantToStackMove() {
-        return true;
-    }
-
     public NodeMatchRules getNodeMatchRules() {
         return nodeMatchRules;
     }
@@ -300,10 +293,11 @@
                  * new Variable.
                  */
                 value = gen.emitMove(value);
-            } else if (!allowObjectConstantToStackMove() && node instanceof ConstantNode && !value.getLIRKind().isValue()) {
+            } else if (LIRValueUtil.isConstantValue(value) && !gen.getMoveFactory().allowConstantToStackMove(LIRValueUtil.asConstant(value))) {
                 /*
-                 * Object constants are not allowed as inputs for PHIs. Explicitly create a copy of
-                 * this value to force it into a register. The new variable is only used in the PHI.
+                 * Some constants are not allowed as inputs for PHIs in certain backends. Explicitly
+                 * create a copy of this value to force it into a register. The new variable is only
+                 * used in the PHI.
                  */
                 Variable result = gen.newVariable(value.getLIRKind());
                 gen.emitMove(result, value);
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EconomyLowTier.java	Wed Nov 18 12:01:29 2015 -0800
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EconomyLowTier.java	Wed Nov 18 12:01:42 2015 -0800
@@ -29,7 +29,6 @@
 import com.oracle.graal.phases.common.CanonicalizerPhase;
 import com.oracle.graal.phases.common.ExpandLogicPhase;
 import com.oracle.graal.phases.common.LoweringPhase;
-import com.oracle.graal.phases.common.RemoveValueProxyPhase;
 import com.oracle.graal.phases.tiers.LowTierContext;
 
 public class EconomyLowTier extends PhaseSuite<LowTierContext> {
@@ -43,6 +42,5 @@
         appendPhase(new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.LOW_TIER));
 
         appendPhase(new ExpandLogicPhase());
-        appendPhase(new RemoveValueProxyPhase());
     }
 }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EconomyMidTier.java	Wed Nov 18 12:01:29 2015 -0800
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EconomyMidTier.java	Wed Nov 18 12:01:42 2015 -0800
@@ -31,6 +31,7 @@
 import com.oracle.graal.phases.common.GuardLoweringPhase;
 import com.oracle.graal.phases.common.LoopSafepointInsertionPhase;
 import com.oracle.graal.phases.common.LoweringPhase;
+import com.oracle.graal.phases.common.RemoveValueProxyPhase;
 import com.oracle.graal.phases.tiers.MidTierContext;
 
 public class EconomyMidTier extends PhaseSuite<MidTierContext> {
@@ -40,6 +41,7 @@
         if (ImmutableCode.getValue()) {
             canonicalizer.disableReadCanonicalization();
         }
+        appendPhase(new RemoveValueProxyPhase());
 
         appendPhase(new LoopSafepointInsertionPhase());
 
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java	Wed Nov 18 12:01:29 2015 -0800
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java	Wed Nov 18 12:01:42 2015 -0800
@@ -37,6 +37,8 @@
 import jdk.vm.ci.options.OptionType;
 import jdk.vm.ci.options.OptionValue;
 
+import com.oracle.graal.loop.DefaultLoopPolicies;
+import com.oracle.graal.loop.LoopPolicies;
 import com.oracle.graal.loop.phases.LoopFullUnrollPhase;
 import com.oracle.graal.loop.phases.LoopPeelingPhase;
 import com.oracle.graal.loop.phases.LoopUnswitchingPhase;
@@ -87,16 +89,17 @@
             appendPhase(new ConvertDeoptimizeToGuardPhase());
         }
 
+        LoopPolicies loopPolicies = createLoopPolicies();
         if (FullUnroll.getValue()) {
-            appendPhase(new LoopFullUnrollPhase(canonicalizer));
+            appendPhase(new LoopFullUnrollPhase(canonicalizer, loopPolicies));
         }
 
         if (OptLoopTransform.getValue()) {
             if (LoopPeeling.getValue()) {
-                appendPhase(new LoopPeelingPhase());
+                appendPhase(new LoopPeelingPhase(loopPolicies));
             }
             if (LoopUnswitch.getValue()) {
-                appendPhase(new LoopUnswitchingPhase());
+                appendPhase(new LoopUnswitchingPhase(loopPolicies));
             }
         }
 
@@ -114,4 +117,8 @@
             appendPhase(new HighTierReconcileInstrumentationPhase());
         }
     }
+
+    public LoopPolicies createLoopPolicies() {
+        return new DefaultLoopPolicies();
+    }
 }
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugins.java	Wed Nov 18 12:01:29 2015 -0800
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugins.java	Wed Nov 18 12:01:42 2015 -0800
@@ -254,7 +254,22 @@
          *            {@code declaringClass}
          */
         public void registerMethodSubstitution(Class<?> substituteDeclaringClass, String name, Class<?>... argumentTypes) {
-            MethodSubstitutionPlugin plugin = new MethodSubstitutionPlugin(substituteDeclaringClass, name, argumentTypes);
+            registerMethodSubstitution(substituteDeclaringClass, name, name, argumentTypes);
+        }
+
+        /**
+         * Registers a plugin that implements a method based on the bytecode of a substitute method.
+         *
+         * @param substituteDeclaringClass the class declaring the substitute method
+         * @param name the name of both the original method
+         * @param substituteName the name of the substitute method
+         * @param argumentTypes the argument types of the method. Element 0 of this array must be
+         *            the {@link Class} value for {@link InvocationPlugin.Receiver} iff the method
+         *            is non-static. Upon returning, element 0 will have been rewritten to
+         *            {@code declaringClass}
+         */
+        public void registerMethodSubstitution(Class<?> substituteDeclaringClass, String name, String substituteName, Class<?>... argumentTypes) {
+            MethodSubstitutionPlugin plugin = new MethodSubstitutionPlugin(substituteDeclaringClass, substituteName, argumentTypes);
             plugins.register(plugin, false, allowOverwrite, declaringClass, name, argumentTypes);
         }
     }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotMoveFactory.java	Wed Nov 18 12:01:29 2015 -0800
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotMoveFactory.java	Wed Nov 18 12:01:42 2015 -0800
@@ -23,6 +23,7 @@
 package com.oracle.graal.hotspot.amd64;
 
 import jdk.vm.ci.hotspot.HotSpotCompressedNullConstant;
+import jdk.vm.ci.hotspot.HotSpotConstant;
 import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
 import jdk.vm.ci.hotspot.HotSpotObjectConstant;
 import jdk.vm.ci.meta.AllocatableValue;
@@ -51,6 +52,14 @@
     }
 
     @Override
+    public boolean allowConstantToStackMove(Constant value) {
+        if (value instanceof HotSpotConstant) {
+            return ((HotSpotConstant) value).isCompressed();
+        }
+        return true;
+    }
+
+    @Override
     public AMD64LIRInstruction createLoad(AllocatableValue dst, Constant src) {
         if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(src)) {
             return super.createLoad(dst, JavaConstant.INT_0);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java	Wed Nov 18 12:01:29 2015 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java	Wed Nov 18 12:01:42 2015 -0800
@@ -132,6 +132,12 @@
     public static final ForeignCallDescriptor DECRYPT_BLOCK = new ForeignCallDescriptor("decrypt_block", void.class, Word.class, Word.class, Pointer.class);
 
     /**
+     * @see AESCryptSubstitutions#decryptBlockStub(ForeignCallDescriptor, Word, Word, Pointer)
+     */
+    public static final ForeignCallDescriptor DECRYPT_BLOCK_WITH_ORIGINAL_KEY = new ForeignCallDescriptor("decrypt_block_with_original_key", void.class, Word.class, Word.class, Pointer.class,
+                    Pointer.class);
+
+    /**
      * @see CipherBlockChainingSubstitutions#crypt
      */
     public static final ForeignCallDescriptor ENCRYPT = new ForeignCallDescriptor("encrypt", void.class, Word.class, Word.class, Pointer.class, Pointer.class, int.class);
@@ -142,6 +148,12 @@
     public static final ForeignCallDescriptor DECRYPT = new ForeignCallDescriptor("decrypt", void.class, Word.class, Word.class, Pointer.class, Pointer.class, int.class);
 
     /**
+     * @see CipherBlockChainingSubstitutions#crypt
+     */
+    public static final ForeignCallDescriptor DECRYPT_WITH_ORIGINAL_KEY = new ForeignCallDescriptor("decrypt_with_original_key", void.class, Word.class, Word.class, Pointer.class, Pointer.class,
+                    int.class, Pointer.class);
+
+    /**
      * @see VMErrorNode
      */
     public static final ForeignCallDescriptor VM_ERROR = new ForeignCallDescriptor("vm_error", void.class, Object.class, Object.class, long.class);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java	Wed Nov 18 12:01:29 2015 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java	Wed Nov 18 12:01:42 2015 -0800
@@ -293,17 +293,20 @@
             assert config.aescryptDecryptBlockStub != 0L;
             assert config.cipherBlockChainingEncryptAESCryptStub != 0L;
             assert config.cipherBlockChainingDecryptAESCryptStub != 0L;
+            String arch = HotSpotVMConfig.config().getHostArchitectureName();
+            String decryptSuffix = arch.equals("sparc") ? "WithOriginalKey" : "";
             Class<?> c = MethodSubstitutionPlugin.resolveClass("com.sun.crypto.provider.CipherBlockChaining", true);
             if (c != null) {
                 Registration r = new Registration(plugins, c);
                 r.registerMethodSubstitution(CipherBlockChainingSubstitutions.class, cbcEncryptName, Receiver.class, byte[].class, int.class, int.class, byte[].class, int.class);
-                r.registerMethodSubstitution(CipherBlockChainingSubstitutions.class, cbcDecryptName, Receiver.class, byte[].class, int.class, int.class, byte[].class, int.class);
+                r.registerMethodSubstitution(CipherBlockChainingSubstitutions.class, cbcDecryptName, cbcDecryptName + decryptSuffix, Receiver.class, byte[].class, int.class, int.class, byte[].class,
+                                int.class);
             }
             c = MethodSubstitutionPlugin.resolveClass("com.sun.crypto.provider.AESCrypt", true);
             if (c != null) {
                 Registration r = new Registration(plugins, c);
                 r.registerMethodSubstitution(AESCryptSubstitutions.class, aesEncryptName, Receiver.class, byte[].class, int.class, byte[].class, int.class);
-                r.registerMethodSubstitution(AESCryptSubstitutions.class, aesDecryptName, Receiver.class, byte[].class, int.class, byte[].class, int.class);
+                r.registerMethodSubstitution(AESCryptSubstitutions.class, aesDecryptName, aesDecryptName + decryptSuffix, Receiver.class, byte[].class, int.class, byte[].class, int.class);
             }
         }
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java	Wed Nov 18 12:01:29 2015 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java	Wed Nov 18 12:01:42 2015 -0800
@@ -30,7 +30,9 @@
 import static com.oracle.graal.compiler.target.Backend.ARITHMETIC_SIN;
 import static com.oracle.graal.compiler.target.Backend.ARITHMETIC_TAN;
 import static com.oracle.graal.hotspot.HotSpotBackend.DECRYPT;
+import static com.oracle.graal.hotspot.HotSpotBackend.DECRYPT_WITH_ORIGINAL_KEY;
 import static com.oracle.graal.hotspot.HotSpotBackend.DECRYPT_BLOCK;
+import static com.oracle.graal.hotspot.HotSpotBackend.DECRYPT_BLOCK_WITH_ORIGINAL_KEY;
 import static com.oracle.graal.hotspot.HotSpotBackend.ENCRYPT;
 import static com.oracle.graal.hotspot.HotSpotBackend.ENCRYPT_BLOCK;
 import static com.oracle.graal.hotspot.HotSpotBackend.EXCEPTION_HANDLER;
@@ -306,6 +308,8 @@
                 // These stubs do callee saving
                 registerForeignCall(ENCRYPT_BLOCK, c.aescryptEncryptBlockStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, NamedLocationIdentity.getArrayLocation(JavaKind.Byte));
                 registerForeignCall(DECRYPT_BLOCK, c.aescryptDecryptBlockStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, NamedLocationIdentity.getArrayLocation(JavaKind.Byte));
+                registerForeignCall(DECRYPT_BLOCK_WITH_ORIGINAL_KEY, c.aescryptDecryptBlockStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE,
+                                NamedLocationIdentity.getArrayLocation(JavaKind.Byte));
             } catch (JVMCIError e) {
                 if (!(e.getCause() instanceof ClassNotFoundException)) {
                     throw e;
@@ -317,6 +321,8 @@
                                 NamedLocationIdentity.getArrayLocation(JavaKind.Byte));
                 registerForeignCall(DECRYPT, c.cipherBlockChainingDecryptAESCryptStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE,
                                 NamedLocationIdentity.getArrayLocation(JavaKind.Byte));
+                registerForeignCall(DECRYPT_WITH_ORIGINAL_KEY, c.cipherBlockChainingDecryptAESCryptStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE,
+                                NamedLocationIdentity.getArrayLocation(JavaKind.Byte));
             } catch (JVMCIError e) {
                 if (!(e.getCause() instanceof ClassNotFoundException)) {
                     throw e;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/OnStackReplacementPhase.java	Wed Nov 18 12:01:29 2015 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/OnStackReplacementPhase.java	Wed Nov 18 12:01:42 2015 -0800
@@ -31,8 +31,8 @@
 import com.oracle.graal.graph.Node;
 import com.oracle.graal.graph.iterators.NodeIterable;
 import com.oracle.graal.loop.LoopEx;
-import com.oracle.graal.loop.LoopTransformations;
 import com.oracle.graal.loop.LoopsData;
+import com.oracle.graal.loop.phases.LoopTransformations;
 import com.oracle.graal.nodeinfo.InputType;
 import com.oracle.graal.nodeinfo.Verbosity;
 import com.oracle.graal.nodes.AbstractBeginNode;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AESCryptSubstitutions.java	Wed Nov 18 12:01:29 2015 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AESCryptSubstitutions.java	Wed Nov 18 12:01:42 2015 -0800
@@ -23,6 +23,7 @@
 package com.oracle.graal.hotspot.replacements;
 
 import static com.oracle.graal.hotspot.HotSpotBackend.DECRYPT_BLOCK;
+import static com.oracle.graal.hotspot.HotSpotBackend.DECRYPT_BLOCK_WITH_ORIGINAL_KEY;
 import static com.oracle.graal.hotspot.HotSpotBackend.ENCRYPT_BLOCK;
 import static com.oracle.graal.nodes.extended.BranchProbabilityNode.VERY_SLOW_PATH_PROBABILITY;
 import static com.oracle.graal.nodes.extended.BranchProbabilityNode.probability;
@@ -56,6 +57,7 @@
 public class AESCryptSubstitutions {
 
     static final long kOffset;
+    static final long lastKeyOffset;
     static final Class<?> AESCryptClass;
     static final int AES_BLOCK_SIZE;
 
@@ -66,6 +68,7 @@
             ClassLoader cl = Launcher.getLauncher().getClassLoader();
             AESCryptClass = Class.forName("com.sun.crypto.provider.AESCrypt", true, cl);
             kOffset = UnsafeAccess.UNSAFE.objectFieldOffset(AESCryptClass.getDeclaredField("K"));
+            lastKeyOffset = UnsafeAccess.UNSAFE.objectFieldOffset(AESCryptClass.getDeclaredField("lastKey"));
             Field aesBlockSizeField = Class.forName("com.sun.crypto.provider.AESConstants", true, cl).getDeclaredField("AES_BLOCK_SIZE");
             aesBlockSizeField.setAccessible(true);
             AES_BLOCK_SIZE = aesBlockSizeField.getInt(null);
@@ -75,32 +78,53 @@
     }
 
     static void encryptBlock(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset) {
-        crypt(rcvr, in, inOffset, out, outOffset, true);
+        crypt(rcvr, in, inOffset, out, outOffset, true, false);
     }
 
     static void implEncryptBlock(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset) {
-        crypt(rcvr, in, inOffset, out, outOffset, true);
+        crypt(rcvr, in, inOffset, out, outOffset, true, false);
     }
 
     static void decryptBlock(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset) {
-        crypt(rcvr, in, inOffset, out, outOffset, false);
+        crypt(rcvr, in, inOffset, out, outOffset, false, false);
     }
 
     static void implDecryptBlock(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset) {
-        crypt(rcvr, in, inOffset, out, outOffset, false);
+        crypt(rcvr, in, inOffset, out, outOffset, false, false);
     }
 
-    private static void crypt(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset, boolean encrypt) {
+    /**
+     * Variation for platforms (e.g. SPARC) that need do key expansion in stubs due to compatibility
+     * issues between Java key expansion and hardware crypto instructions.
+     */
+    static void decryptBlockWithOriginalKey(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset) {
+        crypt(rcvr, in, inOffset, out, outOffset, false, true);
+    }
+
+    /**
+     * @see #decryptBlockWithOriginalKey(Object, byte[], int, byte[], int)
+     */
+    static void implDecryptBlockWithOriginalKey(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset) {
+        crypt(rcvr, in, inOffset, out, outOffset, false, true);
+    }
+
+    private static void crypt(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset, boolean encrypt, boolean withOriginalKey) {
         checkArgs(in, inOffset, out, outOffset);
         Object realReceiver = PiNode.piCastNonNull(rcvr, AESCryptClass);
         Object kObject = UnsafeLoadNode.load(realReceiver, kOffset, JavaKind.Object, LocationIdentity.any());
-        Pointer kAddr = Word.objectToTrackedPointer(kObject).add(getArrayBaseOffset(JavaKind.Byte));
+        Pointer kAddr = Word.objectToTrackedPointer(kObject).add(getArrayBaseOffset(JavaKind.Int));
         Word inAddr = Word.unsigned(ComputeObjectAddressNode.get(in, getArrayBaseOffset(JavaKind.Byte) + inOffset));
         Word outAddr = Word.unsigned(ComputeObjectAddressNode.get(out, getArrayBaseOffset(JavaKind.Byte) + outOffset));
         if (encrypt) {
             encryptBlockStub(ENCRYPT_BLOCK, inAddr, outAddr, kAddr);
         } else {
-            decryptBlockStub(DECRYPT_BLOCK, inAddr, outAddr, kAddr);
+            if (withOriginalKey) {
+                Object lastKeyObject = UnsafeLoadNode.load(realReceiver, lastKeyOffset, JavaKind.Object, LocationIdentity.any());
+                Pointer lastKeyAddr = Word.objectToTrackedPointer(lastKeyObject).add(getArrayBaseOffset(JavaKind.Byte));
+                decryptBlockWithOriginalKeyStub(DECRYPT_BLOCK_WITH_ORIGINAL_KEY, inAddr, outAddr, kAddr, lastKeyAddr);
+            } else {
+                decryptBlockStub(DECRYPT_BLOCK, inAddr, outAddr, kAddr);
+            }
         }
     }
 
@@ -118,4 +142,7 @@
 
     @NodeIntrinsic(ForeignCallNode.class)
     public static native void decryptBlockStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word in, Word out, Pointer key);
+
+    @NodeIntrinsic(ForeignCallNode.class)
+    public static native void decryptBlockWithOriginalKeyStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word in, Word out, Pointer key, Pointer originalKey);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CipherBlockChainingSubstitutions.java	Wed Nov 18 12:01:29 2015 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CipherBlockChainingSubstitutions.java	Wed Nov 18 12:01:42 2015 -0800
@@ -23,6 +23,7 @@
 package com.oracle.graal.hotspot.replacements;
 
 import static com.oracle.graal.hotspot.HotSpotBackend.DECRYPT;
+import static com.oracle.graal.hotspot.HotSpotBackend.DECRYPT_WITH_ORIGINAL_KEY;
 import static com.oracle.graal.hotspot.HotSpotBackend.ENCRYPT;
 import static com.oracle.graal.hotspot.replacements.UnsafeAccess.UNSAFE;
 import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayBaseOffset;
@@ -79,7 +80,7 @@
         Object embeddedCipher = UnsafeLoadNode.load(realReceiver, embeddedCipherOffset, JavaKind.Object, LocationIdentity.any());
         if (getAESCryptClass().isInstance(embeddedCipher)) {
             Object aesCipher = PiNode.piCastNonNull(embeddedCipher, AESCryptSubstitutions.AESCryptClass);
-            crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, true);
+            crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, true, false);
             return inLength;
         } else {
             return encrypt(realReceiver, in, inOffset, inLength, out, outOffset);
@@ -91,7 +92,7 @@
         Object embeddedCipher = UnsafeLoadNode.load(realReceiver, embeddedCipherOffset, JavaKind.Object, LocationIdentity.any());
         if (getAESCryptClass().isInstance(embeddedCipher)) {
             Object aesCipher = PiNode.piCastNonNull(embeddedCipher, AESCryptSubstitutions.AESCryptClass);
-            crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, true);
+            crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, true, false);
             return inLength;
         } else {
             return implEncrypt(realReceiver, in, inOffset, inLength, out, outOffset);
@@ -103,7 +104,7 @@
         Object embeddedCipher = UnsafeLoadNode.load(realReceiver, embeddedCipherOffset, JavaKind.Object, LocationIdentity.any());
         if (in != out && getAESCryptClass().isInstance(embeddedCipher)) {
             Object aesCipher = PiNode.piCastNonNull(embeddedCipher, AESCryptSubstitutions.AESCryptClass);
-            crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, false);
+            crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, false, false);
             return inLength;
         } else {
             return decrypt(realReceiver, in, inOffset, inLength, out, outOffset);
@@ -115,26 +116,64 @@
         Object embeddedCipher = UnsafeLoadNode.load(realReceiver, embeddedCipherOffset, JavaKind.Object, LocationIdentity.any());
         if (in != out && getAESCryptClass().isInstance(embeddedCipher)) {
             Object aesCipher = PiNode.piCastNonNull(embeddedCipher, AESCryptSubstitutions.AESCryptClass);
-            crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, false);
+            crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, false, false);
             return inLength;
         } else {
             return implDecrypt(realReceiver, in, inOffset, inLength, out, outOffset);
         }
     }
 
-    private static void crypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset, Object embeddedCipher, boolean encrypt) {
+    /**
+     * Variation for platforms (e.g. SPARC) that need do key expansion in stubs due to compatibility
+     * issues between Java key expansion and hardware crypto instructions.
+     */
+    static int decryptWithOriginalKey(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset) {
+        Object realReceiver = PiNode.piCastNonNull(rcvr, cipherBlockChainingClass);
+        Object embeddedCipher = UnsafeLoadNode.load(realReceiver, embeddedCipherOffset, JavaKind.Object, LocationIdentity.any());
+        if (in != out && getAESCryptClass().isInstance(embeddedCipher)) {
+            Object aesCipher = PiNode.piCastNonNull(embeddedCipher, AESCryptSubstitutions.AESCryptClass);
+            crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, false, true);
+            return inLength;
+        } else {
+            return decryptWithOriginalKey(realReceiver, in, inOffset, inLength, out, outOffset);
+        }
+    }
+
+    /**
+     * @see #decryptWithOriginalKey(Object, byte[], int, int, byte[], int)
+     */
+    static int implDecryptWithOriginalKey(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset) {
+        Object realReceiver = PiNode.piCastNonNull(rcvr, cipherBlockChainingClass);
+        Object embeddedCipher = UnsafeLoadNode.load(realReceiver, embeddedCipherOffset, JavaKind.Object, LocationIdentity.any());
+        if (in != out && getAESCryptClass().isInstance(embeddedCipher)) {
+            Object aesCipher = PiNode.piCastNonNull(embeddedCipher, AESCryptSubstitutions.AESCryptClass);
+            crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, false, true);
+            return inLength;
+        } else {
+            return implDecryptWithOriginalKey(realReceiver, in, inOffset, inLength, out, outOffset);
+        }
+    }
+
+    private static void crypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset, Object embeddedCipher, boolean encrypt, boolean withOriginalKey) {
         AESCryptSubstitutions.checkArgs(in, inOffset, out, outOffset);
         Object realReceiver = PiNode.piCastNonNull(rcvr, cipherBlockChainingClass);
-        Object kObject = UnsafeLoadNode.load(embeddedCipher, AESCryptSubstitutions.kOffset, JavaKind.Object, LocationIdentity.any());
+        Object aesCipher = PiNode.piCastNonNull(embeddedCipher, AESCryptSubstitutions.AESCryptClass);
+        Object kObject = UnsafeLoadNode.load(aesCipher, AESCryptSubstitutions.kOffset, JavaKind.Object, LocationIdentity.any());
         Object rObject = UnsafeLoadNode.load(realReceiver, rOffset, JavaKind.Object, LocationIdentity.any());
-        Pointer kAddr = Word.objectToTrackedPointer(kObject).add(getArrayBaseOffset(JavaKind.Byte));
+        Pointer kAddr = Word.objectToTrackedPointer(kObject).add(getArrayBaseOffset(JavaKind.Int));
         Pointer rAddr = Word.objectToTrackedPointer(rObject).add(getArrayBaseOffset(JavaKind.Byte));
         Word inAddr = Word.unsigned(ComputeObjectAddressNode.get(in, getArrayBaseOffset(JavaKind.Byte) + inOffset));
         Word outAddr = Word.unsigned(ComputeObjectAddressNode.get(out, getArrayBaseOffset(JavaKind.Byte) + outOffset));
         if (encrypt) {
             encryptAESCryptStub(ENCRYPT, inAddr, outAddr, kAddr, rAddr, inLength);
         } else {
-            decryptAESCryptStub(DECRYPT, inAddr, outAddr, kAddr, rAddr, inLength);
+            if (withOriginalKey) {
+                Object lastKeyObject = UnsafeLoadNode.load(aesCipher, AESCryptSubstitutions.lastKeyOffset, JavaKind.Object, LocationIdentity.any());
+                Pointer lastKeyAddr = Word.objectToTrackedPointer(lastKeyObject).add(getArrayBaseOffset(JavaKind.Byte));
+                decryptAESCryptWithOriginalKeyStub(DECRYPT_WITH_ORIGINAL_KEY, inAddr, outAddr, kAddr, rAddr, inLength, lastKeyAddr);
+            } else {
+                decryptAESCryptStub(DECRYPT, inAddr, outAddr, kAddr, rAddr, inLength);
+            }
         }
     }
 
@@ -143,4 +182,7 @@
 
     @NodeIntrinsic(ForeignCallNode.class)
     public static native void decryptAESCryptStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word in, Word out, Pointer key, Pointer r, int inLength);
+
+    @NodeIntrinsic(ForeignCallNode.class)
+    public static native void decryptAESCryptWithOriginalKeyStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word in, Word out, Pointer key, Pointer r, int inLength, Pointer originalKey);
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstruction.java	Wed Nov 18 12:01:29 2015 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstruction.java	Wed Nov 18 12:01:42 2015 -0800
@@ -26,6 +26,7 @@
 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.CONST;
 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.HINT;
 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.ILLEGAL;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.OUTGOING;
 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.REG;
 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.STACK;
 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.UNINITIALIZED;
@@ -160,6 +161,9 @@
          * is only used to avoid false positives in verification code.
          */
         UNINITIALIZED,
+
+        /** Outgoing block value. */
+        OUTGOING,
     }
 
     /**
@@ -170,7 +174,7 @@
     static {
         ALLOWED_FLAGS = new EnumMap<>(OperandMode.class);
         ALLOWED_FLAGS.put(OperandMode.USE, EnumSet.of(REG, STACK, COMPOSITE, CONST, ILLEGAL, HINT, UNINITIALIZED));
-        ALLOWED_FLAGS.put(ALIVE, EnumSet.of(REG, STACK, COMPOSITE, CONST, ILLEGAL, HINT, UNINITIALIZED));
+        ALLOWED_FLAGS.put(ALIVE, EnumSet.of(REG, STACK, COMPOSITE, CONST, ILLEGAL, HINT, UNINITIALIZED, OUTGOING));
         ALLOWED_FLAGS.put(TEMP, EnumSet.of(REG, STACK, COMPOSITE, ILLEGAL, HINT));
         ALLOWED_FLAGS.put(DEF, EnumSet.of(REG, STACK, COMPOSITE, ILLEGAL, HINT));
     }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StandardOp.java	Wed Nov 18 12:01:29 2015 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StandardOp.java	Wed Nov 18 12:01:42 2015 -0800
@@ -24,6 +24,7 @@
 
 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.CONST;
 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.HINT;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.OUTGOING;
 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.REG;
 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.STACK;
 import static com.oracle.graal.lir.LIRValueUtil.isVariable;
@@ -172,9 +173,9 @@
 
     public abstract static class AbstractBlockEndOp extends LIRInstruction implements BlockEndOp {
         public static final LIRInstructionClass<AbstractBlockEndOp> TYPE = LIRInstructionClass.create(AbstractBlockEndOp.class);
-        private static final EnumSet<OperandFlag> flags = EnumSet.of(REG, STACK, CONST);
+        private static final EnumSet<OperandFlag> flags = EnumSet.of(REG, STACK, CONST, OUTGOING);
 
-        @Alive({REG, STACK, CONST}) private Value[] outgoingValues;
+        @Alive({REG, STACK, CONST, OUTGOING}) private Value[] outgoingValues;
         private int size;
 
         protected AbstractBlockEndOp(LIRInstructionClass<? extends AbstractBlockEndOp> c) {
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScan.java	Wed Nov 18 12:01:29 2015 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScan.java	Wed Nov 18 12:01:42 2015 -0800
@@ -722,7 +722,7 @@
                 }
             }
         }
-        Debug.dump(new LinearScanIntervalDumper(Arrays.copyOf(intervals, intervalsSize)), label);
+        Debug.dump(1, new LinearScanIntervalDumper(Arrays.copyOf(intervals, intervalsSize)), label);
     }
 
     public void printLir(String label, @SuppressWarnings("unused") boolean hirValid) {
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceLinearScanLifetimeAnalysisPhase.java	Wed Nov 18 12:01:29 2015 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceLinearScanLifetimeAnalysisPhase.java	Wed Nov 18 12:01:42 2015 -0800
@@ -23,13 +23,15 @@
 package com.oracle.graal.lir.alloc.trace;
 
 import static com.oracle.graal.lir.LIRValueUtil.asVariable;
+import static com.oracle.graal.lir.LIRValueUtil.isStackSlotValue;
 import static com.oracle.graal.lir.LIRValueUtil.isVariable;
 import static com.oracle.graal.lir.alloc.trace.TraceLinearScan.isVariableOrRegister;
 import static com.oracle.graal.lir.alloc.trace.TraceRegisterAllocationPhase.Options.TraceRAshareSpillInformation;
 import static com.oracle.graal.lir.alloc.trace.TraceRegisterAllocationPhase.Options.TraceRAuseInterTraceHints;
+import static com.oracle.graal.lir.alloc.trace.TraceUtil.asShadowedRegisterValue;
+import static com.oracle.graal.lir.alloc.trace.TraceUtil.isShadowedRegisterValue;
 import static jdk.vm.ci.code.ValueUtil.asRegisterValue;
 import static jdk.vm.ci.code.ValueUtil.asStackSlot;
-import static jdk.vm.ci.code.ValueUtil.isIllegal;
 import static jdk.vm.ci.code.ValueUtil.isRegister;
 import static jdk.vm.ci.code.ValueUtil.isStackSlot;
 
@@ -41,6 +43,7 @@
 import jdk.vm.ci.code.Register;
 import jdk.vm.ci.code.RegisterValue;
 import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.common.JVMCIError;
 import jdk.vm.ci.meta.AllocatableValue;
 import jdk.vm.ci.meta.JavaConstant;
 import jdk.vm.ci.meta.LIRKind;
@@ -57,6 +60,7 @@
 import com.oracle.graal.lir.LIRInstruction;
 import com.oracle.graal.lir.LIRInstruction.OperandFlag;
 import com.oracle.graal.lir.LIRInstruction.OperandMode;
+import com.oracle.graal.lir.LIRValueUtil;
 import com.oracle.graal.lir.StandardOp.BlockEndOp;
 import com.oracle.graal.lir.StandardOp.LabelOp;
 import com.oracle.graal.lir.StandardOp.LoadConstantOp;
@@ -437,6 +441,9 @@
          * register.
          */
         private static RegisterPriority registerPriorityOfInputOperand(EnumSet<OperandFlag> flags) {
+            if (flags.contains(OperandFlag.OUTGOING)) {
+                return RegisterPriority.None;
+            }
             if (flags.contains(OperandFlag.STACK)) {
                 return RegisterPriority.ShouldHaveRegister;
             }
@@ -581,21 +588,12 @@
                         BlockEndOp outgoing = SSIUtil.outgoing(lir, pred);
                         for (int i = 0; i < outgoing.getOutgoingSize(); i++) {
                             Value toValue = label.getIncomingValue(i);
-                            if (!isIllegal(toValue) && !isRegister(toValue)) {
+                            assert !isShadowedRegisterValue(toValue) : "Shadowed Registers are not allowed here: " + toValue;
+                            if (isVariable(toValue)) {
                                 Value fromValue = outgoing.getOutgoingValue(i);
                                 assert sameTrace(block, pred) || !isVariable(fromValue) : "Unallocated variable: " + fromValue;
-
-                                if (isVariableOrRegister(fromValue)) {
-                                    IntervalHint from = getIntervalHint((AllocatableValue) fromValue);
-                                    TraceInterval to = allocator.getOrCreateInterval((AllocatableValue) toValue);
-                                    setHint(label, to, from);
-                                } else if (TraceRAshareSpillInformation.getValue() && TraceUtil.isShadowedRegisterValue(fromValue)) {
-                                    ShadowedRegisterValue shadowedRegisterValue = TraceUtil.asShadowedRegisterValue(fromValue);
-                                    IntervalHint from = getIntervalHint(shadowedRegisterValue.getRegister());
-                                    TraceInterval to = allocator.getOrCreateInterval((AllocatableValue) toValue);
-                                    setHint(label, to, from);
-                                    to.setSpillSlot(shadowedRegisterValue.getStackSlot());
-                                    to.setSpillState(SpillState.StartInMemory);
+                                if (!LIRValueUtil.isConstantValue(fromValue)) {
+                                    addInterTraceHint(label, (AllocatableValue) toValue, fromValue);
                                 }
                             }
                         }
@@ -604,6 +602,29 @@
             }
         }
 
+        private void addInterTraceHint(LabelOp label, AllocatableValue toValue, Value fromValue) {
+            assert isVariable(toValue) : "Wrong toValue: " + toValue;
+            assert isRegister(fromValue) || isVariable(fromValue) || isStackSlotValue(fromValue) || isShadowedRegisterValue(fromValue) : "Wrong fromValue: " + fromValue;
+            if (isVariableOrRegister(fromValue)) {
+                TraceInterval to = allocator.getOrCreateInterval(toValue);
+                IntervalHint from = getIntervalHint((AllocatableValue) fromValue);
+                setHint(label, to, from);
+            } else if (isStackSlotValue(fromValue)) {
+                TraceInterval to = allocator.getOrCreateInterval(toValue);
+                to.setSpillSlot((AllocatableValue) fromValue);
+                to.setSpillState(SpillState.StartInMemory);
+            } else if (TraceRAshareSpillInformation.getValue() && isShadowedRegisterValue(fromValue)) {
+                ShadowedRegisterValue shadowedRegisterValue = asShadowedRegisterValue(fromValue);
+                IntervalHint from = getIntervalHint(shadowedRegisterValue.getRegister());
+                TraceInterval to = allocator.getOrCreateInterval(toValue);
+                setHint(label, to, from);
+                to.setSpillSlot(shadowedRegisterValue.getStackSlot());
+                to.setSpillState(SpillState.StartInMemory);
+            } else {
+                throw JVMCIError.shouldNotReachHere();
+            }
+        }
+
         /**
          * Returns a value for a interval definition, which can be used for re-materialization.
          *
@@ -619,6 +640,9 @@
                 LoadConstantOp move = (LoadConstantOp) op;
                 if (move.getConstant() instanceof JavaConstant) {
                     if (!allocator.neverSpillConstants()) {
+                        if (!allocator.getSpillMoveFactory().allowConstantToStackMove(move.getConstant())) {
+                            return null;
+                        }
                         /*
                          * Check if the interval has any uses which would accept an stack location
                          * (priority == ShouldHaveRegister). Rematerialization of such intervals can
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceLinearScanWalker.java	Wed Nov 18 12:01:29 2015 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceLinearScanWalker.java	Wed Nov 18 12:01:42 2015 -0800
@@ -640,9 +640,13 @@
             // The new created part is added to the unhandled list and will get a register
             // when it is activated
             int minSplitPos = currentPos + 1;
-            int maxSplitPos = Math.min(interval.nextUsage(RegisterPriority.MustHaveRegister, minSplitPos), interval.to());
+            int maxSplitPos = interval.nextUsage(RegisterPriority.MustHaveRegister, minSplitPos);
 
-            splitBeforeUsage(interval, minSplitPos, maxSplitPos);
+            if (maxSplitPos <= interval.to()) {
+                splitBeforeUsage(interval, minSplitPos, maxSplitPos);
+            } else {
+                Debug.log("No more usage, no need to split: %s", interval);
+            }
 
             assert interval.nextUsage(RegisterPriority.MustHaveRegister, currentPos) == Integer.MAX_VALUE : "the remaining part is spilled to stack and therefore has no register";
             splitForSpilling(interval);
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGeneratorTool.java	Wed Nov 18 12:01:29 2015 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGeneratorTool.java	Wed Nov 18 12:01:42 2015 -0800
@@ -67,6 +67,12 @@
          */
         boolean canInlineConstant(JavaConstant c);
 
+        /**
+         * @param constant The constant that might be moved to a stack slot.
+         * @return {@code true} if constant to stack moves are supported for this constant.
+         */
+        boolean allowConstantToStackMove(Constant constant);
+
         LIRInstruction createMove(AllocatableValue result, Value input);
 
         LIRInstruction createStackMove(AllocatableValue result, AllocatableValue input);
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/VerifyingMoveFactory.java	Wed Nov 18 12:01:29 2015 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/VerifyingMoveFactory.java	Wed Nov 18 12:01:42 2015 -0800
@@ -54,6 +54,10 @@
         return inner.canInlineConstant(c);
     }
 
+    public boolean allowConstantToStackMove(Constant constant) {
+        return inner.allowConstantToStackMove(constant);
+    }
+
     public LIRInstruction createMove(AllocatableValue result, Value input) {
         LIRInstruction inst = inner.createMove(result, input);
         assert checkResult(inst, result, input);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.loop.phases/src/com/oracle/graal/loop/phases/ContextlessLoopPhase.java	Wed Nov 18 12:01:42 2015 -0800
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2015, 2015, 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.loop.phases;
+
+import com.oracle.graal.loop.LoopPolicies;
+import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.phases.tiers.PhaseContext;
+
+public abstract class ContextlessLoopPhase<P extends LoopPolicies> extends LoopPhase<P> {
+
+    public ContextlessLoopPhase(P policies) {
+        super(policies);
+    }
+
+    public final void apply(final StructuredGraph graph) {
+        apply(graph, true);
+    }
+
+    public final void apply(final StructuredGraph graph, final boolean dumpGraph) {
+        apply(graph, null, dumpGraph);
+    }
+
+    protected abstract void run(StructuredGraph graph);
+
+    @Override
+    protected final void run(StructuredGraph graph, PhaseContext context) {
+        run(graph);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.loop.phases/src/com/oracle/graal/loop/phases/LoopFullUnrollPhase.java	Wed Nov 18 12:01:42 2015 -0800
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.loop.phases;
+
+import com.oracle.graal.debug.Debug;
+import com.oracle.graal.debug.DebugMetric;
+import com.oracle.graal.loop.LoopEx;
+import com.oracle.graal.loop.LoopPolicies;
+import com.oracle.graal.loop.LoopsData;
+import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.phases.common.CanonicalizerPhase;
+import com.oracle.graal.phases.tiers.PhaseContext;
+
+public class LoopFullUnrollPhase extends LoopPhase<LoopPolicies> {
+
+    private static final DebugMetric FULLY_UNROLLED_LOOPS = Debug.metric("FullUnrolls");
+    private final CanonicalizerPhase canonicalizer;
+
+    public LoopFullUnrollPhase(CanonicalizerPhase canonicalizer, LoopPolicies policies) {
+        super(policies);
+        this.canonicalizer = canonicalizer;
+    }
+
+    @Override
+    protected void run(StructuredGraph graph, PhaseContext context) {
+        if (graph.hasLoops()) {
+            boolean peeled;
+            do {
+                peeled = false;
+                final LoopsData dataCounted = new LoopsData(graph);
+                dataCounted.detectedCountedLoops();
+                for (LoopEx loop : dataCounted.countedLoops()) {
+                    if (getPolicies().shouldFullUnroll(loop)) {
+                        Debug.log("FullUnroll %s", loop);
+                        LoopTransformations.fullUnroll(loop, context, canonicalizer);
+                        FULLY_UNROLLED_LOOPS.increment();
+                        Debug.dump(graph, "FullUnroll %s", loop);
+                        peeled = true;
+                        break;
+                    }
+                }
+                dataCounted.deleteUnusedNodes();
+            } while (peeled);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.loop.phases/src/com/oracle/graal/loop/phases/LoopPeelingPhase.java	Wed Nov 18 12:01:42 2015 -0800
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2012, 2015, 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.loop.phases;
+
+import com.oracle.graal.debug.Debug;
+import com.oracle.graal.loop.LoopEx;
+import com.oracle.graal.loop.LoopPolicies;
+import com.oracle.graal.loop.LoopsData;
+import com.oracle.graal.nodes.StructuredGraph;
+
+public class LoopPeelingPhase extends ContextlessLoopPhase<LoopPolicies> {
+
+    public LoopPeelingPhase(LoopPolicies policies) {
+        super(policies);
+    }
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        if (graph.hasLoops()) {
+            LoopsData data = new LoopsData(graph);
+            for (LoopEx loop : data.outerFirst()) {
+                if (getPolicies().shouldPeel(loop, data.getCFG())) {
+                    Debug.log("Peeling %s", loop);
+                    LoopTransformations.peel(loop);
+                    Debug.dump(graph, "Peeling %s", loop);
+                }
+            }
+            data.deleteUnusedNodes();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.loop.phases/src/com/oracle/graal/loop/phases/LoopPhase.java	Wed Nov 18 12:01:42 2015 -0800
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.loop.phases;
+
+import com.oracle.graal.loop.LoopPolicies;
+import com.oracle.graal.phases.BasePhase;
+import com.oracle.graal.phases.tiers.PhaseContext;
+
+public abstract class LoopPhase<P extends LoopPolicies> extends BasePhase<PhaseContext> {
+    private P policies;
+
+    public LoopPhase(P policies) {
+        this.policies = policies;
+    }
+
+    protected P getPolicies() {
+        return policies;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.loop.phases/src/com/oracle/graal/loop/phases/LoopSafepointEliminationPhase.java	Wed Nov 18 12:01:42 2015 -0800
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2011, 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.loop.phases;
+
+import com.oracle.graal.loop.LoopEx;
+import com.oracle.graal.loop.LoopsData;
+import com.oracle.graal.nodes.FixedNode;
+import com.oracle.graal.nodes.Invoke;
+import com.oracle.graal.nodes.LoopEndNode;
+import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.nodes.cfg.Block;
+import com.oracle.graal.nodes.extended.ForeignCallNode;
+import com.oracle.graal.phases.BasePhase;
+import com.oracle.graal.phases.tiers.MidTierContext;
+
+public class LoopSafepointEliminationPhase extends BasePhase<MidTierContext> {
+
+    @Override
+    protected void run(StructuredGraph graph, MidTierContext context) {
+        LoopsData loops = new LoopsData(graph);
+        if (context.getOptimisticOptimizations().useLoopLimitChecks() && graph.getGuardsStage().allowsFloatingGuards()) {
+            loops.detectedCountedLoops();
+            for (LoopEx loop : loops.countedLoops()) {
+                if (loop.loop().getChildren().isEmpty() && loop.counted().getStamp().getBits() <= 32) {
+                    boolean hasSafepoint = false;
+                    for (LoopEndNode loopEnd : loop.loopBegin().loopEnds()) {
+                        hasSafepoint |= loopEnd.canSafepoint();
+                    }
+                    if (hasSafepoint) {
+                        loop.counted().createOverFlowGuard();
+                        loop.loopBegin().disableSafepoint();
+                    }
+                }
+            }
+        }
+        for (LoopEx loop : loops.countedLoops()) {
+            for (LoopEndNode loopEnd : loop.loopBegin().loopEnds()) {
+                Block b = loops.getCFG().blockFor(loopEnd);
+                blocks: while (b != loop.loop().getHeader()) {
+                    assert b != null;
+                    for (FixedNode node : b.getNodes()) {
+                        if (node instanceof Invoke || node instanceof ForeignCallNode) {
+                            loopEnd.disableSafepoint();
+                            break blocks;
+                        }
+                    }
+                    b = b.getDominator();
+                }
+            }
+        }
+        loops.deleteUnusedNodes();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.loop.phases/src/com/oracle/graal/loop/phases/LoopTransformations.java	Wed Nov 18 12:01:42 2015 -0800
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.loop.phases;
+
+import static com.oracle.graal.compiler.common.GraalOptions.MaximumDesiredSize;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.oracle.graal.graph.Graph.Mark;
+import com.oracle.graal.graph.NodePosIterator;
+import com.oracle.graal.graph.Position;
+import com.oracle.graal.loop.LoopEx;
+import com.oracle.graal.loop.LoopFragmentWhole;
+import com.oracle.graal.nodeinfo.InputType;
+import com.oracle.graal.nodes.AbstractBeginNode;
+import com.oracle.graal.nodes.BeginNode;
+import com.oracle.graal.nodes.ControlSplitNode;
+import com.oracle.graal.nodes.IfNode;
+import com.oracle.graal.nodes.LoopBeginNode;
+import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.nodes.extended.SwitchNode;
+import com.oracle.graal.phases.common.CanonicalizerPhase;
+import com.oracle.graal.phases.tiers.PhaseContext;
+
+import jdk.vm.ci.code.BailoutException;
+
+public abstract class LoopTransformations {
+
+    private LoopTransformations() {
+        // does not need to be instantiated
+    }
+
+    public static void peel(LoopEx loop) {
+        loop.inside().duplicate().insertBefore(loop);
+        loop.loopBegin().setLoopFrequency(Math.max(0.0, loop.loopBegin().loopFrequency() - 1));
+    }
+
+    public static void fullUnroll(LoopEx loop, PhaseContext context, CanonicalizerPhase canonicalizer) {
+        // assert loop.isCounted(); //TODO (gd) strenghten : counted with known trip count
+        LoopBeginNode loopBegin = loop.loopBegin();
+        StructuredGraph graph = loopBegin.graph();
+        while (!loopBegin.isDeleted()) {
+            Mark mark = graph.getMark();
+            peel(loop);
+            canonicalizer.applyIncremental(graph, context, mark);
+            loopBegin.removeDeadPhis();
+            loop.invalidateFragments();
+            if (graph.getNodeCount() > MaximumDesiredSize.getValue() * 3) {
+                throw new BailoutException("FullUnroll : Graph seems to grow out of proportion");
+            }
+        }
+    }
+
+    public static void unswitch(LoopEx loop, List<ControlSplitNode> controlSplitNodeSet) {
+        ControlSplitNode firstNode = controlSplitNodeSet.iterator().next();
+        LoopFragmentWhole originalLoop = loop.whole();
+        StructuredGraph graph = firstNode.graph();
+
+        loop.loopBegin().incrementUnswitches();
+
+        // create new control split out of loop
+        ControlSplitNode newControlSplit = (ControlSplitNode) firstNode.copyWithInputs();
+        originalLoop.entryPoint().replaceAtPredecessor(newControlSplit);
+
+        /*
+         * The code below assumes that all of the control split nodes have the same successor
+         * structure, which should have been enforced by findUnswitchable.
+         */
+        NodePosIterator successors = firstNode.successors().iterator();
+        assert successors.hasNext();
+        // original loop is used as first successor
+        Position firstPosition = successors.nextPosition();
+        AbstractBeginNode originalLoopBegin = BeginNode.begin(originalLoop.entryPoint());
+        firstPosition.set(newControlSplit, originalLoopBegin);
+
+        while (successors.hasNext()) {
+            Position position = successors.nextPosition();
+            // create a new loop duplicate and connect it.
+            LoopFragmentWhole duplicateLoop = originalLoop.duplicate();
+            AbstractBeginNode newBegin = BeginNode.begin(duplicateLoop.entryPoint());
+            position.set(newControlSplit, newBegin);
+
+            // For each cloned ControlSplitNode, simplify the proper path
+            for (ControlSplitNode controlSplitNode : controlSplitNodeSet) {
+                ControlSplitNode duplicatedControlSplit = duplicateLoop.getDuplicatedNode(controlSplitNode);
+                if (duplicatedControlSplit.isAlive()) {
+                    AbstractBeginNode survivingSuccessor = (AbstractBeginNode) position.get(duplicatedControlSplit);
+                    survivingSuccessor.replaceAtUsages(InputType.Guard, newBegin);
+                    graph.removeSplitPropagate(duplicatedControlSplit, survivingSuccessor);
+                }
+            }
+        }
+        // original loop is simplified last to avoid deleting controlSplitNode too early
+        for (ControlSplitNode controlSplitNode : controlSplitNodeSet) {
+            if (controlSplitNode.isAlive()) {
+                AbstractBeginNode survivingSuccessor = (AbstractBeginNode) firstPosition.get(controlSplitNode);
+                survivingSuccessor.replaceAtUsages(InputType.Guard, originalLoopBegin);
+                graph.removeSplitPropagate(controlSplitNode, survivingSuccessor);
+            }
+        }
+
+        // TODO (gd) probabilities need some amount of fixup.. (probably also in other transforms)
+    }
+
+    public static List<ControlSplitNode> findUnswitchable(LoopEx loop) {
+        List<ControlSplitNode> controls = null;
+        ValueNode invariantValue = null;
+        for (IfNode ifNode : loop.whole().nodes().filter(IfNode.class)) {
+            if (loop.isOutsideLoop(ifNode.condition())) {
+                if (controls == null) {
+                    invariantValue = ifNode.condition();
+                    controls = new ArrayList<>();
+                    controls.add(ifNode);
+                } else if (ifNode.condition() == invariantValue) {
+                    controls.add(ifNode);
+                }
+            }
+        }
+        if (controls == null) {
+            SwitchNode firstSwitch = null;
+            for (SwitchNode switchNode : loop.whole().nodes().filter(SwitchNode.class)) {
+                if (switchNode.successors().count() > 1 && loop.isOutsideLoop(switchNode.value())) {
+                    if (controls == null) {
+                        firstSwitch = switchNode;
+                        invariantValue = switchNode.value();
+                        controls = new ArrayList<>();
+                        controls.add(switchNode);
+                    } else if (switchNode.value() == invariantValue && firstSwitch.structureEquals(switchNode)) {
+                        // Only collect switches which test the same values in the same order
+                        controls.add(switchNode);
+                    }
+                }
+            }
+        }
+        return controls;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.loop.phases/src/com/oracle/graal/loop/phases/LoopUnswitchingPhase.java	Wed Nov 18 12:01:42 2015 -0800
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.loop.phases;
+
+import java.util.List;
+
+import com.oracle.graal.debug.Debug;
+import com.oracle.graal.debug.DebugMetric;
+import com.oracle.graal.graph.NodePosIterator;
+import com.oracle.graal.loop.LoopEx;
+import com.oracle.graal.loop.LoopPolicies;
+import com.oracle.graal.loop.LoopsData;
+import com.oracle.graal.nodes.AbstractBeginNode;
+import com.oracle.graal.nodes.ControlSplitNode;
+import com.oracle.graal.nodes.StructuredGraph;
+
+public class LoopUnswitchingPhase extends ContextlessLoopPhase<LoopPolicies> {
+    private static final DebugMetric UNSWITCHED = Debug.metric("Unswitched");
+    private static final DebugMetric UNSWITCH_CANDIDATES = Debug.metric("UnswitchCandidates");
+    private static final DebugMetric UNSWITCH_EARLY_REJECTS = Debug.metric("UnswitchEarlyRejects");
+
+    public LoopUnswitchingPhase(LoopPolicies policies) {
+        super(policies);
+    }
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        if (graph.hasLoops()) {
+            boolean unswitched;
+            do {
+                unswitched = false;
+                final LoopsData dataUnswitch = new LoopsData(graph);
+                for (LoopEx loop : dataUnswitch.outerFirst()) {
+                    if (getPolicies().shouldTryUnswitch(loop)) {
+                        List<ControlSplitNode> controlSplits = LoopTransformations.findUnswitchable(loop);
+                        if (controlSplits != null) {
+                            UNSWITCH_CANDIDATES.increment();
+                            if (getPolicies().shouldUnswitch(loop, controlSplits)) {
+                                if (Debug.isLogEnabled()) {
+                                    logUnswitch(loop, controlSplits);
+                                }
+                                LoopTransformations.unswitch(loop, controlSplits);
+                                UNSWITCHED.increment();
+                                unswitched = true;
+                                break;
+                            }
+                        }
+                    } else {
+                        UNSWITCH_EARLY_REJECTS.increment();
+                    }
+                }
+            } while (unswitched);
+        }
+    }
+
+    private static void logUnswitch(LoopEx loop, List<ControlSplitNode> controlSplits) {
+        StringBuilder sb = new StringBuilder("Unswitching ");
+        sb.append(loop).append(" at ");
+        for (ControlSplitNode controlSplit : controlSplits) {
+            sb.append(controlSplit).append(" [");
+            NodePosIterator it = controlSplit.successors().iterator();
+            while (it.hasNext()) {
+                sb.append(controlSplit.probability((AbstractBeginNode) it.next()));
+                if (it.hasNext()) {
+                    sb.append(", ");
+                }
+            }
+            sb.append("]");
+        }
+        Debug.log("%s", sb);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.loop.phases/src/com/oracle/graal/loop/phases/ReassociateInvariantPhase.java	Wed Nov 18 12:01:42 2015 -0800
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2015, 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.loop.phases;
+
+import com.oracle.graal.debug.Debug;
+import com.oracle.graal.debug.Debug.Scope;
+import com.oracle.graal.loop.LoopEx;
+import com.oracle.graal.loop.LoopsData;
+import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.phases.Phase;
+
+public class ReassociateInvariantPhase extends Phase {
+
+    @SuppressWarnings("try")
+    @Override
+    protected void run(StructuredGraph graph) {
+        if (graph.hasLoops()) {
+            final LoopsData dataReassociate = new LoopsData(graph);
+            try (Scope s = Debug.scope("ReassociateInvariants")) {
+                for (LoopEx loop : dataReassociate.loops()) {
+                    loop.reassociateInvariants();
+                }
+            } catch (Throwable e) {
+                throw Debug.handle(e);
+            }
+            dataReassociate.deleteUnusedNodes();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DefaultLoopPolicies.java	Wed Nov 18 12:01:42 2015 -0800
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2012, 2015, 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.loop;
+
+import static com.oracle.graal.compiler.common.GraalOptions.LoopMaxUnswitch;
+import static com.oracle.graal.compiler.common.GraalOptions.MaximumDesiredSize;
+import static com.oracle.graal.compiler.common.GraalOptions.MinimumPeelProbability;
+
+import java.util.List;
+
+import jdk.vm.ci.options.Option;
+import jdk.vm.ci.options.OptionType;
+import jdk.vm.ci.options.OptionValue;
+
+import com.oracle.graal.debug.Debug;
+import com.oracle.graal.debug.DebugMetric;
+import com.oracle.graal.graph.Node;
+import com.oracle.graal.nodes.AbstractBeginNode;
+import com.oracle.graal.nodes.ControlSplitNode;
+import com.oracle.graal.nodes.LoopBeginNode;
+import com.oracle.graal.nodes.MergeNode;
+import com.oracle.graal.nodes.VirtualState;
+import com.oracle.graal.nodes.VirtualState.VirtualClosure;
+import com.oracle.graal.nodes.cfg.Block;
+import com.oracle.graal.nodes.cfg.ControlFlowGraph;
+import com.oracle.graal.nodes.debug.ControlFlowAnchorNode;
+
+public class DefaultLoopPolicies implements LoopPolicies {
+    @Option(help = "", type = OptionType.Expert) public static final OptionValue<Integer> LoopUnswitchMaxIncrease = new OptionValue<>(500);
+    @Option(help = "", type = OptionType.Expert) public static final OptionValue<Integer> LoopUnswitchTrivial = new OptionValue<>(10);
+    @Option(help = "", type = OptionType.Expert) public static final OptionValue<Double> LoopUnswitchFrequencyBoost = new OptionValue<>(10.0);
+
+    @Option(help = "", type = OptionType.Expert) public static final OptionValue<Integer> FullUnrollMaxNodes = new OptionValue<>(300);
+    @Option(help = "", type = OptionType.Expert) public static final OptionValue<Integer> FullUnrollMaxIterations = new OptionValue<>(600);
+    @Option(help = "", type = OptionType.Expert) public static final OptionValue<Integer> ExactFullUnrollMaxNodes = new OptionValue<>(1200);
+
+    // TODO (gd) change when inversion is available
+    @Override
+    public boolean shouldPeel(LoopEx loop, ControlFlowGraph cfg) {
+        if (loop.detectCounted()) {
+            return false;
+        }
+        LoopBeginNode loopBegin = loop.loopBegin();
+        double entryProbability = cfg.blockFor(loopBegin.forwardEnd()).probability();
+        if (entryProbability > MinimumPeelProbability.getValue() && loop.size() + loopBegin.graph().getNodeCount() < MaximumDesiredSize.getValue()) {
+            // check whether we're allowed to peel this loop
+            for (Node node : loop.inside().nodes()) {
+                if (node instanceof ControlFlowAnchorNode) {
+                    return false;
+                }
+            }
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    @Override
+    public boolean shouldFullUnroll(LoopEx loop) {
+        if (!loop.isCounted() || !loop.counted().isConstantMaxTripCount()) {
+            return false;
+        }
+        CountedLoopInfo counted = loop.counted();
+        long maxTrips = counted.constantMaxTripCount();
+        int maxNodes = (counted.isExactTripCount() && counted.isConstantExactTripCount()) ? ExactFullUnrollMaxNodes.getValue() : FullUnrollMaxNodes.getValue();
+        maxNodes = Math.min(maxNodes, MaximumDesiredSize.getValue() - loop.loopBegin().graph().getNodeCount());
+        int size = Math.max(1, loop.size() - 1 - loop.loopBegin().phis().count());
+        if (maxTrips <= FullUnrollMaxIterations.getValue() && size * maxTrips <= maxNodes) {
+            // check whether we're allowed to unroll this loop
+            for (Node node : loop.inside().nodes()) {
+                if (node instanceof ControlFlowAnchorNode) {
+                    return false;
+                }
+            }
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    @Override
+    public boolean shouldTryUnswitch(LoopEx loop) {
+        LoopBeginNode loopBegin = loop.loopBegin();
+        double loopFrequency = loopBegin.loopFrequency();
+        if (loopFrequency <= 1.0) {
+            return false;
+        }
+        return loopBegin.unswitches() <= LoopMaxUnswitch.getValue();
+    }
+
+    private static final class CountingClosure implements VirtualClosure {
+        int count;
+
+        public void apply(VirtualState node) {
+            count++;
+        }
+    }
+
+    private static class IsolatedInitialization {
+        static final DebugMetric UNSWITCH_SPLIT_WITH_PHIS = Debug.metric("UnswitchSplitWithPhis");
+    }
+
+    @Override
+    public boolean shouldUnswitch(LoopEx loop, List<ControlSplitNode> controlSplits) {
+        int inBranchTotal = 0;
+        int phis = 0;
+        for (ControlSplitNode controlSplit : controlSplits) {
+            for (Node successor : controlSplit.successors()) {
+                AbstractBeginNode branch = (AbstractBeginNode) successor;
+                // this may count twice because of fall-through in switches
+                inBranchTotal += loop.nodesInLoopBranch(branch).count();
+            }
+            Block postDomBlock = loop.loopsData().getCFG().blockFor(controlSplit).getPostdominator();
+            if (postDomBlock != null) {
+                IsolatedInitialization.UNSWITCH_SPLIT_WITH_PHIS.increment();
+                phis += ((MergeNode) postDomBlock.getBeginNode()).phis().count();
+            }
+        }
+
+        CountingClosure stateNodesCount = new CountingClosure();
+        double loopFrequency = loop.loopBegin().loopFrequency();
+        int maxDiff = LoopUnswitchTrivial.getValue() + (int) (LoopUnswitchFrequencyBoost.getValue() * (loopFrequency - 1.0 + phis));
+
+        maxDiff = Math.min(maxDiff, LoopUnswitchMaxIncrease.getValue());
+        int remainingGraphSpace = MaximumDesiredSize.getValue() - loop.loopBegin().graph().getNodeCount();
+        maxDiff = Math.min(maxDiff, remainingGraphSpace);
+
+        loop.loopBegin().stateAfter().applyToVirtual(stateNodesCount);
+        int loopTotal = loop.size() - loop.loopBegin().phis().count() - stateNodesCount.count - 1;
+        int actualDiff = loopTotal - inBranchTotal;
+
+        Debug.log("shouldUnswitch(%s, %s) : delta=%d (%.2f%% inside of branches), max=%d, f=%.2f, phis=%d -> %b", loop, controlSplits, actualDiff, (double) (inBranchTotal) / loopTotal * 100, maxDiff,
+                        loopFrequency, phis, actualDiff <= maxDiff);
+        return actualDiff <= maxDiff;
+    }
+
+}
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopPolicies.java	Wed Nov 18 12:01:29 2015 -0800
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopPolicies.java	Wed Nov 18 12:01:42 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2015, 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
@@ -22,136 +22,17 @@
  */
 package com.oracle.graal.loop;
 
-import static com.oracle.graal.compiler.common.GraalOptions.LoopMaxUnswitch;
-import static com.oracle.graal.compiler.common.GraalOptions.MaximumDesiredSize;
-import static com.oracle.graal.compiler.common.GraalOptions.MinimumPeelProbability;
-
 import java.util.List;
 
-import jdk.vm.ci.options.Option;
-import jdk.vm.ci.options.OptionType;
-import jdk.vm.ci.options.OptionValue;
-
-import com.oracle.graal.debug.Debug;
-import com.oracle.graal.debug.DebugMetric;
-import com.oracle.graal.graph.Node;
-import com.oracle.graal.nodes.AbstractBeginNode;
 import com.oracle.graal.nodes.ControlSplitNode;
-import com.oracle.graal.nodes.LoopBeginNode;
-import com.oracle.graal.nodes.MergeNode;
-import com.oracle.graal.nodes.VirtualState;
-import com.oracle.graal.nodes.VirtualState.VirtualClosure;
-import com.oracle.graal.nodes.cfg.Block;
 import com.oracle.graal.nodes.cfg.ControlFlowGraph;
-import com.oracle.graal.nodes.debug.ControlFlowAnchorNode;
-
-public abstract class LoopPolicies {
-    @Option(help = "", type = OptionType.Expert) public static final OptionValue<Integer> LoopUnswitchMaxIncrease = new OptionValue<>(500);
-    @Option(help = "", type = OptionType.Expert) public static final OptionValue<Integer> LoopUnswitchTrivial = new OptionValue<>(10);
-    @Option(help = "", type = OptionType.Expert) public static final OptionValue<Double> LoopUnswitchFrequencyBoost = new OptionValue<>(10.0);
 
-    @Option(help = "", type = OptionType.Expert) public static final OptionValue<Integer> FullUnrollMaxNodes = new OptionValue<>(300);
-    @Option(help = "", type = OptionType.Expert) public static final OptionValue<Integer> FullUnrollMaxIterations = new OptionValue<>(600);
-    @Option(help = "", type = OptionType.Expert) public static final OptionValue<Integer> ExactFullUnrollMaxNodes = new OptionValue<>(1200);
-
-    private LoopPolicies() {
-        // does not need to be instantiated
-    }
-
-    // TODO (gd) change when inversion is available
-    public static boolean shouldPeel(LoopEx loop, ControlFlowGraph cfg) {
-        if (loop.detectCounted()) {
-            return false;
-        }
-        LoopBeginNode loopBegin = loop.loopBegin();
-        double entryProbability = cfg.blockFor(loopBegin.forwardEnd()).probability();
-        if (entryProbability > MinimumPeelProbability.getValue() && loop.size() + loopBegin.graph().getNodeCount() < MaximumDesiredSize.getValue()) {
-            // check whether we're allowed to peel this loop
-            for (Node node : loop.inside().nodes()) {
-                if (node instanceof ControlFlowAnchorNode) {
-                    return false;
-                }
-            }
-            return true;
-        } else {
-            return false;
-        }
-    }
+public interface LoopPolicies {
+    boolean shouldPeel(LoopEx loop, ControlFlowGraph cfg);
 
-    public static boolean shouldFullUnroll(LoopEx loop) {
-        if (!loop.isCounted() || !loop.counted().isConstantMaxTripCount()) {
-            return false;
-        }
-        CountedLoopInfo counted = loop.counted();
-        long maxTrips = counted.constantMaxTripCount();
-        int maxNodes = (counted.isExactTripCount() && counted.isConstantExactTripCount()) ? ExactFullUnrollMaxNodes.getValue() : FullUnrollMaxNodes.getValue();
-        maxNodes = Math.min(maxNodes, MaximumDesiredSize.getValue() - loop.loopBegin().graph().getNodeCount());
-        int size = Math.max(1, loop.size() - 1 - loop.loopBegin().phis().count());
-        if (size * maxTrips <= maxNodes) {
-            // check whether we're allowed to unroll this loop
-            for (Node node : loop.inside().nodes()) {
-                if (node instanceof ControlFlowAnchorNode) {
-                    return false;
-                }
-            }
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    public static boolean shouldTryUnswitch(LoopEx loop) {
-        LoopBeginNode loopBegin = loop.loopBegin();
-        double loopFrequency = loopBegin.loopFrequency();
-        if (loopFrequency <= 1.0) {
-            return false;
-        }
-        return loopBegin.unswitches() <= LoopMaxUnswitch.getValue();
-    }
-
-    private static final class CountingClosure implements VirtualClosure {
-        int count;
-
-        public void apply(VirtualState node) {
-            count++;
-        }
-    }
+    boolean shouldFullUnroll(LoopEx loop);
 
-    private static class IsolatedInitialization {
-        static final DebugMetric UNSWITCH_SPLIT_WITH_PHIS = Debug.metric("UnswitchSplitWithPhis");
-    }
+    boolean shouldTryUnswitch(LoopEx loop);
 
-    public static boolean shouldUnswitch(LoopEx loop, List<ControlSplitNode> controlSplits) {
-        int inBranchTotal = 0;
-        int phis = 0;
-        for (ControlSplitNode controlSplit : controlSplits) {
-            for (Node successor : controlSplit.successors()) {
-                AbstractBeginNode branch = (AbstractBeginNode) successor;
-                // this may count twice because of fall-through in switches
-                inBranchTotal += loop.nodesInLoopBranch(branch).count();
-            }
-            Block postDomBlock = loop.loopsData().getCFG().blockFor(controlSplit).getPostdominator();
-            if (postDomBlock != null) {
-                IsolatedInitialization.UNSWITCH_SPLIT_WITH_PHIS.increment();
-                phis += ((MergeNode) postDomBlock.getBeginNode()).phis().count();
-            }
-        }
-
-        CountingClosure stateNodesCount = new CountingClosure();
-        double loopFrequency = loop.loopBegin().loopFrequency();
-        int maxDiff = LoopUnswitchTrivial.getValue() + (int) (LoopUnswitchFrequencyBoost.getValue() * (loopFrequency - 1.0 + phis));
-
-        maxDiff = Math.min(maxDiff, LoopUnswitchMaxIncrease.getValue());
-        int remainingGraphSpace = MaximumDesiredSize.getValue() - loop.loopBegin().graph().getNodeCount();
-        maxDiff = Math.min(maxDiff, remainingGraphSpace);
-
-        loop.loopBegin().stateAfter().applyToVirtual(stateNodesCount);
-        int loopTotal = loop.size() - loop.loopBegin().phis().count() - stateNodesCount.count - 1;
-        int actualDiff = loopTotal - inBranchTotal;
-
-        Debug.log("shouldUnswitch(%s, %s) : delta=%d (%.2f%% inside of branches), max=%d, f=%.2f, phis=%d -> %b", loop, controlSplits, actualDiff, (double) (inBranchTotal) / loopTotal * 100, maxDiff,
-                        loopFrequency, phis, actualDiff <= maxDiff);
-        return actualDiff <= maxDiff;
-    }
-
+    boolean shouldUnswitch(LoopEx loop, List<ControlSplitNode> controlSplits);
 }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopTransformations.java	Wed Nov 18 12:01:29 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,158 +0,0 @@
-/*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.loop;
-
-import static com.oracle.graal.compiler.common.GraalOptions.MaximumDesiredSize;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import jdk.vm.ci.code.BailoutException;
-
-import com.oracle.graal.graph.Graph.Mark;
-import com.oracle.graal.graph.NodePosIterator;
-import com.oracle.graal.graph.Position;
-import com.oracle.graal.nodeinfo.InputType;
-import com.oracle.graal.nodes.AbstractBeginNode;
-import com.oracle.graal.nodes.BeginNode;
-import com.oracle.graal.nodes.ControlSplitNode;
-import com.oracle.graal.nodes.IfNode;
-import com.oracle.graal.nodes.LoopBeginNode;
-import com.oracle.graal.nodes.StructuredGraph;
-import com.oracle.graal.nodes.ValueNode;
-import com.oracle.graal.nodes.extended.SwitchNode;
-import com.oracle.graal.phases.common.CanonicalizerPhase;
-import com.oracle.graal.phases.tiers.PhaseContext;
-
-public abstract class LoopTransformations {
-
-    private LoopTransformations() {
-        // does not need to be instantiated
-    }
-
-    public static void peel(LoopEx loop) {
-        loop.inside().duplicate().insertBefore(loop);
-        loop.loopBegin().setLoopFrequency(Math.max(0.0, loop.loopBegin().loopFrequency() - 1));
-    }
-
-    public static void fullUnroll(LoopEx loop, PhaseContext context, CanonicalizerPhase canonicalizer) {
-        // assert loop.isCounted(); //TODO (gd) strenghten : counted with known trip count
-        int iterations = 0;
-        LoopBeginNode loopBegin = loop.loopBegin();
-        StructuredGraph graph = loopBegin.graph();
-        while (!loopBegin.isDeleted()) {
-            Mark mark = graph.getMark();
-            peel(loop);
-            canonicalizer.applyIncremental(graph, context, mark);
-            loopBegin.removeDeadPhis();
-            loop.invalidateFragments();
-            if (iterations++ > LoopPolicies.FullUnrollMaxIterations.getValue() || graph.getNodeCount() > MaximumDesiredSize.getValue() * 3) {
-                throw new BailoutException("FullUnroll : Graph seems to grow out of proportion");
-            }
-        }
-    }
-
-    public static void unswitch(LoopEx loop, List<ControlSplitNode> controlSplitNodeSet) {
-        ControlSplitNode firstNode = controlSplitNodeSet.iterator().next();
-        LoopFragmentWhole originalLoop = loop.whole();
-        StructuredGraph graph = firstNode.graph();
-
-        loop.loopBegin().incrementUnswitches();
-
-        // create new control split out of loop
-        ControlSplitNode newControlSplit = (ControlSplitNode) firstNode.copyWithInputs();
-        originalLoop.entryPoint().replaceAtPredecessor(newControlSplit);
-
-        /*
-         * The code below assumes that all of the control split nodes have the same successor
-         * structure, which should have been enforced by findUnswitchable.
-         */
-        NodePosIterator successors = firstNode.successors().iterator();
-        assert successors.hasNext();
-        // original loop is used as first successor
-        Position firstPosition = successors.nextPosition();
-        AbstractBeginNode originalLoopBegin = BeginNode.begin(originalLoop.entryPoint());
-        firstPosition.set(newControlSplit, originalLoopBegin);
-
-        while (successors.hasNext()) {
-            Position position = successors.nextPosition();
-            // create a new loop duplicate and connect it.
-            LoopFragmentWhole duplicateLoop = originalLoop.duplicate();
-            AbstractBeginNode newBegin = BeginNode.begin(duplicateLoop.entryPoint());
-            position.set(newControlSplit, newBegin);
-
-            // For each cloned ControlSplitNode, simplify the proper path
-            for (ControlSplitNode controlSplitNode : controlSplitNodeSet) {
-                ControlSplitNode duplicatedControlSplit = duplicateLoop.getDuplicatedNode(controlSplitNode);
-                if (duplicatedControlSplit.isAlive()) {
-                    AbstractBeginNode survivingSuccessor = (AbstractBeginNode) position.get(duplicatedControlSplit);
-                    survivingSuccessor.replaceAtUsages(InputType.Guard, newBegin);
-                    graph.removeSplitPropagate(duplicatedControlSplit, survivingSuccessor);
-                }
-            }
-        }
-        // original loop is simplified last to avoid deleting controlSplitNode too early
-        for (ControlSplitNode controlSplitNode : controlSplitNodeSet) {
-            if (controlSplitNode.isAlive()) {
-                AbstractBeginNode survivingSuccessor = (AbstractBeginNode) firstPosition.get(controlSplitNode);
-                survivingSuccessor.replaceAtUsages(InputType.Guard, originalLoopBegin);
-                graph.removeSplitPropagate(controlSplitNode, survivingSuccessor);
-            }
-        }
-
-        // TODO (gd) probabilities need some amount of fixup.. (probably also in other transforms)
-    }
-
-    public static List<ControlSplitNode> findUnswitchable(LoopEx loop) {
-        List<ControlSplitNode> controls = null;
-        ValueNode invariantValue = null;
-        for (IfNode ifNode : loop.whole().nodes().filter(IfNode.class)) {
-            if (loop.isOutsideLoop(ifNode.condition())) {
-                if (controls == null) {
-                    invariantValue = ifNode.condition();
-                    controls = new ArrayList<>();
-                    controls.add(ifNode);
-                } else if (ifNode.condition() == invariantValue) {
-                    controls.add(ifNode);
-                }
-            }
-        }
-        if (controls == null) {
-            SwitchNode firstSwitch = null;
-            for (SwitchNode switchNode : loop.whole().nodes().filter(SwitchNode.class)) {
-                if (switchNode.successors().count() > 1 && loop.isOutsideLoop(switchNode.value())) {
-                    if (controls == null) {
-                        firstSwitch = switchNode;
-                        invariantValue = switchNode.value();
-                        controls = new ArrayList<>();
-                        controls.add(switchNode);
-                    } else if (switchNode.value() == invariantValue && firstSwitch.structureEquals(switchNode)) {
-                        // Only collect switches which test the same values in the same order
-                        controls.add(switchNode);
-                    }
-                }
-            }
-        }
-        return controls;
-    }
-}
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopFullUnrollPhase.java	Wed Nov 18 12:01:29 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-/*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.loop.phases;
-
-import com.oracle.graal.debug.Debug;
-import com.oracle.graal.debug.DebugMetric;
-import com.oracle.graal.loop.LoopEx;
-import com.oracle.graal.loop.LoopPolicies;
-import com.oracle.graal.loop.LoopTransformations;
-import com.oracle.graal.loop.LoopsData;
-import com.oracle.graal.nodes.StructuredGraph;
-import com.oracle.graal.phases.BasePhase;
-import com.oracle.graal.phases.common.CanonicalizerPhase;
-import com.oracle.graal.phases.tiers.PhaseContext;
-
-public class LoopFullUnrollPhase extends BasePhase<PhaseContext> {
-
-    private static final DebugMetric FULLY_UNROLLED_LOOPS = Debug.metric("FullUnrolls");
-    private final CanonicalizerPhase canonicalizer;
-
-    public LoopFullUnrollPhase(CanonicalizerPhase canonicalizer) {
-        this.canonicalizer = canonicalizer;
-    }
-
-    @Override
-    protected void run(StructuredGraph graph, PhaseContext context) {
-        if (graph.hasLoops()) {
-            boolean peeled;
-            do {
-                peeled = false;
-                final LoopsData dataCounted = new LoopsData(graph);
-                dataCounted.detectedCountedLoops();
-                for (LoopEx loop : dataCounted.countedLoops()) {
-                    if (LoopPolicies.shouldFullUnroll(loop)) {
-                        Debug.log("FullUnroll %s", loop);
-                        LoopTransformations.fullUnroll(loop, context, canonicalizer);
-                        FULLY_UNROLLED_LOOPS.increment();
-                        Debug.dump(graph, "FullUnroll %s", loop);
-                        peeled = true;
-                        break;
-                    }
-                }
-                dataCounted.deleteUnusedNodes();
-            } while (peeled);
-        }
-    }
-}
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopPeelingPhase.java	Wed Nov 18 12:01:29 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2012, 2015, 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.loop.phases;
-
-import com.oracle.graal.debug.Debug;
-import com.oracle.graal.loop.LoopEx;
-import com.oracle.graal.loop.LoopPolicies;
-import com.oracle.graal.loop.LoopTransformations;
-import com.oracle.graal.loop.LoopsData;
-import com.oracle.graal.nodes.StructuredGraph;
-import com.oracle.graal.phases.Phase;
-
-public class LoopPeelingPhase extends Phase {
-
-    @Override
-    protected void run(StructuredGraph graph) {
-        if (graph.hasLoops()) {
-            LoopsData data = new LoopsData(graph);
-            for (LoopEx loop : data.outerFirst()) {
-                if (LoopPolicies.shouldPeel(loop, data.getCFG())) {
-                    Debug.log("Peeling %s", loop);
-                    LoopTransformations.peel(loop);
-                    Debug.dump(graph, "Peeling %s", loop);
-                }
-            }
-            data.deleteUnusedNodes();
-        }
-    }
-}
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopSafepointEliminationPhase.java	Wed Nov 18 12:01:29 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,73 +0,0 @@
-/*
- * Copyright (c) 2011, 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.loop.phases;
-
-import com.oracle.graal.loop.LoopEx;
-import com.oracle.graal.loop.LoopsData;
-import com.oracle.graal.nodes.FixedNode;
-import com.oracle.graal.nodes.Invoke;
-import com.oracle.graal.nodes.LoopEndNode;
-import com.oracle.graal.nodes.StructuredGraph;
-import com.oracle.graal.nodes.cfg.Block;
-import com.oracle.graal.nodes.extended.ForeignCallNode;
-import com.oracle.graal.phases.BasePhase;
-import com.oracle.graal.phases.tiers.MidTierContext;
-
-public class LoopSafepointEliminationPhase extends BasePhase<MidTierContext> {
-
-    @Override
-    protected void run(StructuredGraph graph, MidTierContext context) {
-        LoopsData loops = new LoopsData(graph);
-        if (context.getOptimisticOptimizations().useLoopLimitChecks() && graph.getGuardsStage().allowsFloatingGuards()) {
-            loops.detectedCountedLoops();
-            for (LoopEx loop : loops.countedLoops()) {
-                if (loop.loop().getChildren().isEmpty() && loop.counted().getStamp().getBits() <= 32) {
-                    boolean hasSafepoint = false;
-                    for (LoopEndNode loopEnd : loop.loopBegin().loopEnds()) {
-                        hasSafepoint |= loopEnd.canSafepoint();
-                    }
-                    if (hasSafepoint) {
-                        loop.counted().createOverFlowGuard();
-                        loop.loopBegin().disableSafepoint();
-                    }
-                }
-            }
-        }
-        for (LoopEx loop : loops.countedLoops()) {
-            for (LoopEndNode loopEnd : loop.loopBegin().loopEnds()) {
-                Block b = loops.getCFG().blockFor(loopEnd);
-                blocks: while (b != loop.loop().getHeader()) {
-                    assert b != null;
-                    for (FixedNode node : b.getNodes()) {
-                        if (node instanceof Invoke || node instanceof ForeignCallNode) {
-                            loopEnd.disableSafepoint();
-                            break blocks;
-                        }
-                    }
-                    b = b.getDominator();
-                }
-            }
-        }
-        loops.deleteUnusedNodes();
-    }
-}
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopUnswitchingPhase.java	Wed Nov 18 12:01:29 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,91 +0,0 @@
-/*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.loop.phases;
-
-import java.util.List;
-
-import com.oracle.graal.debug.Debug;
-import com.oracle.graal.debug.DebugMetric;
-import com.oracle.graal.graph.NodePosIterator;
-import com.oracle.graal.loop.LoopEx;
-import com.oracle.graal.loop.LoopPolicies;
-import com.oracle.graal.loop.LoopTransformations;
-import com.oracle.graal.loop.LoopsData;
-import com.oracle.graal.nodes.AbstractBeginNode;
-import com.oracle.graal.nodes.ControlSplitNode;
-import com.oracle.graal.nodes.StructuredGraph;
-import com.oracle.graal.phases.Phase;
-
-public class LoopUnswitchingPhase extends Phase {
-
-    private static final DebugMetric UNSWITCHED = Debug.metric("Unswitched");
-    private static final DebugMetric UNSWITCH_CANDIDATES = Debug.metric("UnswitchCandidates");
-    private static final DebugMetric UNSWITCH_EARLY_REJECTS = Debug.metric("UnswitchEarlyRejects");
-
-    @Override
-    protected void run(StructuredGraph graph) {
-        if (graph.hasLoops()) {
-            boolean unswitched;
-            do {
-                unswitched = false;
-                final LoopsData dataUnswitch = new LoopsData(graph);
-                for (LoopEx loop : dataUnswitch.outerFirst()) {
-                    if (LoopPolicies.shouldTryUnswitch(loop)) {
-                        List<ControlSplitNode> controlSplits = LoopTransformations.findUnswitchable(loop);
-                        if (controlSplits != null) {
-                            UNSWITCH_CANDIDATES.increment();
-                            if (LoopPolicies.shouldUnswitch(loop, controlSplits)) {
-                                if (Debug.isLogEnabled()) {
-                                    logUnswitch(loop, controlSplits);
-                                }
-                                LoopTransformations.unswitch(loop, controlSplits);
-                                UNSWITCHED.increment();
-                                unswitched = true;
-                                break;
-                            }
-                        }
-                    } else {
-                        UNSWITCH_EARLY_REJECTS.increment();
-                    }
-                }
-            } while (unswitched);
-        }
-    }
-
-    private static void logUnswitch(LoopEx loop, List<ControlSplitNode> controlSplits) {
-        StringBuilder sb = new StringBuilder("Unswitching ");
-        sb.append(loop).append(" at ");
-        for (ControlSplitNode controlSplit : controlSplits) {
-            sb.append(controlSplit).append(" [");
-            NodePosIterator it = controlSplit.successors().iterator();
-            while (it.hasNext()) {
-                sb.append(controlSplit.probability((AbstractBeginNode) it.next()));
-                if (it.hasNext()) {
-                    sb.append(", ");
-                }
-            }
-            sb.append("]");
-        }
-        Debug.log("%s", sb);
-    }
-}
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/ReassociateInvariantPhase.java	Wed Nov 18 12:01:29 2015 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2015, 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.loop.phases;
-
-import com.oracle.graal.debug.Debug;
-import com.oracle.graal.debug.Debug.Scope;
-import com.oracle.graal.loop.LoopEx;
-import com.oracle.graal.loop.LoopsData;
-import com.oracle.graal.nodes.StructuredGraph;
-import com.oracle.graal.phases.Phase;
-
-public class ReassociateInvariantPhase extends Phase {
-
-    @SuppressWarnings("try")
-    @Override
-    protected void run(StructuredGraph graph) {
-        if (graph.hasLoops()) {
-            final LoopsData dataReassociate = new LoopsData(graph);
-            try (Scope s = Debug.scope("ReassociateInvariants")) {
-                for (LoopEx loop : dataReassociate.loops()) {
-                    loop.reassociateInvariants();
-                }
-            } catch (Throwable e) {
-                throw Debug.handle(e);
-            }
-            dataReassociate.deleteUnusedNodes();
-        }
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/IfNodeCanonicalizationTest.java	Wed Nov 18 12:01:42 2015 -0800
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2015, 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.test;
+
+import org.junit.Assert;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import com.oracle.graal.api.directives.GraalDirectives;
+import com.oracle.graal.compiler.test.GraalCompilerTest;
+import com.oracle.graal.graph.Node;
+import com.oracle.graal.nodes.AbstractMergeNode;
+import com.oracle.graal.nodes.IfNode;
+import com.oracle.graal.nodes.LogicNode;
+import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
+import com.oracle.graal.nodes.calc.SubNode;
+import com.oracle.graal.phases.common.CanonicalizerPhase;
+import com.oracle.graal.phases.common.ConvertDeoptimizeToGuardPhase;
+import com.oracle.graal.phases.common.IterativeConditionalEliminationPhase;
+import com.oracle.graal.phases.tiers.PhaseContext;
+
+/**
+ * A few tests of expected simplifications by
+ * {@link IfNode#simplify(com.oracle.graal.graph.spi.SimplifierTool)}.
+ */
+public class IfNodeCanonicalizationTest extends GraalCompilerTest {
+
+    static int value;
+
+    static final byte[] testValues = {-128, -1, 0, 1, 127};
+
+    @Test
+    public void test1() {
+        /*
+         * exercise conversion of x - y < 0 into x < y, both by checking expected graph shape and
+         * that the transformed code produces the right answer.
+         */
+        test("testSnippet1", SubNode.class, 0);
+        byte[] values = new byte[4];
+        for (byte a : testValues) {
+            values[0] = a;
+            for (byte b : testValues) {
+                values[1] = b;
+                for (byte c : testValues) {
+                    values[2] = c;
+                    for (byte d : testValues) {
+                        values[3] = d;
+                        value = 2;
+                        super.test("testSnippet1", values, true);
+                        super.test("testSnippet1", values, false);
+                    }
+                }
+            }
+        }
+    }
+
+    public int testSnippet1(byte[] values, boolean test) {
+        int v = values[0] - values[1];
+        if (test) {
+            v = values[2] - values[3];
+        }
+        if (v < 0) {
+            value = 1;
+        }
+        return value;
+    }
+
+    @Test
+    public void test2() {
+        test("testSnippet2", 1);
+    }
+
+    public boolean testSnippet2(int a, int[] limit) {
+        int l = limit.length;
+        if (!(a >= 0 && a < l)) {
+            value = a;
+            return true;
+        }
+        return false;
+    }
+
+    @Ignore("currently not working because swapped case isn't handled")
+    @Test
+    public void test3() {
+        test("testSnippet3", 1);
+    }
+
+    public boolean testSnippet3(int a, int[] limit) {
+        int l = limit.length;
+        if (a < l && a >= 0) {
+            value = 9;
+            return true;
+        }
+        return false;
+    }
+
+    @Test
+    public void test4() {
+        test("testSnippet4", 1);
+    }
+
+    public boolean testSnippet4(int a, int[] limit) {
+        int l = limit.length;
+        if (a < 0) {
+            GraalDirectives.deoptimize();
+        }
+        if (a >= l) {
+            GraalDirectives.deoptimize();
+        }
+        return true;
+    }
+
+    @Ignore("Reversed conditions aren't working with guards")
+    @Test
+    public void test5() {
+        test("testSnippet5", 1);
+    }
+
+    public boolean testSnippet5(int a, int[] limit) {
+        int l = limit.length;
+        if (a >= l) {
+            GraalDirectives.deoptimize();
+        }
+        if (a < 0) {
+            GraalDirectives.deoptimize();
+        }
+        return true;
+    }
+
+    public void test(String name, int logicCount) {
+        test(name, LogicNode.class, logicCount);
+    }
+
+    public void test(String name, Class<? extends Node> expectedClass, int expectedCount) {
+        StructuredGraph graph = parseEager(name, AllowAssumptions.YES);
+
+        PhaseContext context = new PhaseContext(getProviders());
+        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        for (AbstractMergeNode merge : graph.getNodes(AbstractMergeNode.TYPE)) {
+            merge.setStateAfter(null);
+        }
+        canonicalizer.apply(graph, context);
+
+        new ConvertDeoptimizeToGuardPhase().apply(graph, context);
+        // new DominatorConditionalEliminationPhase(true).apply(graph, context);
+        new IterativeConditionalEliminationPhase(canonicalizer, true).apply(graph, context);
+        canonicalizer.apply(graph, context);
+        canonicalizer.apply(graph, context);
+
+        Assert.assertEquals(expectedCount, graph.getNodes().filter(expectedClass).count());
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConditionAnchorNode.java	Wed Nov 18 12:01:29 2015 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConditionAnchorNode.java	Wed Nov 18 12:01:42 2015 -0800
@@ -70,12 +70,12 @@
     }
 
     public Node canonical(CanonicalizerTool tool, Node forValue) {
-        if (condition instanceof LogicNegationNode) {
-            LogicNegationNode negation = (LogicNegationNode) condition;
+        if (forValue instanceof LogicNegationNode) {
+            LogicNegationNode negation = (LogicNegationNode) forValue;
             return new ConditionAnchorNode(negation.getValue(), !negated);
         }
-        if (condition instanceof LogicConstantNode) {
-            LogicConstantNode c = (LogicConstantNode) condition;
+        if (forValue instanceof LogicConstantNode) {
+            LogicConstantNode c = (LogicConstantNode) forValue;
             if (c.getValue() != negated) {
                 return null;
             } else {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Wed Nov 18 12:01:29 2015 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Wed Nov 18 12:01:42 2015 -0800
@@ -784,18 +784,18 @@
 
         for (EndNode end : merge.forwardEnds().snapshot()) {
             Node value = phi.valueAt(end);
-            Node result = null;
+            LogicNode result = null;
             if (condition() instanceof Canonicalizable.Binary<?>) {
                 Canonicalizable.Binary<Node> compare = (Canonicalizable.Binary<Node>) condition;
                 if (compare.getX() == phi) {
-                    result = compare.canonical(tool, value, compare.getY());
+                    result = (LogicNode) compare.canonical(tool, value, compare.getY());
                 } else {
-                    result = compare.canonical(tool, compare.getX(), value);
+                    result = (LogicNode) compare.canonical(tool, compare.getX(), value);
                 }
             } else {
                 assert condition() instanceof Canonicalizable.Unary<?>;
                 Canonicalizable.Unary<Node> compare = (Canonicalizable.Unary<Node>) condition;
-                result = compare.canonical(tool, value);
+                result = (LogicNode) compare.canonical(tool, value);
             }
             if (result instanceof LogicConstantNode) {
                 merge.removeEnd(end);
@@ -810,6 +810,31 @@
                     }
                     falseMerge.addForwardEnd(end);
                 }
+            } else if (result != condition) {
+                // Build a new IfNode using the new condition
+                BeginNode trueBegin = graph().add(new BeginNode());
+                BeginNode falseBegin = graph().add(new BeginNode());
+
+                if (result.graph() == null) {
+                    result = graph().addOrUniqueWithInputs(result);
+                }
+                IfNode newIfNode = graph().add(new IfNode(result, trueBegin, falseBegin, trueSuccessorProbability));
+                merge.removeEnd(end);
+                ((FixedWithNextNode) end.predecessor()).setNext(newIfNode);
+
+                if (trueMerge == null) {
+                    trueMerge = insertMerge(trueSuccessor());
+                }
+                trueBegin.setNext(graph().add(new EndNode()));
+                trueMerge.addForwardEnd((EndNode) trueBegin.next());
+
+                if (falseMerge == null) {
+                    falseMerge = insertMerge(falseSuccessor());
+                }
+                falseBegin.setNext(graph().add(new EndNode()));
+                falseMerge.addForwardEnd((EndNode) falseBegin.next());
+
+                end.safeDelete();
             }
         }
         transferProxies(trueSuccessor(), trueMerge);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java	Wed Nov 18 12:01:29 2015 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java	Wed Nov 18 12:01:42 2015 -0800
@@ -132,6 +132,12 @@
             ConvertNode convertX = (ConvertNode) forX;
             ConvertNode convertY = (ConvertNode) forY;
             if (convertX.preservesOrder(condition()) && convertY.preservesOrder(condition()) && convertX.getValue().stamp().isCompatible(convertY.getValue().stamp())) {
+                boolean multiUsage = (convertX.asNode().getUsageCount() > 1 || convertY.asNode().getUsageCount() > 1);
+                if ((forX instanceof ZeroExtendNode || forX instanceof SignExtendNode) && multiUsage) {
+                    // Do not perform for zero or sign extend if there are multiple usages of the
+                    // value.
+                    return this;
+                }
                 return duplicateModified(convertX.getValue(), convertY.getValue());
             }
         }
@@ -154,6 +160,12 @@
             return optimizeNormalizeCmp(constant, (NormalizeCompareNode) nonConstant, mirrored);
         } else if (nonConstant instanceof ConvertNode) {
             ConvertNode convert = (ConvertNode) nonConstant;
+            boolean multiUsage = (convert.asNode().getUsageCount() > 1 && convert.getValue().getUsageCount() == 1);
+            if ((convert instanceof ZeroExtendNode || convert instanceof SignExtendNode) && multiUsage) {
+                // Do not perform for zero or sign extend if it could introduce
+                // new live values.
+                return this;
+            }
             ConstantNode newConstant = canonicalConvertConstant(tool, convert, constant);
             if (newConstant != null) {
                 if (mirrored) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerLessThanNode.java	Wed Nov 18 12:01:29 2015 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerLessThanNode.java	Wed Nov 18 12:01:42 2015 -0800
@@ -83,6 +83,20 @@
         return this;
     }
 
+    public static boolean subtractMayUnderflow(long x, long y, long minValue) {
+        long r = x - y;
+        // HD 2-12 Overflow iff the arguments have different signs and
+        // the sign of the result is different than the sign of x
+        return (((x ^ y) & (x ^ r)) < 0) || r <= minValue;
+    }
+
+    public static boolean subtractMayOverflow(long x, long y, long maxValue) {
+        long r = x - y;
+        // HD 2-12 Overflow iff the arguments have different signs and
+        // the sign of the result is different than the sign of x
+        return (((x ^ y) & (x ^ r)) < 0) || r > maxValue;
+    }
+
     @Override
     public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
         ValueNode result = super.canonical(tool, forX, forY);
@@ -98,6 +112,18 @@
                 return new IntegerBelowNode(forX, forY);
             }
         }
+        if (forY.isConstant() && forY.asConstant().isDefaultForKind() && forX instanceof SubNode) {
+            // (x - y) < 0 when x - y is known not to underflow == x < y
+            SubNode sub = (SubNode) forX;
+            IntegerStamp xStamp = (IntegerStamp) sub.getX().stamp();
+            IntegerStamp yStamp = (IntegerStamp) sub.getY().stamp();
+            long minValue = CodeUtil.minValue(xStamp.getBits());
+            long maxValue = CodeUtil.maxValue(xStamp.getBits());
+
+            if (!subtractMayUnderflow(xStamp.lowerBound(), yStamp.upperBound(), minValue) && !subtractMayOverflow(xStamp.upperBound(), yStamp.lowerBound(), maxValue)) {
+                return new IntegerLessThanNode(sub.getX(), sub.getY());
+            }
+        }
         return this;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowNode.java	Wed Nov 18 12:01:29 2015 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowNode.java	Wed Nov 18 12:01:42 2015 -0800
@@ -85,6 +85,12 @@
         } else if (forValue instanceof IntegerConvertNode) {
             // SignExtendNode or ZeroExtendNode
             IntegerConvertNode<?, ?> other = (IntegerConvertNode<?, ?>) forValue;
+            if (other.getValue().getUsageCount() == 1 && other.getUsageCount() > 1) {
+                // Do not perform if this will introduce a new live value.
+                // If the original value's usage count is > 1, there is already another user.
+                // If the convert's usage count is <=1, it will be dead code eliminated.
+                return this;
+            }
             if (getResultBits() == other.getInputBits()) {
                 // xxxx -(extend)-> yyyy xxxx -(narrow)-> xxxx
                 // ==> no-op
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java	Wed Nov 18 12:01:29 2015 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java	Wed Nov 18 12:01:42 2015 -0800
@@ -48,6 +48,7 @@
 import com.oracle.graal.nodes.ProxyNode;
 import com.oracle.graal.nodes.StartNode;
 import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.nodes.StructuredGraph.GuardsStage;
 
 public class ControlFlowGraph implements AbstractControlFlowGraph<Block> {
     /**
@@ -287,23 +288,27 @@
                     computeLoopBlocks(endBlock, loop);
                 }
 
-                for (LoopExitNode exit : loopBegin.loopExits()) {
-                    Block exitBlock = nodeToBlock.get(exit);
-                    assert exitBlock.getPredecessorCount() == 1;
-                    computeLoopBlocks(exitBlock.getFirstPredecessor(), loop);
-                    loop.getExits().add(exitBlock);
+                if (graph.getGuardsStage() != GuardsStage.AFTER_FSA) {
+                    for (LoopExitNode exit : loopBegin.loopExits()) {
+                        Block exitBlock = nodeToBlock.get(exit);
+                        assert exitBlock.getPredecessorCount() == 1;
+                        computeLoopBlocks(exitBlock.getFirstPredecessor(), loop);
+                        loop.getExits().add(exitBlock);
+                    }
                 }
 
-                // The following loop can add new blocks to the end of the loop's block list.
-                int size = loop.getBlocks().size();
-                for (int i = 0; i < size; ++i) {
-                    Block b = loop.getBlocks().get(i);
-                    for (Block sux : b.getSuccessors()) {
-                        if (sux.loop != loop) {
-                            AbstractBeginNode begin = sux.getBeginNode();
-                            if (!(begin instanceof LoopExitNode && ((LoopExitNode) begin).loopBegin() == loopBegin)) {
-                                Debug.log(3, "Unexpected loop exit with %s, including whole branch in the loop", sux);
-                                addBranchToLoop(loop, sux);
+                if (graph.hasValueProxies()) {
+                    // The following loop can add new blocks to the end of the loop's block list.
+                    int size = loop.getBlocks().size();
+                    for (int i = 0; i < size; ++i) {
+                        Block b = loop.getBlocks().get(i);
+                        for (Block sux : b.getSuccessors()) {
+                            if (sux.loop != loop) {
+                                AbstractBeginNode begin = sux.getBeginNode();
+                                if (!(begin instanceof LoopExitNode && ((LoopExitNode) begin).loopBegin() == loopBegin)) {
+                                    Debug.log(3, "Unexpected loop exit with %s, including whole branch in the loop", sux);
+                                    addBranchToLoop(loop, sux);
+                                }
                             }
                         }
                     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RawMonitorEnterNode.java	Wed Nov 18 12:01:29 2015 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RawMonitorEnterNode.java	Wed Nov 18 12:01:42 2015 -0800
@@ -38,8 +38,8 @@
 import com.oracle.graal.nodes.virtual.VirtualObjectNode;
 
 /**
- * The {@code MonitorEnterNode} represents the acquisition of a monitor. The object needs already be
- * non-null and the hub is an additional parameter to the node.
+ * The {@code RawMonitorEnterNode} represents the acquisition of a monitor. The object needs to
+ * already be non-null and the hub is an additional parameter to the node.
  */
 @NodeInfo
 public final class RawMonitorEnterNode extends AccessMonitorNode implements Virtualizable, Lowerable, IterableNodeType, MonitorEnter, MemoryCheckpoint.Single {
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/MemoryScheduleVerification.java	Wed Nov 18 12:01:29 2015 -0800
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/MemoryScheduleVerification.java	Wed Nov 18 12:01:42 2015 -0800
@@ -140,7 +140,9 @@
     @Override
     protected Set<FloatingReadNode> cloneState(Set<FloatingReadNode> oldState) {
         Set<FloatingReadNode> result = CollectionsFactory.newSet();
-        result.addAll(oldState);
+        if (oldState != null) {
+            result.addAll(oldState);
+        }
         return result;
     }
 
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Wed Nov 18 12:01:29 2015 -0800
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Wed Nov 18 12:01:42 2015 -0800
@@ -49,6 +49,7 @@
 import com.oracle.graal.nodes.AbstractMergeNode;
 import com.oracle.graal.nodes.ControlSinkNode;
 import com.oracle.graal.nodes.ControlSplitNode;
+import com.oracle.graal.nodes.DeoptimizeNode;
 import com.oracle.graal.nodes.FixedNode;
 import com.oracle.graal.nodes.FrameState;
 import com.oracle.graal.nodes.GuardNode;
@@ -275,6 +276,10 @@
             for (Node n : nodes) {
                 assert n.isAlive();
                 assert nodeMap.get(n) == b;
+                StructuredGraph g = (StructuredGraph) n.graph();
+                if (g.hasLoops() && g.getGuardsStage().areDeoptsFixed() && n instanceof DeoptimizeNode) {
+                    assert b.getLoopDepth() == 0 : n;
+                }
             }
         }
         return true;
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java	Wed Nov 18 12:01:29 2015 -0800
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java	Wed Nov 18 12:01:42 2015 -0800
@@ -37,11 +37,6 @@
 import java.util.Map;
 import java.util.Map.Entry;
 
-import jdk.vm.ci.meta.JavaType;
-import jdk.vm.ci.meta.ResolvedJavaField;
-import jdk.vm.ci.meta.ResolvedJavaMethod;
-import jdk.vm.ci.meta.Signature;
-
 import com.oracle.graal.compiler.common.cfg.BlockMap;
 import com.oracle.graal.debug.Debug;
 import com.oracle.graal.graph.CachedGraph;
@@ -66,6 +61,11 @@
 import com.oracle.graal.nodes.cfg.ControlFlowGraph;
 import com.oracle.graal.phases.schedule.SchedulePhase;
 
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.ResolvedJavaField;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.Signature;
+
 public class BinaryGraphPrinter implements GraphPrinter {
 
     private static final int CONSTANT_POOL_MAX_SIZE = 8000;
@@ -428,6 +428,20 @@
         return node.getId();
     }
 
+    private Object getBlockForNode(Node node, NodeMap<Block> nodeToBlocks) {
+        if (nodeToBlocks.isNew(node)) {
+            return "NEW (not in schedule)";
+        } else {
+            Block block = nodeToBlocks.get(node);
+            if (block != null) {
+                return block.getId();
+            } else if (node instanceof PhiNode) {
+                return getBlockForNode(((PhiNode) node).merge(), nodeToBlocks);
+            }
+        }
+        return null;
+    }
+
     private void writeNodes(Graph graph, NodeMap<Block> nodeToBlocks, ControlFlowGraph cfg) throws IOException {
         Map<Object, Object> props = new HashMap<>();
 
@@ -444,13 +458,9 @@
                 }
             }
             if (nodeToBlocks != null) {
-                if (nodeToBlocks.isNew(node)) {
-                    props.put("node-to-block", "NEW (not in schedule)");
-                } else {
-                    Block block = nodeToBlocks.get(node);
-                    if (block != null) {
-                        props.put("node-to-block", block.getId());
-                    }
+                Object block = getBlockForNode(node, nodeToBlocks);
+                if (block != null) {
+                    props.put("node-to-block", block);
                 }
             }
 
@@ -535,9 +545,23 @@
             writeInt(blocks.size());
             for (Block block : blocks) {
                 List<Node> nodes = blockToNodes.get(block);
+                List<Node> extraNodes = new LinkedList<>();
                 writeInt(block.getId());
-                writeInt(nodes.size());
                 for (Node node : nodes) {
+                    if (node instanceof AbstractMergeNode) {
+                        AbstractMergeNode merge = (AbstractMergeNode) node;
+                        for (PhiNode phi : merge.phis()) {
+                            if (!nodes.contains(phi)) {
+                                extraNodes.add(phi);
+                            }
+                        }
+                    }
+                }
+                writeInt(nodes.size() + extraNodes.size());
+                for (Node node : nodes) {
+                    writeInt(getNodeId(node));
+                }
+                for (Node node : extraNodes) {
                     writeInt(getNodeId(node));
                 }
                 writeInt(block.getSuccessors().size());
--- a/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64MathIntrinsicNode.java	Wed Nov 18 12:01:29 2015 -0800
+++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64MathIntrinsicNode.java	Wed Nov 18 12:01:42 2015 -0800
@@ -28,6 +28,7 @@
 
 import com.oracle.graal.compiler.common.type.FloatStamp;
 import com.oracle.graal.compiler.common.type.PrimitiveStamp;
+import com.oracle.graal.compiler.common.type.Stamp;
 import com.oracle.graal.compiler.common.type.StampFactory;
 import com.oracle.graal.graph.NodeClass;
 import com.oracle.graal.graph.spi.CanonicalizerTool;
@@ -81,6 +82,20 @@
     }
 
     @Override
+    public Stamp foldStamp(Stamp newStamp) {
+        if (newStamp instanceof FloatStamp) {
+            FloatStamp floatStamp = (FloatStamp) newStamp;
+            switch (operation()) {
+                case COS:
+                case SIN:
+                    boolean nonNaN = floatStamp.lowerBound() != Double.NEGATIVE_INFINITY && floatStamp.upperBound() != Double.POSITIVE_INFINITY;
+                    return StampFactory.forFloat(JavaKind.Double, -1.0, 1.0, nonNaN);
+            }
+        }
+        return super.foldStamp(newStamp);
+    }
+
+    @Override
     public void generate(NodeLIRBuilderTool nodeValueMap, ArithmeticLIRGeneratorTool lirGen) {
         AMD64ArithmeticLIRGeneratorTool gen = (AMD64ArithmeticLIRGeneratorTool) lirGen;
         Value input = nodeValueMap.operand(getValue());
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Wed Nov 18 12:01:29 2015 -0800
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Wed Nov 18 12:01:42 2015 -0800
@@ -73,8 +73,8 @@
 import com.oracle.graal.graph.NodePosIterator;
 import com.oracle.graal.graph.Position;
 import com.oracle.graal.loop.LoopEx;
-import com.oracle.graal.loop.LoopTransformations;
 import com.oracle.graal.loop.LoopsData;
+import com.oracle.graal.loop.phases.LoopTransformations;
 import com.oracle.graal.nodeinfo.InputType;
 import com.oracle.graal.nodeinfo.NodeInfo;
 import com.oracle.graal.nodes.AbstractBeginNode;
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/debug/TraceCompilationASTListener.java	Wed Nov 18 12:01:29 2015 -0800
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/debug/TraceCompilationASTListener.java	Wed Nov 18 12:01:42 2015 -0800
@@ -69,7 +69,7 @@
                     target.log(String.format("%s%s", indent, node.getClass().getSimpleName()));
                 } else {
                     String fieldName = "unknownField";
-                    NodeFieldAccessor[] fields = NodeClass.Lookup.get(parent).getFields();
+                    NodeFieldAccessor[] fields = NodeClass.get(parent).getFields();
                     for (NodeFieldAccessor field : fields) {
                         Object value = field.loadValue(parent);
                         if (value == node) {
--- a/mx.graal/suite.py	Wed Nov 18 12:01:29 2015 -0800
+++ b/mx.graal/suite.py	Wed Nov 18 12:01:42 2015 -0800
@@ -39,7 +39,7 @@
             {
                "name" : "jvmci",
                "optional" : "true",
-               "version" : "c2b84783a4a4950a5fc5b4c75536291ae6952c40",
+               "version" : "2dea101cdfe9aacf55083cf5bd6f84cb23106f4e",
                "urls" : [
                     {"url" : "http://lafo.ssw.uni-linz.ac.at/hg/graal-jvmci-8", "kind" : "hg"},
                     {"url" : "https://curio.ssw.jku.at/nexus/content/repositories/snapshots", "kind" : "binary"},
@@ -47,7 +47,7 @@
             },
             {
                "name" : "truffle",
-               "version" : "0d4b0e4263ee95e3b0576409d7311489d4f5d463",
+               "version" : "dea950d41ef34ae68759ff0300a1fd80cf145c0f",
                "urls" : [
                     {"url" : "http://lafo.ssw.uni-linz.ac.at/hg/truffle", "kind" : "hg"},
                     {"url" : "https://curio.ssw.jku.at/nexus/content/repositories/snapshots", "kind" : "binary"},
@@ -493,7 +493,7 @@
       "dependencies" : [
         "com.oracle.graal.api.directives",
         "com.oracle.graal.java",
-        "com.oracle.graal.loop",
+        "com.oracle.graal.loop.phases",
         "com.oracle.graal.word",
       ],
       "checkstyle" : "com.oracle.graal.graph",
@@ -664,7 +664,20 @@
     "com.oracle.graal.loop" : {
       "subDir" : "graal",
       "sourceDirs" : ["src"],
-      "dependencies" : ["com.oracle.graal.phases.common"],
+      "dependencies" : ["com.oracle.graal.nodes"],
+      "annotationProcessors" : deps(["jvmci:JVMCI_OPTIONS_PROCESSOR"]),
+      "checkstyle" : "com.oracle.graal.graph",
+      "javaCompliance" : "1.8",
+      "workingSets" : "Graal",
+    },
+
+    "com.oracle.graal.loop.phases" : {
+      "subDir" : "graal",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+	 "com.oracle.graal.loop",
+	 "com.oracle.graal.phases.common",
+       ],
       "annotationProcessors" : deps(["jvmci:JVMCI_OPTIONS_PROCESSOR"]),
       "checkstyle" : "com.oracle.graal.graph",
       "javaCompliance" : "1.8",
@@ -676,7 +689,7 @@
       "sourceDirs" : ["src"],
       "dependencies" : [
         "com.oracle.graal.virtual",
-        "com.oracle.graal.loop",
+        "com.oracle.graal.loop.phases",
       ],
       "checkstyle" : "com.oracle.graal.graph",
       "javaCompliance" : "1.8",