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

📄 mips.c

📁 gcc3.2.1源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
{  if (GET_CODE (op) == CONST_INT && SMALL_INT_UNSIGNED (op))    return 1;  return register_operand (op, mode);}/* Return truth value of whether OP can be used as an operands   where a 16 bit integer is needed  */intarith_operand (op, mode)     rtx op;     enum machine_mode mode;{  if (GET_CODE (op) == CONST_INT && SMALL_INT (op))    return 1;  /* On the mips16, a GP relative value is a signed 16 bit offset.  */  if (TARGET_MIPS16 && GET_CODE (op) == CONST && mips16_gp_offset_p (op))    return 1;  return register_operand (op, mode);}/* Return truth value of whether OP can be used as an operand in a two   address arithmetic insn (such as set 123456,%o4) of mode MODE.  */intarith32_operand (op, mode)     rtx op;     enum machine_mode mode;{  if (GET_CODE (op) == CONST_INT)    return 1;  return register_operand (op, mode);}/* Return truth value of whether OP is an integer which fits in 16 bits.  */intsmall_int (op, mode)     rtx op;     enum machine_mode mode ATTRIBUTE_UNUSED;{  return (GET_CODE (op) == CONST_INT && SMALL_INT (op));}/* Return truth value of whether OP is a 32 bit integer which is too big to   be loaded with one instruction.  */intlarge_int (op, mode)     rtx op;     enum machine_mode mode ATTRIBUTE_UNUSED;{  HOST_WIDE_INT value;  if (GET_CODE (op) != CONST_INT)    return 0;  value = INTVAL (op);  /* ior reg,$r0,value */  if ((value & ~ ((HOST_WIDE_INT) 0x0000ffff)) == 0)    return 0;  /* subu reg,$r0,value */  if (((unsigned HOST_WIDE_INT) (value + 32768)) <= 32767)    return 0;  /* lui reg,value>>16 */  if ((value & 0x0000ffff) == 0)    return 0;  return 1;}/* Return truth value of whether OP is a register or the constant 0.   In mips16 mode, we only accept a register, since the mips16 does   not have $0.  */intreg_or_0_operand (op, mode)     rtx op;     enum machine_mode mode;{  switch (GET_CODE (op))    {    case CONST_INT:      if (TARGET_MIPS16)	return 0;      return INTVAL (op) == 0;    case CONST_DOUBLE:      if (TARGET_MIPS16)	return 0;      return op == CONST0_RTX (mode);    case REG:    case SUBREG:      return register_operand (op, mode);    default:      break;    }  return 0;}/* Return truth value of whether OP is a register or the constant 0,   even in mips16 mode.  */inttrue_reg_or_0_operand (op, mode)     rtx op;     enum machine_mode mode;{  switch (GET_CODE (op))    {    case CONST_INT:      return INTVAL (op) == 0;    case CONST_DOUBLE:      return op == CONST0_RTX (mode);    case REG:    case SUBREG:      return register_operand (op, mode);    default:      break;    }  return 0;}/* Return truth value if a CONST_DOUBLE is ok to be a legitimate constant.  */intmips_const_double_ok (op, mode)     rtx op;     enum machine_mode mode;{  REAL_VALUE_TYPE d;  if (GET_CODE (op) != CONST_DOUBLE)    return 0;  if (mode == VOIDmode)    return 1;  if (mode != SFmode && mode != DFmode)    return 0;  if (op == CONST0_RTX (mode))    return 1;  /* ??? li.s does not work right with SGI's Irix 6 assembler.  */  if (mips_abi != ABI_32 && mips_abi != ABI_O64 && mips_abi != ABI_EABI)    return 0;  REAL_VALUE_FROM_CONST_DOUBLE (d, op);  if (REAL_VALUE_ISNAN (d))    return FALSE;  if (REAL_VALUE_NEGATIVE (d))    d = REAL_VALUE_NEGATE (d);  if (mode == DFmode)    {      if (REAL_VALUES_LESS (d, dfhigh)	  && REAL_VALUES_LESS (dflow, d))	return 1;    }  else    {      if (REAL_VALUES_LESS (d, sfhigh)	  && REAL_VALUES_LESS (sflow, d))	return 1;    }  return 0;}/* Accept the floating point constant 1 in the appropriate mode.  */intconst_float_1_operand (op, mode)     rtx op;     enum machine_mode mode;{  REAL_VALUE_TYPE d;  static REAL_VALUE_TYPE onedf;  static REAL_VALUE_TYPE onesf;  static int one_initialized;  if (GET_CODE (op) != CONST_DOUBLE      || mode != GET_MODE (op)      || (mode != DFmode && mode != SFmode))    return 0;  REAL_VALUE_FROM_CONST_DOUBLE (d, op);  /* We only initialize these values if we need them, since we will     never get called unless mips_isa >= 4.  */  if (! one_initialized)    {      onedf = REAL_VALUE_ATOF ("1.0", DFmode);      onesf = REAL_VALUE_ATOF ("1.0", SFmode);      one_initialized = 1;    }  if (mode == DFmode)    return REAL_VALUES_EQUAL (d, onedf);  else    return REAL_VALUES_EQUAL (d, onesf);}/* Return true if a memory load or store of REG plus OFFSET in MODE   can be represented in a single word on the mips16.  */static intmips16_simple_memory_operand (reg, offset, mode)     rtx reg;     rtx offset;     enum machine_mode mode;{  unsigned int size;  int off;  if (mode == BLKmode)    {      /* We can't tell, because we don't know how the value will         eventually be accessed.  Returning 0 here does no great         harm; it just prevents some possible instruction scheduling.  */      return 0;    }  size = GET_MODE_SIZE (mode);  if (INTVAL (offset) % size != 0)    return 0;  if (REGNO (reg) == STACK_POINTER_REGNUM && GET_MODE_SIZE (mode) == 4)    off = 0x100;  else    off = 0x20;  if (INTVAL (offset) >= 0 && INTVAL (offset) < (HOST_WIDE_INT)(off * size))    return 1;  return 0;}/* Return truth value if a memory operand fits in a single instruction   (ie, register + small offset).  */intsimple_memory_operand (op, mode)     rtx op;     enum machine_mode mode;{  rtx addr, plus0, plus1;  /* Eliminate non-memory operations */  if (GET_CODE (op) != MEM)    return 0;  /* dword operations really put out 2 instructions, so eliminate them.  */  /* ??? This isn't strictly correct.  It is OK to accept multiword modes     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 in current_frame_info.  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)	  && current_frame_info.insns_len > 0)	{	  long size;	  size = current_frame_info.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));}

⌨️ 快捷键说明

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