diff --git a/ChangeLog b/ChangeLog index 523028da4a..3f7e5d6e20 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,22 @@ +2016-12-15 Joseph Myers + + [BZ #20947] + * sysdeps/i386/fpu/s_fmaxl.S (__fmaxl): Add the arguments when + either is a signaling NaN. + * sysdeps/i386/fpu/s_fminl.S (__fminl): Likewise. Make code + follow fmaxl more closely. + * sysdeps/i386/i686/fpu/s_fmaxl.S (__fmaxl): Add the arguments + when either is a signaling NaN. + * sysdeps/i386/i686/fpu/s_fminl.S (__fminl): Likewise. + * sysdeps/x86_64/fpu/s_fmax.S (__fmax): Likewise. + * sysdeps/x86_64/fpu/s_fmaxf.S (__fmaxf): Likewise. + * sysdeps/x86_64/fpu/s_fmaxl.S (__fmaxl): Likewise. + * sysdeps/x86_64/fpu/s_fmin.S (__fmin): Likewise. + * sysdeps/x86_64/fpu/s_fminf.S (__fminf): Likewise. + * sysdeps/x86_64/fpu/s_fminl.S (__fminl): Likewise. + * math/libm-test.inc (fmax_test_data): Add tests of sNaN inputs. + (fmin_test_data): Likewise. + 2016-12-15 Andreas Schwab * support/support_test_main.c (support_test_main): Don't shadow diff --git a/math/libm-test.inc b/math/libm-test.inc index e973a3f6ae..110b4215d5 100644 --- a/math/libm-test.inc +++ b/math/libm-test.inc @@ -7799,6 +7799,14 @@ static const struct test_ff_f_data fmax_test_data[] = TEST_ff_f (fmax, 9, -qnan_value, 9, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_ff_f (fmax, -9, qnan_value, -9, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_ff_f (fmax, -9, -qnan_value, -9, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_ff_f (fmax, 0, snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmax, 0, -snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmax, minus_zero, snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmax, minus_zero, -snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmax, 9, snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmax, 9, -snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmax, -9, snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmax, -9, -snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), TEST_ff_f (fmax, qnan_value, 0, 0, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_ff_f (fmax, -qnan_value, 0, 0, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_ff_f (fmax, qnan_value, minus_zero, minus_zero, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), @@ -7807,18 +7815,46 @@ static const struct test_ff_f_data fmax_test_data[] = TEST_ff_f (fmax, -qnan_value, 9, 9, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_ff_f (fmax, qnan_value, -9, -9, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_ff_f (fmax, -qnan_value, -9, -9, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_ff_f (fmax, snan_value, 0, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmax, -snan_value, 0, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmax, snan_value, minus_zero, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmax, -snan_value, minus_zero, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmax, snan_value, 9, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmax, -snan_value, 9, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmax, snan_value, -9, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmax, -snan_value, -9, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), TEST_ff_f (fmax, plus_infty, qnan_value, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_ff_f (fmax, plus_infty, -qnan_value, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_ff_f (fmax, minus_infty, qnan_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_ff_f (fmax, minus_infty, -qnan_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_ff_f (fmax, plus_infty, snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmax, plus_infty, -snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmax, minus_infty, snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmax, minus_infty, -snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), TEST_ff_f (fmax, qnan_value, plus_infty, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_ff_f (fmax, -qnan_value, plus_infty, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_ff_f (fmax, qnan_value, minus_infty, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_ff_f (fmax, -qnan_value, minus_infty, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_ff_f (fmax, snan_value, plus_infty, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmax, -snan_value, plus_infty, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmax, snan_value, minus_infty, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmax, -snan_value, minus_infty, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), TEST_ff_f (fmax, qnan_value, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_ff_f (fmax, qnan_value, -qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_ff_f (fmax, -qnan_value, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_ff_f (fmax, -qnan_value, -qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_ff_f (fmax, qnan_value, snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmax, qnan_value, -snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmax, -qnan_value, snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmax, -qnan_value, -snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmax, snan_value, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmax, snan_value, -qnan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmax, -snan_value, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmax, -snan_value, -qnan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmax, snan_value, snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmax, snan_value, -snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmax, -snan_value, snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmax, -snan_value, -snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), }; static void @@ -7862,6 +7898,14 @@ static const struct test_ff_f_data fmin_test_data[] = TEST_ff_f (fmin, 9, -qnan_value, 9, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_ff_f (fmin, -9, qnan_value, -9, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_ff_f (fmin, -9, -qnan_value, -9, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_ff_f (fmin, 0, snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmin, 0, -snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmin, minus_zero, snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmin, minus_zero, -snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmin, 9, snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmin, 9, -snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmin, -9, snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmin, -9, -snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), TEST_ff_f (fmin, qnan_value, 0, 0, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_ff_f (fmin, -qnan_value, 0, 0, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_ff_f (fmin, qnan_value, minus_zero, minus_zero, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), @@ -7870,18 +7914,46 @@ static const struct test_ff_f_data fmin_test_data[] = TEST_ff_f (fmin, -qnan_value, 9, 9, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_ff_f (fmin, qnan_value, -9, -9, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_ff_f (fmin, -qnan_value, -9, -9, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_ff_f (fmin, snan_value, 0, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmin, -snan_value, 0, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmin, snan_value, minus_zero, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmin, -snan_value, minus_zero, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmin, snan_value, 9, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmin, -snan_value, 9, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmin, snan_value, -9, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmin, -snan_value, -9, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), TEST_ff_f (fmin, plus_infty, qnan_value, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_ff_f (fmin, plus_infty, -qnan_value, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_ff_f (fmin, minus_infty, qnan_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_ff_f (fmin, minus_infty, -qnan_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_ff_f (fmin, plus_infty, snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmin, plus_infty, -snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmin, minus_infty, snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmin, minus_infty, -snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), TEST_ff_f (fmin, qnan_value, plus_infty, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_ff_f (fmin, -qnan_value, plus_infty, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_ff_f (fmin, qnan_value, minus_infty, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_ff_f (fmin, -qnan_value, minus_infty, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_ff_f (fmin, snan_value, plus_infty, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmin, -snan_value, plus_infty, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmin, snan_value, minus_infty, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmin, -snan_value, minus_infty, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), TEST_ff_f (fmin, qnan_value, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_ff_f (fmin, qnan_value, -qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_ff_f (fmin, -qnan_value, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_ff_f (fmin, -qnan_value, -qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_ff_f (fmin, qnan_value, snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmin, qnan_value, -snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmin, -qnan_value, snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmin, -qnan_value, -snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmin, snan_value, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmin, snan_value, -qnan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmin, -snan_value, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmin, -snan_value, -qnan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmin, snan_value, snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmin, snan_value, -snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmin, -snan_value, snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), + TEST_ff_f (fmin, -snan_value, -snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION), }; static void diff --git a/sysdeps/i386/fpu/s_fmaxl.S b/sysdeps/i386/fpu/s_fmaxl.S index a38a1946bc..a30401a4db 100644 --- a/sysdeps/i386/fpu/s_fmaxl.S +++ b/sysdeps/i386/fpu/s_fmaxl.S @@ -28,7 +28,13 @@ ENTRY(__fmaxl) andb $0x45, %ah cmpb $0x01, %ah - je 1f // y == NaN + je 2f // y == NaN + + fxam + fnstsw + andb $0x45, %ah + cmpb $0x01, %ah + je 3f // x == NaN fucom %st(1) fnstsw @@ -39,5 +45,27 @@ ENTRY(__fmaxl) 1: fstp %st(1) ret + +2: // st(1) is a NaN; st(0) may or may not be. + fxam + fnstsw + andb $0x45, %ah + cmpb $0x01, %ah + je 4f + // st(1) is a NaN; st(0) is not. Test if st(1) is signaling. + testb $0x40, 23(%esp) + jz 4f + fstp %st(1) + ret + +3: // st(0) is a NaN; st(1) is not. Test if st(0) is signaling. + testb $0x40, 11(%esp) + jz 4f + fstp %st(0) + ret + +4: // Both arguments are NaNs, or one is a signaling NaN. + faddp + ret END(__fmaxl) weak_alias (__fmaxl, fmaxl) diff --git a/sysdeps/i386/fpu/s_fminl.S b/sysdeps/i386/fpu/s_fminl.S index fb5169b8f2..a617e460dc 100644 --- a/sysdeps/i386/fpu/s_fminl.S +++ b/sysdeps/i386/fpu/s_fminl.S @@ -21,23 +21,51 @@ .text ENTRY(__fminl) - fldt 4(%esp) // x - fldt 16(%esp) // x : y + fldt 16(%esp) // y + fxam + fnstsw + fldt 4(%esp) // y : x + + andb $0x45, %ah + cmpb $0x01, %ah + je 2f // y == NaN fxam fnstsw andb $0x45, %ah cmpb $0x01, %ah - je 1f // y == NaN + je 3f // x == NaN fucom %st(1) fnstsw sahf - jc 2f + jc 1f -1: fxch %st(1) -2: fstp %st(1) + fxch %st(1) +1: fstp %st(1) ret + +2: // st(1) is a NaN; st(0) may or may not be. + fxam + fnstsw + andb $0x45, %ah + cmpb $0x01, %ah + je 4f + // st(1) is a NaN; st(0) is not. Test if st(1) is signaling. + testb $0x40, 23(%esp) + jz 4f + fstp %st(1) + ret + +3: // st(0) is a NaN; st(1) is not. Test if st(0) is signaling. + testb $0x40, 11(%esp) + jz 4f + fstp %st(0) + ret + +4: // Both arguments are NaNs, or one is a signaling NaN. + faddp + ret END(__fminl) weak_alias (__fminl, fminl) diff --git a/sysdeps/i386/i686/fpu/s_fmaxl.S b/sysdeps/i386/i686/fpu/s_fmaxl.S index e5dcd26923..5bade5b5e4 100644 --- a/sysdeps/i386/i686/fpu/s_fmaxl.S +++ b/sysdeps/i386/i686/fpu/s_fmaxl.S @@ -24,16 +24,35 @@ ENTRY(__fmaxl) fldt 4(%esp) // x fldt 16(%esp) // x : y - fucomi %st(0), %st - fcmovu %st(1), %st // now %st contains y if not NaN, x otherwise - - fxch - fucomi %st(1), %st + jp 2f fcmovb %st(1), %st fstp %st(1) ret + +2: // Unordered. + fucomi %st(0), %st + jp 3f + // st(1) is a NaN; st(0) is not. Test if st(1) is signaling. + testb $0x40, 11(%esp) + jz 4f + fstp %st(1) + ret + +3: // st(0) is a NaN; st(1) may or may not be. + fxch + fucomi %st(0), %st + jp 4f + // st(1) is a NaN; st(0) is not. Test if st(1) is signaling. + testb $0x40, 23(%esp) + jz 4f + fstp %st(1) + ret + +4: // Both arguments are NaNs, or one is a signaling NaN. + faddp + ret END(__fmaxl) weak_alias (__fmaxl, fmaxl) diff --git a/sysdeps/i386/i686/fpu/s_fminl.S b/sysdeps/i386/i686/fpu/s_fminl.S index ddbd81115e..d586f52b79 100644 --- a/sysdeps/i386/i686/fpu/s_fminl.S +++ b/sysdeps/i386/i686/fpu/s_fminl.S @@ -24,14 +24,35 @@ ENTRY(__fminl) fldt 4(%esp) // x fldt 16(%esp) // x : y - fucomi %st(0), %st - fcmovu %st(1), %st // now %st contains y if not NaN, x otherwise - fucomi %st(1), %st + jp 2f fcmovnb %st(1), %st fstp %st(1) ret + +2: // Unordered. + fucomi %st(0), %st + jp 3f + // st(1) is a NaN; st(0) is not. Test if st(1) is signaling. + testb $0x40, 11(%esp) + jz 4f + fstp %st(1) + ret + +3: // st(0) is a NaN; st(1) may or may not be. + fxch + fucomi %st(0), %st + jp 4f + // st(1) is a NaN; st(0) is not. Test if st(1) is signaling. + testb $0x40, 23(%esp) + jz 4f + fstp %st(1) + ret + +4: // Both arguments are NaNs, or one is a signaling NaN. + faddp + ret END(__fminl) weak_alias (__fminl, fminl) diff --git a/sysdeps/x86_64/fpu/s_fmax.S b/sysdeps/x86_64/fpu/s_fmax.S index 02096c0aea..0ff326fb66 100644 --- a/sysdeps/x86_64/fpu/s_fmax.S +++ b/sysdeps/x86_64/fpu/s_fmax.S @@ -27,8 +27,25 @@ ENTRY(__fmax) jmp 2f 1: ucomisd %xmm1, %xmm1 // Is xmm1 a NaN? - jp 2f // then return xmm0 + jp 3f + // xmm0 is a NaN; xmm1 is not. Test if xmm0 is signaling. + movsd %xmm0, -8(%rsp) + testb $0x8, -2(%rsp) + jz 4f movsd %xmm1, %xmm0 // otherwise return xmm1 + ret + +3: // xmm1 is a NaN; xmm0 may or may not be. + ucomisd %xmm0, %xmm0 + jp 4f + // xmm1 is a NaN; xmm0 is not. Test if xmm1 is signaling. + movsd %xmm1, -8(%rsp) + testb $0x8, -2(%rsp) + jz 4f + ret + +4: // Both arguments are NaNs, or one is a signaling NaN. + addsd %xmm1, %xmm0 2: ret END(__fmax) diff --git a/sysdeps/x86_64/fpu/s_fmaxf.S b/sysdeps/x86_64/fpu/s_fmaxf.S index 28e129701e..0f36ee084c 100644 --- a/sysdeps/x86_64/fpu/s_fmaxf.S +++ b/sysdeps/x86_64/fpu/s_fmaxf.S @@ -27,8 +27,25 @@ ENTRY(__fmaxf) jmp 2f 1: ucomiss %xmm1, %xmm1 // Is xmm1 a NaN? - jp 2f // then return xmm0 + jp 3f + // xmm0 is a NaN; xmm1 is not. Test if xmm0 is signaling. + movss %xmm0, -4(%rsp) + testb $0x40, -2(%rsp) + jz 4f movss %xmm1, %xmm0 // otherwise return xmm1 + ret + +3: // xmm1 is a NaN; xmm0 may or may not be. + ucomiss %xmm0, %xmm0 + jp 4f + // xmm1 is a NaN; xmm0 is not. Test if xmm1 is signaling. + movss %xmm1, -4(%rsp) + testb $0x40, -2(%rsp) + jz 4f + ret + +4: // Both arguments are NaNs, or one is a signaling NaN. + addss %xmm1, %xmm0 2: ret END(__fmaxf) diff --git a/sysdeps/x86_64/fpu/s_fmaxl.S b/sysdeps/x86_64/fpu/s_fmaxl.S index f0c2bc0d56..5f0b1e0860 100644 --- a/sysdeps/x86_64/fpu/s_fmaxl.S +++ b/sysdeps/x86_64/fpu/s_fmaxl.S @@ -24,16 +24,35 @@ ENTRY(__fmaxl) fldt 8(%rsp) // x fldt 24(%rsp) // x : y - fucomi %st(0), %st - fcmovu %st(1), %st // now %st contains y if not NaN, x otherwise - - fxch - fucomi %st(1), %st + jp 2f fcmovb %st(1), %st fstp %st(1) ret + +2: // Unordered. + fucomi %st(0), %st + jp 3f + // st(1) is a NaN; st(0) is not. Test if st(1) is signaling. + testb $0x40, 15(%rsp) + jz 4f + fstp %st(1) + ret + +3: // st(0) is a NaN; st(1) may or may not be. + fxch + fucomi %st(0), %st + jp 4f + // st(1) is a NaN; st(0) is not. Test if st(1) is signaling. + testb $0x40, 31(%rsp) + jz 4f + fstp %st(1) + ret + +4: // Both arguments are NaNs, or one is a signaling NaN. + faddp + ret END(__fmaxl) weak_alias (__fmaxl, fmaxl) diff --git a/sysdeps/x86_64/fpu/s_fmin.S b/sysdeps/x86_64/fpu/s_fmin.S index fb14e2f3ed..db89befb6b 100644 --- a/sysdeps/x86_64/fpu/s_fmin.S +++ b/sysdeps/x86_64/fpu/s_fmin.S @@ -27,8 +27,25 @@ ENTRY(__fmin) jmp 2f 1: ucomisd %xmm1, %xmm1 // Is xmm1 a NaN? - jp 2f // then return xmm0 + jp 3f + // xmm0 is a NaN; xmm1 is not. Test if xmm0 is signaling. + movsd %xmm0, -8(%rsp) + testb $0x8, -2(%rsp) + jz 4f movsd %xmm1, %xmm0 // otherwise return xmm1 + ret + +3: // xmm1 is a NaN; xmm0 may or may not be. + ucomisd %xmm0, %xmm0 + jp 4f + // xmm1 is a NaN; xmm0 is not. Test if xmm1 is signaling. + movsd %xmm1, -8(%rsp) + testb $0x8, -2(%rsp) + jz 4f + ret + +4: // Both arguments are NaNs, or one is a signaling NaN. + addsd %xmm1, %xmm0 2: ret END(__fmin) diff --git a/sysdeps/x86_64/fpu/s_fminf.S b/sysdeps/x86_64/fpu/s_fminf.S index c8d6d0fd33..41a99787d3 100644 --- a/sysdeps/x86_64/fpu/s_fminf.S +++ b/sysdeps/x86_64/fpu/s_fminf.S @@ -27,8 +27,25 @@ ENTRY(__fminf) jmp 2f 1: ucomiss %xmm1, %xmm1 // Is xmm1 a NaN? - jp 2f // then return xmm0 + jp 3f + // xmm0 is a NaN; xmm1 is not. Test if xmm0 is signaling. + movss %xmm0, -4(%rsp) + testb $0x40, -2(%rsp) + jz 4f movss %xmm1, %xmm0 // otherwise return xmm1 + ret + +3: // xmm1 is a NaN; xmm0 may or may not be. + ucomiss %xmm0, %xmm0 + jp 4f + // xmm1 is a NaN; xmm0 is not. Test if xmm1 is signaling. + movss %xmm1, -4(%rsp) + testb $0x40, -2(%rsp) + jz 4f + ret + +4: // Both arguments are NaNs, or one is a signaling NaN. + addss %xmm1, %xmm0 2: ret END(__fminf) diff --git a/sysdeps/x86_64/fpu/s_fminl.S b/sysdeps/x86_64/fpu/s_fminl.S index f1a06d29d7..12fc3fb06c 100644 --- a/sysdeps/x86_64/fpu/s_fminl.S +++ b/sysdeps/x86_64/fpu/s_fminl.S @@ -24,14 +24,35 @@ ENTRY(__fminl) fldt 8(%rsp) // x fldt 24(%rsp) // x : y - fucomi %st(0), %st - fcmovu %st(1), %st // now %st contains y if not NaN, x otherwise - fucomi %st(1), %st + jp 2f fcmovnb %st(1), %st fstp %st(1) ret + +2: // Unordered. + fucomi %st(0), %st + jp 3f + // st(1) is a NaN; st(0) is not. Test if st(1) is signaling. + testb $0x40, 15(%rsp) + jz 4f + fstp %st(1) + ret + +3: // st(0) is a NaN; st(1) may or may not be. + fxch + fucomi %st(0), %st + jp 4f + // st(1) is a NaN; st(0) is not. Test if st(1) is signaling. + testb $0x40, 31(%rsp) + jz 4f + fstp %st(1) + ret + +4: // Both arguments are NaNs, or one is a signaling NaN. + faddp + ret END(__fminl) weak_alias (__fminl, fminl)