clang miscompiles OpenLibm on i686-*-freebsd

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

clang miscompiles OpenLibm on i686-*-freebsd

Steve Kargl
TL;DR summary: clang is broken for numerical on i686 FreeBSD.


% uname -a
FreeBSD mobile 13.0-CURRENT FreeBSD 13.0-CURRENT #0 r361834M:
Fri Jun  5 08:49:26 PDT 2020 obj/usr/src/i386.i386/sys/MOBILE  i386

% which clang
/usr/bin/clang
% clang --version
FreeBSD clang version 10.0.1 ([hidden email]:llvm/llvm-project.git llvmorg-10.0.1-rc1-0-gf79cd71e145)
Target: i386-unknown-freebsd13.0
Thread model: posix
InstalledDir: /usr/bin

My testing for exp2f(x) shows

Interval tested for exp2f: [1,8]
       ulp <= 0.5:  0.936%    235635 |   0.936%    235635
0.5 <  ulp <  0.6:  0.016%      4098 |   0.953%    239733
0.6 <  ulp <  0.7:  0.024%      6147 |   0.977%    245880
0.7 <  ulp <  0.8:  0.008%      2049 |   0.985%    247929
0.8 <  ulp <  0.9:  0.016%      4098 |   1.001%    252027
0.9 <  ulp <  1.0:  0.008%      2049 |   1.010%    254076
1.0 <  ulp <  1.5:  0.334%     84009 |   1.343%    338085
1.5 <  ulp <  2.0:  0.187%     47127 |   1.531%    385212
2.0 <  ulp <  3.0:  0.839%    211047 |   2.369%    596259
3.0 <  ulp <  0.0: 97.631%  24569565 | 100.000%  25165824
Max ulp: 359512.000000 at 1.96875286e+00

which is bad (ulp means errors in the Unit of Last Place).

By default OpenLibm uses "-march=i686 -O3 -m32" on an i686 target.
The commandline used in compiling s_exp2f.c is

   clang -fno-builtin -fno-strict-aliasing -O3 -fPIC -march=i686 -m32
   -std=c99 -Wall -I/usr/home/kargl/tmp/olibm
   -I/usr/home/kargl/tmp/olibm/include -I/usr/home/kargl/tmp/olibm/i387
   -I/usr/home/kargl/tmp/olibm/src -DASSEMBLER -D__BSD_VISIBLE
   -Wno-implicit-function-declaration -I/usr/home/kargl/tmp/olibm/ld80
   -c src/s_exp2f.c -o src/s_exp2f.c.o

If I use -O1 or -O2 I get the same above results.  If I
change to -O0, I get

   clang -fno-builtin -fno-strict-aliasing -O0 -fPIC -march=i686 -m32
   -std=c99 -Wall -I/usr/home/kargl/tmp/olibm
   -I/usr/home/kargl/tmp/olibm/include -I/usr/home/kargl/tmp/olibm/i387
   -I/usr/home/kargl/tmp/olibm/src -DASSEMBLER -D__BSD_VISIBLE
   -Wno-implicit-function-declaration -I/usr/home/kargl/tmp/olibm/ld80
   -c src/s_exp2f.c -o src/s_exp2f.c.o

Interval tested for exp2f: [1,8]
       ulp <= 0.5:  0.056%     14072 |   0.056%     14072
0.5 <  ulp <  0.6:  0.000%         8 |   0.056%     14080
3.0 <  ulp <  0.0: 99.944%  25151744 | 100.000%  25165824
Max ulp: 22729.386719 at 1.00195301e+00

This is better, but still bad.  If I remove -m32, I get

   clang -fno-builtin -fno-strict-aliasing -O0 -fPIC -march=i686
   -std=c99 -Wall -I/usr/home/kargl/tmp/olibm
   -I/usr/home/kargl/tmp/olibm/include -I/usr/home/kargl/tmp/olibm/i387
   -I/usr/home/kargl/tmp/olibm/src -DASSEMBLER -D__BSD_VISIBLE
   -Wno-implicit-function-declaration -I/usr/home/kargl/tmp/olibm/ld80
   -c src/s_exp2f.c -o src/s_exp2f.c.o

Interval tested for exp2f: [1,8]
       ulp <= 0.5: 99.959%  25155610 |  99.959%  25155610
0.5 <  ulp <  0.6:  0.041%     10214 | 100.000%  25165824
Max ulp: 0.500980 at 1.97115958e+00

This is good, but unoptimized.  If I use -O1, -O2, or -O3 without
-m32, I get the initial bad results above.  If I change -march=i686
to -march=pentiumpro, I get the same results.

Theoretically, OpenLibm would test for SSE capabilities and choose
a better -march, but it doesn't.  This, however, is unimportant.
Any port that uses clang (or cc) that does numerical computation
and uses -march=i686 (or pentiumpro) is likely broken.

--
Steve
_______________________________________________
[hidden email] mailing list
https://lists.freebsd.org/mailman/listinfo/freebsd-current
To unsubscribe, send any mail to "[hidden email]"
Reply | Threaded
Open this post in threaded view
|

Re: clang miscompiles OpenLibm on i686-*-freebsd

Steve Kargl
On Mon, Sep 07, 2020 at 07:55:13PM -0700, Steve Kargl wrote:

> On Mon, Sep 07, 2020 at 07:10:02PM -0700, Steve Kargl wrote:
> >
> > Interval tested for exp2f: [1,8]
> >        ulp <= 0.5:  0.056%     14072 |   0.056%     14072
> > 0.5 <  ulp <  0.6:  0.000%         8 |   0.056%     14080
> > 3.0 <  ulp <  0.0: 99.944%  25151744 | 100.000%  25165824
> > Max ulp: 22729.386719 at 1.00195301e+00
> >
>
> Note, compiling s_exp2f.c with gcc9 gives the above
> result with -O3 -march=i686 -m32. So, gcc9 is not
> nearly as bad as clang, but both give bad results.
> Comparing OpenLibm's s_exp2f.c and FreeBSD's s_exp2f.c,
> one sees that the files are almost identical.
>
> Note, FreeBSD's libm gives
>
> % ./tlibm_libm -DEfP exp2
> Interval tested for exp2f: [1,8]
>        ulp <= 0.5: 99.959%  25155610 |  99.959%  25155610
> 0.5 <  ulp <  0.6:  0.041%     10214 | 100.000%  25165824
> Max ulp: 0.500980 at 1.97115958e+00
>
> which is good, but this is compiled with CPUTYPE ?= core2
> in /etc/make.conf.
>

I think I've found the problem, and it appears to be
due to a change byt Openlibm developers to the file
math_private.h copied from FreeBSD.  Namely, one finds

//VBS
#define STRICT_ASSIGN(type, lval, rval) ((lval) = (rval))

/* VBS
#ifdef FLT_EVAL_METHOD
// Attempt to get strict C99 semantics for assignment with non-C99 compilers.
#if FLT_EVAL_METHOD == 0 || __GNUC__ == 0
#define STRICT_ASSIGN(type, lval, rval) ((lval) = (rval))
#else
#define STRICT_ASSIGN(type, lval, rval) do { \
 volatile type __lval;   \
      \
 if (sizeof(type) >= sizeof(double)) \
  (lval) = (rval);  \
 else {     \
  __lval = (rval);  \
  (lval) = __lval;  \
 }     \
} while (0)
#endif
#endif
*/

So, STRICT_ASSIGN is broken in Openlibm.  I'll be reporting
a bug upstream.  Apoogies for the noise.

--
Steve
_______________________________________________
[hidden email] mailing list
https://lists.freebsd.org/mailman/listinfo/freebsd-current
To unsubscribe, send any mail to "[hidden email]"
Reply | Threaded
Open this post in threaded view
|

Re: clang miscompiles OpenLibm on i686-*-freebsd

Dimitry Andric-4
On 8 Sep 2020, at 19:47, Steve Kargl <[hidden email]> wrote:

>
> On Mon, Sep 07, 2020 at 07:55:13PM -0700, Steve Kargl wrote:
>> On Mon, Sep 07, 2020 at 07:10:02PM -0700, Steve Kargl wrote:
>>>
>>> Interval tested for exp2f: [1,8]
>>>       ulp <= 0.5:  0.056%     14072 |   0.056%     14072
>>> 0.5 <  ulp <  0.6:  0.000%         8 |   0.056%     14080
>>> 3.0 <  ulp <  0.0: 99.944%  25151744 | 100.000%  25165824
>>> Max ulp: 22729.386719 at 1.00195301e+00
>>>
>>
>> Note, compiling s_exp2f.c with gcc9 gives the above
>> result with -O3 -march=i686 -m32. So, gcc9 is not
>> nearly as bad as clang, but both give bad results.
>> Comparing OpenLibm's s_exp2f.c and FreeBSD's s_exp2f.c,
>> one sees that the files are almost identical.
>>
>> Note, FreeBSD's libm gives
>>
>> % ./tlibm_libm -DEfP exp2
>> Interval tested for exp2f: [1,8]
>>       ulp <= 0.5: 99.959%  25155610 |  99.959%  25155610
>> 0.5 <  ulp <  0.6:  0.041%     10214 | 100.000%  25165824
>> Max ulp: 0.500980 at 1.97115958e+00
>>
>> which is good, but this is compiled with CPUTYPE ?= core2
>> in /etc/make.conf.
>>
>
> I think I've found the problem, and it appears to be
> due to a change byt Openlibm developers to the file
> math_private.h copied from FreeBSD.  Namely, one finds
>
> //VBS
> #define STRICT_ASSIGN(type, lval, rval) ((lval) = (rval))
>
> /* VBS
> #ifdef FLT_EVAL_METHOD
> // Attempt to get strict C99 semantics for assignment with non-C99 compilers.
> #if FLT_EVAL_METHOD == 0 || __GNUC__ == 0
> #define STRICT_ASSIGN(type, lval, rval) ((lval) = (rval))
> #else
> #define STRICT_ASSIGN(type, lval, rval) do { \
> volatile type __lval;   \
>      \
> if (sizeof(type) >= sizeof(double)) \
>  (lval) = (rval);  \
> else {     \
>  __lval = (rval);  \
>  (lval) = __lval;  \
> }     \
> } while (0)
> #endif
> #endif
> */
>
> So, STRICT_ASSIGN is broken in Openlibm.  I'll be reporting
> a bug upstream.  Apoogies for the noise.
Hi Steve,

I'm curious what their rationale was, as the commit that changed it is:

https://github.com/JuliaMath/openlibm/commit/f5fb92746715beb0441a60feca202ee16cb19fc9

with a description of just "Build with gcc"... Maybe they've assumed gcc
never needs the volatile approach?

-Dimitry


signature.asc (230 bytes) Download Attachment