[gcc r16-9492] RISC-V: Exclude t1 from SIBCALL_REGS

Jeff Law via Gcc-cvs <[email protected]> Tue, 4 Aug 2026 00:26:18 +0000 (GMT)
Newsgroups gmane.comp.gcc.cvs
Message-ID <[email protected]>
https://gcc.gnu.org/g:b6e36ee233bf2d75ea427fd46304161954f2f70b

commit r16-9492-gb6e36ee233bf2d75ea427fd46304161954f2f70b
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.
    
    (cherry picked from commit bfc82936d1ea078d21a58e063fd27022371ca3a3)

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 8a39c791c26d..7ca36b5803a8 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -362,7 +362,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 26e5e7cd64a0..72d1c5f63a64 100644
--- a/gcc/config/riscv/riscv.h
+++ b/gcc/config/riscv/riscv.h
@@ -426,10 +426,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)
@@ -568,7 +569,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 03c7a447de59..453980994df5 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} } } */