]> sourceware.org Git - glibc.git/commitdiff
Fix x86, x86_64 fmax, fmin sNaN handling, add tests (bug 20947).
authorJoseph Myers <joseph@codesourcery.com>
Thu, 15 Dec 2016 23:52:18 +0000 (23:52 +0000)
committerJoseph Myers <joseph@codesourcery.com>
Thu, 15 Dec 2016 23:52:18 +0000 (23:52 +0000)
Various fmax and fmin function implementations mishandle sNaN
arguments:

(a) When both arguments are NaNs, the return value should be a qNaN,
but sometimes it is an sNaN if at least one argument is an sNaN.

(b) Under TS 18661-1 semantics, if either argument is an sNaN then the
result should be a qNaN (whereas if one argument is a qNaN and the
other is not a NaN, the result should be the non-NaN argument).
Various implementations treat sNaNs like qNaNs here.

This patch fixes the x86 and x86_64 versions (ignoring float and
double for 32-bit x86 given the inability to reliably avoid the sNaN
turning into a qNaN before it gets to the called function).  Tests of
sNaN inputs to these functions are added.

Note on architecture versions I haven't changed for this issue:
AArch64 already gets this right (it uses a hardware instruction with
the correct semantics for both quiet and signaling NaNs) and does not
need changes.  It's possible Alpha, IA64, SPARC might need changes
(this would be shown by the testsuite if so).

Tested for x86_64 and x86 (both i686 and i586 builds, to cover the
different x86 implementations).

[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.

12 files changed:
ChangeLog
math/libm-test.inc
sysdeps/i386/fpu/s_fmaxl.S
sysdeps/i386/fpu/s_fminl.S
sysdeps/i386/i686/fpu/s_fmaxl.S
sysdeps/i386/i686/fpu/s_fminl.S
sysdeps/x86_64/fpu/s_fmax.S
sysdeps/x86_64/fpu/s_fmaxf.S
sysdeps/x86_64/fpu/s_fmaxl.S
sysdeps/x86_64/fpu/s_fmin.S
sysdeps/x86_64/fpu/s_fminf.S
sysdeps/x86_64/fpu/s_fminl.S

index 523028da4a253a311c683fb81efb0abfe9f35865..3f7e5d6e2002e9b5d86693d425a2faaa12636f37 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,22 @@
+2016-12-15  Joseph Myers  <joseph@codesourcery.com>
+
+       [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  <schwab@suse.de>
 
        * support/support_test_main.c (support_test_main): Don't shadow
index e973a3f6aea6dd85b88a05037dab5ff0618e9f28..110b4215d5aa872ca0a26479c1200809c01dcc19 100644 (file)
@@ -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
index a38a1946bcb2601d1fe5fb20807773388a9450d6..a30401a4dba76a3666dd0499bc6097bdca830bd1 100644 (file)
@@ -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)
index fb5169b8f22e52f949bd52594de7f534f93baccb..a617e460dccfbc7450bca948a29efd3a8b009332 100644 (file)
 
        .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
+
+       fxch    %st(1)
+1:     fstp    %st(1)
+
+       ret
 
-1:     fxch    %st(1)
-2:     fstp    %st(1)
+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)
index e5dcd269230bb5010f7ffe14f4a7906eb3297a5d..5bade5b5e4bff460d4dc5692e951f000d6a8992e 100644 (file)
@@ -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)
index ddbd81115e0d4185fadb7284fb4d221113d06150..d586f52b79cf59c1fe4062fee2370dd1f0b98a44 100644 (file)
@@ -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)
index 02096c0aeaa2bedf1ce08caf38b91f2ada2288e1..0ff326fb662fd01a7cf99212c1c6f3e2ef3d5111 100644 (file)
@@ -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)
index 28e129701e5ae6de971d1e6b8a8f4f0b19bbb734..0f36ee084ceb025e607d5cf8c2f1f8ea3bbf5a86 100644 (file)
@@ -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)
index f0c2bc0d567c8fb81f788f2471c02d8cedb876b9..5f0b1e0860a74587809df9255a592c3ce6e89df1 100644 (file)
@@ -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)
index fb14e2f3ed2af7aedd960c68c53510ebac2ff926..db89befb6b7be935b38d714721f8a329ec2de76b 100644 (file)
@@ -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)
index c8d6d0fd33dfd821e5c0eb18a9c0b7e9f002c60f..41a99787d30210e7549bc8caca63aef27d51e077 100644 (file)
@@ -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)
index f1a06d29d76c924ec698c01bad2c81887a40cf04..12fc3fb06cae7e5eb2ac73161e377aefaf474fd9 100644 (file)
@@ -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)
This page took 0.72808 seconds and 5 git commands to generate.