# HG changeset patch # User Roland Schatz # Date 1422970630 -3600 # Node ID 81e464d4513765c70c5b00b8312da6e631096d70 # Parent 5e33637f5e5abda5bf23a766137250a306bd0d31 Prevent duplication of ControlFlowAnchor nodes. diff -r 5e33637f5e5a -r 81e464d45137 graal/com.oracle.graal.api.directives.test/src/com/oracle/graal/api/directives/test/ControlFlowAnchorDirectiveTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.api.directives.test/src/com/oracle/graal/api/directives/test/ControlFlowAnchorDirectiveTest.java Tue Feb 03 14:37:10 2015 +0100 @@ -0,0 +1,206 @@ +/* + * 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.api.directives.test; + +import java.lang.annotation.*; +import java.util.*; + +import org.junit.*; + +import com.oracle.graal.api.directives.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.iterators.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.debug.*; + +public class ControlFlowAnchorDirectiveTest extends GraalCompilerTest { + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.METHOD) + @Repeatable(AnchorSnippet.class) + private @interface NodeCount { + + Class nodeClass(); + + int expectedCount(); + } + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.METHOD) + private @interface AnchorSnippet { + NodeCount[] value(); + } + + @NodeCount(nodeClass = ReturnNode.class, expectedCount = 1) + public static int verifyMergeSnippet(int arg) { + if (arg > 5) { + return 1; + } else { + return 2; + } + } + + @NodeCount(nodeClass = ControlFlowAnchorNode.class, expectedCount = 2) + @NodeCount(nodeClass = ReturnNode.class, expectedCount = 2) + public static int preventMergeSnippet(int arg) { + if (arg > 5) { + GraalDirectives.controlFlowAnchor(); + return 1; + } else { + GraalDirectives.controlFlowAnchor(); + return 2; + } + } + + @Test + public void testMerge() { + test("verifyMergeSnippet", 42); + test("preventMergeSnippet", 42); + } + + @NodeCount(nodeClass = ReturnNode.class, expectedCount = 2) + public static int verifyDuplicateSnippet(int arg) { + int ret; + if (arg > 5) { + ret = 17; + } else { + ret = arg; + } + return 42 / ret; + } + + @NodeCount(nodeClass = ControlFlowAnchorNode.class, expectedCount = 1) + @NodeCount(nodeClass = ReturnNode.class, expectedCount = 1) + public static int preventDuplicateSnippet(int arg) { + int ret; + if (arg > 5) { + ret = 17; + } else { + ret = arg; + } + GraalDirectives.controlFlowAnchor(); + return 42 / ret; + } + + @Test + public void testDuplicate() { + test("verifyDuplicateSnippet", 42); + test("preventDuplicateSnippet", 42); + } + + @NodeCount(nodeClass = LoopBeginNode.class, expectedCount = 0) + public static int verifyFullUnrollSnippet(int arg) { + int ret = arg; + for (int i = 0; i < 5; i++) { + ret = ret * 3 + 1; + } + return ret; + } + + @NodeCount(nodeClass = LoopBeginNode.class, expectedCount = 1) + @NodeCount(nodeClass = ControlFlowAnchorNode.class, expectedCount = 1) + public static int preventFullUnrollSnippet(int arg) { + int ret = arg; + for (int i = 0; i < 5; i++) { + GraalDirectives.controlFlowAnchor(); + ret = ret * 3 + 1; + } + return ret; + } + + @Test + public void testFullUnroll() { + test("verifyFullUnrollSnippet", 42); + test("preventFullUnrollSnippet", 42); + } + + @NodeCount(nodeClass = LoopBeginNode.class, expectedCount = 1) + @NodeCount(nodeClass = IfNode.class, expectedCount = 4) + public static void verifyPeelSnippet(int arg) { + int ret = arg; + while (ret > 1) { + if (ret % 2 == 0) { + ret /= 2; + } else { + ret = 3 * ret + 1; + } + } + } + + @NodeCount(nodeClass = LoopBeginNode.class, expectedCount = 1) + @NodeCount(nodeClass = IfNode.class, expectedCount = 2) + public static void preventPeelSnippet(int arg) { + int ret = arg; + while (ret > 1) { + GraalDirectives.controlFlowAnchor(); + if (ret % 2 == 0) { + ret /= 2; + } else { + ret = 3 * ret + 1; + } + } + } + + @Test + public void testPeel() { + test("verifyPeelSnippet", 42); + test("preventPeelSnippet", 42); + } + + private static List getNodeCountAnnotations(StructuredGraph graph) { + ResolvedJavaMethod method = graph.method(); + AnchorSnippet snippet = method.getAnnotation(AnchorSnippet.class); + if (snippet != null) { + return Arrays.asList(snippet.value()); + } + + NodeCount single = method.getAnnotation(NodeCount.class); + if (single != null) { + return Collections.singletonList(single); + } + + return Collections.emptyList(); + } + + @Override + protected boolean checkLowTierGraph(StructuredGraph graph) { + List anchors = graph.getNodes().filter(ControlFlowAnchorNode.class).snapshot(); + for (int i = 0; i < anchors.size(); i++) { + ControlFlowAnchorNode a = anchors.get(i); + for (int j = i + 1; j < anchors.size(); j++) { + ControlFlowAnchorNode b = anchors.get(j); + if (a.valueEquals(b)) { + Assert.fail("found duplicated control flow anchors (" + a + " and " + b + ")"); + } + } + } + + for (NodeCount nodeCount : getNodeCountAnnotations(graph)) { + NodeIterable nodes = graph.getNodes().filter(nodeCount.nodeClass()); + Assert.assertEquals(nodeCount.nodeClass().getSimpleName(), nodeCount.expectedCount(), nodes.count()); + } + return true; + } +} diff -r 5e33637f5e5a -r 81e464d45137 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 Tue Feb 03 11:10:24 2015 +0100 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopPolicies.java Tue Feb 03 14:37:10 2015 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -31,6 +31,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.cfg.*; +import com.oracle.graal.nodes.debug.*; public abstract class LoopPolicies { @@ -45,7 +46,17 @@ } LoopBeginNode loopBegin = loop.loopBegin(); double entryProbability = probabilities.applyAsDouble(loopBegin.forwardEnd()); - return entryProbability > MinimumPeelProbability.getValue() && loop.size() + loopBegin.graph().getNodeCount() < MaximumDesiredSize.getValue(); + 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 static boolean shouldFullUnroll(LoopEx loop) { @@ -57,7 +68,17 @@ 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()); - return size * maxTrips <= maxNodes; + 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) { diff -r 5e33637f5e5a -r 81e464d45137 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/ControlFlowAnchorNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/ControlFlowAnchorNode.java Tue Feb 03 11:10:24 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/ControlFlowAnchorNode.java Tue Feb 03 14:37:10 2015 +0100 @@ -23,6 +23,7 @@ package com.oracle.graal.nodes.debug; import com.oracle.graal.compiler.common.type.*; +import com.oracle.graal.graph.*; import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; @@ -47,4 +48,9 @@ public void generate(NodeLIRBuilderTool generator) { // do nothing } + + @Override + protected void afterClone(Node other) { + assert false : this + " should never be cloned"; + } } diff -r 5e33637f5e5a -r 81e464d45137 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java Tue Feb 03 11:10:24 2015 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java Tue Feb 03 14:37:10 2015 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -36,6 +36,7 @@ import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.VirtualState.NodeClosure; +import com.oracle.graal.nodes.debug.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; @@ -192,7 +193,7 @@ int fixedCount = 0; while (fixed instanceof FixedWithNextNode) { fixed = ((FixedWithNextNode) fixed).next(); - if (fixed instanceof CommitAllocationNode) { + if (fixed instanceof CommitAllocationNode || fixed instanceof ControlFlowAnchorNode) { return false; } fixedCount++;