diff options
Diffstat (limited to 'gcc/combine.c')
-rw-r--r-- | gcc/combine.c | 158 |
1 files changed, 108 insertions, 50 deletions
diff --git a/gcc/combine.c b/gcc/combine.c index ab91989..e2e7258 100644 --- a/gcc/combine.c +++ b/gcc/combine.c @@ -321,15 +321,14 @@ static int nonzero_sign_valid; /* Record one modification to rtl structure - to be undone by storing old_contents into *where. - is_int is 1 if the contents are an int. */ + to be undone by storing old_contents into *where. */ struct undo { struct undo *next; - int is_int; - union {rtx r; int i;} old_contents; - union {rtx *r; int *i;} where; + enum { UNDO_RTX, UNDO_INT, UNDO_MODE } kind; + union { rtx r; int i; enum machine_mode m; } old_contents; + union { rtx *r; int *i; } where; }; /* Record a bunch of changes to be undone, up to MAX_UNDO of them. @@ -490,7 +489,7 @@ do_SUBST (rtx *into, rtx newval) else buf = xmalloc (sizeof (struct undo)); - buf->is_int = 0; + buf->kind = UNDO_RTX; buf->where.r = into; buf->old_contents.r = oldval; *into = newval; @@ -518,7 +517,7 @@ do_SUBST_INT (int *into, int newval) else buf = xmalloc (sizeof (struct undo)); - buf->is_int = 1; + buf->kind = UNDO_INT; buf->where.i = into; buf->old_contents.i = oldval; *into = newval; @@ -527,6 +526,35 @@ do_SUBST_INT (int *into, int newval) } #define SUBST_INT(INTO, NEWVAL) do_SUBST_INT(&(INTO), (NEWVAL)) + +/* Similar to SUBST, but just substitute the mode. This is used when + changing the mode of a pseudo-register, so that any other + references to the entry in the regno_reg_rtx array will change as + well. */ + +static void +do_SUBST_MODE (rtx *into, enum machine_mode newval) +{ + struct undo *buf; + enum machine_mode oldval = GET_MODE (*into); + + if (oldval == newval) + return; + + if (undobuf.frees) + buf = undobuf.frees, undobuf.frees = buf->next; + else + buf = xmalloc (sizeof (struct undo)); + + buf->kind = UNDO_MODE; + buf->where.r = into; + buf->old_contents.m = oldval; + PUT_MODE (*into, newval); + + buf->next = undobuf.undos, undobuf.undos = buf; +} + +#define SUBST_MODE(INTO, NEWVAL) do_SUBST_MODE(&(INTO), (NEWVAL)) /* Subroutine of try_combine. Determine whether the combine replacement patterns NEWPAT and NEWI2PAT are cheaper according to insn_rtx_cost @@ -2224,10 +2252,15 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p) compare_mode)) { unsigned int regno = REGNO (SET_DEST (newpat)); - rtx new_dest = gen_rtx_REG (compare_mode, regno); + rtx new_dest; - if (regno >= FIRST_PSEUDO_REGISTER) - SUBST (regno_reg_rtx[regno], new_dest); + if (regno < FIRST_PSEUDO_REGISTER) + new_dest = gen_rtx_REG (compare_mode, regno); + else + { + SUBST_MODE (regno_reg_rtx[regno], compare_mode); + new_dest = regno_reg_rtx[regno]; + } SUBST (SET_DEST (newpat), new_dest); SUBST (XEXP (*cc_use, 0), new_dest); @@ -2476,7 +2509,6 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p) && asm_noperands (newpat) < 0) { rtx m_split, *split; - rtx ni2dest = i2dest; /* See if the MD file can split NEWPAT. If it can't, see if letting it use I2DEST as a scratch register will help. In the latter case, @@ -2491,34 +2523,55 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p) possible to try that as a scratch reg. This would require adding more code to make it work though. */ - if (m_split == 0 && ! reg_overlap_mentioned_p (ni2dest, newpat)) + if (m_split == 0 && ! reg_overlap_mentioned_p (i2dest, newpat)) { - enum machine_mode new_mode = GET_MODE (SET_DEST (newpat)); - /* If I2DEST is a hard register or the only use of a pseudo, - we can change its mode. */ - if (new_mode != GET_MODE (i2dest) - && new_mode != VOIDmode - && can_change_dest_mode (i2dest, added_sets_2, new_mode)) - ni2dest = gen_rtx_REG (GET_MODE (SET_DEST (newpat)), - REGNO (i2dest)); + enum machine_mode new_mode = GET_MODE (SET_DEST (newpat)); + /* First try to split using the original register as a + scratch register. */ m_split = split_insns (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, newpat, gen_rtx_CLOBBER (VOIDmode, - ni2dest))), + i2dest))), i3); - /* If the split with the mode-changed register didn't work, try - the original register. */ - if (! m_split && ni2dest != i2dest) + + /* If that didn't work, try changing the mode of I2DEST if + we can. */ + if (m_split == 0 + && new_mode != GET_MODE (i2dest) + && new_mode != VOIDmode + && can_change_dest_mode (i2dest, added_sets_2, new_mode)) { - ni2dest = i2dest; + enum machine_mode old_mode = GET_MODE (i2dest); + rtx ni2dest; + + if (REGNO (i2dest) < FIRST_PSEUDO_REGISTER) + ni2dest = gen_rtx_REG (new_mode, REGNO (i2dest)); + else + { + SUBST_MODE (regno_reg_rtx[REGNO (i2dest)], new_mode); + ni2dest = regno_reg_rtx[REGNO (i2dest)]; + } + m_split = split_insns (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, newpat, gen_rtx_CLOBBER (VOIDmode, - i2dest))), + ni2dest))), i3); + + if (m_split == 0 + && REGNO (i2dest) >= FIRST_PSEUDO_REGISTER) + { + struct undo *buf; + + PUT_MODE (regno_reg_rtx[REGNO (i2dest)], old_mode); + buf = undobuf.undos; + undobuf.undos = buf->next; + buf->next = undobuf.frees; + undobuf.frees = buf; + } } } @@ -2547,13 +2600,6 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p) i3set = single_set (NEXT_INSN (m_split)); i2set = single_set (m_split); - /* In case we changed the mode of I2DEST, replace it in the - pseudo-register table here. We can't do it above in case this - code doesn't get executed and we do a split the other way. */ - - if (REGNO (i2dest) >= FIRST_PSEUDO_REGISTER) - SUBST (regno_reg_rtx[REGNO (i2dest)], ni2dest); - i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes); /* If I2 or I3 has multiple SETs, we won't know how to track @@ -2624,10 +2670,13 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p) validated that we can do this. */ if (GET_MODE (i2dest) != split_mode && split_mode != VOIDmode) { - newdest = gen_rtx_REG (split_mode, REGNO (i2dest)); - - if (REGNO (i2dest) >= FIRST_PSEUDO_REGISTER) - SUBST (regno_reg_rtx[REGNO (i2dest)], newdest); + if (REGNO (i2dest) < FIRST_PSEUDO_REGISTER) + newdest = gen_rtx_REG (split_mode, REGNO (i2dest)); + else + { + SUBST_MODE (regno_reg_rtx[REGNO (i2dest)], split_mode); + newdest = regno_reg_rtx[REGNO (i2dest)]; + } } /* If *SPLIT is a (mult FOO (const_int pow2)), convert it to @@ -3328,10 +3377,20 @@ undo_all (void) for (undo = undobuf.undos; undo; undo = next) { next = undo->next; - if (undo->is_int) - *undo->where.i = undo->old_contents.i; - else - *undo->where.r = undo->old_contents.r; + switch (undo->kind) + { + case UNDO_RTX: + *undo->where.r = undo->old_contents.r; + break; + case UNDO_INT: + *undo->where.i = undo->old_contents.i; + break; + case UNDO_MODE: + PUT_MODE (*undo->where.r, undo->old_contents.m); + break; + default: + gcc_unreachable (); + } undo->next = undobuf.frees; undobuf.frees = undo; @@ -5160,10 +5219,15 @@ simplify_set (rtx x) if (can_change_dest_mode (dest, 0, compare_mode)) { unsigned int regno = REGNO (dest); - rtx new_dest = gen_rtx_REG (compare_mode, regno); + rtx new_dest; - if (regno >= FIRST_PSEUDO_REGISTER) - SUBST (regno_reg_rtx[regno], new_dest); + if (regno < FIRST_PSEUDO_REGISTER) + new_dest = gen_rtx_REG (compare_mode, regno); + else + { + SUBST_MODE (regno_reg_rtx[regno], compare_mode); + new_dest = regno_reg_rtx[regno]; + } SUBST (SET_DEST (x), new_dest); SUBST (XEXP (*cc_use, 0), new_dest); @@ -11709,12 +11773,6 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2, rtx elim_i2, { rtx place = 0, place2 = 0; - /* If this NOTE references a pseudo register, ensure it references - the latest copy of that register. */ - if (XEXP (note, 0) && REG_P (XEXP (note, 0)) - && REGNO (XEXP (note, 0)) >= FIRST_PSEUDO_REGISTER) - XEXP (note, 0) = regno_reg_rtx[REGNO (XEXP (note, 0))]; - next_note = XEXP (note, 1); switch (REG_NOTE_KIND (note)) { |