1 /* 2 * Copyright (c) 2012, 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.replacements.test; 24 25 import org.junit.Assert; 26 import org.junit.Assume; 27 import org.junit.Test; 28 29 import org.graalvm.compiler.core.common.type.StampFactory; 30 import org.graalvm.compiler.core.test.GraalCompilerTest; 31 import org.graalvm.compiler.nodes.ReturnNode; 32 import org.graalvm.compiler.nodes.StructuredGraph; 33 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; 34 import org.graalvm.compiler.nodes.ValueNode; 35 import org.graalvm.compiler.phases.common.CanonicalizerPhase; 36 import org.graalvm.compiler.phases.common.inlining.InliningPhase; 37 import org.graalvm.compiler.phases.tiers.HighTierContext; 38 import org.graalvm.compiler.replacements.nodes.BitScanReverseNode; 39 40 import jdk.vm.ci.amd64.AMD64; 41 import jdk.vm.ci.code.Architecture; 42 import jdk.vm.ci.meta.JavaKind; 43 import jdk.vm.ci.sparc.SPARC; 44 45 public class BitOpNodesTest extends GraalCompilerTest { 46 47 private static final int INT_CONSTANT_1 = 0x80100010; 48 private static final int INT_CONSTANT_2 = 0x00011110; 49 private static final int INT_CONSTANT_3 = 0x00000000; 50 51 private static final long LONG_CONSTANT_1 = 0x8000000000100010L; 52 private static final long LONG_CONSTANT_2 = 0x0000000000011110L; 53 private static final long LONG_CONSTANT_3 = 0x0000000000000000L; 54 55 public static long dummyField; 56 57 /* 58 * Tests for BitCountNode canonicalizations. 59 */ 60 61 public static int bitCountIntConstantSnippet() { 62 return Integer.bitCount(INT_CONSTANT_1) + Integer.bitCount(INT_CONSTANT_2) + Integer.bitCount(INT_CONSTANT_3); 63 } 64 65 @Test 66 public void testBitCountIntConstant() { 67 ValueNode result = parseAndInline("bitCountIntConstantSnippet"); 68 Assert.assertEquals(7, result.asJavaConstant().asInt()); 69 } 70 71 public static int bitCountLongConstantSnippet() { 72 return Long.bitCount(LONG_CONSTANT_1) + Long.bitCount(LONG_CONSTANT_2) + Long.bitCount(LONG_CONSTANT_3); 73 } 74 75 public static int bitCountIntSnippet(int v) { 76 return Integer.bitCount(v & 0xFFFFFF | 0xFF); 77 } 78 79 @Test 80 public void testBitCountInt() { 81 Architecture arch = getBackend().getTarget().arch; 82 boolean isAmd64WithPopCount = arch instanceof AMD64 && ((AMD64) arch).getFeatures().contains(AMD64.CPUFeature.POPCNT); 83 boolean isSparc = arch instanceof SPARC; 84 Assume.assumeTrue("Only works on hardware with popcnt at the moment", isAmd64WithPopCount || isSparc); 85 ValueNode result = parseAndInline("bitCountIntSnippet"); 86 Assert.assertEquals(StampFactory.forInteger(JavaKind.Int, 8, 24), result.stamp()); 87 } 88 89 public static int bitCountIntEmptySnippet(int v) { 90 return Integer.bitCount(v & 0xFFFFFF); 91 } 92 93 @Test 94 public void testBitCountIntEmpty() { 95 Architecture arch = getBackend().getTarget().arch; 96 boolean isAmd64WithPopCount = arch instanceof AMD64 && ((AMD64) arch).getFeatures().contains(AMD64.CPUFeature.POPCNT); 97 boolean isSparc = arch instanceof SPARC; 98 Assume.assumeTrue("Only works on hardware with popcnt at the moment", isAmd64WithPopCount || isSparc); 99 ValueNode result = parseAndInline("bitCountIntEmptySnippet"); 100 Assert.assertEquals(StampFactory.forInteger(JavaKind.Int, 0, 24), result.stamp()); 101 } 102 103 @Test 104 public void testBitCountLongConstant() { 105 ValueNode result = parseAndInline("bitCountLongConstantSnippet"); 106 Assert.assertEquals(7, result.asJavaConstant().asInt()); 107 } 108 109 public static int bitCountLongSnippet(long v) { 110 return Long.bitCount(v & 0xFFFFFFFFFFL | 0xFFL); 111 } 112 113 @Test 114 public void testBitCountLong() { 115 Architecture arch = getBackend().getTarget().arch; 116 boolean isAmd64WithPopCount = arch instanceof AMD64 && ((AMD64) arch).getFeatures().contains(AMD64.CPUFeature.POPCNT); 117 boolean isSparc = arch instanceof SPARC; 118 Assume.assumeTrue("Only works on hardware with popcnt at the moment", isAmd64WithPopCount || isSparc); 119 ValueNode result = parseAndInline("bitCountLongSnippet"); 120 Assert.assertEquals(StampFactory.forInteger(JavaKind.Int, 8, 40), result.stamp()); 121 } 122 123 public static int bitCountLongEmptySnippet(long v) { 124 return Long.bitCount(v & 0xFFFFFFFFFFL); 125 } 126 127 @Test 128 public void testBitCountLongEmpty() { 129 Architecture arch = getBackend().getTarget().arch; 130 boolean isAmd64WithPopCount = arch instanceof AMD64 && ((AMD64) arch).getFeatures().contains(AMD64.CPUFeature.POPCNT); 131 boolean isSparc = arch instanceof SPARC; 132 Assume.assumeTrue("Only works on hardware with popcnt at the moment", isAmd64WithPopCount || isSparc); 133 ValueNode result = parseAndInline("bitCountLongEmptySnippet"); 134 Assert.assertEquals(StampFactory.forInteger(JavaKind.Int, 0, 40), result.stamp()); 135 } 136 137 /* 138 * Tests for BitScanForwardNode 139 */ 140 141 public static int scanForwardIntConstantSnippet() { 142 return Integer.numberOfTrailingZeros(INT_CONSTANT_1) + Integer.numberOfTrailingZeros(INT_CONSTANT_2) + Integer.numberOfTrailingZeros(INT_CONSTANT_3); 143 } 144 145 @Test 146 public void testScanForwardIntConstant() { 147 ValueNode result = parseAndInline("scanForwardIntConstantSnippet"); 148 Assert.assertEquals(40, result.asJavaConstant().asInt()); 149 } 150 151 public static int scanForwardIntSnippet(int v) { 152 return Integer.numberOfTrailingZeros(v & 0xFFF0 | 0xFF00); 153 } 154 155 @Test 156 public void testScanForwardInt() { 157 ValueNode result = parseAndInline("scanForwardIntSnippet"); 158 Assert.assertEquals(StampFactory.forInteger(JavaKind.Int, 4, 8), result.stamp()); 159 } 160 161 public static int scanForwardLongConstantSnippet() { 162 return Long.numberOfTrailingZeros(LONG_CONSTANT_1) + Long.numberOfTrailingZeros(LONG_CONSTANT_2) + Long.numberOfTrailingZeros(LONG_CONSTANT_3); 163 } 164 165 @Test 166 public void testScanForwardLongConstant() { 167 ValueNode result = parseAndInline("scanForwardLongConstantSnippet"); 168 Assert.assertEquals(72, result.asJavaConstant().asInt()); 169 } 170 171 public static int scanForwardLongSnippet(long v) { 172 return Long.numberOfTrailingZeros(v & 0xFFFF000000L | 0xFF00000000L); 173 } 174 175 @Test 176 public void testScanForwardLong() { 177 ValueNode result = parseAndInline("scanForwardLongSnippet"); 178 Assert.assertEquals(StampFactory.forInteger(JavaKind.Int, 24, 32), result.stamp()); 179 } 180 181 public static int scanForwardLongEmptySnippet(long v) { 182 int result = Long.numberOfTrailingZeros(v & 0xFFFF000000L); 183 dummyField = result; 184 return result; 185 } 186 187 @Test 188 public void testScanForwardLongEmpty() { 189 ValueNode result = parseAndInline("scanForwardLongEmptySnippet"); 190 Assert.assertEquals(StampFactory.forInteger(JavaKind.Int, 24, 64), result.stamp()); 191 } 192 193 /* 194 * Tests for BitScanReverseNode 195 */ 196 197 public static int scanReverseIntConstantSnippet() { 198 return Integer.numberOfLeadingZeros(INT_CONSTANT_1) + Integer.numberOfLeadingZeros(INT_CONSTANT_2) + Integer.numberOfLeadingZeros(INT_CONSTANT_3); 199 } 200 201 @Test 202 public void testScanReverseIntConstant() { 203 ValueNode result = parseAndInline("scanReverseIntConstantSnippet"); 204 Assert.assertEquals(47, result.asJavaConstant().asInt()); 205 } 206 207 public static int scanReverseIntSnippet(int v) { 208 return Integer.numberOfLeadingZeros(v & 0xFFF0 | 0xFF0); 209 } 210 211 @Test 212 public void testScanReverseInt() { 213 /* This test isn't valid unless the BitScanReverseNode intrinsic is used. */ 214 ValueNode result = parseAndInline("scanReverseIntSnippet", BitScanReverseNode.class); 215 if (result != null) { 216 Assert.assertEquals(StampFactory.forInteger(JavaKind.Int, 16, 20), result.stamp()); 217 } 218 } 219 220 public static int scanReverseLongConstantSnippet() { 221 return Long.numberOfLeadingZeros(LONG_CONSTANT_1) + Long.numberOfLeadingZeros(LONG_CONSTANT_2) + Long.numberOfLeadingZeros(LONG_CONSTANT_3); 222 } 223 224 @Test 225 public void testScanReverseLongConstant() { 226 ValueNode result = parseAndInline("scanReverseLongConstantSnippet"); 227 Assert.assertEquals(111, result.asJavaConstant().asInt()); 228 } 229 230 public static int scanReverseLongSnippet(long v) { 231 int result = Long.numberOfLeadingZeros(v & 0xFFF0); 232 dummyField = result; 233 return result; 234 } 235 236 @Test 237 public void testScanReverseLong() { 238 /* This test isn't valid unless the BitScanReverseNode intrinsic is used. */ 239 ValueNode result = parseAndInline("scanReverseLongSnippet", BitScanReverseNode.class); 240 if (result != null) { 241 Assert.assertEquals(StampFactory.forInteger(JavaKind.Int, 48, 64), result.stamp()); 242 } 243 } 244 245 public static int scanReverseLongEmptySnippet(long v) { 246 int result = Long.numberOfLeadingZeros(v & 0xFFFF000000L); 247 dummyField = result; 248 return result; 249 } 250 251 @Test 252 public void testScanReverseLongEmpty() { 253 /* This test isn't valid unless the BitScanReverseNode intrinsic is used. */ 254 ValueNode result = parseAndInline("scanReverseLongEmptySnippet", BitScanReverseNode.class); 255 if (result != null) { 256 Assert.assertEquals(StampFactory.forInteger(JavaKind.Int, 24, 64), result.stamp()); 257 } 258 } 259 260 private ValueNode parseAndInline(String name) { 261 return parseAndInline(name, null); 262 } 263 264 /** 265 * Parse and optimize {@code name}. If {@code expectedClass} is non-null and a node of that type 266 * isn't found simply return null. Otherwise return the node returned by the graph. 267 * 268 * @param name 269 * @param expectedClass 270 * @return the returned value or null if {@code expectedClass} is not found in the graph. 271 */ 272 private ValueNode parseAndInline(String name, Class<? extends ValueNode> expectedClass) { 273 StructuredGraph graph = parseEager(name, AllowAssumptions.YES); 274 HighTierContext context = getDefaultHighTierContext(); 275 CanonicalizerPhase canonicalizer = new CanonicalizerPhase(); 276 canonicalizer.apply(graph, context); 277 new InliningPhase(canonicalizer).apply(graph, context); 278 canonicalizer.apply(graph, context); 279 Assert.assertEquals(1, graph.getNodes(ReturnNode.TYPE).count()); 280 if (expectedClass != null) { 281 if (graph.getNodes().filter(expectedClass).count() == 0) { 282 return null; 283 } 284 } 285 return graph.getNodes(ReturnNode.TYPE).first().result(); 286 } 287 }