001/*
002 * Copyright (c) 2012, 2014, 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.replacements.test;
024
025import java.util.*;
026
027import jdk.internal.jvmci.code.*;
028import jdk.internal.jvmci.meta.*;
029
030import org.junit.*;
031
032import com.oracle.graal.api.replacements.*;
033import com.oracle.graal.nodes.*;
034import com.oracle.graal.nodes.calc.*;
035import com.oracle.graal.replacements.nodes.*;
036
037/**
038 * Tests the VM independent {@link MethodSubstitution}s.
039 */
040public class StandardMethodSubstitutionsTest extends MethodSubstitutionTest {
041
042    @Test
043    public void testMathSubstitutions() {
044        assertInGraph(assertNotInGraph(testGraph("mathAbs"), IfNode.class), AbsNode.class);     // Java
045        double value = 34567.891D;
046        testGraph("mathCos");
047        testGraph("mathLog");
048        testGraph("mathLog10");
049        testGraph("mathSin");
050        testGraph("mathSqrt");
051        testGraph("mathTan");
052        testGraph("mathAll");
053
054        test("mathCos", value);
055        test("mathLog", value);
056        test("mathLog10", value);
057        test("mathSin", value);
058        test("mathSqrt", value);
059        test("mathTan", value);
060        test("mathAll", value);
061    }
062
063    @Test
064    public void testMathPow() {
065        double a = 34567.891D;
066        double b = 4.6D;
067        test("mathPow", a, b);
068
069        // Test the values directly handled by the substitution
070
071        // If the second argument is positive or negative zero, then the result is 1.0.
072        test("mathPow", a, 0.0D);
073        test("mathPow", a, -0.0D);
074        // If the second argument is 1.0, then the result is the same as the first argument.
075        test("mathPow", a, 1.0D);
076        // If the second argument is NaN, then the result is NaN.
077        test("mathPow", a, Double.NaN);
078        // If the first argument is NaN and the second argument is nonzero, then the result is NaN.
079        test("mathPow", Double.NaN, b);
080        test("mathPow", Double.NaN, 0.0D);
081        // x**-1 = 1/x
082        test("mathPow", a, -1.0D);
083        // x**2 = x*x
084        test("mathPow", a, 2.0D);
085        // x**0.5 = sqrt(x)
086        test("mathPow", a, 0.5D);
087    }
088
089    public static double mathPow(double a, double b) {
090        return mathPow0(a, b);
091    }
092
093    public static double mathPow0(double a, double b) {
094        return Math.pow(a, b);
095    }
096
097    public static double mathAbs(double value) {
098        return Math.abs(value);
099    }
100
101    public static double mathSqrt(double value) {
102        return Math.sqrt(value);
103    }
104
105    public static double mathLog(double value) {
106        return Math.log(value);
107    }
108
109    public static double mathLog10(double value) {
110        return Math.log10(value);
111    }
112
113    public static double mathSin(double value) {
114        return Math.sin(value);
115    }
116
117    public static double mathCos(double value) {
118        return Math.cos(value);
119    }
120
121    public static double mathTan(double value) {
122        return Math.tan(value);
123    }
124
125    public static double mathAll(double value) {
126        return Math.sqrt(value) + Math.log(value) + Math.log10(value) + Math.sin(value) + Math.cos(value) + Math.tan(value);
127    }
128
129    public void testSubstitution(String testMethodName, Class<?> intrinsicClass, Class<?> holder, String methodName, boolean optional, Object... args) {
130        ResolvedJavaMethod realJavaMethod = getResolvedJavaMethod(holder, methodName);
131        ResolvedJavaMethod testJavaMethod = getResolvedJavaMethod(testMethodName);
132        StructuredGraph graph = testGraph(testMethodName);
133
134        // Check to see if the resulting graph contains the expected node
135        StructuredGraph replacement = getReplacements().getSubstitution(realJavaMethod, -1);
136        if (replacement == null && !optional) {
137            assertInGraph(graph, intrinsicClass);
138        }
139
140        for (Object l : args) {
141            // Force compilation
142            InstalledCode code = getCode(testJavaMethod);
143            assert optional || code != null;
144            // Verify that the original method and the substitution produce the same value
145            Object expected = invokeSafe(realJavaMethod, null, l);
146            assertDeepEquals(expected, invokeSafe(testJavaMethod, null, l));
147            // Verify that the generated code and the original produce the same value
148            assertDeepEquals(expected, executeVarargsSafe(code, l));
149        }
150    }
151
152    @Test
153    public void testIntegerSubstitutions() {
154        Object[] args = new Object[]{Integer.MIN_VALUE, -1, 0, 1, Integer.MAX_VALUE};
155
156        testSubstitution("integerReverseBytes", ReverseBytesNode.class, Integer.class, "reverseBytes", false, args);
157        testSubstitution("integerNumberOfLeadingZeros", BitScanReverseNode.class, Integer.class, "numberOfLeadingZeros", true, args);
158        testSubstitution("integerNumberOfTrailingZeros", BitScanForwardNode.class, Integer.class, "numberOfTrailingZeros", false, args);
159        testSubstitution("integerBitCount", BitCountNode.class, Integer.class, "bitCount", true, args);
160    }
161
162    public static int integerReverseBytes(int value) {
163        return Integer.reverseBytes(value);
164    }
165
166    public static int integerNumberOfLeadingZeros(int value) {
167        return Integer.numberOfLeadingZeros(value);
168    }
169
170    public static int integerNumberOfTrailingZeros(int value) {
171        return Integer.numberOfTrailingZeros(value);
172    }
173
174    public static int integerBitCount(int value) {
175        return Integer.bitCount(value);
176    }
177
178    @Test
179    public void testLongSubstitutions() {
180        Object[] args = new Object[]{Long.MIN_VALUE, -1L, 0L, 1L, Long.MAX_VALUE};
181
182        testSubstitution("longReverseBytes", ReverseBytesNode.class, Long.class, "reverseBytes", false, args);
183        testSubstitution("longNumberOfLeadingZeros", BitScanReverseNode.class, Long.class, "numberOfLeadingZeros", true, args);
184        testSubstitution("longNumberOfTrailingZeros", BitScanForwardNode.class, Long.class, "numberOfTrailingZeros", false, args);
185        testSubstitution("longBitCount", BitCountNode.class, Long.class, "bitCount", true, args);
186    }
187
188    public static long longReverseBytes(long value) {
189        return Long.reverseBytes(value);
190    }
191
192    public static int longNumberOfLeadingZeros(long value) {
193        return Long.numberOfLeadingZeros(value);
194    }
195
196    public static int longNumberOfTrailingZeros(long value) {
197        return Long.numberOfTrailingZeros(value);
198    }
199
200    public static int longBitCount(long value) {
201        return Long.bitCount(value);
202    }
203
204    @Test
205    public void testFloatSubstitutions() {
206        assertInGraph(testGraph("floatToIntBits"), ReinterpretNode.class); // Java
207        testGraph("intBitsToFloat");
208    }
209
210    public static int floatToIntBits(float value) {
211        return Float.floatToIntBits(value);
212    }
213
214    public static float intBitsToFloat(int value) {
215        return Float.intBitsToFloat(value);
216    }
217
218    @Test
219    public void testDoubleSubstitutions() {
220        assertInGraph(testGraph("doubleToLongBits"), ReinterpretNode.class); // Java
221        testGraph("longBitsToDouble");
222    }
223
224    public static long doubleToLongBits(double value) {
225        return Double.doubleToLongBits(value);
226    }
227
228    public static double longBitsToDouble(long value) {
229        return Double.longBitsToDouble(value);
230    }
231
232    public static boolean isInstance(Class<?> clazz, Object object) {
233        return clazz.isInstance(object);
234    }
235
236    public static boolean isInstance2(boolean cond, Object object) {
237        Class<?> clazz;
238        if (cond) {
239            clazz = String.class;
240        } else {
241            clazz = java.util.HashMap.class;
242        }
243        return clazz.isInstance(object);
244    }
245
246    public static boolean isAssignableFrom(Class<?> clazz, Class<?> other) {
247        return clazz.isAssignableFrom(other);
248    }
249
250    @Test
251    public void testClassSubstitutions() {
252        testGraph("isInstance");
253        testGraph("isInstance2");
254        testGraph("isAssignableFrom");
255        for (Class<?> c : new Class[]{getClass(), Cloneable.class, int[].class, String[][].class}) {
256            for (Object o : new Object[]{this, new int[5], new String[2][], new Object()}) {
257                test("isInstance", c, o);
258                test("isAssignableFrom", c, o.getClass());
259            }
260        }
261
262        test("isInstance2", true, null);
263        test("isInstance2", false, null);
264        test("isInstance2", true, "string");
265        test("isInstance2", false, "string");
266        test("isInstance2", true, new HashMap<>());
267        test("isInstance2", false, new HashMap<>());
268    }
269}