[PATCH 3/4] Use libc_fe* macros in ldbl-128/e_expl.c.

Stefan Liebler stli@linux.ibm.com
Wed Mar 25 10:13:27 GMT 2020


Unfortunately, this patch is responsible for testfails on x86_64:

math/test-float128-exp.out:
Failure: exp (-0x1p-10000): Exception "Underflow" set
Failure: exp (-0x2p-16384): Exception "Underflow" set
...

math/test-float128-cexp.out:
Failure: Real part of: cexp (0x2p-16384 - 0x4p-1076 i): Exception 
"Underflow" set
Failure: Real part of: cexp (0x2p-16384 - 0x8p-152 i): Exception 
"Underflow" set
...

I've stepped through "expf128 (0x1p-10000)" in 
sysdeps/ieee754/float128/../ldbl-128/e_expl.c:
151: libc_feholdexcept_setroundl (&oldenv, FE_TONEAREST);    // before 
this patch: feholdexcept (&oldenv); fesetround (FE_TONEAREST);
199: x22 = x + x*x*(P1+x*(P2+x*(P3+x*(P4+x*(P5+x*P6)))));
203: libc_fesetenvl (&oldenv);    // before this patch: fesetenv (&oldenv);

During the evaluation of x22 the underflow exception occures while:
<__ieee754_expf128+920>  callq  0x7ffff7f2a7c0 <__multf3>
which calls __sfp_handle_exceptions():
ae8be:       40 f6 c7 10             test   $0x10,%dil
ae8c2:       74 0f                   je     ae8d3 
<__sfp_handle_exceptions+0x73>
ae8c4:       d9 74 24 d8             fnstenv -0x28(%rsp)
ae8c8:       66 83 4c 24 dc 10       orw    $0x10,-0x24(%rsp)
ae8ce:       d9 64 24 d8             fldenv -0x28(%rsp)
ae8d2:       9b                      fwait

According to sysdeps/x86/fpu/fenv_private.h:
#ifdef __x86_64__
# define libc_feholdexcept_setroundf128 libc_feholdexcept_setround_sse
# define libc_fesetenvf128	libc_fesetenv_sse
#else
# define libc_feholdexcept_setroundf128	default_libc_feholdexcept_setround
# define libc_fesetenvf128	default_libc_fesetenv
#endif

// On my machine:
# define STMXCSR "stmxcsr"
# define LDMXCSR "ldmxcsr"

static __always_inline void
libc_feholdexcept_setround_sse (fenv_t *e, int r)
{
   unsigned int mxcsr;
   asm (STMXCSR " %0" : "=m" (*&mxcsr));
   e->__mxcsr = mxcsr;
   mxcsr = ((mxcsr | 0x1f80) & ~0x603f) | (r << 3);
   asm volatile (LDMXCSR " %0" : : "m" (*&mxcsr));
}

Whereas the feholdexcept() function is using in
./sysdeps/x86_64/fpu/feholdexcpt.c:
int
__feholdexcept (fenv_t *envp)
{
   unsigned int mxcsr;

   /* Store the environment.  Recall that fnstenv has a side effect of
      masking all exceptions.  Then clear all exceptions.  */
   __asm__ ("fnstenv %0\n\t"
	   "stmxcsr %1\n\t"
	   "fnclex"
	   : "=m" (*envp), "=m" (envp->__mxcsr));

   /* Set the SSE MXCSR register.  */
   mxcsr = (envp->__mxcsr | 0x1f80) & ~0x3f;
   __asm__ ("ldmxcsr %0" : : "m" (*&mxcsr));

   return 0;
}

I assume that the underflow exception keeps active as the pair of 
fnstenv / fldenv is missing if libc_feholdexcept_setroundf128 / 
libc_fesetenvf128 is used instead of feholdexcept, fesetround and fesetenv.
As I'm not familiar with float128 on x86_64, can anybody please help?

Bye,
Stefan

On 3/25/20 11:06 AM, Stefan Liebler wrote:
> The calls to feholdexcept, fesetround and fesetenv are replaced
> by the libc_fe* macros.
> ---
>   sysdeps/ieee754/ldbl-128/e_expl.c | 8 +++++---
>   1 file changed, 5 insertions(+), 3 deletions(-)
> 
> diff --git a/sysdeps/ieee754/ldbl-128/e_expl.c b/sysdeps/ieee754/ldbl-128/e_expl.c
> index 37c1538c08..104ace1690 100644
> --- a/sysdeps/ieee754/ldbl-128/e_expl.c
> +++ b/sysdeps/ieee754/ldbl-128/e_expl.c
> @@ -66,6 +66,7 @@
>   #include <inttypes.h>
>   #include <math-barriers.h>
>   #include <math_private.h>
> +#include <fenv_private.h>
>   #include <math-underflow.h>
>   #include <stdlib.h>
>   #include "t_expl.h"
> @@ -146,9 +147,10 @@ __ieee754_expl (_Float128 x)
>         union ieee854_long_double ex2_u, scale_u;
>         fenv_t oldenv;
>   
> -      feholdexcept (&oldenv);
>   #ifdef FE_TONEAREST
> -      fesetround (FE_TONEAREST);
> +      libc_feholdexcept_setroundl (&oldenv, FE_TONEAREST);
> +#else
> +      libc_feholdexceptl (&oldenv);
>   #endif
>   
>         /* Calculate n.  */
> @@ -198,7 +200,7 @@ __ieee754_expl (_Float128 x)
>         math_force_eval (x22);
>   
>         /* Return result.  */
> -      fesetenv (&oldenv);
> +      libc_fesetenvl (&oldenv);
>   
>         result = x22 * ex2_u.d + ex2_u.d;
>   
> 



More information about the Libc-alpha mailing list