Hi,

It was discovered that with the attached test case compiled with -O2 
-funroll-loops,
the regrename pass renamed one of the registers ($2) to $8 that was not
saved by the prologue.

The attached patch fixes it by defining macro HARD_REGNO_RENAME_OK that returns
zero iff the current function is an interrupt handler and a register was never 
live.

Regression is still in progress. Ok to apply if it passes?

Regards,
Robert

gcc/
        * config/mips/mips-protos.h (mips_hard_regno_rename_ok): New prototype.
        * config/mips/mips.c (mips_hard_regno_rename_ok): New function.
        * config/mips/mips.h (HARD_REGNO_RENAME_OK): New.

gcc/testsuite/
        * gcc.target/mips/interrupt_handler-bug-1.c: New test.
---
 gcc/config/mips/mips-protos.h                           |  1 +
 gcc/config/mips/mips.c                                  | 14 ++++++++++++++
 gcc/config/mips/mips.h                                  |  3 +++
 gcc/testsuite/gcc.target/mips/interrupt_handler-bug-1.c | 12 ++++++++++++
 4 files changed, 30 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/mips/interrupt_handler-bug-1.c

diff --git a/gcc/config/mips/mips-protos.h b/gcc/config/mips/mips-protos.h
index 6ce3d70..e455553 100644
--- a/gcc/config/mips/mips-protos.h
+++ b/gcc/config/mips/mips-protos.h
@@ -317,6 +317,7 @@ extern unsigned int mips_sync_loop_insns (rtx, rtx *);
 extern const char *mips_output_division (const char *, rtx *);
 extern const char *mips_msa_output_division (const char *, rtx *);
 extern const char *mips_output_probe_stack_range (rtx, rtx);
+extern bool mips_hard_regno_rename_ok (unsigned int, unsigned int);
 extern unsigned int mips_hard_regno_nregs (int, machine_mode);
 extern bool mips_linked_madd_p (rtx, rtx);
 extern bool mips_store_data_bypass_p (rtx, rtx);
diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c
index a9829bd..151f774 100644
--- a/gcc/config/mips/mips.c
+++ b/gcc/config/mips/mips.c
@@ -12959,6 +12959,20 @@ mips_hard_regno_mode_ok_p (unsigned int regno, 
machine_mode mode)
   return false;
 }
 
+/* Return nonzero if register OLD_REG can be renamed to register NEW_REG.  */
+
+bool
+mips_hard_regno_rename_ok (unsigned int old_reg ATTRIBUTE_UNUSED,
+                          unsigned int new_reg)
+{
+  /* Interrupt functions can only use registers that have already been
+     saved by the prologue, even if they would normally be call-clobbered.  */
+  if (cfun->machine->interrupt_handler_p && !df_regs_ever_live_p (new_reg))
+    return false;
+
+  return true;
+}
+
 /* Implement HARD_REGNO_NREGS.  */
 
 unsigned int
diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h
index 6578ae5..3fe690a 100644
--- a/gcc/config/mips/mips.h
+++ b/gcc/config/mips/mips.h
@@ -1932,6 +1932,9 @@ struct mips_cpu_info {
 #define HARD_REGNO_MODE_OK(REGNO, MODE)                                        
\
   mips_hard_regno_mode_ok[ (int)(MODE) ][ (REGNO) ]
 
+#define HARD_REGNO_RENAME_OK(OLD_REG, NEW_REG)                         \
+  mips_hard_regno_rename_ok (OLD_REG, NEW_REG)
+
 /* Select a register mode required for caller save of hard regno REGNO.  */
 #define HARD_REGNO_CALLER_SAVE_MODE(REGNO, NREGS, MODE) \
   mips_hard_regno_caller_save_mode (REGNO, NREGS, MODE)
diff --git a/gcc/testsuite/gcc.target/mips/interrupt_handler-bug-1.c 
b/gcc/testsuite/gcc.target/mips/interrupt_handler-bug-1.c
new file mode 100644
index 0000000..877d00c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/interrupt_handler-bug-1.c
@@ -0,0 +1,12 @@
+/* { dg-options "-funroll-loops" } */
+int foo;
+int bar;
+
+void __attribute__ ((interrupt)) isr(void)
+{
+  if (!foo)
+   {
+      while (bar & 0xFF30);
+   }
+}
+/* { dg-final { scan-assembler-not "\\\$8" } } */
-- 
2.4.5

Reply via email to