RISCV_CALL_ADDRESS_TEMP and RISCV_PROLOGUE_TEMP2 both resolve to x6/t1.
When a weak-symbol indirect sibcall materializes the target address into
t1 and the function has an RVV scalable frame, the epilogue overwrites
t1 with vlenb*N before the final jump.

Fix by constructing SIBCALL_REGS dynamically from JALR_REGS, excluding
fixed and callee-saved GPRs, and additionally t1 under TARGET_VECTOR.
Reject sibcall when no safe target register (t4-t6) is available.

gcc/ChangeLog:

        * config/riscv/riscv.cc (riscv_conditional_register_usage):
        Construct SIBCALL_REGS dynamically; exclude t1 under TARGET_VECTOR.
        (riscv_sibcall_has_safe_target_reg_p): New.
        (riscv_function_ok_for_sibcall): Reject when no safe reg available.

gcc/testsuite/ChangeLog:

        * gcc.target/riscv/rvv/base/sibcall-scalable-frame-weak.c: New.
        * gcc.target/riscv/rvv/base/sibcall-no-safe-reg.c: New.
        * gcc.target/riscv/rvv/base/sibcall-ffixed-t4.c: New.
        * gcc.target/riscv/rvv/base/sibcall-weak-no-vector.c: New.
---
 gcc/config/riscv/riscv.cc                     | 28 +++++++++++++++++++
 .../riscv/rvv/base/sibcall-ffixed-t4.c        | 13 +++++++++
 .../riscv/rvv/base/sibcall-no-safe-reg.c      | 14 ++++++++++
 .../rvv/base/sibcall-scalable-frame-weak.c    | 27 ++++++++++++++++++
 .../riscv/rvv/base/sibcall-weak-no-vector.c   | 14 ++++++++++
 5 files changed, 96 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/sibcall-ffixed-t4.c
 create mode 100644 
gcc/testsuite/gcc.target/riscv/rvv/base/sibcall-no-safe-reg.c
 create mode 100644 
gcc/testsuite/gcc.target/riscv/rvv/base/sibcall-scalable-frame-weak.c
 create mode 100644 
gcc/testsuite/gcc.target/riscv/rvv/base/sibcall-weak-no-vector.c

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 873defc5a5b..3121c21f961 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -12447,6 +12447,17 @@ riscv_conditional_register_usage (void)
       fixed_regs[VXRM_REGNUM] = call_used_regs[VXRM_REGNUM] = 1;
       fixed_regs[FRM_REGNUM] = call_used_regs[FRM_REGNUM] = 1;
     }
+
+  /* SIBCALL_REGS: only caller-saved, non-fixed GPRs.  */
+  reg_class_contents[SIBCALL_REGS] = reg_class_contents[JALR_REGS];
+  for (int regno = GP_REG_FIRST; regno <= GP_REG_LAST; ++regno)
+    if (fixed_regs[regno] || !call_used_regs[regno])
+      CLEAR_HARD_REG_BIT (reg_class_contents[SIBCALL_REGS], regno);
+
+  /* Scalable-frame epilogue clobbers PROLOGUE_TEMP2 (t1).  */
+  if (TARGET_VECTOR)
+    CLEAR_HARD_REG_BIT (reg_class_contents[SIBCALL_REGS],
+                       RISCV_PROLOGUE_TEMP2_REGNUM);
 }
 
 /* Return a register priority for hard reg REGNO.  */
@@ -12670,6 +12681,19 @@ riscv_trampoline_init (rtx m_tramp, tree fndecl, rtx 
chain_value)
   emit_insn (gen_clear_cache (addr, end_addr));
 }
 
+/* Check that t4-t6 (x29-x31) has at least one usable sibcall target reg.
+   These are not clobbered by epilogue (t0/t1), static chain (t2),
+   Zicfilp (t2/t3), or vector stack-clash CFA (t3).  */
+
+static bool
+riscv_sibcall_has_safe_target_reg_p (void)
+{
+  for (int regno = GP_REG_FIRST + 29; regno <= GP_REG_FIRST + 31; ++regno)
+    if (TEST_HARD_REG_BIT (reg_class_contents[SIBCALL_REGS], regno))
+      return true;
+  return false;
+}
+
 /* Implement TARGET_FUNCTION_OK_FOR_SIBCALL.  */
 
 static bool
@@ -12700,6 +12724,10 @@ riscv_function_ok_for_sibcall (tree decl 
ATTRIBUTE_UNUSED,
   if (riscv_cmodel == CM_LARGE)
     return false;
 
+  /* Need an epilogue-safe indirect sibcall target register.  */
+  if (!riscv_sibcall_has_safe_target_reg_p ())
+    return false;
+
   return true;
 }
 
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/sibcall-ffixed-t4.c 
b/gcc/testsuite/gcc.target/riscv/rvv/base/sibcall-ffixed-t4.c
new file mode 100644
index 00000000000..8a26080c1c6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/sibcall-ffixed-t4.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fPIC -march=rv64gcv -mabi=lp64d -ffixed-t4" } */
+/* Under TARGET_VECTOR, t1 is excluded from SIBCALL_REGS.  */
+
+extern int callee (int) __attribute__((weak));
+
+int
+caller (int x)
+{
+  return callee (x);
+}
+
+/* { dg-final { scan-assembler-not "jr\tt1" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/sibcall-no-safe-reg.c 
b/gcc/testsuite/gcc.target/riscv/rvv/base/sibcall-no-safe-reg.c
new file mode 100644
index 00000000000..872e1998d6c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/sibcall-no-safe-reg.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fPIC -march=rv64gcv -mabi=lp64d -ffixed-t4 -ffixed-t5 
-ffixed-t6" } */
+/* No epilogue-safe register: sibcall must degrade to regular call.  */
+
+extern int callee (int) __attribute__((weak));
+
+int
+caller (int x)
+{
+  return callee (x);
+}
+
+/* Regular call saves ra; sibcall does not.  */
+/* { dg-final { scan-assembler "sd\tra" } } */
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 00000000000..b59844ae69f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/sibcall-scalable-frame-weak.c
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fPIC -march=rv64gcv_zfh_zvfh -mabi=lp64d" } */
+/* Weak indirect sibcall must not lose the target symbol when an RVV
+   scalable frame is present.  */
+
+#include <riscv_vector.h>
+
+extern int kernel (int) __attribute__((noinline));
+extern int wrap (int (*)(int), int) __attribute__((weak));
+int kernel (int x) { return x + 1; }
+
+int __attribute__((noinline))
+victim (float *p, int n, int flag)
+{
+  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);
+  if (flag)
+    return wrap (kernel, n);
+  return n;
+}
+
+/* { dg-final { scan-assembler "wrap" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/sibcall-weak-no-vector.c 
b/gcc/testsuite/gcc.target/riscv/rvv/base/sibcall-weak-no-vector.c
new file mode 100644
index 00000000000..d64ee563872
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/sibcall-weak-no-vector.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fPIC -march=rv64gc -mabi=lp64d" } */
+/* Without vector: weak sibcall behaviour unchanged.  */
+
+extern int callee (int) __attribute__((weak));
+
+int
+caller (int x)
+{
+  return callee (x);
+}
+
+/* { dg-final { scan-assembler "jr\t" } } */
+/* { dg-final { scan-assembler "callee" } } */
-- 
2.52.0

Reply via email to