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

Reply via email to