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

Jakub Jelinek <jakub at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |hubicka at gcc dot gnu.org,
                   |                            |jakub at gcc dot gnu.org,
                   |                            |matz at gcc dot gnu.org

--- Comment #2 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
I've started by checking the argument passing against the psABI:
struct S { long long a, b; };
struct __attribute__((aligned (16))) T { long long a, b; };
void f1 (__int128);
void f2 (int, __int128);
void f3 (int, int, __int128);
void f4 (int, int, int, __int128);
void f5 (int, int, int, int, __int128);
void f6 (int, int, int, int, int, __int128);
void f7 (int, int, int, int, int, int, __int128);
void f8 (int, int, int, int, int, int, int, __int128);
void f9 (int, ...);
void f10 (struct S);
void f11 (int, struct S);
void f12 (int, int, struct S);
void f13 (int, int, int, struct S);
void f14 (int, int, int, int, struct S);
void f15 (int, int, int, int, int, struct S);
void f16 (int, int, int, int, int, int, struct S);
void f17 (int, int, int, int, int, int, int, struct S);
void f18 (struct T);
void f19 (int, struct T);
void f20 (int, int, struct T);
void f21 (int, int, int, struct T);
void f22 (int, int, int, int, struct T);
void f23 (int, int, int, int, int, struct T);
void f24 (int, int, int, int, int, int, struct T);
void f25 (int, int, int, int, int, int, int, struct T);

void
foo ()
{
  __int128 i = -1;
  struct S s = { -1, -1 };
  struct T t = { -1, -1 };
  f1 (-1);
  f2 (0, -1);
  f3 (0, 0, -1);
  f4 (0, 0, 0, -1);
  f5 (0, 0, 0, 0, -1);
  f6 (0, 0, 0, 0, 0, -1);
  f7 (0, 0, 0, 0, 0, 0, -1);
  f8 (0, 0, 0, 0, 0, 0, 0, -1);
  f9 (0, i);
  f9 (0, 0, i);
  f9 (0, 0, 0, i);
  f9 (0, 0, 0, 0, i);
  f9 (0, 0, 0, 0, 0, i);
  f9 (0, 0, 0, 0, 0, 0, i);
  f9 (0, 0, 0, 0, 0, 0, 0, i);
  f10 (s);
  f11 (0, s);
  f12 (0, 0, s);
  f13 (0, 0, 0, s);
  f14 (0, 0, 0, 0, s);
  f15 (0, 0, 0, 0, 0, s);
  f16 (0, 0, 0, 0, 0, 0, s);
  f17 (0, 0, 0, 0, 0, 0, 0, s);
  f9 (0, s);
  f9 (0, 0, s);
  f9 (0, 0, 0, s);
  f9 (0, 0, 0, 0, s);
  f9 (0, 0, 0, 0, 0, s);
  f9 (0, 0, 0, 0, 0, 0, s);
  f9 (0, 0, 0, 0, 0, 0, 0, s);
  f18 (t);
  f19 (0, t);
  f20 (0, 0, t);
  f21 (0, 0, 0, t);
  f22 (0, 0, 0, 0, t);
  f23 (0, 0, 0, 0, 0, t);
  f24 (0, 0, 0, 0, 0, 0, t);
  f25 (0, 0, 0, 0, 0, 0, 0, t);
  f9 (0, t);
  f9 (0, 0, t);
  f9 (0, 0, 0, t);
  f9 (0, 0, 0, 0, t);
  f9 (0, 0, 0, 0, 0, t);
  f9 (0, 0, 0, 0, 0, 0, t);
  f9 (0, 0, 0, 0, 0, 0, 0, t);
}

I believe GCC follows the psABI here:
"For classification purposes __int128 is treated as if it were implemented
as:
typedef struct {
long low, high;
} __int128;
with the exception that arguments of type __int128 that are stored in
memory must be aligned on a 16-byte boundary."
and __int128 is passed the same as the aligned(16) structure containing two
long/long long fields, in particular, if both halves fit in general purpose
registers, they are passed there, without any gaps, if only half fits into gpr
and the other would need to go onto stack, it is passed on stack, and when
passed on stack, it is passed aligned on 16-byte boundary.
So, I'd say the bug is in the x86_64 va_arg expansion that when reading the
__int128 (and maybe > 8 bytes aligned struct too) from the area of spilled gprs
it should use 8 byte alignment (i.e. lower than the type has), will keep
looking into that.
Also checked with clang and that one seems to ignore the psABI completely,
hapilly passing the __int128 partially in gpr (%r9) and on the stack (that is
the f6 call and f9 (0, 0, 0, 0, 0, i);), which violates the psABI:
"If there are no registers available for any eightbyte of an argument, the
whole
argument is passed on the stack."
or that the __int128 should be passed 16-byte aligned on the stack (that is the
f8 call and f9 (0, 0, 0, 0, 0, 0, 0, -1);), which violates the psABI:
"with the exception that arguments of type __int128 that are stored in
memory must be aligned on a 16-byte boundary."
Note, the passing of struct S and struct T seems to be correct in both
compilers.

Reply via email to