Re: clang gets numerical underflow wrong, please fix.

2016-03-14 Thread Steve Kargl
On Mon, Mar 14, 2016 at 08:23:33PM +0100, Dimitry Andric wrote:
> 
> Maybe this is a usable workaround for libm.
> 

Thanks for looking into this.  I just read the audit
trail at llvm.org.  Searching the clang user manual
turns up

   The support for standard C in clang is feature-complete
   except for the C99 floating-point pragmas.

There is no other statement concerning the implementation
defined behavior.  The understated assumption that FENV_ACCESS
is tacitly set to OFF should be documented.

It won't help possible libm issues.  The libm function is
trying to raise the FE_UNDERFLOW signal and return 0 to
a program.  As it is now, the libm function returns a
nonzero invalid result.

-- 
Steve
___
freebsd-toolchain@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/freebsd-toolchain
To unsubscribe, send any mail to "freebsd-toolchain-unsubscr...@freebsd.org"


Re: clang gets numerical underflow wrong, please fix.

2016-03-14 Thread Dimitry Andric
On 14 Mar 2016, at 02:53, Steve Kargl  wrote:
...
> #include 
> #include 
> 
> int
> main(void)
> {
>   int i;
>   float x = 1.f;
>   i = 0;
>   feclearexcept(FE_ALL_EXCEPT);
>   do {
>  x *= 2;
>  i++;
>  printf("%d %e\n", i, x);
>   } while(!fetestexcept(FE_OVERFLOW));
>   if (fetestexcept(FE_OVERFLOW)) printf("FE_UNDERFLOW: ");
>   printf("x = %e after %d iterations\n", x, i);
> 
>   return 0;
> }
> 
> You'll get a bunch of invalid output before the OVERFLOW.
> 
> % cc -O -o z b.c -lm && ./z | tail
> 1016 7.022239e+305  <-- not a valid float
> 1017 1.404448e+306  <-- not a valid float
> 1018 2.808896e+306  <-- not a valid float
> 1019 5.617791e+306  <-- not a valid float
> 1020 1.123558e+307  <-- not a valid float
> 1021 2.247116e+307  <-- not a valid float
> 1022 4.494233e+307  <-- not a valid float
> 1023 8.988466e+307  <-- not a valid float
> 1024 inf
> FE_UNDERFLOW: x = inf after 1024 iterations
> 
> Clang is broken with or without #pragma FENV_ACCESS "on".

Well, it simply doesn't support that #pragma [1], just like gcc [2]. :-(

Apparently compiler writers have trouble with this pragma, don't
implement it, and assume that it's always off.  Which then appears to
make most (or all) fenv.h functions into undefined behavior.

That said, making 'x' in your test case volatile helps, e.g. the main
loop was:

fadd%st(0), %st(0)
fstl-20(%ebp)
incl%esi
movl%esi, 4(%esp)
fstpl   8(%esp)
movl$.L.str, (%esp)
calll   printf
fnstsw  -10(%ebp)

and becomes:

flds-16(%ebp)
fadd%st(0), %st(0)
fstps   -16(%ebp)
incl%esi
flds-16(%ebp)
fstpl   8(%esp)
movl%esi, 4(%esp)
movl$.L.str, (%esp)
calll   printf
#APP
fnstsw  -10(%ebp)

So the fstps causes an overflow when 128 iterations are reached:

[...]
126 8.507059e+37
127 1.701412e+38
128 inf
FE_UNDERFLOW: x = inf after 128 iterations

Maybe this is a usable workaround for libm.

-Dimitry

[1] https://llvm.org/bugs/show_bug.cgi?id=8100
[2] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=34678



signature.asc
Description: Message signed with OpenPGP using GPGMail