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