📄 mips.c
字号:
{ if (GET_CODE (op) == CONST_INT && SMALL_INT_UNSIGNED (op)) return 1; return register_operand (op, mode);}/* Return truth value of whether OP can be used as an operands where a 16 bit integer is needed */intarith_operand (op, mode) rtx op; enum machine_mode mode;{ if (GET_CODE (op) == CONST_INT && SMALL_INT (op)) return 1; /* On the mips16, a GP relative value is a signed 16 bit offset. */ if (TARGET_MIPS16 && GET_CODE (op) == CONST && mips16_gp_offset_p (op)) return 1; return register_operand (op, mode);}/* Return truth value of whether OP can be used as an operand in a two address arithmetic insn (such as set 123456,%o4) of mode MODE. */intarith32_operand (op, mode) rtx op; enum machine_mode mode;{ if (GET_CODE (op) == CONST_INT) return 1; return register_operand (op, mode);}/* Return truth value of whether OP is an integer which fits in 16 bits. */intsmall_int (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ return (GET_CODE (op) == CONST_INT && SMALL_INT (op));}/* Return truth value of whether OP is a 32 bit integer which is too big to be loaded with one instruction. */intlarge_int (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ HOST_WIDE_INT value; if (GET_CODE (op) != CONST_INT) return 0; value = INTVAL (op); /* ior reg,$r0,value */ if ((value & ~ ((HOST_WIDE_INT) 0x0000ffff)) == 0) return 0; /* subu reg,$r0,value */ if (((unsigned HOST_WIDE_INT) (value + 32768)) <= 32767) return 0; /* lui reg,value>>16 */ if ((value & 0x0000ffff) == 0) return 0; return 1;}/* Return truth value of whether OP is a register or the constant 0. In mips16 mode, we only accept a register, since the mips16 does not have $0. */intreg_or_0_operand (op, mode) rtx op; enum machine_mode mode;{ switch (GET_CODE (op)) { case CONST_INT: if (TARGET_MIPS16) return 0; return INTVAL (op) == 0; case CONST_DOUBLE: if (TARGET_MIPS16) return 0; return op == CONST0_RTX (mode); case REG: case SUBREG: return register_operand (op, mode); default: break; } return 0;}/* Return truth value of whether OP is a register or the constant 0, even in mips16 mode. */inttrue_reg_or_0_operand (op, mode) rtx op; enum machine_mode mode;{ switch (GET_CODE (op)) { case CONST_INT: return INTVAL (op) == 0; case CONST_DOUBLE: return op == CONST0_RTX (mode); case REG: case SUBREG: return register_operand (op, mode); default: break; } return 0;}/* Return truth value if a CONST_DOUBLE is ok to be a legitimate constant. */intmips_const_double_ok (op, mode) rtx op; enum machine_mode mode;{ REAL_VALUE_TYPE d; if (GET_CODE (op) != CONST_DOUBLE) return 0; if (mode == VOIDmode) return 1; if (mode != SFmode && mode != DFmode) return 0; if (op == CONST0_RTX (mode)) return 1; /* ??? li.s does not work right with SGI's Irix 6 assembler. */ if (mips_abi != ABI_32 && mips_abi != ABI_O64 && mips_abi != ABI_EABI) return 0; REAL_VALUE_FROM_CONST_DOUBLE (d, op); if (REAL_VALUE_ISNAN (d)) return FALSE; if (REAL_VALUE_NEGATIVE (d)) d = REAL_VALUE_NEGATE (d); if (mode == DFmode) { if (REAL_VALUES_LESS (d, dfhigh) && REAL_VALUES_LESS (dflow, d)) return 1; } else { if (REAL_VALUES_LESS (d, sfhigh) && REAL_VALUES_LESS (sflow, d)) return 1; } return 0;}/* Accept the floating point constant 1 in the appropriate mode. */intconst_float_1_operand (op, mode) rtx op; enum machine_mode mode;{ REAL_VALUE_TYPE d; static REAL_VALUE_TYPE onedf; static REAL_VALUE_TYPE onesf; static int one_initialized; if (GET_CODE (op) != CONST_DOUBLE || mode != GET_MODE (op) || (mode != DFmode && mode != SFmode)) return 0; REAL_VALUE_FROM_CONST_DOUBLE (d, op); /* We only initialize these values if we need them, since we will never get called unless mips_isa >= 4. */ if (! one_initialized) { onedf = REAL_VALUE_ATOF ("1.0", DFmode); onesf = REAL_VALUE_ATOF ("1.0", SFmode); one_initialized = 1; } if (mode == DFmode) return REAL_VALUES_EQUAL (d, onedf); else return REAL_VALUES_EQUAL (d, onesf);}/* Return true if a memory load or store of REG plus OFFSET in MODE can be represented in a single word on the mips16. */static intmips16_simple_memory_operand (reg, offset, mode) rtx reg; rtx offset; enum machine_mode mode;{ unsigned int size; int off; if (mode == BLKmode) { /* We can't tell, because we don't know how the value will eventually be accessed. Returning 0 here does no great harm; it just prevents some possible instruction scheduling. */ return 0; } size = GET_MODE_SIZE (mode); if (INTVAL (offset) % size != 0) return 0; if (REGNO (reg) == STACK_POINTER_REGNUM && GET_MODE_SIZE (mode) == 4) off = 0x100; else off = 0x20; if (INTVAL (offset) >= 0 && INTVAL (offset) < (HOST_WIDE_INT)(off * size)) return 1; return 0;}/* Return truth value if a memory operand fits in a single instruction (ie, register + small offset). */intsimple_memory_operand (op, mode) rtx op; enum machine_mode mode;{ rtx addr, plus0, plus1; /* Eliminate non-memory operations */ if (GET_CODE (op) != MEM) return 0; /* dword operations really put out 2 instructions, so eliminate them. */ /* ??? This isn't strictly correct. It is OK to accept multiword modes here, since the length attributes are being set correctly, but only if the address is offsettable. LO_SUM is not offsettable. */ if (GET_MODE_SIZE (GET_MODE (op)) > (unsigned) UNITS_PER_WORD) return 0; /* Decode the address now. */ addr = XEXP (op, 0); switch (GET_CODE (addr)) { case REG: case LO_SUM: return 1; case CONST_INT: if (TARGET_MIPS16) return 0; return SMALL_INT (addr); case PLUS: plus0 = XEXP (addr, 0); plus1 = XEXP (addr, 1); if (GET_CODE (plus0) == REG && GET_CODE (plus1) == CONST_INT && SMALL_INT (plus1) && (! TARGET_MIPS16 || mips16_simple_memory_operand (plus0, plus1, mode))) return 1; else if (GET_CODE (plus1) == REG && GET_CODE (plus0) == CONST_INT && SMALL_INT (plus0) && (! TARGET_MIPS16 || mips16_simple_memory_operand (plus1, plus0, mode))) return 1; else return 0;#if 0 /* We used to allow small symbol refs here (ie, stuff in .sdata or .sbss), but this causes some bugs in G++. Also, it won't interfere if the MIPS linker rewrites the store instruction because the function is PIC. */ case LABEL_REF: /* never gp relative */ break; case CONST: /* If -G 0, we can never have a GP relative memory operation. Also, save some time if not optimizing. */ if (!TARGET_GP_OPT) return 0; { rtx offset = const0_rtx; addr = eliminate_constant_term (XEXP (addr, 0), &offset); if (GET_CODE (op) != SYMBOL_REF) return 0; /* let's be paranoid.... */ if (! SMALL_INT (offset)) return 0; } /* fall through */ case SYMBOL_REF: return SYMBOL_REF_FLAG (addr);#endif /* This SYMBOL_REF case is for the mips16. If the above case is reenabled, this one should be merged in. */ case SYMBOL_REF: /* References to the constant pool on the mips16 use a small offset if the function is small. The only time we care about getting this right is during delayed branch scheduling, so don't need to check until then. The machine_dependent_reorg function will set the total length of the instructions used in the function in current_frame_info. If that is small enough, we know for sure that this is a small offset. It would be better if we could take into account the location of the instruction within the function, but we can't, because we don't know where we are. */ if (TARGET_MIPS16 && CONSTANT_POOL_ADDRESS_P (addr) && current_frame_info.insns_len > 0) { long size; size = current_frame_info.insns_len + get_pool_size (); if (GET_MODE_SIZE (mode) == 4) return size < 4 * 0x100; else if (GET_MODE_SIZE (mode) == 8) return size < 8 * 0x20; else return 0; } return 0; default: break; } return 0;}/* Return nonzero for a memory address that can be used to load or store a doubleword. */intdouble_memory_operand (op, mode) rtx op; enum machine_mode mode;{ if (GET_CODE (op) != MEM || ! memory_operand (op, mode)) { /* During reload, we accept a pseudo register if it has an appropriate memory address. If we don't do this, we will wind up reloading into a register, and then reloading that register from memory, when we could just reload directly from memory. */ if (reload_in_progress && GET_CODE (op) == REG && REGNO (op) >= FIRST_PSEUDO_REGISTER && reg_renumber[REGNO (op)] < 0 && reg_equiv_mem[REGNO (op)] != 0 && double_memory_operand (reg_equiv_mem[REGNO (op)], mode)) return 1; /* All reloaded addresses are valid in TARGET_64BIT mode. This is the same test performed for 'm' in find_reloads. */ if (reload_in_progress && TARGET_64BIT && (GET_CODE (op) == MEM || (GET_CODE (op) == REG && REGNO (op) >= FIRST_PSEUDO_REGISTER && reg_renumber[REGNO (op)] < 0))) return 1; if (reload_in_progress && TARGET_MIPS16 && GET_CODE (op) == MEM) { rtx addr; addr = XEXP (op, 0); /* During reload on the mips16, we accept a large offset from the frame pointer or the stack pointer. This large address will get reloaded anyhow. */ if (GET_CODE (addr) == PLUS && GET_CODE (XEXP (addr, 0)) == REG && (REGNO (XEXP (addr, 0)) == (unsigned) HARD_FRAME_POINTER_REGNUM || REGNO (XEXP (addr, 0)) == STACK_POINTER_REGNUM) && ((GET_CODE (XEXP (addr, 1)) == CONST_INT && ! SMALL_INT (XEXP (addr, 1))) || (GET_CODE (XEXP (addr, 1)) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (XEXP (addr, 1))))) return 1; /* Similarly, we accept a case where the memory address is itself on the stack, and will be reloaded. */ if (GET_CODE (addr) == MEM) { rtx maddr; maddr = XEXP (addr, 0); if (GET_CODE (maddr) == PLUS && GET_CODE (XEXP (maddr, 0)) == REG && (REGNO (XEXP (maddr, 0)) == (unsigned) HARD_FRAME_POINTER_REGNUM || REGNO (XEXP (maddr, 0)) == STACK_POINTER_REGNUM) && ((GET_CODE (XEXP (maddr, 1)) == CONST_INT && ! SMALL_INT (XEXP (maddr, 1))) || (GET_CODE (XEXP (maddr, 1)) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (XEXP (maddr, 1))))) return 1; } /* We also accept the same case when we have a 16 bit signed offset mixed in as well. The large address will get reloaded, and the 16 bit offset will be OK. */ if (GET_CODE (addr) == PLUS && GET_CODE (XEXP (addr, 0)) == MEM && GET_CODE (XEXP (addr, 1)) == CONST_INT && SMALL_INT (XEXP (addr, 1))) { addr = XEXP (XEXP (addr, 0), 0); if (GET_CODE (addr) == PLUS && GET_CODE (XEXP (addr, 0)) == REG && (REGNO (XEXP (addr, 0)) == (unsigned) HARD_FRAME_POINTER_REGNUM || REGNO (XEXP (addr, 0)) == STACK_POINTER_REGNUM) && ((GET_CODE (XEXP (addr, 1)) == CONST_INT && ! SMALL_INT (XEXP (addr, 1))) || (GET_CODE (XEXP (addr, 1)) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (XEXP (addr, 1))))) return 1; } } return 0; } if (TARGET_64BIT) { /* In this case we can use an instruction like sd. */ return 1; } /* Make sure that 4 added to the address is a valid memory address. This essentially just checks for overflow in an added constant. */ if (CONSTANT_ADDRESS_P (XEXP (op, 0))) return 1; op = adjust_address_nv (op, GET_MODE_CLASS (mode) == MODE_INT ? SImode : SFmode, 4); return memory_address_p (GET_MODE (op), XEXP (op, 0));}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -