https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128640
Bug ID: 128640
Summary: x86-64 -mavx: va_arg of union { float vector_size(32)
} reads wrong upper lanes
Product: gcc
Version: 17.0
Status: UNCONFIRMED
Keywords: wrong-code
Severity: normal
Priority: P3
Component: target
Assignee: unassigned at gcc dot gnu.org
Reporter: jeffchen006 at gmail dot com
Target Milestone: ---
#include <stdio.h>
#include <stdarg.h>
typedef float V __attribute__((vector_size(32)));
union U { V f; };
void f(int n, ...) {
va_list ap;
va_start(ap, n);
double d = va_arg(ap, double);
union U u = va_arg(ap, union U);
va_end(ap);
printf("%g %g\n", u.f[0], u.f[7]);
}
int main(void) {
union U u = {};
for (int i = 0; i < 8; i++) u.f[i] = i + 1;
f(1, 0.0, u, 0.0);
}
$ gcc -mavx -O0 t.c && ./a.out
1 0
$ gcc -mavx -O2 t.c && ./a.out
1 0
(same at -O1 and -O3)
Expected: 1 8. Clang prints "1 8". GCC is wrong at all -O levels. The caller
passes the union in %ymm, but va_arg reads it from the register save area,
which holds only 16 bytes per register; lane 7 comes from the next saved xmm. A
64-byte union with -mavx512f has the same problem. A struct with the same
member, or a plain vector, is correct. GCC 8.5.0 -O2 -mavx gets an ICE
(segfault in the stdarg pass) on this test.
Suspected cause: i386 va_arg (ix86_gimplify_va_arg) and the caller argument
passing do not agree for a union whose only member is a 32/64-byte vector.
Known to fail: 12.5.0, 16.2.0, 17.0.
-O0 -fsanitize=undefined,address is clean.
gcc version 17.0.0 20261111 (experimental) (a2a11abfad3), x86_64-pc-linux-gnu
Configured with: --enable-languages=c,c++ --disable-multilib
--disable-bootstrap --enable-checking=release