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

Reply via email to