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);
}
}