001/*
002 * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023package com.oracle.graal.api.directives.test;
024
025import java.lang.annotation.*;
026import java.util.*;
027
028import jdk.internal.jvmci.meta.*;
029
030import org.junit.*;
031
032import com.oracle.graal.api.directives.*;
033import com.oracle.graal.compiler.test.*;
034import com.oracle.graal.graph.*;
035import com.oracle.graal.graph.iterators.*;
036import com.oracle.graal.nodes.*;
037import com.oracle.graal.nodes.debug.*;
038
039public class ControlFlowAnchorDirectiveTest extends GraalCompilerTest {
040
041    @Retention(RetentionPolicy.RUNTIME)
042    @Target(ElementType.METHOD)
043    @Repeatable(AnchorSnippet.class)
044    private @interface NodeCount {
045
046        Class<? extends Node> nodeClass();
047
048        int expectedCount();
049    }
050
051    @Retention(RetentionPolicy.RUNTIME)
052    @Target(ElementType.METHOD)
053    private @interface AnchorSnippet {
054        NodeCount[] value();
055    }
056
057    @NodeCount(nodeClass = ReturnNode.class, expectedCount = 1)
058    public static int verifyMergeSnippet(int arg) {
059        if (arg > 5) {
060            return 1;
061        } else {
062            return 2;
063        }
064    }
065
066    @NodeCount(nodeClass = ControlFlowAnchorNode.class, expectedCount = 2)
067    @NodeCount(nodeClass = ReturnNode.class, expectedCount = 2)
068    public static int preventMergeSnippet(int arg) {
069        if (arg > 5) {
070            GraalDirectives.controlFlowAnchor();
071            return 1;
072        } else {
073            GraalDirectives.controlFlowAnchor();
074            return 2;
075        }
076    }
077
078    @Test
079    public void testMerge() {
080        test("verifyMergeSnippet", 42);
081        test("preventMergeSnippet", 42);
082    }
083
084    @NodeCount(nodeClass = ReturnNode.class, expectedCount = 2)
085    public static int verifyDuplicateSnippet(int arg) {
086        int ret;
087        if (arg > 5) {
088            ret = 17;
089        } else {
090            ret = arg;
091        }
092        return 42 / ret;
093    }
094
095    @NodeCount(nodeClass = ControlFlowAnchorNode.class, expectedCount = 1)
096    @NodeCount(nodeClass = ReturnNode.class, expectedCount = 1)
097    public static int preventDuplicateSnippet(int arg) {
098        int ret;
099        if (arg > 5) {
100            ret = 17;
101        } else {
102            ret = arg;
103        }
104        GraalDirectives.controlFlowAnchor();
105        return 42 / ret;
106    }
107
108    @Test
109    public void testDuplicate() {
110        // test("verifyDuplicateSnippet", 42);
111        test("preventDuplicateSnippet", 42);
112    }
113
114    @NodeCount(nodeClass = LoopBeginNode.class, expectedCount = 0)
115    public static int verifyFullUnrollSnippet(int arg) {
116        int ret = arg;
117        for (int i = 0; i < 5; i++) {
118            ret = ret * 3 + 1;
119        }
120        return ret;
121    }
122
123    @NodeCount(nodeClass = LoopBeginNode.class, expectedCount = 1)
124    @NodeCount(nodeClass = ControlFlowAnchorNode.class, expectedCount = 1)
125    public static int preventFullUnrollSnippet(int arg) {
126        int ret = arg;
127        for (int i = 0; i < 5; i++) {
128            GraalDirectives.controlFlowAnchor();
129            ret = ret * 3 + 1;
130        }
131        return ret;
132    }
133
134    @Test
135    public void testFullUnroll() {
136        test("verifyFullUnrollSnippet", 42);
137        test("preventFullUnrollSnippet", 42);
138    }
139
140    @NodeCount(nodeClass = LoopBeginNode.class, expectedCount = 1)
141    @NodeCount(nodeClass = IfNode.class, expectedCount = 4)
142    public static void verifyPeelSnippet(int arg) {
143        int ret = arg;
144        while (ret > 1) {
145            if (ret % 2 == 0) {
146                ret /= 2;
147            } else {
148                ret = 3 * ret + 1;
149            }
150        }
151    }
152
153    @NodeCount(nodeClass = LoopBeginNode.class, expectedCount = 1)
154    @NodeCount(nodeClass = IfNode.class, expectedCount = 2)
155    public static void preventPeelSnippet(int arg) {
156        int ret = arg;
157        while (ret > 1) {
158            GraalDirectives.controlFlowAnchor();
159            if (ret % 2 == 0) {
160                ret /= 2;
161            } else {
162                ret = 3 * ret + 1;
163            }
164        }
165    }
166
167    @Test
168    public void testPeel() {
169        test("preventPeelSnippet", 42);
170    }
171
172    private static List<NodeCount> getNodeCountAnnotations(StructuredGraph graph) {
173        ResolvedJavaMethod method = graph.method();
174        AnchorSnippet snippet = method.getAnnotation(AnchorSnippet.class);
175        if (snippet != null) {
176            return Arrays.asList(snippet.value());
177        }
178
179        NodeCount single = method.getAnnotation(NodeCount.class);
180        if (single != null) {
181            return Collections.singletonList(single);
182        }
183
184        return Collections.emptyList();
185    }
186
187    @Override
188    protected boolean checkLowTierGraph(StructuredGraph graph) {
189        List<ControlFlowAnchorNode> anchors = graph.getNodes().filter(ControlFlowAnchorNode.class).snapshot();
190        for (int i = 0; i < anchors.size(); i++) {
191            ControlFlowAnchorNode a = anchors.get(i);
192            for (int j = i + 1; j < anchors.size(); j++) {
193                ControlFlowAnchorNode b = anchors.get(j);
194                if (a.valueEquals(b)) {
195                    Assert.fail("found duplicated control flow anchors (" + a + " and " + b + ")");
196                }
197            }
198        }
199
200        for (NodeCount nodeCount : getNodeCountAnnotations(graph)) {
201            NodeIterable<? extends Node> nodes = graph.getNodes().filter(nodeCount.nodeClass());
202            Assert.assertEquals(nodeCount.nodeClass().getSimpleName(), nodeCount.expectedCount(), nodes.count());
203        }
204        return true;
205    }
206}