This patch fixes wrong code when a noreturn function is compiled
with -mcall-prologues and the function gets arguments on the stack.
The bug is that prologue_saves saves more registers than calculated
by avr_regs_to_save() so that the argument pointer is wrong.

The fix is to behave like avr_regs_to_save(), i.e. don't save any
regs in a noreturn function so that prologue_saves is not used.

Ok to apply?

Johann

--
        PR target/127482
gcc/
        * config/avr/avr.cc (sequent_regs_live): Return 0 for
        noreturn functions, OS_task and OS_main.
        (avr_prologue_setup_frame, avr_expand_epilogue) <minimize>: Move
        OS_task and OS_main tests to sequent_regs_live.
gcc/testsuite/
        * gcc.target/avr/torture/pr127482.c: New test.
diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc
index 5c51e0d26cf..58cd25b60a7 100644
--- a/gcc/config/avr/avr.cc
+++ b/gcc/config/avr/avr.cc
@@ -1357,6 +1357,12 @@ avr_simple_epilogue (void)
 static int
 sequent_regs_live (void)
 {
+  // Behave according to avr_regs_to_save().
+  if (TREE_THIS_VOLATILE (current_function_decl)
+      || cfun->machine->is_OS_task
+      || cfun->machine->is_OS_main)
+    return 0;
+
   int live_seq = 0;
   int cur_seq = 0;
 
@@ -1536,8 +1542,6 @@ avr_prologue_setup_frame (HOST_WIDE_INT size, HARD_REG_SET set)
 		   && size < size_max
 		   && live_seq
 		   && !isr_p
-		   && !cfun->machine->is_OS_task
-		   && !cfun->machine->is_OS_main
 		   && !AVR_TINY);
 
   if (minimize
@@ -2062,8 +2066,6 @@ avr_expand_epilogue (bool sibcall_p)
   bool minimize = (TARGET_CALL_PROLOGUES
 		   && live_seq
 		   && !isr_p
-		   && !cfun->machine->is_OS_task
-		   && !cfun->machine->is_OS_main
 		   && !AVR_TINY);
 
   if (minimize
diff --git a/gcc/testsuite/gcc.target/avr/torture/pr127482.c b/gcc/testsuite/gcc.target/avr/torture/pr127482.c
new file mode 100644
index 00000000000..0c02d5c05c0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/torture/pr127482.c
@@ -0,0 +1,31 @@
+/* { dg-do run } */
+/* { dg-additional-options "-mcall-prologues" } */
+
+#include <stdarg.h>
+#include <stdlib.h>
+
+#define NI __attribute((noipa))
+
+NI void xx_fun (void) {}
+NI void xx_vprintf (const char *fmt, va_list args)
+{
+  int i = va_arg (args, int);
+  if (i != 0x1234)
+    exit (10);
+}
+
+void error (const char *msg, ...)
+{
+  va_list args;
+  xx_fun ();
+  va_start (args, msg);
+  xx_vprintf (msg, args);
+  va_end (args);
+  exit (0);
+}
+
+int main (void)
+{
+  error ("bad %d\n", 0x1234);
+  return 0;
+}

Reply via email to