From 3bd0817d1cc191f0d89d2fefa57bf108a53331f2 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 12 Sep 2011 19:25:59 +0000 Subject: [PATCH] mips.c (mips_epilogue): New structure. gcc/ 2011-09-11 Bernd Schmidt Richard Sandiford * config/mips/mips.c (mips_epilogue): New structure. (mips16e_save_restore_reg): Queue REG_CFA_RESTORE notes when restoring registers. (mips_epilogue_emit_cfa_restores): New function. (mips_epilogue_set_cfa): Likewise. (mips_restore_reg): Queue REG_CFA_RESTORE notes. When restoring the current CFA register from the stack, redefine the CFA in terms of the stack pointer. (mips_expand_epilogue): Set up mips_epilogue. Attach CFA information to the epilogue instructions. gcc/testsuite/ * gcc.target/mips/mips.exp (mips_option_groups): Add debug options. * gcc.target/mips/interrupt_handler-2.c: New test. * gcc.target/mips/interrupt_handler-3.c: Likewise. From-SVN: r178794 --- gcc/ChangeLog | 14 +++ gcc/config/mips/mips.c | 100 ++++++++++++++++-- gcc/testsuite/ChangeLog | 6 ++ .../gcc.target/mips/interrupt_handler-2.c | 14 +++ .../gcc.target/mips/interrupt_handler-3.c | 33 ++++++ gcc/testsuite/gcc.target/mips/mips.exp | 1 + 6 files changed, 160 insertions(+), 8 deletions(-) create mode 100644 gcc/testsuite/gcc.target/mips/interrupt_handler-2.c create mode 100644 gcc/testsuite/gcc.target/mips/interrupt_handler-3.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 29c86fb984d..48b4af76907 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,17 @@ +2011-09-12 Bernd Schmidt + Richard Sandiford + + * config/mips/mips.c (mips_epilogue): New structure. + (mips16e_save_restore_reg): Queue REG_CFA_RESTORE notes when + restoring registers. + (mips_epilogue_emit_cfa_restores): New function. + (mips_epilogue_set_cfa): Likewise. + (mips_restore_reg): Queue REG_CFA_RESTORE notes. When restoring + the current CFA register from the stack, redefine the CFA in terms + of the stack pointer. + (mips_expand_epilogue): Set up mips_epilogue. Attach CFA information + to the epilogue instructions. + 2011-09-12 Richard Sandiford * config/mips/mips.c (mips16e_save_restore_reg): Add a reg_parm_p diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index a5fed3dc89d..0c3b184bcb2 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -501,6 +501,21 @@ int sdb_label_count; int mips_dbx_regno[FIRST_PSEUDO_REGISTER]; int mips_dwarf_regno[FIRST_PSEUDO_REGISTER]; +/* Information about the current function's epilogue, used only while + expanding it. */ +static struct { + /* A list of queued REG_CFA_RESTORE notes. */ + rtx cfa_restores; + + /* The CFA is currently defined as CFA_REG + CFA_OFFSET. */ + rtx cfa_reg; + HOST_WIDE_INT cfa_offset; + + /* The offset of the CFA from the stack pointer while restoring + registers. */ + HOST_WIDE_INT cfa_restore_sp_offset; +} mips_epilogue; + /* The nesting depth of the PRINT_OPERAND '%(', '%<' and '%[' constructs. */ struct mips_asm_switch mips_noreorder = { "reorder", 0 }; struct mips_asm_switch mips_nomacro = { "macro", 0 }; @@ -8377,7 +8392,11 @@ mips16e_save_restore_reg (bool restore_p, bool reg_parm_p, mem = gen_frame_mem (SImode, plus_constant (stack_pointer_rtx, offset)); reg = gen_rtx_REG (SImode, regno); if (restore_p) - return gen_rtx_SET (VOIDmode, reg, mem); + { + mips_epilogue.cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, + mips_epilogue.cfa_restores); + return gen_rtx_SET (VOIDmode, reg, mem); + } if (reg_parm_p) return gen_rtx_SET (VOIDmode, mem, reg); return mips_frame_set (mem, reg); @@ -10222,7 +10241,47 @@ mips_expand_prologue (void) emit_insn (gen_blockage ()); } -/* Emit instructions to restore register REG from slot MEM. */ +/* Attach all pending register saves to the previous instruction. + Return that instruction. */ + +static rtx +mips_epilogue_emit_cfa_restores (void) +{ + rtx insn; + + insn = get_last_insn (); + gcc_assert (insn && !REG_NOTES (insn)); + if (mips_epilogue.cfa_restores) + { + RTX_FRAME_RELATED_P (insn) = 1; + REG_NOTES (insn) = mips_epilogue.cfa_restores; + mips_epilogue.cfa_restores = 0; + } + return insn; +} + +/* Like mips_epilogue_emit_cfa_restores, but also record that the CFA is + now at REG + OFFSET. */ + +static void +mips_epilogue_set_cfa (rtx reg, HOST_WIDE_INT offset) +{ + rtx insn; + + insn = mips_epilogue_emit_cfa_restores (); + if (reg != mips_epilogue.cfa_reg || offset != mips_epilogue.cfa_offset) + { + RTX_FRAME_RELATED_P (insn) = 1; + REG_NOTES (insn) = alloc_reg_note (REG_CFA_DEF_CFA, + plus_constant (reg, offset), + REG_NOTES (insn)); + mips_epilogue.cfa_reg = reg; + mips_epilogue.cfa_offset = offset; + } +} + +/* Emit instructions to restore register REG from slot MEM. Also update + the cfa_restores list. */ static void mips_restore_reg (rtx reg, rtx mem) @@ -10231,8 +10290,17 @@ mips_restore_reg (rtx reg, rtx mem) $7 instead and adjust the return insn appropriately. */ if (TARGET_MIPS16 && REGNO (reg) == RETURN_ADDR_REGNUM) reg = gen_rtx_REG (GET_MODE (reg), GP_REG_FIRST + 7); + else + mips_epilogue.cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, + mips_epilogue.cfa_restores); mips_emit_save_slot_move (reg, mem, MIPS_EPILOGUE_TEMP (GET_MODE (reg))); + if (REGNO (reg) == REGNO (mips_epilogue.cfa_reg)) + /* The CFA is currently defined in terms of the register whose + value we have just restored. Redefine the CFA in terms of + the stack pointer. */ + mips_epilogue_set_cfa (stack_pointer_rtx, + mips_epilogue.cfa_restore_sp_offset); } /* Emit any instructions needed before a return. */ @@ -10291,6 +10359,9 @@ mips_expand_epilogue (bool sibcall_p) base = hard_frame_pointer_rtx; step1 -= frame->hard_frame_pointer_offset; } + mips_epilogue.cfa_reg = base; + mips_epilogue.cfa_offset = step1; + mips_epilogue.cfa_restores = NULL_RTX; /* If we need to restore registers, deallocate as much stack as possible in the second step without going out of range. */ @@ -10320,6 +10391,7 @@ mips_expand_epilogue (bool sibcall_p) target = stack_pointer_rtx; emit_insn (gen_add3_insn (target, base, adjust)); + mips_epilogue_set_cfa (target, step2); } /* Copy TARGET into the stack pointer. */ @@ -10332,6 +10404,7 @@ mips_expand_epilogue (bool sibcall_p) if (TARGET_CALL_SAVED_GP && !TARGET_EXPLICIT_RELOCS) emit_insn (gen_blockage ()); + mips_epilogue.cfa_restore_sp_offset = step2; if (GENERATE_MIPS16E_SAVE_RESTORE && frame->mask != 0) { unsigned int regno, mask; @@ -10353,6 +10426,7 @@ mips_expand_epilogue (bool sibcall_p) /* Restore the remaining registers and deallocate the final bit of the frame. */ emit_insn (restore); + mips_epilogue_set_cfa (stack_pointer_rtx, 0); } else { @@ -10388,9 +10462,15 @@ mips_expand_epilogue (bool sibcall_p) /* If we don't use shoadow register set, we need to update SP. */ if (!cfun->machine->use_shadow_register_set_p && step2 > 0) - emit_insn (gen_add3_insn (stack_pointer_rtx, - stack_pointer_rtx, - GEN_INT (step2))); + { + emit_insn (gen_add3_insn (stack_pointer_rtx, + stack_pointer_rtx, + GEN_INT (step2))); + mips_epilogue_set_cfa (stack_pointer_rtx, 0); + } + else + /* The choice of position is somewhat arbitrary in this case. */ + mips_epilogue_emit_cfa_restores (); /* Move to COP0 Status. */ emit_insn (gen_cop0_move (gen_rtx_REG (SImode, COP0_STATUS_REG_NUM), @@ -10400,11 +10480,15 @@ mips_expand_epilogue (bool sibcall_p) { /* Deallocate the final bit of the frame. */ if (step2 > 0) - emit_insn (gen_add3_insn (stack_pointer_rtx, - stack_pointer_rtx, - GEN_INT (step2))); + { + emit_insn (gen_add3_insn (stack_pointer_rtx, + stack_pointer_rtx, + GEN_INT (step2))); + mips_epilogue_set_cfa (stack_pointer_rtx, 0); + } } } + gcc_assert (!mips_epilogue.cfa_restores); /* Add in the __builtin_eh_return stack adjustment. We need to use a temporary in MIPS16 code. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index dde09f5773f..eea712ece6c 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2011-09-12 Richard Sandiford + + * gcc.target/mips/mips.exp (mips_option_groups): Add debug options. + * gcc.target/mips/interrupt_handler-2.c: New test. + * gcc.target/mips/interrupt_handler-3.c: Likewise. + 2011-09-12 Jason Merrill * g++.dg/cpp0x/fntmpdefarg2.C: Add more tests. diff --git a/gcc/testsuite/gcc.target/mips/interrupt_handler-2.c b/gcc/testsuite/gcc.target/mips/interrupt_handler-2.c new file mode 100644 index 00000000000..13b41e11885 --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/interrupt_handler-2.c @@ -0,0 +1,14 @@ +/* Make sure that we emit .cfa_restore notes for LO and HI. */ +/* { dg-options "-mips32r2 -msoft-float -O -g" } */ +/* { dg-final { scan-assembler "\t\\\.cfi_restore 64\n" } } */ +/* { dg-final { scan-assembler "\t\\\.cfi_restore 65\n" } } */ +/* { dg-final { scan-assembler-not "\\\.cfi_def_cfa( |\t)" } } */ +/* { dg-final { scan-assembler-not "\\\.cfi_def_cfa_register( |\t)" } } */ + +extern void f (void); + +NOMIPS16 void __attribute__ ((interrupt, use_shadow_register_set)) +v1 (void) +{ + f (); +} diff --git a/gcc/testsuite/gcc.target/mips/interrupt_handler-3.c b/gcc/testsuite/gcc.target/mips/interrupt_handler-3.c new file mode 100644 index 00000000000..2380123b16e --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/interrupt_handler-3.c @@ -0,0 +1,33 @@ +/* Make sure that we emit .cfa_restore notes for LO, HI and GPRs. */ +/* { dg-options "-mips32r2 -msoft-float -O -g" } */ +/* { dg-final { scan-assembler "\t\\\.cfi_restore 1\n" } } */ +/* { dg-final { scan-assembler "\t\\\.cfi_restore 2\n" } } */ +/* { dg-final { scan-assembler "\t\\\.cfi_restore 3\n" } } */ +/* { dg-final { scan-assembler "\t\\\.cfi_restore 4\n" } } */ +/* { dg-final { scan-assembler "\t\\\.cfi_restore 5\n" } } */ +/* { dg-final { scan-assembler "\t\\\.cfi_restore 6\n" } } */ +/* { dg-final { scan-assembler "\t\\\.cfi_restore 7\n" } } */ +/* { dg-final { scan-assembler "\t\\\.cfi_restore 8\n" } } */ +/* { dg-final { scan-assembler "\t\\\.cfi_restore 9\n" } } */ +/* { dg-final { scan-assembler "\t\\\.cfi_restore 10\n" } } */ +/* { dg-final { scan-assembler "\t\\\.cfi_restore 11\n" } } */ +/* { dg-final { scan-assembler "\t\\\.cfi_restore 12\n" } } */ +/* { dg-final { scan-assembler "\t\\\.cfi_restore 13\n" } } */ +/* { dg-final { scan-assembler "\t\\\.cfi_restore 14\n" } } */ +/* { dg-final { scan-assembler "\t\\\.cfi_restore 15\n" } } */ +/* { dg-final { scan-assembler "\t\\\.cfi_restore 24\n" } } */ +/* { dg-final { scan-assembler "\t\\\.cfi_restore 25\n" } } */ +/* { dg-final { scan-assembler "\t\\\.cfi_restore 31\n" } } */ +/* { dg-final { scan-assembler "\t\\\.cfi_restore 64\n" } } */ +/* { dg-final { scan-assembler "\t\\\.cfi_restore 65\n" } } */ +/* { dg-final { scan-assembler "\t\\\.cfi_def_cfa_offset 0\n" } } */ +/* { dg-final { scan-assembler-not "\\\.cfi_def_cfa( |\t)" } } */ +/* { dg-final { scan-assembler-not "\\\.cfi_def_cfa_register( |\t)" } } */ + +extern void f (void); + +NOMIPS16 void __attribute__ ((interrupt)) +v1 (void) +{ + f (); +} diff --git a/gcc/testsuite/gcc.target/mips/mips.exp b/gcc/testsuite/gcc.target/mips/mips.exp index 5889902456a..857cfe87eba 100644 --- a/gcc/testsuite/gcc.target/mips/mips.exp +++ b/gcc/testsuite/gcc.target/mips/mips.exp @@ -226,6 +226,7 @@ set mips_option_groups { abi "-mabi=.*" addressing "addressing=.*" arch "-mips([1-5]|32.*|64.*)|-march=.*|isa(|_rev)(=|<=|>=).*" + debug "-g*" dump_pattern "-dp" endianness "-E(L|B)|-me(l|b)" float "-m(hard|soft)-float" -- 2.30.2