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