# HG changeset patch # User Christian Wimmer # Date 1447876902 28800 # Node ID 4af472d10ad60e1b388576d2b5759eaf65db2a13 # Parent e3bcc6af1bccea6f9e1f8d1f12ae3306f2c0f5ff# Parent 2b32ccbf4999d884a1edf7e582f5377b4773f21c merge diff -r e3bcc6af1bcc -r 4af472d10ad6 .hgtags --- a/.hgtags Wed Nov 18 12:01:29 2015 -0800 +++ b/.hgtags Wed Nov 18 12:01:42 2015 -0800 @@ -619,3 +619,4 @@ efbf340fc7f56e49735111c23cef030413146409 jdk8u45-b13 3c622007e098d8905d8e0947362a3894a629a5f1 graal-0.8 3e8357b49024cb168ab5ebd511d8b5c03c068f75 graal-0.9 +795ada9208d8f35991b98bb934f624c70b8a0183 graal-0.10 diff -r e3bcc6af1bcc -r 4af472d10ad6 CHANGELOG.md --- a/CHANGELOG.md Wed Nov 18 12:01:29 2015 -0800 +++ b/CHANGELOG.md Wed Nov 18 12:01:42 2015 -0800 @@ -1,12 +1,16 @@ -# GraalVM Changelog +# Graal Changelog This changelog summarizes major changes between Graal versions relevant to developers building technology on top of Graal. The main focus is on APIs exported by Graal but other significant performance/stability changes are mentioned as well. ## `tip` +... + +## Version 0.10 +17-Nov-2015, [Repository Revision](http://hg.openjdk.java.net/graal/graal-compiler/shortlog/graal-0.10) * Added experimental Trace Register Allocator. * All JVMCI (and HotSpot) code has been moved into a [separate repository](http://hg.openjdk.java.net/graal/graal-jvmci-8/). * JVMCI code is now in jdk.vm.ci.* name space. -* Graal now works on top of a JVMCI enabled JDK9 binary. +* Graal now passes the gate on top of a JVMCI enabled JDK9 binary. * Separate Graal compiler can be specified for Truffle compilation with new `-G:TruffleCompiler` option. * Initialization of the Truffle compiler is delayed until first Truffle compilation request. diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64MoveFactory.java --- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64MoveFactory.java Wed Nov 18 12:01:29 2015 -0800 +++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64MoveFactory.java Wed Nov 18 12:01:42 2015 -0800 @@ -44,7 +44,7 @@ import com.oracle.graal.lir.amd64.AMD64Move.MoveToRegOp; import com.oracle.graal.lir.framemap.FrameMapBuilder; -public class AMD64MoveFactory extends AMD64MoveFactoryBase { +public abstract class AMD64MoveFactory extends AMD64MoveFactoryBase { private final FrameMapBuilder frameMapBuilder; diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCMoveFactory.java --- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCMoveFactory.java Wed Nov 18 12:01:29 2015 -0800 +++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCMoveFactory.java Wed Nov 18 12:01:42 2015 -0800 @@ -106,4 +106,10 @@ return false; } } + + @Override + public boolean allowConstantToStackMove(Constant value) { + return false; + } + } diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java Wed Nov 18 12:01:29 2015 -0800 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java Wed Nov 18 12:01:42 2015 -0800 @@ -26,6 +26,7 @@ import org.junit.Ignore; import org.junit.Test; +import com.oracle.graal.loop.DefaultLoopPolicies; import com.oracle.graal.loop.phases.LoopPeelingPhase; import com.oracle.graal.nodes.ReturnNode; import com.oracle.graal.nodes.StructuredGraph; @@ -326,7 +327,7 @@ canonicalizer.apply(graph, context); new InliningPhase(new CanonicalizerPhase()).apply(graph, context); if (loopPeeling) { - new LoopPeelingPhase().apply(graph); + new LoopPeelingPhase(new DefaultLoopPolicies()).apply(graph, context); } new DeadCodeEliminationPhase().apply(graph); canonicalizer.apply(graph, context); diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/LoopUnswitchTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/LoopUnswitchTest.java Wed Nov 18 12:01:29 2015 -0800 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/LoopUnswitchTest.java Wed Nov 18 12:01:42 2015 -0800 @@ -28,6 +28,7 @@ import com.oracle.graal.debug.Debug.Scope; import com.oracle.graal.debug.DebugDumpScope; import com.oracle.graal.graph.Node; +import com.oracle.graal.loop.DefaultLoopPolicies; import com.oracle.graal.loop.phases.LoopUnswitchingPhase; import com.oracle.graal.nodes.StateSplit; import com.oracle.graal.nodes.StructuredGraph; @@ -128,7 +129,7 @@ final StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO); final StructuredGraph referenceGraph = parseEager(referenceSnippet, AllowAssumptions.NO); - new LoopUnswitchingPhase().apply(graph); + new LoopUnswitchingPhase(new DefaultLoopPolicies()).apply(graph); // Framestates create comparison problems for (Node stateSplit : graph.getNodes().filterInterface(StateSplit.class)) { diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java Wed Nov 18 12:01:29 2015 -0800 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java Wed Nov 18 12:01:42 2015 -0800 @@ -28,6 +28,7 @@ import org.junit.Test; import com.oracle.graal.graph.Node; +import com.oracle.graal.loop.DefaultLoopPolicies; import com.oracle.graal.loop.phases.LoopFullUnrollPhase; import com.oracle.graal.loop.phases.LoopPeelingPhase; import com.oracle.graal.nodes.extended.ValueAnchorNode; @@ -312,7 +313,7 @@ @Test public void testFullyUnrolledLoop() { prepareGraph("testFullyUnrolledLoopSnippet", false); - new LoopFullUnrollPhase(new CanonicalizerPhase()).apply(graph, context); + new LoopFullUnrollPhase(new CanonicalizerPhase(), new DefaultLoopPolicies()).apply(graph, context); new PartialEscapePhase(false, new CanonicalizerPhase()).apply(graph, context); Assert.assertEquals(1, returnNodes.size()); Assert.assertTrue(returnNodes.get(0).result() instanceof AllocatedObjectNode); @@ -343,7 +344,7 @@ @Test public void testPeeledLoop() { prepareGraph("testPeeledLoopSnippet", false); - new LoopPeelingPhase().apply(graph); + new LoopPeelingPhase(new DefaultLoopPolicies()).apply(graph); new SchedulePhase().apply(graph); } diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java Wed Nov 18 12:01:29 2015 -0800 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java Wed Nov 18 12:01:42 2015 -0800 @@ -67,6 +67,7 @@ import com.oracle.graal.lir.FullInfopointOp; import com.oracle.graal.lir.LIRFrameState; import com.oracle.graal.lir.LIRInstruction; +import com.oracle.graal.lir.LIRValueUtil; import com.oracle.graal.lir.LabelRef; import com.oracle.graal.lir.SimpleInfopointOp; import com.oracle.graal.lir.StandardOp.JumpOp; @@ -81,7 +82,6 @@ import com.oracle.graal.nodes.AbstractBeginNode; import com.oracle.graal.nodes.AbstractEndNode; import com.oracle.graal.nodes.AbstractMergeNode; -import com.oracle.graal.nodes.ConstantNode; import com.oracle.graal.nodes.DeoptimizingNode; import com.oracle.graal.nodes.DirectCallTargetNode; import com.oracle.graal.nodes.FixedNode; @@ -144,13 +144,6 @@ nodeMatchRules.lirBuilder = this; } - /** - * @return {@code true} if object constant to stack moves are supported. - */ - protected boolean allowObjectConstantToStackMove() { - return true; - } - public NodeMatchRules getNodeMatchRules() { return nodeMatchRules; } @@ -300,10 +293,11 @@ * new Variable. */ value = gen.emitMove(value); - } else if (!allowObjectConstantToStackMove() && node instanceof ConstantNode && !value.getLIRKind().isValue()) { + } else if (LIRValueUtil.isConstantValue(value) && !gen.getMoveFactory().allowConstantToStackMove(LIRValueUtil.asConstant(value))) { /* - * Object constants are not allowed as inputs for PHIs. Explicitly create a copy of - * this value to force it into a register. The new variable is only used in the PHI. + * Some constants are not allowed as inputs for PHIs in certain backends. Explicitly + * create a copy of this value to force it into a register. The new variable is only + * used in the PHI. */ Variable result = gen.newVariable(value.getLIRKind()); gen.emitMove(result, value); diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EconomyLowTier.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EconomyLowTier.java Wed Nov 18 12:01:29 2015 -0800 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EconomyLowTier.java Wed Nov 18 12:01:42 2015 -0800 @@ -29,7 +29,6 @@ import com.oracle.graal.phases.common.CanonicalizerPhase; import com.oracle.graal.phases.common.ExpandLogicPhase; import com.oracle.graal.phases.common.LoweringPhase; -import com.oracle.graal.phases.common.RemoveValueProxyPhase; import com.oracle.graal.phases.tiers.LowTierContext; public class EconomyLowTier extends PhaseSuite { @@ -43,6 +42,5 @@ appendPhase(new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.LOW_TIER)); appendPhase(new ExpandLogicPhase()); - appendPhase(new RemoveValueProxyPhase()); } } diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EconomyMidTier.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EconomyMidTier.java Wed Nov 18 12:01:29 2015 -0800 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EconomyMidTier.java Wed Nov 18 12:01:42 2015 -0800 @@ -31,6 +31,7 @@ import com.oracle.graal.phases.common.GuardLoweringPhase; import com.oracle.graal.phases.common.LoopSafepointInsertionPhase; import com.oracle.graal.phases.common.LoweringPhase; +import com.oracle.graal.phases.common.RemoveValueProxyPhase; import com.oracle.graal.phases.tiers.MidTierContext; public class EconomyMidTier extends PhaseSuite { @@ -40,6 +41,7 @@ if (ImmutableCode.getValue()) { canonicalizer.disableReadCanonicalization(); } + appendPhase(new RemoveValueProxyPhase()); appendPhase(new LoopSafepointInsertionPhase()); diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java Wed Nov 18 12:01:29 2015 -0800 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java Wed Nov 18 12:01:42 2015 -0800 @@ -37,6 +37,8 @@ import jdk.vm.ci.options.OptionType; import jdk.vm.ci.options.OptionValue; +import com.oracle.graal.loop.DefaultLoopPolicies; +import com.oracle.graal.loop.LoopPolicies; import com.oracle.graal.loop.phases.LoopFullUnrollPhase; import com.oracle.graal.loop.phases.LoopPeelingPhase; import com.oracle.graal.loop.phases.LoopUnswitchingPhase; @@ -87,16 +89,17 @@ appendPhase(new ConvertDeoptimizeToGuardPhase()); } + LoopPolicies loopPolicies = createLoopPolicies(); if (FullUnroll.getValue()) { - appendPhase(new LoopFullUnrollPhase(canonicalizer)); + appendPhase(new LoopFullUnrollPhase(canonicalizer, loopPolicies)); } if (OptLoopTransform.getValue()) { if (LoopPeeling.getValue()) { - appendPhase(new LoopPeelingPhase()); + appendPhase(new LoopPeelingPhase(loopPolicies)); } if (LoopUnswitch.getValue()) { - appendPhase(new LoopUnswitchingPhase()); + appendPhase(new LoopUnswitchingPhase(loopPolicies)); } } @@ -114,4 +117,8 @@ appendPhase(new HighTierReconcileInstrumentationPhase()); } } + + public LoopPolicies createLoopPolicies() { + return new DefaultLoopPolicies(); + } } diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LowTier.java diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugins.java --- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugins.java Wed Nov 18 12:01:29 2015 -0800 +++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugins.java Wed Nov 18 12:01:42 2015 -0800 @@ -254,7 +254,22 @@ * {@code declaringClass} */ public void registerMethodSubstitution(Class substituteDeclaringClass, String name, Class... argumentTypes) { - MethodSubstitutionPlugin plugin = new MethodSubstitutionPlugin(substituteDeclaringClass, name, argumentTypes); + registerMethodSubstitution(substituteDeclaringClass, name, name, argumentTypes); + } + + /** + * Registers a plugin that implements a method based on the bytecode of a substitute method. + * + * @param substituteDeclaringClass the class declaring the substitute method + * @param name the name of both the original method + * @param substituteName the name of the substitute method + * @param argumentTypes the argument types of the method. Element 0 of this array must be + * the {@link Class} value for {@link InvocationPlugin.Receiver} iff the method + * is non-static. Upon returning, element 0 will have been rewritten to + * {@code declaringClass} + */ + public void registerMethodSubstitution(Class substituteDeclaringClass, String name, String substituteName, Class... argumentTypes) { + MethodSubstitutionPlugin plugin = new MethodSubstitutionPlugin(substituteDeclaringClass, substituteName, argumentTypes); plugins.register(plugin, false, allowOverwrite, declaringClass, name, argumentTypes); } } diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotMoveFactory.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotMoveFactory.java Wed Nov 18 12:01:29 2015 -0800 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotMoveFactory.java Wed Nov 18 12:01:42 2015 -0800 @@ -23,6 +23,7 @@ package com.oracle.graal.hotspot.amd64; import jdk.vm.ci.hotspot.HotSpotCompressedNullConstant; +import jdk.vm.ci.hotspot.HotSpotConstant; import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; import jdk.vm.ci.hotspot.HotSpotObjectConstant; import jdk.vm.ci.meta.AllocatableValue; @@ -51,6 +52,14 @@ } @Override + public boolean allowConstantToStackMove(Constant value) { + if (value instanceof HotSpotConstant) { + return ((HotSpotConstant) value).isCompressed(); + } + return true; + } + + @Override public AMD64LIRInstruction createLoad(AllocatableValue dst, Constant src) { if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(src)) { return super.createLoad(dst, JavaConstant.INT_0); diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java Wed Nov 18 12:01:29 2015 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java Wed Nov 18 12:01:42 2015 -0800 @@ -132,6 +132,12 @@ public static final ForeignCallDescriptor DECRYPT_BLOCK = new ForeignCallDescriptor("decrypt_block", void.class, Word.class, Word.class, Pointer.class); /** + * @see AESCryptSubstitutions#decryptBlockStub(ForeignCallDescriptor, Word, Word, Pointer) + */ + public static final ForeignCallDescriptor DECRYPT_BLOCK_WITH_ORIGINAL_KEY = new ForeignCallDescriptor("decrypt_block_with_original_key", void.class, Word.class, Word.class, Pointer.class, + Pointer.class); + + /** * @see CipherBlockChainingSubstitutions#crypt */ public static final ForeignCallDescriptor ENCRYPT = new ForeignCallDescriptor("encrypt", void.class, Word.class, Word.class, Pointer.class, Pointer.class, int.class); @@ -142,6 +148,12 @@ public static final ForeignCallDescriptor DECRYPT = new ForeignCallDescriptor("decrypt", void.class, Word.class, Word.class, Pointer.class, Pointer.class, int.class); /** + * @see CipherBlockChainingSubstitutions#crypt + */ + public static final ForeignCallDescriptor DECRYPT_WITH_ORIGINAL_KEY = new ForeignCallDescriptor("decrypt_with_original_key", void.class, Word.class, Word.class, Pointer.class, Pointer.class, + int.class, Pointer.class); + + /** * @see VMErrorNode */ public static final ForeignCallDescriptor VM_ERROR = new ForeignCallDescriptor("vm_error", void.class, Object.class, Object.class, long.class); diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java Wed Nov 18 12:01:29 2015 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java Wed Nov 18 12:01:42 2015 -0800 @@ -293,17 +293,20 @@ assert config.aescryptDecryptBlockStub != 0L; assert config.cipherBlockChainingEncryptAESCryptStub != 0L; assert config.cipherBlockChainingDecryptAESCryptStub != 0L; + String arch = HotSpotVMConfig.config().getHostArchitectureName(); + String decryptSuffix = arch.equals("sparc") ? "WithOriginalKey" : ""; Class c = MethodSubstitutionPlugin.resolveClass("com.sun.crypto.provider.CipherBlockChaining", true); if (c != null) { Registration r = new Registration(plugins, c); r.registerMethodSubstitution(CipherBlockChainingSubstitutions.class, cbcEncryptName, Receiver.class, byte[].class, int.class, int.class, byte[].class, int.class); - r.registerMethodSubstitution(CipherBlockChainingSubstitutions.class, cbcDecryptName, Receiver.class, byte[].class, int.class, int.class, byte[].class, int.class); + r.registerMethodSubstitution(CipherBlockChainingSubstitutions.class, cbcDecryptName, cbcDecryptName + decryptSuffix, Receiver.class, byte[].class, int.class, int.class, byte[].class, + int.class); } c = MethodSubstitutionPlugin.resolveClass("com.sun.crypto.provider.AESCrypt", true); if (c != null) { Registration r = new Registration(plugins, c); r.registerMethodSubstitution(AESCryptSubstitutions.class, aesEncryptName, Receiver.class, byte[].class, int.class, byte[].class, int.class); - r.registerMethodSubstitution(AESCryptSubstitutions.class, aesDecryptName, Receiver.class, byte[].class, int.class, byte[].class, int.class); + r.registerMethodSubstitution(AESCryptSubstitutions.class, aesDecryptName, aesDecryptName + decryptSuffix, Receiver.class, byte[].class, int.class, byte[].class, int.class); } } } diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java Wed Nov 18 12:01:29 2015 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java Wed Nov 18 12:01:42 2015 -0800 @@ -30,7 +30,9 @@ import static com.oracle.graal.compiler.target.Backend.ARITHMETIC_SIN; import static com.oracle.graal.compiler.target.Backend.ARITHMETIC_TAN; import static com.oracle.graal.hotspot.HotSpotBackend.DECRYPT; +import static com.oracle.graal.hotspot.HotSpotBackend.DECRYPT_WITH_ORIGINAL_KEY; import static com.oracle.graal.hotspot.HotSpotBackend.DECRYPT_BLOCK; +import static com.oracle.graal.hotspot.HotSpotBackend.DECRYPT_BLOCK_WITH_ORIGINAL_KEY; import static com.oracle.graal.hotspot.HotSpotBackend.ENCRYPT; import static com.oracle.graal.hotspot.HotSpotBackend.ENCRYPT_BLOCK; import static com.oracle.graal.hotspot.HotSpotBackend.EXCEPTION_HANDLER; @@ -306,6 +308,8 @@ // These stubs do callee saving registerForeignCall(ENCRYPT_BLOCK, c.aescryptEncryptBlockStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, NamedLocationIdentity.getArrayLocation(JavaKind.Byte)); registerForeignCall(DECRYPT_BLOCK, c.aescryptDecryptBlockStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, NamedLocationIdentity.getArrayLocation(JavaKind.Byte)); + registerForeignCall(DECRYPT_BLOCK_WITH_ORIGINAL_KEY, c.aescryptDecryptBlockStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, + NamedLocationIdentity.getArrayLocation(JavaKind.Byte)); } catch (JVMCIError e) { if (!(e.getCause() instanceof ClassNotFoundException)) { throw e; @@ -317,6 +321,8 @@ NamedLocationIdentity.getArrayLocation(JavaKind.Byte)); registerForeignCall(DECRYPT, c.cipherBlockChainingDecryptAESCryptStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, NamedLocationIdentity.getArrayLocation(JavaKind.Byte)); + registerForeignCall(DECRYPT_WITH_ORIGINAL_KEY, c.cipherBlockChainingDecryptAESCryptStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, + NamedLocationIdentity.getArrayLocation(JavaKind.Byte)); } catch (JVMCIError e) { if (!(e.getCause() instanceof ClassNotFoundException)) { throw e; diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/OnStackReplacementPhase.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/OnStackReplacementPhase.java Wed Nov 18 12:01:29 2015 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/OnStackReplacementPhase.java Wed Nov 18 12:01:42 2015 -0800 @@ -31,8 +31,8 @@ import com.oracle.graal.graph.Node; import com.oracle.graal.graph.iterators.NodeIterable; import com.oracle.graal.loop.LoopEx; -import com.oracle.graal.loop.LoopTransformations; import com.oracle.graal.loop.LoopsData; +import com.oracle.graal.loop.phases.LoopTransformations; import com.oracle.graal.nodeinfo.InputType; import com.oracle.graal.nodeinfo.Verbosity; import com.oracle.graal.nodes.AbstractBeginNode; diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AESCryptSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AESCryptSubstitutions.java Wed Nov 18 12:01:29 2015 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AESCryptSubstitutions.java Wed Nov 18 12:01:42 2015 -0800 @@ -23,6 +23,7 @@ package com.oracle.graal.hotspot.replacements; import static com.oracle.graal.hotspot.HotSpotBackend.DECRYPT_BLOCK; +import static com.oracle.graal.hotspot.HotSpotBackend.DECRYPT_BLOCK_WITH_ORIGINAL_KEY; import static com.oracle.graal.hotspot.HotSpotBackend.ENCRYPT_BLOCK; import static com.oracle.graal.nodes.extended.BranchProbabilityNode.VERY_SLOW_PATH_PROBABILITY; import static com.oracle.graal.nodes.extended.BranchProbabilityNode.probability; @@ -56,6 +57,7 @@ public class AESCryptSubstitutions { static final long kOffset; + static final long lastKeyOffset; static final Class AESCryptClass; static final int AES_BLOCK_SIZE; @@ -66,6 +68,7 @@ ClassLoader cl = Launcher.getLauncher().getClassLoader(); AESCryptClass = Class.forName("com.sun.crypto.provider.AESCrypt", true, cl); kOffset = UnsafeAccess.UNSAFE.objectFieldOffset(AESCryptClass.getDeclaredField("K")); + lastKeyOffset = UnsafeAccess.UNSAFE.objectFieldOffset(AESCryptClass.getDeclaredField("lastKey")); Field aesBlockSizeField = Class.forName("com.sun.crypto.provider.AESConstants", true, cl).getDeclaredField("AES_BLOCK_SIZE"); aesBlockSizeField.setAccessible(true); AES_BLOCK_SIZE = aesBlockSizeField.getInt(null); @@ -75,32 +78,53 @@ } static void encryptBlock(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset) { - crypt(rcvr, in, inOffset, out, outOffset, true); + crypt(rcvr, in, inOffset, out, outOffset, true, false); } static void implEncryptBlock(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset) { - crypt(rcvr, in, inOffset, out, outOffset, true); + crypt(rcvr, in, inOffset, out, outOffset, true, false); } static void decryptBlock(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset) { - crypt(rcvr, in, inOffset, out, outOffset, false); + crypt(rcvr, in, inOffset, out, outOffset, false, false); } static void implDecryptBlock(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset) { - crypt(rcvr, in, inOffset, out, outOffset, false); + crypt(rcvr, in, inOffset, out, outOffset, false, false); } - private static void crypt(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset, boolean encrypt) { + /** + * Variation for platforms (e.g. SPARC) that need do key expansion in stubs due to compatibility + * issues between Java key expansion and hardware crypto instructions. + */ + static void decryptBlockWithOriginalKey(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset) { + crypt(rcvr, in, inOffset, out, outOffset, false, true); + } + + /** + * @see #decryptBlockWithOriginalKey(Object, byte[], int, byte[], int) + */ + static void implDecryptBlockWithOriginalKey(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset) { + crypt(rcvr, in, inOffset, out, outOffset, false, true); + } + + private static void crypt(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset, boolean encrypt, boolean withOriginalKey) { checkArgs(in, inOffset, out, outOffset); Object realReceiver = PiNode.piCastNonNull(rcvr, AESCryptClass); Object kObject = UnsafeLoadNode.load(realReceiver, kOffset, JavaKind.Object, LocationIdentity.any()); - Pointer kAddr = Word.objectToTrackedPointer(kObject).add(getArrayBaseOffset(JavaKind.Byte)); + Pointer kAddr = Word.objectToTrackedPointer(kObject).add(getArrayBaseOffset(JavaKind.Int)); Word inAddr = Word.unsigned(ComputeObjectAddressNode.get(in, getArrayBaseOffset(JavaKind.Byte) + inOffset)); Word outAddr = Word.unsigned(ComputeObjectAddressNode.get(out, getArrayBaseOffset(JavaKind.Byte) + outOffset)); if (encrypt) { encryptBlockStub(ENCRYPT_BLOCK, inAddr, outAddr, kAddr); } else { - decryptBlockStub(DECRYPT_BLOCK, inAddr, outAddr, kAddr); + if (withOriginalKey) { + Object lastKeyObject = UnsafeLoadNode.load(realReceiver, lastKeyOffset, JavaKind.Object, LocationIdentity.any()); + Pointer lastKeyAddr = Word.objectToTrackedPointer(lastKeyObject).add(getArrayBaseOffset(JavaKind.Byte)); + decryptBlockWithOriginalKeyStub(DECRYPT_BLOCK_WITH_ORIGINAL_KEY, inAddr, outAddr, kAddr, lastKeyAddr); + } else { + decryptBlockStub(DECRYPT_BLOCK, inAddr, outAddr, kAddr); + } } } @@ -118,4 +142,7 @@ @NodeIntrinsic(ForeignCallNode.class) public static native void decryptBlockStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word in, Word out, Pointer key); + + @NodeIntrinsic(ForeignCallNode.class) + public static native void decryptBlockWithOriginalKeyStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word in, Word out, Pointer key, Pointer originalKey); } diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CipherBlockChainingSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CipherBlockChainingSubstitutions.java Wed Nov 18 12:01:29 2015 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CipherBlockChainingSubstitutions.java Wed Nov 18 12:01:42 2015 -0800 @@ -23,6 +23,7 @@ package com.oracle.graal.hotspot.replacements; import static com.oracle.graal.hotspot.HotSpotBackend.DECRYPT; +import static com.oracle.graal.hotspot.HotSpotBackend.DECRYPT_WITH_ORIGINAL_KEY; import static com.oracle.graal.hotspot.HotSpotBackend.ENCRYPT; import static com.oracle.graal.hotspot.replacements.UnsafeAccess.UNSAFE; import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayBaseOffset; @@ -79,7 +80,7 @@ Object embeddedCipher = UnsafeLoadNode.load(realReceiver, embeddedCipherOffset, JavaKind.Object, LocationIdentity.any()); if (getAESCryptClass().isInstance(embeddedCipher)) { Object aesCipher = PiNode.piCastNonNull(embeddedCipher, AESCryptSubstitutions.AESCryptClass); - crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, true); + crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, true, false); return inLength; } else { return encrypt(realReceiver, in, inOffset, inLength, out, outOffset); @@ -91,7 +92,7 @@ Object embeddedCipher = UnsafeLoadNode.load(realReceiver, embeddedCipherOffset, JavaKind.Object, LocationIdentity.any()); if (getAESCryptClass().isInstance(embeddedCipher)) { Object aesCipher = PiNode.piCastNonNull(embeddedCipher, AESCryptSubstitutions.AESCryptClass); - crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, true); + crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, true, false); return inLength; } else { return implEncrypt(realReceiver, in, inOffset, inLength, out, outOffset); @@ -103,7 +104,7 @@ Object embeddedCipher = UnsafeLoadNode.load(realReceiver, embeddedCipherOffset, JavaKind.Object, LocationIdentity.any()); if (in != out && getAESCryptClass().isInstance(embeddedCipher)) { Object aesCipher = PiNode.piCastNonNull(embeddedCipher, AESCryptSubstitutions.AESCryptClass); - crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, false); + crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, false, false); return inLength; } else { return decrypt(realReceiver, in, inOffset, inLength, out, outOffset); @@ -115,26 +116,64 @@ Object embeddedCipher = UnsafeLoadNode.load(realReceiver, embeddedCipherOffset, JavaKind.Object, LocationIdentity.any()); if (in != out && getAESCryptClass().isInstance(embeddedCipher)) { Object aesCipher = PiNode.piCastNonNull(embeddedCipher, AESCryptSubstitutions.AESCryptClass); - crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, false); + crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, false, false); return inLength; } else { return implDecrypt(realReceiver, in, inOffset, inLength, out, outOffset); } } - private static void crypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset, Object embeddedCipher, boolean encrypt) { + /** + * Variation for platforms (e.g. SPARC) that need do key expansion in stubs due to compatibility + * issues between Java key expansion and hardware crypto instructions. + */ + static int decryptWithOriginalKey(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset) { + Object realReceiver = PiNode.piCastNonNull(rcvr, cipherBlockChainingClass); + Object embeddedCipher = UnsafeLoadNode.load(realReceiver, embeddedCipherOffset, JavaKind.Object, LocationIdentity.any()); + if (in != out && getAESCryptClass().isInstance(embeddedCipher)) { + Object aesCipher = PiNode.piCastNonNull(embeddedCipher, AESCryptSubstitutions.AESCryptClass); + crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, false, true); + return inLength; + } else { + return decryptWithOriginalKey(realReceiver, in, inOffset, inLength, out, outOffset); + } + } + + /** + * @see #decryptWithOriginalKey(Object, byte[], int, int, byte[], int) + */ + static int implDecryptWithOriginalKey(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset) { + Object realReceiver = PiNode.piCastNonNull(rcvr, cipherBlockChainingClass); + Object embeddedCipher = UnsafeLoadNode.load(realReceiver, embeddedCipherOffset, JavaKind.Object, LocationIdentity.any()); + if (in != out && getAESCryptClass().isInstance(embeddedCipher)) { + Object aesCipher = PiNode.piCastNonNull(embeddedCipher, AESCryptSubstitutions.AESCryptClass); + crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, false, true); + return inLength; + } else { + return implDecryptWithOriginalKey(realReceiver, in, inOffset, inLength, out, outOffset); + } + } + + private static void crypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset, Object embeddedCipher, boolean encrypt, boolean withOriginalKey) { AESCryptSubstitutions.checkArgs(in, inOffset, out, outOffset); Object realReceiver = PiNode.piCastNonNull(rcvr, cipherBlockChainingClass); - Object kObject = UnsafeLoadNode.load(embeddedCipher, AESCryptSubstitutions.kOffset, JavaKind.Object, LocationIdentity.any()); + Object aesCipher = PiNode.piCastNonNull(embeddedCipher, AESCryptSubstitutions.AESCryptClass); + Object kObject = UnsafeLoadNode.load(aesCipher, AESCryptSubstitutions.kOffset, JavaKind.Object, LocationIdentity.any()); Object rObject = UnsafeLoadNode.load(realReceiver, rOffset, JavaKind.Object, LocationIdentity.any()); - Pointer kAddr = Word.objectToTrackedPointer(kObject).add(getArrayBaseOffset(JavaKind.Byte)); + Pointer kAddr = Word.objectToTrackedPointer(kObject).add(getArrayBaseOffset(JavaKind.Int)); Pointer rAddr = Word.objectToTrackedPointer(rObject).add(getArrayBaseOffset(JavaKind.Byte)); Word inAddr = Word.unsigned(ComputeObjectAddressNode.get(in, getArrayBaseOffset(JavaKind.Byte) + inOffset)); Word outAddr = Word.unsigned(ComputeObjectAddressNode.get(out, getArrayBaseOffset(JavaKind.Byte) + outOffset)); if (encrypt) { encryptAESCryptStub(ENCRYPT, inAddr, outAddr, kAddr, rAddr, inLength); } else { - decryptAESCryptStub(DECRYPT, inAddr, outAddr, kAddr, rAddr, inLength); + if (withOriginalKey) { + Object lastKeyObject = UnsafeLoadNode.load(aesCipher, AESCryptSubstitutions.lastKeyOffset, JavaKind.Object, LocationIdentity.any()); + Pointer lastKeyAddr = Word.objectToTrackedPointer(lastKeyObject).add(getArrayBaseOffset(JavaKind.Byte)); + decryptAESCryptWithOriginalKeyStub(DECRYPT_WITH_ORIGINAL_KEY, inAddr, outAddr, kAddr, rAddr, inLength, lastKeyAddr); + } else { + decryptAESCryptStub(DECRYPT, inAddr, outAddr, kAddr, rAddr, inLength); + } } } @@ -143,4 +182,7 @@ @NodeIntrinsic(ForeignCallNode.class) public static native void decryptAESCryptStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word in, Word out, Pointer key, Pointer r, int inLength); + + @NodeIntrinsic(ForeignCallNode.class) + public static native void decryptAESCryptWithOriginalKeyStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word in, Word out, Pointer key, Pointer r, int inLength, Pointer originalKey); } diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstruction.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstruction.java Wed Nov 18 12:01:29 2015 -0800 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstruction.java Wed Nov 18 12:01:42 2015 -0800 @@ -26,6 +26,7 @@ import static com.oracle.graal.lir.LIRInstruction.OperandFlag.CONST; import static com.oracle.graal.lir.LIRInstruction.OperandFlag.HINT; import static com.oracle.graal.lir.LIRInstruction.OperandFlag.ILLEGAL; +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.OUTGOING; import static com.oracle.graal.lir.LIRInstruction.OperandFlag.REG; import static com.oracle.graal.lir.LIRInstruction.OperandFlag.STACK; import static com.oracle.graal.lir.LIRInstruction.OperandFlag.UNINITIALIZED; @@ -160,6 +161,9 @@ * is only used to avoid false positives in verification code. */ UNINITIALIZED, + + /** Outgoing block value. */ + OUTGOING, } /** @@ -170,7 +174,7 @@ static { ALLOWED_FLAGS = new EnumMap<>(OperandMode.class); ALLOWED_FLAGS.put(OperandMode.USE, EnumSet.of(REG, STACK, COMPOSITE, CONST, ILLEGAL, HINT, UNINITIALIZED)); - ALLOWED_FLAGS.put(ALIVE, EnumSet.of(REG, STACK, COMPOSITE, CONST, ILLEGAL, HINT, UNINITIALIZED)); + ALLOWED_FLAGS.put(ALIVE, EnumSet.of(REG, STACK, COMPOSITE, CONST, ILLEGAL, HINT, UNINITIALIZED, OUTGOING)); ALLOWED_FLAGS.put(TEMP, EnumSet.of(REG, STACK, COMPOSITE, ILLEGAL, HINT)); ALLOWED_FLAGS.put(DEF, EnumSet.of(REG, STACK, COMPOSITE, ILLEGAL, HINT)); } diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StandardOp.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StandardOp.java Wed Nov 18 12:01:29 2015 -0800 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StandardOp.java Wed Nov 18 12:01:42 2015 -0800 @@ -24,6 +24,7 @@ import static com.oracle.graal.lir.LIRInstruction.OperandFlag.CONST; import static com.oracle.graal.lir.LIRInstruction.OperandFlag.HINT; +import static com.oracle.graal.lir.LIRInstruction.OperandFlag.OUTGOING; import static com.oracle.graal.lir.LIRInstruction.OperandFlag.REG; import static com.oracle.graal.lir.LIRInstruction.OperandFlag.STACK; import static com.oracle.graal.lir.LIRValueUtil.isVariable; @@ -172,9 +173,9 @@ public abstract static class AbstractBlockEndOp extends LIRInstruction implements BlockEndOp { public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AbstractBlockEndOp.class); - private static final EnumSet flags = EnumSet.of(REG, STACK, CONST); + private static final EnumSet 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 c) { diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScan.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScan.java Wed Nov 18 12:01:29 2015 -0800 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScan.java Wed Nov 18 12:01:42 2015 -0800 @@ -722,7 +722,7 @@ } } } - Debug.dump(new LinearScanIntervalDumper(Arrays.copyOf(intervals, intervalsSize)), label); + Debug.dump(1, new LinearScanIntervalDumper(Arrays.copyOf(intervals, intervalsSize)), label); } public void printLir(String label, @SuppressWarnings("unused") boolean hirValid) { diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceLinearScanLifetimeAnalysisPhase.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceLinearScanLifetimeAnalysisPhase.java Wed Nov 18 12:01:29 2015 -0800 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceLinearScanLifetimeAnalysisPhase.java Wed Nov 18 12:01:42 2015 -0800 @@ -23,13 +23,15 @@ package com.oracle.graal.lir.alloc.trace; import static com.oracle.graal.lir.LIRValueUtil.asVariable; +import static com.oracle.graal.lir.LIRValueUtil.isStackSlotValue; import static com.oracle.graal.lir.LIRValueUtil.isVariable; import static com.oracle.graal.lir.alloc.trace.TraceLinearScan.isVariableOrRegister; import static com.oracle.graal.lir.alloc.trace.TraceRegisterAllocationPhase.Options.TraceRAshareSpillInformation; import static com.oracle.graal.lir.alloc.trace.TraceRegisterAllocationPhase.Options.TraceRAuseInterTraceHints; +import static com.oracle.graal.lir.alloc.trace.TraceUtil.asShadowedRegisterValue; +import static com.oracle.graal.lir.alloc.trace.TraceUtil.isShadowedRegisterValue; import static jdk.vm.ci.code.ValueUtil.asRegisterValue; import static jdk.vm.ci.code.ValueUtil.asStackSlot; -import static jdk.vm.ci.code.ValueUtil.isIllegal; import static jdk.vm.ci.code.ValueUtil.isRegister; import static jdk.vm.ci.code.ValueUtil.isStackSlot; @@ -41,6 +43,7 @@ import jdk.vm.ci.code.Register; import jdk.vm.ci.code.RegisterValue; import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.common.JVMCIError; import jdk.vm.ci.meta.AllocatableValue; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.LIRKind; @@ -57,6 +60,7 @@ import com.oracle.graal.lir.LIRInstruction; import com.oracle.graal.lir.LIRInstruction.OperandFlag; import com.oracle.graal.lir.LIRInstruction.OperandMode; +import com.oracle.graal.lir.LIRValueUtil; import com.oracle.graal.lir.StandardOp.BlockEndOp; import com.oracle.graal.lir.StandardOp.LabelOp; import com.oracle.graal.lir.StandardOp.LoadConstantOp; @@ -437,6 +441,9 @@ * register. */ private static RegisterPriority registerPriorityOfInputOperand(EnumSet 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 diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceLinearScanWalker.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceLinearScanWalker.java Wed Nov 18 12:01:29 2015 -0800 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/trace/TraceLinearScanWalker.java Wed Nov 18 12:01:42 2015 -0800 @@ -640,9 +640,13 @@ // The new created part is added to the unhandled list and will get a register // when it is activated int minSplitPos = currentPos + 1; - int maxSplitPos = Math.min(interval.nextUsage(RegisterPriority.MustHaveRegister, minSplitPos), interval.to()); + int maxSplitPos = interval.nextUsage(RegisterPriority.MustHaveRegister, minSplitPos); - splitBeforeUsage(interval, minSplitPos, maxSplitPos); + if (maxSplitPos <= interval.to()) { + splitBeforeUsage(interval, minSplitPos, maxSplitPos); + } else { + Debug.log("No more usage, no need to split: %s", interval); + } assert interval.nextUsage(RegisterPriority.MustHaveRegister, currentPos) == Integer.MAX_VALUE : "the remaining part is spilled to stack and therefore has no register"; splitForSpilling(interval); diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGeneratorTool.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGeneratorTool.java Wed Nov 18 12:01:29 2015 -0800 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGeneratorTool.java Wed Nov 18 12:01:42 2015 -0800 @@ -67,6 +67,12 @@ */ boolean canInlineConstant(JavaConstant c); + /** + * @param constant The constant that might be moved to a stack slot. + * @return {@code true} if constant to stack moves are supported for this constant. + */ + boolean allowConstantToStackMove(Constant constant); + LIRInstruction createMove(AllocatableValue result, Value input); LIRInstruction createStackMove(AllocatableValue result, AllocatableValue input); diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/VerifyingMoveFactory.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/VerifyingMoveFactory.java Wed Nov 18 12:01:29 2015 -0800 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/VerifyingMoveFactory.java Wed Nov 18 12:01:42 2015 -0800 @@ -54,6 +54,10 @@ return inner.canInlineConstant(c); } + public boolean allowConstantToStackMove(Constant constant) { + return inner.allowConstantToStackMove(constant); + } + public LIRInstruction createMove(AllocatableValue result, Value input) { LIRInstruction inst = inner.createMove(result, input); assert checkResult(inst, result, input); diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.loop.phases/src/com/oracle/graal/loop/phases/ContextlessLoopPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.loop.phases/src/com/oracle/graal/loop/phases/ContextlessLoopPhase.java Wed Nov 18 12:01:42 2015 -0800 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.loop.phases; + +import com.oracle.graal.loop.LoopPolicies; +import com.oracle.graal.nodes.StructuredGraph; +import com.oracle.graal.phases.tiers.PhaseContext; + +public abstract class ContextlessLoopPhase

extends LoopPhase

{ + + 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); + } +} diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.loop.phases/src/com/oracle/graal/loop/phases/LoopFullUnrollPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.loop.phases/src/com/oracle/graal/loop/phases/LoopFullUnrollPhase.java Wed Nov 18 12:01:42 2015 -0800 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.loop.phases; + +import com.oracle.graal.debug.Debug; +import com.oracle.graal.debug.DebugMetric; +import com.oracle.graal.loop.LoopEx; +import com.oracle.graal.loop.LoopPolicies; +import com.oracle.graal.loop.LoopsData; +import com.oracle.graal.nodes.StructuredGraph; +import com.oracle.graal.phases.common.CanonicalizerPhase; +import com.oracle.graal.phases.tiers.PhaseContext; + +public class LoopFullUnrollPhase extends LoopPhase { + + 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); + } + } +} diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.loop.phases/src/com/oracle/graal/loop/phases/LoopPeelingPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.loop.phases/src/com/oracle/graal/loop/phases/LoopPeelingPhase.java Wed Nov 18 12:01:42 2015 -0800 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.loop.phases; + +import com.oracle.graal.debug.Debug; +import com.oracle.graal.loop.LoopEx; +import com.oracle.graal.loop.LoopPolicies; +import com.oracle.graal.loop.LoopsData; +import com.oracle.graal.nodes.StructuredGraph; + +public class LoopPeelingPhase extends ContextlessLoopPhase { + + 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(); + } + } +} diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.loop.phases/src/com/oracle/graal/loop/phases/LoopPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.loop.phases/src/com/oracle/graal/loop/phases/LoopPhase.java Wed Nov 18 12:01:42 2015 -0800 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.loop.phases; + +import com.oracle.graal.loop.LoopPolicies; +import com.oracle.graal.phases.BasePhase; +import com.oracle.graal.phases.tiers.PhaseContext; + +public abstract class LoopPhase

extends BasePhase { + private P policies; + + public LoopPhase(P policies) { + this.policies = policies; + } + + protected P getPolicies() { + return policies; + } +} diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.loop.phases/src/com/oracle/graal/loop/phases/LoopSafepointEliminationPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.loop.phases/src/com/oracle/graal/loop/phases/LoopSafepointEliminationPhase.java Wed Nov 18 12:01:42 2015 -0800 @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.loop.phases; + +import com.oracle.graal.loop.LoopEx; +import com.oracle.graal.loop.LoopsData; +import com.oracle.graal.nodes.FixedNode; +import com.oracle.graal.nodes.Invoke; +import com.oracle.graal.nodes.LoopEndNode; +import com.oracle.graal.nodes.StructuredGraph; +import com.oracle.graal.nodes.cfg.Block; +import com.oracle.graal.nodes.extended.ForeignCallNode; +import com.oracle.graal.phases.BasePhase; +import com.oracle.graal.phases.tiers.MidTierContext; + +public class LoopSafepointEliminationPhase extends BasePhase { + + @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(); + } +} diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.loop.phases/src/com/oracle/graal/loop/phases/LoopTransformations.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.loop.phases/src/com/oracle/graal/loop/phases/LoopTransformations.java Wed Nov 18 12:01:42 2015 -0800 @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.loop.phases; + +import static com.oracle.graal.compiler.common.GraalOptions.MaximumDesiredSize; + +import java.util.ArrayList; +import java.util.List; + +import com.oracle.graal.graph.Graph.Mark; +import com.oracle.graal.graph.NodePosIterator; +import com.oracle.graal.graph.Position; +import com.oracle.graal.loop.LoopEx; +import com.oracle.graal.loop.LoopFragmentWhole; +import com.oracle.graal.nodeinfo.InputType; +import com.oracle.graal.nodes.AbstractBeginNode; +import com.oracle.graal.nodes.BeginNode; +import com.oracle.graal.nodes.ControlSplitNode; +import com.oracle.graal.nodes.IfNode; +import com.oracle.graal.nodes.LoopBeginNode; +import com.oracle.graal.nodes.StructuredGraph; +import com.oracle.graal.nodes.ValueNode; +import com.oracle.graal.nodes.extended.SwitchNode; +import com.oracle.graal.phases.common.CanonicalizerPhase; +import com.oracle.graal.phases.tiers.PhaseContext; + +import jdk.vm.ci.code.BailoutException; + +public abstract class LoopTransformations { + + private LoopTransformations() { + // does not need to be instantiated + } + + public static void peel(LoopEx loop) { + loop.inside().duplicate().insertBefore(loop); + loop.loopBegin().setLoopFrequency(Math.max(0.0, loop.loopBegin().loopFrequency() - 1)); + } + + public static void fullUnroll(LoopEx loop, PhaseContext context, CanonicalizerPhase canonicalizer) { + // assert loop.isCounted(); //TODO (gd) strenghten : counted with known trip count + LoopBeginNode loopBegin = loop.loopBegin(); + StructuredGraph graph = loopBegin.graph(); + while (!loopBegin.isDeleted()) { + Mark mark = graph.getMark(); + peel(loop); + canonicalizer.applyIncremental(graph, context, mark); + loopBegin.removeDeadPhis(); + loop.invalidateFragments(); + if (graph.getNodeCount() > MaximumDesiredSize.getValue() * 3) { + throw new BailoutException("FullUnroll : Graph seems to grow out of proportion"); + } + } + } + + public static void unswitch(LoopEx loop, List 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 findUnswitchable(LoopEx loop) { + List 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; + } +} diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.loop.phases/src/com/oracle/graal/loop/phases/LoopUnswitchingPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.loop.phases/src/com/oracle/graal/loop/phases/LoopUnswitchingPhase.java Wed Nov 18 12:01:42 2015 -0800 @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.loop.phases; + +import java.util.List; + +import com.oracle.graal.debug.Debug; +import com.oracle.graal.debug.DebugMetric; +import com.oracle.graal.graph.NodePosIterator; +import com.oracle.graal.loop.LoopEx; +import com.oracle.graal.loop.LoopPolicies; +import com.oracle.graal.loop.LoopsData; +import com.oracle.graal.nodes.AbstractBeginNode; +import com.oracle.graal.nodes.ControlSplitNode; +import com.oracle.graal.nodes.StructuredGraph; + +public class LoopUnswitchingPhase extends ContextlessLoopPhase { + 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 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 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); + } +} diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.loop.phases/src/com/oracle/graal/loop/phases/ReassociateInvariantPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.loop.phases/src/com/oracle/graal/loop/phases/ReassociateInvariantPhase.java Wed Nov 18 12:01:42 2015 -0800 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.loop.phases; + +import com.oracle.graal.debug.Debug; +import com.oracle.graal.debug.Debug.Scope; +import com.oracle.graal.loop.LoopEx; +import com.oracle.graal.loop.LoopsData; +import com.oracle.graal.nodes.StructuredGraph; +import com.oracle.graal.phases.Phase; + +public class ReassociateInvariantPhase extends Phase { + + @SuppressWarnings("try") + @Override + protected void run(StructuredGraph graph) { + if (graph.hasLoops()) { + final LoopsData dataReassociate = new LoopsData(graph); + try (Scope s = Debug.scope("ReassociateInvariants")) { + for (LoopEx loop : dataReassociate.loops()) { + loop.reassociateInvariants(); + } + } catch (Throwable e) { + throw Debug.handle(e); + } + dataReassociate.deleteUnusedNodes(); + } + } +} diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DefaultLoopPolicies.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DefaultLoopPolicies.java Wed Nov 18 12:01:42 2015 -0800 @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.loop; + +import static com.oracle.graal.compiler.common.GraalOptions.LoopMaxUnswitch; +import static com.oracle.graal.compiler.common.GraalOptions.MaximumDesiredSize; +import static com.oracle.graal.compiler.common.GraalOptions.MinimumPeelProbability; + +import java.util.List; + +import jdk.vm.ci.options.Option; +import jdk.vm.ci.options.OptionType; +import jdk.vm.ci.options.OptionValue; + +import com.oracle.graal.debug.Debug; +import com.oracle.graal.debug.DebugMetric; +import com.oracle.graal.graph.Node; +import com.oracle.graal.nodes.AbstractBeginNode; +import com.oracle.graal.nodes.ControlSplitNode; +import com.oracle.graal.nodes.LoopBeginNode; +import com.oracle.graal.nodes.MergeNode; +import com.oracle.graal.nodes.VirtualState; +import com.oracle.graal.nodes.VirtualState.VirtualClosure; +import com.oracle.graal.nodes.cfg.Block; +import com.oracle.graal.nodes.cfg.ControlFlowGraph; +import com.oracle.graal.nodes.debug.ControlFlowAnchorNode; + +public class DefaultLoopPolicies implements LoopPolicies { + @Option(help = "", type = OptionType.Expert) public static final OptionValue LoopUnswitchMaxIncrease = new OptionValue<>(500); + @Option(help = "", type = OptionType.Expert) public static final OptionValue LoopUnswitchTrivial = new OptionValue<>(10); + @Option(help = "", type = OptionType.Expert) public static final OptionValue LoopUnswitchFrequencyBoost = new OptionValue<>(10.0); + + @Option(help = "", type = OptionType.Expert) public static final OptionValue FullUnrollMaxNodes = new OptionValue<>(300); + @Option(help = "", type = OptionType.Expert) public static final OptionValue FullUnrollMaxIterations = new OptionValue<>(600); + @Option(help = "", type = OptionType.Expert) public static final OptionValue 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 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; + } + +} diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopPolicies.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopPolicies.java Wed Nov 18 12:01:29 2015 -0800 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopPolicies.java Wed Nov 18 12:01:42 2015 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,136 +22,17 @@ */ package com.oracle.graal.loop; -import static com.oracle.graal.compiler.common.GraalOptions.LoopMaxUnswitch; -import static com.oracle.graal.compiler.common.GraalOptions.MaximumDesiredSize; -import static com.oracle.graal.compiler.common.GraalOptions.MinimumPeelProbability; - import java.util.List; -import jdk.vm.ci.options.Option; -import jdk.vm.ci.options.OptionType; -import jdk.vm.ci.options.OptionValue; - -import com.oracle.graal.debug.Debug; -import com.oracle.graal.debug.DebugMetric; -import com.oracle.graal.graph.Node; -import com.oracle.graal.nodes.AbstractBeginNode; import com.oracle.graal.nodes.ControlSplitNode; -import com.oracle.graal.nodes.LoopBeginNode; -import com.oracle.graal.nodes.MergeNode; -import com.oracle.graal.nodes.VirtualState; -import com.oracle.graal.nodes.VirtualState.VirtualClosure; -import com.oracle.graal.nodes.cfg.Block; import com.oracle.graal.nodes.cfg.ControlFlowGraph; -import com.oracle.graal.nodes.debug.ControlFlowAnchorNode; - -public abstract class LoopPolicies { - @Option(help = "", type = OptionType.Expert) public static final OptionValue LoopUnswitchMaxIncrease = new OptionValue<>(500); - @Option(help = "", type = OptionType.Expert) public static final OptionValue LoopUnswitchTrivial = new OptionValue<>(10); - @Option(help = "", type = OptionType.Expert) public static final OptionValue LoopUnswitchFrequencyBoost = new OptionValue<>(10.0); - @Option(help = "", type = OptionType.Expert) public static final OptionValue FullUnrollMaxNodes = new OptionValue<>(300); - @Option(help = "", type = OptionType.Expert) public static final OptionValue FullUnrollMaxIterations = new OptionValue<>(600); - @Option(help = "", type = OptionType.Expert) public static final OptionValue 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 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 controlSplits); } diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopTransformations.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopTransformations.java Wed Nov 18 12:01:29 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,158 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.loop; - -import static com.oracle.graal.compiler.common.GraalOptions.MaximumDesiredSize; - -import java.util.ArrayList; -import java.util.List; - -import jdk.vm.ci.code.BailoutException; - -import com.oracle.graal.graph.Graph.Mark; -import com.oracle.graal.graph.NodePosIterator; -import com.oracle.graal.graph.Position; -import com.oracle.graal.nodeinfo.InputType; -import com.oracle.graal.nodes.AbstractBeginNode; -import com.oracle.graal.nodes.BeginNode; -import com.oracle.graal.nodes.ControlSplitNode; -import com.oracle.graal.nodes.IfNode; -import com.oracle.graal.nodes.LoopBeginNode; -import com.oracle.graal.nodes.StructuredGraph; -import com.oracle.graal.nodes.ValueNode; -import com.oracle.graal.nodes.extended.SwitchNode; -import com.oracle.graal.phases.common.CanonicalizerPhase; -import com.oracle.graal.phases.tiers.PhaseContext; - -public abstract class LoopTransformations { - - private LoopTransformations() { - // does not need to be instantiated - } - - public static void peel(LoopEx loop) { - loop.inside().duplicate().insertBefore(loop); - loop.loopBegin().setLoopFrequency(Math.max(0.0, loop.loopBegin().loopFrequency() - 1)); - } - - public static void fullUnroll(LoopEx loop, PhaseContext context, CanonicalizerPhase canonicalizer) { - // assert loop.isCounted(); //TODO (gd) strenghten : counted with known trip count - int iterations = 0; - LoopBeginNode loopBegin = loop.loopBegin(); - StructuredGraph graph = loopBegin.graph(); - while (!loopBegin.isDeleted()) { - Mark mark = graph.getMark(); - peel(loop); - canonicalizer.applyIncremental(graph, context, mark); - loopBegin.removeDeadPhis(); - loop.invalidateFragments(); - if (iterations++ > LoopPolicies.FullUnrollMaxIterations.getValue() || graph.getNodeCount() > MaximumDesiredSize.getValue() * 3) { - throw new BailoutException("FullUnroll : Graph seems to grow out of proportion"); - } - } - } - - public static void unswitch(LoopEx loop, List 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 findUnswitchable(LoopEx loop) { - List 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; - } -} diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopFullUnrollPhase.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopFullUnrollPhase.java Wed Nov 18 12:01:29 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.loop.phases; - -import com.oracle.graal.debug.Debug; -import com.oracle.graal.debug.DebugMetric; -import com.oracle.graal.loop.LoopEx; -import com.oracle.graal.loop.LoopPolicies; -import com.oracle.graal.loop.LoopTransformations; -import com.oracle.graal.loop.LoopsData; -import com.oracle.graal.nodes.StructuredGraph; -import com.oracle.graal.phases.BasePhase; -import com.oracle.graal.phases.common.CanonicalizerPhase; -import com.oracle.graal.phases.tiers.PhaseContext; - -public class LoopFullUnrollPhase extends BasePhase { - - 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); - } - } -} diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopPeelingPhase.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopPeelingPhase.java Wed Nov 18 12:01:29 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.loop.phases; - -import com.oracle.graal.debug.Debug; -import com.oracle.graal.loop.LoopEx; -import com.oracle.graal.loop.LoopPolicies; -import com.oracle.graal.loop.LoopTransformations; -import com.oracle.graal.loop.LoopsData; -import com.oracle.graal.nodes.StructuredGraph; -import com.oracle.graal.phases.Phase; - -public class LoopPeelingPhase extends Phase { - - @Override - protected void run(StructuredGraph graph) { - if (graph.hasLoops()) { - LoopsData data = new LoopsData(graph); - for (LoopEx loop : data.outerFirst()) { - if (LoopPolicies.shouldPeel(loop, data.getCFG())) { - Debug.log("Peeling %s", loop); - LoopTransformations.peel(loop); - Debug.dump(graph, "Peeling %s", loop); - } - } - data.deleteUnusedNodes(); - } - } -} diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopSafepointEliminationPhase.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopSafepointEliminationPhase.java Wed Nov 18 12:01:29 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.loop.phases; - -import com.oracle.graal.loop.LoopEx; -import com.oracle.graal.loop.LoopsData; -import com.oracle.graal.nodes.FixedNode; -import com.oracle.graal.nodes.Invoke; -import com.oracle.graal.nodes.LoopEndNode; -import com.oracle.graal.nodes.StructuredGraph; -import com.oracle.graal.nodes.cfg.Block; -import com.oracle.graal.nodes.extended.ForeignCallNode; -import com.oracle.graal.phases.BasePhase; -import com.oracle.graal.phases.tiers.MidTierContext; - -public class LoopSafepointEliminationPhase extends BasePhase { - - @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(); - } -} diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopUnswitchingPhase.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopUnswitchingPhase.java Wed Nov 18 12:01:29 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.loop.phases; - -import java.util.List; - -import com.oracle.graal.debug.Debug; -import com.oracle.graal.debug.DebugMetric; -import com.oracle.graal.graph.NodePosIterator; -import com.oracle.graal.loop.LoopEx; -import com.oracle.graal.loop.LoopPolicies; -import com.oracle.graal.loop.LoopTransformations; -import com.oracle.graal.loop.LoopsData; -import com.oracle.graal.nodes.AbstractBeginNode; -import com.oracle.graal.nodes.ControlSplitNode; -import com.oracle.graal.nodes.StructuredGraph; -import com.oracle.graal.phases.Phase; - -public class LoopUnswitchingPhase extends Phase { - - private static final DebugMetric UNSWITCHED = Debug.metric("Unswitched"); - private static final DebugMetric UNSWITCH_CANDIDATES = Debug.metric("UnswitchCandidates"); - private static final DebugMetric UNSWITCH_EARLY_REJECTS = Debug.metric("UnswitchEarlyRejects"); - - @Override - protected void run(StructuredGraph graph) { - if (graph.hasLoops()) { - boolean unswitched; - do { - unswitched = false; - final LoopsData dataUnswitch = new LoopsData(graph); - for (LoopEx loop : dataUnswitch.outerFirst()) { - if (LoopPolicies.shouldTryUnswitch(loop)) { - List 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 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); - } -} diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/ReassociateInvariantPhase.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/ReassociateInvariantPhase.java Wed Nov 18 12:01:29 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.loop.phases; - -import com.oracle.graal.debug.Debug; -import com.oracle.graal.debug.Debug.Scope; -import com.oracle.graal.loop.LoopEx; -import com.oracle.graal.loop.LoopsData; -import com.oracle.graal.nodes.StructuredGraph; -import com.oracle.graal.phases.Phase; - -public class ReassociateInvariantPhase extends Phase { - - @SuppressWarnings("try") - @Override - protected void run(StructuredGraph graph) { - if (graph.hasLoops()) { - final LoopsData dataReassociate = new LoopsData(graph); - try (Scope s = Debug.scope("ReassociateInvariants")) { - for (LoopEx loop : dataReassociate.loops()) { - loop.reassociateInvariants(); - } - } catch (Throwable e) { - throw Debug.handle(e); - } - dataReassociate.deleteUnusedNodes(); - } - } -} diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/IfNodeCanonicalizationTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/IfNodeCanonicalizationTest.java Wed Nov 18 12:01:42 2015 -0800 @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.nodes.test; + +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; + +import com.oracle.graal.api.directives.GraalDirectives; +import com.oracle.graal.compiler.test.GraalCompilerTest; +import com.oracle.graal.graph.Node; +import com.oracle.graal.nodes.AbstractMergeNode; +import com.oracle.graal.nodes.IfNode; +import com.oracle.graal.nodes.LogicNode; +import com.oracle.graal.nodes.StructuredGraph; +import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions; +import com.oracle.graal.nodes.calc.SubNode; +import com.oracle.graal.phases.common.CanonicalizerPhase; +import com.oracle.graal.phases.common.ConvertDeoptimizeToGuardPhase; +import com.oracle.graal.phases.common.IterativeConditionalEliminationPhase; +import com.oracle.graal.phases.tiers.PhaseContext; + +/** + * A few tests of expected simplifications by + * {@link IfNode#simplify(com.oracle.graal.graph.spi.SimplifierTool)}. + */ +public class IfNodeCanonicalizationTest extends GraalCompilerTest { + + static int value; + + static final byte[] testValues = {-128, -1, 0, 1, 127}; + + @Test + public void test1() { + /* + * exercise conversion of x - y < 0 into x < y, both by checking expected graph shape and + * that the transformed code produces the right answer. + */ + test("testSnippet1", SubNode.class, 0); + byte[] values = new byte[4]; + for (byte a : testValues) { + values[0] = a; + for (byte b : testValues) { + values[1] = b; + for (byte c : testValues) { + values[2] = c; + for (byte d : testValues) { + values[3] = d; + value = 2; + super.test("testSnippet1", values, true); + super.test("testSnippet1", values, false); + } + } + } + } + } + + public int testSnippet1(byte[] values, boolean test) { + int v = values[0] - values[1]; + if (test) { + v = values[2] - values[3]; + } + if (v < 0) { + value = 1; + } + return value; + } + + @Test + public void test2() { + test("testSnippet2", 1); + } + + public boolean testSnippet2(int a, int[] limit) { + int l = limit.length; + if (!(a >= 0 && a < l)) { + value = a; + return true; + } + return false; + } + + @Ignore("currently not working because swapped case isn't handled") + @Test + public void test3() { + test("testSnippet3", 1); + } + + public boolean testSnippet3(int a, int[] limit) { + int l = limit.length; + if (a < l && a >= 0) { + value = 9; + return true; + } + return false; + } + + @Test + public void test4() { + test("testSnippet4", 1); + } + + public boolean testSnippet4(int a, int[] limit) { + int l = limit.length; + if (a < 0) { + GraalDirectives.deoptimize(); + } + if (a >= l) { + GraalDirectives.deoptimize(); + } + return true; + } + + @Ignore("Reversed conditions aren't working with guards") + @Test + public void test5() { + test("testSnippet5", 1); + } + + public boolean testSnippet5(int a, int[] limit) { + int l = limit.length; + if (a >= l) { + GraalDirectives.deoptimize(); + } + if (a < 0) { + GraalDirectives.deoptimize(); + } + return true; + } + + public void test(String name, int logicCount) { + test(name, LogicNode.class, logicCount); + } + + public void test(String name, Class 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()); + } +} diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConditionAnchorNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConditionAnchorNode.java Wed Nov 18 12:01:29 2015 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConditionAnchorNode.java Wed Nov 18 12:01:42 2015 -0800 @@ -70,12 +70,12 @@ } public Node canonical(CanonicalizerTool tool, Node forValue) { - if (condition instanceof LogicNegationNode) { - LogicNegationNode negation = (LogicNegationNode) condition; + if (forValue instanceof LogicNegationNode) { + LogicNegationNode negation = (LogicNegationNode) forValue; return new ConditionAnchorNode(negation.getValue(), !negated); } - if (condition instanceof LogicConstantNode) { - LogicConstantNode c = (LogicConstantNode) condition; + if (forValue instanceof LogicConstantNode) { + LogicConstantNode c = (LogicConstantNode) forValue; if (c.getValue() != negated) { return null; } else { diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java Wed Nov 18 12:01:29 2015 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java Wed Nov 18 12:01:42 2015 -0800 @@ -784,18 +784,18 @@ for (EndNode end : merge.forwardEnds().snapshot()) { Node value = phi.valueAt(end); - Node result = null; + LogicNode result = null; if (condition() instanceof Canonicalizable.Binary) { Canonicalizable.Binary compare = (Canonicalizable.Binary) 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 compare = (Canonicalizable.Unary) 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); diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java Wed Nov 18 12:01:29 2015 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java Wed Nov 18 12:01:42 2015 -0800 @@ -132,6 +132,12 @@ ConvertNode convertX = (ConvertNode) forX; ConvertNode convertY = (ConvertNode) forY; if (convertX.preservesOrder(condition()) && convertY.preservesOrder(condition()) && convertX.getValue().stamp().isCompatible(convertY.getValue().stamp())) { + boolean multiUsage = (convertX.asNode().getUsageCount() > 1 || convertY.asNode().getUsageCount() > 1); + if ((forX instanceof ZeroExtendNode || forX instanceof SignExtendNode) && multiUsage) { + // Do not perform for zero or sign extend if there are multiple usages of the + // value. + return this; + } return duplicateModified(convertX.getValue(), convertY.getValue()); } } @@ -154,6 +160,12 @@ return optimizeNormalizeCmp(constant, (NormalizeCompareNode) nonConstant, mirrored); } else if (nonConstant instanceof ConvertNode) { ConvertNode convert = (ConvertNode) nonConstant; + boolean multiUsage = (convert.asNode().getUsageCount() > 1 && convert.getValue().getUsageCount() == 1); + if ((convert instanceof ZeroExtendNode || convert instanceof SignExtendNode) && multiUsage) { + // Do not perform for zero or sign extend if it could introduce + // new live values. + return this; + } ConstantNode newConstant = canonicalConvertConstant(tool, convert, constant); if (newConstant != null) { if (mirrored) { diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerLessThanNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerLessThanNode.java Wed Nov 18 12:01:29 2015 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerLessThanNode.java Wed Nov 18 12:01:42 2015 -0800 @@ -83,6 +83,20 @@ return this; } + public static boolean subtractMayUnderflow(long x, long y, long minValue) { + long r = x - y; + // HD 2-12 Overflow iff the arguments have different signs and + // the sign of the result is different than the sign of x + return (((x ^ y) & (x ^ r)) < 0) || r <= minValue; + } + + public static boolean subtractMayOverflow(long x, long y, long maxValue) { + long r = x - y; + // HD 2-12 Overflow iff the arguments have different signs and + // the sign of the result is different than the sign of x + return (((x ^ y) & (x ^ r)) < 0) || r > maxValue; + } + @Override public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) { ValueNode result = super.canonical(tool, forX, forY); @@ -98,6 +112,18 @@ return new IntegerBelowNode(forX, forY); } } + if (forY.isConstant() && forY.asConstant().isDefaultForKind() && forX instanceof SubNode) { + // (x - y) < 0 when x - y is known not to underflow == x < y + SubNode sub = (SubNode) forX; + IntegerStamp xStamp = (IntegerStamp) sub.getX().stamp(); + IntegerStamp yStamp = (IntegerStamp) sub.getY().stamp(); + long minValue = CodeUtil.minValue(xStamp.getBits()); + long maxValue = CodeUtil.maxValue(xStamp.getBits()); + + if (!subtractMayUnderflow(xStamp.lowerBound(), yStamp.upperBound(), minValue) && !subtractMayOverflow(xStamp.upperBound(), yStamp.lowerBound(), maxValue)) { + return new IntegerLessThanNode(sub.getX(), sub.getY()); + } + } return this; } diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowNode.java Wed Nov 18 12:01:29 2015 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowNode.java Wed Nov 18 12:01:42 2015 -0800 @@ -85,6 +85,12 @@ } else if (forValue instanceof IntegerConvertNode) { // SignExtendNode or ZeroExtendNode IntegerConvertNode other = (IntegerConvertNode) forValue; + if (other.getValue().getUsageCount() == 1 && other.getUsageCount() > 1) { + // Do not perform if this will introduce a new live value. + // If the original value's usage count is > 1, there is already another user. + // If the convert's usage count is <=1, it will be dead code eliminated. + return this; + } if (getResultBits() == other.getInputBits()) { // xxxx -(extend)-> yyyy xxxx -(narrow)-> xxxx // ==> no-op diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java Wed Nov 18 12:01:29 2015 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java Wed Nov 18 12:01:42 2015 -0800 @@ -48,6 +48,7 @@ import com.oracle.graal.nodes.ProxyNode; import com.oracle.graal.nodes.StartNode; import com.oracle.graal.nodes.StructuredGraph; +import com.oracle.graal.nodes.StructuredGraph.GuardsStage; public class ControlFlowGraph implements AbstractControlFlowGraph { /** @@ -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); + } } } } diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RawMonitorEnterNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RawMonitorEnterNode.java Wed Nov 18 12:01:29 2015 -0800 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RawMonitorEnterNode.java Wed Nov 18 12:01:42 2015 -0800 @@ -38,8 +38,8 @@ import com.oracle.graal.nodes.virtual.VirtualObjectNode; /** - * The {@code MonitorEnterNode} represents the acquisition of a monitor. The object needs already be - * non-null and the hub is an additional parameter to the node. + * The {@code RawMonitorEnterNode} represents the acquisition of a monitor. The object needs to + * already be non-null and the hub is an additional parameter to the node. */ @NodeInfo public final class RawMonitorEnterNode extends AccessMonitorNode implements Virtualizable, Lowerable, IterableNodeType, MonitorEnter, MemoryCheckpoint.Single { diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/MemoryScheduleVerification.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/MemoryScheduleVerification.java Wed Nov 18 12:01:29 2015 -0800 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/MemoryScheduleVerification.java Wed Nov 18 12:01:42 2015 -0800 @@ -140,7 +140,9 @@ @Override protected Set cloneState(Set oldState) { Set result = CollectionsFactory.newSet(); - result.addAll(oldState); + if (oldState != null) { + result.addAll(oldState); + } return result; } diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java Wed Nov 18 12:01:29 2015 -0800 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java Wed Nov 18 12:01:42 2015 -0800 @@ -49,6 +49,7 @@ import com.oracle.graal.nodes.AbstractMergeNode; import com.oracle.graal.nodes.ControlSinkNode; import com.oracle.graal.nodes.ControlSplitNode; +import com.oracle.graal.nodes.DeoptimizeNode; import com.oracle.graal.nodes.FixedNode; import com.oracle.graal.nodes.FrameState; import com.oracle.graal.nodes.GuardNode; @@ -275,6 +276,10 @@ for (Node n : nodes) { assert n.isAlive(); assert nodeMap.get(n) == b; + StructuredGraph g = (StructuredGraph) n.graph(); + if (g.hasLoops() && g.getGuardsStage().areDeoptsFixed() && n instanceof DeoptimizeNode) { + assert b.getLoopDepth() == 0 : n; + } } } return true; diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java --- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java Wed Nov 18 12:01:29 2015 -0800 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java Wed Nov 18 12:01:42 2015 -0800 @@ -37,11 +37,6 @@ import java.util.Map; import java.util.Map.Entry; -import jdk.vm.ci.meta.JavaType; -import jdk.vm.ci.meta.ResolvedJavaField; -import jdk.vm.ci.meta.ResolvedJavaMethod; -import jdk.vm.ci.meta.Signature; - import com.oracle.graal.compiler.common.cfg.BlockMap; import com.oracle.graal.debug.Debug; import com.oracle.graal.graph.CachedGraph; @@ -66,6 +61,11 @@ import com.oracle.graal.nodes.cfg.ControlFlowGraph; import com.oracle.graal.phases.schedule.SchedulePhase; +import jdk.vm.ci.meta.JavaType; +import jdk.vm.ci.meta.ResolvedJavaField; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.Signature; + public class BinaryGraphPrinter implements GraphPrinter { private static final int CONSTANT_POOL_MAX_SIZE = 8000; @@ -428,6 +428,20 @@ return node.getId(); } + private Object getBlockForNode(Node node, NodeMap nodeToBlocks) { + if (nodeToBlocks.isNew(node)) { + return "NEW (not in schedule)"; + } else { + Block block = nodeToBlocks.get(node); + if (block != null) { + return block.getId(); + } else if (node instanceof PhiNode) { + return getBlockForNode(((PhiNode) node).merge(), nodeToBlocks); + } + } + return null; + } + private void writeNodes(Graph graph, NodeMap nodeToBlocks, ControlFlowGraph cfg) throws IOException { Map props = new HashMap<>(); @@ -444,13 +458,9 @@ } } if (nodeToBlocks != null) { - if (nodeToBlocks.isNew(node)) { - props.put("node-to-block", "NEW (not in schedule)"); - } else { - Block block = nodeToBlocks.get(node); - if (block != null) { - props.put("node-to-block", block.getId()); - } + Object block = getBlockForNode(node, nodeToBlocks); + if (block != null) { + props.put("node-to-block", block); } } @@ -535,9 +545,23 @@ writeInt(blocks.size()); for (Block block : blocks) { List nodes = blockToNodes.get(block); + List extraNodes = new LinkedList<>(); writeInt(block.getId()); - writeInt(nodes.size()); for (Node node : nodes) { + if (node instanceof AbstractMergeNode) { + AbstractMergeNode merge = (AbstractMergeNode) node; + for (PhiNode phi : merge.phis()) { + if (!nodes.contains(phi)) { + extraNodes.add(phi); + } + } + } + } + writeInt(nodes.size() + extraNodes.size()); + for (Node node : nodes) { + writeInt(getNodeId(node)); + } + for (Node node : extraNodes) { writeInt(getNodeId(node)); } writeInt(block.getSuccessors().size()); diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64MathIntrinsicNode.java --- a/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64MathIntrinsicNode.java Wed Nov 18 12:01:29 2015 -0800 +++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64MathIntrinsicNode.java Wed Nov 18 12:01:42 2015 -0800 @@ -28,6 +28,7 @@ import com.oracle.graal.compiler.common.type.FloatStamp; import com.oracle.graal.compiler.common.type.PrimitiveStamp; +import com.oracle.graal.compiler.common.type.Stamp; import com.oracle.graal.compiler.common.type.StampFactory; import com.oracle.graal.graph.NodeClass; import com.oracle.graal.graph.spi.CanonicalizerTool; @@ -81,6 +82,20 @@ } @Override + public Stamp foldStamp(Stamp newStamp) { + if (newStamp instanceof FloatStamp) { + FloatStamp floatStamp = (FloatStamp) newStamp; + switch (operation()) { + case COS: + case SIN: + boolean nonNaN = floatStamp.lowerBound() != Double.NEGATIVE_INFINITY && floatStamp.upperBound() != Double.POSITIVE_INFINITY; + return StampFactory.forFloat(JavaKind.Double, -1.0, 1.0, nonNaN); + } + } + return super.foldStamp(newStamp); + } + + @Override public void generate(NodeLIRBuilderTool nodeValueMap, ArithmeticLIRGeneratorTool lirGen) { AMD64ArithmeticLIRGeneratorTool gen = (AMD64ArithmeticLIRGeneratorTool) lirGen; Value input = nodeValueMap.operand(getValue()); diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java Wed Nov 18 12:01:29 2015 -0800 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java Wed Nov 18 12:01:42 2015 -0800 @@ -73,8 +73,8 @@ import com.oracle.graal.graph.NodePosIterator; import com.oracle.graal.graph.Position; import com.oracle.graal.loop.LoopEx; -import com.oracle.graal.loop.LoopTransformations; import com.oracle.graal.loop.LoopsData; +import com.oracle.graal.loop.phases.LoopTransformations; import com.oracle.graal.nodeinfo.InputType; import com.oracle.graal.nodeinfo.NodeInfo; import com.oracle.graal.nodes.AbstractBeginNode; diff -r e3bcc6af1bcc -r 4af472d10ad6 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/debug/TraceCompilationASTListener.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/debug/TraceCompilationASTListener.java Wed Nov 18 12:01:29 2015 -0800 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/debug/TraceCompilationASTListener.java Wed Nov 18 12:01:42 2015 -0800 @@ -69,7 +69,7 @@ target.log(String.format("%s%s", indent, node.getClass().getSimpleName())); } else { String fieldName = "unknownField"; - NodeFieldAccessor[] fields = NodeClass.Lookup.get(parent).getFields(); + NodeFieldAccessor[] fields = NodeClass.get(parent).getFields(); for (NodeFieldAccessor field : fields) { Object value = field.loadValue(parent); if (value == node) { diff -r e3bcc6af1bcc -r 4af472d10ad6 mx.graal/suite.py --- a/mx.graal/suite.py Wed Nov 18 12:01:29 2015 -0800 +++ b/mx.graal/suite.py Wed Nov 18 12:01:42 2015 -0800 @@ -39,7 +39,7 @@ { "name" : "jvmci", "optional" : "true", - "version" : "c2b84783a4a4950a5fc5b4c75536291ae6952c40", + "version" : "2dea101cdfe9aacf55083cf5bd6f84cb23106f4e", "urls" : [ {"url" : "http://lafo.ssw.uni-linz.ac.at/hg/graal-jvmci-8", "kind" : "hg"}, {"url" : "https://curio.ssw.jku.at/nexus/content/repositories/snapshots", "kind" : "binary"}, @@ -47,7 +47,7 @@ }, { "name" : "truffle", - "version" : "0d4b0e4263ee95e3b0576409d7311489d4f5d463", + "version" : "dea950d41ef34ae68759ff0300a1fd80cf145c0f", "urls" : [ {"url" : "http://lafo.ssw.uni-linz.ac.at/hg/truffle", "kind" : "hg"}, {"url" : "https://curio.ssw.jku.at/nexus/content/repositories/snapshots", "kind" : "binary"}, @@ -493,7 +493,7 @@ "dependencies" : [ "com.oracle.graal.api.directives", "com.oracle.graal.java", - "com.oracle.graal.loop", + "com.oracle.graal.loop.phases", "com.oracle.graal.word", ], "checkstyle" : "com.oracle.graal.graph", @@ -664,7 +664,20 @@ "com.oracle.graal.loop" : { "subDir" : "graal", "sourceDirs" : ["src"], - "dependencies" : ["com.oracle.graal.phases.common"], + "dependencies" : ["com.oracle.graal.nodes"], + "annotationProcessors" : deps(["jvmci:JVMCI_OPTIONS_PROCESSOR"]), + "checkstyle" : "com.oracle.graal.graph", + "javaCompliance" : "1.8", + "workingSets" : "Graal", + }, + + "com.oracle.graal.loop.phases" : { + "subDir" : "graal", + "sourceDirs" : ["src"], + "dependencies" : [ + "com.oracle.graal.loop", + "com.oracle.graal.phases.common", + ], "annotationProcessors" : deps(["jvmci:JVMCI_OPTIONS_PROCESSOR"]), "checkstyle" : "com.oracle.graal.graph", "javaCompliance" : "1.8", @@ -676,7 +689,7 @@ "sourceDirs" : ["src"], "dependencies" : [ "com.oracle.graal.virtual", - "com.oracle.graal.loop", + "com.oracle.graal.loop.phases", ], "checkstyle" : "com.oracle.graal.graph", "javaCompliance" : "1.8",