combine anyway. */
#include "config.h"
-#ifdef __STDC__
-#include <stdarg.h>
-#else
-#include <varargs.h>
-#endif
-
-/* Must precede rtl.h for FFS. */
-#include <stdio.h>
-
-#include "rtl.h"
+#include "system.h"
+#include "rtl.h" /* stdio.h must precede rtl.h for FFS. */
#include "flags.h"
#include "regs.h"
#include "hard-reg-set.h"
-#include "expr.h"
#include "basic-block.h"
#include "insn-config.h"
+/* Include expr.h after insn-config.h so we get HAVE_conditional_move. */
+#include "expr.h"
#include "insn-flags.h"
#include "insn-codes.h"
#include "insn-attr.h"
#include "recog.h"
#include "real.h"
+#include "toplev.h"
/* It is not safe to use ordinary gen_lowpart in combine.
Use gen_lowpart_for_combine instead. See comments there. */
static void setup_incoming_promotions PROTO((void));
static void set_nonzero_bits_and_sign_copies PROTO((rtx, rtx));
static int can_combine_p PROTO((rtx, rtx, rtx, rtx, rtx *, rtx *));
+static int sets_function_arg_p PROTO((rtx));
static int combinable_i3pat PROTO((rtx, rtx *, rtx, rtx, int, rtx *));
static rtx try_combine PROTO((rtx, rtx, rtx));
static void undo_all PROTO((void));
enum machine_mode, int *));
static rtx simplify_shift_const PROTO((rtx, enum rtx_code, enum machine_mode,
rtx, int));
-static int recog_for_combine PROTO((rtx *, rtx, rtx *, int *));
+static int recog_for_combine PROTO((rtx *, rtx, rtx *));
static rtx gen_lowpart_for_combine PROTO((enum machine_mode, rtx));
static rtx gen_rtx_combine PVPROTO((enum rtx_code code, enum machine_mode mode,
...));
total_successes += combine_successes;
nonzero_sign_valid = 0;
+
+ /* Make recognizer allow volatile MEMs again. */
+ init_recog ();
}
/* Wipe the reg_last_xxx arrays in preparation for another pass. */
can_combine_p (insn, i3, pred, succ, pdest, psrc)
rtx insn;
rtx i3;
- rtx pred, succ;
+ rtx pred ATTRIBUTE_UNUSED;
+ rtx succ;
rtx *pdest, *psrc;
{
int i;
switch (GET_CODE (elt))
{
+ /* This is important to combine floating point insns
+ for the SH4 port. */
+ case USE:
+ /* Combining an isolated USE doesn't make sense.
+ We depend here on combinable_i3_pat to reject them. */
+ /* The code below this loop only verifies that the inputs of
+ the SET in INSN do not change. We call reg_set_between_p
+ to verify that the REG in the USE does not change betweeen
+ I3 and INSN.
+ If the USE in INSN was for a pseudo register, the matching
+ insn pattern will likely match any register; combining this
+ with any other USE would only be safe if we knew that the
+ used registers have identical values, or if there was
+ something to tell them apart, e.g. different modes. For
+ now, we forgo such compilcated tests and simply disallow
+ combining of USES of pseudo registers with any other USE. */
+ if (GET_CODE (XEXP (elt, 0)) == REG
+ && GET_CODE (PATTERN (i3)) == PARALLEL)
+ {
+ rtx i3pat = PATTERN (i3);
+ int i = XVECLEN (i3pat, 0) - 1;
+ int regno = REGNO (XEXP (elt, 0));
+ do
+ {
+ rtx i3elt = XVECEXP (i3pat, 0, i);
+ if (GET_CODE (i3elt) == USE
+ && GET_CODE (XEXP (i3elt, 0)) == REG
+ && (REGNO (XEXP (i3elt, 0)) == regno
+ ? reg_set_between_p (XEXP (elt, 0),
+ PREV_INSN (insn), i3)
+ : regno >= FIRST_PSEUDO_REGISTER))
+ return 0;
+ }
+ while (--i >= 0);
+ }
+ break;
+
/* We can ignore CLOBBERs. */
case CLOBBER:
break;
/* Don't substitute into an incremented register. */
|| FIND_REG_INC_NOTE (i3, dest)
|| (succ && FIND_REG_INC_NOTE (succ, dest))
+#if 0
/* Don't combine the end of a libcall into anything. */
+ /* ??? This gives worse code, and appears to be unnecessary, since no
+ pass after flow uses REG_LIBCALL/REG_RETVAL notes. Local-alloc does
+ use REG_RETVAL notes for noconflict blocks, but other code here
+ makes sure that those insns don't disappear. */
|| find_reg_note (insn, REG_RETVAL, NULL_RTX)
+#endif
/* Make sure that DEST is not used after SUCC but before I3. */
|| (succ && ! all_adjacent
&& reg_used_between_p (dest, succ, i3))
return 0;
/* If INSN contains anything volatile, or is an `asm' (whether volatile
- or not), reject, unless nothing volatile comes between it and I3,
- with the exception of SUCC. */
+ or not), reject, unless nothing volatile comes between it and I3 */
if (GET_CODE (src) == ASM_OPERANDS || volatile_refs_p (src))
- for (p = NEXT_INSN (insn); p != i3; p = NEXT_INSN (p))
- if (GET_RTX_CLASS (GET_CODE (p)) == 'i'
- && p != succ && volatile_refs_p (PATTERN (p)))
- return 0;
+ {
+ /* Make sure succ doesn't contain a volatile reference. */
+ if (succ != 0 && volatile_refs_p (PATTERN (succ)))
+ return 0;
+
+ for (p = NEXT_INSN (insn); p != i3; p = NEXT_INSN (p))
+ if (GET_RTX_CLASS (GET_CODE (p)) == 'i'
+ && p != succ && volatile_refs_p (PATTERN (p)))
+ return 0;
+ }
/* If INSN is an asm, and DEST is a hard register, reject, since it has
to be an explicit register variable, and was chosen for a reason. */
rtx set = expand_field_assignment (x);
rtx dest = SET_DEST (set);
rtx src = SET_SRC (set);
- rtx inner_dest = dest, inner_src = src;
+ rtx inner_dest = dest;
+
+#if 0
+ rtx inner_src = src;
+#endif
SUBST (*loc, set);
int i3_subst_into_i2 = 0;
/* Notes that I1, I2 or I3 is a MULT operation. */
int have_mult = 0;
- /* Number of clobbers of SCRATCH we had to add. */
- int i3_scratches = 0, i2_scratches = 0, other_scratches = 0;
int maxreg;
rtx temp;
if (GET_RTX_CLASS (GET_CODE (i3)) != 'i'
|| GET_RTX_CLASS (GET_CODE (i2)) != 'i'
|| (i1 && GET_RTX_CLASS (GET_CODE (i1)) != 'i')
- || find_reg_note (i3, REG_LIBCALL, NULL_RTX))
+#if 0
+ /* ??? This gives worse code, and appears to be unnecessary, since no
+ pass after flow uses REG_LIBCALL/REG_RETVAL notes. */
+ || find_reg_note (i3, REG_LIBCALL, NULL_RTX)
+#endif
+)
return 0;
combine_attempts++;
&& XEXP (SET_SRC (PATTERN (i3)), 1) == const0_rtx
&& rtx_equal_p (XEXP (SET_SRC (PATTERN (i3)), 0), i2dest))
{
+#ifdef EXTRA_CC_MODES
rtx *cc_use;
enum machine_mode compare_mode;
+#endif
newpat = PATTERN (i3);
SUBST (XEXP (SET_SRC (newpat), 0), i2src);
mark_used_regs_combine (newpat);
/* Is the result of combination a valid instruction? */
- insn_code_number
- = recog_for_combine (&newpat, i3, &new_i3_notes, &i3_scratches);
+ insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
/* If the result isn't valid, see if it is a PARALLEL of two SETs where
the second SET's destination is a register that is unused. In that case,
&& asm_noperands (newpat) < 0)
{
newpat = XVECEXP (newpat, 0, 0);
- insn_code_number
- = recog_for_combine (&newpat, i3, &new_i3_notes, &i3_scratches);
+ insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
}
else if (insn_code_number < 0 && GET_CODE (newpat) == PARALLEL
&& asm_noperands (newpat) < 0)
{
newpat = XVECEXP (newpat, 0, 1);
- insn_code_number
- = recog_for_combine (&newpat, i3, &new_i3_notes, &i3_scratches);
+ insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
}
/* If we were combining three insns and the result is a simple SET
if (REGNO (i2dest) >= FIRST_PSEUDO_REGISTER)
SUBST (regno_reg_rtx[REGNO (i2dest)], ni2dest);
- i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes,
- &i2_scratches);
+ i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes);
/* If I2 or I3 has multiple SETs, we won't know how to track
register status, so don't use these insns. If I2's destination
if (i2_code_number >= 0 && i2set && i3set
&& (next_real_insn (i2) == i3
|| ! reg_used_between_p (SET_DEST (i2set), i2, i3)))
- insn_code_number = recog_for_combine (&newi3pat, i3, &new_i3_notes,
- &i3_scratches);
+ insn_code_number = recog_for_combine (&newi3pat, i3,
+ &new_i3_notes);
if (insn_code_number >= 0)
newpat = newi3pat;
newi2pat = gen_rtx_combine (SET, VOIDmode, newdest, *split);
SUBST (*split, newdest);
- i2_code_number
- = recog_for_combine (&newi2pat, i2, &new_i2_notes, &i2_scratches);
+ i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes);
/* If the split point was a MULT and we didn't have one before,
don't use one now. */
if (i2_code_number >= 0 && ! (split_code == MULT && ! have_mult))
- insn_code_number
- = recog_for_combine (&newpat, i3, &new_i3_notes, &i3_scratches);
+ insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
}
}
newpat = XVECEXP (newpat, 0, 1);
SUBST (SET_SRC (newpat),
gen_lowpart_for_combine (GET_MODE (SET_SRC (newpat)), ni2dest));
- i2_code_number
- = recog_for_combine (&newi2pat, i2, &new_i2_notes, &i2_scratches);
+ i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes);
if (i2_code_number >= 0)
- insn_code_number
- = recog_for_combine (&newpat, i3, &new_i3_notes, &i3_scratches);
+ insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
if (insn_code_number >= 0)
{
newpat = XVECEXP (newpat, 0, 0);
}
- i2_code_number
- = recog_for_combine (&newi2pat, i2, &new_i2_notes, &i2_scratches);
+ i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes);
if (i2_code_number >= 0)
- insn_code_number
- = recog_for_combine (&newpat, i3, &new_i3_notes, &i3_scratches);
+ insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
}
/* If it still isn't recognized, fail and change things back the way they
CLEAR_HARD_REG_SET (newpat_used_regs);
- other_code_number
- = recog_for_combine (&other_pat, undobuf.other_insn,
- &new_other_notes, &other_scratches);
+ other_code_number = recog_for_combine (&other_pat, undobuf.other_insn,
+ &new_other_notes);
if (other_code_number < 0 && ! check_asm_operands (other_pat))
{
if (newi2pat)
note_stores (newi2pat, set_nonzero_bits_and_sign_copies);
- /* If we added any (clobber (scratch)), add them to the max for a
- block. This is a very pessimistic calculation, since we might
- have had them already and this might not be the worst block, but
- it's not worth doing any better. */
- max_scratch += i3_scratches + i2_scratches + other_scratches;
-
/* If I3 is now an unconditional jump, ensure that it has a
BARRIER following it since it may have initially been a
conditional jump. It may also be the last nonnote insn. */
if (BITS_BIG_ENDIAN)
pos = GET_MODE_BITSIZE (mode) - len - pos;
- if (src == mask)
+ if ((unsigned HOST_WIDE_INT) src == mask)
SUBST (SET_SRC (x),
gen_binary (IOR, mode, dest, GEN_INT (src << pos)));
else
if (COMBINE_RTX_EQUAL_P (x, to))
return to;
- len = GET_RTX_LENGTH (code);
- fmt = GET_RTX_FORMAT (code);
+ /* Parallel asm_operands need special attention because all of the
+ inputs are shared across the arms. Furthermore, unsharing the
+ rtl results in recognition failures. Failure to handle this case
+ specially can result in circular rtl.
- /* We don't need to process a SET_DEST that is a register, CC0, or PC, so
- set up to skip this common case. All other cases where we want to
- suppress replacing something inside a SET_SRC are handled via the
- IN_DEST operand. */
- if (code == SET
- && (GET_CODE (SET_DEST (x)) == REG
- || GET_CODE (SET_DEST (x)) == CC0
- || GET_CODE (SET_DEST (x)) == PC))
- fmt = "ie";
-
- /* Get the mode of operand 0 in case X is now a SIGN_EXTEND of a
- constant. */
- if (fmt[0] == 'e')
- op0_mode = GET_MODE (XEXP (x, 0));
+ Solve this by doing a normal pass across the first entry of the
+ parallel, and only processing the SET_DESTs of the subsequent
+ entries. Ug. */
- for (i = 0; i < len; i++)
+ if (code == PARALLEL
+ && GET_CODE (XVECEXP (x, 0, 0)) == SET
+ && GET_CODE (SET_SRC (XVECEXP (x, 0, 0))) == ASM_OPERANDS)
{
- if (fmt[i] == 'E')
+ new = subst (XVECEXP (x, 0, 0), from, to, 0, unique_copy);
+
+ /* If this substitution failed, this whole thing fails. */
+ if (GET_CODE (new) == CLOBBER
+ && XEXP (new, 0) == const0_rtx)
+ return new;
+
+ SUBST (XVECEXP (x, 0, 0), new);
+
+ for (i = XVECLEN (x, 0) - 1; i >= 1; i--)
{
- register int j;
- for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+ rtx dest = SET_DEST (XVECEXP (x, 0, i));
+
+ if (GET_CODE (dest) != REG
+ && GET_CODE (dest) != CC0
+ && GET_CODE (dest) != PC)
{
- if (COMBINE_RTX_EQUAL_P (XVECEXP (x, i, j), from))
- {
- new = (unique_copy && n_occurrences ? copy_rtx (to) : to);
- n_occurrences++;
- }
- else
- {
- new = subst (XVECEXP (x, i, j), from, to, 0, unique_copy);
+ new = subst (dest, from, to, 0, unique_copy);
- /* If this substitution failed, this whole thing fails. */
- if (GET_CODE (new) == CLOBBER && XEXP (new, 0) == const0_rtx)
- return new;
- }
+ /* If this substitution failed, this whole thing fails. */
+ if (GET_CODE (new) == CLOBBER
+ && XEXP (new, 0) == const0_rtx)
+ return new;
- SUBST (XVECEXP (x, i, j), new);
+ SUBST (SET_DEST (XVECEXP (x, 0, i)), new);
}
}
- else if (fmt[i] == 'e')
+ }
+ else
+ {
+ len = GET_RTX_LENGTH (code);
+ fmt = GET_RTX_FORMAT (code);
+
+ /* We don't need to process a SET_DEST that is a register, CC0,
+ or PC, so set up to skip this common case. All other cases
+ where we want to suppress replacing something inside a
+ SET_SRC are handled via the IN_DEST operand. */
+ if (code == SET
+ && (GET_CODE (SET_DEST (x)) == REG
+ || GET_CODE (SET_DEST (x)) == CC0
+ || GET_CODE (SET_DEST (x)) == PC))
+ fmt = "ie";
+
+ /* Get the mode of operand 0 in case X is now a SIGN_EXTEND of a
+ constant. */
+ if (fmt[0] == 'e')
+ op0_mode = GET_MODE (XEXP (x, 0));
+
+ for (i = 0; i < len; i++)
{
- if (COMBINE_RTX_EQUAL_P (XEXP (x, i), from))
+ if (fmt[i] == 'E')
{
- /* In general, don't install a subreg involving two modes not
- tieable. It can worsen register allocation, and can even
- make invalid reload insns, since the reg inside may need to
- be copied from in the outside mode, and that may be invalid
- if it is an fp reg copied in integer mode.
-
- We allow two exceptions to this: It is valid if it is inside
- another SUBREG and the mode of that SUBREG and the mode of
- the inside of TO is tieable and it is valid if X is a SET
- that copies FROM to CC0. */
- if (GET_CODE (to) == SUBREG
- && ! MODES_TIEABLE_P (GET_MODE (to),
- GET_MODE (SUBREG_REG (to)))
- && ! (code == SUBREG
- && MODES_TIEABLE_P (GET_MODE (x),
- GET_MODE (SUBREG_REG (to))))
+ register int j;
+ for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+ {
+ if (COMBINE_RTX_EQUAL_P (XVECEXP (x, i, j), from))
+ {
+ new = (unique_copy && n_occurrences
+ ? copy_rtx (to) : to);
+ n_occurrences++;
+ }
+ else
+ {
+ new = subst (XVECEXP (x, i, j), from, to, 0,
+ unique_copy);
+
+ /* If this substitution failed, this whole thing
+ fails. */
+ if (GET_CODE (new) == CLOBBER
+ && XEXP (new, 0) == const0_rtx)
+ return new;
+ }
+
+ SUBST (XVECEXP (x, i, j), new);
+ }
+ }
+ else if (fmt[i] == 'e')
+ {
+ if (COMBINE_RTX_EQUAL_P (XEXP (x, i), from))
+ {
+ /* In general, don't install a subreg involving two
+ modes not tieable. It can worsen register
+ allocation, and can even make invalid reload
+ insns, since the reg inside may need to be copied
+ from in the outside mode, and that may be invalid
+ if it is an fp reg copied in integer mode.
+
+ We allow two exceptions to this: It is valid if
+ it is inside another SUBREG and the mode of that
+ SUBREG and the mode of the inside of TO is
+ tieable and it is valid if X is a SET that copies
+ FROM to CC0. */
+
+ if (GET_CODE (to) == SUBREG
+ && ! MODES_TIEABLE_P (GET_MODE (to),
+ GET_MODE (SUBREG_REG (to)))
+ && ! (code == SUBREG
+ && MODES_TIEABLE_P (GET_MODE (x),
+ GET_MODE (SUBREG_REG (to))))
#ifdef HAVE_cc0
- && ! (code == SET && i == 1 && XEXP (x, 0) == cc0_rtx)
+ && ! (code == SET && i == 1 && XEXP (x, 0) == cc0_rtx)
#endif
- )
- return gen_rtx_CLOBBER (VOIDmode, const0_rtx);
+ )
+ return gen_rtx_CLOBBER (VOIDmode, const0_rtx);
- new = (unique_copy && n_occurrences ? copy_rtx (to) : to);
- n_occurrences++;
+ new = (unique_copy && n_occurrences ? copy_rtx (to) : to);
+ n_occurrences++;
+ }
+ else
+ /* If we are in a SET_DEST, suppress most cases unless we
+ have gone inside a MEM, in which case we want to
+ simplify the address. We assume here that things that
+ are actually part of the destination have their inner
+ parts in the first expression. This is true for SUBREG,
+ STRICT_LOW_PART, and ZERO_EXTRACT, which are the only
+ things aside from REG and MEM that should appear in a
+ SET_DEST. */
+ new = subst (XEXP (x, i), from, to,
+ (((in_dest
+ && (code == SUBREG || code == STRICT_LOW_PART
+ || code == ZERO_EXTRACT))
+ || code == SET)
+ && i == 0), unique_copy);
+
+ /* If we found that we will have to reject this combination,
+ indicate that by returning the CLOBBER ourselves, rather than
+ an expression containing it. This will speed things up as
+ well as prevent accidents where two CLOBBERs are considered
+ to be equal, thus producing an incorrect simplification. */
+
+ if (GET_CODE (new) == CLOBBER && XEXP (new, 0) == const0_rtx)
+ return new;
+
+ SUBST (XEXP (x, i), new);
}
- else
- /* If we are in a SET_DEST, suppress most cases unless we
- have gone inside a MEM, in which case we want to
- simplify the address. We assume here that things that
- are actually part of the destination have their inner
- parts in the first expression. This is true for SUBREG,
- STRICT_LOW_PART, and ZERO_EXTRACT, which are the only
- things aside from REG and MEM that should appear in a
- SET_DEST. */
- new = subst (XEXP (x, i), from, to,
- (((in_dest
- && (code == SUBREG || code == STRICT_LOW_PART
- || code == ZERO_EXTRACT))
- || code == SET)
- && i == 0), unique_copy);
-
- /* If we found that we will have to reject this combination,
- indicate that by returning the CLOBBER ourselves, rather than
- an expression containing it. This will speed things up as
- well as prevent accidents where two CLOBBERs are considered
- to be equal, thus producing an incorrect simplification. */
-
- if (GET_CODE (new) == CLOBBER && XEXP (new, 0) == const0_rtx)
- return new;
-
- SUBST (XEXP (x, i), new);
}
}
if (GET_MODE_CLASS (mode) == MODE_PARTIAL_INT)
break;
- if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
+ if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
+ && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
+ GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))))
SUBST (XEXP (x, 0),
force_to_mode (XEXP (x, 0), GET_MODE (XEXP (x, 0)),
GET_MODE_MASK (mode), NULL_RTX, 0));
return SUBREG_REG (XEXP (x, 0));
/* If we know that the value is already truncated, we can
- replace the TRUNCATE with a SUBREG. */
- if (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))) <= HOST_BITS_PER_WIDE_INT
- && (nonzero_bits (XEXP (x, 0), GET_MODE (XEXP (x, 0)))
- &~ GET_MODE_MASK (mode)) == 0)
+ replace the TRUNCATE with a SUBREG if TRULY_NOOP_TRUNCATION is
+ nonzero for the corresponding modes. */
+ if (TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
+ GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))))
+ && num_sign_bit_copies (XEXP (x, 0), GET_MODE (XEXP (x, 0)))
+ >= GET_MODE_BITSIZE (mode) + 1)
return gen_lowpart_for_combine (mode, XEXP (x, 0));
/* A truncate of a comparison can be replaced with a subreg if
if (new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
&& GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
&& ((STORE_FLAG_VALUE & GET_MODE_MASK (mode))
- == (HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1))
+ == (unsigned HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE(mode)-1))
&& op1 == const0_rtx
&& mode == GET_MODE (op0)
&& (i = exact_log2 (nonzero_bits (op0, mode))) >= 0)
&& exact_log2 (mask = nonzero_bits (op0, GET_MODE (op0))) >= 0)
{
rtx pat = PATTERN (other_insn), note = 0;
- int scratches;
- if ((recog_for_combine (&pat, other_insn, ¬e, &scratches) < 0
+ if ((recog_for_combine (&pat, other_insn, ¬e) < 0
&& ! check_asm_operands (pat)))
{
PUT_CODE (*cc_use, old_code);
we only care about the low bits of the result.
However, on machines without WORD_REGISTER_OPERATIONS defined, we cannot
- perform a narrower operation that requested since the high-order bits will
+ perform a narrower operation than requested since the high-order bits will
be undefined. On machine where it is defined, this transformation is safe
as long as M1 and M2 have the same number of words. */
when STORE_FLAG_VALUE is the sign bit. */
if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
&& ((STORE_FLAG_VALUE & GET_MODE_MASK (mode))
- == (HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1))
+ == (unsigned HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1))
&& op1 == const_true_rtx
&& GET_RTX_CLASS (GET_CODE (op0)) == '<'
&& reversible_comparison_p (op0))
&& subreg_lowpart_p (XEXP (x, 0))
&& GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT
&& (nonzero_bits (SUBREG_REG (XEXP (x, 0)), GET_MODE (x))
- & ~ GET_MODE_MASK (GET_MODE (SUBREG_REG (x)))) == 0)
+ & ~ GET_MODE_MASK (GET_MODE (XEXP (x, 0)))) == 0)
return SUBREG_REG (XEXP (x, 0));
/* (zero_extend:DI (truncate:SI foo:DI)) is just foo:DI when foo
compute_mode = GET_MODE (inner);
+ /* Don't attempt bitwise arithmetic on non-integral modes. */
+ if (! INTEGRAL_MODE_P (compute_mode))
+ {
+ enum machine_mode imode;
+
+ /* Something is probably seriously wrong if this matches. */
+ if (! FLOAT_MODE_P (compute_mode))
+ break;
+
+ /* Try to find an integral mode to pun with. */
+ imode = mode_for_size (GET_MODE_BITSIZE (compute_mode), MODE_INT, 0);
+ if (imode == BLKmode)
+ break;
+
+ compute_mode = imode;
+ inner = gen_lowpart_for_combine (imode, inner);
+ }
+
/* Compute a mask of LEN bits, if we can do this on the host machine. */
if (len < HOST_BITS_PER_WIDE_INT)
mask = GEN_INT (((HOST_WIDE_INT) 1 << len) - 1);
#ifdef HAVE_insv
if (in_dest)
{
- wanted_inner_reg_mode = insn_operand_mode[(int) CODE_FOR_insv][0];
- pos_mode = insn_operand_mode[(int) CODE_FOR_insv][2];
- extraction_mode = insn_operand_mode[(int) CODE_FOR_insv][3];
+ wanted_inner_reg_mode
+ = (insn_operand_mode[(int) CODE_FOR_insv][0] == VOIDmode
+ ? word_mode
+ : insn_operand_mode[(int) CODE_FOR_insv][0]);
+ pos_mode = (insn_operand_mode[(int) CODE_FOR_insv][2] == VOIDmode
+ ? word_mode : insn_operand_mode[(int) CODE_FOR_insv][2]);
+ extraction_mode = (insn_operand_mode[(int) CODE_FOR_insv][3] == VOIDmode
+ ? word_mode
+ : insn_operand_mode[(int) CODE_FOR_insv][3]);
}
#endif
#ifdef HAVE_extzv
if (! in_dest && unsignedp)
{
- wanted_inner_reg_mode = insn_operand_mode[(int) CODE_FOR_extzv][1];
- pos_mode = insn_operand_mode[(int) CODE_FOR_extzv][3];
- extraction_mode = insn_operand_mode[(int) CODE_FOR_extzv][0];
+ wanted_inner_reg_mode
+ = (insn_operand_mode[(int) CODE_FOR_extzv][1] == VOIDmode
+ ? word_mode
+ : insn_operand_mode[(int) CODE_FOR_extzv][1]);
+ pos_mode = (insn_operand_mode[(int) CODE_FOR_extzv][3] == VOIDmode
+ ? word_mode : insn_operand_mode[(int) CODE_FOR_extzv][3]);
+ extraction_mode = (insn_operand_mode[(int) CODE_FOR_extzv][0] == VOIDmode
+ ? word_mode
+ : insn_operand_mode[(int) CODE_FOR_extzv][0]);
}
#endif
#ifdef HAVE_extv
if (! in_dest && ! unsignedp)
{
- wanted_inner_reg_mode = insn_operand_mode[(int) CODE_FOR_extv][1];
- pos_mode = insn_operand_mode[(int) CODE_FOR_extv][3];
- extraction_mode = insn_operand_mode[(int) CODE_FOR_extv][0];
+ wanted_inner_reg_mode
+ = (insn_operand_mode[(int) CODE_FOR_extv][1] == VOIDmode
+ ? word_mode
+ : insn_operand_mode[(int) CODE_FOR_extv][1]);
+ pos_mode = (insn_operand_mode[(int) CODE_FOR_extv][3] == VOIDmode
+ ? word_mode : insn_operand_mode[(int) CODE_FOR_extv][3]);
+ extraction_mode = (insn_operand_mode[(int) CODE_FOR_extv][0] == VOIDmode
+ ? word_mode
+ : insn_operand_mode[(int) CODE_FOR_extv][0]);
}
#endif
return newer;
}
+
+ /* If this is a paradoxical subreg, and the new code is a sign or
+ zero extension, omit the subreg and widen the extension. If it
+ is a regular subreg, we can still get rid of the subreg by not
+ widening so much, or in fact removing the extension entirely. */
+ if ((GET_CODE (tem) == SIGN_EXTEND
+ || GET_CODE (tem) == ZERO_EXTEND)
+ && subreg_lowpart_p (x))
+ {
+ if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (GET_MODE (tem))
+ || (GET_MODE_SIZE (mode) >
+ GET_MODE_SIZE (GET_MODE (XEXP (tem, 0)))))
+ tem = gen_rtx_combine (GET_CODE (tem), mode, XEXP (tem, 0));
+ else
+ tem = gen_lowpart_for_combine (mode, XEXP (tem, 0));
+ return tem;
+ }
break;
default:
need it. */
if (GET_CODE (x) == AND && GET_CODE (XEXP (x, 1)) == CONST_INT
- && INTVAL (XEXP (x, 1)) == mask)
+ && (unsigned HOST_WIDE_INT) INTVAL (XEXP (x, 1)) == mask)
x = XEXP (x, 0);
/* If it remains an AND, try making another AND with the bits
/* If we are just looking for the sign bit, we don't need this shift at
all, even if it has a variable count. */
if (GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT
- && (mask == ((HOST_WIDE_INT) 1
+ && (mask == ((unsigned HOST_WIDE_INT) 1
<< (GET_MODE_BITSIZE (GET_MODE (x)) - 1))))
return force_to_mode (XEXP (x, 0), mode, mask, reg, next_select);
rtx x;
rtx y;
{
- rtx last_x, last_y;
-
if (x == y || rtx_equal_p (x, y))
return 1;
gen_lowpart_for_combine (GET_MODE (SUBREG_REG (x)), y)))
return 1;
- last_x = get_last_value (x);
- last_y = get_last_value (y);
-
- return ((last_x != 0
- && GET_CODE (last_x) != CLOBBER
- && rtx_equal_for_field_assignment_p (last_x, y))
- || (last_y != 0
- && GET_CODE (last_y) != CLOBBER
- && rtx_equal_for_field_assignment_p (x, last_y))
- || (last_x != 0 && last_y != 0
- && GET_CODE (last_x) != CLOBBER
- && GET_CODE (last_y) != CLOBBER
- && rtx_equal_for_field_assignment_p (last_x, last_y)));
+ /* We used to see if get_last_value of X and Y were the same but that's
+ not correct. In one direction, we'll cause the assignment to have
+ the wrong destination and in the case, we'll import a register into this
+ insn that might have already have been dead. So fail if none of the
+ above cases are true. */
+ return 0;
}
\f
/* See if X, a SET operation, can be rewritten as a bit-field assignment.
pos = get_pos_from_mask ((~ c1) & GET_MODE_MASK (GET_MODE (dest)), &len);
if (pos < 0 || pos + len > GET_MODE_BITSIZE (GET_MODE (dest))
- || (GET_MODE_BITSIZE (GET_MODE (other)) <= HOST_BITS_PER_WIDE_INT
- && (c1 & nonzero_bits (other, GET_MODE (other))) != 0))
+ || GET_MODE_BITSIZE (GET_MODE (dest)) > HOST_BITS_PER_WIDE_INT
+ || (c1 & nonzero_bits (other, GET_MODE (dest))) != 0)
return x;
assign = make_extraction (VOIDmode, dest, pos, NULL_RTX, len, 1, 1, 0);
else
{
if (GET_CODE (XEXP (x, 1)) != CONST_INT
- || INTVAL (XEXP (x, 1)) != constop)
+ || (unsigned HOST_WIDE_INT) INTVAL (XEXP (x, 1)) != constop)
SUBST (XEXP (x, 1), GEN_INT (constop));
SUBST (XEXP (x, 0), varop);
{
nonzero &= nonzero_bits (SUBREG_REG (x), mode);
-#ifndef WORD_REGISTER_OPERATIONS
- /* On many CISC machines, accessing an object in a wider mode
- causes the high-order bits to become undefined. So they are
- not known to be zero. */
- if (GET_MODE_SIZE (GET_MODE (x))
- > GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
- nonzero |= (GET_MODE_MASK (GET_MODE (x))
- & ~ GET_MODE_MASK (GET_MODE (SUBREG_REG (x))));
+#if defined (WORD_REGISTER_OPERATIONS) && defined (LOAD_EXTEND_OP)
+ /* If this is a typical RISC machine, we only have to worry
+ about the way loads are extended. */
+ if (LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (x))) == SIGN_EXTEND
+ ? (nonzero
+ & (1L << (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x))) - 1)))
+ : LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (x))) != ZERO_EXTEND)
#endif
+ {
+ /* On many CISC machines, accessing an object in a wider mode
+ causes the high-order bits to become undefined. So they are
+ not known to be zero. */
+ if (GET_MODE_SIZE (GET_MODE (x))
+ > GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
+ nonzero |= (GET_MODE_MASK (GET_MODE (x))
+ & ~ GET_MODE_MASK (GET_MODE (SUBREG_REG (x))));
+ }
}
break;
op0 = NIL;
else if (const0 == 0 && op0 == AND)
op0 = SET;
- else if (const0 == GET_MODE_MASK (mode) && op0 == AND)
+ else if ((unsigned HOST_WIDE_INT) const0 == GET_MODE_MASK (mode)
+ && op0 == AND)
op0 = NIL;
/* If this would be an entire word for the target, but is not for
&& GET_CODE (XEXP (varop, 0)) == LSHIFTRT
&& GET_CODE (XEXP (XEXP (varop, 0), 1)) == CONST_INT
&& (INTVAL (XEXP (XEXP (varop, 0), 1))
- >= (GET_MODE_BITSIZE (GET_MODE (XEXP (varop, 0))) - GET_MODE_BITSIZE (varop))))
+ >= (GET_MODE_BITSIZE (GET_MODE (XEXP (varop, 0)))
+ - GET_MODE_BITSIZE (GET_MODE (varop)))))
{
rtx varop_inner = XEXP (varop, 0);
PNOTES is a pointer to a location where any REG_UNUSED notes added for
the CLOBBERs are placed.
- PADDED_SCRATCHES is set to the number of (clobber (scratch)) patterns
- we had to add.
-
The value is the final insn code from the pattern ultimately matched,
or -1. */
static int
-recog_for_combine (pnewpat, insn, pnotes, padded_scratches)
+recog_for_combine (pnewpat, insn, pnotes)
rtx *pnewpat;
rtx insn;
rtx *pnotes;
- int *padded_scratches;
{
register rtx pat = *pnewpat;
int insn_code_number;
int i;
rtx notes = 0;
- *padded_scratches = 0;
-
/* If PAT is a PARALLEL, check to see if it contains the CLOBBER
we use to indicate that something didn't match. If we find such a
thing, force rejection. */
if (GET_CODE (XEXP (XVECEXP (newpat, 0, i), 0)) == REG
&& ! reg_dead_at_p (XEXP (XVECEXP (newpat, 0, i), 0), insn))
return -1;
- else if (GET_CODE (XEXP (XVECEXP (newpat, 0, i), 0)) == SCRATCH)
- (*padded_scratches)++;
notes = gen_rtx_EXPR_LIST (REG_UNUSED,
XEXP (XVECEXP (newpat, 0, i), 0), notes);
}
static rtx
gen_rtx_combine VPROTO((enum rtx_code code, enum machine_mode mode, ...))
{
-#ifndef __STDC__
+#ifndef ANSI_PROTOTYPES
enum rtx_code code;
enum machine_mode mode;
#endif
VA_START (p, mode);
-#ifndef __STDC__
+#ifndef ANSI_PROTOTYPES
code = va_arg (p, enum rtx_code);
mode = va_arg (p, enum machine_mode);
#endif
&& GET_RTX_CLASS (GET_CODE (op1)) != 'o')))
return gen_rtx_combine (code, mode, op1, op0);
+ /* If we are turning off bits already known off in OP0, we need not do
+ an AND. */
+ else if (code == AND && GET_CODE (op1) == CONST_INT
+ && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
+ && (nonzero_bits (op0, mode) & ~ INTVAL (op1)) == 0)
+ return op0;
+
return gen_rtx_combine (code, mode, op0, op1);
}
> GET_MODE_SIZE (GET_MODE (SUBREG_REG (inner_op0))))
&& (GET_MODE (SUBREG_REG (inner_op0))
== GET_MODE (SUBREG_REG (inner_op1)))
- && (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (op0)))
+ && (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (inner_op0)))
<= HOST_BITS_PER_WIDE_INT)
&& (0 == ((~c0) & nonzero_bits (SUBREG_REG (inner_op0),
- GET_MODE (SUBREG_REG (op0)))))
+ GET_MODE (SUBREG_REG (inner_op0)))))
&& (0 == ((~c1) & nonzero_bits (SUBREG_REG (inner_op1),
GET_MODE (SUBREG_REG (inner_op1))))))
{
for (tmode = GET_CLASS_NARROWEST_MODE
(GET_MODE_CLASS (GET_MODE (op0)));
tmode != GET_MODE (op0); tmode = GET_MODE_WIDER_MODE (tmode))
- if (c0 == GET_MODE_MASK (tmode))
+ if ((unsigned HOST_WIDE_INT) c0 == GET_MODE_MASK (tmode))
{
op0 = gen_lowpart_for_combine (tmode, inner_op0);
op1 = gen_lowpart_for_combine (tmode, inner_op1);
|| code == LT || code == LTU)
&& mode_width <= HOST_BITS_PER_WIDE_INT
&& exact_log2 (const_op) >= 0
- && nonzero_bits (op0, mode) == const_op)
+ && nonzero_bits (op0, mode) == (unsigned HOST_WIDE_INT) const_op)
{
code = (code == EQ || code == GE || code == GEU ? NE : EQ);
op1 = const0_rtx, const_op = 0;
&& (i = exact_log2 (INTVAL (XEXP (op0, 0)))) >= 0)
{
if (BITS_BIG_ENDIAN)
+ {
#ifdef HAVE_extzv
- i = (GET_MODE_BITSIZE
- (insn_operand_mode[(int) CODE_FOR_extzv][1]) - 1 - i);
+ mode = insn_operand_mode[(int) CODE_FOR_extzv][1];
+ if (mode == VOIDmode)
+ mode = word_mode;
+ i = (GET_MODE_BITSIZE (mode) - 1 - i);
#else
- i = BITS_PER_WORD - 1 - i;
+ i = BITS_PER_WORD - 1 - i;
#endif
+ }
op0 = XEXP (op0, 2);
op1 = GEN_INT (i);
&& (GET_MODE_BITSIZE (GET_MODE (XEXP (op0, 0)))
<= HOST_BITS_PER_WIDE_INT)
&& ((unsigned HOST_WIDE_INT) const_op
- < (((HOST_WIDE_INT) 1
+ < (((unsigned HOST_WIDE_INT) 1
<< (GET_MODE_BITSIZE (GET_MODE (XEXP (op0, 0))) - 1)))))
{
op0 = XEXP (op0, 0);
&& GET_CODE (XEXP (SUBREG_REG (op0), 1)) == CONST_INT
&& INTVAL (XEXP (SUBREG_REG (op0), 1)) < 0
&& (- INTVAL (XEXP (SUBREG_REG (op0), 1))
- < GET_MODE_MASK (mode) / 2)
+ < (HOST_WIDE_INT)(GET_MODE_MASK (mode) / 2))
&& (unsigned HOST_WIDE_INT) const_op < GET_MODE_MASK (mode) / 2
&& (0 == (nonzero_bits (XEXP (SUBREG_REG (op0), 0),
GET_MODE (SUBREG_REG (op0)))
&& GET_CODE (XEXP (op0, 1)) == CONST_INT
&& mode_width <= HOST_BITS_PER_WIDE_INT
&& ((INTVAL (XEXP (op0, 1)) & GET_MODE_MASK (mode))
- == (HOST_WIDE_INT) 1 << (mode_width - 1)))
+ == (unsigned HOST_WIDE_INT) 1 << (mode_width - 1)))
{
op0 = XEXP (op0, 0);
code = (code == EQ ? GE : LT);
op0 = gen_lowpart_for_combine (tmode, XEXP (op0, 0));
continue;
}
+
+ /* If this is (and:M1 (subreg:M2 X 0) (const_int C1)) where C1 fits
+ in both M1 and M2 and the SUBREG is either paradoxical or
+ represents the low part, permute the SUBREG and the AND and
+ try again. */
+ if (GET_CODE (XEXP (op0, 0)) == SUBREG
+ && ((mode_width
+ >= GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (XEXP (op0, 0)))))
+#ifdef WORD_REGISTER_OPERATIONS
+ || subreg_lowpart_p (XEXP (op0, 0))
+#endif
+ )
+#ifndef WORD_REGISTER_OPERATIONS
+ /* It is unsafe to commute the AND into the SUBREG if the SUBREG
+ is paradoxical and WORD_REGISTER_OPERATIONS is not defined.
+ As originally written the upper bits have a defined value
+ due to the AND operation. However, if we commute the AND
+ inside the SUBREG then they no longer have defined values
+ and the meaning of the code has been changed. */
+ && (GET_MODE_SIZE (GET_MODE (XEXP (op0, 0)))
+ <= GET_MODE_SIZE (GET_MODE (SUBREG_REG (XEXP (op0, 0)))))
+#endif
+ && GET_CODE (XEXP (op0, 1)) == CONST_INT
+ && mode_width <= HOST_BITS_PER_WIDE_INT
+ && (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (XEXP (op0, 0))))
+ <= HOST_BITS_PER_WIDE_INT)
+ && (INTVAL (XEXP (op0, 1)) & ~ mask) == 0
+ && 0 == (~ GET_MODE_MASK (GET_MODE (SUBREG_REG (XEXP (op0, 0))))
+ & INTVAL (XEXP (op0, 1)))
+ && (unsigned HOST_WIDE_INT) INTVAL (XEXP (op0, 1)) != mask
+ && ((unsigned HOST_WIDE_INT) INTVAL (XEXP (op0, 1))
+ != GET_MODE_MASK (GET_MODE (SUBREG_REG (XEXP (op0, 0))))))
+
+ {
+ op0
+ = gen_lowpart_for_combine
+ (mode,
+ gen_binary (AND, GET_MODE (SUBREG_REG (XEXP (op0, 0))),
+ SUBREG_REG (XEXP (op0, 0)), XEXP (op0, 1)));
+ continue;
+ }
+
break;
case ASHIFT:
if (reg_set_p (XEXP (note, 0), PATTERN (tem)))
{
rtx set = single_set (tem);
+ rtx inner_dest = 0;
+#ifdef HAVE_cc0
+ rtx cc0_setter = NULL_RTX;
+#endif
+
+ if (set != 0)
+ for (inner_dest = SET_DEST (set);
+ GET_CODE (inner_dest) == STRICT_LOW_PART
+ || GET_CODE (inner_dest) == SUBREG
+ || GET_CODE (inner_dest) == ZERO_EXTRACT;
+ inner_dest = XEXP (inner_dest, 0))
+ ;
/* Verify that it was the set, and not a clobber that
- modified the register. */
+ modified the register.
+
+ CC0 targets must be careful to maintain setter/user
+ pairs. If we cannot delete the setter due to side
+ effects, mark the user with an UNUSED note instead
+ of deleting it. */
if (set != 0 && ! side_effects_p (SET_SRC (set))
- && (rtx_equal_p (XEXP (note, 0), SET_DEST (set))
- || (GET_CODE (SET_DEST (set)) == SUBREG
- && rtx_equal_p (XEXP (note, 0),
- XEXP (SET_DEST (set), 0)))))
+ && rtx_equal_p (XEXP (note, 0), inner_dest)
+#ifdef HAVE_cc0
+ && (! reg_mentioned_p (cc0_rtx, SET_SRC (set))
+ || ((cc0_setter = prev_cc0_setter (tem)) != NULL
+ && sets_cc0_p (PATTERN (cc0_setter)) > 0))
+#endif
+ )
{
/* Move the notes and links of TEM elsewhere.
This might delete other dead insns recursively.
PUT_CODE (tem, NOTE);
NOTE_LINE_NUMBER (tem) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (tem) = 0;
+
+#ifdef HAVE_cc0
+ /* Delete the setter too. */
+ if (cc0_setter)
+ {
+ PATTERN (cc0_setter) = pc_rtx;
+
+ distribute_notes (REG_NOTES (cc0_setter),
+ cc0_setter, cc0_setter,
+ NULL_RTX, NULL_RTX, NULL_RTX);
+ distribute_links (LOG_LINKS (cc0_setter));
+
+ PUT_CODE (cc0_setter, NOTE);
+ NOTE_LINE_NUMBER (cc0_setter) = NOTE_INSN_DELETED;
+ NOTE_SOURCE_FILE (cc0_setter) = 0;
+ }
+#endif
+ }
+ /* If the register is both set and used here, put the
+ REG_DEAD note here, but place a REG_UNUSED note
+ here too unless there already is one. */
+ else if (reg_referenced_p (XEXP (note, 0),
+ PATTERN (tem)))
+ {
+ place = tem;
+
+ if (! find_regno_note (tem, REG_UNUSED,
+ REGNO (XEXP (note, 0))))
+ REG_NOTES (tem)
+ = gen_rtx_EXPR_LIST (REG_UNUSED,
+ XEXP (note, 0),
+ REG_NOTES (tem));
}
else
{
}
/* If the register is set or already dead at PLACE, we needn't do
- anything with this note if it is still a REG_DEAD note.
+ anything with this note if it is still a REG_DEAD note.
+ We can here if it is set at all, not if is it totally replace,
+ which is what `dead_or_set_p' checks, so also check for it being
+ set partially. */
+
- Note that we cannot use just `dead_or_set_p' here since we can
- convert an assignment to a register into a bit-field assignment.
- Therefore, we must also omit the note if the register is the
- target of a bitfield assignment. */
-
if (place && REG_NOTE_KIND (note) == REG_DEAD)
{
int regno = REGNO (XEXP (note, 0));