llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
28.77k stars 11.9k forks source link

LLVM does not correctly align `__int128` parameters passed on the stack #33994

Open llvmbot opened 7 years ago

llvmbot commented 7 years ago
Bugzilla Link 34646
Version 5.0
OS All
Reporter LLVM Bugzilla Contributor
CC @topperc,@efriedma-quic,@hfinkel

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:

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.

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:

__int128
test(__int128 a, __int128 b, __int128 c, __int128 d)
{
        return a + b + c +d;
}
llvmbot commented 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.

llvmbot commented 7 years ago

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.