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