This patch fixes PR rtl-optimization/60155.
The PA backend has a number of INSN patterns which trap on signed
overflow. These are
implemented as parallels using the trap_if code. Currently,
single_set does not consider
a parallel with a trap_if rtx to be a single set. This causes an ICE
in gcse.c when an insn with
a trap_if is encountered.
The problem is fixed by implementing a gcse specific version of
"single_set" which only
looks at whether there is a single non-dead set in an insn pattern.
It allows multiple other
sets if they are dead.
Tested on hppa-unknown-linux-gnu, hppa2.0w-hp-hpux11.11 and hppa64-hp-
hpux11.11.
OK for trunk?
Dave
--
John David Anglin dave.ang...@bell.net
2014-03-13 John David Anglin <dang...@gcc.gnu.org>
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.
Index: gcse.c
===================================================================
--- gcse.c (revision 208442)
+++ gcse.c (working copy)
@@ -2502,6 +2502,57 @@
}
}
+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;
+
+ s.insn = insn;
+ s.nsets = 0;
+ note_stores (PATTERN (insn), 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 +2560,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 +3421,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 +3507,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);