/* Optimize by combining instructions for GNU compiler.
Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- 2011 Free Software Foundation, Inc.
+ 2011, 2012 Free Software Foundation, Inc.
This file is part of GCC.
/* Record one modification to rtl structure
to be undone by storing old_contents into *where. */
-enum undo_kind { UNDO_RTX, UNDO_INT, UNDO_MODE };
+enum undo_kind { UNDO_RTX, UNDO_INT, UNDO_MODE, UNDO_LINKS };
struct undo
{
struct undo *next;
enum undo_kind kind;
- union { rtx r; int i; enum machine_mode m; } old_contents;
- union { rtx *r; int *i; } where;
+ union { rtx r; int i; enum machine_mode m; struct insn_link *l; } old_contents;
+ union { rtx *r; int *i; struct insn_link **l; } where;
};
/* Record a bunch of changes to be undone, up to MAX_UNDO of them.
}
#define SUBST_MODE(INTO, NEWVAL) do_SUBST_MODE(&(INTO), (NEWVAL))
+
+#ifndef HAVE_cc0
+/* Similar to SUBST, but NEWVAL is a LOG_LINKS expression. */
+
+static void
+do_SUBST_LINK (struct insn_link **into, struct insn_link *newval)
+{
+ struct undo *buf;
+ struct insn_link * oldval = *into;
+
+ if (oldval == newval)
+ return;
+
+ if (undobuf.frees)
+ buf = undobuf.frees, undobuf.frees = buf->next;
+ else
+ buf = XNEW (struct undo);
+
+ buf->kind = UNDO_LINKS;
+ buf->where.l = into;
+ buf->old_contents.l = oldval;
+ *into = newval;
+
+ buf->next = undobuf.undos, undobuf.undos = buf;
+}
+
+#define SUBST_LINK(oldval, newval) do_SUBST_LINK (&oldval, newval)
+#endif
\f
/* Subroutine of try_combine. Determine whether the replacement patterns
NEWPAT, NEWI2PAT and NEWOTHERPAT are cheaper according to insn_rtx_cost
rtx link;
#endif
bool all_adjacent = true;
+ int (*is_volatile_p) (const_rtx);
if (succ)
{
if (set == 0)
return 0;
+ /* The simplification in expand_field_assignment may call back to
+ get_last_value, so set safe guard here. */
+ subst_low_luid = DF_INSN_LUID (insn);
+
set = expand_field_assignment (set);
src = SET_SRC (set), dest = SET_DEST (set);
&& REG_P (dest) && REGNO (dest) < FIRST_PSEUDO_REGISTER)
return 0;
- /* If there are any volatile insns between INSN and I3, reject, because
- they might affect machine state. */
+ /* If INSN contains volatile references (specifically volatile MEMs),
+ we cannot combine across any other volatile references.
+ Even if INSN doesn't contain volatile references, any intervening
+ volatile insn might affect machine state. */
+ is_volatile_p = volatile_refs_p (PATTERN (insn))
+ ? volatile_refs_p
+ : volatile_insn_p;
+
for (p = NEXT_INSN (insn); p != i3; p = NEXT_INSN (p))
- if (INSN_P (p) && p != succ && p != succ2 && volatile_insn_p (PATTERN (p)))
+ if (INSN_P (p) && p != succ && p != succ2 && is_volatile_p (PATTERN (p)))
return 0;
/* If INSN contains an autoincrement or autodecrement, make sure that
rtx i3dest_killed = 0;
/* SET_DEST and SET_SRC of I2, I1 and I0. */
rtx i2dest = 0, i2src = 0, i1dest = 0, i1src = 0, i0dest = 0, i0src = 0;
- /* Copy of SET_SRC of I1, if needed. */
- rtx i1src_copy = 0;
+ /* Copy of SET_SRC of I1 and I0, if needed. */
+ rtx i1src_copy = 0, i0src_copy = 0, i0src_copy2 = 0;
/* Set if I2DEST was reused as a scratch register. */
bool i2scratch = false;
/* The PATTERNs of I0, I1, and I2, or a copy of them in certain cases. */
SUBST (PATTERN (i2), XVECEXP (PATTERN (i2), 0, 0));
SUBST (XEXP (SET_SRC (PATTERN (i2)), 0),
SET_DEST (PATTERN (i1)));
+ SUBST_LINK (LOG_LINKS (i2), alloc_insn_link (i1, LOG_LINKS (i2)));
}
}
#endif
n_occurrences = 0;
subst_low_luid = DF_INSN_LUID (i1);
+ /* If the following substitution will modify I1SRC, make a copy of it
+ for the case where it is substituted for I1DEST in I2PAT later. */
+ if (added_sets_2 && i1_feeds_i2_n)
+ i1src_copy = copy_rtx (i1src);
+
/* If I0 feeds into I1 and I0DEST is in I0SRC, we need to make a unique
copy of I1SRC each time we substitute it, in order to avoid creating
self-referential RTL when we will be substituting I0SRC for I0DEST
return 0;
}
- /* If the following substitution will modify I1SRC, make a copy of it
- for the case where it is substituted for I1DEST in I2PAT later. */
- if (i0_feeds_i1_n && added_sets_2 && i1_feeds_i2_n)
- i1src_copy = copy_rtx (i1src);
+ /* If the following substitution will modify I0SRC, make a copy of it
+ for the case where it is substituted for I0DEST in I1PAT later. */
+ if (added_sets_1 && i0_feeds_i1_n)
+ i0src_copy = copy_rtx (i0src);
+ /* And a copy for I0DEST in I2PAT substitution. */
+ if (added_sets_2 && ((i0_feeds_i1_n && i1_feeds_i2_n)
+ || (i0_feeds_i2_n)))
+ i0src_copy2 = copy_rtx (i0src);
n_occurrences = 0;
subst_low_luid = DF_INSN_LUID (i0);
{
rtx t = i1pat;
if (i0_feeds_i1_n)
- t = subst (t, i0dest, i0src, 0, 0, 0);
+ t = subst (t, i0dest, i0src_copy ? i0src_copy : i0src, 0, 0, 0);
XVECEXP (newpat, 0, --total_sets) = t;
}
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, 0);
+ t = subst (t, i0dest, i0src_copy2 ? i0src_copy2 : i0src, 0, 0, 0);
XVECEXP (newpat, 0, --total_sets) = t;
}
case UNDO_MODE:
adjust_reg_mode (*undo->where.r, undo->old_contents.m);
break;
+ case UNDO_LINKS:
+ *undo->where.l = undo->old_contents.l;
+ break;
default:
gcc_unreachable ();
}
else if (SHIFT_COUNT_TRUNCATED && !REG_P (XEXP (x, 1)))
SUBST (XEXP (x, 1),
force_to_mode (XEXP (x, 1), GET_MODE (XEXP (x, 1)),
- targetm.shift_truncation_mask (GET_MODE (x)),
+ ((unsigned HOST_WIDE_INT) 1
+ << exact_log2 (GET_MODE_BITSIZE (GET_MODE (x))))
+ - 1,
0));
break;
&& exact_log2 (nzb = nonzero_bits (from, GET_MODE (from))) >= 0)
{
false_code = EQ;
- false_val = GEN_INT (trunc_int_for_mode (nzb, GET_MODE (from)));
+ false_val = gen_int_mode (nzb, GET_MODE (from));
}
else if (true_code == EQ && true_val == const0_rtx
&& (num_sign_bit_copies (from, GET_MODE (from))
rtx *cc_use;
/* (set (pc) (return)) gets written as (return). */
- if (GET_CODE (dest) == PC && GET_CODE (src) == RETURN)
+ if (GET_CODE (dest) == PC && ANY_RETURN_P (src))
return src;
/* Now that we know for sure which bits of SRC we are using, see if we can
rtx temp2 = expand_compound_operation (temp);
/* Make sure this is a profitable operation. */
- if (rtx_cost (x, SET, optimize_this_for_speed_p)
- > rtx_cost (temp2, SET, optimize_this_for_speed_p))
+ if (set_src_cost (x, optimize_this_for_speed_p)
+ > set_src_cost (temp2, optimize_this_for_speed_p))
return temp2;
- else if (rtx_cost (x, SET, optimize_this_for_speed_p)
- > rtx_cost (temp, SET, optimize_this_for_speed_p))
+ else if (set_src_cost (x, optimize_this_for_speed_p)
+ > set_src_cost (temp, optimize_this_for_speed_p))
return temp;
else
return x;
/* Prefer ZERO_EXTENSION, since it gives more information to
backends. */
- if (rtx_cost (temp, SET, optimize_this_for_speed_p)
- <= rtx_cost (temp1, SET, optimize_this_for_speed_p))
+ if (set_src_cost (temp, optimize_this_for_speed_p)
+ <= set_src_cost (temp1, optimize_this_for_speed_p))
return temp;
return temp1;
}
/* Prefer ZERO_EXTENSION, since it gives more information to
backends. */
- if (rtx_cost (temp1, SET, optimize_this_for_speed_p)
- < rtx_cost (temp, SET, optimize_this_for_speed_p))
+ if (set_src_cost (temp1, optimize_this_for_speed_p)
+ < set_src_cost (temp, optimize_this_for_speed_p))
temp = temp1;
}
pos_rtx = temp;
&& GET_CODE (lhs) == ASHIFT
&& CONST_INT_P (XEXP (lhs, 1))
&& INTVAL (rhs) >= INTVAL (XEXP (lhs, 1))
+ && INTVAL (XEXP (lhs, 1)) >= 0
&& INTVAL (rhs) < mode_width)
{
new_rtx = make_compound_operation (XEXP (lhs, 0), next_code);
y = simplify_gen_binary (AND, GET_MODE (x),
XEXP (x, 0), GEN_INT (cval));
- if (rtx_cost (y, SET, optimize_this_for_speed_p)
- < rtx_cost (x, SET, optimize_this_for_speed_p))
+ if (set_src_cost (y, optimize_this_for_speed_p)
+ < set_src_cost (x, optimize_this_for_speed_p))
x = y;
}
in OP_MODE. */
if (CONST_INT_P (XEXP (x, 1))
+ && INTVAL (XEXP (x, 1)) >= 0
&& INTVAL (XEXP (x, 1)) < HOST_BITS_PER_WIDE_INT
&& HWI_COMPUTABLE_MODE_P (op_mode))
{
tmp = apply_distributive_law (simplify_gen_binary (inner_code, mode,
new_op0, new_op1));
if (GET_CODE (tmp) != outer_code
- && rtx_cost (tmp, SET, optimize_this_for_speed_p)
- < rtx_cost (x, SET, optimize_this_for_speed_p))
+ && (set_src_cost (tmp, optimize_this_for_speed_p)
+ < set_src_cost (x, optimize_this_for_speed_p)))
return tmp;
return NULL_RTX;
want to do this inside the loop as it makes it more difficult to
combine shifts. */
if (SHIFT_COUNT_TRUNCATED)
- orig_count &= targetm.shift_truncation_mask (mode);
+ orig_count &= GET_MODE_BITSIZE (mode) - 1;
/* If we were given an invalid count, don't do anything except exactly
what was requested. */
break;
/* Make this fit the case below. */
- varop = gen_rtx_XOR (mode, XEXP (varop, 0),
- GEN_INT (GET_MODE_MASK (mode)));
+ varop = gen_rtx_XOR (mode, XEXP (varop, 0), constm1_rtx);
continue;
case IOR:
if (omode == imode)
return x;
- /* Return identity if this is a CONST or symbolic reference. */
- if (omode == Pmode
- && (GET_CODE (x) == CONST
- || GET_CODE (x) == SYMBOL_REF
- || GET_CODE (x) == LABEL_REF))
- return x;
-
/* We can only support MODE being wider than a word if X is a
constant integer or has a mode the same size. */
if (GET_MODE_SIZE (omode) > UNITS_PER_WORD
later on, and then we wouldn't know whether to sign- or
zero-extend. */
mode = GET_MODE (XEXP (op0, 0));
- if (mode != VOIDmode && GET_MODE_CLASS (mode) == MODE_INT
+ if (GET_MODE_CLASS (mode) == MODE_INT
&& ! unsigned_comparison_p
- && val_signbit_known_clear_p (mode, const_op)
+ && HWI_COMPUTABLE_MODE_P (mode)
+ && trunc_int_for_mode (const_op, mode) == const_op
&& have_insn_for (COMPARE, mode))
{
op0 = XEXP (op0, 0);
case ZERO_EXTEND:
mode = GET_MODE (XEXP (op0, 0));
- if (mode != VOIDmode && GET_MODE_CLASS (mode) == MODE_INT
+ if (GET_MODE_CLASS (mode) == MODE_INT
&& (unsigned_comparison_p || equality_comparison_p)
&& HWI_COMPUTABLE_MODE_P (mode)
- && ((unsigned HOST_WIDE_INT) const_op < GET_MODE_MASK (mode))
+ && (unsigned HOST_WIDE_INT) const_op <= GET_MODE_MASK (mode)
+ && const_op >= 0
&& have_insn_for (COMPARE, mode))
{
op0 = XEXP (op0, 0);
}
break;
+ case REG_ARGS_SIZE:
+ /* ??? How to distribute between i3-i1. Assume i3 contains the
+ entire adjustment. Assert i3 contains at least some adjust. */
+ if (!noop_move_p (i3))
+ {
+ int old_size, args_size = INTVAL (XEXP (note, 0));
+ /* fixup_args_size_notes looks at REG_NORETURN note,
+ so ensure the note is placed there first. */
+ if (CALL_P (i3))
+ {
+ rtx *np;
+ for (np = &next_note; *np; np = &XEXP (*np, 1))
+ if (REG_NOTE_KIND (*np) == REG_NORETURN)
+ {
+ rtx n = *np;
+ *np = XEXP (n, 1);
+ XEXP (n, 1) = REG_NOTES (i3);
+ REG_NOTES (i3) = n;
+ break;
+ }
+ }
+ old_size = fixup_args_size_notes (PREV_INSN (i3), i3, args_size);
+ /* emit_call_1 adds for !ACCUMULATE_OUTGOING_ARGS
+ REG_ARGS_SIZE note to all noreturn calls, allow that here. */
+ gcc_assert (old_size != args_size
+ || (CALL_P (i3)
+ && !ACCUMULATE_OUTGOING_ARGS
+ && find_reg_note (i3, REG_NORETURN, NULL_RTX)));
+ }
+ break;
+
case REG_NORETURN:
case REG_SETJMP:
+ case REG_TM:
/* These notes must remain with the call. It should not be
possible for both I2 and I3 to be a call. */
if (CALL_P (i3))