https://gcc.gnu.org/g:0748d2c83fc0440f101fe01cc3dfc97c8e11c3b2
commit r17-2408-g0748d2c83fc0440f101fe01cc3dfc97c8e11c3b2 Author: Luke Zhuang <[email protected]> Date: Thu Jun 25 13:45:16 2026 +0800 RISC-V: Declare TLSDESC clobbers for vector registers and CSRs per psABI Per the RISC-V psABI, the TLSDESC resolver clobbers a0 and t0 in the base case. With the new psABI update (https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/496), when the V extension is enabled, it additionally clobbers all vector registers and vector CSRs. This patch updates the clobbering of tlsdesc define_insn: clobbering not only a0 and t0, but also all V-regs (using 4 x LMUL8 reg groups covering all 32 physical V-regs), and 4 vector CSRs (vl/vtype/vxrm/vxstat). Three new tests are added covering GPR, vector register, and vector CSR clobber behavior. gcc/ChangeLog: * config/riscv/riscv.md (VXSAT_REGNUM): New constant. (@tlsdesc<mode>): update clobbering. gcc/testsuite/ChangeLog: * gcc.target/riscv/tlsdesc_clobber.c: New test. * gcc.target/riscv/tlsdesc_clobber_v.c: New test. * gcc.target/riscv/tlsdesc_clobber_v_csr.c: New test. Diff: --- gcc/config/riscv/riscv.md | 11 ++++- gcc/testsuite/gcc.target/riscv/tlsdesc_clobber.c | 29 +++++++++++ gcc/testsuite/gcc.target/riscv/tlsdesc_clobber_v.c | 56 ++++++++++++++++++++++ .../gcc.target/riscv/tlsdesc_clobber_v_csr.c | 39 +++++++++++++++ 4 files changed, 134 insertions(+), 1 deletion(-) diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md index f10a08460acf..c64e4ff3c77b 100644 --- a/gcc/config/riscv/riscv.md +++ b/gcc/config/riscv/riscv.md @@ -181,6 +181,7 @@ (VTYPE_REGNUM 67) (VXRM_REGNUM 68) (FRM_REGNUM 69) + (VXSAT_REGNUM 70) ]) (include "predicates.md") @@ -2478,7 +2479,15 @@ (unspec:P [(match_operand:P 0 "symbolic_operand" "")] UNSPEC_TLSDESC)) - (clobber (reg:P T0_REGNUM))] + (clobber (reg:P T0_REGNUM)) + (clobber (reg:RVVM8QI 96)) + (clobber (reg:RVVM8QI 104)) + (clobber (reg:RVVM8QI 112)) + (clobber (reg:RVVM8QI 120)) + (clobber (reg:SI VL_REGNUM)) + (clobber (reg:SI VTYPE_REGNUM)) + (clobber (reg:SI VXRM_REGNUM)) + (clobber (reg:SI VXSAT_REGNUM))] "TARGET_TLSDESC" { return ".LT%=: auipc\ta0,%%tlsdesc_hi(%0)\;" diff --git a/gcc/testsuite/gcc.target/riscv/tlsdesc_clobber.c b/gcc/testsuite/gcc.target/riscv/tlsdesc_clobber.c new file mode 100644 index 000000000000..6a004d6820fd --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/tlsdesc_clobber.c @@ -0,0 +1,29 @@ +/* Verify that the TLSDESC resolver only clobbers a0 and t0 while assuming + all other registers as preserved per its custom ABI (no vector case), + which is different from a normal call. */ + +/* { dg-do compile } */ +/* { dg-require-effective-target tls_native } */ +/* { dg-options "-O2 -fpic -mtls-dialect=desc -march=rv64gc -mabi=lp64d" } */ +/* { dg-require-effective-target fpic } */ + +extern __thread int tls_var; + +long +test_clobber (long a, long b, long c, long d) +{ + /* a=a0, b=a1, c=a2, d=a3. + TLSDESC clobbers a0 and t0 only, so the compiler must save/restore + a0 (by stack or mv or whatever), but should not do the same thing + for a1-a3 like a normal call. */ + tls_var = 1; + return a + b + c + d; +} + +/* The TLSDESC call should be present. */ +/* { dg-final { scan-assembler-times {jalr\tt0,} 1 } } */ + +/* ra/a1-a3 should NOT be moved to s-regs or saved to stack. */ +/* { dg-final { scan-assembler-not {mv\ts[0-9]+,a[0-9]+} } } */ +/* { dg-final { scan-assembler-not {sd\ta[0-9]+,.*\(sp\)} } } */ +/* { dg-final { scan-assembler-not {sd\tra,.*\(sp\)} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/tlsdesc_clobber_v.c b/gcc/testsuite/gcc.target/riscv/tlsdesc_clobber_v.c new file mode 100644 index 000000000000..a5fb350f76e7 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/tlsdesc_clobber_v.c @@ -0,0 +1,56 @@ +/* Verify that when the V extension is enabled, the TLSDESC resolver clobbers + all vector registers per the psABI. The compiler must save/restore any + live vector registers across the TLSDESC call. */ + +/* { dg-do compile } */ +/* { dg-require-effective-target tls_native } */ +/* { dg-options "-O2 -fpic -mtls-dialect=desc -march=rv64gcv -mabi=lp64d" } */ +/* { dg-require-effective-target fpic } */ + +extern __thread int tls_var; + +void +test_vector_reg_clobber (void) +{ + __rvv_int32m1_t v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12; + + /* Write two v-regs. */ + asm volatile ("# def v1" : "=vr"(v1)); + asm volatile ("# def v2" : "=vr"(v2)); + asm volatile ("# def v3" : "=vr"(v3)); + asm volatile ("# def v4" : "=vr"(v4)); + asm volatile ("# def v5" : "=vr"(v5)); + asm volatile ("# def v6" : "=vr"(v6)); + asm volatile ("# def v7" : "=vr"(v7)); + asm volatile ("# def v8" : "=vr"(v8)); + asm volatile ("# def v9" : "=vr"(v9)); + asm volatile ("# def v10" : "=vr"(v10)); + asm volatile ("# def v11" : "=vr"(v11)); + asm volatile ("# def v12" : "=vr"(v12)); + + /* TLSDESC call — clobbers all vector regs. */ + asm volatile ("" ::: "memory"); /* Prevent scheduling... */ + tls_var = 1; + asm volatile ("" ::: "memory"); /* Prevent scheduling... */ + + /* Read the two v-regs; their live-range spans across the TLSDESC call, + so the compiler must emit vector store/load pairs to preserve them. */ + asm volatile ("# use v1" : : "vr"(v1)); + asm volatile ("# use v2" : : "vr"(v2)); + asm volatile ("# use v3" : : "vr"(v3)); + asm volatile ("# use v4" : : "vr"(v4)); + asm volatile ("# use v5" : : "vr"(v5)); + asm volatile ("# use v6" : : "vr"(v6)); + asm volatile ("# use v7" : : "vr"(v7)); + asm volatile ("# use v8" : : "vr"(v8)); + asm volatile ("# use v9" : : "vr"(v9)); + asm volatile ("# use v10" : : "vr"(v10)); + asm volatile ("# use v11" : : "vr"(v11)); + asm volatile ("# use v12" : : "vr"(v12)); +} + +/* { dg-final { scan-assembler-times {jalr\tt0,} 1 } } */ + +/* Vector stores before and loads after the TLSDESC call. */ +/* { dg-final { scan-assembler-times {\tvs[0-9]+r\.v\t} 12 } } */ +/* { dg-final { scan-assembler-times {\tvl[0-9]+re[0-9]+\.v\t} 12 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/tlsdesc_clobber_v_csr.c b/gcc/testsuite/gcc.target/riscv/tlsdesc_clobber_v_csr.c new file mode 100644 index 000000000000..ffb9c9a61a47 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/tlsdesc_clobber_v_csr.c @@ -0,0 +1,39 @@ +/* Verify that when the V extension is enabled, the TLSDESC resolver clobbers + vector CSRs (vl, vtype, vxrm, vxsat) per the psABI. The compiler must + re-emit a vsetvli after the TLSDESC call to recover the vector status. */ + +/* { dg-do compile } */ +/* { dg-require-effective-target tls_native } */ +/* { dg-options "-O2 -fpic -mtls-dialect=desc -march=rv64gcv -mabi=lp64d" } */ +/* { dg-require-effective-target fpic } */ + +typedef int v4si __attribute__ ((vector_size (16))); + +extern __thread int tls_var; + +void +test_vector_csr_clobber (v4si *in, v4si *out) +{ + v4si vec; + + /* A pair of local load/store whose live-range does not span accross + the TLSDESC. It has a special size format so it needs a vsetvli. */ + vec = *in; + *out = vec; + + /* TLSDESC call — clobbers all vector CSRs including vl/vtype. */ + asm volatile ("" ::: "memory"); /* Prevent scheduling... */ + tls_var = 1; + asm volatile ("" ::: "memory"); /* Prevent scheduling... */ + + /* Another pair of local load/store. But since TLSDESC clobbers vl/vtype, we + must re-emit a vsetvli here. */ + vec = *in; + *out = vec; +} + +/* { dg-final { scan-assembler-times {jalr\tt0,} 1 } } */ + +/* Two vsetvli: one before each vector segment. The second is needed because + TLSDESC clobbers vl/vtype. */ +/* { dg-final { scan-assembler-times {vsetvli|vsetivli} 2 } } */
