This fixes a bug originally reported at https://github.com/riscv/riscv-gcc/issues/115 where mixing -msave-restore and sibcall optimizations results in corrupted call-save registers, because we are restoring them from a different offset in the epilogue than they were saved in the prologue. The simple short term fix is to just disallow sibcall optimization when -msave-restore is used. Longer term we will want to write a more complex fix that tries to make them work together, but we haven't had time to try that yet.
Tested with rv64gc lp64d make check, there were no regressions. The new testcase works with the patch, and fails without the patch. 2018-01-08 Monk Chiang <sh.chian...@gmail.com> Kito Cheng <kito.ch...@gmail.com> gcc/ * config/riscv/riscv.c (machine_function::is_leaf): Remove field. (riscv_leaf_function_p): Delete. (riscv_function_ok_for_sibcall): Return false when TARGET_SAVE_RESTORE. 2018-01-08 Chih-Mao Chen <pkmx...@gmail.com> Monk Chiang <sh.chian...@gmail.com> gcc/testsuite/ * gcc.target/riscv/save-restore-1.c: New. --- gcc/config/riscv/riscv.c | 18 ++---------------- gcc/testsuite/gcc.target/riscv/save-restore-1.c | 25 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 16 deletions(-) create mode 100644 gcc/testsuite/gcc.target/riscv/save-restore-1.c diff --git a/gcc/config/riscv/riscv.c b/gcc/config/riscv/riscv.c index 0147c314b7a..c60c1c4f69f 100644 --- a/gcc/config/riscv/riscv.c +++ b/gcc/config/riscv/riscv.c @@ -127,9 +127,6 @@ struct GTY(()) machine_function { This area is allocated by the callee at the very top of the frame. */ int varargs_size; - /* Memoized return value of leaf_function_p. <0 if false, >0 if true. */ - int is_leaf; - /* The current frame information, calculated by riscv_compute_frame_info. */ struct riscv_frame_info frame; }; @@ -4176,26 +4173,15 @@ riscv_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value) emit_insn (gen_clear_cache (addr, end_addr)); } -/* Return leaf_function_p () and memoize the result. */ - -static bool -riscv_leaf_function_p (void) -{ - if (cfun->machine->is_leaf == 0) - cfun->machine->is_leaf = leaf_function_p () ? 1 : -1; - - return cfun->machine->is_leaf > 0; -} - /* Implement TARGET_FUNCTION_OK_FOR_SIBCALL. */ static bool riscv_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED, tree exp ATTRIBUTE_UNUSED) { - /* When optimzing for size, don't use sibcalls in non-leaf routines */ + /* Don't use sibcalls when use save-restore routine. */ if (TARGET_SAVE_RESTORE) - return riscv_leaf_function_p (); + return false; return true; } diff --git a/gcc/testsuite/gcc.target/riscv/save-restore-1.c b/gcc/testsuite/gcc.target/riscv/save-restore-1.c new file mode 100644 index 00000000000..35b08b96760 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/save-restore-1.c @@ -0,0 +1,25 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -msave-restore -fomit-frame-pointer" } */ + +#include <stdlib.h> + +__attribute__((noinline)) int g(void) { return 42; } + +__attribute__((noinline)) int f(void) { + asm volatile ("li s0, 0x87654321" ::: "s0"); + return g(); +} + +int main(void) { + asm volatile ("li s0, 0x12345678" ::: "s0"); + + f(); + + long s0; + asm volatile ("mv %0, s0" : "=r"(s0)); + + if (s0 == 0x12345678) + exit (0); + else + abort(); +} -- 2.14.1