112 lines
2.6 KiB
Diff
112 lines
2.6 KiB
Diff
|
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);
|