Here's a new version, which adds support for mips16 and tries to avoid the window with the frame pointer restore.
Testing mips16 is problematic, all the execute tests fail before and after - I interpret one of your earlier mails to say that this is expected. There are no new compilation failures with this patch, but incorrect earlier versions triggered a few, indicating that the testing is at least somewhat useful. I get the following output for restore insns: move $sp,$17 restore 8,$16,$17 $LCFI2 = . .cfi_remember_state .cfi_restore 16 .cfi_restore 17 .cfi_def_cfa 29, 0 which I think is correct. Question for Richard H.: What is this actually good for, other than presenting consistent information to dwarf2cfi? Do we actually expect code to unwind through the middle of an epilogue? Bernd
* config/mips/mips.c (cfa_restores, cfa_sp_offset): New static variables. (mips16e_save_restore_reg): Add to cfa_restores. (mips_restore_reg): Add to cfa_restores, and add a REG_CFA_DEF_CFA note to insns restoring the frame pointer. (mips_expand_epilogue): Initialize the new variables. Annotate RTL to ensure dwarf2cfi sees the effects of the epilogue. Generate a simple_return only if the return address is in r31. Index: gcc/config/mips/mips.c =================================================================== --- gcc/config/mips/mips.c (revision 178135) +++ gcc/config/mips/mips.c (working copy) @@ -501,6 +501,11 @@ int sdb_label_count; int mips_dbx_regno[FIRST_PSEUDO_REGISTER]; int mips_dwarf_regno[FIRST_PSEUDO_REGISTER]; +/* Used to collect REG_CFA notes during epilogue generation. */ +static rtx cfa_restores = NULL_RTX; +/* Used to produce REG_CFA_DEF_CFA notes during epilogue generation. */ +static HOST_WIDE_INT cfa_sp_offset; + /* 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 }; @@ -8371,8 +8376,8 @@ mips16e_collect_argument_saves (void) } /* Return a move between register REGNO and memory location SP + OFFSET. - Make the move a load if RESTORE_P, otherwise make it a frame-related - store. */ + Make the move a load and update cfa_restores if RESTORE_P, otherwise + make it a frame-related store. */ static rtx mips16e_save_restore_reg (bool restore_p, HOST_WIDE_INT offset, @@ -8382,6 +8387,9 @@ mips16e_save_restore_reg (bool restore_p mem = gen_frame_mem (SImode, plus_constant (stack_pointer_rtx, offset)); reg = gen_rtx_REG (SImode, regno); + if (restore_p) + cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, cfa_restores); + return (restore_p ? gen_rtx_SET (VOIDmode, reg, mem) : mips_frame_set (mem, reg)); @@ -10227,17 +10236,30 @@ mips_expand_prologue (void) emit_insn (gen_blockage ()); } -/* Emit instructions to restore register REG from slot MEM. */ +/* Emit instructions to restore register REG from slot MEM. Also update + the cfa_restores list. */ static void mips_restore_reg (rtx reg, rtx mem) { + rtx orig_reg = reg; + rtx last; + /* There's no MIPS16 instruction to load $31 directly. Load into $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); mips_emit_save_slot_move (reg, mem, MIPS_EPILOGUE_TEMP (GET_MODE (reg))); + if (reg == orig_reg) + cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, cfa_restores); + + if (!frame_pointer_needed || REGNO (reg) != HARD_FRAME_POINTER_REGNUM) + return; + last = get_last_insn (); + add_reg_note (last, REG_CFA_DEF_CFA, plus_constant (stack_pointer_rtx, + cfa_sp_offset)); + RTX_FRAME_RELATED_P (last) = 1; } /* Emit any instructions needed before a return. */ @@ -10268,6 +10290,8 @@ mips_expand_epilogue (bool sibcall_p) HOST_WIDE_INT step1, step2; rtx base, target, insn; + cfa_restores = NULL_RTX; + if (!sibcall_p && mips_can_use_return_insn ()) { emit_jump_insn (gen_return ()); @@ -10306,6 +10330,8 @@ mips_expand_epilogue (bool sibcall_p) step1 -= step2; } + cfa_sp_offset = step2; + /* Set TARGET to BASE + STEP1. */ target = base; if (step1 > 0) @@ -10324,12 +10350,26 @@ mips_expand_epilogue (bool sibcall_p) if (!TARGET_MIPS16) target = stack_pointer_rtx; - emit_insn (gen_add3_insn (target, base, adjust)); + insn = emit_insn (gen_add3_insn (target, base, adjust)); + if (!frame_pointer_needed && target == stack_pointer_rtx) + { + RTX_FRAME_RELATED_P (insn) = 1; + add_reg_note (insn, REG_CFA_DEF_CFA, + plus_constant (stack_pointer_rtx, step2)); + } } /* Copy TARGET into the stack pointer. */ if (target != stack_pointer_rtx) - mips_emit_move (stack_pointer_rtx, target); + { + insn = mips_emit_move (stack_pointer_rtx, target); + if (!frame_pointer_needed) + { + add_reg_note (insn, REG_CFA_DEF_CFA, + plus_constant (stack_pointer_rtx, step2)); + RTX_FRAME_RELATED_P (insn) = 1; + } + } /* If we're using addressing macros, $gp is implicitly used by all SYMBOL_REFs. We must emit a blockage insn before restoring $gp @@ -10357,7 +10397,10 @@ mips_expand_epilogue (bool sibcall_p) /* Restore the remaining registers and deallocate the final bit of the frame. */ - emit_insn (restore); + restore = emit_insn (restore); + REG_NOTES (restore) = cfa_restores; + RTX_FRAME_RELATED_P (restore) = 1; + add_reg_note (restore, REG_CFA_DEF_CFA, stack_pointer_rtx); } else { @@ -10393,9 +10436,14 @@ 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))); + { + insn = emit_insn (gen_add3_insn (stack_pointer_rtx, + stack_pointer_rtx, + GEN_INT (step2))); + REG_NOTES (insn) = cfa_restores; + RTX_FRAME_RELATED_P (insn) = 1; + add_reg_note (insn, REG_CFA_DEF_CFA, stack_pointer_rtx); + } /* Move to COP0 Status. */ emit_insn (gen_cop0_move (gen_rtx_REG (SImode, COP0_STATUS_REG_NUM), @@ -10405,9 +10453,14 @@ 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))); + { + insn = emit_insn (gen_add3_insn (stack_pointer_rtx, + stack_pointer_rtx, + GEN_INT (step2))); + REG_NOTES (insn) = cfa_restores; + RTX_FRAME_RELATED_P (insn) = 1; + add_reg_note (insn, REG_CFA_DEF_CFA, stack_pointer_rtx); + } } } @@ -10442,7 +10495,7 @@ mips_expand_epilogue (bool sibcall_p) } else { - unsigned int regno; + rtx pat; /* When generating MIPS16 code, the normal mips_for_each_saved_gpr_and_fpr path will restore the return @@ -10450,11 +10503,16 @@ mips_expand_epilogue (bool sibcall_p) if (TARGET_MIPS16 && !GENERATE_MIPS16E_SAVE_RESTORE && BITSET_P (frame->mask, RETURN_ADDR_REGNUM)) - regno = GP_REG_FIRST + 7; + { + rtx reg = gen_rtx_REG (Pmode, GP_REG_FIRST + 7); + pat = gen_return_internal (reg); + } else - regno = RETURN_ADDR_REGNUM; - emit_jump_insn (gen_simple_return_internal (gen_rtx_REG (Pmode, - regno))); + { + rtx reg = gen_rtx_REG (Pmode, RETURN_ADDR_REGNUM); + pat = gen_simple_return_internal (reg); + } + emit_jump_insn (pat); } }