]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
RISC-V: Declare TLSDESC clobbers for vector registers and CSRs per psABI
authorLuke Zhuang <luke.zhuang@linux.alibaba.com>
Thu, 25 Jun 2026 05:45:16 +0000 (13:45 +0800)
committerKito Cheng <kito.cheng@sifive.com>
Wed, 15 Jul 2026 09:29:14 +0000 (17:29 +0800)
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.

gcc/config/riscv/riscv.md
gcc/testsuite/gcc.target/riscv/tlsdesc_clobber.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/tlsdesc_clobber_v.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/tlsdesc_clobber_v_csr.c [new file with mode: 0644]

index f10a08460acfb3dc976c96348e0ac70c981324c3..c64e4ff3c77b9fdd80032a3a5cc28a9ca7471329 100644 (file)
    (VTYPE_REGNUM               67)
    (VXRM_REGNUM                        68)
    (FRM_REGNUM                 69)
+   (VXSAT_REGNUM               70)
 ])
 
 (include "predicates.md")
        (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 (file)
index 0000000..6a004d6
--- /dev/null
@@ -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 (file)
index 0000000..a5fb350
--- /dev/null
@@ -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 (file)
index 0000000..ffb9c9a
--- /dev/null
@@ -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 } } */