> -(define_insn "@tlsdesc<mode>"
> +(define_expand "@tlsdesc<mode>"
> +  [(unspec:P [(match_operand:P 0 "symbolic_operand" "")]
> +            UNSPEC_TLSDESC)]
> +  "TARGET_TLSDESC"
> +{
> +  if (TARGET_VECTOR)
> +    emit_insn (gen_tlsdesc_vec<mode> (operands[0]));

Just always use tlsdesc_vec's one should be fine, extra clobber for
non-available register is harmless :)

> +  else
> +    emit_insn (gen_tlsdesc_base<mode> (operands[0]));
> +  DONE;
> +})
> +
> +;; Base TLSDESC: clobbers a0 and t0 only (no V extension).
> +(define_insn "tlsdesc_base<mode>"
>    [(set (reg:P A0_REGNUM)
> -       (unspec:P
> -           [(match_operand:P 0 "symbolic_operand" "")]
> -           UNSPEC_TLSDESC))
> +       (unspec:P [(match_operand:P 0 "symbolic_operand" "")]
> +                 UNSPEC_TLSDESC))
>     (clobber (reg:P T0_REGNUM))]
> -  "TARGET_TLSDESC"
> +  "TARGET_TLSDESC && !TARGET_VECTOR"
> +  {
> +    return ".LT%=: auipc\ta0,%%tlsdesc_hi(%0)\;"
> +           "<load>\tt0,%%tlsdesc_load_lo(.LT%=)(a0)\;"
> +           "addi\ta0,a0,%%tlsdesc_add_lo(.LT%=)\;"
> +           "jalr\tt0,t0,%%tlsdesc_call(.LT%=)";
> +  }
> +  [(set_attr "type" "multi")
> +   (set_attr "length" "16")
> +   (set_attr "mode" "<MODE>")])
> +
> +;; TLSDESC with V extension: additionally clobbers all 32 vector registers
> +;; (using LMUL=8 groups: v0, v8, v16, v24 each cover 8 physical registers)
> +;; and vector CSRs (vl, vtype, vxrm, vxsat) per the psABI.
> +(define_insn "tlsdesc_vec<mode>"
> +  [(set (reg:P A0_REGNUM)
> +       (unspec:P [(match_operand:P 0 "symbolic_operand" "")]
> +                 UNSPEC_TLSDESC))
> +   (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 && TARGET_VECTOR"
>    {
>      return ".LT%=: auipc\ta0,%%tlsdesc_hi(%0)\;"
>             "<load>\tt0,%%tlsdesc_load_lo(.LT%=)(a0)\;"
> 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