summaryrefslogtreecommitdiff
path: root/gcc/reload1.c
diff options
context:
space:
mode:
authorWilco Dijkstra <wdijkstr@arm.com>2019-06-19 12:52:43 +0000
committerWilco Dijkstra <wilco@gcc.gnu.org>2019-06-19 12:52:43 +0000
commit25403c416e5f12d681d1fc45a8789d19ab40297f (patch)
tree6474f549d25800480316cfea891569617209bd25 /gcc/reload1.c
parent2e83f583c27ef7a9d3b0fb0b5ed372439d6222a8 (diff)
Simplify setjmp and non-local goto implementation (PR84521)
This fixes and simplifies the setjmp and non-local goto implementation. Currently the virtual frame pointer is saved when using __builtin_setjmp or a non-local goto. Depending on whether a frame pointer is used, this may either save SP or FP with an immediate offset. However the goto or longjmp always updates the hard frame pointer. A receiver veneer in the original function then assigns the hard frame pointer to the virtual frame pointer, which should, if it works correctly, again assign SP or FP. However the special elimination code in eliminate_regs_in_insn doesn't do this correctly unless the frame pointer is used, and even if it worked by writing SP, the frame pointer would still be corrupted. A much simpler implementation is to always save and restore the hard frame pointer. This avoids 2 redundant instructions which add/subtract the virtual frame offset. A large amount of code can be removed as a result, including all implementations of TARGET_BUILTIN_SETJMP_FRAME_VALUE (all of which already use the hard frame pointer). The expansion of nonlocal_goto on PA can be simplied to just restore the hard frame pointer. This fixes the most obvious issues, however there are still issues on targets which define HARD_FRAME_POINTER_IS_FRAME_POINTER (arm, mips). Each function could have a different hard frame pointer, so a non-local goto may restore the wrong frame pointer (TARGET_BUILTIN_SETJMP_FRAME_VALUE could be useful for this). The i386 TARGET_BUILTIN_SETJMP_FRAME_VALUE was incorrect: if stack_realign_fp is true, it would save the hard frame pointer value but restore the virtual frame pointer which according to ix86_initial_elimination_offset can have a non-zero offset from the hard frame pointer. The ia64 implementation of nonlocal_goto seems incorrect since the helper function moves the the frame pointer value into the static chain register (so this patch does nothing to make it better or worse). AArch64 + x86-64 bootstrap OK, new test passes on AArch64, x86-64 and Arm. gcc/ PR middle-end/84521 * builtins.c (expand_builtin_setjmp_setup): Save hard_frame_pointer_rtx. (expand_builtin_setjmp_receiver): Do not emit sfp = fp move since we restore fp. * function.c (expand_function_start): Save hard_frame_pointer_rtx for non-local goto. * lra-eliminations.c (eliminate_regs_in_insn): Remove sfp = fp elimination code. (remove_reg_equal_offset_note): Remove unused function. * reload1.c (eliminate_regs_in_insn): Remove sfp = hfp elimination code. * config/arc/arc.c (TARGET_BUILTIN_SETJMP_FRAME_VALUE): Remove. (arc_builtin_setjmp_frame_value): Remove function. * config/avr/avr.c (TARGET_BUILTIN_SETJMP_FRAME_VALUE): Remove. (avr_builtin_setjmp_frame_value): Remove function. * config/i386/i386.c (TARGET_BUILTIN_SETJMP_FRAME_VALUE): Remove. (ix86_builtin_setjmp_frame_value): Remove function. * config/pa/pa.md (nonlocal_goto): Remove FP adjustment. * config/sparc/sparc.c (TARGET_BUILTIN_SETJMP_FRAME_VALUE): Remove. (sparc_builtin_setjmp_frame_value): Remove function. * config/vax/vax.c (TARGET_BUILTIN_SETJMP_FRAME_VALUE): Remove. (vax_builtin_setjmp_frame_value): Remove function. * config/xtensa/xtensa.c (xtensa_frame_pointer_required): Force frame pointer if has_nonlocal_label. testsuite/ PR middle-end/84521 * gcc.c-torture/execute/pr84521.c: New test. From-SVN: r272473
Diffstat (limited to 'gcc/reload1.c')
-rw-r--r--gcc/reload1.c90
1 files changed, 0 insertions, 90 deletions
diff --git a/gcc/reload1.c b/gcc/reload1.c
index 5039ceed581..3ad6f1d9c1f 100644
--- a/gcc/reload1.c
+++ b/gcc/reload1.c
@@ -3234,96 +3234,6 @@ eliminate_regs_in_insn (rtx_insn *insn, int replace)
return 0;
}
- if (old_set != 0 && REG_P (SET_DEST (old_set))
- && REGNO (SET_DEST (old_set)) < FIRST_PSEUDO_REGISTER)
- {
- /* Check for setting an eliminable register. */
- for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
- if (ep->from_rtx == SET_DEST (old_set) && ep->can_eliminate)
- {
- /* If this is setting the frame pointer register to the
- hardware frame pointer register and this is an elimination
- that will be done (tested above), this insn is really
- adjusting the frame pointer downward to compensate for
- the adjustment done before a nonlocal goto. */
- if (!HARD_FRAME_POINTER_IS_FRAME_POINTER
- && ep->from == FRAME_POINTER_REGNUM
- && ep->to == HARD_FRAME_POINTER_REGNUM)
- {
- rtx base = SET_SRC (old_set);
- rtx_insn *base_insn = insn;
- HOST_WIDE_INT offset = 0;
-
- while (base != ep->to_rtx)
- {
- rtx_insn *prev_insn;
- rtx prev_set;
-
- if (GET_CODE (base) == PLUS
- && CONST_INT_P (XEXP (base, 1)))
- {
- offset += INTVAL (XEXP (base, 1));
- base = XEXP (base, 0);
- }
- else if ((prev_insn = prev_nonnote_insn (base_insn)) != 0
- && (prev_set = single_set (prev_insn)) != 0
- && rtx_equal_p (SET_DEST (prev_set), base))
- {
- base = SET_SRC (prev_set);
- base_insn = prev_insn;
- }
- else
- break;
- }
-
- if (base == ep->to_rtx)
- {
- rtx src = plus_constant (Pmode, ep->to_rtx,
- offset - ep->offset);
-
- new_body = old_body;
- if (! replace)
- {
- new_body = copy_insn (old_body);
- if (REG_NOTES (insn))
- REG_NOTES (insn) = copy_insn_1 (REG_NOTES (insn));
- }
- PATTERN (insn) = new_body;
- old_set = single_set (insn);
-
- /* First see if this insn remains valid when we
- make the change. If not, keep the INSN_CODE
- the same and let reload fit it up. */
- validate_change (insn, &SET_SRC (old_set), src, 1);
- validate_change (insn, &SET_DEST (old_set),
- ep->to_rtx, 1);
- if (! apply_change_group ())
- {
- SET_SRC (old_set) = src;
- SET_DEST (old_set) = ep->to_rtx;
- }
-
- val = 1;
- goto done;
- }
- }
-
- /* In this case this insn isn't serving a useful purpose. We
- will delete it in reload_as_needed once we know that this
- elimination is, in fact, being done.
-
- If REPLACE isn't set, we can't delete this insn, but needn't
- process it since it won't be used unless something changes. */
- if (replace)
- {
- delete_dead_insn (insn);
- return 1;
- }
- val = 1;
- goto done;
- }
- }
-
/* We allow one special case which happens to work on all machines we
currently support: a single set with the source or a REG_EQUAL
note being a PLUS of an eliminable register and a constant. */