aboutsummaryrefslogtreecommitdiff
path: root/gcc/combine.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/combine.cc')
-rw-r--r--gcc/combine.cc139
1 files changed, 94 insertions, 45 deletions
diff --git a/gcc/combine.cc b/gcc/combine.cc
index ef13f5d..4dbc1f6 100644
--- a/gcc/combine.cc
+++ b/gcc/combine.cc
@@ -309,6 +309,7 @@ static int *uid_insn_cost;
struct insn_link {
rtx_insn *insn;
unsigned int regno;
+ int insn_count;
struct insn_link *next;
};
@@ -342,6 +343,7 @@ alloc_insn_link (rtx_insn *insn, unsigned int regno, struct insn_link *next)
sizeof (struct insn_link));
l->insn = insn;
l->regno = regno;
+ l->insn_count = 0;
l->next = next;
return l;
}
@@ -456,6 +458,7 @@ static rtx simplify_shift_const (rtx, enum rtx_code, machine_mode, rtx,
int);
static int recog_for_combine (rtx *, rtx_insn *, rtx *, unsigned = 0, unsigned = 0);
static rtx gen_lowpart_for_combine (machine_mode, rtx);
+static rtx gen_lowpart_for_combine_no_emit (machine_mode, rtx);
static enum rtx_code simplify_compare_const (enum rtx_code, machine_mode,
rtx *, rtx *);
static enum rtx_code simplify_comparison (enum rtx_code, rtx *, rtx *);
@@ -472,7 +475,8 @@ static void move_deaths (rtx, rtx, int, rtx_insn *, rtx *);
static bool reg_bitfield_target_p (rtx, rtx);
static void distribute_notes (rtx, rtx_insn *, rtx_insn *, rtx_insn *,
rtx, rtx, rtx);
-static void distribute_links (struct insn_link *);
+static void distribute_links (struct insn_link *, rtx_insn * = nullptr,
+ int limit = INT_MAX);
static void mark_used_regs_combine (rtx);
static void record_promoted_value (rtx_insn *, rtx);
static bool unmentioned_reg_p (rtx, rtx);
@@ -488,7 +492,7 @@ static rtx gen_lowpart_or_truncate (machine_mode, rtx);
/* Our implementation of gen_lowpart never emits a new pseudo. */
#undef RTL_HOOKS_GEN_LOWPART_NO_EMIT
-#define RTL_HOOKS_GEN_LOWPART_NO_EMIT gen_lowpart_for_combine
+#define RTL_HOOKS_GEN_LOWPART_NO_EMIT gen_lowpart_for_combine_no_emit
#undef RTL_HOOKS_REG_NONZERO_REG_BITS
#define RTL_HOOKS_REG_NONZERO_REG_BITS reg_nonzero_bits_for_combine
@@ -812,7 +816,7 @@ do_SUBST_LINK (struct insn_link **into, struct insn_link *newval)
#define SUBST_LINK(oldval, newval) do_SUBST_LINK (&oldval, newval)
/* Subroutine of try_combine. Determine whether the replacement patterns
- NEWPAT, NEWI2PAT and NEWOTHERPAT are cheaper according to insn_cost
+ NEWPAT, NEWI2PAT and NEWOTHERPAT are more expensive according to insn_cost
than the original sequence I0, I1, I2, I3 and undobuf.other_insn. Note
that I0, I1 and/or NEWI2PAT may be NULL_RTX. Similarly, NEWOTHERPAT and
undobuf.other_insn may also both be NULL_RTX. Return false if the cost
@@ -4012,37 +4016,39 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
rtx set1 = XVECEXP (newpat, 0, 1);
/* Normally, it doesn't matter which of the two is done first, but
- one which uses any regs/memory set in between i2 and i3 can't
- be first. The PARALLEL might also have been pre-existing in i3,
- so we need to make sure that we won't wrongly hoist a SET to i2
- that would conflict with a death note present in there, or would
- have its dest modified between i2 and i3. */
- if (!modified_between_p (SET_SRC (set1), i2, i3)
- && !(REG_P (SET_DEST (set1))
- && find_reg_note (i2, REG_DEAD, SET_DEST (set1)))
- && !(GET_CODE (SET_DEST (set1)) == SUBREG
- && find_reg_note (i2, REG_DEAD,
- SUBREG_REG (SET_DEST (set1))))
- && !modified_between_p (SET_DEST (set1), i2, i3)
+ one which uses any regs/memory set or used in between i2 and i3
+ can't be first. The PARALLEL might also have been pre-existing
+ in i3, so we need to make sure that we won't wrongly hoist a SET
+ to i2 that would conflict with a death note present in there, or
+ would have its dest modified or used between i2 and i3. */
+ if ((set_noop_p (set1)
+ || (!modified_between_p (SET_SRC (set1), i2, i3)
+ && !(REG_P (SET_DEST (set1))
+ && find_reg_note (i2, REG_DEAD, SET_DEST (set1)))
+ && !(GET_CODE (SET_DEST (set1)) == SUBREG
+ && find_reg_note (i2, REG_DEAD,
+ SUBREG_REG (SET_DEST (set1))))
+ && SET_DEST (set1) != pc_rtx
+ && !reg_used_between_p (SET_DEST (set1), i2, i3)))
/* If I3 is a jump, ensure that set0 is a jump so that
we do not create invalid RTL. */
- && (!JUMP_P (i3) || SET_DEST (set0) == pc_rtx)
- )
+ && (!JUMP_P (i3) || SET_DEST (set0) == pc_rtx))
{
newi2pat = set1;
newpat = set0;
}
- else if (!modified_between_p (SET_SRC (set0), i2, i3)
- && !(REG_P (SET_DEST (set0))
- && find_reg_note (i2, REG_DEAD, SET_DEST (set0)))
- && !(GET_CODE (SET_DEST (set0)) == SUBREG
- && find_reg_note (i2, REG_DEAD,
- SUBREG_REG (SET_DEST (set0))))
- && !modified_between_p (SET_DEST (set0), i2, i3)
+ else if ((set_noop_p (set0)
+ || (!modified_between_p (SET_SRC (set0), i2, i3)
+ && !(REG_P (SET_DEST (set0))
+ && find_reg_note (i2, REG_DEAD, SET_DEST (set0)))
+ && !(GET_CODE (SET_DEST (set0)) == SUBREG
+ && find_reg_note (i2, REG_DEAD,
+ SUBREG_REG (SET_DEST (set0))))
+ && SET_DEST (set0) != pc_rtx
+ && !reg_used_between_p (SET_DEST (set0), i2, i3)))
/* If I3 is a jump, ensure that set1 is a jump so that
we do not create invalid RTL. */
- && (!JUMP_P (i3) || SET_DEST (set1) == pc_rtx)
- )
+ && (!JUMP_P (i3) || SET_DEST (set1) == pc_rtx))
{
newi2pat = set0;
newpat = set1;
@@ -4124,8 +4130,8 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
}
}
- /* Only allow this combination if insn_cost reports that the
- replacement instructions are cheaper than the originals. */
+ /* Reject this combination if insn_cost reports that the replacement
+ instructions are more expensive than the originals. */
if (!combine_validate_cost (i0, i1, i2, i3, newpat, newi2pat, other_pat))
{
undo_all ();
@@ -4208,16 +4214,13 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
adjust_for_new_dest (i3);
}
- /* If I2 didn't change, this is not a combination (but a simplification or
- canonicalisation with context), which should not be done here. Doing
- it here explodes the algorithm. Don't. */
- if (rtx_equal_p (newi2pat, PATTERN (i2)))
- {
- if (dump_file)
- fprintf (dump_file, "i2 didn't change, not doing this\n");
- undo_all ();
- return 0;
- }
+ bool only_i3_changed = !i0 && !i1 && rtx_equal_p (newi2pat, PATTERN (i2));
+
+ /* If only i3 has changed, any split of the combined instruction just
+ restored i2 to its original state. No destinations moved from i3
+ to i2. */
+ if (only_i3_changed)
+ split_i2i3 = false;
/* We now know that we can do this combination. Merge the insns and
update the status of registers and LOG_LINKS. */
@@ -4593,10 +4596,15 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
NULL_RTX, NULL_RTX, NULL_RTX);
}
- distribute_links (i3links);
- distribute_links (i2links);
- distribute_links (i1links);
- distribute_links (i0links);
+ if (only_i3_changed)
+ distribute_links (i3links, i3, param_max_combine_search_insns);
+ else
+ {
+ distribute_links (i3links);
+ distribute_links (i2links, i2);
+ distribute_links (i1links);
+ distribute_links (i0links);
+ }
if (REG_P (i2dest))
{
@@ -4785,6 +4793,9 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
combine_successes++;
undo_commit ();
+ if (only_i3_changed)
+ return i3;
+
rtx_insn *ret = newi2pat ? i2 : i3;
if (added_links_insn && DF_INSN_LUID (added_links_insn) < DF_INSN_LUID (ret))
ret = added_links_insn;
@@ -5270,6 +5281,12 @@ find_split_point (rtx *loc, rtx_insn *insn, bool set_src)
SUBST (XEXP (x, 0), XEXP (x, 1));
SUBST (XEXP (x, 1), tem);
}
+ /* Many targets have a `(and (not X) Y)` and/or `(ior (not X) Y)` instructions.
+ Split at that insns. However if this is
+ the SET_SRC, we likely do not have such an instruction and it's
+ worthless to try this split. */
+ if (!set_src && GET_CODE (XEXP (x, 0)) == NOT)
+ return loc;
break;
case PLUS:
@@ -11874,6 +11891,22 @@ gen_lowpart_for_combine (machine_mode omode, rtx x)
fail:
return gen_rtx_CLOBBER (omode, const0_rtx);
}
+
+/* Like gen_lowpart_for_combine but returns NULL_RTX
+ for an error instead of CLOBBER.
+ Note no_emit is not called directly from combine but rather from
+ simplify_rtx and is expecting a NULL on failure rather than
+ a CLOBBER. */
+
+static rtx
+gen_lowpart_for_combine_no_emit (machine_mode omode, rtx x)
+{
+ rtx tem = gen_lowpart_for_combine (omode, x);
+ if (!tem || GET_CODE (tem) == CLOBBER)
+ return NULL_RTX;
+ return tem;
+}
+
/* Try to simplify a comparison between OP0 and a constant OP1,
where CODE is the comparison code that will be tested, into a
@@ -14984,10 +15017,15 @@ distribute_notes (rtx notes, rtx_insn *from_insn, rtx_insn *i3, rtx_insn *i2,
/* Similarly to above, distribute the LOG_LINKS that used to be present on
I3, I2, and I1 to new locations. This is also called to add a link
- pointing at I3 when I3's destination is changed. */
+ pointing at I3 when I3's destination is changed.
+
+ If START is nonnull and an insn, we know that the next location for each
+ link is no earlier than START. LIMIT is the maximum number of nondebug
+ instructions that can be scanned when looking for the next use of a
+ definition. */
static void
-distribute_links (struct insn_link *links)
+distribute_links (struct insn_link *links, rtx_insn *start, int limit)
{
struct insn_link *link, *next_link;
@@ -15053,7 +15091,13 @@ distribute_links (struct insn_link *links)
I3 to I2. Also note that not much searching is typically done here
since most links don't point very far away. */
- for (insn = NEXT_INSN (link->insn);
+ int count = 0;
+ insn = start;
+ if (!insn || NOTE_P (insn))
+ insn = NEXT_INSN (link->insn);
+ else
+ count = link->insn_count;
+ for (;
(insn && (this_basic_block->next_bb == EXIT_BLOCK_PTR_FOR_FN (cfun)
|| BB_HEAD (this_basic_block->next_bb) != insn));
insn = NEXT_INSN (insn))
@@ -15073,6 +15117,11 @@ distribute_links (struct insn_link *links)
}
else if (INSN_P (insn) && reg_set_p (reg, insn))
break;
+ else if (count >= limit)
+ break;
+ else
+ count += 1;
+ link->insn_count = count;
/* If we found a place to put the link, place it there unless there
is already a link to the same insn as LINK at that point. */