https://gcc.gnu.org/g:6c9258271e44b8662ed15ee6e9847eb3cdebfd83

commit 6c9258271e44b8662ed15ee6e9847eb3cdebfd83
Author: Tsukasa OI <[email protected]>
Date:   Tue Sep 9 01:51:18 2025 +0000

    RISC-V: Suppress cross CC sibcall optimization from vector
    
    In general, tail call optimization requires that the callee's saved
    registers are a superset of the caller's.
    
    The Standard Vector Calling Convention Variant (assembler: .variant_cc)
    requires that a function with this calling convention preserves vector
    registers v1-v7 and v24-v31 across calls (i.e. callee-saved).  However,
    the same set of registers are (function-local) temporary registers
    (i.e. caller-saved) on the normal (non-vector) calling convention.
    
    Even if a function with this calling convention variant calls another
    function with a non-vector calling convention, those vector registers
    are correctly clobbered -- except when the sibling (tail) call
    optimization occurs as it violates the general rule mentioned above.
    
    If this happens, following function body:
    
    1.  Save v1-v7 and v24-v31 for clobbering
    2.  Call another function with a non-vector calling convention
        (which may destroy v1-v7 and/or v24-v31)
    3.  Restore v1-v7 and v24-v31
    4.  Return.
    
    may be incorrectly optimized into the following sequence:
    
    1.  Save v1-v7 and v24-v31 for clobbering
    2.  Restore v1-v7 and v24-v31 (?!)
    3.  Jump to another function with a non-vector calling convention
        (which may destroy v1-v7 and/or v24-v31).
    
    This commit suppresses cross CC sibling call optimization from
    the vector calling convention variant.
    
    gcc/ChangeLog:
    
            * config/riscv/riscv.cc (riscv_function_ok_for_sibcall):
            Suppress cross calling convention sibcall optimization from
            the vector calling convention variant.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.target/riscv/rvv/base/abi-call-variant_cc-sibcall.c: New test.
            * 
gcc.target/riscv/rvv/base/abi-call-variant_cc-sibcall-indirect-1.c: Ditto.
            * 
gcc.target/riscv/rvv/base/abi-call-variant_cc-sibcall-indirect-2.c: Ditto.
    
    (cherry picked from commit ebd64a42512e53eb2f0b4169f2d68f3c6c5f23a8)

Diff:
---
 gcc/config/riscv/riscv.cc                          |  6 +++
 .../base/abi-call-variant_cc-sibcall-indirect-1.c  | 12 +++++
 .../base/abi-call-variant_cc-sibcall-indirect-2.c  | 12 +++++
 .../riscv/rvv/base/abi-call-variant_cc-sibcall.c   | 54 ++++++++++++++++++++++
 4 files changed, 84 insertions(+)

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 6083f81618bf..228571f2b3f5 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -11994,6 +11994,12 @@ riscv_function_ok_for_sibcall (tree decl 
ATTRIBUTE_UNUSED,
   if (cfun->machine->interrupt_handler_p)
     return false;
 
+  /* Don't use sibcall if a non-vector CC function is being called
+     from a vector CC function.  */
+  if ((riscv_cc) crtl->abi->id () == RISCV_CC_V
+      && (riscv_cc) expr_callee_abi (exp).id () != RISCV_CC_V)
+    return false;
+
   /* Don't use sibcalls in the large model, because a sibcall instruction
      expanding and a epilogue expanding both use RISCV_PROLOGUE_TEMP
      register.  */
diff --git 
a/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-variant_cc-sibcall-indirect-1.c
 
b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-variant_cc-sibcall-indirect-1.c
new file mode 100644
index 000000000000..54ff106716f8
--- /dev/null
+++ 
b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-variant_cc-sibcall-indirect-1.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d -O2" } */
+
+void __attribute__((riscv_vector_cc))
+f_try_sibcall_v2v_indirect (void __attribute__((riscv_vector_cc))
+                           (*func) (void))
+{
+  func ();
+}
+
+/* { dg-final { scan-assembler-times 
"\\.variant_cc\tf_try_sibcall_v2v_indirect\n" 1 } } */
+/* { dg-final { scan-assembler-times "\tjr\ta0\n" 1 } } */
diff --git 
a/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-variant_cc-sibcall-indirect-2.c
 
b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-variant_cc-sibcall-indirect-2.c
new file mode 100644
index 000000000000..121ac0f57e0a
--- /dev/null
+++ 
b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-variant_cc-sibcall-indirect-2.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d -O2" } */
+
+void __attribute__((riscv_vector_cc))
+f_try_sibcall_v2n_indirect (void (*func) (void))
+{
+  func ();
+}
+
+/* { dg-final { scan-assembler-times 
"\\.variant_cc\tf_try_sibcall_v2n_indirect\n" 1 } } */
+/* { dg-final { scan-assembler-times "\tjalr\ta0\n" 1 } } */
+/* { dg-final { scan-assembler-times "\tjr\tra\n" 1 } } */
diff --git 
a/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-variant_cc-sibcall.c 
b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-variant_cc-sibcall.c
new file mode 100644
index 000000000000..ccfc38777f49
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-variant_cc-sibcall.c
@@ -0,0 +1,54 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d -O2" } */
+
+void f_ext_n2n (void);
+void f_ext_v2n (void);
+void __attribute__((riscv_vector_cc)) f_ext_n2v (void);
+void __attribute__((riscv_vector_cc)) f_ext_v2v (void);
+
+/* { dg-final { scan-assembler-times "\\.variant_cc\tf_ext_n2n\n" 0 } } */
+/* { dg-final { scan-assembler-times "\\.variant_cc\tf_ext_v2n\n" 0 } } */
+/* { dg-final { scan-assembler-times "\\.variant_cc\tf_ext_n2v\n" 1 } } */
+/* { dg-final { scan-assembler-times "\\.variant_cc\tf_ext_v2v\n" 1 } } */
+
+void
+f_try_sibcall_n2n (void)
+{
+  f_ext_n2n ();
+}
+
+/* { dg-final { scan-assembler-times "\\.variant_cc\tf_try_sibcall_n2n\n" 0 } 
} */
+/* { dg-final { scan-assembler-times "\ttail\tf_ext_n2n\n" 1 } } */
+/* { dg-final { scan-assembler-times "\tcall\tf_ext_n2n\n" 0 } } */
+
+void
+f_try_sibcall_n2v (void)
+{
+  f_ext_n2v ();
+}
+
+/* { dg-final { scan-assembler-times "\\.variant_cc\tf_try_sibcall_n2v\n" 0 } 
} */
+/* { dg-final { scan-assembler-times "\ttail\tf_ext_n2v\n" 1 } } */
+/* { dg-final { scan-assembler-times "\tcall\tf_ext_n2v\n" 0 } } */
+
+void __attribute__((riscv_vector_cc))
+f_try_sibcall_v2n (void)
+{
+  /* Vector to normal: sibling call optimization shall be
+     suppressed to preserve caller's registers: v1-v7 and v24-v31.  */
+  f_ext_v2n ();
+}
+
+/* { dg-final { scan-assembler-times "\\.variant_cc\tf_try_sibcall_v2n\n" 1 } 
} */
+/* { dg-final { scan-assembler-times "\ttail\tf_ext_v2n\n" 0 } } */
+/* { dg-final { scan-assembler-times "\tcall\tf_ext_v2n\n" 1 } } */
+
+void __attribute__((riscv_vector_cc))
+f_try_sibcall_v2v (void)
+{
+  f_ext_v2v ();
+}
+
+/* { dg-final { scan-assembler-times "\\.variant_cc\tf_try_sibcall_v2v\n" 1 } 
} */
+/* { dg-final { scan-assembler-times "\ttail\tf_ext_v2v\n" 1 } } */
+/* { dg-final { scan-assembler-times "\tcall\tf_ext_v2v\n" 0 } } */

Reply via email to