- return x;
-}
-
-/* Fold MEM. Not to be called directly, see fold_rtx_mem instead. */
-
-static rtx
-fold_rtx_mem_1 (rtx x, rtx insn)
-{
- enum machine_mode mode = GET_MODE (x);
- rtx new;
-
- /* If we are not actually processing an insn, don't try to find the
- best address. Not only don't we care, but we could modify the
- MEM in an invalid way since we have no insn to validate
- against. */
- if (insn != 0)
- find_best_addr (insn, &XEXP (x, 0), mode);
-
- {
- /* Even if we don't fold in the insn itself, we can safely do so
- here, in hopes of getting a constant. */
- rtx addr = fold_rtx (XEXP (x, 0), NULL_RTX);
- rtx base = 0;
- HOST_WIDE_INT offset = 0;
-
- if (REG_P (addr)
- && REGNO_QTY_VALID_P (REGNO (addr)))
- {
- int addr_q = REG_QTY (REGNO (addr));
- struct qty_table_elem *addr_ent = &qty_table[addr_q];
-
- if (GET_MODE (addr) == addr_ent->mode
- && addr_ent->const_rtx != NULL_RTX)
- addr = addr_ent->const_rtx;
- }
-
- /* Call target hook to avoid the effects of -fpic etc.... */
- addr = targetm.delegitimize_address (addr);
-
- /* If address is constant, split it into a base and integer
- offset. */
- if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == LABEL_REF)
- base = addr;
- else if (GET_CODE (addr) == CONST && GET_CODE (XEXP (addr, 0)) == PLUS
- && GET_CODE (XEXP (XEXP (addr, 0), 1)) == CONST_INT)
- {
- base = XEXP (XEXP (addr, 0), 0);
- offset = INTVAL (XEXP (XEXP (addr, 0), 1));
- }
- else if (GET_CODE (addr) == LO_SUM
- && GET_CODE (XEXP (addr, 1)) == SYMBOL_REF)
- base = XEXP (addr, 1);
-
- /* If this is a constant pool reference, we can fold it into its
- constant to allow better value tracking. */
- if (base && GET_CODE (base) == SYMBOL_REF
- && CONSTANT_POOL_ADDRESS_P (base))
- {
- rtx constant = get_pool_constant (base);
- enum machine_mode const_mode = get_pool_mode (base);
- rtx new;
-
- if (CONSTANT_P (constant) && GET_CODE (constant) != CONST_INT)
- {
- constant_pool_entries_cost = COST (constant);
- constant_pool_entries_regcost = approx_reg_cost (constant);
- }
-
- /* If we are loading the full constant, we have an
- equivalence. */
- if (offset == 0 && mode == const_mode)
- return constant;
-
- /* If this actually isn't a constant (weird!), we can't do
- anything. Otherwise, handle the two most common cases:
- extracting a word from a multi-word constant, and
- extracting the low-order bits. Other cases don't seem
- common enough to worry about. */
- if (! CONSTANT_P (constant))
- return x;
-
- if (GET_MODE_CLASS (mode) == MODE_INT
- && GET_MODE_SIZE (mode) == UNITS_PER_WORD
- && offset % UNITS_PER_WORD == 0
- && (new = operand_subword (constant,
- offset / UNITS_PER_WORD,
- 0, const_mode)) != 0)
- return new;
-
- if (((BYTES_BIG_ENDIAN
- && offset == GET_MODE_SIZE (GET_MODE (constant)) - 1)
- || (! BYTES_BIG_ENDIAN && offset == 0))
- && (new = gen_lowpart (mode, constant)) != 0)
- return new;
- }
-
- /* If this is a reference to a label at a known position in a jump
- table, we also know its value. */
- if (base && GET_CODE (base) == LABEL_REF)
- {
- rtx label = XEXP (base, 0);
- rtx table_insn = NEXT_INSN (label);
-
- if (table_insn && JUMP_P (table_insn)
- && GET_CODE (PATTERN (table_insn)) == ADDR_VEC)
- {
- rtx table = PATTERN (table_insn);
-
- if (offset >= 0
- && (offset / GET_MODE_SIZE (GET_MODE (table))
- < XVECLEN (table, 0)))
- {
- rtx label = XVECEXP
- (table, 0, offset / GET_MODE_SIZE (GET_MODE (table)));
- rtx set;
-
- /* If we have an insn that loads the label from the
- jumptable into a reg, we don't want to set the reg
- to the label, because this may cause a reference to
- the label to remain after the label is removed in
- some very obscure cases (PR middle-end/18628). */
- if (!insn)
- return label;
-
- set = single_set (insn);
-
- if (! set || SET_SRC (set) != x)
- return x;
-
- /* If it's a jump, it's safe to reference the label. */
- if (SET_DEST (set) == pc_rtx)
- return label;
-
- return x;
- }
- }
- if (table_insn && JUMP_P (table_insn)
- && GET_CODE (PATTERN (table_insn)) == ADDR_DIFF_VEC)
- {
- rtx table = PATTERN (table_insn);
-
- if (offset >= 0
- && (offset / GET_MODE_SIZE (GET_MODE (table))
- < XVECLEN (table, 1)))
- {
- offset /= GET_MODE_SIZE (GET_MODE (table));
- new = gen_rtx_MINUS (Pmode, XVECEXP (table, 1, offset),
- XEXP (table, 0));
-
- if (GET_MODE (table) != Pmode)
- new = gen_rtx_TRUNCATE (GET_MODE (table), 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.
-
- Note this expression must be explicitly discarded,
- by cse_insn, else it may end up in a REG_EQUAL note
- and "escape" to cause problems elsewhere. */
- return gen_rtx_CONST (GET_MODE (new), new);
- }
- }
- }
-
- return x;
- }
-}
-
-/* Fold MEM. */
-
-static rtx
-fold_rtx_mem (rtx x, rtx insn)
-{
- /* To avoid infinite oscillations between fold_rtx and fold_rtx_mem,
- refuse to allow recursion of the latter past n levels. This can
- happen because fold_rtx_mem will try to fold the address of the
- memory reference it is passed, i.e. conceptually throwing away
- the MEM and reinjecting the bare address into fold_rtx. As a
- result, patterns like
-
- set (reg1)
- (plus (reg)
- (mem (plus (reg2) (const_int))))
-
- set (reg2)
- (plus (reg)
- (mem (plus (reg1) (const_int))))
-
- will defeat any "first-order" short-circuit put in either
- function to prevent these infinite oscillations.
-
- The heuristics for determining n is as follows: since each time
- it is invoked fold_rtx_mem throws away a MEM, and since MEMs
- are generically not nested, we assume that each invocation of
- fold_rtx_mem corresponds to a new "top-level" operand, i.e.
- the source or the destination of a SET. So fold_rtx_mem is
- bound to stop or cycle before n recursions, n being the number
- of expressions recorded in the hash table. We also leave some
- play to account for the initial steps. */
-
- static unsigned int depth;
- rtx ret;
-
- if (depth > 3 + table_size)
- return x;
-
- depth++;
- ret = fold_rtx_mem_1 (x, insn);
- depth--;
-
- return ret;
-}
-
-/* If X is a nontrivial arithmetic operation on an argument
- for which a constant value can be determined, return
- the result of operating on that value, as a constant.
- Otherwise, return X, possibly with one or more operands
- modified by recursive calls to this function.
-
- If X is a register whose contents are known, we do NOT
- return those contents here. equiv_constant is called to
- perform that task.