From: Tsukasa OI <research_tra...@irq.a4lg.com> 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. --- gcc/config/riscv/riscv.cc | 6 +++ .../abi-call-variant_cc-sibcall-indirect-1.c | 12 +++++ .../abi-call-variant_cc-sibcall-indirect-2.c | 12 +++++ .../rvv/base/abi-call-variant_cc-sibcall.c | 54 +++++++++++++++++++ 4 files changed, 84 insertions(+) create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-variant_cc-sibcall-indirect-1.c create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-variant_cc-sibcall-indirect-2.c create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/abi-call-variant_cc-sibcall.c diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index bfd43fba1013..0dcc3029c6bf 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -11997,6 +11997,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 } } */ -- 2.43.0