#ifdef OVERLAPPING_REGNO_P
#define FIXED_REGNO_P(N) \
(((N) == FRAME_POINTER_REGNUM || (N) == HARD_FRAME_POINTER_REGNUM \
- || fixed_regs[N]) \
+ || fixed_regs[N] || global_regs[N]) \
&& ! OVERLAPPING_REGNO_P ((N)))
#else
#define FIXED_REGNO_P(N) \
((N) == FRAME_POINTER_REGNUM || (N) == HARD_FRAME_POINTER_REGNUM \
- || fixed_regs[N])
+ || fixed_regs[N] || global_regs[N])
#endif
/* Compute cost of X, as stored in the `cost' field of a table_elt. Fixed
of 0. Next come pseudos with a cost of one and other hard registers with
a cost of 2. Aside from these special cases, call `rtx_cost'. */
-#define CHEAP_REG(N) \
+#define CHEAP_REGNO(N) \
((N) == FRAME_POINTER_REGNUM || (N) == HARD_FRAME_POINTER_REGNUM \
|| (N) == STACK_POINTER_REGNUM || (N) == ARG_POINTER_REGNUM \
|| ((N) >= FIRST_VIRTUAL_REGISTER && (N) <= LAST_VIRTUAL_REGISTER) \
|| ((N) < FIRST_PSEUDO_REGISTER \
&& FIXED_REGNO_P (N) && REGNO_REG_CLASS (N) != NO_REGS))
+/* A register is cheap if it is a user variable assigned to the register
+ or if its register number always corresponds to a cheap register. */
+
+#define CHEAP_REG(N) \
+ ((REG_USERVAR_P (N) && REGNO (N) < FIRST_PSEUDO_REGISTER) \
+ || CHEAP_REGNO (REGNO (N)))
+
#define COST(X) \
(GET_CODE (X) == REG \
- ? (CHEAP_REG (REGNO (X)) ? 0 \
+ ? (CHEAP_REG (X) ? 0 \
: REGNO (X) >= FIRST_PSEUDO_REGISTER ? 1 \
: 2) \
: rtx_cost (X, SET) * 2)
enum machine_mode));
static void merge_equiv_classes PROTO((struct table_elt *,
struct table_elt *));
-static void invalidate PROTO((rtx));
+static void invalidate PROTO((rtx, enum machine_mode));
static void remove_invalid_refs PROTO((int));
static void rehash_using_reg PROTO((rtx));
static void invalidate_memory PROTO((struct write_data *));
switch (code)
{
case REG:
- return ! CHEAP_REG (REGNO (x));
+ return ! CHEAP_REG (x);
case SUBREG:
/* If we can't tie these modes, make this expensive. The larger
next_qty = max_reg;
- bzero (reg_tick, max_reg * sizeof (int));
+ bzero ((char *) reg_tick, max_reg * sizeof (int));
- bcopy (all_minus_one, reg_in_table, max_reg * sizeof (int));
- bcopy (consec_ints, reg_qty, max_reg * sizeof (int));
+ bcopy ((char *) all_minus_one, (char *) reg_in_table,
+ max_reg * sizeof (int));
+ bcopy ((char *) consec_ints, (char *) reg_qty, max_reg * sizeof (int));
CLEAR_HARD_REG_SET (hard_regs_in_table);
/* The per-quantity values used to be initialized here, but it is
}
}
- bzero (table, sizeof table);
+ bzero ((char *) table, sizeof table);
prev_insn = 0;
(because, when a memory reference with a varying address is stored in,
all memory references are removed by invalidate_memory
so specific invalidation is superfluous).
+ FULL_MODE, if not VOIDmode, indicates that this much should be invalidated
+ instead of just the amount indicated by the mode of X. This is only used
+ for bitfield stores into memory.
A nonvarying address may be just a register or just
a symbol reference, or it may be either of those plus
a numeric offset. */
static void
-invalidate (x)
+invalidate (x, full_mode)
rtx x;
+ enum machine_mode full_mode;
{
register int i;
register struct table_elt *p;
{
if (GET_CODE (SUBREG_REG (x)) != REG)
abort ();
- invalidate (SUBREG_REG (x));
+ invalidate (SUBREG_REG (x), VOIDmode);
return;
}
if (GET_CODE (x) != MEM)
abort ();
- set_nonvarying_address_components (XEXP (x, 0), GET_MODE_SIZE (GET_MODE (x)),
+ if (full_mode == VOIDmode)
+ full_mode = GET_MODE (x);
+
+ set_nonvarying_address_components (XEXP (x, 0), GET_MODE_SIZE (full_mode),
&base, &start, &end);
for (i = 0; i < NBUCKETS; i++)
if (reg_tick[regno] >= 0)
reg_tick[regno]++;
- in_table |= TEST_HARD_REG_BIT (hard_regs_in_table, regno);
+ in_table |= (TEST_HARD_REG_BIT (hard_regs_in_table, regno) != 0);
}
/* In the case where we have no call-clobbered hard registers in the
case SYMBOL_REF:
hash
- += ((unsigned) SYMBOL_REF << 7) + (unsigned HOST_WIDE_INT) XEXP (x, 0);
+ += ((unsigned) SYMBOL_REF << 7) + (unsigned HOST_WIDE_INT) XSTR (x, 0);
return hash;
case MEM:
return INTVAL (x) == INTVAL (y);
case LABEL_REF:
- case SYMBOL_REF:
return XEXP (x, 0) == XEXP (y, 0);
+ case SYMBOL_REF:
+ return XSTR (x, 0) == XSTR (y, 0);
+
case REG:
{
int regno = REGNO (y);
set PBASE, PSTART, and PEND which correspond to the base of the address,
the starting offset, and ending offset respectively.
- ADDR is known to be a nonvarying address.
+ ADDR is known to be a nonvarying address. */
- cse_address_varies_p returns zero for nonvarying addresses. */
+/* ??? Despite what the comments say, this function is in fact frequently
+ passed varying addresses. This does not appear to cause any problems. */
static void
set_nonvarying_address_components (addr, size, pbase, pstart, pend)
HOST_WIDE_INT *pstart, *pend;
{
rtx base;
- int start, end;
+ HOST_WIDE_INT start, end;
base = addr;
start = 0;
base = qty_const[reg_qty[REGNO (XEXP (base, 0))]];
}
- /* By definition, operand1 of a LO_SUM is the associated constant
- address. Use the associated constant address as the base instead. */
- if (GET_CODE (base) == LO_SUM)
- base = XEXP (base, 1);
+ /* Handle everything that we can find inside an address that has been
+ viewed as constant. */
+
+ while (1)
+ {
+ /* If no part of this switch does a "continue", the code outside
+ will exit this loop. */
+
+ switch (GET_CODE (base))
+ {
+ case LO_SUM:
+ /* By definition, operand1 of a LO_SUM is the associated constant
+ address. Use the associated constant address as the base
+ instead. */
+ base = XEXP (base, 1);
+ continue;
+
+ case CONST:
+ /* Strip off CONST. */
+ base = XEXP (base, 0);
+ continue;
+
+ case PLUS:
+ if (GET_CODE (XEXP (base, 1)) == CONST_INT)
+ {
+ start += INTVAL (XEXP (base, 1));
+ base = XEXP (base, 0);
+ continue;
+ }
+ break;
+
+ case AND:
+ /* Handle the case of an AND which is the negative of a power of
+ two. This is used to represent unaligned memory operations. */
+ if (GET_CODE (XEXP (base, 1)) == CONST_INT
+ && exact_log2 (- INTVAL (XEXP (base, 1))) > 0)
+ {
+ set_nonvarying_address_components (XEXP (base, 0), size,
+ pbase, pstart, pend);
+
+ /* Assume the worst misalignment. START is affected, but not
+ END, so compensate but adjusting SIZE. Don't lose any
+ constant we already had. */
+
+ size = *pend - *pstart - INTVAL (XEXP (base, 1)) - 1;
+ start += *pstart - INTVAL (XEXP (base, 1)) - 1;
+ base = *pbase;
+ }
+ break;
+ }
- /* Strip off CONST. */
- if (GET_CODE (base) == CONST)
- base = XEXP (base, 0);
+ break;
+ }
- if (GET_CODE (base) == PLUS
- && GET_CODE (XEXP (base, 1)) == CONST_INT)
+ if (GET_CODE (base) == CONST_INT)
{
- start += INTVAL (XEXP (base, 1));
- base = XEXP (base, 0);
+ start += INTVAL (base);
+ base = const0_rtx;
}
end = start + size;
register enum rtx_code code;
register char *fmt;
- if (GET_CODE (base) == CONST_INT)
- {
- start += INTVAL (base);
- end += INTVAL (base);
- base = const0_rtx;
- }
-
repeat:
if (x == 0)
return 0;
check the wrong mode (input vs. output) for a conversion operation,
such as FIX. At some point, this should be simplified. */
-#if !defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC)
- if (code == FLOAT && GET_CODE (op) == CONST_INT)
- {
- REAL_VALUE_TYPE d;
+#if !defined(REAL_IS_NOT_DOUBLE) || defined(REAL_ARITHMETIC)
-#ifdef REAL_ARITHMETIC
- REAL_VALUE_FROM_INT (d, INTVAL (op), INTVAL (op) < 0 ? ~0 : 0);
-#else
- d = (double) INTVAL (op);
-#endif
- return CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
- }
- else if (code == UNSIGNED_FLOAT && GET_CODE (op) == CONST_INT)
+ if (code == FLOAT && GET_MODE (op) == VOIDmode
+ && (GET_CODE (op) == CONST_DOUBLE || GET_CODE (op) == CONST_INT))
{
+ HOST_WIDE_INT hv, lv;
REAL_VALUE_TYPE d;
-#ifdef REAL_ARITHMETIC
- REAL_VALUE_FROM_INT (d, INTVAL (op), 0);
-#else
- d = (double) (unsigned int) INTVAL (op);
-#endif
- return CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
- }
-
- else if (code == FLOAT && GET_CODE (op) == CONST_DOUBLE
- && GET_MODE (op) == VOIDmode)
- {
- REAL_VALUE_TYPE d;
+ if (GET_CODE (op) == CONST_INT)
+ lv = INTVAL (op), hv = INTVAL (op) < 0 ? -1 : 0;
+ else
+ lv = CONST_DOUBLE_LOW (op), hv = CONST_DOUBLE_HIGH (op);
#ifdef REAL_ARITHMETIC
- REAL_VALUE_FROM_INT (d, CONST_DOUBLE_LOW (op), CONST_DOUBLE_HIGH (op));
+ REAL_VALUE_FROM_INT (d, lv, hv);
#else
- if (CONST_DOUBLE_HIGH (op) < 0)
+ if (hv < 0)
{
- d = (double) (~ CONST_DOUBLE_HIGH (op));
+ d = (double) (~ hv);
d *= ((double) ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2))
* (double) ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2)));
- d += (double) (unsigned HOST_WIDE_INT) (~ CONST_DOUBLE_LOW (op));
+ d += (double) (unsigned HOST_WIDE_INT) (~ lv);
d = (- d - 1.0);
}
else
{
- d = (double) CONST_DOUBLE_HIGH (op);
+ d = (double) hv;
d *= ((double) ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2))
* (double) ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2)));
- d += (double) (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (op);
+ d += (double) (unsigned HOST_WIDE_INT) lv;
}
#endif /* REAL_ARITHMETIC */
+
return CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
}
- else if (code == UNSIGNED_FLOAT && GET_CODE (op) == CONST_DOUBLE
- && GET_MODE (op) == VOIDmode)
+ else if (code == UNSIGNED_FLOAT && GET_MODE (op) == VOIDmode
+ && (GET_CODE (op) == CONST_DOUBLE || GET_CODE (op) == CONST_INT))
{
+ HOST_WIDE_INT hv, lv;
REAL_VALUE_TYPE d;
+ if (GET_CODE (op) == CONST_INT)
+ lv = INTVAL (op), hv = INTVAL (op) < 0 ? -1 : 0;
+ else
+ lv = CONST_DOUBLE_LOW (op), hv = CONST_DOUBLE_HIGH (op);
+
+ if (GET_MODE_BITSIZE (op_mode) >= HOST_BITS_PER_WIDE_INT * 2)
+ ;
+ else
+ hv = 0, lv &= GET_MODE_MASK (op_mode);
+
#ifdef REAL_ARITHMETIC
- REAL_VALUE_FROM_UNSIGNED_INT (d, CONST_DOUBLE_LOW (op),
- CONST_DOUBLE_HIGH (op));
+ REAL_VALUE_FROM_UNSIGNED_INT (d, lv, hv);
#else
- d = (double) CONST_DOUBLE_HIGH (op);
+
+ d = (double) (unsigned HOST_WIDE_INT) hv;
d *= ((double) ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2))
* (double) ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2)));
- d += (double) (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (op);
+ d += (double) (unsigned HOST_WIDE_INT) lv;
#endif /* REAL_ARITHMETIC */
+
return CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
}
#endif
/* We can do some operations on integer CONST_DOUBLEs. Also allow
for a DImode operation on a CONST_INT. */
- else if (GET_MODE (op) == VOIDmode && width == HOST_BITS_PER_INT * 2
+ else if (GET_MODE (op) == VOIDmode && width <= HOST_BITS_PER_INT * 2
&& (GET_CODE (op) == CONST_DOUBLE || GET_CODE (op) == CONST_INT))
{
HOST_WIDE_INT l1, h1, lv, hv;
break;
case TRUNCATE:
- if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
- return GEN_INT (l1 & GET_MODE_MASK (mode));
- else
- return 0;
+ /* This is just a change-of-mode, so do nothing. */
break;
case ZERO_EXTEND:
abort ();
}
- x = immed_real_const_1 (d, mode);
+ x = CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
set_float_handler (NULL_PTR);
return x;
}
- else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE_CLASS (mode) == MODE_INT
+
+ else if (GET_CODE (op) == CONST_DOUBLE
+ && GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT
+ && GET_MODE_CLASS (mode) == MODE_INT
&& width <= HOST_BITS_PER_WIDE_INT && width > 0)
{
REAL_VALUE_TYPE d;
}
#endif
- set_float_handler (NULL_PTR);
value = real_value_truncate (mode, value);
- return immed_real_const_1 (value, mode);
+ set_float_handler (NULL_PTR);
+ return CONST_DOUBLE_FROM_REAL_VALUE (value, mode);
}
#endif /* not REAL_IS_NOT_DOUBLE, or REAL_ARITHMETIC */
break;
case LSHIFTRT: case ASHIFTRT:
- case ASHIFT: case LSHIFT:
+ case ASHIFT:
case ROTATE: case ROTATERT:
#ifdef SHIFT_COUNT_TRUNCATED
if (SHIFT_COUNT_TRUNCATED)
if (code == LSHIFTRT || code == ASHIFTRT)
rshift_double (l1, h1, l2, GET_MODE_BITSIZE (mode), &lv, &hv,
code == ASHIFTRT);
- else if (code == ASHIFT || code == LSHIFT)
- lshift_double (l1, h1, l2, GET_MODE_BITSIZE (mode), &lv, &hv,
- code == ASHIFT);
+ else if (code == ASHIFT)
+ lshift_double (l1, h1, l2, GET_MODE_BITSIZE (mode), &lv, &hv, 1);
else if (code == ROTATE)
lrotate_double (l1, h1, l2, GET_MODE_BITSIZE (mode), &lv, &hv);
else /* code == ROTATERT */
return tem;
/* Don't let a relocatable value get a negative coeff. */
- if (GET_CODE (op1) == CONST_INT && GET_MODE (op1) != VOIDmode)
+ if (GET_CODE (op1) == CONST_INT && GET_MODE (op0) != VOIDmode)
return plus_constant (op0, - INTVAL (op1));
break;
/* ... fall through ... */
- case LSHIFT:
case ASHIFT:
case ASHIFTRT:
case LSHIFTRT:
break;
case ASHIFT:
- case LSHIFT:
if (arg1 < 0)
return 0;
int first = 1, negate = 0, changed;
int i, j;
- bzero (ops, sizeof ops);
+ bzero ((char *) ops, sizeof ops);
/* Set up the two operands and then expand them until nothing has been
changed. If we run out of room in our array, give up; this should
be zero, but a SYMBOL_REF can due to #pragma weak. */
if (((NONZERO_BASE_PLUS_P (op0) && op1 == const0_rtx)
|| GET_CODE (op0) == LABEL_REF)
-#if FRAME_POINTER_REGNO != ARG_POINTGER_REGNO
+#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
/* On some machines, the ap reg can be 0 sometimes. */
&& op0 != arg_pointer_rtx
#endif
case NE:
if (((NONZERO_BASE_PLUS_P (op0) && op1 == const0_rtx)
|| GET_CODE (op0) == LABEL_REF)
-#if FRAME_POINTER_REGNO != ARG_POINTER_REGNO
+#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
&& op0 != arg_pointer_rtx
#endif
)
to compute that in SImode, because a 32-bit shift
in SImode is unpredictable. We know the value is 0. */
if (op0 && op1
- && (GET_CODE (elt->exp) == ASHIFT
- || GET_CODE (elt->exp) == LSHIFT)
+ && GET_CODE (elt->exp) == ASHIFT
&& GET_CODE (op1) == CONST_INT
&& INTVAL (op1) >= GET_MODE_BITSIZE (mode))
{
if (GET_MODE (table) != Pmode)
new = gen_rtx (TRUNCATE, GET_MODE (table), new);
- return new;
+ /* Indicate this is a constant. This isn't a
+ valid form of CONST, but it will only be used
+ to fold the next insns and then discarded, so
+ it should be safe. */
+ return gen_rtx (CONST, GET_MODE (new), new);
}
}
}
switch (GET_RTX_CLASS (code))
{
case '1':
- /* We can't simplify extension ops unless we know the original mode. */
- if ((code == ZERO_EXTEND || code == SIGN_EXTEND)
- && mode_arg0 == VOIDmode)
- break;
- new = simplify_unary_operation (code, mode,
- const_arg0 ? const_arg0 : folded_arg0,
- mode_arg0);
+ {
+ int is_const = 0;
+
+ /* We can't simplify extension ops unless we know the
+ original mode. */
+ if ((code == ZERO_EXTEND || code == SIGN_EXTEND)
+ && mode_arg0 == VOIDmode)
+ break;
+
+ /* If we had a CONST, strip it off and put it back later if we
+ fold. */
+ if (const_arg0 != 0 && GET_CODE (const_arg0) == CONST)
+ is_const = 1, const_arg0 = XEXP (const_arg0, 0);
+
+ new = simplify_unary_operation (code, mode,
+ const_arg0 ? const_arg0 : folded_arg0,
+ mode_arg0);
+ if (new != 0 && is_const)
+ new = gen_rtx (CONST, mode, new);
+ }
break;
case '<':
#ifdef FLOAT_STORE_FLAG_VALUE
if (GET_MODE_CLASS (mode) == MODE_FLOAT)
{
- true = immed_real_const_1 (FLOAT_STORE_FLAG_VALUE, mode);
+ true = CONST_DOUBLE_FROM_REAL_VALUE (FLOAT_STORE_FLAG_VALUE,
+ mode);
false = CONST0_RTX (mode);
}
#endif
#ifdef FLOAT_STORE_FLAG_VALUE
if (GET_MODE_CLASS (mode) == MODE_FLOAT)
{
- true = immed_real_const_1 (FLOAT_STORE_FLAG_VALUE, mode);
+ true = CONST_DOUBLE_FROM_REAL_VALUE (FLOAT_STORE_FLAG_VALUE,
+ mode);
false = CONST0_RTX (mode);
}
#endif
#ifdef FLOAT_STORE_FLAG_VALUE
if (new != 0 && GET_MODE_CLASS (mode) == MODE_FLOAT)
new = ((new == const0_rtx) ? CONST0_RTX (mode)
- : immed_real_const_1 (FLOAT_STORE_FLAG_VALUE, mode));
+ : CONST_DOUBLE_FROM_REAL_VALUE (FLOAT_STORE_FLAG_VALUE, mode));
#endif
break;
ADDR_DIFF_VEC table. */
if (const_arg1 && GET_CODE (const_arg1) == LABEL_REF)
{
- rtx y = lookup_as_function (folded_arg0, MINUS);
+ rtx y
+ = GET_CODE (folded_arg0) == MINUS ? folded_arg0
+ : lookup_as_function (folded_arg0, MINUS);
if (y != 0 && GET_CODE (XEXP (y, 1)) == LABEL_REF
&& XEXP (XEXP (y, 1), 0) == XEXP (const_arg1, 0))
return XEXP (y, 0);
+
+ /* Now try for a CONST of a MINUS like the above. */
+ if ((y = (GET_CODE (folded_arg0) == CONST ? folded_arg0
+ : lookup_as_function (folded_arg0, CONST))) != 0
+ && GET_CODE (XEXP (y, 0)) == MINUS
+ && GET_CODE (XEXP (XEXP (y, 0), 1)) == LABEL_REF
+ && XEXP (XEXP (XEXP (y, 0),1), 0) == XEXP (const_arg1, 0))
+ return XEXP (XEXP (y, 0), 0);
+ }
+
+ /* Likewise if the operands are in the other order. */
+ if (const_arg0 && GET_CODE (const_arg0) == LABEL_REF)
+ {
+ rtx y
+ = GET_CODE (folded_arg1) == MINUS ? folded_arg1
+ : lookup_as_function (folded_arg1, MINUS);
+
+ if (y != 0 && GET_CODE (XEXP (y, 1)) == LABEL_REF
+ && XEXP (XEXP (y, 1), 0) == XEXP (const_arg0, 0))
+ return XEXP (y, 0);
+
+ /* Now try for a CONST of a MINUS like the above. */
+ if ((y = (GET_CODE (folded_arg1) == CONST ? folded_arg1
+ : lookup_as_function (folded_arg1, CONST))) != 0
+ && GET_CODE (XEXP (y, 0)) == MINUS
+ && GET_CODE (XEXP (XEXP (y, 0), 1)) == LABEL_REF
+ && XEXP (XEXP (XEXP (y, 0),1), 0) == XEXP (const_arg0, 0))
+ return XEXP (XEXP (y, 0), 0);
}
/* If second operand is a register equivalent to a negative
op0_elt = lookup (op0, op0_hash, mode);
op1_elt = lookup (op1, op1_hash, mode);
+ /* If both operands are already equivalent or if they are not in the
+ table but are identical, do nothing. */
+ if ((op0_elt != 0 && op1_elt != 0
+ && op0_elt->first_same_value == op1_elt->first_same_value)
+ || op0 == op1 || rtx_equal_p (op0, op1))
+ return;
+
/* If we aren't setting two things equal all we can do is save this
comparison. Similarly if this is floating-point. In the latter
case, OP1 might be zero and both -0.0 and 0.0 are equal to it.
int in_libcall_block;
{
register rtx x = PATTERN (insn);
- rtx tem;
register int i;
+ rtx tem;
register int n_sets = 0;
/* Records what this insn does to set CC0. */
Also determine whether there is a CLOBBER that invalidates
all memory references, or all references at varying addresses. */
+ if (GET_CODE (insn) == CALL_INSN)
+ {
+ for (tem = CALL_INSN_FUNCTION_USAGE (insn); tem; tem = XEXP (tem, 1))
+ if (GET_CODE (XEXP (tem, 0)) == CLOBBER)
+ invalidate (SET_DEST (XEXP (tem, 0)), VOIDmode);
+ }
+
if (GET_CODE (x) == SET)
{
sets = (struct set *) alloca (sizeof (struct set));
canon_reg (SET_SRC (x), insn);
apply_change_group ();
fold_rtx (SET_SRC (x), insn);
- invalidate (SET_DEST (x));
+ invalidate (SET_DEST (x), VOIDmode);
}
else
n_sets = 1;
if (GET_CODE (clobbered) == REG
|| GET_CODE (clobbered) == SUBREG)
- invalidate (clobbered);
+ invalidate (clobbered, VOIDmode);
else if (GET_CODE (clobbered) == STRICT_LOW_PART
|| GET_CODE (clobbered) == ZERO_EXTRACT)
- invalidate (XEXP (clobbered, 0));
+ invalidate (XEXP (clobbered, 0), GET_MODE (clobbered));
}
}
canon_reg (SET_SRC (y), insn);
apply_change_group ();
fold_rtx (SET_SRC (y), insn);
- invalidate (SET_DEST (y));
+ invalidate (SET_DEST (y), VOIDmode);
}
else if (SET_DEST (y) == pc_rtx
&& GET_CODE (SET_SRC (y)) == LABEL_REF)
fold_rtx (x, insn);
}
- if (n_sets == 1 && REG_NOTES (insn) != 0)
- {
- /* Store the equivalent value in SRC_EQV, if different. */
- rtx tem = find_reg_note (insn, REG_EQUAL, NULL_RTX);
-
- if (tem && ! rtx_equal_p (XEXP (tem, 0), SET_SRC (sets[0].rtl)))
- src_eqv = canon_reg (XEXP (tem, 0), NULL_RTX);
- }
+ /* Store the equivalent value in SRC_EQV, if different, or if the DEST
+ is a STRICT_LOW_PART. The latter condition is necessary because SRC_EQV
+ is handled specially for this case, and if it isn't set, then there will
+ be no equivalence for the destinatation. */
+ if (n_sets == 1 && REG_NOTES (insn) != 0
+ && (tem = find_reg_note (insn, REG_EQUAL, NULL_RTX)) != 0
+ && (! rtx_equal_p (XEXP (tem, 0), SET_SRC (sets[0].rtl))
+ || GET_CODE (SET_DEST (sets[0].rtl)) == STRICT_LOW_PART))
+ src_eqv = canon_reg (XEXP (tem, 0), NULL_RTX);
/* Canonicalize sources and addresses of destinations.
We do this in a separate pass to avoid problems when a MATCH_DUP is
if (n_sets == 1 && src_const && GET_CODE (dest) == REG
&& GET_CODE (src_const) != REG)
{
- rtx tem = find_reg_note (insn, REG_EQUAL, NULL_RTX);
+ tem = find_reg_note (insn, REG_EQUAL, NULL_RTX);
/* Record the actual constant value in a REG_EQUAL note, making
a new one if one does not already exist. */
{
if (GET_CODE (dest) == REG || GET_CODE (dest) == SUBREG
|| GET_CODE (dest) == MEM)
- invalidate (dest);
+ invalidate (dest, VOIDmode);
else if (GET_CODE (dest) == STRICT_LOW_PART
|| GET_CODE (dest) == ZERO_EXTRACT)
- invalidate (XEXP (dest, 0));
+ invalidate (XEXP (dest, 0), GET_MODE (dest));
sets[i].rtl = 0;
}
for (i = 0; i < n_sets; i++)
if (sets[i].rtl)
{
- register rtx dest = sets[i].inner_dest;
+ /* We can't use the inner dest, because the mode associated with
+ a ZERO_EXTRACT is significant. */
+ register rtx dest = SET_DEST (sets[i].rtl);
/* Needed for registers to remove the register from its
previous quantity's chain.
Needed for memory if this is a nonvarying address, unless
we have just done an invalidate_memory that covers even those. */
if (GET_CODE (dest) == REG || GET_CODE (dest) == SUBREG
- || (! writes_memory.all && ! cse_rtx_addr_varies_p (dest)))
- invalidate (dest);
+ || (GET_CODE (dest) == MEM && ! writes_memory.all
+ && ! cse_rtx_addr_varies_p (dest)))
+ invalidate (dest, VOIDmode);
else if (GET_CODE (dest) == STRICT_LOW_PART
|| GET_CODE (dest) == ZERO_EXTRACT)
- invalidate (XEXP (dest, 0));
+ invalidate (XEXP (dest, 0), GET_MODE (dest));
}
/* Make sure registers mentioned in destinations
already entered SRC and DEST of the SET in the table. */
if (GET_CODE (dest) == SUBREG
- && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest))) / UNITS_PER_WORD
- == GET_MODE_SIZE (GET_MODE (dest)) / UNITS_PER_WORD)
+ && (((GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest))) - 1)
+ / UNITS_PER_WORD)
+ == (GET_MODE_SIZE (GET_MODE (dest)) - 1)/ UNITS_PER_WORD)
&& (GET_MODE_SIZE (GET_MODE (dest))
>= GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest))))
&& sets[i].src_elt != 0)
/* This should be *very* rare. */
if (TEST_HARD_REG_BIT (hard_regs_in_table, STACK_POINTER_REGNUM))
- invalidate (stack_pointer_rtx);
+ invalidate (stack_pointer_rtx, VOIDmode);
}
if (GET_CODE (x) == CLOBBER)
{
if (GET_CODE (ref) == REG || GET_CODE (ref) == SUBREG
|| (GET_CODE (ref) == MEM && ! w->all))
- invalidate (ref);
+ invalidate (ref, VOIDmode);
else if (GET_CODE (ref) == STRICT_LOW_PART
|| GET_CODE (ref) == ZERO_EXTRACT)
- invalidate (XEXP (ref, 0));
+ invalidate (XEXP (ref, 0), GET_MODE (ref));
}
}
else if (GET_CODE (x) == PARALLEL)
{
if (GET_CODE (ref) == REG || GET_CODE (ref) == SUBREG
|| (GET_CODE (ref) == MEM && !w->all))
- invalidate (ref);
+ invalidate (ref, VOIDmode);
else if (GET_CODE (ref) == STRICT_LOW_PART
|| GET_CODE (ref) == ZERO_EXTRACT)
- invalidate (XEXP (ref, 0));
+ invalidate (XEXP (ref, 0), GET_MODE (ref));
}
}
}
for (p = last_jump_equiv_class->first_same_value; p;
p = p->next_same_value)
if (GET_CODE (p->exp) == MEM || GET_CODE (p->exp) == REG
- || GET_CODE (p->exp) == SUBREG)
- invalidate (p->exp);
+ || (GET_CODE (p->exp) == SUBREG
+ && GET_CODE (SUBREG_REG (p->exp)) == REG))
+ invalidate (p->exp, VOIDmode);
else if (GET_CODE (p->exp) == STRICT_LOW_PART
|| GET_CODE (p->exp) == ZERO_EXTRACT)
- invalidate (XEXP (p->exp, 0));
+ invalidate (XEXP (p->exp, 0), GET_MODE (p->exp));
/* Process insns starting after LOOP_START until we hit a CALL_INSN or
a CODE_LABEL (we could handle a CALL_INSN, but it isn't worth it).
if (GET_CODE (dest) == REG || GET_CODE (dest) == SUBREG
|| (! skipped_writes_memory.all && ! cse_rtx_addr_varies_p (dest)))
- invalidate (dest);
+ invalidate (dest, VOIDmode);
else if (GET_CODE (dest) == STRICT_LOW_PART
|| GET_CODE (dest) == ZERO_EXTRACT)
- invalidate (XEXP (dest, 0));
+ invalidate (XEXP (dest, 0), GET_MODE (dest));
}
/* Invalidate all insns from START up to the end of the function or the
if (GET_CODE (SET_DEST (x)) == REG || GET_CODE (SET_DEST (x)) == SUBREG
|| (GET_CODE (SET_DEST (x)) == MEM && ! writes_memory.all
&& ! cse_rtx_addr_varies_p (SET_DEST (x))))
- invalidate (SET_DEST (x));
+ invalidate (SET_DEST (x), VOIDmode);
else if (GET_CODE (SET_DEST (x)) == STRICT_LOW_PART
|| GET_CODE (SET_DEST (x)) == ZERO_EXTRACT)
- invalidate (XEXP (SET_DEST (x), 0));
+ invalidate (XEXP (SET_DEST (x), 0), GET_MODE (SET_DEST (x)));
}
\f
/* Find the end of INSN's basic block and return its range,
/* Discard all the free elements of the previous function
since they are allocated in the temporarily obstack. */
- bzero (table, sizeof table);
+ bzero ((char *) table, sizeof table);
free_element_chain = 0;
n_elements_made = 0;
max_uid = get_max_uid ();
uid_cuid = (int *) alloca ((max_uid + 1) * sizeof (int));
- bzero (uid_cuid, (max_uid + 1) * sizeof (int));
+ bzero ((char *) uid_cuid, (max_uid + 1) * sizeof (int));
/* Compute the mapping from uids to cuids.
CUIDs are numbers assigned to insns, like uids,
#if ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
&& ! (i == ARG_POINTER_REGNUM && fixed_regs[i])
#endif
-#ifdef PIC_OFFSET_TABLE_REGNUM
+#if defined (PIC_OFFSET_TABLE_REGNUM) && !defined (PIC_OFFSET_TABLE_REG_CALL_CLOBBERED)
&& ! (i == PIC_OFFSET_TABLE_REGNUM && flag_pic)
#endif
)
rtx dest;
int incr;
{
- enum rtx_code code = GET_CODE (x);
+ enum rtx_code code;
char *fmt;
int i, j;
- switch (code)
+ if (x == 0)
+ return;
+
+ switch (code = GET_CODE (x))
{
case REG:
if (x != dest)
/* Unless we are setting a REG, count everything in SET_DEST. */
if (GET_CODE (SET_DEST (x)) != REG)
count_reg_usage (SET_DEST (x), counts, NULL_RTX, incr);
- count_reg_usage (SET_SRC (x), counts, SET_DEST (x), incr);
+
+ /* If SRC has side-effects, then we can't delete this insn, so the
+ usage of SET_DEST inside SRC counts.
+
+ ??? Strictly-speaking, we might be preserving this insn
+ because some other SET has side-effects, but that's hard
+ to do and can't happen now. */
+ count_reg_usage (SET_SRC (x), counts,
+ side_effects_p (SET_SRC (x)) ? NULL_RTX : SET_DEST (x),
+ incr);
return;
+ case CALL_INSN:
+ count_reg_usage (CALL_INSN_FUNCTION_USAGE (x), counts, NULL_RTX, incr);
+
+ /* ... falls through ... */
case INSN:
case JUMP_INSN:
- case CALL_INSN:
count_reg_usage (PATTERN (x), counts, NULL_RTX, incr);
/* Things used in a REG_EQUAL note aren't dead since loop may try to
use them. */
- if (REG_NOTES (x))
- count_reg_usage (REG_NOTES (x), counts, NULL_RTX, incr);
+ count_reg_usage (REG_NOTES (x), counts, NULL_RTX, incr);
return;
case EXPR_LIST:
case INSN_LIST:
- if (REG_NOTE_KIND (x) == REG_EQUAL)
+ if (REG_NOTE_KIND (x) == REG_EQUAL
+ || GET_CODE (XEXP (x,0)) == USE)
count_reg_usage (XEXP (x, 0), counts, NULL_RTX, incr);
- if (XEXP (x, 1))
- count_reg_usage (XEXP (x, 1), counts, NULL_RTX, incr);
+ count_reg_usage (XEXP (x, 1), counts, NULL_RTX, incr);
return;
}
int in_libcall = 0;
/* First count the number of times each register is used. */
- bzero (counts, sizeof (int) * nreg);
+ bzero ((char *) counts, sizeof (int) * nreg);
for (insn = next_real_insn (insns); insn; insn = next_real_insn (insn))
count_reg_usage (insn, counts, NULL_RTX, 1);