[PATCH] Fix nextafterf

Jie Zhang jie.zhang at analog.com
Mon Feb 9 09:58:30 UTC 2009


Denys Vlasenko wrote:
> On Friday 06 February 2009 03:39, Jie Zhang wrote:
>>>> A patch is attached. This patch copies nextafterf from glibc. Tested on 
>>>> Blackfin with the above test case. If it's OK, please apply. Thanks.
>>> Why the patch touches libm/s_nextafter.c (the double version)?
>>> Your comment says nothing about it.
>>>
>> Sorry for not explain that.
>>
>> math_opt_barrier and math_force_eval were added in glibc to fix glibc bug:
>>
>> http://sources.redhat.com/bugzilla/show_bug.cgi?id=3306
>>
>> When I copied nextafterf, I noticed this. So I modified nextafter, too.
> 
> Ok, I took a look.
> 
> There is optimized version of them for i386 and x86_64.
> You didn't use that.
> 
I cannot find them in glibc CVS HEAD. Maybe you are referring to the 
long double versions of i386 and x86_64.

> Also, glibc didn't bother to explain what these macros do.
> I would like to do better than that, I want people
> to be able to hack on uclibc not in a "blind" mode.
> Code readability needs to be improved.
> 
Maybe glibc developers thought this piece of code is obvious.

> I added this:
> 
> /*
>  * math_opt_barrier(x): force expression x to be evaluated and put into
>  * a floating point register or memory. This macro returns the value.
>  *
>  * math_force_eval(x): force expression x to be evaluated and put into
>  * a floating point register or memory *of the appropriate size*.
>  * This forces floating point flags to be set correctly
>  * (for example, when float value is overflowing, but FPU registers
>  * are wide enough to "hide" this).
>  */
> 
> Is it correct?
> 
Not completely.

math_opt_barrier(x) prevents compiler doing optimization across it.

math_force_eval(x) prevents compiler optimizing away calculation of x.

> 
> Now, let's see how they are used in nextafterf.
> 
>         if (ix == 0) { /* x == 0? */
>                 float u;
>                 /* return +-minsubnormal */
>                 SET_FLOAT_WORD(x, (hy & 0x80000000) | 1);
>                 u = math_opt_barrier(x);
>                 u = u * u;
>                 math_force_eval(u); /* raise underflow flag */
>                 return x;
> 
> Ok, we constructed smallest possible subnormal in x.
> Why do we load it through math_opt_barrier()?

As stated above, prevent compiler doing optimization.

> Why we multiply it by itself?

To raise the underflow flag.

> Can't we just math_force_eval(x)?

This will not work.

> which tells me that  /* raise underflow flag */ comment
> is on the wrong line! _multiplication_ is the operation which sets
> underflow flag, FST instruction never sets it (I just checked
> the manual). In all cases, FST instruction generated here
> is useless, it does no useful work whatsoever.
> 
It's not in the wrong line completely. Without math_force_eval, the 
underflow fag might not be set because of compiler optimization. You may 
like comments as below

     u = math_opt_barrier(x); /* don't optimize across this */
     u = u * u;               /* raise underflow flag */
     math_force_eval(u);      /* force evaluation of the above expr */

But doesn't this looks a little wordy?
> 
>>> You also did not remove the wrapper from float_wrappers.c
>>>
>> I indeed removed it in my patch.
> 
> Ah, now I see. sorry.
> 
No problem.

> 
>>> I think math_opt_barrier macro should be either eliminated
>>> or moved to its sole user, libm/s_nextafterf.c
>>>
>> nextafter also needs them. But if uClibc does not care of the spec on 
>> this corner, they can be removed from both.
> 
> Btw, can you give an example C code which demonstrates
> how math_opt_barrier() and math_force_eval() are resulting
> in correct implemetation. So far it sounds somewhat nebulous.
> 
I attached a test case in this email, which is adapted from the test case in

http://sources.redhat.com/bugzilla/show_bug.cgi?id=3306

Put all three files in the same directory.

$ gcc -o test test.c -O2 -lm -DMATH_OPT_BARRIER -DMATH_FORCE_EVAL
$ ./test
fetestexcept: 30
FE_UNDERFLOW: 10
FE_INEXACT: 20

Drop -DMATH_OPT_BARRIER or -DMATH_FORCE_EVAL or all of them will get us:

$ ./test
fetestexcept: 0
FE_UNDERFLOW: 10
FE_INEXACT: 20

> IOW: do you have a testcase which checks that nextafter[f]
> sets these exception flags and whatnot?

I think the test code in

http://sources.redhat.com/bugzilla/show_bug.cgi?id=3306

is a good one.


Regards,
Jie


More information about the uClibc mailing list