[AArch64] SVE state not regarded as clobbered by TLSDESC resolver call
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
TLSDESC resolvers have a special calling convention to keep the fast path case (when the library has not been dlopen'ed) performant, where almost all registers are regarded as callee-saved, since in the fast path case few, if any, temporary registers are needed. This includes the Q registers.
However, for SVE, due to the sheer size of the state needed to be saved and restored in the slow path on the rare chance that the caller was using SVE, it was decided that the resolver should not preserve it, only the Q (sub)registers. (See also how, for functions that take SVE arguments, they are marked as STO_AARCH64_VARIANT_PCS so that they are not subjected to lazy binding, which would similarly require the resolver save SVE state just in case SVE arguments were being passed.)
LLVM does not currently adhere to this; it remains stuck in the world view that only NZCV, LR, X0 and X1 (or X16 for PAuth) are clobbered by the entire sequence (with LR and X1/X16 clobbered solely by the compiler-generated instruction sequence in the caller), and therefore treats SVE registers as live across the call. Moreover even aside from register liveness within the function, AAPCS requires that, if a function takes scalable vector or predicate registers as arguments, or returns a result in them, it must preserve all of z8-z23 and p4-p15, so any such function needs to save and restore those around TLSDESC resolver calls.
See https://godbolt.org/z/dq8Gdr5oo for an example of this (source code copied below), where LLVM assumes z0 is not clobbered, nor z8-z23/p4-p15 for the purposes of conforming to AAPCS, whereas GCC spills and restores all of them (a little confusingly it reloads z0 into z31 using x1 rather than the x0 used to spill, but both are sp+592). See https://github.com/gcc-mirror/gcc/commit/80c13ac5ec1a584561a2c474a5d61e7881ef4f82 for the GCC change that treats this as the ABI, though I'm not aware of TLSDESC for AArch64 currently being specified anywhere in abi-aa (and the 2006 TLSDESC PDF linked to is too old, only discussing 32-bit Arm).
```c
/* Compile with -O2 -fPIC -march=armv8-a+sve -msve-vector-bits=256 [-mtls-dialect=desc] */
#include
typedef svint32_t vec __attribute__((arm_sve_vector_bits(256)));
void
foo(vec a)
{
extern _Thread_local vec x;
x = a;
}
```
Contributor guide
Assessment
This issue has not been assessed yet.