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