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. */
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;
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 (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')
+ {
+ 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')
{
- /* 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))))
+ 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);
}
}
&& 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);
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