[PATCH 3/4] Use libc_fe* macros in ldbl-128/e_expl.c.
Adhemerval Zanella
adhemerval.zanella@linaro.org
Mon Mar 30 18:12:47 GMT 2020
On 27/03/2020 11:23, Stefan Liebler via Libc-alpha wrote:
> 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.
I will send a RFC for this patch, we need to check with x86 maintainers
if this the desirable direction and if I got everything right.
>
> 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?
The float128 on gcc/x86_64 is implemented by soft-fp library in libgcc [1]
and its ABI passes arguments through SSE register [2].
[1] https://stackoverflow.com/questions/26639477/what-exactly-is-a-float128-if-im-using-gcc-4-9-on-x86-64
[2] https://github.com/hjl-tools/x86-psABI/wiki/X86-psABI
More information about the Libc-alpha
mailing list