diff options
author | zadeck <zadeck@138bc75d-0d04-0410-961f-82ee72b054a4> | 2006-01-11 13:09:13 +0000 |
---|---|---|
committer | zadeck <zadeck@138bc75d-0d04-0410-961f-82ee72b054a4> | 2006-01-11 13:09:13 +0000 |
commit | df738c1f721fd7482b0d2c122f8007b08c79f86a (patch) | |
tree | b73c1561df90c815d1d60a4bb0387bf76970973d /gcc | |
parent | ac70caaded6c0f5df39f9bd7e2ed9c7f82a8dbd4 (diff) | |
download | gcc-df738c1f721fd7482b0d2c122f8007b08c79f86a.tar.gz |
2006-01-11 Ian Lance Taylor <ian@airs.com>
* combine.c (struct undo): Remove is_int. Enumify types of undos.
Allow undoing set of machine mode.
(do_SUBST): Use enums instead of is_int.
(do_SUBST_MODE): New function.
(SUBST_MODE): New macro.
(try_combine): Use SUBST_MODE/PUT_MODE instead of generating a new
reg and trying to replace reg_regno_rtx with a new register.
(undo_all): Use new enums, handle undoing a PUT_MODE change.
(simplify_set): Use SUBST_MODE.
(distribute_notes): Remove code that tried to update reg notes
for regno_reg_rtx changes.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@109579 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 14 | ||||
-rw-r--r-- | gcc/combine.c | 158 | ||||
-rw-r--r-- | gcc/testsuite/gcc.c-torture/compile/20060109-1.c | 36 |
3 files changed, 158 insertions, 50 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 0701660bb13..e8f5b8a7eed 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,17 @@ +2006-01-11 Ian Lance Taylor <ian@airs.com> + + * combine.c (struct undo): Remove is_int. Enumify types of undos. + Allow undoing set of machine mode. + (do_SUBST): Use enums instead of is_int. + (do_SUBST_MODE): New function. + (SUBST_MODE): New macro. + (try_combine): Use SUBST_MODE/PUT_MODE instead of generating a new + reg and trying to replace reg_regno_rtx with a new register. + (undo_all): Use new enums, handle undoing a PUT_MODE change. + (simplify_set): Use SUBST_MODE. + (distribute_notes): Remove code that tried to update reg notes + for regno_reg_rtx changes. + 2006-01-11 Paolo Bonzini <bonzini@gnu.org> PR tree-optimization/23109 diff --git a/gcc/combine.c b/gcc/combine.c index ab91989534e..e2e72583fde 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)) { diff --git a/gcc/testsuite/gcc.c-torture/compile/20060109-1.c b/gcc/testsuite/gcc.c-torture/compile/20060109-1.c new file mode 100644 index 00000000000..9ef9c2fdd9f --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/20060109-1.c @@ -0,0 +1,36 @@ +/* This test exposed a bug in combine where it was improperly changing + the mode of a register. The bug appeared to be latent until web + was moved after combine. This is the reduced test that fails + by crashing in reload. */ + + +typedef struct cpp_reader cpp_reader; +typedef struct cpp_string cpp_string; +struct cpp_string +{ + unsigned int len; + const unsigned char *text; +}; +struct cpp_callbacks +{ + void (*ident) (cpp_reader *, unsigned int, const cpp_string *); +}; +static void cb_ident (cpp_reader *, unsigned int, const cpp_string *); +init_c_lex (void) +{ + struct cpp_callbacks *cb; + cb->ident = cb_ident; +} +cb_ident (cpp_reader * pfile __attribute__ ((__unused__)), unsigned int +line + __attribute__ ((__unused__)), const cpp_string * str + __attribute__ ((__unused__))) +{ + { + cpp_string cstr = { + }; + if (cpp_interpret_string (pfile, str, 1, &cstr, 0)) + { + } + } +} |