]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
Fix x86_64/x86 powl handling of sNaN arguments (bug 20916).
authorJoseph Myers <joseph@codesourcery.com>
Tue, 6 Dec 2016 00:33:19 +0000 (00:33 +0000)
committerJoseph Myers <joseph@codesourcery.com>
Tue, 6 Dec 2016 00:33:19 +0000 (00:33 +0000)
The x86_64/x86 powl implementations mishandle sNaN arguments, both by
returning sNaN in some cases (instead of doing arithmetic on the
arguments to produce the result when NaN arguments result in NaN
results) and by treating sNaN the same as qNaN for arguments (1, sNaN)
and (sNaN, 0), contrary to TS 18661-1 which requires those cases to
return qNaN instead of 1.

This patch makes the x86_64/x86 powl implementations follow TS 18661-1
semantics for sNaN arguments; sNaN tests are also added for pow.
Given the problems with testing float and double sNaN arguments on
32-bit x86 (sNaN tests disabled because the compiler may convert
unnecessarily to a qNaN when passing arguments), no changes are made
to the powf and pow implementations there.

Tested for x86_64 and x86.

[BZ #20916]
* sysdeps/i386/fpu/e_powl.S (__ieee754_powl): Do not return 1 for
arguments (sNaN, 0) or (1, sNaN).  Do arithmetic on NaN arguments
to compute result.
* sysdeps/x86_64/fpu/e_powl.S (__ieee754_powl): Likewise.
* math/libm-test.inc (pow_test_data): Add tests of sNaN arguments.

ChangeLog
math/libm-test.inc
sysdeps/i386/fpu/e_powl.S
sysdeps/x86_64/fpu/e_powl.S

index 9c0aaa6e431452b69aeb077d5b073e565d3867e4..ab723ebfbb877847e2eafccd64c2802081e440ae 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2016-12-06  Joseph Myers  <joseph@codesourcery.com>
+
+       [BZ #20916]
+       * sysdeps/i386/fpu/e_powl.S (__ieee754_powl): Do not return 1 for
+       arguments (sNaN, 0) or (1, sNaN).  Do arithmetic on NaN arguments
+       to compute result.
+       * sysdeps/x86_64/fpu/e_powl.S (__ieee754_powl): Likewise.
+       * math/libm-test.inc (pow_test_data): Add tests of sNaN arguments.
+
 2016-12-05  Torvald Riegel  <triegel@redhat.com>
 
        * include/atomic.h (__atomic_check_size_ls): New.
index 85df9deb865ed521d71b87421498dfd63a36b781..9123dcfc48f904b574ad18c5f3742ee697bf6dc7 100644 (file)
@@ -11090,6 +11090,10 @@ static const struct test_ff_f_data pow_test_data[] =
     TEST_ff_f (pow, -qnan_value, 0, 1, ERRNO_UNCHANGED|NO_TEST_MATHVEC),
     TEST_ff_f (pow, qnan_value, minus_zero, 1, ERRNO_UNCHANGED|NO_TEST_MATHVEC),
     TEST_ff_f (pow, -qnan_value, minus_zero, 1, ERRNO_UNCHANGED|NO_TEST_MATHVEC),
+    TEST_ff_f (pow, snan_value, 0, qnan_value, INVALID_EXCEPTION|NO_TEST_MATHVEC),
+    TEST_ff_f (pow, -snan_value, 0, qnan_value, INVALID_EXCEPTION|NO_TEST_MATHVEC),
+    TEST_ff_f (pow, snan_value, minus_zero, qnan_value, INVALID_EXCEPTION|NO_TEST_MATHVEC),
+    TEST_ff_f (pow, -snan_value, minus_zero, qnan_value, INVALID_EXCEPTION|NO_TEST_MATHVEC),
 
     TEST_ff_f (pow, 1.1L, plus_infty, plus_infty, ERRNO_UNCHANGED|NO_TEST_INLINE),
     TEST_ff_f (pow, plus_infty, plus_infty, plus_infty, ERRNO_UNCHANGED|NO_TEST_INLINE),
@@ -11151,18 +11155,40 @@ static const struct test_ff_f_data pow_test_data[] =
     TEST_ff_f (pow, qnan_value, -qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
     TEST_ff_f (pow, -qnan_value, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
     TEST_ff_f (pow, -qnan_value, -qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_ff_f (pow, qnan_value, snan_value, qnan_value, INVALID_EXCEPTION),
+    TEST_ff_f (pow, qnan_value, -snan_value, qnan_value, INVALID_EXCEPTION),
+    TEST_ff_f (pow, -qnan_value, snan_value, qnan_value, INVALID_EXCEPTION),
+    TEST_ff_f (pow, -qnan_value, -snan_value, qnan_value, INVALID_EXCEPTION),
+    TEST_ff_f (pow, snan_value, qnan_value, qnan_value, INVALID_EXCEPTION),
+    TEST_ff_f (pow, snan_value, -qnan_value, qnan_value, INVALID_EXCEPTION),
+    TEST_ff_f (pow, -snan_value, qnan_value, qnan_value, INVALID_EXCEPTION),
+    TEST_ff_f (pow, -snan_value, -qnan_value, qnan_value, INVALID_EXCEPTION),
+    TEST_ff_f (pow, snan_value, snan_value, qnan_value, INVALID_EXCEPTION),
+    TEST_ff_f (pow, snan_value, -snan_value, qnan_value, INVALID_EXCEPTION),
+    TEST_ff_f (pow, -snan_value, snan_value, qnan_value, INVALID_EXCEPTION),
+    TEST_ff_f (pow, -snan_value, -snan_value, qnan_value, INVALID_EXCEPTION),
     TEST_ff_f (pow, 0, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
     TEST_ff_f (pow, 0, -qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_ff_f (pow, 0, snan_value, qnan_value, INVALID_EXCEPTION),
+    TEST_ff_f (pow, 0, -snan_value, qnan_value, INVALID_EXCEPTION),
     TEST_ff_f (pow, 1, qnan_value, 1, ERRNO_UNCHANGED),
     TEST_ff_f (pow, 1, -qnan_value, 1, ERRNO_UNCHANGED),
+    TEST_ff_f (pow, 1, snan_value, qnan_value, INVALID_EXCEPTION|NO_TEST_MATHVEC),
+    TEST_ff_f (pow, 1, -snan_value, qnan_value, INVALID_EXCEPTION|NO_TEST_MATHVEC),
     TEST_ff_f (pow, -1, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
     TEST_ff_f (pow, -1, -qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_ff_f (pow, -1, snan_value, qnan_value, INVALID_EXCEPTION),
+    TEST_ff_f (pow, -1, -snan_value, qnan_value, INVALID_EXCEPTION),
     TEST_ff_f (pow, qnan_value, 1, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
     TEST_ff_f (pow, -qnan_value, 1, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_ff_f (pow, snan_value, 1, qnan_value, INVALID_EXCEPTION),
+    TEST_ff_f (pow, -snan_value, 1, qnan_value, INVALID_EXCEPTION),
     TEST_ff_f (pow, qnan_value, -1, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
     TEST_ff_f (pow, -qnan_value, -1, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_ff_f (pow, snan_value, -1, qnan_value, INVALID_EXCEPTION),
+    TEST_ff_f (pow, -snan_value, -1, qnan_value, INVALID_EXCEPTION),
 
-    /* pow (x, qNaN) == qNaN.  */
+    /* pow (x, qNaN or sNaN) == qNaN.  */
     TEST_ff_f (pow, 3.0, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
     TEST_ff_f (pow, 3.0, -qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
     TEST_ff_f (pow, minus_zero, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
@@ -11173,6 +11199,16 @@ static const struct test_ff_f_data pow_test_data[] =
     TEST_ff_f (pow, -3.0, -qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
     TEST_ff_f (pow, minus_infty, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
     TEST_ff_f (pow, minus_infty, -qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_ff_f (pow, 3.0, snan_value, qnan_value, INVALID_EXCEPTION),
+    TEST_ff_f (pow, 3.0, -snan_value, qnan_value, INVALID_EXCEPTION),
+    TEST_ff_f (pow, minus_zero, snan_value, qnan_value, INVALID_EXCEPTION),
+    TEST_ff_f (pow, minus_zero, -snan_value, qnan_value, INVALID_EXCEPTION),
+    TEST_ff_f (pow, plus_infty, snan_value, qnan_value, INVALID_EXCEPTION),
+    TEST_ff_f (pow, plus_infty, -snan_value, qnan_value, INVALID_EXCEPTION),
+    TEST_ff_f (pow, -3.0, snan_value, qnan_value, INVALID_EXCEPTION),
+    TEST_ff_f (pow, -3.0, -snan_value, qnan_value, INVALID_EXCEPTION),
+    TEST_ff_f (pow, minus_infty, snan_value, qnan_value, INVALID_EXCEPTION),
+    TEST_ff_f (pow, minus_infty, -snan_value, qnan_value, INVALID_EXCEPTION),
 
     TEST_ff_f (pow, qnan_value, 3.0, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
     TEST_ff_f (pow, -qnan_value, 3.0, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
@@ -11190,6 +11226,22 @@ static const struct test_ff_f_data pow_test_data[] =
     TEST_ff_f (pow, -qnan_value, min_subnorm_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
     TEST_ff_f (pow, qnan_value, -min_subnorm_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
     TEST_ff_f (pow, -qnan_value, -min_subnorm_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_ff_f (pow, snan_value, 3.0, qnan_value, INVALID_EXCEPTION),
+    TEST_ff_f (pow, -snan_value, 3.0, qnan_value, INVALID_EXCEPTION),
+    TEST_ff_f (pow, snan_value, -3.0, qnan_value, INVALID_EXCEPTION),
+    TEST_ff_f (pow, -snan_value, -3.0, qnan_value, INVALID_EXCEPTION),
+    TEST_ff_f (pow, snan_value, plus_infty, qnan_value, INVALID_EXCEPTION),
+    TEST_ff_f (pow, -snan_value, plus_infty, qnan_value, INVALID_EXCEPTION),
+    TEST_ff_f (pow, snan_value, minus_infty, qnan_value, INVALID_EXCEPTION),
+    TEST_ff_f (pow, -snan_value, minus_infty, qnan_value, INVALID_EXCEPTION),
+    TEST_ff_f (pow, snan_value, 2.5, qnan_value, INVALID_EXCEPTION),
+    TEST_ff_f (pow, -snan_value, 2.5, qnan_value, INVALID_EXCEPTION),
+    TEST_ff_f (pow, snan_value, -2.5, qnan_value, INVALID_EXCEPTION),
+    TEST_ff_f (pow, -snan_value, -2.5, qnan_value, INVALID_EXCEPTION),
+    TEST_ff_f (pow, snan_value, min_subnorm_value, qnan_value, INVALID_EXCEPTION),
+    TEST_ff_f (pow, -snan_value, min_subnorm_value, qnan_value, INVALID_EXCEPTION),
+    TEST_ff_f (pow, snan_value, -min_subnorm_value, qnan_value, INVALID_EXCEPTION),
+    TEST_ff_f (pow, -snan_value, -min_subnorm_value, qnan_value, INVALID_EXCEPTION),
 
     TEST_ff_f (pow, 1, plus_infty, 1, ERRNO_UNCHANGED),
     TEST_ff_f (pow, -1, plus_infty, 1, ERRNO_UNCHANGED),
index 923ee372227404ede3fdbe473e79003e0e1e76e2..57b80beb645fd34baf5c18afb83e442159366175 100644 (file)
@@ -201,15 +201,21 @@ ENTRY(__ieee754_powl)
        fucomp  %st(1)          // x : y
        fnstsw
        sahf
-       je      31f
-       fxch                    // y : x
-31:    fstp    %st(1)
+       je      33f
+31:    /* At least one argument NaN, and result should be NaN.  */
+       faddp
+       ret
+33:    jp      31b
+       /* pow (1, NaN); check if the NaN signaling.  */
+       testb   $0x40, 23(%esp)
+       jz      31b
+       fstp    %st(1)
        ret
 
        cfi_adjust_cfa_offset (8)
 32:    addl    $8, %esp
        cfi_adjust_cfa_offset (-8)
-       fstp    %st(1)
+       faddp
        ret
 
        cfi_adjust_cfa_offset (8)
@@ -241,12 +247,24 @@ ENTRY(__ieee754_powl)
        cfi_adjust_cfa_offset (-36)
        ret
 
-       // pow(x,±0) = 1
+       // pow(x,±0) = 1, unless x is sNaN
        .align ALIGNARG(4)
 11:    fstp    %st(0)          // pop y
+       fldt    4(%esp)         // x
+       fxam
+       fnstsw
+       andb    $0x45, %ah
+       cmpb    $0x01, %ah
+       je      112f            // x is NaN
+111:   fstp    %st(0)
        fldl    MO(one)
        ret
 
+112:   testb   $0x40, 11(%esp)
+       jnz     111b
+       fadd    %st(0)
+       ret
+
        // y == ±inf
        .align ALIGNARG(4)
 12:    fstp    %st(0)          // pop y
@@ -274,6 +292,7 @@ ENTRY(__ieee754_powl)
 
        .align ALIGNARG(4)
 13:    fldt    4(%esp)         // load x == NaN
+       fadd    %st(0)
        ret
 
        cfi_adjust_cfa_offset (8)
index 4a7f3a18d38bead23c8d09e96e9199d9fcf0b228..2b36077a3290f19a23aea1302ead3ca270d1dee1 100644 (file)
@@ -184,9 +184,15 @@ ENTRY(__ieee754_powl)
 30:    fldt    8(%rsp)         // x : y
        fldl    MO(one)         // 1.0 : x : y
        fucomip %st(1),%st      // x : y
-       je      31f
-       fxch                    // y : x
-31:    fstp    %st(1)
+       je      32f
+31:    /* At least one argument NaN, and result should be NaN.  */
+       faddp
+       ret
+32:    jc      31b
+       /* pow (1, NaN); check if the NaN signaling.  */
+       testb   $0x40, 31(%rsp)
+       jz      31b
+       fstp    %st(1)
        ret
 
        .align ALIGNARG(4)
@@ -217,12 +223,24 @@ ENTRY(__ieee754_powl)
        cfi_adjust_cfa_offset (-40)
        ret
 
-       // pow(x,±0) = 1
+       // pow(x,±0) = 1, unless x is sNaN
        .align ALIGNARG(4)
 11:    fstp    %st(0)          // pop y
+       fldt    8(%rsp)         // x
+       fxam
+       fnstsw
+       andb    $0x45, %ah
+       cmpb    $0x01, %ah
+       je      112f            // x is NaN
+111:   fstp    %st(0)
        fldl    MO(one)
        ret
 
+112:   testb   $0x40, 15(%rsp)
+       jnz     111b
+       fadd    %st(0)
+       ret
+
        // y == ±inf
        .align ALIGNARG(4)
 12:    fstp    %st(0)          // pop y
@@ -255,6 +273,7 @@ ENTRY(__ieee754_powl)
 
        .align ALIGNARG(4)
 13:    fldt    8(%rsp)         // load x == NaN
+       fadd    %st(0)
        ret
 
        .align ALIGNARG(4)