/* Optimize by combining instructions for GNU compiler.
- Copyright (C) 1987, 88, 92, 93, 94, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
This file is part of GNU CC.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
/* This module is essentially the "combiner" phase of the U. of Arizona
static int total_attempts, total_merges, total_extras, total_successes;
-/* Define a defulat value for REVERSIBLE_CC_MODE.
+/* Define a default value for REVERSIBLE_CC_MODE.
We can never assume that a condition code mode is safe to reverse unless
the md tells us so. */
#ifndef REVERSIBLE_CC_MODE
/* Get the cuid of an insn. */
-#define INSN_CUID(INSN) (INSN_UID (INSN) > max_uid_cuid \
- ? (abort(), 0) \
- : uid_cuid[INSN_UID (INSN)])
+#define INSN_CUID(INSN) \
+(INSN_UID (INSN) > max_uid_cuid ? insn_cuid (INSN) : uid_cuid[INSN_UID (INSN)])
/* Maximum register number, which is the size of the tables below. */
static int n_occurrences;
-static void init_reg_last_arrays PROTO(());
-static void setup_incoming_promotions PROTO(());
+static void init_reg_last_arrays PROTO((void));
+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 combinable_i3pat PROTO((rtx, rtx *, rtx, rtx, int, rtx *));
unsigned HOST_WIDE_INT, rtx, int));
static rtx if_then_else_cond PROTO((rtx, rtx *, rtx *));
static rtx known_cond PROTO((rtx, enum rtx_code, rtx, rtx));
+static int rtx_equal_for_field_assignment_p PROTO((rtx, rtx));
static rtx make_field_assignment PROTO((rtx));
static rtx apply_distributive_law PROTO((rtx));
static rtx simplify_and_const_int PROTO((rtx, enum machine_mode, rtx,
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 *));
+static int recog_for_combine PROTO((rtx *, rtx, rtx *, int *));
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,
...));
static void distribute_notes PROTO((rtx, rtx, rtx, rtx, rtx, rtx));
static void distribute_links PROTO((rtx));
static void mark_used_regs_combine PROTO((rtx));
+static int insn_cuid PROTO((rtx));
\f
/* Main entry point for combiner. F is the first insn of the function.
NREGS is the first unused pseudo-reg number. */
label_tick = 1;
+ /* We need to initialize it here, because record_dead_and_set_regs may call
+ get_last_value. */
+ subst_prev_insn = NULL_RTX;
+
setup_incoming_promotions ();
for (insn = f, i = 0; insn; insn = NEXT_INSN (insn))
{
note_stores (PATTERN (insn), set_nonzero_bits_and_sign_copies);
record_dead_and_set_regs (insn);
+
+#ifdef AUTO_INC_DEC
+ for (links = REG_NOTES (insn); links; links = XEXP (links, 1))
+ if (REG_NOTE_KIND (links) == REG_INC)
+ set_nonzero_bits_and_sign_copies (XEXP (links, 0), NULL_RTX);
+#endif
}
if (GET_CODE (insn) == CODE_LABEL)
#endif
}
\f
-/* Called via note_stores. If X is a pseudo that is used in more than
- one basic block, is narrower that HOST_BITS_PER_WIDE_INT, and is being
- set, record what bits are known zero. If we are clobbering X,
- ignore this "set" because the clobbered value won't be used.
+/* Called via note_stores. If X is a pseudo that is narrower than
+ HOST_BITS_PER_WIDE_INT and is being set, record what bits are known zero.
If we are setting only a portion of X and we can't figure out what
portion, assume all bits will be used since we don't know what will
if (GET_CODE (x) == REG
&& REGNO (x) >= FIRST_PSEUDO_REGISTER
- && reg_n_sets[REGNO (x)] > 1
- && reg_basic_block[REGNO (x)] < 0
/* If this register is undefined at the start of the file, we can't
say what its contents were. */
&& ! (basic_block_live_at_start[0][REGNO (x) / REGSET_ELT_BITS]
& ((REGSET_ELT_TYPE) 1 << (REGNO (x) % REGSET_ELT_BITS)))
&& GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT)
{
- if (GET_CODE (set) == CLOBBER)
+ if (set == 0 || GET_CODE (set) == CLOBBER)
{
reg_nonzero_bits[REGNO (x)] = GET_MODE_MASK (GET_MODE (x));
- reg_sign_bit_copies[REGNO (x)] = 0;
+ reg_sign_bit_copies[REGNO (x)] = 1;
return;
}
else
{
reg_nonzero_bits[REGNO (x)] = GET_MODE_MASK (GET_MODE (x));
- reg_sign_bit_copies[REGNO (x)] = 0;
+ reg_sign_bit_copies[REGNO (x)] = 1;
}
}
}
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;
The problem can also happen if the dest of I3 is a memory ref,
if another dest in I2 is an indirect memory ref. */
for (i = 0; i < XVECLEN (p2, 0); i++)
- if (GET_CODE (XVECEXP (p2, 0, i)) == SET
+ if ((GET_CODE (XVECEXP (p2, 0, i)) == SET
+ || GET_CODE (XVECEXP (p2, 0, i)) == CLOBBER)
&& reg_overlap_mentioned_p (SET_DEST (PATTERN (i3)),
SET_DEST (XVECEXP (p2, 0, i))))
break;
mark_used_regs_combine (newpat);
/* Is the result of combination a valid instruction? */
- insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
+ insn_code_number
+ = recog_for_combine (&newpat, i3, &new_i3_notes, &i3_scratches);
/* 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);
+ insn_code_number
+ = recog_for_combine (&newpat, i3, &new_i3_notes, &i3_scratches);
}
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);
+ insn_code_number
+ = recog_for_combine (&newpat, i3, &new_i3_notes, &i3_scratches);
}
/* 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_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes,
+ &i2_scratches);
/* If I2 or I3 has multiple SETs, we won't know how to track
register status, so don't use these insns. */
if (i2_code_number >= 0 && i2set && i3set)
- insn_code_number = recog_for_combine (&newi3pat, i3,
- &new_i3_notes);
-
+ insn_code_number = recog_for_combine (&newi3pat, i3, &new_i3_notes,
+ &i3_scratches);
if (insn_code_number >= 0)
newpat = newi3pat;
/* It is possible that both insns now set the destination of I3.
If so, we must show an extra use of it. */
- if (insn_code_number >= 0 && GET_CODE (SET_DEST (i3set)) == REG
- && GET_CODE (SET_DEST (i2set)) == REG
- && REGNO (SET_DEST (i3set)) == REGNO (SET_DEST (i2set)))
- reg_n_sets[REGNO (SET_DEST (i2set))]++;
+ if (insn_code_number >= 0)
+ {
+ rtx new_i3_dest = SET_DEST (i3set);
+ rtx new_i2_dest = SET_DEST (i2set);
+
+ while (GET_CODE (new_i3_dest) == ZERO_EXTRACT
+ || GET_CODE (new_i3_dest) == STRICT_LOW_PART
+ || GET_CODE (new_i3_dest) == SUBREG)
+ new_i3_dest = XEXP (new_i3_dest, 0);
+
+ if (GET_CODE (new_i3_dest) == REG
+ && GET_CODE (new_i2_dest) == REG
+ && REGNO (new_i3_dest) == REGNO (new_i2_dest))
+ reg_n_sets[REGNO (SET_DEST (i2set))]++;
+ }
}
/* If we can split it and use I2DEST, go ahead and see if that
newi2pat = gen_rtx_combine (SET, VOIDmode, newdest, *split);
SUBST (*split, newdest);
- i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes);
+ i2_code_number
+ = recog_for_combine (&newi2pat, i2, &new_i2_notes, &i2_scratches);
/* 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);
+ insn_code_number
+ = recog_for_combine (&newpat, i3, &new_i3_notes, &i3_scratches);
}
}
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_code_number
+ = recog_for_combine (&newi2pat, i2, &new_i2_notes, &i2_scratches);
+
if (i2_code_number >= 0)
- insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
+ insn_code_number
+ = recog_for_combine (&newpat, i3, &new_i3_notes, &i3_scratches);
if (insn_code_number >= 0)
{
newi2pat = XVECEXP (newpat, 0, 1);
newpat = XVECEXP (newpat, 0, 0);
- i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes);
+ i2_code_number
+ = recog_for_combine (&newi2pat, i2, &new_i2_notes, &i2_scratches);
+
if (i2_code_number >= 0)
- insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
+ insn_code_number
+ = recog_for_combine (&newpat, i3, &new_i3_notes, &i3_scratches);
}
/* 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_code_number
+ = recog_for_combine (&other_pat, undobuf.other_insn,
+ &new_other_notes, &other_scratches);
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. */
combine_successes++;
+ /* Clear this here, so that subsequent get_last_value calls are not
+ affected. */
+ subst_prev_insn = NULL_RTX;
+
if (added_links_insn
&& (newi2pat == 0 || INSN_CUID (added_links_insn) < INSN_CUID (i2))
&& INSN_CUID (added_links_insn) < INSN_CUID (i3))
obfree (undobuf.storage);
undobuf.num_undo = 0;
+
+ /* Clear this here, so that subsequent get_last_value calls are not
+ affected. */
+ subst_prev_insn = NULL_RTX;
}
\f
/* Find the innermost point within the rtx at LOC, possibly LOC itself,
/* If we have a PLUS whose second operand is a constant and the
address is not valid, perhaps will can split it up using
the machine-specific way to split large constants. We use
- the first psuedo-reg (one of the virtual regs) as a placeholder;
+ the first pseudo-reg (one of the virtual regs) as a placeholder;
it will not remain in the result. */
if (GET_CODE (XEXP (x, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
if (split && split != &SET_SRC (x))
return split;
+ /* See if we can split SET_DEST as it stands. */
+ split = find_split_point (&SET_DEST (x), insn);
+ if (split && split != &SET_DEST (x))
+ return split;
+
/* See if this is a bitfield assignment with everything constant. If
so, this is an IOR of an AND, so split it into that. */
if (GET_CODE (SET_DEST (x)) == ZERO_EXTRACT
&& XEXP (*split, 0) == SET_DEST (x)
&& XEXP (*split, 1) == const0_rtx)
{
- SUBST (SET_SRC (x),
- make_extraction (GET_MODE (SET_DEST (x)),
- XEXP (SET_SRC (x), 0),
- pos, NULL_RTX, 1, 1, 0, 0));
- return find_split_point (loc, insn);
+ rtx extraction = make_extraction (GET_MODE (SET_DEST (x)),
+ XEXP (SET_SRC (x), 0),
+ pos, NULL_RTX, 1, 1, 0, 0);
+ if (extraction != 0)
+ {
+ SUBST (SET_SRC (x), extraction);
+ return find_split_point (loc, insn);
+ }
}
break;
rtx cop1 = const0_rtx;
enum rtx_code cond_code = simplify_comparison (NE, &cond, &cop1);
+ if (cond_code == NE && GET_RTX_CLASS (GET_CODE (cond)) == '<')
+ return x;
+
/* Simplify the alternative arms; this may collapse the true and
false arms to store-flag values. */
true = subst (true, pc_rtx, pc_rtx, 0, 0);
always valid. On a big-endian machine, it's valid
only if the constant's mode fits in one word. */
if (CONSTANT_P (SUBREG_REG (x)) && subreg_lowpart_p (x)
- && GET_MODE_SIZE (mode) < GET_MODE_SIZE (op0_mode)
+ && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (op0_mode)
&& (! WORDS_BIG_ENDIAN
|| GET_MODE_BITSIZE (op0_mode) <= BITS_PER_WORD))
return gen_lowpart_for_combine (mode, SUBREG_REG (x));
SUBST (XEXP (x, 2), true);
temp = true, true = false, false = temp, cond = XEXP (x, 0);
+
+ /* It is possible that the conditional has been simplified out. */
+ true_code = GET_CODE (cond);
+ comparison_p = GET_RTX_CLASS (true_code) == '<';
}
/* If the two arms are identical, we don't need the comparison. */
if (rtx_equal_p (true, false) && ! side_effects_p (cond))
return true;
+ /* Convert a == b ? b : a to "a". */
+ if (true_code == EQ && ! side_effects_p (cond)
+ && rtx_equal_p (XEXP (cond, 0), false)
+ && rtx_equal_p (XEXP (cond, 1), true))
+ return false;
+ else if (true_code == NE && ! side_effects_p (cond)
+ && rtx_equal_p (XEXP (cond, 0), true)
+ && rtx_equal_p (XEXP (cond, 1), false))
+ return true;
+
/* Look for cases where we have (abs x) or (neg (abs X)). */
if (GET_MODE_CLASS (mode) == MODE_INT
&& 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) < 0
+ if ((recog_for_combine (&pat, other_insn, ¬e, &scratches) < 0
&& ! check_asm_operands (pat)))
{
PUT_CODE (*cc_use, old_code);
{
inner = SUBREG_REG (XEXP (SET_DEST (x), 0));
len = GET_MODE_BITSIZE (GET_MODE (XEXP (SET_DEST (x), 0)));
- pos = const0_rtx;
+ pos = GEN_INT (BITS_PER_WORD * SUBREG_WORD (XEXP (SET_DEST (x), 0)));
}
else if (GET_CODE (SET_DEST (x)) == ZERO_EXTRACT
&& GET_CODE (XEXP (SET_DEST (x), 1)) == CONST_INT)
IN_COMPARE is non-zero if we are in a COMPARE. This means that a
ZERO_EXTRACT should be built even for bits starting at bit 0.
- MODE is the desired mode of the result (if IN_DEST == 0). */
+ MODE is the desired mode of the result (if IN_DEST == 0).
+
+ The result is an RTX for the extraction or NULL_RTX if the target
+ can't handle it. */
static rtx
make_extraction (mode, inner, pos, pos_rtx, len,
ignore the POS lowest bits, etc. */
enum machine_mode is_mode = GET_MODE (inner);
enum machine_mode inner_mode;
- enum machine_mode wanted_mem_mode = byte_mode;
+ enum machine_mode wanted_inner_mode = byte_mode;
+ enum machine_mode wanted_inner_reg_mode = word_mode;
enum machine_mode pos_mode = word_mode;
enum machine_mode extraction_mode = word_mode;
enum machine_mode tmode = mode_for_size (len, MODE_INT, 1);
if (tmode != BLKmode
&& ! (spans_byte && inner_mode != tmode)
- && ((pos_rtx == 0 && pos == 0 && GET_CODE (inner) != MEM
+ && ((pos_rtx == 0 && (pos % BITS_PER_WORD) == 0
+ && GET_CODE (inner) != MEM
&& (! in_dest
|| (GET_CODE (inner) == REG
&& (movstrict_optab->handlers[(int) tmode].insn_code
field. If the original and current mode are the same, we need not
adjust the offset. Otherwise, we do if bytes big endian.
- If INNER is not a MEM, get a piece consisting of the just the field
- of interest (in this case POS must be 0). */
+ If INNER is not a MEM, get a piece consisting of just the field
+ of interest (in this case POS % BITS_PER_WORD must be 0). */
if (GET_CODE (inner) == MEM)
{
new = gen_rtx (SUBREG, tmode, inner,
(WORDS_BIG_ENDIAN
&& GET_MODE_SIZE (inner_mode) > UNITS_PER_WORD
- ? ((GET_MODE_SIZE (inner_mode)
- - GET_MODE_SIZE (tmode))
- / UNITS_PER_WORD)
- : 0));
+ ? (((GET_MODE_SIZE (inner_mode)
+ - GET_MODE_SIZE (tmode))
+ / UNITS_PER_WORD)
+ - pos / BITS_PER_WORD)
+ : pos / BITS_PER_WORD));
else
new = inner;
}
|| (pos_rtx != 0 && len != 1)))
return 0;
- /* Get the mode to use should INNER be a MEM, the mode for the position,
+ /* Get the mode to use should INNER not be a MEM, the mode for the position,
and the mode for the result. */
#ifdef HAVE_insv
if (in_dest)
{
- wanted_mem_mode = insn_operand_mode[(int) CODE_FOR_insv][0];
+ 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];
}
#ifdef HAVE_extzv
if (! in_dest && unsignedp)
{
- wanted_mem_mode = insn_operand_mode[(int) CODE_FOR_extzv][1];
+ 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];
}
#ifdef HAVE_extv
if (! in_dest && ! unsignedp)
{
- wanted_mem_mode = insn_operand_mode[(int) CODE_FOR_extv][1];
+ 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];
}
&& GET_MODE_SIZE (pos_mode) < GET_MODE_SIZE (GET_MODE (pos_rtx)))
pos_mode = GET_MODE (pos_rtx);
- /* If this is not from memory or we have to change the mode of memory and
- cannot, the desired mode is EXTRACTION_MODE. */
- if (GET_CODE (inner) != MEM
- || (inner_mode != wanted_mem_mode
- && (mode_dependent_address_p (XEXP (inner, 0))
- || MEM_VOLATILE_P (inner))))
- wanted_mem_mode = extraction_mode;
+ /* If this is not from memory, the desired mode is wanted_inner_reg_mode;
+ if we have to change the mode of memory and cannot, the desired mode is
+ EXTRACTION_MODE. */
+ if (GET_CODE (inner) != MEM)
+ wanted_inner_mode = wanted_inner_reg_mode;
+ else if (inner_mode != wanted_inner_mode
+ && (mode_dependent_address_p (XEXP (inner, 0))
+ || MEM_VOLATILE_P (inner)))
+ wanted_inner_mode = extraction_mode;
orig_pos = pos;
if (BITS_BIG_ENDIAN)
{
- /* If position is constant, compute new position. Otherwise,
- build subtraction. */
+ /* POS is passed as if BITS_BIG_ENDIAN == 0, so we need to convert it to
+ BITS_BIG_ENDIAN style. If position is constant, compute new
+ position. Otherwise, build subtraction.
+ Note that POS is relative to the mode of the original argument.
+ If it's a MEM we need to recompute POS relative to that.
+ However, if we're extracting from (or inserting into) a register,
+ we want to recompute POS relative to wanted_inner_mode. */
+ int width = (GET_CODE (inner) == MEM
+ ? GET_MODE_BITSIZE (is_mode)
+ : GET_MODE_BITSIZE (wanted_inner_mode));
+
if (pos_rtx == 0)
- pos = (MAX (GET_MODE_BITSIZE (is_mode),
- GET_MODE_BITSIZE (wanted_mem_mode))
- - len - pos);
+ pos = width - len - pos;
else
pos_rtx
= gen_rtx_combine (MINUS, GET_MODE (pos_rtx),
- GEN_INT (MAX (GET_MODE_BITSIZE (is_mode),
- GET_MODE_BITSIZE (wanted_mem_mode))
- - len),
- pos_rtx);
+ GEN_INT (width - len), pos_rtx);
+ /* POS may be less than 0 now, but we check for that below.
+ Note that it can only be less than 0 if GET_CODE (inner) != MEM. */
}
/* If INNER has a wider mode, make it smaller. If this is a constant
extract, try to adjust the byte to point to the byte containing
the value. */
- if (wanted_mem_mode != VOIDmode
- && GET_MODE_SIZE (wanted_mem_mode) < GET_MODE_SIZE (is_mode)
+ if (wanted_inner_mode != VOIDmode
+ && GET_MODE_SIZE (wanted_inner_mode) < GET_MODE_SIZE (is_mode)
&& ((GET_CODE (inner) == MEM
- && (inner_mode == wanted_mem_mode
+ && (inner_mode == wanted_inner_mode
|| (! mode_dependent_address_p (XEXP (inner, 0))
&& ! MEM_VOLATILE_P (inner))))))
{
if (pos_rtx == 0)
{
offset += pos / BITS_PER_UNIT;
- pos %= GET_MODE_BITSIZE (wanted_mem_mode);
+ pos %= GET_MODE_BITSIZE (wanted_inner_mode);
}
if (BYTES_BIG_ENDIAN != BITS_BIG_ENDIAN
&& ! spans_byte
- && is_mode != wanted_mem_mode)
+ && is_mode != wanted_inner_mode)
offset = (GET_MODE_SIZE (is_mode)
- - GET_MODE_SIZE (wanted_mem_mode) - offset);
+ - GET_MODE_SIZE (wanted_inner_mode) - offset);
- if (offset != 0 || inner_mode != wanted_mem_mode)
+ if (offset != 0 || inner_mode != wanted_inner_mode)
{
- rtx newmem = gen_rtx (MEM, wanted_mem_mode,
+ rtx newmem = gen_rtx (MEM, wanted_inner_mode,
plus_constant (XEXP (inner, 0), offset));
RTX_UNCHANGING_P (newmem) = RTX_UNCHANGING_P (inner);
MEM_VOLATILE_P (newmem) = MEM_VOLATILE_P (inner);
}
}
- /* If INNER is not memory, we can always get it into the proper mode. */
+ /* If INNER is not memory, we can always get it into the proper mode. If we
+ are changing its mode, POS must be a constant and smaller than the size
+ of the new mode. */
else if (GET_CODE (inner) != MEM)
- inner = force_to_mode (inner, extraction_mode,
- pos_rtx || len + orig_pos >= HOST_BITS_PER_WIDE_INT
- ? GET_MODE_MASK (extraction_mode)
- : (((HOST_WIDE_INT) 1 << len) - 1) << orig_pos,
- NULL_RTX, 0);
+ {
+ if (GET_MODE (inner) != wanted_inner_mode
+ && (pos_rtx != 0
+ || orig_pos + len > GET_MODE_BITSIZE (wanted_inner_mode)))
+ return 0;
+
+ inner = force_to_mode (inner, wanted_inner_mode,
+ pos_rtx
+ || len + orig_pos >= HOST_BITS_PER_WIDE_INT
+ ? GET_MODE_MASK (wanted_inner_mode)
+ : (((HOST_WIDE_INT) 1 << len) - 1) << orig_pos,
+ NULL_RTX, 0);
+ }
/* Adjust mode of POS_RTX, if needed. If we want a wider mode, we
have to zero extend. Otherwise, we can just use a SUBREG. */
+ floor_log2 (INTVAL (XEXP (x, 1))))
< GET_MODE_BITSIZE (GET_MODE (x)))
&& (INTVAL (XEXP (x, 1))
- & ~ nonzero_bits (XEXP (x, 0), GET_MODE (x)) == 0))
+ & ~ nonzero_bits (XEXP (x, 0), GET_MODE (x))) == 0)
{
temp = GEN_INT ((INTVAL (XEXP (x, 1)) & mask)
<< INTVAL (XEXP (XEXP (x, 0), 1)));
temp = gen_binary (GET_CODE (x), GET_MODE (x),
XEXP (XEXP (x, 0), 0), temp);
- x = gen_binary (LSHIFTRT, GET_MODE (x), temp, XEXP (x, 1));
+ x = gen_binary (LSHIFTRT, GET_MODE (x), temp,
+ XEXP (XEXP (x, 0), 1));
return force_to_mode (x, mode, mask, reg, next_select);
}
case ASHIFTRT:
/* 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 (mask == ((HOST_WIDE_INT) 1
- << (GET_MODE_BITSIZE (GET_MODE (x)) - 1)))
+ if (GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT
+ && (mask == ((HOST_WIDE_INT) 1
+ << (GET_MODE_BITSIZE (GET_MODE (x)) - 1))))
return force_to_mode (XEXP (x, 0), mode, mask, reg, next_select);
/* If this is a shift by a constant, get a mask that contains those bits
{
int i = -1;
- nonzero = GET_MODE_MASK (GET_MODE (x));
- nonzero >>= INTVAL (XEXP (x, 1));
+ /* If the considered data is wider then HOST_WIDE_INT, we can't
+ represent a mask for all its bits in a single scalar.
+ But we only care about the lower bits, so calculate these. */
+
+ if (GET_MODE_BITSIZE (GET_MODE (x)) > HOST_BITS_PER_WIDE_INT)
+ {
+ nonzero = ~(HOST_WIDE_INT)0;
+
+ /* GET_MODE_BITSIZE (GET_MODE (x)) - INTVAL (XEXP (x, 1))
+ is the number of bits a full-width mask would have set.
+ We need only shift if these are fewer than nonzero can
+ hold. If not, we must keep all bits set in nonzero. */
+
+ if (GET_MODE_BITSIZE (GET_MODE (x)) - INTVAL (XEXP (x, 1))
+ < HOST_BITS_PER_WIDE_INT)
+ nonzero >>= INTVAL (XEXP (x, 1))
+ + HOST_BITS_PER_WIDE_INT
+ - GET_MODE_BITSIZE (GET_MODE (x)) ;
+ }
+ else
+ {
+ nonzero = GET_MODE_MASK (GET_MODE (x));
+ nonzero >>= INTVAL (XEXP (x, 1));
+ }
if ((mask & ~ nonzero) == 0
|| (i = exact_log2 (mask)) >= 0)
return force_to_mode (x, mode, mask, reg, next_select);
}
+ /* (and (not FOO) CONST) is (not (or FOO (not CONST))), so we must
+ use the full mask inside the NOT. */
+ mask = fuller_mask;
+
unop:
op0 = gen_lowpart_for_combine (op_mode,
force_to_mode (XEXP (x, 0), mode, mask,
}
/* If this is a COMPARE, do nothing, since the IF_THEN_ELSE we would
- make can't possibly match and would supress other optimizations. */
+ make can't possibly match and would suppress other optimizations. */
else if (code == COMPARE)
;
return x;
}
\f
+/* See if X and Y are equal for the purposes of seeing if we can rewrite an
+ assignment as a field assignment. */
+
+static int
+rtx_equal_for_field_assignment_p (x, y)
+ rtx x;
+ rtx y;
+{
+ rtx last_x, last_y;
+
+ if (x == y || rtx_equal_p (x, y))
+ return 1;
+
+ if (x == 0 || y == 0 || GET_MODE (x) != GET_MODE (y))
+ return 0;
+
+ /* Check for a paradoxical SUBREG of a MEM compared with the MEM.
+ Note that all SUBREGs of MEM are paradoxical; otherwise they
+ would have been rewritten. */
+ if (GET_CODE (x) == MEM && GET_CODE (y) == SUBREG
+ && GET_CODE (SUBREG_REG (y)) == MEM
+ && rtx_equal_p (SUBREG_REG (y),
+ gen_lowpart_for_combine (GET_MODE (SUBREG_REG (y)), x)))
+ return 1;
+
+ if (GET_CODE (y) == MEM && GET_CODE (x) == SUBREG
+ && GET_CODE (SUBREG_REG (x)) == MEM
+ && rtx_equal_p (SUBREG_REG (x),
+ 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 && rtx_equal_for_field_assignment_p (last_x, y))
+ || (last_y != 0 && rtx_equal_for_field_assignment_p (x, last_y))
+ || (last_x != 0 && last_y != 0
+ && rtx_equal_for_field_assignment_p (last_x, last_y)));
+}
+\f
/* See if X, a SET operation, can be rewritten as a bit-field assignment.
Return that assignment if so.
rtx dest = SET_DEST (x);
rtx src = SET_SRC (x);
rtx assign;
+ rtx rhs, lhs;
HOST_WIDE_INT c1;
int pos, len;
rtx other;
if (GET_CODE (src) == AND && GET_CODE (XEXP (src, 0)) == ROTATE
&& GET_CODE (XEXP (XEXP (src, 0), 0)) == CONST_INT
&& INTVAL (XEXP (XEXP (src, 0), 0)) == -2
- && (rtx_equal_p (dest, XEXP (src, 1))
- || rtx_equal_p (dest, get_last_value (XEXP (src, 1)))
- || rtx_equal_p (get_last_value (dest), XEXP (src, 1))))
+ && rtx_equal_for_field_assignment_p (dest, XEXP (src, 1)))
{
assign = make_extraction (VOIDmode, dest, 0, XEXP (XEXP (src, 0), 1),
1, 1, 1, 0);
- return gen_rtx (SET, VOIDmode, assign, const0_rtx);
+ if (assign != 0)
+ return gen_rtx (SET, VOIDmode, assign, const0_rtx);
+ return x;
}
else if (GET_CODE (src) == AND && GET_CODE (XEXP (src, 0)) == SUBREG
< GET_MODE_SIZE (GET_MODE (SUBREG_REG (XEXP (src, 0)))))
&& GET_CODE (SUBREG_REG (XEXP (src, 0))) == ROTATE
&& INTVAL (XEXP (SUBREG_REG (XEXP (src, 0)), 0)) == -2
- && (rtx_equal_p (dest, XEXP (src, 1))
- || rtx_equal_p (dest, get_last_value (XEXP (src, 1)))
- || rtx_equal_p (get_last_value (dest), XEXP (src, 1))))
+ && rtx_equal_for_field_assignment_p (dest, XEXP (src, 1)))
{
assign = make_extraction (VOIDmode, dest, 0,
XEXP (SUBREG_REG (XEXP (src, 0)), 1),
1, 1, 1, 0);
- return gen_rtx (SET, VOIDmode, assign, const0_rtx);
+ if (assign != 0)
+ return gen_rtx (SET, VOIDmode, assign, const0_rtx);
+ return x;
}
- /* If SRC is (ior (ashift (const_int 1) POS DEST)), this is a set of a
+ /* If SRC is (ior (ashift (const_int 1) POS) DEST), this is a set of a
one-bit field. */
else if (GET_CODE (src) == IOR && GET_CODE (XEXP (src, 0)) == ASHIFT
&& XEXP (XEXP (src, 0), 0) == const1_rtx
- && (rtx_equal_p (dest, XEXP (src, 1))
- || rtx_equal_p (dest, get_last_value (XEXP (src, 1)))
- || rtx_equal_p (get_last_value (dest), XEXP (src, 1))))
+ && rtx_equal_for_field_assignment_p (dest, XEXP (src, 1)))
{
assign = make_extraction (VOIDmode, dest, 0, XEXP (XEXP (src, 0), 1),
1, 1, 1, 0);
- return gen_rtx (SET, VOIDmode, assign, const1_rtx);
+ if (assign != 0)
+ return gen_rtx (SET, VOIDmode, assign, const1_rtx);
+ return x;
}
/* The other case we handle is assignments into a constant-position
- field. They look like (ior (and DEST C1) OTHER). If C1 represents
+ field. They look like (ior/xor (and DEST C1) OTHER). If C1 represents
a mask that has all one bits except for a group of zero bits and
OTHER is known to have zeros where C1 has ones, this is such an
assignment. Compute the position and length from C1. Shift OTHER
to the appropriate position, force it to the required mode, and
make the extraction. Check for the AND in both operands. */
- if (GET_CODE (src) == IOR && GET_CODE (XEXP (src, 0)) == AND
- && GET_CODE (XEXP (XEXP (src, 0), 1)) == CONST_INT
- && (rtx_equal_p (XEXP (XEXP (src, 0), 0), dest)
- || rtx_equal_p (XEXP (XEXP (src, 0), 0), get_last_value (dest))
- || rtx_equal_p (get_last_value (XEXP (XEXP (src, 0), 1)), dest)))
- c1 = INTVAL (XEXP (XEXP (src, 0), 1)), other = XEXP (src, 1);
- else if (GET_CODE (src) == IOR && GET_CODE (XEXP (src, 1)) == AND
- && GET_CODE (XEXP (XEXP (src, 1), 1)) == CONST_INT
- && (rtx_equal_p (XEXP (XEXP (src, 1), 0), dest)
- || rtx_equal_p (XEXP (XEXP (src, 1), 0), get_last_value (dest))
- || rtx_equal_p (get_last_value (XEXP (XEXP (src, 1), 0)),
- dest)))
- c1 = INTVAL (XEXP (XEXP (src, 1), 1)), other = XEXP (src, 0);
+ if (GET_CODE (src) != IOR && GET_CODE (src) != XOR)
+ return x;
+
+ rhs = expand_compound_operation (XEXP (src, 0));
+ lhs = expand_compound_operation (XEXP (src, 1));
+
+ if (GET_CODE (rhs) == AND
+ && GET_CODE (XEXP (rhs, 1)) == CONST_INT
+ && rtx_equal_for_field_assignment_p (XEXP (rhs, 0), dest))
+ c1 = INTVAL (XEXP (rhs, 1)), other = lhs;
+ else if (GET_CODE (lhs) == AND
+ && GET_CODE (XEXP (lhs, 1)) == CONST_INT
+ && rtx_equal_for_field_assignment_p (XEXP (lhs, 0), dest))
+ c1 = INTVAL (XEXP (lhs, 1)), other = rhs;
else
return x;
- pos = get_pos_from_mask (c1 ^ GET_MODE_MASK (GET_MODE (dest)), &len);
+ 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))
return x;
assign = make_extraction (VOIDmode, dest, pos, NULL_RTX, len, 1, 1, 0);
+ if (assign == 0)
+ return x;
/* The mode to use for the source is the mode of the assignment, or of
what is inside a possible STRICT_LOW_PART. */
switch (code)
{
case REG:
+#ifdef POINTERS_EXTEND_UNSIGNED
+ /* If pointers extend unsigned and this is a pointer in Pmode, say that
+ all the bits above ptr_mode are known to be zero. */
+ if (POINTERS_EXTEND_UNSIGNED && GET_MODE (x) == Pmode
+ && REGNO_POINTER_FLAG (REGNO (x)))
+ nonzero &= GET_MODE_MASK (ptr_mode);
+#endif
+
#ifdef STACK_BOUNDARY
/* If this is the stack pointer, we may know something about its
alignment. If PUSH_ROUNDING is defined, it is possible for the
stack to be momentarily aligned only to that amount, so we pick
the least alignment. */
- if (x == stack_pointer_rtx)
+ /* We can't check for arg_pointer_rtx here, because it is not
+ guaranteed to have as much alignment as the stack pointer.
+ In particular, in the Irix6 n64 ABI, the stack has 128 bit
+ alignment but the argument pointer has only 64 bit alignment. */
+
+ if (x == stack_pointer_rtx || x == frame_pointer_rtx
+ || x == hard_frame_pointer_rtx
+ || (REGNO (x) >= FIRST_VIRTUAL_REGISTER
+ && REGNO (x) <= LAST_VIRTUAL_REGISTER))
{
int sp_alignment = STACK_BOUNDARY / BITS_PER_UNIT;
#ifdef PUSH_ROUNDING
- sp_alignment = MIN (PUSH_ROUNDING (1), sp_alignment);
+ if (REGNO (x) == STACK_POINTER_REGNUM)
+ sp_alignment = MIN (PUSH_ROUNDING (1), sp_alignment);
#endif
- nonzero &= ~ (sp_alignment - 1);
+ /* We must return here, otherwise we may get a worse result from
+ one of the choices below. There is nothing useful below as
+ far as the stack pointer is concerned. */
+ return nonzero &= ~ (sp_alignment - 1);
}
#endif
-#ifdef POINTERS_EXTEND_UNSIGNED
- /* If pointers extend unsigned and this is a pointer in Pmode, say that
- all the bits above ptr_mode are known to be zero. */
- if (POINTERS_EXTEND_UNSIGNED && GET_MODE (x) == Pmode
- && REGNO_POINTER_FLAG (REGNO (x)))
- nonzero &= GET_MODE_MASK (ptr_mode);
-#endif
-
/* If X is a register whose nonzero bits value is current, use it.
Otherwise, if X is a register whose value we can find, use that
value. Otherwise, use the previously-computed global nonzero bits
&& bitwidth <= HOST_BITS_PER_WIDE_INT
&& ((nonzero_bits (XEXP (x, 0), mode)
& ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0)
- && (nonzero_bits (XEXP (x, 1), mode)
- & ((HOST_WIDE_INT) 1 << (bitwidth - 1)) != 0))
+ && ((nonzero_bits (XEXP (x, 1), mode)
+ & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0))
result--;
return MAX (1, result);
if (complement_p)
break;
- /* Convert ROTATETRT to ROTATE. */
+ /* Convert ROTATERT to ROTATE. */
if (code == ROTATERT)
code = ROTATE, count = GET_MODE_BITSIZE (result_mode) - count;
/* We need to determine what mode we will do the shift in. If the
- shift is a ASHIFTRT or ROTATE, we must always do it in the mode it
- was originally done in. Otherwise, we can do it in MODE, the widest
- mode encountered. */
- shift_mode = (code == ASHIFTRT || code == ROTATE ? result_mode : mode);
+ shift is a right shift or a ROTATE, we must always do it in the mode
+ it was originally done in. Otherwise, we can do it in MODE, the
+ widest mode encountered. */
+ shift_mode
+ = (code == ASHIFTRT || code == LSHIFTRT || code == ROTATE
+ ? result_mode : mode);
/* Handle cases where the count is greater than the size of the mode
minus 1. For ASHIFT, use the size minus one as the count (this can
ASHIFTRT.
If the mode of this shift is not the mode of the outer shift,
- we can't do this if either shift is ASHIFTRT or ROTATE.
+ we can't do this if either shift is a right shift or ROTATE.
Finally, we can't do any of these if the mode is too wide
unless the codes are the same.
if (code == first_code)
{
if (GET_MODE (varop) != result_mode
- && (code == ASHIFTRT || code == ROTATE))
+ && (code == ASHIFTRT || code == LSHIFTRT
+ || code == ROTATE))
break;
count += first_count;
|| (code == ROTATE && first_code == ASHIFTRT)
|| GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT
|| (GET_MODE (varop) != result_mode
- && (first_code == ASHIFTRT || first_code == ROTATE
+ && (first_code == ASHIFTRT || first_code == LSHIFTRT
+ || first_code == ROTATE
|| code == ROTATE)))
break;
}
/* We need to determine what mode to do the shift in. If the shift is
- a ASHIFTRT or ROTATE, we must always do it in the mode it was originally
- done in. Otherwise, we can do it in MODE, the widest mode encountered.
- The code we care about is that of the shift that will actually be done,
- not the shift that was originally requested. */
- shift_mode = (code == ASHIFTRT || code == ROTATE ? result_mode : mode);
+ a right shift or ROTATE, we must always do it in the mode it was
+ originally done in. Otherwise, we can do it in MODE, the widest mode
+ encountered. The code we care about is that of the shift that will
+ actually be done, not the shift that was originally requested. */
+ shift_mode
+ = (code == ASHIFTRT || code == LSHIFTRT || code == ROTATE
+ ? result_mode : mode);
/* We have now finished analyzing the shift. The result should be
a shift of type CODE with SHIFT_MODE shifting VAROP COUNT places. If
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)
+recog_for_combine (pnewpat, insn, pnotes, padded_scratches)
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);
}
== GET_MODE (SUBREG_REG (inner_op1)))
&& (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (op0)))
<= HOST_BITS_PER_WIDE_INT)
- && (0 == (~c0) & nonzero_bits (SUBREG_REG (inner_op0),
- GET_MODE (SUBREG_REG (op0))))
- && (0 == (~c1) & nonzero_bits (SUBREG_REG (inner_op1),
- GET_MODE (SUBREG_REG (inner_op1)))))
+ && (0 == ((~c0) & nonzero_bits (SUBREG_REG (inner_op0),
+ GET_MODE (SUBREG_REG (op0)))))
+ && (0 == ((~c1) & nonzero_bits (SUBREG_REG (inner_op1),
+ GET_MODE (SUBREG_REG (inner_op1))))))
{
op0 = SUBREG_REG (inner_op0);
op1 = SUBREG_REG (inner_op1);
/* If we are extracting a single bit from a variable position in
a constant that has only a single bit set and are comparing it
with zero, we can convert this into an equality comparison
- between the position and the location of the single bit. We can't
- do this if bit endian and we don't have an extzv since we then
- can't know what mode to use for the endianness adjustment. */
+ between the position and the location of the single bit. */
if (GET_CODE (XEXP (op0, 0)) == CONST_INT
&& XEXP (op0, 1) == const1_rtx
&& equality_comparison_p && const_op == 0
- && (i = exact_log2 (INTVAL (XEXP (op0, 0)))) >= 0
- && (! BITS_BIG_ENDIAN
-#ifdef HAVE_extzv
- || HAVE_extzv
-#endif
- ))
+ && (i = exact_log2 (INTVAL (XEXP (op0, 0)))) >= 0)
{
-#ifdef HAVE_extzv
if (BITS_BIG_ENDIAN)
+#ifdef HAVE_extzv
i = (GET_MODE_BITSIZE
(insn_operand_mode[(int) CODE_FOR_extzv][1]) - 1 - i);
+#else
+ i = BITS_PER_WORD - 1 - i;
#endif
op0 = XEXP (op0, 2);
case SUBREG:
/* Check for the case where we are comparing A - C1 with C2,
- both constants are smaller than 1/2 the maxium positive
+ both constants are smaller than 1/2 the maximum positive
value in MODE, and the comparison is equality or unsigned.
In that case, if A is either zero-extended to MODE or has
sufficient sign bits so that the high-order bit in MODE
This does not work if there exists an instruction which is temporarily
not on the insn chain. */
- if (INSN_CUID (reg_last_set[regno]) >= subst_low_cuid && ! subst_prev_insn)
+ if (INSN_CUID (reg_last_set[regno]) >= subst_low_cuid)
{
rtx insn, set;
+ /* We can not do anything useful in this case, because there is
+ an instruction which is not on the insn chain. */
+ if (subst_prev_insn)
+ return 0;
+
/* Skip over USE insns. They are not useful here, and they may have
been made by combine, in which case they do not have a INSN_CUID
value. We can't use prev_real_insn, because that would incorrectly
value = SET_SRC (set);
/* Make sure that VALUE doesn't reference X. Replace any
- expliit references with a CLOBBER. If there are any remaining
+ explicit references with a CLOBBER. If there are any remaining
references (rare), don't use the value. */
if (reg_mentioned_p (x, value))
/* Function called via note_stores from reg_dead_at_p.
- If DEST is within [reg_dead_rengno, reg_dead_endregno), set
+ If DEST is within [reg_dead_regno, reg_dead_endregno), set
reg_dead_flag to 1 if X is a CLOBBER and to -1 it is a SET. */
static void
/* Scan backwards until we find a REG_DEAD note, SET, CLOBBER, label, or
beginning of function. */
- for (; insn && GET_CODE (insn) != CODE_LABEL;
+ for (; insn && GET_CODE (insn) != CODE_LABEL && GET_CODE (insn) != BARRIER;
insn = prev_nonnote_insn (insn))
{
note_stores (PATTERN (insn), reg_dead_at_p_1);
gen_rtx (REG, reg_raw_mode[i], i),
REG_NOTES (where_dead));
}
+ /* If we didn't find any note, and we have a multi-reg hard
+ register, then to be safe we must check for REG_DEAD notes
+ for each register other than the first. They could have
+ their own REG_DEAD notes lying around. */
+ else if (note == 0 && regno < FIRST_PSEUDO_REGISTER
+ && HARD_REGNO_NREGS (regno, GET_MODE (x)) > 1)
+ {
+ int ourend = regno + HARD_REGNO_NREGS (regno, GET_MODE (x));
+ int i;
+ rtx oldnotes = 0;
+
+ for (i = regno + 1; i < ourend; i++)
+ move_deaths (gen_rtx (REG, reg_raw_mode[i], i),
+ from_cuid, to_insn, &oldnotes);
+ }
if (note != 0 && GET_MODE (XEXP (note, 0)) == GET_MODE (x))
{
modified the register. */
if (set != 0 && ! side_effects_p (SET_SRC (set))
- && rtx_equal_p (XEXP (note, 0), SET_DEST (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)))))
{
/* Move the notes and links of TEM elsewhere.
This might delete other dead insns recursively.
&& find_reg_fusage (tem, USE, XEXP (note, 0))))
{
place = tem;
+
+ /* If we are doing a 3->2 combination, and we have a
+ register which formerly died in i3 and was not used
+ by i2, which now no longer dies in i3 and is used in
+ i2 but does not die in i2, and place is between i2
+ and i3, then we may need to move a link from place to
+ i2. */
+ if (i2 && INSN_UID (place) <= max_uid_cuid
+ && INSN_CUID (place) > INSN_CUID (i2)
+ && from_insn && INSN_CUID (from_insn) > INSN_CUID (i2)
+ && reg_referenced_p (XEXP (note, 0), PATTERN (i2)))
+ {
+ rtx links = LOG_LINKS (place);
+ LOG_LINKS (place) = 0;
+ distribute_links (links);
+ }
break;
}
}
}
}
\f
+/* Compute INSN_CUID for INSN, which is an insn made by combine. */
+
+static int
+insn_cuid (insn)
+ rtx insn;
+{
+ while (insn != 0 && INSN_UID (insn) > max_uid_cuid
+ && GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == USE)
+ insn = NEXT_INSN (insn);
+
+ if (INSN_UID (insn) > max_uid_cuid)
+ abort ();
+
+ return INSN_CUID (insn);
+}
+\f
void
dump_combine_stats (file)
FILE *file;