8073670: TypeF::eq and TypeD::eq do not handle NaNs correctly

Fri, 11 Aug 2017 03:30:28 -0400

author
dbuck
date
Fri, 11 Aug 2017 03:30:28 -0400
changeset 8886
fbb8f75498f4
parent 8885
1832e44a9889
child 8887
b55756ea22d8

8073670: TypeF::eq and TypeD::eq do not handle NaNs correctly
Summary: Change TypeF:eq and TypeD:eq to compare NaN values using a bitwise comparison.
Reviewed-by: kvn
Contributed-by: Stefan Anzinger <stefan.anzinger@oracle.com>

src/share/vm/opto/type.cpp file | annotate | diff | comparison | revisions
test/compiler/c2/FloatingPointFoldingTest.java file | annotate | diff | comparison | revisions
     1.1 --- a/src/share/vm/opto/type.cpp	Wed Jul 19 09:00:13 2017 +0200
     1.2 +++ b/src/share/vm/opto/type.cpp	Fri Aug 11 03:30:28 2017 -0400
     1.3 @@ -1001,21 +1001,10 @@
     1.4  
     1.5  //------------------------------eq---------------------------------------------
     1.6  // Structural equality check for Type representations
     1.7 -bool TypeF::eq( const Type *t ) const {
     1.8 -  if( g_isnan(_f) ||
     1.9 -      g_isnan(t->getf()) ) {
    1.10 -    // One or both are NANs.  If both are NANs return true, else false.
    1.11 -    return (g_isnan(_f) && g_isnan(t->getf()));
    1.12 -  }
    1.13 -  if (_f == t->getf()) {
    1.14 -    // (NaN is impossible at this point, since it is not equal even to itself)
    1.15 -    if (_f == 0.0) {
    1.16 -      // difference between positive and negative zero
    1.17 -      if (jint_cast(_f) != jint_cast(t->getf()))  return false;
    1.18 -    }
    1.19 -    return true;
    1.20 -  }
    1.21 -  return false;
    1.22 +bool TypeF::eq(const Type *t) const {
    1.23 +  // Bitwise comparison to distinguish between +/-0. These values must be treated
    1.24 +  // as different to be consistent with C1 and the interpreter.
    1.25 +  return (jint_cast(_f) == jint_cast(t->getf()));
    1.26  }
    1.27  
    1.28  //------------------------------hash-------------------------------------------
    1.29 @@ -1116,21 +1105,10 @@
    1.30  
    1.31  //------------------------------eq---------------------------------------------
    1.32  // Structural equality check for Type representations
    1.33 -bool TypeD::eq( const Type *t ) const {
    1.34 -  if( g_isnan(_d) ||
    1.35 -      g_isnan(t->getd()) ) {
    1.36 -    // One or both are NANs.  If both are NANs return true, else false.
    1.37 -    return (g_isnan(_d) && g_isnan(t->getd()));
    1.38 -  }
    1.39 -  if (_d == t->getd()) {
    1.40 -    // (NaN is impossible at this point, since it is not equal even to itself)
    1.41 -    if (_d == 0.0) {
    1.42 -      // difference between positive and negative zero
    1.43 -      if (jlong_cast(_d) != jlong_cast(t->getd()))  return false;
    1.44 -    }
    1.45 -    return true;
    1.46 -  }
    1.47 -  return false;
    1.48 +bool TypeD::eq(const Type *t) const {
    1.49 +  // Bitwise comparison to distinguish between +/-0. These values must be treated
    1.50 +  // as different to be consistent with C1 and the interpreter.
    1.51 +  return (jlong_cast(_d) == jlong_cast(t->getd()));
    1.52  }
    1.53  
    1.54  //------------------------------hash-------------------------------------------
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/test/compiler/c2/FloatingPointFoldingTest.java	Fri Aug 11 03:30:28 2017 -0400
     2.3 @@ -0,0 +1,163 @@
     2.4 +/*
     2.5 + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
     2.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     2.7 + *
     2.8 + * This code is free software; you can redistribute it and/or modify it
     2.9 + * under the terms of the GNU General Public License version 2 only, as
    2.10 + * published by the Free Software Foundation.
    2.11 + *
    2.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    2.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    2.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    2.15 + * version 2 for more details (a copy is included in the LICENSE file that
    2.16 + * accompanied this code).
    2.17 + *
    2.18 + * You should have received a copy of the GNU General Public License version
    2.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    2.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    2.21 + *
    2.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    2.23 + * or visit www.oracle.com if you need additional information or have any
    2.24 + * questions.
    2.25 + *
    2.26 + */
    2.27 +
    2.28 +/**
    2.29 + * @test
    2.30 + * @bug 8073670
    2.31 + * @summary Test that causes C2 to fold two NaNs with different values into a single NaN.
    2.32 + * @run main/othervm -XX:-TieredCompilation -Xcomp -XX:CompileCommand=compileonly,FloatingPointFoldingTest.test_double_inf -XX:CompileCommand=compileonly,FloatingPointFoldingTest.test_double_zero -XX:CompileCommand=compileonly,FloatingPointFoldingTest.test_double_nan -XX:CompileCommand=compileonly,FloatingPointFoldingTest.test_float_inf -XX:CompileCommand=compileonly,FloatingPointFoldingTest.test_float_zero -XX:CompileCommand=compileonly,FloatingPointFoldingTest.test_float_nan FloatingPointFoldingTest
    2.33 + */
    2.34 +
    2.35 +public class FloatingPointFoldingTest {
    2.36 +    // Double values.
    2.37 +    public static final long MINUS_INF_LONGBITS = 0xfff0000000000000L;
    2.38 +    public static final double DOUBLE_MINUS_INF = Double.longBitsToDouble(MINUS_INF_LONGBITS);
    2.39 +
    2.40 +    public static final long PLUS_INF_LONGBITS = 0x7ff0000000000000L;
    2.41 +    public static final double DOUBLE_PLUS_INF = Double.longBitsToDouble(PLUS_INF_LONGBITS);
    2.42 +
    2.43 +    public static final long MINUS_ZERO_LONGBITS = 0x8000000000000000L;
    2.44 +    public static final double DOUBLE_MINUS_ZERO = Double.longBitsToDouble(MINUS_ZERO_LONGBITS);
    2.45 +
    2.46 +    // We need two different NaN values. A floating point number is
    2.47 +    // considered to be NaN is the sign bit is 0, all exponent bits
    2.48 +    // are set to 1, and at least one bit of the exponent is not zero.
    2.49 +    //
    2.50 +    // As java.lang.Double.NaN is 0x7ff8000000000000L, we use
    2.51 +    // 0x7ffc000000000000L as a second NaN double value.
    2.52 +    public static final long NAN_LONGBITS = 0x7ffc000000000000L;
    2.53 +    public static final double DOUBLE_NAN = Double.longBitsToDouble(NAN_LONGBITS);
    2.54 +
    2.55 +    // Float values.
    2.56 +    public static final int MINUS_INF_INTBITS = 0xff800000;
    2.57 +    public static final float FLOAT_MINUS_INF = Float.intBitsToFloat(MINUS_INF_INTBITS);
    2.58 +
    2.59 +    public static final int PLUS_INF_INTBITS = 0x7f800000;
    2.60 +    public static final float FLOAT_PLUS_INF = Float.intBitsToFloat(PLUS_INF_INTBITS);
    2.61 +
    2.62 +    public static final int MINUS_ZERO_INTBITS = 0x80000000;
    2.63 +    public static final float FLOAT_MINUS_ZERO = Float.intBitsToFloat(MINUS_ZERO_INTBITS);
    2.64 +
    2.65 +    // As java.lang.Float.NaN is 0x7fc00000, we use 0x7fe00000
    2.66 +    // as a second NaN float value.
    2.67 +    public static final int NAN_INTBITS = 0x7fe00000;
    2.68 +    public static final float FLOAT_NAN = Float.intBitsToFloat(NAN_INTBITS);
    2.69 +
    2.70 +
    2.71 +    // Double tests.
    2.72 +    static void test_double_inf(long[] result) {
    2.73 +        double d1 = DOUBLE_MINUS_INF;
    2.74 +        double d2 = DOUBLE_PLUS_INF;
    2.75 +        result[0] = Double.doubleToRawLongBits(d1);
    2.76 +        result[1] = Double.doubleToRawLongBits(d2);
    2.77 +    }
    2.78 +
    2.79 +    static void test_double_zero(long[] result) {
    2.80 +        double d1 = DOUBLE_MINUS_ZERO;
    2.81 +        double d2 = 0;
    2.82 +        result[0] = Double.doubleToRawLongBits(d1);
    2.83 +        result[1] = Double.doubleToRawLongBits(d2);
    2.84 +    }
    2.85 +
    2.86 +    static void test_double_nan(long[] result) {
    2.87 +        double d1 = DOUBLE_NAN;
    2.88 +        double d2 = Double.NaN;
    2.89 +        result[0] = Double.doubleToRawLongBits(d1);
    2.90 +        result[1] = Double.doubleToRawLongBits(d2);
    2.91 +    }
    2.92 +
    2.93 +    // Float tests.
    2.94 +    static void test_float_inf(int[] result) {
    2.95 +        float f1 = FLOAT_MINUS_INF;
    2.96 +        float f2 = FLOAT_PLUS_INF;
    2.97 +        result[0] = Float.floatToRawIntBits(f1);
    2.98 +        result[1] = Float.floatToRawIntBits(f2);
    2.99 +    }
   2.100 +
   2.101 +    static void test_float_zero(int[] result) {
   2.102 +        float f1 = FLOAT_MINUS_ZERO;
   2.103 +        float f2 = 0;
   2.104 +        result[0] = Float.floatToRawIntBits(f1);
   2.105 +        result[1] = Float.floatToRawIntBits(f2);
   2.106 +    }
   2.107 +
   2.108 +    static void test_float_nan(int[] result) {
   2.109 +        float f1 = FLOAT_NAN;
   2.110 +        float f2 = Float.NaN;
   2.111 +        result[0] = Float.floatToRawIntBits(f1);
   2.112 +        result[1] = Float.floatToRawIntBits(f2);
   2.113 +    }
   2.114 +
   2.115 +    // Check doubles.
   2.116 +    static void check_double(long[] result, double d1, double d2) {
   2.117 +        if (result[0] == result[1]) {
   2.118 +            throw new RuntimeException("ERROR: Two different double values are considered equal. \n"
   2.119 +                                       + String.format("\toriginal values: 0x%x 0x%x\n", Double.doubleToRawLongBits(d1), Double.doubleToRawLongBits(d2))
   2.120 +                                       + String.format("\tvalues after execution of method test(): 0x%x 0x%x", result[0], result[1]));
   2.121 +        }
   2.122 +    }
   2.123 +
   2.124 +    // Check floats.
   2.125 +    static void check_float(int[] result, float f1, float f2) {
   2.126 +        if (result[0] == result[1]) {
   2.127 +            throw new RuntimeException("ERROR: Two different float values are considered equal. \n"
   2.128 +                                       + String.format("\toriginal values: 0x%x 0x%x\n", Float.floatToRawIntBits(f1), Float.floatToRawIntBits(f2))
   2.129 +                                       + String.format("\tvalues after execution of method test(): 0x%x 0x%x", result[0], result[1]));
   2.130 +        }
   2.131 +    }
   2.132 +
   2.133 +    public static void main(String[] args) {
   2.134 +        // Float tests.
   2.135 +
   2.136 +        int[] iresult = new int[2];
   2.137 +
   2.138 +        // -Inf and +Inf.
   2.139 +        test_float_inf(iresult);
   2.140 +        check_float(iresult, FLOAT_MINUS_INF, FLOAT_PLUS_INF);
   2.141 +
   2.142 +        // 0 and -0.
   2.143 +        test_float_zero(iresult);
   2.144 +        check_float(iresult, FLOAT_MINUS_ZERO, 0);
   2.145 +
   2.146 +        // Diferrent NaNs.
   2.147 +        test_float_nan(iresult);
   2.148 +        check_float(iresult, FLOAT_NAN, Float.NaN);
   2.149 +
   2.150 +        // Double tests.
   2.151 +
   2.152 +        long[] lresult = new long[2];
   2.153 +
   2.154 +        // -Inf and +Inf.
   2.155 +        test_double_inf(lresult);
   2.156 +        check_double(lresult, DOUBLE_MINUS_INF, DOUBLE_PLUS_INF);
   2.157 +
   2.158 +        // 0 and -0.
   2.159 +        test_double_zero(lresult);
   2.160 +        check_double(lresult, DOUBLE_MINUS_ZERO, 0);
   2.161 +
   2.162 +        // Diferrent NaNs.
   2.163 +        test_double_nan(lresult);
   2.164 +        check_double(lresult, DOUBLE_NAN, Double.NaN);
   2.165 +    }
   2.166 +}

mercurial