aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog19
-rw-r--r--math/libm-test.inc72
-rw-r--r--sysdeps/i386/fpu/s_fmaxl.S30
-rw-r--r--sysdeps/i386/fpu/s_fminl.S40
-rw-r--r--sysdeps/i386/i686/fpu/s_fmaxl.S29
-rw-r--r--sysdeps/i386/i686/fpu/s_fminl.S27
-rw-r--r--sysdeps/x86_64/fpu/s_fmax.S19
-rw-r--r--sysdeps/x86_64/fpu/s_fmaxf.S19
-rw-r--r--sysdeps/x86_64/fpu/s_fmaxl.S29
-rw-r--r--sysdeps/x86_64/fpu/s_fmin.S19
-rw-r--r--sysdeps/x86_64/fpu/s_fminf.S19
-rw-r--r--sysdeps/x86_64/fpu/s_fminl.S27
12 files changed, 322 insertions, 27 deletions
diff --git a/ChangeLog b/ChangeLog
index 523028da4a..3f7e5d6e20 100644
--- 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
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
+
+ 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)
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)