📄 mips.c
字号:
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 (cfun->machine->insns_len). 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) && cfun->machine->insns_len > 0) { long size; size = cfun->machine->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));}/* Return nonzero if the code of this rtx pattern is EQ or NE. */intequality_op (op, mode) rtx op; enum machine_mode mode;{ if (mode != GET_MODE (op)) return 0; return GET_CODE (op) == EQ || GET_CODE (op) == NE;}/* Return nonzero if the code is a relational operations (EQ, LE, etc.) */intcmp_op (op, mode) rtx op; enum machine_mode mode;{ if (mode != GET_MODE (op)) return 0; return GET_RTX_CLASS (GET_CODE (op)) == '<';}/* Return nonzero if the code is a relational operation suitable for a conditional trap instructuion (only EQ, NE, LT, LTU, GE, GEU). We need this in the insn that expands `trap_if' in order to prevent combine from erroneously altering the condition. */inttrap_cmp_op (op, mode) rtx op; enum machine_mode mode;{ if (mode != GET_MODE (op)) return 0; switch (GET_CODE (op)) { case EQ: case NE: case LT: case LTU: case GE: case GEU: return 1; default: return 0; }}/* Return nonzero if the operand is either the PC or a label_ref. */intpc_or_label_operand (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ if (op == pc_rtx) return 1; if (GET_CODE (op) == LABEL_REF) return 1; return 0;}/* Test for a valid operand for a call instruction. Don't allow the arg pointer register or virtual regs since they may change into reg + const, which the patterns can't handle yet. */intcall_insn_operand (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ return (CONSTANT_ADDRESS_P (op) || (GET_CODE (op) == REG && op != arg_pointer_rtx && ! (REGNO (op) >= FIRST_PSEUDO_REGISTER && REGNO (op) <= LAST_VIRTUAL_REGISTER)));}/* Return nonzero if OPERAND is valid as a source operand for a move instruction. */intmove_operand (op, mode) rtx op; enum machine_mode mode;{ /* Accept any general operand after reload has started; doing so avoids losing if reload does an in-place replacement of a register with a SYMBOL_REF or CONST. */ return (general_operand (op, mode) && (! (mips_split_addresses && mips_check_split (op, mode)) || reload_in_progress || reload_completed) && ! (TARGET_MIPS16 && GET_CODE (op) == SYMBOL_REF && ! mips16_constant (op, mode, 1, 0)));}/* Return nonzero if OPERAND is valid as a source operand for movdi. This accepts not only general_operand, but also sign extended move_operands. Note that we need to accept sign extended constants in case a sign extended register which is used in an expression, and is equivalent to a constant, is spilled. We need to accept sign-extended memory in order to reload registers from stack slots, and so that we generate efficient code for extendsidi2. */intmovdi_operand (op, mode) rtx op; enum machine_mode mode;{ if (TARGET_64BIT && mode == DImode && GET_CODE (op) == SIGN_EXTEND && GET_MODE (op) == DImode && move_operand (XEXP (op, 0), SImode)) return 1; return (general_operand (op, mode) && ! (TARGET_MIPS16 && GET_CODE (op) == SYMBOL_REF && ! mips16_constant (op, mode, 1, 0)));}/* Like register_operand, but when in 64 bit mode also accept a sign extend of a 32 bit register, since the value is known to be already sign extended. */intse_register_operand (op, mode) rtx op; enum machine_mode mode;{ if (TARGET_64BIT && mode == DImode && GET_CODE (op) == SIGN_EXTEND && GET_MODE (op) == DImode && GET_MODE (XEXP (op, 0)) == SImode && register_operand (XEXP (op, 0), SImode)) return 1; return register_operand (op, mode);}/* Like reg_or_0_operand, but when in 64 bit mode also accept a sign extend of a 32 bit register, since the value is known to be already sign extended. */intse_reg_or_0_operand (op, mode) rtx op; enum machine_mode mode;{ if (TARGET_64BIT && mode == DImode && GET_CODE (op) == SIGN_EXTEND && GET_MODE (op) == DImode && GET_MODE (XEXP (op, 0)) == SImode && register_operand (XEXP (op, 0), SImode)) return 1; return reg_or_0_operand (op, mode);}/* Like uns_arith_operand, but when in 64 bit mode also accept a sign extend of a 32 bit register, since the value is known to be already sign extended. */intse_uns_arith_operand (op, mode) rtx op; enum machine_mode mode;{ if (TARGET_64BIT && mode == DImode && GET_CODE (op) == SIGN_EXTEND && GET_MODE (op) == DImode && GET_MODE (XEXP (op, 0)) == SImode && register_operand (XEXP (op, 0), SImode)) return 1; return uns_arith_operand (op, mode);}/* Like arith_operand, but when in 64 bit mode also accept a sign extend of a 32 bit register, since the value is known to be already sign extended. */intse_arith_operand (op, mode) rtx op; enum machine_mode mode;{ if (TARGET_64BIT && mode == DImode && GET_CODE (op) == SIGN_EXTEND && GET_MODE (op) == DImode && GET_MODE (XEXP (op, 0)) == SImode && register_operand (XEXP (op, 0), SImode)) return 1; return arith_operand (op, mode);}/* Like nonmemory_operand, but when in 64 bit mode also accept a sign extend of a 32 bit register, since the value is known to be already sign extended. */intse_nonmemory_operand (op, mode) rtx op; enum machine_mode mode;{ if (TARGET_64BIT && mode == DImode && GET_CODE (op) == SIGN_EXTEND && GET_MODE (op) == DImode && GET_MODE (XEXP (op, 0)) == SImode && register_operand (XEXP (op, 0), SImode)) return 1; return nonmemory_operand (op, mode);}/* Accept any operand that can appear in a mips16 constant table instruction. We can't use any of the standard operand functions because for these instructions we accept values that are not accepted by LEGITIMATE_CONSTANT, such as arbitrary SYMBOL_REFs. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -