?? mips.c.svn-base
字號:
{ if (GET_MODE_SIZE (mode) == 4 && base == stack_pointer_rtx) return INTVAL (offset) < 256 * GET_MODE_SIZE (mode); return INTVAL (offset) < 32 * GET_MODE_SIZE (mode); } return false;}/* Return the number of instructions needed to load or store a value of mode MODE at X. Return 0 if X isn't valid for MODE. For mips16 code, count extended instructions as two instructions. */intmips_address_insns (rtx x, enum machine_mode mode){ struct mips_address_info addr; int factor; if (mode == BLKmode) /* BLKmode is used for single unaligned loads and stores. */ factor = 1; else /* Each word of a multi-word value will be accessed individually. */ factor = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD; if (mips_classify_address (&addr, x, mode, false)) switch (addr.type) { case ADDRESS_REG: if (TARGET_MIPS16 && !mips16_unextended_reference_p (mode, addr.reg, addr.offset)) return factor * 2; return factor; case ADDRESS_LO_SUM: return (TARGET_MIPS16 ? factor * 2 : factor); case ADDRESS_CONST_INT: return factor; case ADDRESS_SYMBOLIC: return factor * mips_symbol_insns (addr.symbol_type); } return 0;}/* Likewise for constant X. */intmips_const_insns (rtx x){ struct mips_integer_op codes[MIPS_MAX_INTEGER_OPS]; enum mips_symbol_type symbol_type; HOST_WIDE_INT offset; switch (GET_CODE (x)) { case HIGH: if (TARGET_MIPS16 || !mips_symbolic_constant_p (XEXP (x, 0), &symbol_type) || !mips_split_p[symbol_type]) return 0; return 1; case CONST_INT: if (TARGET_MIPS16) /* Unsigned 8-bit constants can be loaded using an unextended LI instruction. Unsigned 16-bit constants can be loaded using an extended LI. Negative constants must be loaded using LI and then negated. */ return (INTVAL (x) >= 0 && INTVAL (x) < 256 ? 1 : SMALL_OPERAND_UNSIGNED (INTVAL (x)) ? 2 : INTVAL (x) > -256 && INTVAL (x) < 0 ? 2 : SMALL_OPERAND_UNSIGNED (-INTVAL (x)) ? 3 : 0); return mips_build_integer (codes, INTVAL (x)); case CONST_DOUBLE: case CONST_VECTOR: return (!TARGET_MIPS16 && x == CONST0_RTX (GET_MODE (x)) ? 1 : 0); case CONST: if (CONST_GP_P (x)) return 1; /* See if we can refer to X directly. */ if (mips_symbolic_constant_p (x, &symbol_type)) return mips_symbol_insns (symbol_type); /* Otherwise try splitting the constant into a base and offset. 16-bit offsets can be added using an extra addiu. Larger offsets must be calculated separately and then added to the base. */ mips_split_const (x, &x, &offset); if (offset != 0) { int n = mips_const_insns (x); if (n != 0) { if (SMALL_OPERAND (offset)) return n + 1; else return n + 1 + mips_build_integer (codes, offset); } } return 0; case SYMBOL_REF: case LABEL_REF: return mips_symbol_insns (mips_classify_symbol (x)); default: return 0; }}/* Return the number of instructions needed for memory reference X. Count extended mips16 instructions as two instructions. */intmips_fetch_insns (rtx x){ gcc_assert (MEM_P (x)); return mips_address_insns (XEXP (x, 0), GET_MODE (x));}/* Return the number of instructions needed for an integer division. */intmips_idiv_insns (void){ int count; count = 1; if (TARGET_CHECK_ZERO_DIV) { if (GENERATE_DIVIDE_TRAPS) count++; else count += 2; } if (TARGET_FIX_R4000 || TARGET_FIX_R4400) count++; return count;}/* This function is used to implement GO_IF_LEGITIMATE_ADDRESS. It returns a nonzero value if X is a legitimate address for a memory operand of the indicated MODE. STRICT is nonzero if this function is called during reload. */boolmips_legitimate_address_p (enum machine_mode mode, rtx x, int strict){ struct mips_address_info addr; return mips_classify_address (&addr, x, mode, strict);}/* Copy VALUE to a register and return that register. If new psuedos are allowed, copy it into a new register, otherwise use DEST. */static rtxmips_force_temporary (rtx dest, rtx value){ if (!no_new_pseudos) return force_reg (Pmode, value); else { emit_move_insn (copy_rtx (dest), value); return dest; }}/* Return a LO_SUM expression for ADDR. TEMP is as for mips_force_temporary and is used to load the high part into a register. */static rtxmips_split_symbol (rtx temp, rtx addr){ rtx high; if (TARGET_MIPS16) high = mips16_gp_pseudo_reg (); else high = mips_force_temporary (temp, gen_rtx_HIGH (Pmode, copy_rtx (addr))); return gen_rtx_LO_SUM (Pmode, high, addr);}/* Return an UNSPEC address with underlying address ADDRESS and symbol type SYMBOL_TYPE. */rtxmips_unspec_address (rtx address, enum mips_symbol_type symbol_type){ rtx base; HOST_WIDE_INT offset; mips_split_const (address, &base, &offset); base = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, base), UNSPEC_ADDRESS_FIRST + symbol_type); return plus_constant (gen_rtx_CONST (Pmode, base), offset);}/* If mips_unspec_address (ADDR, SYMBOL_TYPE) is a 32-bit value, add the high part to BASE and return the result. Just return BASE otherwise. TEMP is available as a temporary register if needed. The returned expression can be used as the first operand to a LO_SUM. */static rtxmips_unspec_offset_high (rtx temp, rtx base, rtx addr, enum mips_symbol_type symbol_type){ if (mips_split_p[symbol_type]) { addr = gen_rtx_HIGH (Pmode, mips_unspec_address (addr, symbol_type)); addr = mips_force_temporary (temp, addr); return mips_force_temporary (temp, gen_rtx_PLUS (Pmode, addr, base)); } return base;}/* Return a legitimate address for REG + OFFSET. TEMP is as for mips_force_temporary; it is only needed when OFFSET is not a SMALL_OPERAND. */static rtxmips_add_offset (rtx temp, rtx reg, HOST_WIDE_INT offset){ if (!SMALL_OPERAND (offset)) { rtx high; if (TARGET_MIPS16) { /* Load the full offset into a register so that we can use an unextended instruction for the address itself. */ high = GEN_INT (offset); offset = 0; } else { /* Leave OFFSET as a 16-bit offset and put the excess in HIGH. */ high = GEN_INT (CONST_HIGH_PART (offset)); offset = CONST_LOW_PART (offset); } high = mips_force_temporary (temp, high); reg = mips_force_temporary (temp, gen_rtx_PLUS (Pmode, high, reg)); } return plus_constant (reg, offset);}/* This function is used to implement LEGITIMIZE_ADDRESS. If *XLOC can be legitimized in a way that the generic machinery might not expect, put the new address in *XLOC and return true. MODE is the mode of the memory being accessed. */boolmips_legitimize_address (rtx *xloc, enum machine_mode mode){ enum mips_symbol_type symbol_type; /* See if the address can split into a high part and a LO_SUM. */ if (mips_symbolic_constant_p (*xloc, &symbol_type) && mips_symbolic_address_p (symbol_type, mode) && mips_split_p[symbol_type]) { *xloc = mips_split_symbol (0, *xloc); return true; } if (GET_CODE (*xloc) == PLUS && GET_CODE (XEXP (*xloc, 1)) == CONST_INT) { /* Handle REG + CONSTANT using mips_add_offset. */ rtx reg; reg = XEXP (*xloc, 0); if (!mips_valid_base_register_p (reg, mode, 0)) reg = copy_to_mode_reg (Pmode, reg); *xloc = mips_add_offset (0, reg, INTVAL (XEXP (*xloc, 1))); return true; } return false;}/* Subroutine of mips_build_integer (with the same interface). Assume that the final action in the sequence should be a left shift. */static unsigned intmips_build_shift (struct mips_integer_op *codes, HOST_WIDE_INT value){ unsigned int i, shift; /* Shift VALUE right until its lowest bit is set. Shift arithmetically since signed numbers are easier to load than unsigned ones. */ shift = 0; while ((value & 1) == 0) value /= 2, shift++; i = mips_build_integer (codes, value); codes[i].code = ASHIFT; codes[i].value = shift; return i + 1;}/* As for mips_build_shift, but assume that the final action will be an IOR or PLUS operation. */static unsigned intmips_build_lower (struct mips_integer_op *codes, unsigned HOST_WIDE_INT value){ unsigned HOST_WIDE_INT high; unsigned int i; high = value & ~(unsigned HOST_WIDE_INT) 0xffff; if (!LUI_OPERAND (high) && (value & 0x18000) == 0x18000) { /* The constant is too complex to load with a simple lui/ori pair so our goal is to clear as many trailing zeros as possible. In this case, we know bit 16 is set and that the low 16 bits form a negative number. If we subtract that number from VALUE, we will clear at least the lowest 17 bits, maybe more. */ i = mips_build_integer (codes, CONST_HIGH_PART (value)); codes[i].code = PLUS; codes[i].value = CONST_LOW_PART (value); } else { i = mips_build_integer (codes, high); codes[i].code = IOR; codes[i].value = value & 0xffff; } return i + 1;}/* Fill CODES with a sequence of rtl operations to load VALUE. Return the number of operations needed. */static unsigned intmips_build_integer (struct mips_integer_op *codes, unsigned HOST_WIDE_INT value){ if (SMALL_OPERAND (value) || SMALL_OPERAND_UNSIGNED (value) || LUI_OPERAND (value)) { /* The value can be loaded with a single instruction. */ codes[0].code = UNKNOWN; codes[0].value = value; return 1; } else if ((value & 1) != 0 || LUI_OPERAND (CONST_HIGH_PART (value))) { /* Either the constant is a simple LUI/ORI combination or its lowest bit is set. We don't want to shift in this case. */ return mips_build_lower (codes, value); } else if ((value & 0xffff) == 0) { /* The constant will need at least three actions. The lowest 16 bits are clear, so the final action will be a shift. */ return mips_build_shift (codes, value); } else { /* The final action could be a shift, add or inclusive OR. Rather than use a complex condition to select the best approach, try both mips_build_shift and mips_build_lower and pick the one that gives the shortest sequence. Note that this case is only used once per constant. */ struct mips_integer_op alt_codes[MIPS_MAX_INTEGER_OPS]; unsigned int cost, alt_cost; cost = mips_build_shift (codes, value); alt_cost = mips_build_lower (alt_codes, value); if (alt_cost < cost) { memcpy (codes, alt_codes, alt_cost * sizeof (codes[0])); cost = alt_cost; } return cost; }}/* Move VALUE into register DEST. */static voidmips_move_integer (rtx dest, unsigned HOST_WIDE_INT value){ struct mips_integer_op codes[MIPS_MAX_INTEGER_OPS]; enum machine_mode mode; unsigned int i, cost; rtx x; mode = GET_MODE (dest); cost = mips_build_integer (codes, value); /* Apply each binary operation to X. Invariant: X is a legitimate source operand for a SET pattern. */ x = GEN_INT (codes[0].value); for (i = 1; i < cost; i++) {
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -