From ecafcf0577cfe1672f3c9e73045448b8f3d7948b Mon Sep 17 00:00:00 2001 From: Vladimir Makarov Date: Thu, 12 Sep 2013 18:23:09 +0000 Subject: [PATCH] re PR middle-end/58335 (S/390: reload vs lra regression - testcase builtin-in-setjmp) 2013-09-12 Vladimir Makarov PR middle-end/58335 * lra-eliminations (remove_reg_equal_offset_note): New. (eliminate_regs_in_insn): Rewrite frame pointer to hard frame pointer elimination with using remove_reg_equal_offset_note. From-SVN: r202536 --- gcc/ChangeLog | 7 +++ gcc/lra-eliminations.c | 104 +++++++++++++++++++++++------------------ 2 files changed, 66 insertions(+), 45 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a4440a01c89..4a3fca2f193 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2013-09-12 Vladimir Makarov + + PR middle-end/58335 + * lra-eliminations (remove_reg_equal_offset_note): New. + (eliminate_regs_in_insn): Rewrite frame pointer to hard frame + pointer elimination with using remove_reg_equal_offset_note. + 2013-09-12 DJ Delorie * config/msp430/: New port. diff --git a/gcc/lra-eliminations.c b/gcc/lra-eliminations.c index a59ab6eacca..f2a57511cbd 100644 --- a/gcc/lra-eliminations.c +++ b/gcc/lra-eliminations.c @@ -745,13 +745,42 @@ mark_not_eliminable (rtx x) +#ifdef HARD_FRAME_POINTER_REGNUM + +/* Find offset equivalence note for reg WHAT in INSN and return the + found elmination offset. If the note is not found, return NULL. + Remove the found note. */ +static rtx +remove_reg_equal_offset_note (rtx insn, rtx what) +{ + rtx link, *link_loc; + + for (link_loc = ®_NOTES (insn); + (link = *link_loc) != NULL_RTX; + link_loc = &XEXP (link, 1)) + if (REG_NOTE_KIND (link) == REG_EQUAL + && GET_CODE (XEXP (link, 0)) == PLUS + && XEXP (XEXP (link, 0), 0) == what + && CONST_INT_P (XEXP (XEXP (link, 0), 1))) + { + *link_loc = XEXP (link, 1); + return XEXP (XEXP (link, 0), 1); + } + return NULL_RTX; +} + +#endif + /* Scan INSN and eliminate all eliminable hard registers in it. If REPLACE_P is true, do the replacement destructively. Also delete the insn as dead it if it is setting an eliminable register. If REPLACE_P is false, just update the offsets while keeping the - base register the same. */ + base register the same. Attach the note about used elimination for + insns setting frame pointer to update elimination easy (without + parsing already generated elimination insns to find offset + previously used) in future. */ static void eliminate_regs_in_insn (rtx insn, bool replace_p) @@ -790,59 +819,44 @@ eliminate_regs_in_insn (rtx insn, bool replace_p) if (ep->from == FRAME_POINTER_REGNUM && ep->to == HARD_FRAME_POINTER_REGNUM) { + rtx src = SET_SRC (old_set); + rtx off = remove_reg_equal_offset_note (insn, ep->to_rtx); + if (replace_p) { SET_DEST (old_set) = ep->to_rtx; lra_update_insn_recog_data (insn); return; } - else + else if (off != NULL_RTX + || src == ep->to_rtx + || (GET_CODE (src) == PLUS + && XEXP (src, 1) == ep->to_rtx + && CONST_INT_P (XEXP (src, 1)))) { - rtx base = SET_SRC (old_set); - HOST_WIDE_INT offset = 0; - rtx base_insn = insn; - - while (base != ep->to_rtx) + HOST_WIDE_INT offset = (off != NULL_RTX + ? INTVAL (off) + : src == ep->to_rtx + ? 0 : INTVAL (XEXP (src, 1))); + + offset -= (ep->offset - ep->previous_offset); + src = plus_constant (Pmode, ep->to_rtx, offset); + + /* First see if this insn remains valid when we make + the change. If not, keep the INSN_CODE the same + and let the constraint pass fit it up. */ + validate_change (insn, &SET_SRC (old_set), src, 1); + validate_change (insn, &SET_DEST (old_set), + ep->from_rtx, 1); + if (! apply_change_group ()) { - rtx prev_insn, 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; - - offset -= (ep->offset - ep->previous_offset); - src = plus_constant (Pmode, ep->to_rtx, offset); - - /* First see if this insn remains valid when we make - the change. If not, keep the INSN_CODE the same - and let the constraint pass fit it up. */ - validate_change (insn, &SET_SRC (old_set), src, 1); - validate_change (insn, &SET_DEST (old_set), - ep->from_rtx, 1); - if (! apply_change_group ()) - { - SET_SRC (old_set) = src; - SET_DEST (old_set) = ep->from_rtx; - } - lra_update_insn_recog_data (insn); - return; + SET_SRC (old_set) = src; + SET_DEST (old_set) = ep->from_rtx; } + lra_update_insn_recog_data (insn); + /* Add offset note for future updates. */ + add_reg_note (insn, REG_EQUAL, src); + return; } -- 2.30.2