https://gcc.gnu.org/g:bfc82936d1ea078d21a58e063fd27022371ca3a3

commit r17-2468-gbfc82936d1ea078d21a58e063fd27022371ca3a3
Author: Jin Ma <[email protected]>
Date:   Sat Jul 11 22:45:54 2026 +0800

    RISC-V: Exclude t1 from SIBCALL_REGS
    
    RISCV_CALL_ADDRESS_TEMP and RISCV_PROLOGUE_TEMP2 both use t1.  An
    indirect sibcall target in t1 can therefore be overwritten by an RVV
    scalable-frame epilogue before the final jump.
    
    Exclude t1 from SIBCALL_REGS and map it to JALR_REGS.
    
    gcc/ChangeLog:
    
            * config/riscv/riscv.cc (riscv_regno_to_class): Map t1 to
            JALR_REGS.
            * config/riscv/riscv.h (RISCV_PROLOGUE_TEMP_REGNUM): Document
            the SIBCALL_REGS restriction.
            (REG_CLASS_CONTENTS): Remove t1 from SIBCALL_REGS.
    
    gcc/testsuite/ChangeLog:
    
            * g++.target/riscv/pr97682.C: Accept registers in SIBCALL_REGS.
            * gcc.target/riscv/rvv/base/sibcall-scalable-frame-indirect.c:
            New test.
            * gcc.target/riscv/rvv/base/sibcall-scalable-frame-weak.c: New test.

Diff:
---
 gcc/config/riscv/riscv.cc                          |  2 +-
 gcc/config/riscv/riscv.h                           | 11 ++++----
 gcc/testsuite/g++.target/riscv/pr97682.C           |  4 +--
 .../rvv/base/sibcall-scalable-frame-indirect.c     | 28 +++++++++++++++++++
 .../riscv/rvv/base/sibcall-scalable-frame-weak.c   | 32 ++++++++++++++++++++++
 5 files changed, 69 insertions(+), 8 deletions(-)

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 55567cb281f7..596145ca19c1 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -346,7 +346,7 @@ bool riscv_registering_builtins;
 /* Index R is the smallest register class that contains register R.  */
 const enum reg_class riscv_regno_to_class[FIRST_PSEUDO_REGISTER] = {
   GR_REGS,     GR_REGS,        GR_REGS,        GR_REGS,
-  GR_REGS,     GR_REGS,        SIBCALL_REGS,   SIBCALL_REGS,
+  GR_REGS,     GR_REGS,        JALR_REGS,      SIBCALL_REGS,
   JALR_REGS,   JALR_REGS,      SIBCALL_REGS,   SIBCALL_REGS,
   SIBCALL_REGS,        SIBCALL_REGS,   SIBCALL_REGS,   SIBCALL_REGS,
   SIBCALL_REGS,        SIBCALL_REGS,   JALR_REGS,      JALR_REGS,
diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h
index 7eb85d654a7e..4ba6ad260e55 100644
--- a/gcc/config/riscv/riscv.h
+++ b/gcc/config/riscv/riscv.h
@@ -430,10 +430,11 @@ ARCH_UNSET_CLEANUP_SPECS \
 
 /* Registers used as temporaries in prologue/epilogue code.
 
-   The prologue registers mustn't conflict with any
-   incoming arguments, the static chain pointer, or the frame pointer.
-   The epilogue temporary mustn't conflict with the return registers,
-   the frame pointer, the EH stack adjustment, or the EH data registers. */
+   The prologue temporaries mustn't conflict with any incoming arguments,
+   the static chain pointer, or the frame pointer.
+   The epilogue temporaries mustn't conflict with the return registers,
+   the frame pointer, the EH stack adjustment, the EH data registers, or
+   any register in SIBCALL_REGS.  */
 
 #define RISCV_PROLOGUE_TEMP_REGNUM (GP_TEMP_FIRST)
 #define RISCV_PROLOGUE_TEMP(MODE) gen_rtx_REG (MODE, 
RISCV_PROLOGUE_TEMP_REGNUM)
@@ -572,7 +573,7 @@ enum reg_class
 #define REG_CLASS_CONTENTS                                             \
 {                                                                      \
   { 0x00000000, 0x00000000, 0x00000000, 0x00000000 },  /* NO_REGS */           
\
-  { 0xf003fcc0, 0x00000000, 0x00000000, 0x00000000 },  /* SIBCALL_REGS */      
\
+  { 0xf003fc80, 0x00000000, 0x00000000, 0x00000000 },  /* SIBCALL_REGS */      
\
   { 0x0000ff00, 0x00000000, 0x00000000, 0x00000000 },  /* RVC_GR_REGS */       
\
   { 0xffffffc0, 0x00000000, 0x00000000, 0x00000000 },  /* JALR_REGS */         
\
   { 0xffffffff, 0x00000000, 0x00000000, 0x00000000 },  /* GR_REGS */           
\
diff --git a/gcc/testsuite/g++.target/riscv/pr97682.C 
b/gcc/testsuite/g++.target/riscv/pr97682.C
index 68e332a9993d..2c68507f467a 100644
--- a/gcc/testsuite/g++.target/riscv/pr97682.C
+++ b/gcc/testsuite/g++.target/riscv/pr97682.C
@@ -156,5 +156,5 @@ namespace llvm
   void bm::bl() { bk->bl(); }
 }
 
-/* The t1 register is to initial symbol reference for call instruction.  */
-/* { dg-final { scan-assembler "la\tt1,.*FrequencyData.*_M_default_append.*" } 
} */
+/* A register in SIBCALL_REGS is used for the call address.  */
+/* { dg-final { scan-assembler 
{la\t(t[2-6]|a[0-7]),.*FrequencyData.*_M_default_append.*} } } */
diff --git 
a/gcc/testsuite/gcc.target/riscv/rvv/base/sibcall-scalable-frame-indirect.c 
b/gcc/testsuite/gcc.target/riscv/rvv/base/sibcall-scalable-frame-indirect.c
new file mode 100644
index 000000000000..1cc1dda3bc01
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/sibcall-scalable-frame-indirect.c
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=rv64gcv -mabi=lp64d" } */
+
+#include <riscv_vector.h>
+
+typedef int (*fn_t) (int);
+
+int __attribute__ ((noinline))
+victim (float *p, int n, fn_t fn)
+{
+  register fn_t target asm ("t1") = fn;
+
+  size_t vl = __riscv_vsetvl_e32m4 (n);
+  volatile vfloat32m4_t v0 = __riscv_vle32_v_f32m4 (p, vl);
+  volatile vfloat32m4_t v1 = __riscv_vle32_v_f32m4 (p + vl, vl);
+  vfloat32m4_t x0 = v0;
+  vfloat32m4_t x1 = v1;
+
+  x0 = __riscv_vfadd_vv_f32m4 (x0, x1, vl);
+  __riscv_vse32_v_f32m4 (p, x0, vl);
+  asm volatile ("" : "+r" (target));
+
+  return target (n);
+}
+
+/* { dg-final { scan-assembler {csrr\t[^,]+,vlenb} } } */
+/* { dg-final { scan-assembler {\tjr\t(t[2-6]|a[0-7])\n} } } */
+/* { dg-final { scan-assembler-not {\tjr\tt[01]\n} } } */
diff --git 
a/gcc/testsuite/gcc.target/riscv/rvv/base/sibcall-scalable-frame-weak.c 
b/gcc/testsuite/gcc.target/riscv/rvv/base/sibcall-scalable-frame-weak.c
new file mode 100644
index 000000000000..24136ce06c47
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/sibcall-scalable-frame-weak.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fPIC -march=rv64gcv -mabi=lp64d" } */
+
+#include <riscv_vector.h>
+
+extern int wrap (int (*)(int), int) __attribute__ ((weak));
+
+static int __attribute__ ((noinline))
+kernel (int x)
+{
+  return x + 1;
+}
+
+int __attribute__ ((noinline))
+victim (float *p, int n)
+{
+  size_t vl = __riscv_vsetvl_e32m4 (n);
+  volatile vfloat32m4_t v0 = __riscv_vle32_v_f32m4 (p, vl);
+  volatile vfloat32m4_t v1 = __riscv_vle32_v_f32m4 (p + vl, vl);
+  vfloat32m4_t x0 = v0;
+  vfloat32m4_t x1 = v1;
+
+  x0 = __riscv_vfadd_vv_f32m4 (x0, x1, vl);
+  __riscv_vse32_v_f32m4 (p, x0, vl);
+
+  return wrap (kernel, n);
+}
+
+/* { dg-final { scan-assembler "wrap" } } */
+/* { dg-final { scan-assembler {csrr\t[^,]+,vlenb} } } */
+/* { dg-final { scan-assembler {\tjr\t(t[2-6]|a[0-7])\n} } } */
+/* { dg-final { scan-assembler-not {\tjr\tt[01]\n} } } */

Reply via email to