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

📄 mips.c

📁 PSP用开发必装库GCC4.0.1
💻 C
📖 第 1 页 / 共 5 页
字号:
  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);}/* This function is used to implement LEGITIMIZE_ADDRESS.  If *XLOC can   be legitimized in a way that the generic machinery might not expect,   put the new address in *XLOC and return true.  MODE is the mode of   the memory being accessed.  */boolmips_legitimize_address (rtx *xloc, enum machine_mode mode){  enum mips_symbol_type symbol_type;  /* See if the address can split into a high part and a LO_SUM.  */  if (mips_symbolic_constant_p (*xloc, &symbol_type)      && mips_symbolic_address_p (symbol_type, mode)      && mips_split_p[symbol_type])    {      *xloc = mips_split_symbol (0, *xloc);      return true;    }  if (GET_CODE (*xloc) == PLUS && GET_CODE (XEXP (*xloc, 1)) == CONST_INT)    {      /* Handle REG + CONSTANT using mips_add_offset.  */      rtx reg;      reg = XEXP (*xloc, 0);      if (!mips_valid_base_register_p (reg, mode, 0))	reg = copy_to_mode_reg (Pmode, reg);      *xloc = mips_add_offset (0, reg, INTVAL (XEXP (*xloc, 1)));      return true;    }  return false;}/* Subroutine of mips_build_integer (with the same interface).   Assume that the final action in the sequence should be a left shift.  */static unsigned intmips_build_shift (struct mips_integer_op *codes, HOST_WIDE_INT value){  unsigned int i, shift;  /* Shift VALUE right until its lowest bit is set.  Shift arithmetically     since signed numbers are easier to load than unsigned ones.  */  shift = 0;  while ((value & 1) == 0)    value /= 2, shift++;  i = mips_build_integer (codes, value);  codes[i].code = ASHIFT;  codes[i].value = shift;  return i + 1;}/* As for mips_build_shift, but assume that the final action will be   an IOR or PLUS operation.  */static unsigned intmips_build_lower (struct mips_integer_op *codes, unsigned HOST_WIDE_INT value){  unsigned HOST_WIDE_INT high;  unsigned int i;  high = value & ~(unsigned HOST_WIDE_INT) 0xffff;  if (!LUI_OPERAND (high) && (value & 0x18000) == 0x18000)    {      /* The constant is too complex to load with a simple lui/ori pair	 so our goal is to clear as many trailing zeros as possible.	 In this case, we know bit 16 is set and that the low 16 bits	 form a negative number.  If we subtract that number from VALUE,	 we will clear at least the lowest 17 bits, maybe more.  */      i = mips_build_integer (codes, CONST_HIGH_PART (value));      codes[i].code = PLUS;      codes[i].value = CONST_LOW_PART (value);    }  else    {      i = mips_build_integer (codes, high);      codes[i].code = IOR;      codes[i].value = value & 0xffff;    }  return i + 1;}/* Fill CODES with a sequence of rtl operations to load VALUE.   Return the number of operations needed.  */static unsigned intmips_build_integer (struct mips_integer_op *codes,		    unsigned HOST_WIDE_INT value){  if (SMALL_OPERAND (value)      || SMALL_OPERAND_UNSIGNED (value)      || LUI_OPERAND (value))    {      /* The value can be loaded with a single instruction.  */      codes[0].code = UNKNOWN;      codes[0].value = value;      return 1;    }  else if ((value & 1) != 0 || LUI_OPERAND (CONST_HIGH_PART (value)))    {      /* Either the constant is a simple LUI/ORI combination or its	 lowest bit is set.  We don't want to shift in this case.  */      return mips_build_lower (codes, value);    }  else if ((value & 0xffff) == 0)    {      /* The constant will need at least three actions.  The lowest	 16 bits are clear, so the final action will be a shift.  */      return mips_build_shift (codes, value);    }  else    {      /* The final action could be a shift, add or inclusive OR.	 Rather than use a complex condition to select the best	 approach, try both mips_build_shift and mips_build_lower	 and pick the one that gives the shortest sequence.	 Note that this case is only used once per constant.  */      struct mips_integer_op alt_codes[MIPS_MAX_INTEGER_OPS];      unsigned int cost, alt_cost;      cost = mips_build_shift (codes, value);      alt_cost = mips_build_lower (alt_codes, value);      if (alt_cost < cost)	{	  memcpy (codes, alt_codes, alt_cost * sizeof (codes[0]));	  cost = alt_cost;	}

⌨️ 快捷键说明

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