Hi,
some OSes, for example VxWorks 6, still use DWARF unwinding on the ARM, which
means that they use __builtin_eh_return (EABI unwinding doesn't). The builtin
is implemented by means of {arm|thumb}_set_return_address, which can generate
a store if LR has been stored on function entry. The problem is that, if this
store is FP-based, it is not seen by the RTL DSE pass as being consumed by the
SP-based load at the same address on function exit.
That's by design in the RTL DSE pass: FP and SP are never substituted for each
other by cselib, see for example this comment:
/* The only thing that we are not willing to do (this
is requirement of dse and if others potential uses
need this function we should add a parm to control
it) is that we will not substitute the
STACK_POINTER_REGNUM, FRAME_POINTER or the
HARD_FRAME_POINTER.
These expansions confuses the code that notices that
stores into the frame go dead at the end of the
function and that the frame is not effected by calls
to subroutines. If you allow the
STACK_POINTER_REGNUM substitution, then dse will
think that parameter pushing also goes dead which is
wrong. If you allow the FRAME_POINTER or the
HARD_FRAME_POINTER then you lose the opportunity to
make the frame assumptions. */
if (regno == STACK_POINTER_REGNUM
|| regno == FRAME_POINTER_REGNUM
|| regno == HARD_FRAME_POINTER_REGNUM
|| regno == cfa_base_preserved_regno)
return orig;
so a FP-based store and a SP-based load are never seen as a RAW dependency.
This nevertheless used to work because the blockage insn emitted by the RTL
epilogue was acting as a "wild load" but this got broken by Richard's patch:
2014-03-11 Richard Sandiford <rdsandif...@googlemail.com>
* builtins.c (expand_builtin_setjmp_receiver): Use and clobber
hard_frame_pointer_rtx.
* cse.c (cse_insn): Remove volatile check.
* cselib.c (cselib_process_insn): Likewise.
* dse.c (scan_insn): Likewise.
which removed the "wild load" trick. This is visible at -O2 for:
void
foo (void *c1, void *t1, void *ra)
{
long offset = uw_install_context_1 (c1, t1);
void *handler = __builtin_frob_return_addr (ra);
__builtin_unwind_init ();
__builtin_eh_return (offset, handler);
}
The attached patch fixes the breakage by marking the stores as frame related.
Tested on ARM/VxWorks, OK for mainline and 4.9 branch?
2014-10-17 Eric Botcazou <ebotca...@adacore.com>
* config/arm/arm.c (arm_set_return_address): Mark the store as frame
related, if any.
(thumb_set_return_address): Likewise.
--
Eric Botcazou
Index: config/arm/arm.c
===================================================================
--- config/arm/arm.c (revision 216252)
+++ config/arm/arm.c (working copy)
@@ -28952,7 +28952,11 @@ arm_set_return_address (rtx source, rtx
addr = plus_constant (Pmode, addr, delta);
}
- emit_move_insn (gen_frame_mem (Pmode, addr), source);
+ /* The store needs to be marked as frame related in order to prevent
+ DSE from deleting it as dead if it is based on fp. */
+ rtx insn = emit_move_insn (gen_frame_mem (Pmode, addr), source);
+ RTX_FRAME_RELATED_P (insn) = 1;
+ add_reg_note (insn, REG_CFA_RESTORE, gen_rtx_REG (Pmode, LR_REGNUM));
}
}
@@ -29004,7 +29008,11 @@ thumb_set_return_address (rtx source, rt
else
addr = plus_constant (Pmode, addr, delta);
- emit_move_insn (gen_frame_mem (Pmode, addr), source);
+ /* The store needs to be marked as frame related in order to prevent
+ DSE from deleting it as dead if it is based on fp. */
+ rtx insn = emit_move_insn (gen_frame_mem (Pmode, addr), source);
+ RTX_FRAME_RELATED_P (insn) = 1;
+ add_reg_note (insn, REG_CFA_RESTORE, gen_rtx_REG (Pmode, LR_REGNUM));
}
else
emit_move_insn (gen_rtx_REG (Pmode, LR_REGNUM), source);