- reg_live_length is not updated
- reg_n_refs is not adjusted in the rare case when a register is
no longer required in a computation
- - there are extremely rare cases (see distribute_regnotes) when a
+ - there are extremely rare cases (see distribute_notes) when a
REG_DEAD note is lost
- a LOG_LINKS entry that refers to an insn with multiple SETs may be
removed because there is no way to know which register it was
static rtx make_field_assignment (rtx);
static rtx apply_distributive_law (rtx);
static rtx distribute_and_simplify_rtx (rtx, int);
+static rtx simplify_and_const_int_1 (enum machine_mode, rtx,
+ unsigned HOST_WIDE_INT);
static rtx simplify_and_const_int (rtx, enum machine_mode, rtx,
unsigned HOST_WIDE_INT);
static int merge_outer_ops (enum rtx_code *, HOST_WIDE_INT *, enum rtx_code,
HOST_WIDE_INT, enum machine_mode, int *);
-static rtx simplify_shift_const (rtx, enum rtx_code, enum machine_mode, rtx,
+static rtx simplify_shift_const_1 (enum rtx_code, enum machine_mode, rtx, int);
+static rtx simplify_shift_const (rtx, enum rtx_code, enum machine_mode, rtx,
int);
static int recog_for_combine (rtx *, rtx, rtx *);
static rtx gen_lowpart_for_combine (enum machine_mode, rtx);
&& !REG_USERVAR_P (x));
}
+
+/* Check whether X, the destination of a set, refers to part of
+ the register specified by REG. */
+
+static bool
+reg_subword_p (rtx x, rtx reg)
+{
+ /* Check that reg is an integer mode register. */
+ if (!REG_P (reg) || GET_MODE_CLASS (GET_MODE (reg)) != MODE_INT)
+ return false;
+
+ if (GET_CODE (x) == STRICT_LOW_PART
+ || GET_CODE (x) == ZERO_EXTRACT)
+ x = XEXP (x, 0);
+
+ return GET_CODE (x) == SUBREG
+ && SUBREG_REG (x) == reg
+ && GET_MODE_CLASS (GET_MODE (x)) == MODE_INT;
+}
+
+
/* Try to combine the insns I1 and I2 into I3.
Here I1 and I2 appear earlier than I3.
I1 can be zero; then we combine just I2 into I3.
}
}
- /* If I2 is setting a double-word pseudo to a constant and I3 is setting
- one of those words to another constant, merge them by making a new
+ /* If I2 is setting a pseudo to a constant and I3 is setting some
+ sub-part of it to another constant, merge them by making a new
constant. */
if (i1 == 0
&& (temp = single_set (i2)) != 0
&& (GET_CODE (SET_SRC (temp)) == CONST_INT
|| GET_CODE (SET_SRC (temp)) == CONST_DOUBLE)
- && REG_P (SET_DEST (temp))
- && GET_MODE_CLASS (GET_MODE (SET_DEST (temp))) == MODE_INT
- && GET_MODE_SIZE (GET_MODE (SET_DEST (temp))) == 2 * UNITS_PER_WORD
&& GET_CODE (PATTERN (i3)) == SET
- && GET_CODE (SET_DEST (PATTERN (i3))) == SUBREG
- && SUBREG_REG (SET_DEST (PATTERN (i3))) == SET_DEST (temp)
- && GET_MODE_CLASS (GET_MODE (SET_DEST (PATTERN (i3)))) == MODE_INT
- && GET_MODE_SIZE (GET_MODE (SET_DEST (PATTERN (i3)))) == UNITS_PER_WORD
- && GET_CODE (SET_SRC (PATTERN (i3))) == CONST_INT)
+ && (GET_CODE (SET_SRC (PATTERN (i3))) == CONST_INT
+ || GET_CODE (SET_SRC (PATTERN (i3))) == CONST_DOUBLE)
+ && reg_subword_p (SET_DEST (PATTERN (i3)), SET_DEST (temp)))
{
- HOST_WIDE_INT lo, hi;
+ rtx dest = SET_DEST (PATTERN (i3));
+ int offset = -1;
+ int width = 0;
- if (GET_CODE (SET_SRC (temp)) == CONST_INT)
- lo = INTVAL (SET_SRC (temp)), hi = lo < 0 ? -1 : 0;
- else
+ if (GET_CODE (dest) == STRICT_LOW_PART)
{
- lo = CONST_DOUBLE_LOW (SET_SRC (temp));
- hi = CONST_DOUBLE_HIGH (SET_SRC (temp));
+ width = GET_MODE_BITSIZE (GET_MODE (XEXP (dest, 0)));
+ offset = 0;
}
-
- if (subreg_lowpart_p (SET_DEST (PATTERN (i3))))
+ else if (GET_CODE (dest) == ZERO_EXTRACT)
{
- /* We don't handle the case of the target word being wider
- than a host wide int. */
- gcc_assert (HOST_BITS_PER_WIDE_INT >= BITS_PER_WORD);
+ if (GET_CODE (XEXP (dest, 1)) == CONST_INT
+ && GET_CODE (XEXP (dest, 2)) == CONST_INT)
+ {
+ width = INTVAL (XEXP (dest, 1));
+ offset = INTVAL (XEXP (dest, 2));
- lo &= ~(UWIDE_SHIFT_LEFT_BY_BITS_PER_WORD (1) - 1);
- lo |= (INTVAL (SET_SRC (PATTERN (i3)))
- & (UWIDE_SHIFT_LEFT_BY_BITS_PER_WORD (1) - 1));
+ if (BITS_BIG_ENDIAN)
+ offset = GET_MODE_BITSIZE (GET_MODE (XEXP (dest, 0)))
+ - width - offset;
+ }
}
- else if (HOST_BITS_PER_WIDE_INT == BITS_PER_WORD)
- hi = INTVAL (SET_SRC (PATTERN (i3)));
- else if (HOST_BITS_PER_WIDE_INT >= 2 * BITS_PER_WORD)
+ else if (subreg_lowpart_p (dest))
{
- int sign = -(int) ((unsigned HOST_WIDE_INT) lo
- >> (HOST_BITS_PER_WIDE_INT - 1));
-
- lo &= ~ (UWIDE_SHIFT_LEFT_BY_BITS_PER_WORD
- (UWIDE_SHIFT_LEFT_BY_BITS_PER_WORD (1) - 1));
- lo |= (UWIDE_SHIFT_LEFT_BY_BITS_PER_WORD
- (INTVAL (SET_SRC (PATTERN (i3)))));
- if (hi == sign)
- hi = lo < 0 ? -1 : 0;
+ width = GET_MODE_BITSIZE (GET_MODE (dest));
+ offset = 0;
+ }
+ /* ??? Preserve the original logic to handle setting the high word
+ of double-word pseudos, where inner is half the size of outer
+ but not the lowpart. This could be generalized by handling
+ SUBREG_BYTE, WORDS_BIG_ENDIAN and BYTES_BIG_ENDIAN ourselves.
+ Unfortunately this logic is tricky to get right and probably
+ not worth the effort. */
+ else if (GET_MODE_BITSIZE (GET_MODE (SET_DEST (temp)))
+ == 2 * GET_MODE_BITSIZE (GET_MODE (dest)))
+ {
+ width = GET_MODE_BITSIZE (GET_MODE (dest));
+ offset = width;
}
- else
- /* We don't handle the case of the higher word not fitting
- entirely in either hi or lo. */
- gcc_unreachable ();
- combine_merges++;
- subst_insn = i3;
- subst_low_cuid = INSN_CUID (i2);
- added_sets_2 = added_sets_1 = 0;
- i2dest = SET_DEST (temp);
- i2dest_killed = dead_or_set_p (i2, i2dest);
+ if (offset >= 0)
+ {
+ HOST_WIDE_INT mhi, ohi, ihi;
+ HOST_WIDE_INT mlo, olo, ilo;
+ rtx inner = SET_SRC (PATTERN (i3));
+ rtx outer = SET_SRC (temp);
- SUBST (SET_SRC (temp),
- immed_double_const (lo, hi, GET_MODE (SET_DEST (temp))));
+ if (GET_CODE (outer) == CONST_INT)
+ {
+ olo = INTVAL (outer);
+ ohi = olo < 0 ? -1 : 0;
+ }
+ else
+ {
+ olo = CONST_DOUBLE_LOW (outer);
+ ohi = CONST_DOUBLE_HIGH (outer);
+ }
+
+ if (GET_CODE (inner) == CONST_INT)
+ {
+ ilo = INTVAL (inner);
+ ihi = ilo < 0 ? -1 : 0;
+ }
+ else
+ {
+ ilo = CONST_DOUBLE_LOW (inner);
+ ihi = CONST_DOUBLE_HIGH (inner);
+ }
- newpat = PATTERN (i2);
- goto validate_replacement;
+ if (width < HOST_BITS_PER_WIDE_INT)
+ {
+ mlo = ((unsigned HOST_WIDE_INT) 1 << width) - 1;
+ mhi = 0;
+ }
+ else if (width < HOST_BITS_PER_WIDE_INT * 2)
+ {
+ mhi = ((unsigned HOST_WIDE_INT) 1
+ << (width - HOST_BITS_PER_WIDE_INT)) - 1;
+ mlo = -1;
+ }
+ else
+ {
+ mlo = -1;
+ mhi = -1;
+ }
+
+ ilo &= mlo;
+ ihi &= mhi;
+
+ if (offset >= HOST_BITS_PER_WIDE_INT)
+ {
+ mhi = mlo << (offset - HOST_BITS_PER_WIDE_INT);
+ mlo = 0;
+ ihi = ilo << (offset - HOST_BITS_PER_WIDE_INT);
+ ilo = 0;
+ }
+ else if (offset > 0)
+ {
+ mhi = (mhi << offset) | ((unsigned HOST_WIDE_INT) mlo
+ >> (HOST_BITS_PER_WIDE_INT - offset));
+ mlo = mlo << offset;
+ ihi = (ihi << offset) | ((unsigned HOST_WIDE_INT) ilo
+ >> (HOST_BITS_PER_WIDE_INT - offset));
+ ilo = ilo << offset;
+ }
+
+ olo = (olo & ~mlo) | ilo;
+ ohi = (ohi & ~mhi) | ihi;
+
+ combine_merges++;
+ subst_insn = i3;
+ subst_low_cuid = INSN_CUID (i2);
+ added_sets_2 = added_sets_1 = 0;
+ i2dest = SET_DEST (temp);
+ i2dest_killed = dead_or_set_p (i2, i2dest);
+
+ SUBST (SET_SRC (temp),
+ immed_double_const (olo, ohi, GET_MODE (SET_DEST (temp))));
+
+ newpat = PATTERN (i2);
+ goto validate_replacement;
+ }
}
#ifndef HAVE_cc0
rtx newdest = i2dest;
enum rtx_code split_code = GET_CODE (*split);
enum machine_mode split_mode = GET_MODE (*split);
+ bool subst_done = false;
+ newi2pat = NULL_RTX;
/* Get NEWDEST as a register in the proper mode. We have already
validated that we can do this. */
}
#endif
- newi2pat = gen_rtx_SET (VOIDmode, newdest, *split);
- SUBST (*split, newdest);
+ /* Attempt to split binary operators using arithmetic identities. */
+ if (BINARY_P (SET_SRC (newpat))
+ && split_mode == GET_MODE (SET_SRC (newpat))
+ && ! side_effects_p (SET_SRC (newpat)))
+ {
+ rtx setsrc = SET_SRC (newpat);
+ enum machine_mode mode = GET_MODE (setsrc);
+ enum rtx_code code = GET_CODE (setsrc);
+ rtx src_op0 = XEXP (setsrc, 0);
+ rtx src_op1 = XEXP (setsrc, 1);
+
+ /* Split "X = Y op Y" as "Z = Y; X = Z op Z". */
+ if (rtx_equal_p (src_op0, src_op1))
+ {
+ newi2pat = gen_rtx_SET (VOIDmode, newdest, src_op0);
+ SUBST (XEXP (setsrc, 0), newdest);
+ SUBST (XEXP (setsrc, 1), newdest);
+ subst_done = true;
+ }
+ /* Split "((P op Q) op R) op S" where op is PLUS or MULT. */
+ else if ((code == PLUS || code == MULT)
+ && GET_CODE (src_op0) == code
+ && GET_CODE (XEXP (src_op0, 0)) == code
+ && (INTEGRAL_MODE_P (mode)
+ || (FLOAT_MODE_P (mode)
+ && flag_unsafe_math_optimizations)))
+ {
+ rtx p = XEXP (XEXP (src_op0, 0), 0);
+ rtx q = XEXP (XEXP (src_op0, 0), 1);
+ rtx r = XEXP (src_op0, 1);
+ rtx s = src_op1;
+
+ /* Split both "((X op Y) op X) op Y" and
+ "((X op Y) op Y) op X" as "T op T" where T is
+ "X op Y". */
+ if ((rtx_equal_p (p,r) && rtx_equal_p (q,s))
+ || (rtx_equal_p (p,s) && rtx_equal_p (q,r)))
+ {
+ newi2pat = gen_rtx_SET (VOIDmode, newdest,
+ XEXP (src_op0, 0));
+ SUBST (XEXP (setsrc, 0), newdest);
+ SUBST (XEXP (setsrc, 1), newdest);
+ subst_done = true;
+ }
+ /* Split "((X op X) op Y) op Y)" as "T op T" where
+ T is "X op Y". */
+ else if (rtx_equal_p (p,q) && rtx_equal_p (r,s))
+ {
+ rtx tmp = simplify_gen_binary (code, mode, p, r);
+ newi2pat = gen_rtx_SET (VOIDmode, newdest, tmp);
+ SUBST (XEXP (setsrc, 0), newdest);
+ SUBST (XEXP (setsrc, 1), newdest);
+ subst_done = true;
+ }
+ }
+ }
+
+ if (!subst_done)
+ {
+ newi2pat = gen_rtx_SET (VOIDmode, newdest, *split);
+ SUBST (*split, newdest);
+ }
+
i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes);
/* recog_for_combine might have added CLOBBERs to newi2pat.
if (GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) >= 0
&& INTVAL (XEXP (x, 1)) < HOST_BITS_PER_WIDE_INT)
{
- int i = -1;
+ int i;
/* If the considered data is wider than HOST_WIDE_INT, we can't
represent a mask for all its bits in a single scalar.
nonzero >>= INTVAL (XEXP (x, 1));
}
- if ((mask & ~nonzero) == 0
- || (i = exact_log2 (mask)) >= 0)
+ if ((mask & ~nonzero) == 0)
+ {
+ x = simplify_shift_const (x, LSHIFTRT, GET_MODE (x),
+ XEXP (x, 0), INTVAL (XEXP (x, 1)));
+ if (GET_CODE (x) != ASHIFTRT)
+ return force_to_mode (x, mode, mask, next_select);
+ }
+
+ else if ((i = exact_log2 (mask)) >= 0)
{
x = simplify_shift_const
- (x, LSHIFTRT, GET_MODE (x), XEXP (x, 0),
- i < 0 ? INTVAL (XEXP (x, 1))
- : GET_MODE_BITSIZE (GET_MODE (x)) - 1 - i);
+ (NULL_RTX, LSHIFTRT, GET_MODE (x), XEXP (x, 0),
+ GET_MODE_BITSIZE (GET_MODE (x)) - 1 - i);
if (GET_CODE (x) != ASHIFTRT)
return force_to_mode (x, mode, mask, next_select);
|| (GET_MODE_SIZE (GET_MODE (lhs))
> GET_MODE_SIZE (GET_MODE (SUBREG_REG (lhs))))
|| VECTOR_MODE_P (GET_MODE (lhs))
- || GET_MODE_SIZE (GET_MODE (SUBREG_REG (lhs))) > UNITS_PER_WORD)
+ || GET_MODE_SIZE (GET_MODE (SUBREG_REG (lhs))) > UNITS_PER_WORD
+ /* Result might need to be truncated. Don't change mode if
+ explicit truncation is needed. */
+ || !TRULY_NOOP_TRUNCATION
+ (GET_MODE_BITSIZE (GET_MODE (x)),
+ GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (lhs)))))
return x;
tem = simplify_gen_binary (code, GET_MODE (SUBREG_REG (lhs)),
return NULL_RTX;
}
\f
-/* We have X, a logical `and' of VAROP with the constant CONSTOP, to be done
- in MODE.
-
- Return an equivalent form, if different from X. Otherwise, return X. If
- X is zero, we are to always construct the equivalent form. */
+/* Simplify a logical `and' of VAROP with the constant CONSTOP, to be done
+ in MODE. Return an equivalent form, if different from (and VAROP
+ (const_int CONSTOP)). Otherwise, return NULL_RTX. */
static rtx
-simplify_and_const_int (rtx x, enum machine_mode mode, rtx varop,
- unsigned HOST_WIDE_INT constop)
+simplify_and_const_int_1 (enum machine_mode mode, rtx varop,
+ unsigned HOST_WIDE_INT constop)
{
unsigned HOST_WIDE_INT nonzero;
+ unsigned HOST_WIDE_INT orig_constop;
+ rtx orig_varop;
int i;
+ orig_varop = varop;
+ orig_constop = constop;
+ if (GET_CODE (varop) == CLOBBER)
+ return NULL_RTX;
+
/* Simplify VAROP knowing that we will be only looking at some of the
bits in it.
return o0;
}
- /* Get VAROP in MODE. Try to get a SUBREG if not. Don't make a new SUBREG
- if we already had one (just check for the simplest cases). */
- if (x && GET_CODE (XEXP (x, 0)) == SUBREG
- && GET_MODE (XEXP (x, 0)) == mode
- && SUBREG_REG (XEXP (x, 0)) == varop)
- varop = XEXP (x, 0);
- else
- varop = gen_lowpart (mode, varop);
-
- /* If we can't make the SUBREG, try to return what we were given. */
- if (GET_CODE (varop) == CLOBBER)
- return x ? x : varop;
+ /* Make a SUBREG if necessary. If we can't make it, fail. */
+ varop = gen_lowpart (mode, varop);
+ if (varop == NULL_RTX || GET_CODE (varop) == CLOBBER)
+ return NULL_RTX;
/* If we are only masking insignificant bits, return VAROP. */
if (constop == nonzero)
- x = varop;
- else
- {
- /* Otherwise, return an AND. */
- constop = trunc_int_for_mode (constop, mode);
- /* See how much, if any, of X we can use. */
- if (x == 0 || GET_CODE (x) != AND || GET_MODE (x) != mode)
- x = simplify_gen_binary (AND, mode, varop, GEN_INT (constop));
+ return varop;
- else
- {
- if (GET_CODE (XEXP (x, 1)) != CONST_INT
- || (unsigned HOST_WIDE_INT) INTVAL (XEXP (x, 1)) != constop)
- SUBST (XEXP (x, 1), GEN_INT (constop));
+ if (varop == orig_varop && constop == orig_constop)
+ return NULL_RTX;
- SUBST (XEXP (x, 0), varop);
- }
- }
+ /* Otherwise, return an AND. */
+ constop = trunc_int_for_mode (constop, mode);
+ return simplify_gen_binary (AND, mode, varop, GEN_INT (constop));
+}
+
+
+/* We have X, a logical `and' of VAROP with the constant CONSTOP, to be done
+ in MODE.
+
+ Return an equivalent form, if different from X. Otherwise, return X. If
+ X is zero, we are to always construct the equivalent form. */
+
+static rtx
+simplify_and_const_int (rtx x, enum machine_mode mode, rtx varop,
+ unsigned HOST_WIDE_INT constop)
+{
+ rtx tem = simplify_and_const_int_1 (mode, varop, constop);
+ if (tem)
+ return tem;
+ if (!x)
+ x = simplify_gen_binary (AND, GET_MODE (varop), varop, GEN_INT (constop));
+ if (GET_MODE (x) != mode)
+ x = gen_lowpart (mode, x);
return x;
}
\f
}
\f
/* Simplify a shift of VAROP by COUNT bits. CODE says what kind of shift.
- The result of the shift is RESULT_MODE. X, if nonzero, is an expression
- that we started with.
+ The result of the shift is RESULT_MODE. Return NULL_RTX if we cannot
+ simplify it. Otherwise, return a simplified value.
The shift is normally computed in the widest mode we find in VAROP, as
long as it isn't a different number of words than RESULT_MODE. Exceptions
- are ASHIFTRT and ROTATE, which are always done in their original mode, */
+ are ASHIFTRT and ROTATE, which are always done in their original mode. */
static rtx
-simplify_shift_const (rtx x, enum rtx_code code,
- enum machine_mode result_mode, rtx varop,
- int orig_count)
+simplify_shift_const_1 (enum rtx_code code, enum machine_mode result_mode,
+ rtx varop, int orig_count)
{
enum rtx_code orig_code = code;
- unsigned int count;
- int signed_count;
+ rtx orig_varop = varop;
+ int count;
enum machine_mode mode = result_mode;
enum machine_mode shift_mode, tmode;
unsigned int mode_words
/* We form (outer_op (code varop count) (outer_const)). */
enum rtx_code outer_op = UNKNOWN;
HOST_WIDE_INT outer_const = 0;
- rtx const_rtx;
int complement_p = 0;
- rtx new;
+ rtx new, x;
/* Make sure and truncate the "natural" shift on the way in. We don't
want to do this inside the loop as it makes it more difficult to
what was requested. */
if (orig_count < 0 || orig_count >= (int) GET_MODE_BITSIZE (mode))
- {
- if (x)
- return x;
-
- return gen_rtx_fmt_ee (code, mode, varop, GEN_INT (orig_count));
- }
+ return NULL_RTX;
count = orig_count;
while (count != 0)
{
- /* If we have an operand of (clobber (const_int 0)), just return that
- value. */
+ /* If we have an operand of (clobber (const_int 0)), fail. */
if (GET_CODE (varop) == CLOBBER)
- return varop;
+ return NULL_RTX;
/* If we discovered we had to complement VAROP, leave. Making a NOT
here would cause an infinite loop. */
multiple operations, each of which are defined, we know what the
result is supposed to be. */
- if (count > (unsigned int) (GET_MODE_BITSIZE (shift_mode) - 1))
+ if (count > (GET_MODE_BITSIZE (shift_mode) - 1))
{
if (code == ASHIFTRT)
count = GET_MODE_BITSIZE (shift_mode) - 1;
interpreted as the sign bit in a narrower mode, so, if
the result is narrower, don't discard the shift. */
if (code == LSHIFTRT
- && count == (unsigned int) (GET_MODE_BITSIZE (result_mode) - 1)
+ && count == (GET_MODE_BITSIZE (result_mode) - 1)
&& (GET_MODE_BITSIZE (result_mode)
>= GET_MODE_BITSIZE (GET_MODE (varop))))
{
(ashiftrt:M1 (ashift:M1 (and:M1 (subreg:M1 FOO 0 C2) C3) C1).
This simplifies certain SIGN_EXTEND operations. */
if (code == ASHIFT && first_code == ASHIFTRT
- && count == (unsigned int)
- (GET_MODE_BITSIZE (result_mode)
+ && count == (GET_MODE_BITSIZE (result_mode)
- GET_MODE_BITSIZE (GET_MODE (varop))))
{
/* C3 has the low-order C1 bits zero. */
> first_count))
{
varop = XEXP (varop, 0);
-
- signed_count = count - first_count;
- if (signed_count < 0)
- count = -signed_count, code = ASHIFT;
- else
- count = signed_count;
+ count -= first_count;
+ if (count < 0)
+ {
+ count = -count;
+ code = ASHIFT;
+ }
continue;
}
mask_rtx = GEN_INT (nonzero_bits (varop, GET_MODE (varop)));
mask_rtx
- = simplify_binary_operation (code, result_mode, mask_rtx,
- GEN_INT (count));
+ = simplify_const_binary_operation (code, result_mode, mask_rtx,
+ GEN_INT (count));
/* Give up if we can't compute an outer operation to use. */
if (mask_rtx == 0
/* If the shifts are in the same direction, we add the
counts. Otherwise, we subtract them. */
- signed_count = count;
if ((code == ASHIFTRT || code == LSHIFTRT)
== (first_code == ASHIFTRT || first_code == LSHIFTRT))
- signed_count += first_count;
+ count += first_count;
else
- signed_count -= first_count;
+ count -= first_count;
/* If COUNT is positive, the new shift is usually CODE,
except for the two exceptions below, in which case it is
FIRST_CODE. If the count is negative, FIRST_CODE should
always be used */
- if (signed_count > 0
+ if (count > 0
&& ((first_code == ROTATE && code == ASHIFT)
|| (first_code == ASHIFTRT && code == LSHIFTRT)))
- code = first_code, count = signed_count;
- else if (signed_count < 0)
- code = first_code, count = -signed_count;
- else
- count = signed_count;
+ code = first_code;
+ else if (count < 0)
+ code = first_code, count = -count;
varop = XEXP (varop, 0);
continue;
B is not a constant. */
else if (GET_CODE (varop) == code
- && GET_CODE (XEXP (varop, 1)) != CONST_INT
- && 0 != (new
- = simplify_binary_operation (code, mode,
- XEXP (varop, 0),
- GEN_INT (count))))
+ && GET_CODE (XEXP (varop, 0)) == CONST_INT
+ && GET_CODE (XEXP (varop, 1)) != CONST_INT)
{
+ rtx new = simplify_const_binary_operation (code, mode,
+ XEXP (varop, 0),
+ GEN_INT (count));
varop = gen_rtx_fmt_ee (code, mode, new, XEXP (varop, 1));
count = 0;
continue;
&& XEXP (XEXP (varop, 0), 1) == constm1_rtx
&& (STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1)
&& (code == LSHIFTRT || code == ASHIFTRT)
- && count == (unsigned int)
- (GET_MODE_BITSIZE (GET_MODE (varop)) - 1)
+ && count == (GET_MODE_BITSIZE (GET_MODE (varop)) - 1)
&& rtx_equal_p (XEXP (XEXP (varop, 0), 0), XEXP (varop, 1)))
{
count = 0;
&& !(code == ASHIFTRT && GET_CODE (varop) == XOR
&& 0 > trunc_int_for_mode (INTVAL (XEXP (varop, 1)),
shift_mode))
- && (new = simplify_binary_operation (code, result_mode,
- XEXP (varop, 1),
- GEN_INT (count))) != 0
+ && (new = simplify_const_binary_operation (code, result_mode,
+ XEXP (varop, 1),
+ GEN_INT (count))) != 0
&& GET_CODE (new) == CONST_INT
&& merge_outer_ops (&outer_op, &outer_const, GET_CODE (varop),
INTVAL (new), result_mode, &complement_p))
if (code == LSHIFTRT
&& XEXP (varop, 1) == const0_rtx
&& GET_MODE (XEXP (varop, 0)) == result_mode
- && count == (unsigned int) (GET_MODE_BITSIZE (result_mode) - 1)
+ && count == (GET_MODE_BITSIZE (result_mode) - 1)
&& GET_MODE_BITSIZE (result_mode) <= HOST_BITS_PER_WIDE_INT
- && ((STORE_FLAG_VALUE
- & ((HOST_WIDE_INT) 1
- < (GET_MODE_BITSIZE (result_mode) - 1))))
+ && STORE_FLAG_VALUE == -1
&& nonzero_bits (XEXP (varop, 0), result_mode) == 1
&& merge_outer_ops (&outer_op, &outer_const, XOR,
(HOST_WIDE_INT) 1, result_mode,
/* (lshiftrt (neg A) C) where A is either 0 or 1 and C is one less
than the number of bits in the mode is equivalent to A. */
if (code == LSHIFTRT
- && count == (unsigned int) (GET_MODE_BITSIZE (result_mode) - 1)
+ && count == (GET_MODE_BITSIZE (result_mode) - 1)
&& nonzero_bits (XEXP (varop, 0), result_mode) == 1)
{
varop = XEXP (varop, 0);
is one less than the number of bits in the mode is
equivalent to (xor A 1). */
if (code == LSHIFTRT
- && count == (unsigned int) (GET_MODE_BITSIZE (result_mode) - 1)
+ && count == (GET_MODE_BITSIZE (result_mode) - 1)
&& XEXP (varop, 1) == constm1_rtx
&& nonzero_bits (XEXP (varop, 0), result_mode) == 1
&& merge_outer_ops (&outer_op, &outer_const, XOR,
/* (ashift (plus foo C) N) is (plus (ashift foo N) C'). */
if (code == ASHIFT
&& GET_CODE (XEXP (varop, 1)) == CONST_INT
- && (new = simplify_binary_operation (ASHIFT, result_mode,
- XEXP (varop, 1),
- GEN_INT (count))) != 0
+ && (new = simplify_const_binary_operation (ASHIFT, result_mode,
+ XEXP (varop, 1),
+ GEN_INT (count))) != 0
&& GET_CODE (new) == CONST_INT
&& merge_outer_ops (&outer_op, &outer_const, PLUS,
INTVAL (new), result_mode, &complement_p))
if (code == LSHIFTRT
&& GET_CODE (XEXP (varop, 1)) == CONST_INT
&& mode_signbit_p (result_mode, XEXP (varop, 1))
- && (new = simplify_binary_operation (code, result_mode,
- XEXP (varop, 1),
- GEN_INT (count))) != 0
+ && (new = simplify_const_binary_operation (code, result_mode,
+ XEXP (varop, 1),
+ GEN_INT (count))) != 0
&& GET_CODE (new) == CONST_INT
&& merge_outer_ops (&outer_op, &outer_const, XOR,
INTVAL (new), result_mode, &complement_p))
if ((STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1)
&& GET_CODE (XEXP (varop, 0)) == ASHIFTRT
- && count == (unsigned int)
- (GET_MODE_BITSIZE (GET_MODE (varop)) - 1)
+ && count == (GET_MODE_BITSIZE (GET_MODE (varop)) - 1)
&& (code == LSHIFTRT || code == ASHIFTRT)
&& GET_CODE (XEXP (XEXP (varop, 0), 1)) == CONST_INT
- && (unsigned HOST_WIDE_INT) INTVAL (XEXP (XEXP (varop, 0), 1))
- == count
+ && INTVAL (XEXP (XEXP (varop, 0), 1)) == count
&& rtx_equal_p (XEXP (XEXP (varop, 0), 0), XEXP (varop, 1)))
{
count = 0;
a shift of type CODE with SHIFT_MODE shifting VAROP COUNT places. If
OUTER_OP is non-UNKNOWN, it is an operation that needs to be applied
to the result of the shift. OUTER_CONST is the relevant constant,
- but we must turn off all bits turned off in the shift.
-
- If we were passed a value for X, see if we can use any pieces of
- it. If not, make new rtx. */
-
- if (x && GET_RTX_CLASS (GET_CODE (x)) == RTX_BIN_ARITH
- && GET_CODE (XEXP (x, 1)) == CONST_INT
- && (unsigned HOST_WIDE_INT) INTVAL (XEXP (x, 1)) == count)
- const_rtx = XEXP (x, 1);
- else
- const_rtx = GEN_INT (count);
+ but we must turn off all bits turned off in the shift. */
- if (x && GET_CODE (XEXP (x, 0)) == SUBREG
- && GET_MODE (XEXP (x, 0)) == shift_mode
- && SUBREG_REG (XEXP (x, 0)) == varop)
- varop = XEXP (x, 0);
- else if (GET_MODE (varop) != shift_mode)
- varop = gen_lowpart (shift_mode, varop);
-
- /* If we can't make the SUBREG, try to return what we were given. */
- if (GET_CODE (varop) == CLOBBER)
- return x ? x : varop;
+ if (outer_op == UNKNOWN
+ && orig_code == code && orig_count == count
+ && varop == orig_varop
+ && shift_mode == GET_MODE (varop))
+ return NULL_RTX;
- new = simplify_binary_operation (code, shift_mode, varop, const_rtx);
- if (new != 0)
- x = new;
- else
- x = gen_rtx_fmt_ee (code, shift_mode, varop, const_rtx);
+ /* Make a SUBREG if necessary. If we can't make it, fail. */
+ varop = gen_lowpart (shift_mode, varop);
+ if (varop == NULL_RTX || GET_CODE (varop) == CLOBBER)
+ return NULL_RTX;
/* If we have an outer operation and we just made a shift, it is
possible that we could have simplified the shift were it not
for the outer operation. So try to do the simplification
recursively. */
- if (outer_op != UNKNOWN && GET_CODE (x) == code
- && GET_CODE (XEXP (x, 1)) == CONST_INT)
- x = simplify_shift_const (x, code, shift_mode, XEXP (x, 0),
- INTVAL (XEXP (x, 1)));
+ if (outer_op != UNKNOWN)
+ x = simplify_shift_const_1 (code, shift_mode, varop, count);
+ else
+ x = NULL_RTX;
+
+ if (x == NULL_RTX)
+ x = simplify_gen_binary (code, shift_mode, varop, GEN_INT (count));
/* If we were doing an LSHIFTRT in a wider mode than it was originally,
turn off all the bits that the shift would have turned off. */
return x;
}
+
+/* Simplify a shift of VAROP by COUNT bits. CODE says what kind of shift.
+ The result of the shift is RESULT_MODE. If we cannot simplify it,
+ return X or, if it is NULL, synthesize the expression with
+ simplify_gen_binary. Otherwise, return a simplified value.
+
+ The shift is normally computed in the widest mode we find in VAROP, as
+ long as it isn't a different number of words than RESULT_MODE. Exceptions
+ are ASHIFTRT and ROTATE, which are always done in their original mode. */
+
+static rtx
+simplify_shift_const (rtx x, enum rtx_code code, enum machine_mode result_mode,
+ rtx varop, int count)
+{
+ rtx tem = simplify_shift_const_1 (code, result_mode, varop, count);
+ if (tem)
+ return tem;
+
+ if (!x)
+ x = simplify_gen_binary (code, GET_MODE (varop), varop, GEN_INT (count));
+ if (GET_MODE (x) != result_mode)
+ x = gen_lowpart (result_mode, x);
+ return x;
+}
+
\f
/* Like recog, but we receive the address of a pointer to a new pattern.
We try to match the rtx that the pointer points to.
&& XEXP (XEXP (op0, 0), 0) == const1_rtx)
{
op0 = simplify_and_const_int
- (op0, mode, gen_rtx_LSHIFTRT (mode,
- XEXP (op0, 1),
- XEXP (XEXP (op0, 0), 1)),
+ (NULL_RTX, mode, gen_rtx_LSHIFTRT (mode,
+ XEXP (op0, 1),
+ XEXP (XEXP (op0, 0), 1)),
(HOST_WIDE_INT) 1);
continue;
}