--- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/BitOpNodesTest.java 2016-12-09 00:56:43.600456200 -0800 @@ -0,0 +1,287 @@ +/* + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.replacements.test; + +import org.junit.Assert; +import org.junit.Assume; +import org.junit.Test; + +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.nodes.ReturnNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.inlining.InliningPhase; +import org.graalvm.compiler.phases.tiers.HighTierContext; +import org.graalvm.compiler.replacements.nodes.BitScanReverseNode; + +import jdk.vm.ci.amd64.AMD64; +import jdk.vm.ci.code.Architecture; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.sparc.SPARC; + +public class BitOpNodesTest extends GraalCompilerTest { + + private static final int INT_CONSTANT_1 = 0x80100010; + private static final int INT_CONSTANT_2 = 0x00011110; + private static final int INT_CONSTANT_3 = 0x00000000; + + private static final long LONG_CONSTANT_1 = 0x8000000000100010L; + private static final long LONG_CONSTANT_2 = 0x0000000000011110L; + private static final long LONG_CONSTANT_3 = 0x0000000000000000L; + + public static long dummyField; + + /* + * Tests for BitCountNode canonicalizations. + */ + + public static int bitCountIntConstantSnippet() { + return Integer.bitCount(INT_CONSTANT_1) + Integer.bitCount(INT_CONSTANT_2) + Integer.bitCount(INT_CONSTANT_3); + } + + @Test + public void testBitCountIntConstant() { + ValueNode result = parseAndInline("bitCountIntConstantSnippet"); + Assert.assertEquals(7, result.asJavaConstant().asInt()); + } + + public static int bitCountLongConstantSnippet() { + return Long.bitCount(LONG_CONSTANT_1) + Long.bitCount(LONG_CONSTANT_2) + Long.bitCount(LONG_CONSTANT_3); + } + + public static int bitCountIntSnippet(int v) { + return Integer.bitCount(v & 0xFFFFFF | 0xFF); + } + + @Test + public void testBitCountInt() { + Architecture arch = getBackend().getTarget().arch; + boolean isAmd64WithPopCount = arch instanceof AMD64 && ((AMD64) arch).getFeatures().contains(AMD64.CPUFeature.POPCNT); + boolean isSparc = arch instanceof SPARC; + Assume.assumeTrue("Only works on hardware with popcnt at the moment", isAmd64WithPopCount || isSparc); + ValueNode result = parseAndInline("bitCountIntSnippet"); + Assert.assertEquals(StampFactory.forInteger(JavaKind.Int, 8, 24), result.stamp()); + } + + public static int bitCountIntEmptySnippet(int v) { + return Integer.bitCount(v & 0xFFFFFF); + } + + @Test + public void testBitCountIntEmpty() { + Architecture arch = getBackend().getTarget().arch; + boolean isAmd64WithPopCount = arch instanceof AMD64 && ((AMD64) arch).getFeatures().contains(AMD64.CPUFeature.POPCNT); + boolean isSparc = arch instanceof SPARC; + Assume.assumeTrue("Only works on hardware with popcnt at the moment", isAmd64WithPopCount || isSparc); + ValueNode result = parseAndInline("bitCountIntEmptySnippet"); + Assert.assertEquals(StampFactory.forInteger(JavaKind.Int, 0, 24), result.stamp()); + } + + @Test + public void testBitCountLongConstant() { + ValueNode result = parseAndInline("bitCountLongConstantSnippet"); + Assert.assertEquals(7, result.asJavaConstant().asInt()); + } + + public static int bitCountLongSnippet(long v) { + return Long.bitCount(v & 0xFFFFFFFFFFL | 0xFFL); + } + + @Test + public void testBitCountLong() { + Architecture arch = getBackend().getTarget().arch; + boolean isAmd64WithPopCount = arch instanceof AMD64 && ((AMD64) arch).getFeatures().contains(AMD64.CPUFeature.POPCNT); + boolean isSparc = arch instanceof SPARC; + Assume.assumeTrue("Only works on hardware with popcnt at the moment", isAmd64WithPopCount || isSparc); + ValueNode result = parseAndInline("bitCountLongSnippet"); + Assert.assertEquals(StampFactory.forInteger(JavaKind.Int, 8, 40), result.stamp()); + } + + public static int bitCountLongEmptySnippet(long v) { + return Long.bitCount(v & 0xFFFFFFFFFFL); + } + + @Test + public void testBitCountLongEmpty() { + Architecture arch = getBackend().getTarget().arch; + boolean isAmd64WithPopCount = arch instanceof AMD64 && ((AMD64) arch).getFeatures().contains(AMD64.CPUFeature.POPCNT); + boolean isSparc = arch instanceof SPARC; + Assume.assumeTrue("Only works on hardware with popcnt at the moment", isAmd64WithPopCount || isSparc); + ValueNode result = parseAndInline("bitCountLongEmptySnippet"); + Assert.assertEquals(StampFactory.forInteger(JavaKind.Int, 0, 40), result.stamp()); + } + + /* + * Tests for BitScanForwardNode + */ + + public static int scanForwardIntConstantSnippet() { + return Integer.numberOfTrailingZeros(INT_CONSTANT_1) + Integer.numberOfTrailingZeros(INT_CONSTANT_2) + Integer.numberOfTrailingZeros(INT_CONSTANT_3); + } + + @Test + public void testScanForwardIntConstant() { + ValueNode result = parseAndInline("scanForwardIntConstantSnippet"); + Assert.assertEquals(40, result.asJavaConstant().asInt()); + } + + public static int scanForwardIntSnippet(int v) { + return Integer.numberOfTrailingZeros(v & 0xFFF0 | 0xFF00); + } + + @Test + public void testScanForwardInt() { + ValueNode result = parseAndInline("scanForwardIntSnippet"); + Assert.assertEquals(StampFactory.forInteger(JavaKind.Int, 4, 8), result.stamp()); + } + + public static int scanForwardLongConstantSnippet() { + return Long.numberOfTrailingZeros(LONG_CONSTANT_1) + Long.numberOfTrailingZeros(LONG_CONSTANT_2) + Long.numberOfTrailingZeros(LONG_CONSTANT_3); + } + + @Test + public void testScanForwardLongConstant() { + ValueNode result = parseAndInline("scanForwardLongConstantSnippet"); + Assert.assertEquals(72, result.asJavaConstant().asInt()); + } + + public static int scanForwardLongSnippet(long v) { + return Long.numberOfTrailingZeros(v & 0xFFFF000000L | 0xFF00000000L); + } + + @Test + public void testScanForwardLong() { + ValueNode result = parseAndInline("scanForwardLongSnippet"); + Assert.assertEquals(StampFactory.forInteger(JavaKind.Int, 24, 32), result.stamp()); + } + + public static int scanForwardLongEmptySnippet(long v) { + int result = Long.numberOfTrailingZeros(v & 0xFFFF000000L); + dummyField = result; + return result; + } + + @Test + public void testScanForwardLongEmpty() { + ValueNode result = parseAndInline("scanForwardLongEmptySnippet"); + Assert.assertEquals(StampFactory.forInteger(JavaKind.Int, 24, 64), result.stamp()); + } + + /* + * Tests for BitScanReverseNode + */ + + public static int scanReverseIntConstantSnippet() { + return Integer.numberOfLeadingZeros(INT_CONSTANT_1) + Integer.numberOfLeadingZeros(INT_CONSTANT_2) + Integer.numberOfLeadingZeros(INT_CONSTANT_3); + } + + @Test + public void testScanReverseIntConstant() { + ValueNode result = parseAndInline("scanReverseIntConstantSnippet"); + Assert.assertEquals(47, result.asJavaConstant().asInt()); + } + + public static int scanReverseIntSnippet(int v) { + return Integer.numberOfLeadingZeros(v & 0xFFF0 | 0xFF0); + } + + @Test + public void testScanReverseInt() { + /* This test isn't valid unless the BitScanReverseNode intrinsic is used. */ + ValueNode result = parseAndInline("scanReverseIntSnippet", BitScanReverseNode.class); + if (result != null) { + Assert.assertEquals(StampFactory.forInteger(JavaKind.Int, 16, 20), result.stamp()); + } + } + + public static int scanReverseLongConstantSnippet() { + return Long.numberOfLeadingZeros(LONG_CONSTANT_1) + Long.numberOfLeadingZeros(LONG_CONSTANT_2) + Long.numberOfLeadingZeros(LONG_CONSTANT_3); + } + + @Test + public void testScanReverseLongConstant() { + ValueNode result = parseAndInline("scanReverseLongConstantSnippet"); + Assert.assertEquals(111, result.asJavaConstant().asInt()); + } + + public static int scanReverseLongSnippet(long v) { + int result = Long.numberOfLeadingZeros(v & 0xFFF0); + dummyField = result; + return result; + } + + @Test + public void testScanReverseLong() { + /* This test isn't valid unless the BitScanReverseNode intrinsic is used. */ + ValueNode result = parseAndInline("scanReverseLongSnippet", BitScanReverseNode.class); + if (result != null) { + Assert.assertEquals(StampFactory.forInteger(JavaKind.Int, 48, 64), result.stamp()); + } + } + + public static int scanReverseLongEmptySnippet(long v) { + int result = Long.numberOfLeadingZeros(v & 0xFFFF000000L); + dummyField = result; + return result; + } + + @Test + public void testScanReverseLongEmpty() { + /* This test isn't valid unless the BitScanReverseNode intrinsic is used. */ + ValueNode result = parseAndInline("scanReverseLongEmptySnippet", BitScanReverseNode.class); + if (result != null) { + Assert.assertEquals(StampFactory.forInteger(JavaKind.Int, 24, 64), result.stamp()); + } + } + + private ValueNode parseAndInline(String name) { + return parseAndInline(name, null); + } + + /** + * Parse and optimize {@code name}. If {@code expectedClass} is non-null and a node of that type + * isn't found simply return null. Otherwise return the node returned by the graph. + * + * @param name + * @param expectedClass + * @return the returned value or null if {@code expectedClass} is not found in the graph. + */ + private ValueNode parseAndInline(String name, Class expectedClass) { + StructuredGraph graph = parseEager(name, AllowAssumptions.YES); + HighTierContext context = getDefaultHighTierContext(); + CanonicalizerPhase canonicalizer = new CanonicalizerPhase(); + canonicalizer.apply(graph, context); + new InliningPhase(canonicalizer).apply(graph, context); + canonicalizer.apply(graph, context); + Assert.assertEquals(1, graph.getNodes(ReturnNode.TYPE).count()); + if (expectedClass != null) { + if (graph.getNodes().filter(expectedClass).count() == 0) { + return null; + } + } + return graph.getNodes(ReturnNode.TYPE).first().result(); + } +}