static int can_combine_p (rtx, rtx, rtx, rtx, rtx, rtx, rtx *, rtx *);
static int combinable_i3pat (rtx, rtx *, rtx, rtx, rtx, int, int, rtx *);
static int contains_muldiv (rtx);
-static rtx try_combine (rtx, rtx, rtx, rtx, int *);
+static rtx try_combine (rtx, rtx, rtx, rtx, int *, rtx);
static void undo_all (void);
static void undo_commit (void);
static rtx *find_split_point (rtx *, rtx, bool);
-static rtx subst (rtx, rtx, rtx, int, int);
-static rtx combine_simplify_rtx (rtx, enum machine_mode, int);
+static rtx subst (rtx, rtx, rtx, int, int, int);
+static rtx combine_simplify_rtx (rtx, enum machine_mode, int, int);
static rtx simplify_if_then_else (rtx);
static rtx simplify_set (rtx);
static rtx simplify_logical (rtx);
#define SUBST_MODE(INTO, NEWVAL) do_SUBST_MODE(&(INTO), (NEWVAL))
\f
-/* Subroutine of try_combine. Determine whether the combine replacement
- patterns NEWPAT, NEWI2PAT and NEWOTHERPAT are cheaper according to
- insn_rtx_cost that the original instruction sequence I0, I1, I2, I3 and
- undobuf.other_insn. Note that I1 and/or NEWI2PAT may be NULL_RTX.
- NEWOTHERPAT and undobuf.other_insn may also both be NULL_RTX. This
- function returns false, if the costs of all instructions can be
- estimated, and the replacements are more expensive than the original
- sequence. */
+/* Subroutine of try_combine. Determine whether the replacement patterns
+ NEWPAT, NEWI2PAT and NEWOTHERPAT are cheaper according to insn_rtx_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
+ of all the instructions can be estimated and the replacements are more
+ expensive than the original sequence. */
static bool
combine_validate_cost (rtx i0, rtx i1, rtx i2, rtx i3, rtx newpat,
old_cost = 0;
}
- /* Disallow this recombination if both new_cost and old_cost are
- greater than zero, and new_cost is greater than old cost. */
- if (old_cost > 0
- && new_cost > old_cost)
+ /* Disallow this combination if both new_cost and old_cost are greater than
+ zero, and new_cost is greater than old cost. */
+ if (old_cost > 0 && new_cost > old_cost)
{
if (dump_file)
{
INSN_COST (i2) = new_i2_cost;
INSN_COST (i3) = new_i3_cost;
if (i1)
- INSN_COST (i1) = 0;
+ {
+ INSN_COST (i1) = 0;
+ if (i0)
+ INSN_COST (i0) = 0;
+ }
return true;
}
FOR_EACH_BB (this_basic_block)
{
+ rtx last_combined_insn = NULL_RTX;
optimize_this_for_speed_p = optimize_bb_for_speed_p (this_basic_block);
last_call_luid = 0;
mem_last_set = -1;
next = 0;
if (NONDEBUG_INSN_P (insn))
{
+ while (last_combined_insn
+ && INSN_DELETED_P (last_combined_insn))
+ last_combined_insn = PREV_INSN (last_combined_insn);
+ if (last_combined_insn == NULL_RTX
+ || BARRIER_P (last_combined_insn)
+ || BLOCK_FOR_INSN (last_combined_insn) != this_basic_block
+ || DF_INSN_LUID (last_combined_insn) <= DF_INSN_LUID (insn))
+ last_combined_insn = insn;
+
/* See if we know about function return values before this
insn based upon SUBREG flags. */
check_promoted_subreg (insn, PATTERN (insn));
FOR_EACH_LOG_LINK (links, insn)
if ((next = try_combine (insn, links->insn, NULL_RTX,
- NULL_RTX, &new_direct_jump_p)) != 0)
+ NULL_RTX, &new_direct_jump_p,
+ last_combined_insn)) != 0)
goto retry;
/* Try each sequence of three linked insns ending with this one. */
FOR_EACH_LOG_LINK (nextlinks, link)
if ((next = try_combine (insn, link, nextlinks->insn,
- NULL_RTX,
- &new_direct_jump_p)) != 0)
+ NULL_RTX, &new_direct_jump_p,
+ last_combined_insn)) != 0)
goto retry;
}
&& sets_cc0_p (PATTERN (prev)))
{
if ((next = try_combine (insn, prev, NULL_RTX, NULL_RTX,
- &new_direct_jump_p)) != 0)
+ &new_direct_jump_p,
+ last_combined_insn)) != 0)
goto retry;
FOR_EACH_LOG_LINK (nextlinks, prev)
if ((next = try_combine (insn, prev, nextlinks->insn,
- NULL_RTX,
- &new_direct_jump_p)) != 0)
+ NULL_RTX, &new_direct_jump_p,
+ last_combined_insn)) != 0)
goto retry;
}
&& reg_mentioned_p (cc0_rtx, SET_SRC (PATTERN (insn))))
{
if ((next = try_combine (insn, prev, NULL_RTX, NULL_RTX,
- &new_direct_jump_p)) != 0)
+ &new_direct_jump_p,
+ last_combined_insn)) != 0)
goto retry;
FOR_EACH_LOG_LINK (nextlinks, prev)
if ((next = try_combine (insn, prev, nextlinks->insn,
- NULL_RTX,
- &new_direct_jump_p)) != 0)
+ NULL_RTX, &new_direct_jump_p,
+ last_combined_insn)) != 0)
goto retry;
}
&& NONJUMP_INSN_P (prev)
&& sets_cc0_p (PATTERN (prev))
&& (next = try_combine (insn, links->insn,
- prev, NULL_RTX,
- &new_direct_jump_p)) != 0)
+ prev, NULL_RTX, &new_direct_jump_p,
+ last_combined_insn)) != 0)
goto retry;
#endif
nextlinks = nextlinks->next)
if ((next = try_combine (insn, links->insn,
nextlinks->insn, NULL_RTX,
- &new_direct_jump_p)) != 0)
+ &new_direct_jump_p,
+ last_combined_insn)) != 0)
goto retry;
/* Try four-instruction combinations. */
FOR_EACH_LOG_LINK (nextlinks, link1)
if ((next = try_combine (insn, link, link1,
nextlinks->insn,
- &new_direct_jump_p)) != 0)
+ &new_direct_jump_p,
+ last_combined_insn)) != 0)
goto retry;
/* I0, I1 -> I2, I2 -> I3. */
for (nextlinks = next1->next; nextlinks;
nextlinks = nextlinks->next)
if ((next = try_combine (insn, link, link1,
nextlinks->insn,
- &new_direct_jump_p)) != 0)
+ &new_direct_jump_p,
+ last_combined_insn)) != 0)
goto retry;
}
FOR_EACH_LOG_LINK (nextlinks, link)
if ((next = try_combine (insn, link, link1,
nextlinks->insn,
- &new_direct_jump_p)) != 0)
+ &new_direct_jump_p,
+ last_combined_insn)) != 0)
goto retry;
/* I0 -> I1; I1, I2 -> I3. */
FOR_EACH_LOG_LINK (nextlinks, link1)
if ((next = try_combine (insn, link, link1,
nextlinks->insn,
- &new_direct_jump_p)) != 0)
+ &new_direct_jump_p,
+ last_combined_insn)) != 0)
goto retry;
}
}
i2mod_old_rhs = copy_rtx (orig);
i2mod_new_rhs = copy_rtx (note);
next = try_combine (insn, i2mod, NULL_RTX, NULL_RTX,
- &new_direct_jump_p);
+ &new_direct_jump_p,
+ last_combined_insn);
i2mod = NULL_RTX;
if (next)
goto retry;
}
/* Replace all the occurrences of DEST with SRC in DEBUG_INSNs between INSN
- and LAST. */
+ and LAST, not including INSN, but including LAST. Also stop at the end
+ of THIS_BASIC_BLOCK. */
static void
propagate_for_debug (rtx insn, rtx last, rtx dest, rtx src)
{
- rtx next, loc;
+ rtx next, loc, end = NEXT_INSN (BB_END (this_basic_block));
struct rtx_subst_pair p;
p.to = src;
p.adjusted = false;
next = NEXT_INSN (insn);
- while (next != last)
+ last = NEXT_INSN (last);
+ while (next != last && next != end)
{
insn = next;
next = NEXT_INSN (insn);
update_cfg_for_uncondjump (rtx insn)
{
basic_block bb = BLOCK_FOR_INSN (insn);
- bool at_end = (BB_END (bb) == insn);
+ gcc_assert (BB_END (bb) == insn);
- if (at_end)
- purge_dead_edges (bb);
+ purge_dead_edges (bb);
delete_insn (insn);
- if (at_end && EDGE_COUNT (bb->succs) == 1)
+ if (EDGE_COUNT (bb->succs) == 1)
{
rtx insn;
resume scanning.
Set NEW_DIRECT_JUMP_P to a nonzero value if try_combine creates a
- new direct jump instruction. */
+ new direct jump instruction.
+
+ LAST_COMBINED_INSN is either I3, or some insn after I3 that has
+ been I3 passed to an earlier try_combine within the same basic
+ block. */
static rtx
-try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p)
+try_combine (rtx i3, rtx i2, rtx i1, rtx i0, int *new_direct_jump_p,
+ rtx last_combined_insn)
{
/* New patterns for I3 and I2, respectively. */
rtx newpat, newi2pat = 0;
if (i1)
{
subst_low_luid = DF_INSN_LUID (i1);
- i1src = subst (i1src, pc_rtx, pc_rtx, 0, 0);
+ i1src = subst (i1src, pc_rtx, pc_rtx, 0, 0, 0);
}
subst_low_luid = DF_INSN_LUID (i2);
- i2src = subst (i2src, pc_rtx, pc_rtx, 0, 0);
+ i2src = subst (i2src, pc_rtx, pc_rtx, 0, 0, 0);
}
n_occurrences = 0; /* `subst' counts here */
self-referential RTL when we will be substituting I1SRC for I1DEST
later. Likewise if I0 feeds into I2, either directly or indirectly
through I1, and I0DEST is in I0SRC. */
- newpat = subst (PATTERN (i3), i2dest, i2src, 0,
+ newpat = subst (PATTERN (i3), i2dest, i2src, 0, 0,
(i1_feeds_i2_n && i1dest_in_i1src)
|| ((i0_feeds_i2_n || (i0_feeds_i1_n && i1_feeds_i2_n))
&& i0dest_in_i0src));
copy of I1SRC each time we substitute it, in order to avoid creating
self-referential RTL when we will be substituting I0SRC for I0DEST
later. */
- newpat = subst (newpat, i1dest, i1src, 0,
+ newpat = subst (newpat, i1dest, i1src, 0, 0,
i0_feeds_i1_n && i0dest_in_i0src);
substed_i1 = 1;
n_occurrences = 0;
subst_low_luid = DF_INSN_LUID (i0);
- newpat = subst (newpat, i0dest, i0src, 0, 0);
+ newpat = subst (newpat, i0dest, i0src, 0, 0, 0);
substed_i0 = 1;
}
{
rtx t = i1pat;
if (i0_feeds_i1_n)
- t = subst (t, i0dest, i0src, 0, 0);
+ t = subst (t, i0dest, i0src, 0, 0, 0);
XVECEXP (newpat, 0, --total_sets) = t;
}
{
rtx t = i2pat;
if (i1_feeds_i2_n)
- t = subst (t, i1dest, i1src_copy ? i1src_copy : i1src, 0,
+ t = subst (t, i1dest, i1src_copy ? i1src_copy : i1src, 0, 0,
i0_feeds_i1_n && i0dest_in_i0src);
if ((i0_feeds_i1_n && i1_feeds_i2_n) || i0_feeds_i2_n)
- t = subst (t, i0dest, i0src, 0, 0);
+ t = subst (t, i0dest, i0src, 0, 0, 0);
XVECEXP (newpat, 0, --total_sets) = t;
}
newpat = m_split;
}
else if (m_split && NEXT_INSN (NEXT_INSN (m_split)) == NULL_RTX
- && (next_real_insn (i2) == i3
+ && (next_nonnote_nondebug_insn (i2) == i3
|| ! use_crosses_set_p (PATTERN (m_split), DF_INSN_LUID (i2))))
{
rtx i2set, i3set;
is used between I2 and I3, we also can't use these insns. */
if (i2_code_number >= 0 && i2set && i3set
- && (next_real_insn (i2) == i3
+ && (next_nonnote_nondebug_insn (i2) == i3
|| ! reg_used_between_p (SET_DEST (i2set), i2, i3)))
insn_code_number = recog_for_combine (&newi3pat, i3,
&new_i3_notes);
|| GET_MODE (*split) == VOIDmode
|| can_change_dest_mode (i2dest, added_sets_2,
GET_MODE (*split)))
- && (next_real_insn (i2) == i3
+ && (next_nonnote_nondebug_insn (i2) == i3
|| ! use_crosses_set_p (*split, DF_INSN_LUID (i2)))
/* We can't overwrite I2DEST if its value is still used by
NEWPAT. */
i2src while its original mode is temporarily
restored, and then clear i2scratch so that we don't
do it again later. */
- propagate_for_debug (i2, i3, reg, i2src);
+ propagate_for_debug (i2, last_combined_insn, reg, i2src);
i2scratch = false;
/* Put back the new mode. */
adjust_reg_mode (reg, new_mode);
if (reg == i2dest)
{
first = i2;
- last = i3;
+ last = last_combined_insn;
}
else
{
first = i3;
last = undobuf.other_insn;
gcc_assert (last);
+ if (DF_INSN_LUID (last)
+ < DF_INSN_LUID (last_combined_insn))
+ last = last_combined_insn;
}
/* We're dealing with a reg that changed mode but not
if (newi2pat)
{
if (MAY_HAVE_DEBUG_INSNS && i2scratch)
- propagate_for_debug (i2, i3, i2dest, i2src);
+ propagate_for_debug (i2, last_combined_insn, i2dest, i2src);
INSN_CODE (i2) = i2_code_number;
PATTERN (i2) = newi2pat;
}
else
{
if (MAY_HAVE_DEBUG_INSNS && i2src)
- propagate_for_debug (i2, i3, i2dest, i2src);
+ propagate_for_debug (i2, last_combined_insn, i2dest, i2src);
SET_INSN_DELETED (i2);
}
LOG_LINKS (i1) = NULL;
REG_NOTES (i1) = 0;
if (MAY_HAVE_DEBUG_INSNS)
- propagate_for_debug (i1, i3, i1dest, i1src);
+ propagate_for_debug (i1, last_combined_insn, i1dest, i1src);
SET_INSN_DELETED (i1);
}
LOG_LINKS (i0) = NULL;
REG_NOTES (i0) = 0;
if (MAY_HAVE_DEBUG_INSNS)
- propagate_for_debug (i0, i3, i0dest, i0src);
+ propagate_for_debug (i0, last_combined_insn, i0dest, i0src);
SET_INSN_DELETED (i0);
}
/* A noop might also need cleaning up of CFG, if it comes from the
simplification of a jump. */
- if (GET_CODE (newpat) == SET
+ if (JUMP_P (i3)
+ && GET_CODE (newpat) == SET
&& SET_SRC (newpat) == pc_rtx
&& SET_DEST (newpat) == pc_rtx)
{
}
if (undobuf.other_insn != NULL_RTX
+ && JUMP_P (undobuf.other_insn)
&& GET_CODE (PATTERN (undobuf.other_insn)) == SET
&& SET_SRC (PATTERN (undobuf.other_insn)) == pc_rtx
&& SET_DEST (PATTERN (undobuf.other_insn)) == pc_rtx)
IN_DEST is nonzero if we are processing the SET_DEST of a SET.
+ IN_COND is nonzero if we are at the top level of a condition.
+
UNIQUE_COPY is nonzero if each substitution must be unique. We do this
by copying if `n_occurrences' is nonzero. */
static rtx
-subst (rtx x, rtx from, rtx to, int in_dest, int unique_copy)
+subst (rtx x, rtx from, rtx to, int in_dest, int in_cond, int unique_copy)
{
enum rtx_code code = GET_CODE (x);
enum machine_mode op0_mode = VOIDmode;
&& GET_CODE (XVECEXP (x, 0, 0)) == SET
&& GET_CODE (SET_SRC (XVECEXP (x, 0, 0))) == ASM_OPERANDS)
{
- new_rtx = subst (XVECEXP (x, 0, 0), from, to, 0, unique_copy);
+ new_rtx = subst (XVECEXP (x, 0, 0), from, to, 0, 0, unique_copy);
/* If this substitution failed, this whole thing fails. */
if (GET_CODE (new_rtx) == CLOBBER
&& GET_CODE (dest) != CC0
&& GET_CODE (dest) != PC)
{
- new_rtx = subst (dest, from, to, 0, unique_copy);
+ new_rtx = subst (dest, from, to, 0, 0, unique_copy);
/* If this substitution failed, this whole thing fails. */
if (GET_CODE (new_rtx) == CLOBBER
}
else
{
- new_rtx = subst (XVECEXP (x, i, j), from, to, 0,
- unique_copy);
+ new_rtx = subst (XVECEXP (x, i, j), from, to, 0, 0,
+ unique_copy);
/* If this substitution failed, this whole thing
fails. */
&& (code == SUBREG || code == STRICT_LOW_PART
|| code == ZERO_EXTRACT))
|| code == SET)
- && i == 0), unique_copy);
+ && i == 0),
+ code == IF_THEN_ELSE && i == 0,
+ unique_copy);
/* If we found that we will have to reject this combination,
indicate that by returning the CLOBBER ourselves, rather than
/* If X is sufficiently simple, don't bother trying to do anything
with it. */
if (code != CONST_INT && code != REG && code != CLOBBER)
- x = combine_simplify_rtx (x, op0_mode, in_dest);
+ x = combine_simplify_rtx (x, op0_mode, in_dest, in_cond);
if (GET_CODE (x) == code)
break;
expression.
OP0_MODE is the original mode of XEXP (x, 0). IN_DEST is nonzero
- if we are inside a SET_DEST. */
+ if we are inside a SET_DEST. IN_COND is nonzero if we are at the top level
+ of a condition. */
static rtx
-combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
+combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest,
+ int in_cond)
{
enum rtx_code code = GET_CODE (x);
enum machine_mode mode = GET_MODE (x);
false arms to store-flag values. Be careful to use copy_rtx
here since true_rtx or false_rtx might share RTL with x as a
result of the if_then_else_cond call above. */
- true_rtx = subst (copy_rtx (true_rtx), pc_rtx, pc_rtx, 0, 0);
- false_rtx = subst (copy_rtx (false_rtx), pc_rtx, pc_rtx, 0, 0);
+ true_rtx = subst (copy_rtx (true_rtx), pc_rtx, pc_rtx, 0, 0, 0);
+ false_rtx = subst (copy_rtx (false_rtx), pc_rtx, pc_rtx, 0, 0, 0);
/* If true_rtx and false_rtx are not general_operands, an if_then_else
is unlikely to be simpler. */
{
/* Try to simplify the expression further. */
rtx tor = simplify_gen_binary (IOR, mode, XEXP (x, 0), XEXP (x, 1));
- temp = combine_simplify_rtx (tor, mode, in_dest);
+ temp = combine_simplify_rtx (tor, mode, in_dest, 0);
/* If we could, great. If not, do not go ahead with the IOR
replacement, since PLUS appears in many special purpose
Remove any ZERO_EXTRACT we made when thinking this was a
comparison. It may now be simpler to use, e.g., an AND. If a
ZERO_EXTRACT is indeed appropriate, it will be placed back by
- the call to make_compound_operation in the SET case. */
+ the call to make_compound_operation in the SET case.
+
+ Don't apply these optimizations if the caller would
+ prefer a comparison rather than a value.
+ E.g., for the condition in an IF_THEN_ELSE most targets need
+ an explicit comparison. */
- if (STORE_FLAG_VALUE == 1
+ if (in_cond)
+ ;
+
+ else if (STORE_FLAG_VALUE == 1
&& new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
&& op1 == const0_rtx
&& mode == GET_MODE (op0)
/* If STORE_FLAG_VALUE is -1, we have cases similar to
those above. */
- if (STORE_FLAG_VALUE == -1
+ if (in_cond)
+ ;
+
+ else if (STORE_FLAG_VALUE == -1
&& new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
&& op1 == const0_rtx
&& (num_sign_bit_copies (op0, mode)
if (reg_mentioned_p (from, true_rtx))
true_rtx = subst (known_cond (copy_rtx (true_rtx), true_code,
from, true_val),
- pc_rtx, pc_rtx, 0, 0);
+ pc_rtx, pc_rtx, 0, 0, 0);
if (reg_mentioned_p (from, false_rtx))
false_rtx = subst (known_cond (copy_rtx (false_rtx), false_code,
from, false_val),
- pc_rtx, pc_rtx, 0, 0);
+ pc_rtx, pc_rtx, 0, 0, 0);
SUBST (XEXP (x, 1), swapped ? false_rtx : true_rtx);
SUBST (XEXP (x, 2), swapped ? true_rtx : false_rtx);
{
temp = subst (simplify_gen_relational (true_code, m, VOIDmode,
cond_op0, cond_op1),
- pc_rtx, pc_rtx, 0, 0);
+ pc_rtx, pc_rtx, 0, 0, 0);
temp = simplify_gen_binary (MULT, m, temp,
simplify_gen_binary (MULT, m, c1,
const_true_rtx));
- temp = subst (temp, pc_rtx, pc_rtx, 0, 0);
+ temp = subst (temp, pc_rtx, pc_rtx, 0, 0, 0);
temp = simplify_gen_binary (op, m, gen_lowpart (m, z), temp);
if (extend_op != UNKNOWN)