before the memory reference. */
gcc_assert (mov_insn);
emit_insn_before (mov_insn, inc_insn.insn);
- move_dead_notes (mov_insn, inc_insn.insn, inc_insn.reg0);
+ regno = REGNO (inc_insn.reg0);
+ if (reg_next_use[regno] == mem_insn.insn)
+ move_dead_notes (mov_insn, mem_insn.insn, inc_insn.reg0);
+ else
+ move_dead_notes (mov_insn, inc_insn.insn, inc_insn.reg0);
regno = REGNO (inc_insn.reg_res);
reg_next_def[regno] = mov_insn;
/* A recursive function that checks all of the mem uses in
ADDRESS_OF_X to see if any single one of them is compatible with
- what has been found in inc_insn.
+ what has been found in inc_insn. To avoid accidental matches, we
+ will only find MEMs with FINDREG, be it inc_insn.reg_res, be it
+ inc_insn.reg0.
-1 is returned for success. 0 is returned if nothing was found and
1 is returned for failure. */
static int
-find_address (rtx *address_of_x)
+find_address (rtx *address_of_x, rtx findreg)
{
rtx x = *address_of_x;
enum rtx_code code = GET_CODE (x);
int value = 0;
int tem;
- if (code == MEM && rtx_equal_p (XEXP (x, 0), inc_insn.reg_res))
+ if (code == MEM && findreg == inc_insn.reg_res
+ && rtx_equal_p (XEXP (x, 0), inc_insn.reg_res))
{
- /* Match with *reg0. */
+ /* Match with *reg_res. */
mem_insn.mem_loc = address_of_x;
mem_insn.reg0 = inc_insn.reg_res;
mem_insn.reg1_is_const = true;
mem_insn.reg1 = GEN_INT (0);
return -1;
}
- if (code == MEM && GET_CODE (XEXP (x, 0)) == PLUS
+ if (code == MEM && inc_insn.reg1_is_const && inc_insn.reg0
+ && findreg == inc_insn.reg0
+ && rtx_equal_p (XEXP (x, 0), inc_insn.reg0))
+ {
+ /* Match with *reg0, assumed to be equivalent to
+ *(reg_res - reg1_val); callers must check whether this is the case. */
+ mem_insn.mem_loc = address_of_x;
+ mem_insn.reg0 = inc_insn.reg_res;
+ mem_insn.reg1_is_const = true;
+ mem_insn.reg1_val = -inc_insn.reg1_val;
+ mem_insn.reg1 = GEN_INT (mem_insn.reg1_val);
+ return -1;
+ }
+ if (code == MEM && findreg == inc_insn.reg_res
+ && GET_CODE (XEXP (x, 0)) == PLUS
&& rtx_equal_p (XEXP (XEXP (x, 0), 0), inc_insn.reg_res))
{
rtx b = XEXP (XEXP (x, 0), 1);
{
/* If REG occurs inside a MEM used in a bit-field reference,
that is unacceptable. */
- if (find_address (&XEXP (x, 0)))
+ if (find_address (&XEXP (x, 0), findreg))
return 1;
}
{
if (fmt[i] == 'e')
{
- tem = find_address (&XEXP (x, i));
+ tem = find_address (&XEXP (x, i), findreg);
/* If this is the first use, let it go so the rest of the
insn can be checked. */
if (value == 0)
int j;
for (j = XVECLEN (x, i) - 1; j >= 0; j--)
{
- tem = find_address (&XVECEXP (x, i, j));
+ tem = find_address (&XVECEXP (x, i, j), findreg);
/* If this is the first use, let it go so the rest of
the insn can be checked. */
if (value == 0)
if (dump_file)
dump_inc_insn (dump_file);
- if (ok && find_address (&PATTERN (mem_insn.insn)) == -1)
+ if (ok && find_address (&PATTERN (mem_insn.insn),
+ inc_insn.reg_res) == -1)
+ {
+ if (dump_file)
+ dump_mem_insn (dump_file);
+ if (try_merge ())
+ {
+ success_in_block++;
+ insn_is_add_or_inc = false;
+ }
+ }
+ }
+
+ if (insn_is_add_or_inc
+ /* find_address will only recognize an address
+ with a reg0 that's not reg_res when
+ reg1_is_const, so cut it off early if we
+ already know it won't match. */
+ && inc_insn.reg1_is_const
+ && inc_insn.reg0
+ && inc_insn.reg0 != inc_insn.reg_res)
+ {
+ /* If we identified an inc_insn that uses two
+ different pseudos, it's of the form
+
+ (set reg_res (plus reg0 reg1))
+
+ where reg1 is a constant (*).
+
+ The next use of reg_res was not idenfied by
+ find_address as a mem_insn that we could turn
+ into auto-inc, so see if we find a suitable
+ MEM in the next use of reg0, as long as it's
+ before any subsequent use of reg_res:
+
+ ... (mem (... reg0 ...)) ...
+
+ ... reg_res ...
+
+ In this case, we can turn the plus into a
+ copy, and the reg0 in the MEM address into a
+ post_inc of reg_res:
+
+ (set reg_res reg0)
+
+ ... (mem (... (post_add reg_res reg1) ...)) ...
+
+ reg_res will then have the correct value at
+ subsequent uses, and reg0 will remain
+ unchanged.
+
+ (*) We could support non-const reg1, but then
+ we'd have to check that reg1 remains
+ unchanged all the way to the modified MEM,
+ and we'd have to extend find_address to
+ represent a non-const negated reg1. */
+ regno = REGNO (inc_insn.reg0);
+ rtx_insn *reg0_use = get_next_ref (regno, bb,
+ reg_next_use);
+
+ /* Give up if the next use of reg0 is after the next
+ use of reg_res (same insn is ok; we might have
+ found a MEM with reg_res before, and that failed,
+ but now we try reg0, which might work), or defs
+ of reg_res (same insn is not ok, we'd introduce
+ another def in the same insn) or reg0. */
+ if (reg0_use)
+ {
+ int luid = DF_INSN_LUID (reg0_use);
+
+ /* It might seem pointless to introduce an
+ auto-inc if there's no subsequent use of
+ reg_res (i.e., mem_insn.insn == NULL), but
+ the next use might be in the next iteration
+ of a loop, and it won't hurt if we make the
+ change even if it's not needed. */
+ if (mem_insn.insn
+ && luid > DF_INSN_LUID (mem_insn.insn))
+ reg0_use = NULL;
+
+ rtx_insn *other_insn
+ = get_next_ref (REGNO (inc_insn.reg_res), bb,
+ reg_next_def);
+
+ if (other_insn && luid >= DF_INSN_LUID (other_insn))
+ reg0_use = NULL;
+
+ other_insn
+ = get_next_ref (REGNO (inc_insn.reg0), bb,
+ reg_next_def);
+
+ if (other_insn && luid > DF_INSN_LUID (other_insn))
+ reg0_use = NULL;
+ }
+
+ mem_insn.insn = reg0_use;
+
+ if (mem_insn.insn
+ && find_address (&PATTERN (mem_insn.insn),
+ inc_insn.reg0) == -1)
{
if (dump_file)
dump_mem_insn (dump_file);