1 /* 2 * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package org.graalvm.compiler.api.directives.test; 24 25 import java.lang.annotation.ElementType; 26 import java.lang.annotation.Repeatable; 27 import java.lang.annotation.Retention; 28 import java.lang.annotation.RetentionPolicy; 29 import java.lang.annotation.Target; 30 import java.util.Arrays; 31 import java.util.Collections; 32 import java.util.List; 33 34 import org.junit.Assert; 35 import org.junit.Test; 36 37 import org.graalvm.compiler.api.directives.GraalDirectives; 38 import org.graalvm.compiler.core.test.GraalCompilerTest; 39 import org.graalvm.compiler.graph.Node; 40 import org.graalvm.compiler.graph.iterators.NodeIterable; 41 import org.graalvm.compiler.nodes.IfNode; 42 import org.graalvm.compiler.nodes.LoopBeginNode; 43 import org.graalvm.compiler.nodes.ReturnNode; 44 import org.graalvm.compiler.nodes.StructuredGraph; 45 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; 46 import org.graalvm.compiler.nodes.debug.ControlFlowAnchorNode; 47 48 import jdk.vm.ci.meta.ResolvedJavaMethod; 49 import org.graalvm.compiler.phases.OptimisticOptimizations; 50 import org.graalvm.compiler.phases.OptimisticOptimizations.Optimization; 51 import org.graalvm.compiler.phases.tiers.HighTierContext; 52 53 public class ControlFlowAnchorDirectiveTest extends GraalCompilerTest { 54 55 @Retention(RetentionPolicy.RUNTIME) 56 @Target(ElementType.METHOD) 57 @Repeatable(AnchorSnippet.class) 58 private @interface NodeCount { 59 60 Class<? extends Node> nodeClass(); 61 62 int expectedCount(); 63 } 64 65 @Retention(RetentionPolicy.RUNTIME) 66 @Target(ElementType.METHOD) 67 private @interface AnchorSnippet { 68 NodeCount[] value(); 69 } 70 71 @NodeCount(nodeClass = ReturnNode.class, expectedCount = 1) 72 public static int verifyMergeSnippet(int arg) { 73 if (arg > 5) { 74 return 1; 75 } else { 76 return 2; 77 } 78 } 79 80 @NodeCount(nodeClass = ControlFlowAnchorNode.class, expectedCount = 2) 81 @NodeCount(nodeClass = ReturnNode.class, expectedCount = 2) 82 public static int preventMergeSnippet(int arg) { 83 if (arg > 5) { 84 GraalDirectives.controlFlowAnchor(); 85 return 1; 86 } else { 87 GraalDirectives.controlFlowAnchor(); 88 return 2; 89 } 90 } 91 92 @Test 93 public void testMerge() { 94 test("verifyMergeSnippet", 42); 95 test("preventMergeSnippet", 42); 96 } 97 98 @NodeCount(nodeClass = ReturnNode.class, expectedCount = 2) 99 public static int verifyDuplicateSnippet(int arg) { 100 int ret; 101 if (arg > 5) { 102 ret = 17; 103 } else { 104 ret = arg; 105 } 106 return 42 / ret; 107 } 108 109 @NodeCount(nodeClass = ControlFlowAnchorNode.class, expectedCount = 1) 110 @NodeCount(nodeClass = ReturnNode.class, expectedCount = 1) 111 public static int preventDuplicateSnippet(int arg) { 112 int ret; 113 if (arg > 5) { 114 ret = 17; 115 } else { 116 ret = arg; 117 } 118 GraalDirectives.controlFlowAnchor(); 119 return 42 / ret; 120 } 121 122 @Test 123 public void testDuplicate() { 124 // test("verifyDuplicateSnippet", 42); 125 test("preventDuplicateSnippet", 42); 126 } 127 128 @NodeCount(nodeClass = LoopBeginNode.class, expectedCount = 0) 129 public static int verifyFullUnrollSnippet(int arg) { 130 int ret = arg; 131 for (int i = 0; i < 5; i++) { 132 ret = ret * 3 + 1; 133 } 134 return ret; 135 } 136 137 @NodeCount(nodeClass = LoopBeginNode.class, expectedCount = 1) 138 @NodeCount(nodeClass = ControlFlowAnchorNode.class, expectedCount = 1) 139 public static int preventFullUnrollSnippet(int arg) { 140 int ret = arg; 141 for (int i = 0; i < 5; i++) { 142 GraalDirectives.controlFlowAnchor(); 143 ret = ret * 3 + 1; 144 } 145 return ret; 146 } 147 148 @Test 149 public void testFullUnroll() { 150 test("verifyFullUnrollSnippet", 42); 151 test("preventFullUnrollSnippet", 42); 152 } 153 154 @NodeCount(nodeClass = LoopBeginNode.class, expectedCount = 1) 155 @NodeCount(nodeClass = IfNode.class, expectedCount = 4) 156 public static void verifyPeelSnippet(int arg) { 157 int ret = arg; 158 while (ret > 1) { 159 if (ret % 2 == 0) { 160 ret /= 2; 161 } else { 162 ret = 3 * ret + 1; 163 } 164 } 165 } 166 167 @NodeCount(nodeClass = LoopBeginNode.class, expectedCount = 1) 168 @NodeCount(nodeClass = IfNode.class, expectedCount = 2) 169 public static void preventPeelSnippet(int arg) { 170 int ret = arg; 171 while (ret > 1) { 172 GraalDirectives.controlFlowAnchor(); 173 if (ret % 2 == 0) { 174 GraalDirectives.controlFlowAnchor(); 175 ret /= 2; 176 } else { 177 ret = 3 * ret + 1; 178 } 179 } 180 } 181 182 @Test 183 public void testPeel() { 184 test("preventPeelSnippet", 42); 185 } 186 187 @NodeCount(nodeClass = LoopBeginNode.class, expectedCount = 2) 188 public static void verifyUnswitchSnippet(int arg, boolean flag) { 189 int ret = arg; 190 while (GraalDirectives.injectBranchProbability(0.9999, ret < 1000)) { 191 if (flag) { 192 ret = ret * 2 + 1; 193 } else { 194 ret = ret * 3 + 1; 195 } 196 } 197 } 198 199 @NodeCount(nodeClass = LoopBeginNode.class, expectedCount = 1) 200 @NodeCount(nodeClass = IfNode.class, expectedCount = 2) 201 public static void preventUnswitchSnippet(int arg, boolean flag) { 202 int ret = arg; 203 while (GraalDirectives.injectBranchProbability(0.9999, ret < 1000)) { 204 if (flag) { 205 GraalDirectives.controlFlowAnchor(); 206 ret++; 207 } else { 208 ret += 2; 209 } 210 } 211 } 212 213 @Test 214 public void testUnswitch() { 215 test("verifyUnswitchSnippet", 0, false); 216 test("preventUnswitchSnippet", 0, false); 217 } 218 219 /** 220 * Cloning a ControlFlowAnchorNode is not allowed but cloning a whole graph containing one is 221 * ok. 222 */ 223 @Test 224 public void testClone() { 225 StructuredGraph g = parseEager("preventPeelSnippet", AllowAssumptions.NO); 226 g.copy(g.getDebug()); 227 } 228 229 private static List<NodeCount> getNodeCountAnnotations(StructuredGraph graph) { 230 ResolvedJavaMethod method = graph.method(); 231 AnchorSnippet snippet = method.getAnnotation(AnchorSnippet.class); 232 if (snippet != null) { 233 return Arrays.asList(snippet.value()); 234 } 235 236 NodeCount single = method.getAnnotation(NodeCount.class); 237 if (single != null) { 238 return Collections.singletonList(single); 239 } 240 241 return Collections.emptyList(); 242 } 243 244 @Override 245 protected HighTierContext getDefaultHighTierContext() { 246 return new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL.remove(Optimization.RemoveNeverExecutedCode)); 247 } 248 249 @Override 250 protected boolean checkLowTierGraph(StructuredGraph graph) { 251 List<ControlFlowAnchorNode> anchors = graph.getNodes().filter(ControlFlowAnchorNode.class).snapshot(); 252 for (int i = 0; i < anchors.size(); i++) { 253 ControlFlowAnchorNode a = anchors.get(i); 254 for (int j = i + 1; j < anchors.size(); j++) { 255 ControlFlowAnchorNode b = anchors.get(j); 256 if (a.valueEquals(b)) { 257 Assert.fail("found duplicated control flow anchors (" + a + " and " + b + ")"); 258 } 259 } 260 } 261 262 for (NodeCount nodeCount : getNodeCountAnnotations(graph)) { 263 NodeIterable<? extends Node> nodes = graph.getNodes().filter(nodeCount.nodeClass()); 264 Assert.assertEquals(nodeCount.nodeClass().getSimpleName(), nodeCount.expectedCount(), nodes.count()); 265 } 266 return true; 267 } 268 }