https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93806

--- Comment #34 from Alexander Cherepanov <ch3root at openwall dot com> ---
(In reply to Vincent Lefèvre from comment #13)
> > Since C without Annex F allows arbitrarily awful floating point results,
> 
> In C without Annex F, division by 0 is undefined behavior (really undefined
> behavior, not an unspecified result, which would be very different).
> 
> With the examples using divisions by 0, you need to assume that Annex F
> applies, but at the same time, with your interpretation, -fno-signed-zeros
> breaks Annex F in some cases, e.g. if you have floating-point divisions by
> 0. So I don't follow you...

You seem to say that either Annex F is fully there or not at all but why?
-fno-signed-zeros breaks Annex F but only parts of it. Isn't it possible to
retain the other parts of it? Maybe it's impossible or maybe it's impossible to
retain division by zero, I don't know. What is your logic here?

(In reply to Vincent Lefèvre from comment #15)
> Note that there are very few ways to be able to distinguish the sign of
> zero. The main one is division by zero. Other ones are:
> 
> * Conversion to a character string, e.g. via printf(). But in this case, if
> -fno-signed-zeros is used, whether "0" or "-0" is output (even in a way that
> seems to be inconsistent) doesn't matter since the user does not care about
> the sign of 0, i.e. "0" and "-0" are regarded as equivalent (IIRC, this
> would be a bit like NaN, which has a sign bit in IEEE 754, but the output
> does not need to match its sign bit).

This means that you cannot implement you own printf: if you analyze sign bit of
your value to decide whether you need to print '-', the sign of zero is
significant in your code.

IOW why do you think that printf is fine while "1 / x == 1 / 0." is not?

> * Memory analysis. Again, the sign does not matter, but for instance,
> reading an object twice as a byte sequence while the object has not been
> changed by the code must give the same result. I doubt that this is affected
> by optimization.

Working with objects on byte level is often optimized too:

----------------------------------------------------------------------
#include <string.h>
#include <stdio.h>

__attribute__((noipa)) // imagine it in a separate TU
static double opaque(double d) { return d; }

int main()
{
    int zero = opaque(0);

    double x = opaque(-0.);
    long l;
    memcpy(&l, &x, sizeof l);
    int a = l == 0;
    // or just this:
    //int a = (union { double d; long l; }){x}.l == 0;

    printf("zero = %d\n", zero);

    opaque(a);
    if (zero == a) {
        opaque(0);
        if (x == 0) {
            opaque(0);
            if (a) {
                opaque(0);
                if (zero == 1)
                    printf("zero = %d\n", zero);
            }
        }
    }
}
----------------------------------------------------------------------
$ gcc -std=c11 -pedantic -Wall -Wextra -fno-signed-zeros -O3 test.c && ./a.out
zero = 0
zero = 1
----------------------------------------------------------------------
gcc x86-64 version: gcc (GCC) 10.0.1 20200303 (experimental)
----------------------------------------------------------------------

Bonus: bare -fno-signed-zeros is used here, without -fno-trapping-math.

Reply via email to