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}