catrig[fl].c and inexact
Steve Kargl
sgk at troutmask.apl.washington.edu
Sat May 13 06:08:05 UTC 2017
On Sat, May 13, 2017 at 11:35:49AM +1000, Bruce Evans wrote:
> On Fri, 12 May 2017, Steve Kargl wrote:
>
> > So, I've been making improvements to my implementations of
> > the half-cycle trig functions. In doing so, I decide to
> > add WARNS=2 to msun/Makefile. clang 4.0.0 dies with an
> > error about an unused variable in raise_inexact() from
> > catrig[fl].c.
> >
> > /usr/home/kargl/trunk/math/libm/msun/src/catrigl.c:195:2: error: unused variable
> > 'junk' [-Werror,-Wunused-variable]
> > raise_inexact();
> > ^
> > /usr/home/kargl/trunk/math/libm/msun/src/catrigl.c:56:45: note: expanded from
> > macro 'raise_inexact'
> > #define raise_inexact() do { volatile float junk = 1 + tiny; } while(0)
> > ^
> > Grepping catrig.o for the variable 'junk' suggests that 'junk' is
> > optimized out (with at least -O2).
>
> Just another bug in clang. Volatile variables cannot be optimized out
> (if they are accessed).
Does this depend on scope? 'junk' is local to the do {...} while(0);
construct. Can a compiler completely eliminate a do-nothing scoping
unit? I don't know C well enough to know. I do know what I have
observed in clang.
> > A quick and dirty patch to achieve the intent of the original
> > code follows. It would be nice if some would like to commit
> > the patch. Of course, you may want to wait for Bruce to
> > review the diff.
> >
> > Index: src/catrig.c
> > ===================================================================
> > --- src/catrig.c (revision 1935)
> > +++ src/catrig.c (working copy)
> > @@ -37,7 +37,7 @@ __FBSDID("$FreeBSD: head/lib/msun/src/catrig.c 313863
> > #define isinf(x) (fabs(x) == INFINITY)
> > #undef isnan
> > #define isnan(x) ((x) != (x))
> > -#define raise_inexact() do { volatile float junk = 1 + tiny; } while(0)
> > +#define raise_inexact(x) do { (x) = 1 + tiny; } while(0)
> > #undef signbit
> > #define signbit(x) (__builtin_signbit(x))
> >
> > @@ -315,7 +315,7 @@ casinh(double complex z)
> > return (z);
> >
> > /* All remaining cases are inexact. */
> > - raise_inexact();
> > + raise_inexact(new_y);
> >
> > if (ax < SQRT_6_EPSILON / 4 && ay < SQRT_6_EPSILON / 4)
> > return (z);
>
> Now it doesn't take compiler bugs to optimize it out, since new_y is not
> volatile, and a good compiler would optimize it out in all cases.
I've yet to find a good compiler. They all seem to have bugs.
> new_y
> is obviously unused before the early returns, so it doesn't need to be
> evalated before the returns as far as the compiler can see. Later,
> new_y is initialized indirectly, and the compiler can see that too (not
> so easily, so it can see that raise_inexact() has no effect except possibly
> for its side effect of raising inexact for 1 + tiny.
The later call passes the address of new_y to the routine. How
can the compiler short of inlining the called routine know that
the value assigned to new_y isn't used?
> The change might defeat the intent of the original code in another way.
> 'junk' is intentionally independent of other variables, so that there are
> no dependencies on it. If the compiler doesn't optimize away the assignment
> to new_y, then it is probably because it doesn't see that the assignment is
> dead, so there is a dependency.
It may defeat the intent of the original code, but it seems that
the original code provokes undefined behavior.
> Actually, we want the variable 'junk' to be optimized away. We only want
> the side effect of evaluating 1 + tiny. Compilers have bugs evaluating
> expressions like 1 + tiny, tiny*tiny and huge*huge, and we use assignments
> of the result to volatile variables in tens if not hundreds of places to
> try to work around compiler bugs. If that doesn't work here, then all the
> other places are probably broken too. The other places mostly use a static
> volatile, while this uses an auto volatile. 'tiny' is also volatile, as
> required for the standard magic. I planned to fix all this magic using
> macros like raise_inexact().
If you plan to fix the magic with raise_inexact, then please
test with a suite of compilers. AFAICT, clang is optimizing
out the code. I haven't written a testcase to demonstrate this
as I have other irons in the fire.
--
Steve
20170425 https://www.youtube.com/watch?v=VWUpyCsUKR4
20161221 https://www.youtube.com/watch?v=IbCHE-hONow
More information about the freebsd-numerics
mailing list