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

📄 mips.c

📁 linux下编程用 编译软件
💻 C
📖 第 1 页 / 共 5 页
字号:
      /* 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:    case SYMBOL_TLSGD:    case SYMBOL_TLSLDM:    case SYMBOL_DTPREL:    case SYMBOL_GOTTPREL:    case SYMBOL_TPREL:      /* Check whether the offset is a 16- or 32-bit value.  */      return mips_split_p[type] ? 2 : 1;    case SYMBOL_TLS:      /* We don't treat a bare TLS symbol as a constant.  */      return 0;    }  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)    {      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);}/* Emit a call to __tls_get_addr.  SYM is the TLS symbol we are   referencing, and TYPE is the symbol type to use (either global   dynamic or local dynamic).  V0 is an RTX for the return value   location.  The entire insn sequence is returned.  */static GTY(()) rtx mips_tls_symbol;static rtxmips_call_tls_get_addr (rtx sym, enum mips_symbol_type type, rtx v0){  rtx insn, loc, tga, a0;  a0 = gen_rtx_REG (Pmode, GP_ARG_FIRST);  if (!mips_tls_symbol)    mips_tls_symbol = init_one_libfunc ("__tls_get_addr");  loc = mips_unspec_address (sym, type);  start_sequence ();  emit_insn (gen_rtx_SET (Pmode, a0,			  gen_rtx_LO_SUM (Pmode, pic_offset_table_rtx, loc)));  tga = gen_rtx_MEM (Pmode, mips_tls_symbol);  insn = emit_call_insn (gen_call_value (v0, tga, const0_rtx, const0_rtx));  CONST_OR_PURE_CALL_P (insn) = 1;  use_reg (&CALL_INSN_FUNCTION_USAGE (insn), v0);  use_reg (&CALL_INSN_FUNCTION_USAGE (insn), a0);

⌨️ 快捷键说明

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