llvm / llvm/llvm-project

[AArch64] SVE state not regarded as clobbered by TLSDESC resolver call

Open
#186,500 6 comments 0 reactions 0 assignees View on GitHub
ABI backend:AArch64 SVE
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.