diff options
author | Joseph Myers <joseph@codesourcery.com> | 2012-11-28 13:40:54 +0000 |
---|---|---|
committer | Joseph Myers <joseph@codesourcery.com> | 2012-11-28 13:40:54 +0000 |
commit | 1bead169c32a3a688de863709b863207b7aafddd (patch) | |
tree | 7c3dcf66e7b4d92a9bcc5e3bb67f2cbbb19172f3 /sysdeps/i386/fpu/e_powl.S | |
parent | 0817d63dd1f8e165f8ef6590bf4feddf06705381 (diff) | |
download | glibc-1bead169c32a3a688de863709b863207b7aafddd.tar.gz glibc-1bead169c32a3a688de863709b863207b7aafddd.tar.xz glibc-1bead169c32a3a688de863709b863207b7aafddd.zip |
Fix powl inaccuracy for x86_64 and x86 (bug 13881).
Diffstat (limited to 'sysdeps/i386/fpu/e_powl.S')
-rw-r--r-- | sysdeps/i386/fpu/e_powl.S | 55 |
1 files changed, 25 insertions, 30 deletions
diff --git a/sysdeps/i386/fpu/e_powl.S b/sysdeps/i386/fpu/e_powl.S index ac4842cf63..7e297756ff 100644 --- a/sysdeps/i386/fpu/e_powl.S +++ b/sysdeps/i386/fpu/e_powl.S @@ -26,9 +26,9 @@ .type one,@object one: .double 1.0 ASM_SIZE_DIRECTIVE(one) - .type limit,@object -limit: .double 0.29 - ASM_SIZE_DIRECTIVE(limit) + .type p3,@object +p3: .byte 0, 0, 0, 0, 0, 0, 0x20, 0x40 + ASM_SIZE_DIRECTIVE(p3) .type p63,@object p63: .byte 0, 0, 0, 0, 0, 0, 0xe0, 0x43 ASM_SIZE_DIRECTIVE(p63) @@ -141,7 +141,15 @@ ENTRY(__ieee754_powl) fchs // -0x1p-79 : x jmp 3f -9: /* OK, we have an integer value for y. */ +9: /* OK, we have an integer value for y. Unless very small + (we use < 8), use the algorithm for real exponent to avoid + accumulation of errors. */ + fld %st // y : y : x + fabs // |y| : y : x + fcompl MO(p3) // y : x + fnstsw + sahf + jnc 2f popl %eax cfi_adjust_cfa_offset (-4) popl %edx @@ -182,7 +190,7 @@ ENTRY(__ieee754_powl) cfi_adjust_cfa_offset (8) .align ALIGNARG(4) -2: // y is a large integer (absolute value at least 1L<<63), but +2: // y is a large integer (absolute value at least 8), but // may be odd unless at least 1L<<64. So it may be necessary // to adjust the sign of a negative result afterwards. fxch // x : y @@ -205,34 +213,21 @@ ENTRY(__ieee754_powl) fchs // -(1L<<78) : |x| .align ALIGNARG(4) 3: /* y is a real number. */ - fxch // x : y - fldl MO(one) // 1.0 : x : y - fldl MO(limit) // 0.29 : 1.0 : x : y - fld %st(2) // x : 0.29 : 1.0 : x : y - fsub %st(2) // x-1 : 0.29 : 1.0 : x : y - fabs // |x-1| : 0.29 : 1.0 : x : y - fucompp // 1.0 : x : y - fnstsw - fxch // x : 1.0 : y - sahf - ja 7f - fsub %st(1) // x-1 : 1.0 : y - fyl2xp1 // log2(x) : y - jmp 8f - -7: fyl2x // log2(x) : y -8: fmul %st(1) // y*log2(x) : y - fst %st(1) // y*log2(x) : y*log2(x) - frndint // int(y*log2(x)) : y*log2(x) - fsubr %st, %st(1) // int(y*log2(x)) : fract(y*log2(x)) - fxch // fract(y*log2(x)) : int(y*log2(x)) - f2xm1 // 2^fract(y*log2(x))-1 : int(y*log2(x)) - faddl MO(one) // 2^fract(y*log2(x)) : int(y*log2(x)) - fscale // 2^fract(y*log2(x))*2^int(y*log2(x)) : int(y*log2(x)) - fstp %st(1) // 2^fract(y*log2(x))*2^int(y*log2(x)) + subl $28, %esp + cfi_adjust_cfa_offset (28) + fstpt 12(%esp) // x + fstpt (%esp) // <empty> + mov %edx, 24(%esp) + call HIDDEN_JUMPTARGET (__powl_helper) // <result> + mov 24(%esp), %edx + addl $28, %esp + cfi_adjust_cfa_offset (-28) testb $2, %dh jz 292f // x is negative. If y is an odd integer, negate the result. +#ifdef PIC + LOAD_PIC_REG (cx) +#endif fldt 24(%esp) // y : abs(result) fld %st // y : y : abs(result) fabs // |y| : y : abs(result) |