?? mips.c.svn-base
字號:
if (TARGET_MIPS16) return SYMBOL_CONSTANT_POOL; if (TARGET_ABICALLS) return SYMBOL_GOT_LOCAL; if (GET_MODE_SIZE (get_pool_mode (x)) <= mips_section_threshold) return SYMBOL_SMALL_DATA; return SYMBOL_GENERAL; } if (SYMBOL_REF_SMALL_P (x)) return SYMBOL_SMALL_DATA; if (TARGET_ABICALLS) { if (SYMBOL_REF_DECL (x) == 0) return SYMBOL_REF_LOCAL_P (x) ? SYMBOL_GOT_LOCAL : SYMBOL_GOT_GLOBAL; /* There are three cases to consider: - o32 PIC (either with or without explicit relocs) - n32/n64 PIC without explicit relocs - n32/n64 PIC with explicit relocs In the first case, both local and global accesses will use an R_MIPS_GOT16 relocation. We must correctly predict which of the two semantics (local or global) the assembler and linker will apply. The choice doesn't depend on the symbol's visibility, so we deliberately ignore decl_visibility and binds_local_p here. In the second case, the assembler will not use R_MIPS_GOT16 relocations, but it chooses between local and global accesses in the same way as for o32 PIC. In the third case we have more freedom since both forms of access will work for any kind of symbol. However, there seems little point in doing things differently. */ if (DECL_P (SYMBOL_REF_DECL (x)) && TREE_PUBLIC (SYMBOL_REF_DECL (x))) return SYMBOL_GOT_GLOBAL; return SYMBOL_GOT_LOCAL; } return SYMBOL_GENERAL;}/* Split X into a base and a constant offset, storing them in *BASE and *OFFSET respectively. */static voidmips_split_const (rtx x, rtx *base, HOST_WIDE_INT *offset){ *offset = 0; if (GET_CODE (x) == CONST) x = XEXP (x, 0); if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT) { *offset += INTVAL (XEXP (x, 1)); x = XEXP (x, 0); } *base = x;}/* Return true if SYMBOL is a SYMBOL_REF and OFFSET + SYMBOL points to the same object as SYMBOL. */static boolmips_offset_within_object_p (rtx symbol, HOST_WIDE_INT offset){ if (GET_CODE (symbol) != SYMBOL_REF) return false; if (CONSTANT_POOL_ADDRESS_P (symbol) && offset >= 0 && offset < (int) GET_MODE_SIZE (get_pool_mode (symbol))) return true; if (SYMBOL_REF_DECL (symbol) != 0 && offset >= 0 && offset < int_size_in_bytes (TREE_TYPE (SYMBOL_REF_DECL (symbol)))) return true; return false;}/* Return true if X is a symbolic constant that can be calculated in the same way as a bare symbol. If it is, store the type of the symbol in *SYMBOL_TYPE. */boolmips_symbolic_constant_p (rtx x, enum mips_symbol_type *symbol_type){ HOST_WIDE_INT offset; mips_split_const (x, &x, &offset); if (UNSPEC_ADDRESS_P (x)) *symbol_type = UNSPEC_ADDRESS_TYPE (x); else if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF) *symbol_type = mips_classify_symbol (x); else return false; if (offset == 0) return true; /* Check whether a nonzero offset is valid for the underlying relocations. */ switch (*symbol_type) { case SYMBOL_GENERAL: case SYMBOL_64_HIGH: case SYMBOL_64_MID: case SYMBOL_64_LOW: /* If the target has 64-bit pointers and the object file only supports 32-bit symbols, the values of those symbols will be sign-extended. In this case we can't allow an arbitrary offset in case the 32-bit value X + OFFSET has a different sign from X. */ if (Pmode == DImode && !ABI_HAS_64BIT_SYMBOLS) return mips_offset_within_object_p (x, offset); /* In other cases the relocations can handle any offset. */ return true; case SYMBOL_CONSTANT_POOL: /* Allow constant pool references to be converted to LABEL+CONSTANT. In this case, we no longer have access to the underlying constant, but the original symbol-based access was known to be valid. */ if (GET_CODE (x) == LABEL_REF) return true; /* Fall through. */ case SYMBOL_SMALL_DATA: /* Make sure that the offset refers to something within the underlying object. This should guarantee that the final PC- or GP-relative offset is within the 16-bit limit. */ return mips_offset_within_object_p (x, offset); case SYMBOL_GOT_LOCAL: case SYMBOL_GOTOFF_PAGE: /* The linker should provide enough local GOT entries for a 16-bit offset. Larger offsets may lead to GOT overflow. */ return SMALL_OPERAND (offset); case SYMBOL_GOT_GLOBAL: case SYMBOL_GOTOFF_GLOBAL: case SYMBOL_GOTOFF_CALL: case SYMBOL_GOTOFF_LOADGP: return false; } gcc_unreachable ();}/* Return true if X is a symbolic constant whose value is not split into separate relocations. */boolmips_atomic_symbolic_constant_p (rtx x){ enum mips_symbol_type type; return mips_symbolic_constant_p (x, &type) && !mips_split_p[type];}/* This function is used to implement REG_MODE_OK_FOR_BASE_P. */intmips_regno_mode_ok_for_base_p (int regno, enum machine_mode mode, int strict){ if (regno >= FIRST_PSEUDO_REGISTER) { if (!strict) return true; regno = reg_renumber[regno]; } /* These fake registers will be eliminated to either the stack or hard frame pointer, both of which are usually valid base registers. Reload deals with the cases where the eliminated form isn't valid. */ if (regno == ARG_POINTER_REGNUM || regno == FRAME_POINTER_REGNUM) return true; /* In mips16 mode, the stack pointer can only address word and doubleword values, nothing smaller. There are two problems here: (a) Instantiating virtual registers can introduce new uses of the stack pointer. If these virtual registers are valid addresses, the stack pointer should be too. (b) Most uses of the stack pointer are not made explicit until FRAME_POINTER_REGNUM and ARG_POINTER_REGNUM have been eliminated. We don't know until that stage whether we'll be eliminating to the stack pointer (which needs the restriction) or the hard frame pointer (which doesn't). All in all, it seems more consistent to only enforce this restriction during and after reload. */ if (TARGET_MIPS16 && regno == STACK_POINTER_REGNUM) return !strict || GET_MODE_SIZE (mode) == 4 || GET_MODE_SIZE (mode) == 8; return TARGET_MIPS16 ? M16_REG_P (regno) : GP_REG_P (regno);}/* Return true if X is a valid base register for the given mode. Allow only hard registers if STRICT. */static boolmips_valid_base_register_p (rtx x, enum machine_mode mode, int strict){ if (!strict && GET_CODE (x) == SUBREG) x = SUBREG_REG (x); return (REG_P (x) && mips_regno_mode_ok_for_base_p (REGNO (x), mode, strict));}/* Return true if symbols of type SYMBOL_TYPE can directly address a value with mode MODE. This is used for both symbolic and LO_SUM addresses. */static boolmips_symbolic_address_p (enum mips_symbol_type symbol_type, enum machine_mode mode){ switch (symbol_type) { case SYMBOL_GENERAL: return !TARGET_MIPS16; case SYMBOL_SMALL_DATA: return true; case SYMBOL_CONSTANT_POOL: /* PC-relative addressing is only available for lw and ld. */ return GET_MODE_SIZE (mode) == 4 || GET_MODE_SIZE (mode) == 8; case SYMBOL_GOT_LOCAL: return true; case SYMBOL_GOT_GLOBAL: /* The address will have to be loaded from the GOT first. */ return false; case SYMBOL_GOTOFF_PAGE: case SYMBOL_GOTOFF_GLOBAL: case SYMBOL_GOTOFF_CALL: case SYMBOL_GOTOFF_LOADGP: case SYMBOL_64_HIGH: case SYMBOL_64_MID: case SYMBOL_64_LOW: return true; } gcc_unreachable ();}/* Return true if X is a valid address for machine mode MODE. If it is, fill in INFO appropriately. STRICT is true if we should only accept hard base registers. */static boolmips_classify_address (struct mips_address_info *info, rtx x, enum machine_mode mode, int strict){ switch (GET_CODE (x)) { case REG: case SUBREG: info->type = ADDRESS_REG; info->reg = x; info->offset = const0_rtx; return mips_valid_base_register_p (info->reg, mode, strict); case PLUS: info->type = ADDRESS_REG; info->reg = XEXP (x, 0); info->offset = XEXP (x, 1); return (mips_valid_base_register_p (info->reg, mode, strict) && const_arith_operand (info->offset, VOIDmode)); case LO_SUM: info->type = ADDRESS_LO_SUM; info->reg = XEXP (x, 0); info->offset = XEXP (x, 1); return (mips_valid_base_register_p (info->reg, mode, strict) && mips_symbolic_constant_p (info->offset, &info->symbol_type) && mips_symbolic_address_p (info->symbol_type, mode) && mips_lo_relocs[info->symbol_type] != 0); case CONST_INT: /* Small-integer addresses don't occur very often, but they are legitimate if $0 is a valid base register. */ info->type = ADDRESS_CONST_INT; return !TARGET_MIPS16 && SMALL_INT (x); case CONST: case LABEL_REF: case SYMBOL_REF: info->type = ADDRESS_SYMBOLIC; return (mips_symbolic_constant_p (x, &info->symbol_type) && mips_symbolic_address_p (info->symbol_type, mode) && !mips_split_p[info->symbol_type]); default: return false; }}/* Return the number of instructions needed to load a symbol of the given type into a register. If valid in an address, the same number of instructions are needed for loads and stores. Treat extended mips16 instructions as two instructions. */static intmips_symbol_insns (enum mips_symbol_type type){ switch (type) { case SYMBOL_GENERAL: /* In mips16 code, general symbols must be fetched from the constant pool. */ if (TARGET_MIPS16) return 0; /* When using 64-bit symbols, we need 5 preparatory instructions, such as: lui $at,%highest(symbol) daddiu $at,$at,%higher(symbol) dsll $at,$at,16 daddiu $at,$at,%hi(symbol) dsll $at,$at,16 The final address is then $at + %lo(symbol). With 32-bit symbols we just need a preparatory lui. */ return (ABI_HAS_64BIT_SYMBOLS ? 6 : 2); case SYMBOL_SMALL_DATA: return 1; case SYMBOL_CONSTANT_POOL: /* This case is for mips16 only. Assume we'll need an extended instruction. */ return 2; case SYMBOL_GOT_LOCAL: case SYMBOL_GOT_GLOBAL: /* Unless -funit-at-a-time is in effect, we can't be sure whether the local/global classification is accurate. See override_options for details. The worst cases are: (1) For local symbols when generating o32 or o64 code. The assembler will use: lw $at,%got(symbol) nop ...and the final address will be $at + %lo(symbol). (2) For global symbols when -mxgot. The assembler will use: lui $at,%got_hi(symbol) (d)addu $at,$at,$gp ...and the final address will be $at + %got_lo(symbol). */ return 3; case SYMBOL_GOTOFF_PAGE: case SYMBOL_GOTOFF_GLOBAL: case SYMBOL_GOTOFF_CALL: case SYMBOL_GOTOFF_LOADGP: case SYMBOL_64_HIGH: case SYMBOL_64_MID: case SYMBOL_64_LOW: /* Check whether the offset is a 16- or 32-bit value. */ return mips_split_p[type] ? 2 : 1; } gcc_unreachable ();}/* Return true if X is a legitimate $sp-based address for mode MDOE. */boolmips_stack_address_p (rtx x, enum machine_mode mode){ struct mips_address_info addr; return (mips_classify_address (&addr, x, mode, false) && addr.type == ADDRESS_REG && addr.reg == stack_pointer_rtx);}/* Return true if a value at OFFSET bytes from BASE can be accessed using an unextended mips16 instruction. MODE is the mode of the value. Usually the offset in an unextended instruction is a 5-bit field. The offset is unsigned and shifted left once for HIs, twice for SIs, and so on. An exception is SImode accesses off the stack pointer, which have an 8-bit immediate field. */static boolmips16_unextended_reference_p (enum machine_mode mode, rtx base, rtx offset){ if (TARGET_MIPS16 && GET_CODE (offset) == CONST_INT && INTVAL (offset) >= 0 && (INTVAL (offset) & (GET_MODE_SIZE (mode) - 1)) == 0)
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -