Hi Kito,
Sorry it's my fault for not testing thoroughly :( I just used fuzzer tool today 
to generate a large integration test and happened to found this issue.
And yes, thanks for noticing that and RVVM1QI works for me! I will post another 
patch very soon (and append my reduction test to it as well)
Thank you very much!
Best,
Luke Zhuang
------------------------------------------------------------------
From:Kito Cheng <[email protected]>
Send Time:Wed, Jul 15, 2026, 18:50
To:Luke Zhuang<[email protected]>
CC:"jeffrey.law"<[email protected]>; 
"rdapp.gcc"<[email protected]>; "gcc-patches"<[email protected]>; 
palmer<[email protected]>; andrew<[email protected]>; 
"jim.wilson.gcc"<[email protected]>; 
"juzhe.zhong"<[email protected]>; rdsandiford<[email protected]>; 
"zhuangzhi.zz"<[email protected]>
Subject:Re: [PATCH v4] RISC-V: Declare TLSDESC clobbers for vector registers 
and CSRs per psABI
Hi Luke
Seems like it's a potential bug in LRA, and can be workaround by use
RVVM1QI, could you send a patch for that?
And we may fix that on LRA later...
Kito Cheng <[email protected]> 於 2026年7月15日週三 下午5:34寫道:
>
> oops, I just pushed before I saw this mail, let me try to triage the
> issue to see if we can found a right fix for that issue
>
> Luke Zhuang <[email protected]> 於 2026年7月15日週三 下午3:08寫道:
> >
> > Hi Jeff/Kito/Robin,
> > Sorry I just found a fatal crash of this implementation myself, this small 
> > test case:
> > ```
> > extern __thread int x;
> > extern int bar(int);
> > int f(int id) {
> > x = id * 1000;
> > bar(0);
> > if (x != id * 1000) return bar(x);
> > return 0;
> > }
> > ```
> > crashes with this command: `cc1 -quiet -imultilib . test.c -quiet -dumpbase 
> > a.c -dumpbase-ext .c -march=rv64gcv -mtls-dialect=desc -mtune=generic-ooo 
> > -mabi=lp64d 
> > -march=rv64imafdcv_zicsr_zifencei_zmmul_zaamo_zalrsc_zca_zcd_zve32f_zve32x_zve64d_zve64f_zve64x_zvl128b_zvl32b_zvl64b
> >  -O -fPIC -o test.o`
> > It crashes in LRA process in lra-constraints.cc:6689 here:
> > ```
> > static inline bool
> > need_for_split_p (HARD_REG_SET potential_reload_hard_regs, int regno)
> > {
> > int hard_regno = regno < FIRST_PSEUDO_REGISTER ? regno : 
> > reg_renumber[regno];
> > lra_assert (hard_regno >= 0);
> > ```
> > Looks like a huge clobber set of a non-call insn makes LRA harder to do 
> > spilling (maybe a potential bug in LRA instead of the implementation 
> > itself, not sure)
> >
> > My current opinion is falling back to my first edition: 
> > https://gcc.gnu.org/pipermail/gcc-patches/2026-June/721254.html 
> > <https://gcc.gnu.org/pipermail/gcc-patches/2026-June/721254.html >, which 
> > models TLSDESC as a real call and matches what aarch64 did in <bb6ce448>. 
> > While there's also a small issue: a real call always clobbers `ra` and may 
> > result in one more spilling in some circumstances (maybe not a big problem).
> > May I ask what do you think?
> >
> > Thank you very much!
> >
> > Best,
> > Luke Zhuang
> >
> > ------------------------------------------------------------------
> > From:Kito Cheng <[email protected]>
> > Send Time:Thu, Jul 2, 2026, 07:38
> > To:Luke Zhuang<[email protected]>
> > CC:"gcc-patches"<[email protected]>; palmer<[email protected]>; 
> > "rdapp.gcc"<[email protected]>; andrew<[email protected]>; 
> > "jim.wilson.gcc"<[email protected]>; 
> > "juzhe.zhong"<[email protected]>; 
> > rdsandiford<[email protected]>; 
> > "jeffrey.law"<[email protected]>; 
> > "zhuangzhi.zz"<[email protected]>
> > Subject:Re: [PATCH v4] RISC-V: Declare TLSDESC clobbers for vector 
> > registers and CSRs per psABI
> >
> > LGTM :)
> >
> > Luke Zhuang <[email protected]>於 2026年7月2日週四,00:02寫道:
> > gentle ping :)
> >
> > Luke Zhuang
> >
> > ------------------------------------------------------------------
> > From:Luke Zhuang <[email protected]>
> > Send Time:Thu, Jun 25, 2026, 13:45
> > To:"gcc-patches"<[email protected]>
> > CC:"kito.cheng"<[email protected]>; palmer<[email protected]>; 
> > "rdapp.gcc"<[email protected]>; andrew<[email protected]>; 
> > "jim.wilson.gcc"<[email protected]>; 
> > "juzhe.zhong"<[email protected]>; 
> > rdsandiford<[email protected]>; 
> > "jeffrey.law"<[email protected]>; 
> > "zhuangzhi.zz"<[email protected]>; Luke 
> > Zhuang<[email protected]>
> > Subject:[PATCH v4] RISC-V: Declare TLSDESC clobbers for vector registers 
> > and CSRs per psABI
> >
> > From: "Luke Zhuang" <[email protected]>
> >
> > 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 
> > <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 | 11 +++-
> > .../gcc.target/riscv/tlsdesc_clobber.c | 29 ++++++++++
> > .../gcc.target/riscv/tlsdesc_clobber_v.c | 56 +++++++++++++++++++
> > .../gcc.target/riscv/tlsdesc_clobber_v_csr.c | 39 +++++++++++++
> > 4 files changed, 134 insertions(+), 1 deletion(-)
> > create mode 100644 gcc/testsuite/gcc.target/riscv/tlsdesc_clobber.c
> > create mode 100644 gcc/testsuite/gcc.target/riscv/tlsdesc_clobber_v.c
> > create mode 100644 gcc/testsuite/gcc.target/riscv/tlsdesc_clobber_v_csr.c
> >
> > diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
> > index b90bfe0745a..d3cddacb566 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 00000000000..6a004d6820f
> > --- /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 00000000000..a5fb350f76e
> > --- /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 00000000000..ffb9c9a61a4
> > --- /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 } } */
> > --
> > 2.47.1

Reply via email to