| From gcc bugzilla https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60155 |
| Upstream status: in trunk. |
| |
| Signed-off-by: Gustavo Zacarias <gustavo@zacarias.com.ar> |
| |
| --- trunk/gcc/gcse.c 2014/02/12 14:50:06 207726 |
| +++ trunk/gcc/gcse.c 2014/04/04 22:25:51 209134 |
| @@ -2502,6 +2502,65 @@ |
| } |
| } |
| |
| +struct set_data |
| +{ |
| + rtx insn; |
| + const_rtx set; |
| + int nsets; |
| +}; |
| + |
| +/* Increment number of sets and record set in DATA. */ |
| + |
| +static void |
| +record_set_data (rtx dest, const_rtx set, void *data) |
| +{ |
| + struct set_data *s = (struct set_data *)data; |
| + |
| + if (GET_CODE (set) == SET) |
| + { |
| + /* We allow insns having multiple sets, where all but one are |
| + dead as single set insns. In the common case only a single |
| + set is present, so we want to avoid checking for REG_UNUSED |
| + notes unless necessary. */ |
| + if (s->nsets == 1 |
| + && find_reg_note (s->insn, REG_UNUSED, SET_DEST (s->set)) |
| + && !side_effects_p (s->set)) |
| + s->nsets = 0; |
| + |
| + if (!s->nsets) |
| + { |
| + /* Record this set. */ |
| + s->nsets += 1; |
| + s->set = set; |
| + } |
| + else if (!find_reg_note (s->insn, REG_UNUSED, dest) |
| + || side_effects_p (set)) |
| + s->nsets += 1; |
| + } |
| +} |
| + |
| +static const_rtx |
| +single_set_gcse (rtx insn) |
| +{ |
| + struct set_data s; |
| + rtx pattern; |
| + |
| + gcc_assert (INSN_P (insn)); |
| + |
| + /* Optimize common case. */ |
| + pattern = PATTERN (insn); |
| + if (GET_CODE (pattern) == SET) |
| + return pattern; |
| + |
| + s.insn = insn; |
| + s.nsets = 0; |
| + note_stores (pattern, record_set_data, &s); |
| + |
| + /* Considered invariant insns have exactly one set. */ |
| + gcc_assert (s.nsets == 1); |
| + return s.set; |
| +} |
| + |
| /* Emit move from SRC to DEST noting the equivalence with expression computed |
| in INSN. */ |
| |
| @@ -2509,7 +2568,8 @@ |
| gcse_emit_move_after (rtx dest, rtx src, rtx insn) |
| { |
| rtx new_rtx; |
| - rtx set = single_set (insn), set2; |
| + const_rtx set = single_set_gcse (insn); |
| + rtx set2; |
| rtx note; |
| rtx eqv = NULL_RTX; |
| |
| @@ -3369,13 +3429,12 @@ |
| FOR_EACH_VEC_ELT (occrs_to_hoist, j, occr) |
| { |
| rtx insn; |
| - rtx set; |
| + const_rtx set; |
| |
| gcc_assert (!occr->deleted_p); |
| |
| insn = occr->insn; |
| - set = single_set (insn); |
| - gcc_assert (set); |
| + set = single_set_gcse (insn); |
| |
| /* Create a pseudo-reg to store the result of reaching |
| expressions into. Get the mode for the new pseudo |
| @@ -3456,10 +3515,8 @@ |
| { |
| rtx reg; |
| enum reg_class pressure_class; |
| - rtx set = single_set (insn); |
| + const_rtx set = single_set_gcse (insn); |
| |
| - /* Considered invariant insns have only one set. */ |
| - gcc_assert (set != NULL_RTX); |
| reg = SET_DEST (set); |
| if (GET_CODE (reg) == SUBREG) |
| reg = SUBREG_REG (reg); |