BitOpNodesTest.java revision 12651:6ef01bd40ce2
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 */
23package org.graalvm.compiler.replacements.test;
24
25import org.junit.Assert;
26import org.junit.Assume;
27import org.junit.Test;
28
29import org.graalvm.compiler.core.common.type.StampFactory;
30import org.graalvm.compiler.core.test.GraalCompilerTest;
31import org.graalvm.compiler.nodes.ReturnNode;
32import org.graalvm.compiler.nodes.StructuredGraph;
33import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
34import org.graalvm.compiler.nodes.ValueNode;
35import org.graalvm.compiler.phases.common.CanonicalizerPhase;
36import org.graalvm.compiler.phases.common.inlining.InliningPhase;
37import org.graalvm.compiler.phases.tiers.HighTierContext;
38import org.graalvm.compiler.replacements.nodes.BitScanReverseNode;
39
40import jdk.vm.ci.amd64.AMD64;
41import jdk.vm.ci.code.Architecture;
42import jdk.vm.ci.meta.JavaKind;
43import jdk.vm.ci.sparc.SPARC;
44
45public 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}
288