- if (op0)
- op0 = equiv_constant (op0);
-
- if (op1 && !REG_P (op1) && ! CONSTANT_P (op1))
- op1 = fold_rtx (op1, NULL_RTX);
-
- if (op1)
- op1 = equiv_constant (op1);
-
- /* If we are looking for the low SImode part of
- (ashift:DI c (const_int 32)), it doesn't work
- 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 (op1) == CONST_INT
- && INTVAL (op1) >= GET_MODE_BITSIZE (mode))
- {
- if (INTVAL (op1)
- < GET_MODE_BITSIZE (GET_MODE (elt->exp)))
- /* If the count fits in the inner mode's width,
- but exceeds the outer mode's width,
- the value will get truncated to 0
- by the subreg. */
- new = CONST0_RTX (mode);
- else
- /* If the count exceeds even the inner mode's width,
- don't fold this expression. */
- new = 0;
- }
- else if (op0 && op1)
- new = simplify_binary_operation (GET_CODE (elt->exp), mode, op0, op1);
- }
-
- else if (GET_CODE (elt->exp) == SUBREG
- && GET_MODE (SUBREG_REG (elt->exp)) == mode
- && (GET_MODE_SIZE (GET_MODE (folded_arg0))
- <= UNITS_PER_WORD)
- && exp_equiv_p (elt->exp, elt->exp, 1, false))
- new = copy_rtx (SUBREG_REG (elt->exp));
-
- if (new)
- return new;
- }
- else
- /* A SUBREG resulting from a zero extension may fold to zero if
- it extracts higher bits than the ZERO_EXTEND's source bits.
- FIXME: if combine tried to, er, combine these instructions,
- this transformation may be moved to simplify_subreg. */
- for (; elt; elt = elt->next_same_value)
- {
- if (GET_CODE (elt->exp) == ZERO_EXTEND
- && subreg_lsb (x)
- >= GET_MODE_BITSIZE (GET_MODE (XEXP (elt->exp, 0))))
- return CONST0_RTX (mode);
- }
- }
-
- return x;
-
- case NOT:
- case NEG:
- /* If we have (NOT Y), see if Y is known to be (NOT Z).
- If so, (NOT Y) simplifies to Z. Similarly for NEG. */
- new = lookup_as_function (XEXP (x, 0), code);
- if (new)
- return fold_rtx (copy_rtx (XEXP (new, 0)), insn);
- break;
-
- case MEM:
- /* 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), GET_MODE (x));
-
- {
- /* 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;
- }
-
- /* 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)))
- return XVECEXP (table, 0,
- offset / GET_MODE_SIZE (GET_MODE (table)));
- }
- 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;
- }
-
-#ifdef NO_FUNCTION_CSE
- case CALL:
- if (CONSTANT_P (XEXP (XEXP (x, 0), 0)))
- return x;
- break;
-#endif
-
- case ASM_OPERANDS:
- if (insn)
- {
- for (i = ASM_OPERANDS_INPUT_LENGTH (x) - 1; i >= 0; i--)
- validate_change (insn, &ASM_OPERANDS_INPUT (x, i),
- fold_rtx (ASM_OPERANDS_INPUT (x, i), insn), 0);
- }
- break;
-
- default:
- break;
- }
-
- const_arg0 = 0;
- const_arg1 = 0;
- const_arg2 = 0;
- mode_arg0 = VOIDmode;
-
- /* Try folding our operands.
- Then see which ones have constant values known. */
-
- fmt = GET_RTX_FORMAT (code);
- for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
- if (fmt[i] == 'e')
- {
- rtx arg = XEXP (x, i);
- rtx folded_arg = arg, const_arg = 0;
- enum machine_mode mode_arg = GET_MODE (arg);
- rtx cheap_arg, expensive_arg;
- rtx replacements[2];
- int j;
- int old_cost = COST_IN (XEXP (x, i), code);
-
- /* Most arguments are cheap, so handle them specially. */
- switch (GET_CODE (arg))
- {
- case REG:
- /* This is the same as calling equiv_constant; it is duplicated
- here for speed. */
- if (REGNO_QTY_VALID_P (REGNO (arg)))
- {
- int arg_q = REG_QTY (REGNO (arg));
- struct qty_table_elem *arg_ent = &qty_table[arg_q];
-
- if (arg_ent->const_rtx != NULL_RTX
- && !REG_P (arg_ent->const_rtx)
- && GET_CODE (arg_ent->const_rtx) != PLUS)
- const_arg
- = gen_lowpart (GET_MODE (arg),
- arg_ent->const_rtx);
- }
- break;
-
- case CONST:
- case CONST_INT:
- case SYMBOL_REF:
- case LABEL_REF:
- case CONST_DOUBLE:
- case CONST_VECTOR:
- const_arg = arg;
- break;