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