On Sat, Nov 13, 2010 at 6:41 PM, Charles R Harris <charlesr.har...@gmail.com
> wrote:

> Hi All,
>
> This is in reference to numpy ticket 
> #1671<http://projects.scipy.org/numpy/ticket/1671>and the comments on pull
> request 13 <https://github.com/numpy/numpy/pull/13>. The original problem
> was that the gcc compiler was reordering the instructions so that the
> floating point flags were tested before the computation that needed to be
> checked. The compiler couldn't know that the flags were being tested in the
> original code because it didn't know that about PyUFunc_getfperr(), although
> the fact that floating point computations have side effects should probably
> have limited any code reordering given that unknown. However, even when the
> macro using the glibc function fetestexcept was used the problem persisted.
> This is a known bug <http://gcc.gnu.org/bugzilla/show_bug.cgi?id=29186>against
> gcc >= 4.1 that hasn't been addressed in the last four years and it seems
> unlikely that it will be fixed anytime soon. The upshot is that there is no
> reliable way to check the floating point flags using either PyUFunc_getfperr
> or the macro UFUNC_CHECK_STATUS.
>
> Enter the ugly workarounds. If a floating point operation produces a value,
> it is possible to pass a void pointer to that value as a dummy argument to a
> flag checking routine which will force the value to be computed before the
> function is called. There are other games that can be played with volatile
> but I am not convinced that they are robust or portable across compilers. An
> added complication is that PyUFunc_getfperr is part of the numpy API and the
> macro UFUNC_CHECK_STATUS is public so if we add workarounds they need new
> names. There is also the question if we want to expose them. In any case,
> suggestions as to names and approaches are welcome. And if anyone has a
> better solution it would be great to hear it.
>
> Chuck
>

The ways we have thought of to solve this are:

1) Declare the result of the computation volatile.  This fixed everything
for me, and is a very minimal patch (add the volatile, and cast it away when
passing the output pointer parameter to avoid a warning).  Volatile is
usually applied to variables whose state is visible outside the current
thread, or for low-level device driver programming to prevent reordering, so
this usage on a local variable may be a little suspect.  On the other hand,
it worked for me, and with the added unit test, any other systems out there
which exhibit this or similar bugs would be flagged during testing.

volatile float result = arg1 / arg2;
int retstatus = PyUFunc_getfperr();
if (retstatus) ...


2) Use a compiler memory barrier to block reordering around
PyUFunc_getfperr().  Unfortunately, the suggested barrier for gcc (asm
volatile("" ::: "memory");) did not work, and the bug remained.

3) Enforce ordering by creating a dependency.  Since the compiler doesn't
consider the FP state as important, a different dependency can be used.  One
invasive way is to modify PyUFunc_getfperr to take a void* parameter, then
pass a pointer to the result as a parameter.  For this to work,
PyUFunc_getfperr needs to be opaque to the compiler, for instance by being
non-inline or called through a function pointer.  If we want to force any
modules linking to NumPy to check if they're susceptible to the bug,
changing the API like this, with appropriate documentation, may be the way
to go.

float result = arg1 / arg2;
int retstatus = PyUFunc_getfperr(&result);
if (retstatus) ...


Cheers,
Mark
_______________________________________________
NumPy-Discussion mailing list
NumPy-Discussion@scipy.org
http://mail.scipy.org/mailman/listinfo/numpy-discussion

Reply via email to