1 /*
2  * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
3  * Copyright (c) 2018, 2019, Arm Limited. All rights reserved.
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This code is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License version 2 only, as
8  * published by the Free Software Foundation.
9  *
10  * This code is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13  * version 2 for more details (a copy is included in the LICENSE file that
14  * accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License version
17  * 2 along with this work; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19  *
20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21  * or visit www.oracle.com if you need additional information or have any
22  * questions.
23  */
24 
25 /*
26  * @test
27  * @bug 8212043
28  * @summary Test compiler intrinsics of floating-point Math.min/max
29  * @library /test/lib
30  *
31  * @comment the test isn't marked by 'randomness' b/c randomSearchTree case isn't used
32  * @run main/othervm -Xint compiler.intrinsics.math.TestFpMinMaxIntrinsics sanityTests 1
33  * @run main/othervm -XX:+UnlockDiagnosticVMOptions
34  *                   -Xcomp -XX:TieredStopAtLevel=1
35  *                   -XX:CompileOnly=java/lang/Math
36  *                   compiler.intrinsics.math.TestFpMinMaxIntrinsics sanityTests 1
37  * @run main/othervm -XX:+UnlockDiagnosticVMOptions
38  *                   -Xcomp -XX:-TieredCompilation
39  *                   -XX:CompileOnly=java/lang/Math
40  *                   compiler.intrinsics.math.TestFpMinMaxIntrinsics sanityTests 1
41  * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
42  *                   -XX:-TieredCompilation -XX:CompileThresholdScaling=0.1
43  *                   -XX:CompileCommand=print,compiler/intrinsics/math/TestFpMinMaxIntrinsics.*Test*
44  *                   compiler.intrinsics.math.TestFpMinMaxIntrinsics sanityTests 10000
45  * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
46  *                   -XX:-TieredCompilation -Xcomp
47  *                   -XX:CompileCommand=print,compiler/intrinsics/math/TestFpMinMaxIntrinsics.*Test*
48  *                   -XX:CompileCommand=compileonly,compiler/intrinsics/math/TestFpMinMaxIntrinsics.*Test*
49  *                   compiler.intrinsics.math.TestFpMinMaxIntrinsics reductionTests 100
50  */
51 
52 package compiler.intrinsics.math;
53 
54 import java.util.Arrays;
55 import java.util.Random;
56 import java.lang.reflect.Method;
57 import jdk.test.lib.Utils;
58 
59 public class TestFpMinMaxIntrinsics {
60 
61     private static final float fPos     =  15280.0f;
62     private static final float fNeg     = -55555.5f;
63     private static final float fPosZero =      0.0f;
64     private static final float fNegZero =     -0.0f;
65     private static final float fPosInf  = Float.POSITIVE_INFINITY;
66     private static final float fNegInf  = Float.NEGATIVE_INFINITY;
67     private static final float fNaN     = Float.NaN;
68 
69     private static final double dPos     =  482390926662501720.0;
70     private static final double dNeg     = -333333333333333333.3;
71     private static final double dPosZero =                   0.0;
72     private static final double dNegZero =                  -0.0;
73     private static final double dPosInf  = Double.POSITIVE_INFINITY;
74     private static final double dNegInf  = Double.NEGATIVE_INFINITY;
75     private static final double dNaN     = Double.NaN;
76 
77     private static final float[][] f_cases = {
78         //     a         b         min       max
79         {     fPos,     fPos,     fPos,     fPos },
80         {     fNeg,     fNeg,     fNeg,     fNeg },
81         {     fPos,     fNeg,     fNeg,     fPos },
82         {     fNeg,     fPos,     fNeg,     fPos },
83 
84         { fPosZero, fNegZero, fNegZero, fPosZero },
85         { fNegZero, fPosZero, fNegZero, fPosZero },
86         { fNegZero, fNegZero, fNegZero, fNegZero },
87 
88         {     fPos,  fPosInf,     fPos,  fPosInf },
89         {     fNeg,  fNegInf,  fNegInf,     fNeg },
90 
91         {     fPos,     fNaN,     fNaN,     fNaN },
92         {     fNaN,     fPos,     fNaN,     fNaN },
93         {     fNeg,     fNaN,     fNaN,     fNaN },
94         {     fNaN,     fNeg,     fNaN,     fNaN },
95 
96         {  fPosInf,     fNaN,     fNaN,     fNaN },
97         {     fNaN,  fPosInf,     fNaN,     fNaN },
98         {  fNegInf,     fNaN,     fNaN,     fNaN },
99         {     fNaN,  fNegInf,     fNaN,     fNaN }
100     };
101 
102     private static final double[][] d_cases = {
103         //     a         b         min       max
104         {     dPos,     dPos,     dPos,     dPos },
105         {     dNeg,     dNeg,     dNeg,     dNeg },
106         {     dPos,     dNeg,     dNeg,     dPos },
107         {     dNeg,     dPos,     dNeg,     dPos },
108 
109         { dPosZero, dNegZero, dNegZero, dPosZero },
110         { dNegZero, dPosZero, dNegZero, dPosZero },
111         { dNegZero, dNegZero, dNegZero, dNegZero },
112 
113         {     dPos,  dPosInf,     dPos,  dPosInf },
114         {     dNeg,  dNegInf,  dNegInf,     dNeg },
115 
116         {     dPos,     dNaN,     dNaN,     dNaN },
117         {     dNaN,     dPos,     dNaN,     dNaN },
118         {     dNeg,     dNaN,     dNaN,     dNaN },
119         {     dNaN,     dNeg,     dNaN,     dNaN },
120 
121         {  dPosInf,     dNaN,     dNaN,     dNaN },
122         {     dNaN,  dPosInf,     dNaN,     dNaN },
123         {  dNegInf,     dNaN,     dNaN,     dNaN },
124         {     dNaN,  dNegInf,     dNaN,     dNaN }
125     };
126 
fTest(float[] row)127     private static void fTest(float[] row) {
128         fCheck(row[0], row[1], Math.min(row[0], row[1]), Math.max(row[0], row[1]), row[2], row[3]);
129     }
130 
fReductionTest(float[] row)131     private static void fReductionTest(float[] row) {
132         float fmin = row[0], fmax = row[0];
133 
134         for (int i=0; i<100; i++) {
135             fmin = Math.min(fmin, row[1]);
136             fmax = Math.max(fmax, row[1]);
137         }
138 
139         fCheck(row[0], row[1], fmin, fmax, row[2], row[3]);
140     }
141 
fCheck(float a, float b, float fmin, float fmax, float efmin, float efmax)142     private static void fCheck(float a, float b, float fmin, float fmax, float efmin, float efmax) {
143         int min = Float.floatToRawIntBits(fmin);
144         int max = Float.floatToRawIntBits(fmax);
145         int emin = Float.floatToRawIntBits(efmin);
146         int emax = Float.floatToRawIntBits(efmax);
147 
148         if (min != emin || max != emax) {
149             throw new AssertionError("Unexpected result of float min/max: " +
150                     "a = " + a + ", b = " + b + ", " +
151                     "result = (" + fmin + ", " + fmax + "), " +
152                     "expected = (" + efmin + ", " + efmax + ")");
153         }
154     }
155 
dTest(double[] row)156     private static void dTest(double[] row) {
157         dCheck(row[0], row[1], Math.min(row[0], row[1]), Math.max(row[0], row[1]), row[2], row[3]);
158     }
159 
dReductionTest(double[] row)160     private static void dReductionTest(double[] row) {
161         double dmin = row[0], dmax = row[0];
162 
163         for (int i=0; i<100; i++) {
164             dmin = Math.min(dmin, row[1]);
165             dmax = Math.max(dmax, row[1]);
166         }
167 
168         dCheck(row[0], row[1], dmin, dmax, row[2], row[3]);
169     }
170 
dCheck(double a, double b, double dmin, double dmax, double edmin, double edmax)171     private static void dCheck(double a, double b, double dmin, double dmax, double edmin, double edmax) {
172         double min = Double.doubleToRawLongBits(dmin);
173         double max = Double.doubleToRawLongBits(dmax);
174         double emin = Double.doubleToRawLongBits(edmin);
175         double emax = Double.doubleToRawLongBits(edmax);
176 
177         if (min != emin || max != emax) {
178             throw new AssertionError("Unexpected result of double min/max: " +
179                     "a = " + a + ", b = " + b + ", " +
180                     "result = (" + dmin + ", " + dmax + "), " +
181                     "expected = (" + edmin + ", " + edmax + ")");
182         }
183     }
184 
sanityTests()185     public static void sanityTests() {
186         Arrays.stream(f_cases).forEach(TestFpMinMaxIntrinsics::fTest);
187         Arrays.stream(d_cases).forEach(TestFpMinMaxIntrinsics::dTest);
188     }
189 
reductionTests()190     public static void reductionTests() {
191         Arrays.stream(f_cases).forEach(TestFpMinMaxIntrinsics::fReductionTest);
192         Arrays.stream(d_cases).forEach(TestFpMinMaxIntrinsics::dReductionTest);
193     }
194 
main(String[] args)195     public static void main(String[] args) throws Exception {
196         Method m = TestFpMinMaxIntrinsics.class.getDeclaredMethod(args[0]);
197         for (int i = 0 ; i < Integer.parseInt(args[1]) ; i++)
198             m.invoke(null);
199     }
200 
201     private static final int COUNT = 1000;
202     private static final int LOOPS = 100;
203 
204     private static Random r = Utils.getRandomInstance();
205 
206     private static Node[] pool = new Node[COUNT];
207 
208     private static long time = 0;
209     private static long times = 0;
210 
init()211     public static void init() {
212         for (int i=0; i<COUNT; i++)
213             pool[i] = new Node(Double.NaN);
214     }
215 
finish()216     public static void finish() {
217         // String sorted = pool[0].toString();
218         // System.out.println("Sorted: {" + sorted.substring(0, Math.min(sorted.length(), 180)) + "... }");
219         System.out.println("Average time: " + (time/times) + " ns");
220     }
221 
randomSearchTree()222     public static void randomSearchTree() {
223         init();
224         for (int l=0; l < LOOPS; l++) {
225             Node root = pool[0].reset(r.nextDouble());
226 
227             for (int i=1; i<COUNT; i++)
228                 insert(root, pool[i].reset(r.nextDouble()));
229         }
230         finish();
231     }
232 
sortedSearchTree()233     public static void sortedSearchTree() {
234         init();
235         for (int l=0; l < LOOPS; l++) {
236             Node root = pool[0].reset(-0.0);
237 
238             for (int i=1; i<COUNT; i++)
239                 insert(root, pool[i].reset(i-1));
240         }
241         finish();
242     }
243 
244     private static class Node {
245         private double value;
246         private Node min;
247         private Node max;
248 
Node(double d)249         public Node(double d) { value = d; }
250 
reset(double d)251         public Node reset(double d) { value = d; min = max = null; return this; }
252 
253         @Override
toString()254         public String toString() {
255             return  (min != null ? min + ", " : "") +
256                     value +
257                     (max != null ? ", " + max : "");
258         }
259     }
260 
insert(Node root, Node d)261     private static Node insert(Node root, Node d) {
262         for ( ; ; ) {
263             long rootBits = Double.doubleToRawLongBits(root.value);
264             long dBits = Double.doubleToRawLongBits(d.value);
265 
266             // No duplicates
267             if (rootBits == dBits)
268                 return root;
269 
270             long delta = System.nanoTime();
271 
272             double dmin = min(root.value, d.value);
273 
274             time += System.nanoTime() - delta;
275             times++;
276 
277             long minBits = Double.doubleToRawLongBits(dmin);
278 
279             if (minBits == dBits)
280                 if (root.min != null)
281                     root = root.min;
282                 else
283                     return root.min = d;
284             else
285                 if (root.max != null)
286                     root = root.max;
287                 else
288                     return root.max = d;
289         }
290     }
291 
292     // Wrapper method to prevent code reordering from affecting measures (JLS 17.4).
min(double a, double b)293     private static double min(double a, double b) {
294         return Math.min(a, b);
295     }
296 }
297