> -----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