[PATCH 3/4] Use libc_fe* macros in ldbl-128/e_expl.c.
Stefan Liebler
stli@linux.ibm.com
Fri Mar 27 14:23:08 GMT 2020
On 3/26/20 3:53 PM, Adhemerval Zanella via Libc-alpha wrote:
>
>
> On 26/03/2020 06:08, Stefan Liebler via Libc-alpha wrote:
>> On 3/25/20 4:42 PM, Adhemerval Zanella via Libc-alpha wrote:
>>>
>>>
>>> On 25/03/2020 12:07, Adhemerval Zanella wrote:
>>>>
>>>>
>>>> On 25/03/2020 12:00, Adhemerval Zanella wrote:
>>>>>
>>>>>
>>>>> On 25/03/2020 07:13, Stefan Liebler via Libc-alpha wrote:
>>>>>> 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
>>>>>
>>>>> The sysdeps/x86/fpu/fenv_private.h states:
>>>>>
>>>>> 296 #ifdef __x86_64__
>>>>> 297 /* The SSE rounding mode is used by soft-fp (libgcc and glibc) on
>>>>> 298 x86_64, so that must be set for float128 computations. */
>>>>> 299 # define SET_RESTORE_ROUNDF128(RM) \
>>>>> 300 SET_RESTORE_ROUND_GENERIC (RM, libc_feholdsetround_sse, libc_feresetround_sse)
>>>>>
>>>>> So
>>>>>
>>>>>>> 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);
>>>>>
>>>>> Should be libc_feholdexcept_setroundf128.
>>>>
>>>> But it does not see to help here, so I don't know what is failing as well.
>>>
>>> Ok, so what is happening __sfp_handle_exceptions always use 387 exception
>>> mode for FP_EX_OVERFLOW and FP_EX_UNDERFLOW:
>>>
>>> config/i386/sfp-exceptions.c
>>>
>>> 79 if (_fex & FP_EX_OVERFLOW)
>>> 80 {
>>> 81 struct fenv temp;
>>> 82 asm volatile ("fnstenv\t%0" : "=m" (temp));
>>> 83 temp.__status_word |= FP_EX_OVERFLOW;
>>> 84 asm volatile ("fldenv\t%0" : : "m" (temp));
>>> 85 asm volatile ("fwait");
>>> 86 }
>>> 87 if (_fex & FP_EX_UNDERFLOW)
>>> 88 {
>>> 89 struct fenv temp;
>>> 90 asm volatile ("fnstenv\t%0" : "=m" (temp));
>>> 91 temp.__status_word |= FP_EX_UNDERFLOW;
>>> 92 asm volatile ("fldenv\t%0" : : "m" (temp));
>>> 93 asm volatile ("fwait");
>>> 94 }
>>> Yes this looks like the mentioned disassembly.
>>> Different that FP_EX_INEXACT, for instance, where __SSE_MATH__ sets
>>> whether SSE is used or not.
>>>
>>> So I think it is not safe to use the SSE variants for libc_*_testf128,
>>> as for i387 we should use the default_* instead.
>>>
>> I've just switched to default_* in sysdeps/x86/fpu/fenv_private.h:
>> -#ifdef __x86_64__
>> +#if 0
>> /* The SSE rounding mode is used by soft-fp (libgcc and glibc) on
>> x86_64, so that must be set for float128 computations. */
>> # define SET_RESTORE_ROUNDF128(RM) \
>>
>> But now there are 7 testfails. For some of them, the max.ulp goes up (over 10), but there are even worse cases. Here are shortened excerpts of the out files:
>> - math/test-float128-clog.out:
>> Failure: Test: Real part of: clog_towardzero (0x2.82b795e420b281a934c6dd315cb2p-4 + 0xf.cd42a15bf9a361243a89663e81e8p-4 i)
>> ulp : 162259276829213363391578010288127.0000
>> max.ulp : 3.0000
>> Failure: Test: Real part of: clog_upward (0x2.82b795e420b281a934c6dd315cb2p-4 + 0xf.cd42a15bf9a361243a89663e81e8p-4 i)
>> ulp : 162259276829213363391578010288128.0000
>> max.ulp : 4.0000
>>
>> - math/test-float128-clog10.out:
>> Failure: Test: Real part of: clog10_downward (0x3.bea2bd62e35p-4 + 0xf.8e3d619a8d11bfd30b038eep-4 i)
>> ulp : 4.0000
>> max.ulp : 3.0000
>> Failure: Test: Real part of: clog10_towardzero (0x2.82b795e420b281a934c6dd315cb2p-4 + 0xf.cd42a15bf9a361243a89663e81e8p-4 i)
>> ulp : 140936617129079063283494433422698.0000
>> max.ulp : 4.0000
>> Failure: Test: Real part of: clog10_upward (0x2.82b795e420b281a934c6dd315cb2p-4 + 0xf.cd42a15bf9a361243a89663e81e8p-4 i)
>> ulp : 140936617129079063283494433422698.0000
>> max.ulp : 4.0000
>>
>> - math/test-float128-jn.out
>> - math/test-float128-lgamma.out
>> - math/test-float128-tgamma.out:
>> something like:
>> ulp : 12.0000
>> max.ulp : 4.0000
>>
>> Failure: tgamma_upward (-0x6.ec00000000000008p+8): errno set to 0, expected 34 (ERANGE)
>>
>> - math/test-float128-y1.out:
>> Failure: Test: y1_downward (0x2p+0)
>> ulp : 13.0000
>> max.ulp : 4.0000
>> Failure: Test: y1_towardzero (0x2p+0)
>> ulp : 6.0000
>> max.ulp : 2.0000
>> Failure: Test: y1_upward (0x2p+0)
>> ulp : 10.0000
>> max.ulp : 5.0000
>>
>> - math/test-float128-yn.out
>>
>
> So it seems the issue is the mix on how libm fenv function, the internal
> libc_fe*, and libgcc handles the exception register. The exported fenv
> operates on both i387 and SSE (since it should work on long double as well),
> and the internal libc_fe* will set either SSE for float, double, and float128
> and i387 for long double (as expected).
>
> The libgcc, however, will set either SEE or i387 depending of the exception.
> This broke the assumption of libc_fe* for float128 where either SSE or i387
> will be used.
>
> One option might be to force libgcc to not use its __sfp_handle_exceptions
> on x86_64 and provide one that uses only SEE operations since libgcc does
> not use 'long double' on float128 operations. The patch below does it
> and applied on top your patches shows no regressions.
Great news. Thanks Adhemerval.
I've also successfully build and run the testsuite with your patch on
top of mine and with only your patch without mine.
As e.g. __multf3 or __addtf3 is used in various f128 functions, can you
please first commit your patch? Then I will add a reference to this
commit id in the commit-message.
One other question: Why are the soft-fp functions (for add / multiply)
called at all. Are the corresponding hardware instructions not available
on all x86_64 machines? Or do we miss a compiler flag?
>
> And I think we should fix libgcc in a similar manner, since checking on
> config/i386/64/sfp-machine.h it only support SSE rounding mode.
>
> --
>
> diff --git a/sysdeps/x86/fpu/sfp-exceptions.c b/sysdeps/x86/fpu/sfp-exceptions.c
> new file mode 100644
> index 0000000000..676f396bc3
> --- /dev/null
> +++ b/sysdeps/x86/fpu/sfp-exceptions.c
> @@ -0,0 +1,49 @@
> +#include <fenv.h>
> +#include <float.h>
> +#include <math-barriers.h>
> +
> +#define FP_EX_INVALID 0x01
> +#define FP_EX_DENORM 0x02
> +#define FP_EX_DIVZERO 0x04
> +#define FP_EX_OVERFLOW 0x08
> +#define FP_EX_UNDERFLOW 0x10
> +#define FP_EX_INEXACT 0x20
> +#define FP_EX_ALL \
> + (FP_EX_INVALID | FP_EX_DENORM | FP_EX_DIVZERO | FP_EX_OVERFLOW \
> + | FP_EX_UNDERFLOW | FP_EX_INEXACT)
> +
> +void
> +__sfp_handle_exceptions (int _fex)
> +{
> + if (_fex & FP_EX_INVALID)
> + {
> + float f = 0.0f;
> + math_force_eval (f / f);
> + }
> + if (_fex & FP_EX_DENORM)
> + {
> + float f = FLT_MIN, g = 2.0f;
> + math_force_eval (f / g);
> + }
> + if (_fex & FP_EX_DIVZERO)
> + {
> + float f = 1.0f, g = 0.0f;
> + math_force_eval (f / g);
> + }
> + if (_fex & FP_EX_OVERFLOW)
> + {
> + float force_underflow = FLT_MAX * FLT_MAX;
> + math_force_eval (force_underflow);
> + }
> + if (_fex & FP_EX_UNDERFLOW)
> + {
> + float force_overflow = FLT_MIN * FLT_MIN;
> + math_force_eval (force_overflow);
> + }
> + if (_fex & FP_EX_INEXACT)
> + {
> + float f = 1.0f, g = 3.0f;
> + math_force_eval (f / g);
> + }
> +}
> +strong_alias (__sfp_handle_exceptions, __wrap___sfp_handle_exceptions)
> diff --git a/sysdeps/x86_64/fpu/Makefile b/sysdeps/x86_64/fpu/Makefile
> index a4ff2723a8..5becb96fa3 100644
> --- a/sysdeps/x86_64/fpu/Makefile
> +++ b/sysdeps/x86_64/fpu/Makefile
> @@ -25,6 +25,9 @@ endif
>
> # Variables for libmvec tests.
> ifeq ($(subdir),math)
> +libm-routines += sfp-exceptions
> +LDFLAGS-m.so += -Wl,--wrap=__sfp_handle_exceptions
> +
> ifeq ($(build-mathvec),yes)
> libmvec-tests += double-vlen2 double-vlen4 double-vlen4-avx2 \
> float-vlen4 float-vlen8 float-vlen8-avx2
>
More information about the Libc-alpha
mailing list