Fri, 11 Aug 2017 03:30:28 -0400
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 +}