summaryrefslogtreecommitdiff
path: root/gcc/gcse.c
diff options
context:
space:
mode:
authorJohn David Anglin <danglin@gcc.gnu.org>2014-04-04 22:25:51 +0000
committerJohn David Anglin <danglin@gcc.gnu.org>2014-04-04 22:25:51 +0000
commitb680881871eeab3095ffc35c73b34662803ea4fb (patch)
tree6943553dd4373405684e3bec66c0ad48f3934029 /gcc/gcse.c
parent3e0da29a996ff9457f973781dd233835bb793b3a (diff)
re PR rtl-optimization/60155 (ICE: in get_pressure_class_and_nregs at gcse.c:3438)
PR rtl-optimization/60155 * gcse.c (record_set_data): New function. (single_set_gcse): New function. (gcse_emit_move_after): Use single_set_gcse instead of single_set. (hoist_code): Likewise. (get_pressure_class_and_nregs): Likewise. From-SVN: r209134
Diffstat (limited to 'gcc/gcse.c')
-rw-r--r--gcc/gcse.c71
1 files changed, 64 insertions, 7 deletions
diff --git a/gcc/gcse.c b/gcc/gcse.c
index 2bb0b5fec1e..b852aa1bf22 100644
--- a/gcc/gcse.c
+++ b/gcc/gcse.c
@@ -2502,6 +2502,65 @@ pre_insert_copies (void)
}
}
+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 @@ static rtx
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 @@ hoist_code (void)
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 @@ get_pressure_class_and_nregs (rtx insn, int *nregs)
{
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);