changeset 23013:79266e707964

Merge
author Christian Wimmer <christian.wimmer@oracle.com>
date Tue, 17 Nov 2015 16:32:15 -0800
parents a8bab192d632 (current diff) 6d7d2a220ae0 (diff)
children 60dd55e84d87
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 52 files changed, 1253 insertions(+), 703 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags	Tue Nov 17 16:31:30 2015 -0800
+++ b/.hgtags	Tue Nov 17 16:32:15 2015 -0800
@@ -619,3 +619,4 @@
 efbf340fc7f56e49735111c23cef030413146409 jdk8u45-b13
 3c622007e098d8905d8e0947362a3894a629a5f1 graal-0.8
 3e8357b49024cb168ab5ebd511d8b5c03c068f75 graal-0.9
+795ada9208d8f35991b98bb934f624c70b8a0183 graal-0.10
--- a/CHANGELOG.md	Tue Nov 17 16:31:30 2015 -0800
+++ b/CHANGELOG.md	Tue Nov 17 16:32:15 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	Tue Nov 17 16:31:30 2015 -0800
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64MoveFactory.java	Tue Nov 17 16:32:15 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	Tue Nov 17 16:31:30 2015 -0800
+++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCMoveFactory.java	Tue Nov 17 16:32:15 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	Tue Nov 17 16:31:30 2015 -0800
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java	Tue Nov 17 16:32:15 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	Tue Nov 17 16:31:30 2015 -0800
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/LoopUnswitchTest.java	Tue Nov 17 16:32:15 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	Tue Nov 17 16:31:30 2015 -0800
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java	Tue Nov 17 16:32:15 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	Tue Nov 17 16:31:30 2015 -0800
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java	Tue Nov 17 16:32:15 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	Tue Nov 17 16:31:30 2015 -0800
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EconomyLowTier.java	Tue Nov 17 16:32:15 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	Tue Nov 17 16:31:30 2015 -0800
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EconomyMidTier.java	Tue Nov 17 16:32:15 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	Tue Nov 17 16:31:30 2015 -0800
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java	Tue Nov 17 16:32:15 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	Tue Nov 17 16:31:30 2015 -0800
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugins.java	Tue Nov 17 16:32:15 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	Tue Nov 17 16:31:30 2015 -0800
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotMoveFactory.java	Tue Nov 17 16:32:15 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	Tue Nov 17 16:31:30 2015 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java	Tue Nov 17 16:32:15 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	Tue Nov 17 16:31:30 2015 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java	Tue Nov 17 16:32:15 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	Tue Nov 17 16:31:30 2015 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java	Tue Nov 17 16:32:15 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	Tue Nov 17 16:31:30 2015 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/OnStackReplacementPhase.java	Tue Nov 17 16:32:15 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	Tue Nov 17 16:31:30 2015 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AESCryptSubstitutions.java	Tue Nov 17 16:32:15 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	Tue Nov 17 16:31:30 2015 -0800
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CipherBlockChainingSubstitutions.java	Tue Nov 17 16:32:15 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	Tue Nov 17 16:31:30 2015 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstruction.java	Tue Nov 17 16:32:15 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	Tue Nov 17 16:31:30 2015 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StandardOp.java	Tue Nov 17 16:32:15 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	Tue Nov 17 16:31:30 2015 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScan.java	Tue Nov 17 16:32:15 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	Tue Nov 17 16:31:30 2015 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceLinearScanLifetimeAnalysisPhase.java	Tue Nov 17 16:32:15 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	Tue Nov 17 16:31:30 2015 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceLinearScanWalker.java	Tue Nov 17 16:32:15 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	Tue Nov 17 16:31:30 2015 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGeneratorTool.java	Tue Nov 17 16:32:15 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	Tue Nov 17 16:31:30 2015 -0800
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/VerifyingMoveFactory.java	Tue Nov 17 16:32:15 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	Tue Nov 17 16:32:15 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	Tue Nov 17 16:32:15 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	Tue Nov 17 16:32:15 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	Tue Nov 17 16:32:15 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	Tue Nov 17 16:32:15 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	Tue Nov 17 16:32:15 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	Tue Nov 17 16:32:15 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	Tue Nov 17 16:32:15 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	Tue Nov 17 16:32:15 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	Tue Nov 17 16:31:30 2015 -0800
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopPolicies.java	Tue Nov 17 16:32:15 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	Tue Nov 17 16:31:30 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	Tue Nov 17 16:31:30 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	Tue Nov 17 16:31:30 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	Tue Nov 17 16:31:30 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	Tue Nov 17 16:31:30 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	Tue Nov 17 16:31:30 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	Tue Nov 17 16:32:15 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/IfNode.java	Tue Nov 17 16:31:30 2015 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Tue Nov 17 16:32:15 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/IntegerLessThanNode.java	Tue Nov 17 16:31:30 2015 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerLessThanNode.java	Tue Nov 17 16:32:15 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/cfg/ControlFlowGraph.java	Tue Nov 17 16:31:30 2015 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java	Tue Nov 17 16:32:15 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	Tue Nov 17 16:31:30 2015 -0800
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RawMonitorEnterNode.java	Tue Nov 17 16:32:15 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	Tue Nov 17 16:31:30 2015 -0800
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/MemoryScheduleVerification.java	Tue Nov 17 16:32:15 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	Tue Nov 17 16:31:30 2015 -0800
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Tue Nov 17 16:32:15 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.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Tue Nov 17 16:31:30 2015 -0800
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Tue Nov 17 16:32:15 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	Tue Nov 17 16:31:30 2015 -0800
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/debug/TraceCompilationASTListener.java	Tue Nov 17 16:32:15 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	Tue Nov 17 16:31:30 2015 -0800
+++ b/mx.graal/suite.py	Tue Nov 17 16:32:15 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",