static unsigned canon_hash PROTO((rtx, enum machine_mode));
static unsigned safe_hash PROTO((rtx, enum machine_mode));
static int exp_equiv_p PROTO((rtx, rtx, int, int));
-static void set_nonvarying_address_components PROTO((rtx, int, rtx *,
- HOST_WIDE_INT *,
- HOST_WIDE_INT *));
-static int refers_to_p PROTO((rtx, rtx));
static rtx canon_reg PROTO((rtx, rtx));
static void find_best_addr PROTO((rtx, rtx *));
static enum rtx_code find_comparison_args PROTO((enum rtx_code, rtx *, rtx *,
return 1;
}
\f
-/* Return 1 iff any subexpression of X matches Y.
- Here we do not require that X or Y be valid (for registers referred to)
- for being in the hash table. */
-
-static int
-refers_to_p (x, y)
- rtx x, y;
-{
- register int i;
- register enum rtx_code code;
- register const char *fmt;
-
- repeat:
- if (x == y)
- return 1;
- if (x == 0 || y == 0)
- return 0;
-
- code = GET_CODE (x);
- /* If X as a whole has the same code as Y, they may match.
- If so, return 1. */
- if (code == GET_CODE (y))
- {
- if (exp_equiv_p (x, y, 0, 1))
- return 1;
- }
-
- /* X does not match, so try its subexpressions. */
-
- fmt = GET_RTX_FORMAT (code);
- for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
- if (fmt[i] == 'e')
- {
- if (i == 0)
- {
- x = XEXP (x, 0);
- goto repeat;
- }
- else
- if (refers_to_p (XEXP (x, i), y))
- return 1;
- }
- else if (fmt[i] == 'E')
- {
- int j;
- for (j = 0; j < XVECLEN (x, i); j++)
- if (refers_to_p (XVECEXP (x, i, j), y))
- return 1;
- }
-
- return 0;
-}
-\f
-/* Given ADDR and SIZE (a memory address, and the size of the memory reference),
- 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. */
-
-/* ??? 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)
- rtx addr;
- int size;
- rtx *pbase;
- HOST_WIDE_INT *pstart, *pend;
-{
- rtx base;
- HOST_WIDE_INT start, end;
-
- base = addr;
- start = 0;
- end = 0;
-
- if (flag_pic && GET_CODE (base) == PLUS
- && XEXP (base, 0) == pic_offset_table_rtx)
- base = XEXP (base, 1);
-
- /* Registers with nonvarying addresses usually have constant equivalents;
- but the frame pointer register is also possible. */
- if (GET_CODE (base) == REG
- && qty_const != 0
- && REGNO_QTY_VALID_P (REGNO (base))
- && qty_mode[REG_QTY (REGNO (base))] == GET_MODE (base)
- && qty_const[REG_QTY (REGNO (base))] != 0)
- base = qty_const[REG_QTY (REGNO (base))];
- else if (GET_CODE (base) == PLUS
- && GET_CODE (XEXP (base, 1)) == CONST_INT
- && GET_CODE (XEXP (base, 0)) == REG
- && qty_const != 0
- && REGNO_QTY_VALID_P (REGNO (XEXP (base, 0)))
- && (qty_mode[REG_QTY (REGNO (XEXP (base, 0)))]
- == GET_MODE (XEXP (base, 0)))
- && qty_const[REG_QTY (REGNO (XEXP (base, 0)))])
- {
- start = INTVAL (XEXP (base, 1));
- base = qty_const[REG_QTY (REGNO (XEXP (base, 0)))];
- }
- /* This can happen as the result of virtual register instantiation,
- if the initial offset is too large to be a valid address. */
- else if (GET_CODE (base) == PLUS
- && GET_CODE (XEXP (base, 0)) == REG
- && GET_CODE (XEXP (base, 1)) == REG
- && qty_const != 0
- && REGNO_QTY_VALID_P (REGNO (XEXP (base, 0)))
- && (qty_mode[REG_QTY (REGNO (XEXP (base, 0)))]
- == GET_MODE (XEXP (base, 0)))
- && qty_const[REG_QTY (REGNO (XEXP (base, 0)))]
- && REGNO_QTY_VALID_P (REGNO (XEXP (base, 1)))
- && (qty_mode[REG_QTY (REGNO (XEXP (base, 1)))]
- == GET_MODE (XEXP (base, 1)))
- && qty_const[REG_QTY (REGNO (XEXP (base, 1)))])
- {
- rtx tem = qty_const[REG_QTY (REGNO (XEXP (base, 1)))];
- base = qty_const[REG_QTY (REGNO (XEXP (base, 0)))];
-
- /* One of the two values must be a constant. */
- if (GET_CODE (base) != CONST_INT)
- {
- if (GET_CODE (tem) != CONST_INT)
- abort ();
- start = INTVAL (tem);
- }
- else
- {
- start = INTVAL (base);
- base = tem;
- }
- }
-
- /* 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;
- end += *pend;
- base = *pbase;
- }
- break;
-
- default:
- break;
- }
-
- break;
- }
-
- if (GET_CODE (base) == CONST_INT)
- {
- start += INTVAL (base);
- base = const0_rtx;
- }
-
- end = start + size;
-
- /* Set the return values. */
- *pbase = base;
- *pstart = start;
- *pend = end;
-}
-
/* Return 1 if X has a value that can vary even between two
executions of the program. 0 means X can be compared reliably
against certain constants or near-constants. */