⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mips.c

📁 PSP用开发必装库GCC4.0.1
💻 C
📖 第 1 页 / 共 5 页
字号:
struct gcc_target targetm = TARGET_INITIALIZER;/* Classify symbol X, which must be a SYMBOL_REF or a LABEL_REF.  */static enum mips_symbol_typemips_classify_symbol (rtx x){  if (GET_CODE (x) == LABEL_REF)    {      if (TARGET_MIPS16)	return SYMBOL_CONSTANT_POOL;      if (TARGET_ABICALLS)	return SYMBOL_GOT_LOCAL;      return SYMBOL_GENERAL;    }  gcc_assert (GET_CODE (x) == SYMBOL_REF);  if (CONSTANT_POOL_ADDRESS_P (x))    {      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;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -