> -----Original Message-----
> From: Georg-Johann Lay <a...@gjlay.de>
> Sent: Wednesday, October 2, 2024 3:06 PM
> To: GCC Development <gcc@gcc.gnu.org>; Tamar Christina
> <tamar.christ...@arm.com>
> Subject: Re: Understanding bogus? gcc.dg/signbit-6.c
> 
> Am 02.10.24 um 15:55 schrieb Georg-Johann Lay:
> > I am having problems understanding test case gcc.dg/signbit-6.c
> > which fails on a 16-bit platform (avr).
> >
> > https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=gcc/testsuite/gcc.dg/signbit-
> 6.c;h=da186624cfa057dfc3780c8af4f6b1335ba07e7e;hb=HEAD
> >
> > The relevant part of the code is:
> >
> > int main ()
> > {
> >    TYPE a[N];
> >    TYPE b[N];
> >
> >    a[0] = INT_MIN;
> >    b[0] = INT_MIN;
> >
> >    for (int i = 1; i < N; ++i) ...
> >
> >    fun1 (a, N);
> >    fun2 (b, N);
> >
> >    if (DEBUG)
> >      printf ("%d = 0x%x == 0x%x\n", 0, a[0], b[0]);
> >
> >    if (a[0] != 0x0 || b[0] != -1)
> >          __builtin_abort ();   // <-- triggers
> >
> >
> > where TYPE=int32_t, and the error occurs for a[0] and b[0] so
> > the test can be compiled with -DN=1 and still fails.
> >
> > fun1() and fun2() have the same C code but different optimization level,
> > so how are a[0] and b[0] supposed to be different?
> >
> > __attribute__ ((noinline, noipa))
> > void fun1(TYPE *x, int n)
> > {
> >      for (int i = 0; i < n; i++)
> >        x[i] = (-x[i]) >> 31;
> > }
> >
> > __attribute__ ((noinline, noipa, optimize("O0")))
> > void fun2(TYPE *x, int n)
> > {
> >      for (int i = 0; i < n; i++)
> >        x[i] = (-x[i]) >> 31;
> > }
> >
> > IIUC the compiler may exploit that x and -x will always have different
> > sign bits because "- INT_MIN" is UB.  In fact, on x86_64 the test
> > passes, here with gcc v13.2:
> >
> > $ gcc signbit-6.c -O1 -o x.x -DN=1 && ./x.x
> > 0 = 0x0 == 0xffffffff
> >
> > With -fwrapv so that -INT_MIN is not more UB, it actually fails
> > due to the bad condition  "if (a[0] != 0x0 || b[0] != -1)" :
> >
> > $ gcc signbit-6.c -O1 -o x.x -DN=1 -fwrapv && ./x.x
> > 0 = 0xffffffff == 0xffffffff
> >
> > On avr (int=int16_t), the test aborts after printing "0 = 0x0 == 0x0".
> >
> >
> > So as far as I can see, that test has at least 3 bugs?
> >
> > 1) Missing -fwrapv so that -INT_MIN is no more UB, hence the
> > test would assert that a[0] == b[0].
> >
> > 2) When testing for a specific value of a[0] and b[0], it depends
> > on whether int == int32_t or smaller:  Better use INT32_MIN to
> > initialize a[0] and b[0] instead of just INT_MIN.
> >
> > 3) The test case has bogus printf format strings and should
> > use PRIx32 from inttypes.h instead of %x.
> >
> > With theses fixes, expected result for a[0] and b[0] is
> > (-INT32_MIN) >> 31  =  INT_MIN >> 31  =  INT32_C (-1)
> >
> > Johann
> 
> The test case also passes on avr when a[0] and b[0] are initialized
> to INT32_MIN (instead of INT_MIN), without -fwrapv, and fixing %x:
> 
> 0 = 0x0 == 0xffffffff
> 
> But IMO a test case should not rely on any specific behavior of
> code that is UB.
> 
> FYI, there is also gcc.dg/signbit-4.c that comes with -fwrapv
> and doesn't assume a specific result for a[0], b[0] and just
> that a[0] == b[0] (also uses INT_MIN for init instead of INT32_MIN).
> 

There are multiple tests because -fwrapv is not required to perform the
optimization.  By a target failing without -fwrapv it can save someone time
vs looking at a failing larger program.

The INT_MIN case was added because it was a concern during review.

Thanks,
Tamar

> Johann

Reply via email to