Open llvmbot opened 7 years ago
This goes even further. If a function has the following signature:
void foo(int a, int b, int c, int d, int e, __int128 f, int g)
Then clang puts a
, b
, c
, d
, e
and the lower half of f
into registers, while passing the upper half of f
and g
on the stack.
The correct behavior (that GCC also uses) is to put a
, b
, c
, d
, e
, g
in registers and f
onto the stack. Clang should push a
, b
, c
, d
, e
and then when it wants to push f
, it should notice it only has one register left and thus push it on the stack, and then when it tries to push g
notice that it still has a register left.
See https://software.intel.com/sites/default/files/article/402129/mpx-linux64-abi.pdf for further details.
To clarify: This affects all targets using ELF or Mach-O. I haven't tested Win64, but it's maybe not affected as it uses a different ABI.
Extended Description
Quoting from the x86_64 ABI:
Arguments of type
__int128
offer the same operations as INTEGERs, yet they do not fit into one general purpose register but require two registers. For classification purposes__int128
is treated as if it were implemented as:with the exception that arguments of type
__int128
that are stored in memory must be aligned on a 16-byte boundary.However, Clang does not align them on a 16-byte boundary.
This results in Clang using a different ABI than GCC and others, resulting in incompatible code.
E.g. the following code will create a function with a different ABI when compiled with Clang and GCC: