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

📄 mips.c

📁 gcc3.2.1源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* Return nonzero if the code of this rtx pattern is EQ or NE.  */intequality_op (op, mode)     rtx op;     enum machine_mode mode;{  if (mode != GET_MODE (op))    return 0;  return GET_CODE (op) == EQ || GET_CODE (op) == NE;}/* Return nonzero if the code is a relational operations (EQ, LE, etc.) */intcmp_op (op, mode)     rtx op;     enum machine_mode mode;{  if (mode != GET_MODE (op))    return 0;  return GET_RTX_CLASS (GET_CODE (op)) == '<';}/* Return nonzero if the code is a relational operation suitable for a   conditional trap instructuion (only EQ, NE, LT, LTU, GE, GEU).   We need this in the insn that expands `trap_if' in order to prevent   combine from erroneously altering the condition.  */inttrap_cmp_op (op, mode)     rtx op;     enum machine_mode mode;{  if (mode != GET_MODE (op))    return 0;  switch (GET_CODE (op))    {    case EQ:    case NE:    case LT:    case LTU:    case GE:    case GEU:      return 1;    default:      return 0;    }}/* Return nonzero if the operand is either the PC or a label_ref.  */intpc_or_label_operand (op, mode)     rtx op;     enum machine_mode mode ATTRIBUTE_UNUSED;{  if (op == pc_rtx)    return 1;  if (GET_CODE (op) == LABEL_REF)    return 1;  return 0;}/* Test for a valid operand for a call instruction.   Don't allow the arg pointer register or virtual regs   since they may change into reg + const, which the patterns   can't handle yet.  */intcall_insn_operand (op, mode)     rtx op;     enum machine_mode mode ATTRIBUTE_UNUSED;{  return (CONSTANT_ADDRESS_P (op)	  || (GET_CODE (op) == REG && op != arg_pointer_rtx	      && ! (REGNO (op) >= FIRST_PSEUDO_REGISTER		    && REGNO (op) <= LAST_VIRTUAL_REGISTER)));}/* Return nonzero if OPERAND is valid as a source operand for a move   instruction.  */intmove_operand (op, mode)     rtx op;     enum machine_mode mode;{  /* Accept any general operand after reload has started; doing so     avoids losing if reload does an in-place replacement of a register     with a SYMBOL_REF or CONST.  */  return (general_operand (op, mode)	  && (! (mips_split_addresses && mips_check_split (op, mode))	      || reload_in_progress || reload_completed)	  && ! (TARGET_MIPS16		&& GET_CODE (op) == SYMBOL_REF		&& ! mips16_constant (op, mode, 1, 0)));}/* Return nonzero if OPERAND is valid as a source operand for movdi.   This accepts not only general_operand, but also sign extended   constants and registers.  We need to accept sign extended constants   in case a sign extended register which is used in an expression,   and is equivalent to a constant, is spilled.  */intmovdi_operand (op, mode)     rtx op;     enum machine_mode mode;{  if (TARGET_64BIT      && mode == DImode      && GET_CODE (op) == SIGN_EXTEND      && GET_MODE (op) == DImode      && (GET_MODE (XEXP (op, 0)) == SImode	  || (GET_CODE (XEXP (op, 0)) == CONST_INT	      && GET_MODE (XEXP (op, 0)) == VOIDmode))      && (register_operand (XEXP (op, 0), SImode)	  || immediate_operand (XEXP (op, 0), SImode)))    return 1;  return (general_operand (op, mode)	  && ! (TARGET_MIPS16		&& GET_CODE (op) == SYMBOL_REF		&& ! mips16_constant (op, mode, 1, 0)));}/* Like register_operand, but when in 64 bit mode also accept a sign   extend of a 32 bit register, since the value is known to be already   sign extended.  */intse_register_operand (op, mode)     rtx op;     enum machine_mode mode;{  if (TARGET_64BIT      && mode == DImode      && GET_CODE (op) == SIGN_EXTEND      && GET_MODE (op) == DImode      && GET_MODE (XEXP (op, 0)) == SImode      && register_operand (XEXP (op, 0), SImode))    return 1;  return register_operand (op, mode);}/* Like reg_or_0_operand, but when in 64 bit mode also accept a sign   extend of a 32 bit register, since the value is known to be already   sign extended.  */intse_reg_or_0_operand (op, mode)     rtx op;     enum machine_mode mode;{  if (TARGET_64BIT      && mode == DImode      && GET_CODE (op) == SIGN_EXTEND      && GET_MODE (op) == DImode      && GET_MODE (XEXP (op, 0)) == SImode      && register_operand (XEXP (op, 0), SImode))    return 1;  return reg_or_0_operand (op, mode);}/* Like uns_arith_operand, but when in 64 bit mode also accept a sign   extend of a 32 bit register, since the value is known to be already   sign extended.  */intse_uns_arith_operand (op, mode)     rtx op;     enum machine_mode mode;{  if (TARGET_64BIT      && mode == DImode      && GET_CODE (op) == SIGN_EXTEND      && GET_MODE (op) == DImode      && GET_MODE (XEXP (op, 0)) == SImode      && register_operand (XEXP (op, 0), SImode))    return 1;  return uns_arith_operand (op, mode);}/* Like arith_operand, but when in 64 bit mode also accept a sign   extend of a 32 bit register, since the value is known to be already   sign extended.  */intse_arith_operand (op, mode)     rtx op;     enum machine_mode mode;{  if (TARGET_64BIT      && mode == DImode      && GET_CODE (op) == SIGN_EXTEND      && GET_MODE (op) == DImode      && GET_MODE (XEXP (op, 0)) == SImode      && register_operand (XEXP (op, 0), SImode))    return 1;  return arith_operand (op, mode);}/* Like nonmemory_operand, but when in 64 bit mode also accept a sign   extend of a 32 bit register, since the value is known to be already   sign extended.  */intse_nonmemory_operand (op, mode)     rtx op;     enum machine_mode mode;{  if (TARGET_64BIT      && mode == DImode      && GET_CODE (op) == SIGN_EXTEND      && GET_MODE (op) == DImode      && GET_MODE (XEXP (op, 0)) == SImode      && register_operand (XEXP (op, 0), SImode))    return 1;  return nonmemory_operand (op, mode);}/* Like nonimmediate_operand, but when in 64 bit mode also accept a   sign extend of a 32 bit register, since the value is known to be   already sign extended.  */intse_nonimmediate_operand (op, mode)     rtx op;     enum machine_mode mode;{  if (TARGET_64BIT      && mode == DImode      && GET_CODE (op) == SIGN_EXTEND      && GET_MODE (op) == DImode      && GET_MODE (XEXP (op, 0)) == SImode      && register_operand (XEXP (op, 0), SImode))    return 1;  return nonimmediate_operand (op, mode);}/* Accept any operand that can appear in a mips16 constant table   instruction.  We can't use any of the standard operand functions   because for these instructions we accept values that are not   accepted by LEGITIMATE_CONSTANT, such as arbitrary SYMBOL_REFs.  */intconsttable_operand (op, mode)     rtx op;     enum machine_mode mode ATTRIBUTE_UNUSED;{  return CONSTANT_P (op);}/* Return nonzero if we split the address into high and low parts.  *//* ??? We should also handle reg+array somewhere.  We get four   instructions currently, lui %hi/addui %lo/addui reg/lw.  Better is   lui %hi/addui reg/lw %lo.  Fixing GO_IF_LEGITIMATE_ADDRESS to accept   (plus (reg) (symbol_ref)) doesn't work because the SYMBOL_REF is broken   out of the address, then we have 4 instructions to combine.  Perhaps   add a 3->2 define_split for combine.  *//* ??? We could also split a CONST_INT here if it is a large_int().   However, it doesn't seem to be very useful to have %hi(constant).   We would be better off by doing the masking ourselves and then putting   the explicit high part of the constant in the RTL.  This will give better   optimization.  Also, %hi(constant) needs assembler changes to work.   There is already a define_split that does this.  */intmips_check_split (address, mode)     rtx address;     enum machine_mode mode;{  /* ??? This is the same check used in simple_memory_operand.     We use it here because LO_SUM is not offsettable.  */  if (GET_MODE_SIZE (mode) > (unsigned) UNITS_PER_WORD)    return 0;  if ((GET_CODE (address) == SYMBOL_REF && ! SYMBOL_REF_FLAG (address))      || (GET_CODE (address) == CONST	  && GET_CODE (XEXP (XEXP (address, 0), 0)) == SYMBOL_REF	  && ! SYMBOL_REF_FLAG (XEXP (XEXP (address, 0), 0)))      || GET_CODE (address) == LABEL_REF)    return 1;  return 0;}/* This function is used to implement REG_MODE_OK_FOR_BASE_P.  */intmips_reg_mode_ok_for_base_p (reg, mode, strict)     rtx reg;     enum machine_mode mode;     int strict;{  return (strict	  ? REGNO_MODE_OK_FOR_BASE_P (REGNO (reg), mode)	  : GP_REG_OR_PSEUDO_NONSTRICT_P (REGNO (reg), mode));}/* This function is used to implement GO_IF_LEGITIMATE_ADDRESS.  It   returns a nonzero value if XINSN is a legitimate address for a   memory operand of the indicated MODE.  STRICT is non-zero if this   function is called during reload.  */intmips_legitimate_address_p (mode, xinsn, strict)     enum machine_mode mode;     rtx xinsn;     int strict;{  if (TARGET_DEBUG_B_MODE)    {      GO_PRINTF2 ("\n========== GO_IF_LEGITIMATE_ADDRESS, %sstrict\n",		  strict ? "" : "not ");      GO_DEBUG_RTX (xinsn);    }  /* Check for constant before stripping off SUBREG, so that we don't     accept (subreg (const_int)) which will fail to reload.  */  if (CONSTANT_ADDRESS_P (xinsn)      && ! (mips_split_addresses && mips_check_split (xinsn, mode))      && (! TARGET_MIPS16 || mips16_constant (xinsn, mode, 1, 0)))    return 1;  while (GET_CODE (xinsn) == SUBREG)    xinsn = SUBREG_REG (xinsn);  /* The mips16 can only use the stack pointer as a base register when     loading SImode or DImode values.  */  if (GET_CODE (xinsn) == REG      && mips_reg_mode_ok_for_base_p (xinsn, mode, strict))    return 1;  if (GET_CODE (xinsn) == LO_SUM && mips_split_addresses)    {      register rtx xlow0 = XEXP (xinsn, 0);      register rtx xlow1 = XEXP (xinsn, 1);      while (GET_CODE (xlow0) == SUBREG)	xlow0 = SUBREG_REG (xlow0);      if (GET_CODE (xlow0) == REG	  && mips_reg_mode_ok_for_base_p (xlow0, mode, strict)	  && mips_check_split (xlow1, mode))	return 1;    }  if (GET_CODE (xinsn) == PLUS)    {      register rtx xplus0 = XEXP (xinsn, 0);      register rtx xplus1 = XEXP (xinsn, 1);      register enum rtx_code code0;      register enum rtx_code code1;      while (GET_CODE (xplus0) == SUBREG)	xplus0 = SUBREG_REG (xplus0);      code0 = GET_CODE (xplus0);      while (GET_CODE (xplus1) == SUBREG)	xplus1 = SUBREG_REG (xplus1);      code1 = GET_CODE (xplus1);      /* The mips16 can only use the stack pointer as a base register         when loading SImode or DImode values.  */      if (code0 == REG	  && mips_reg_mode_ok_for_base_p (xplus0, mode, strict))	{	  if (code1 == CONST_INT && SMALL_INT (xplus1))	    return 1;	  /* On the mips16, we represent GP relative offsets in RTL.             These are 16 bit signed values, and can serve as register             offsets.  */	  if (TARGET_MIPS16	      && mips16_gp_offset_p (xplus1))	    return 1;	  /* For some code sequences, you actually get better code by	     pretending that the MIPS supports an address mode of a	     constant address + a register, even though the real	     machine doesn't support it.  This is because the	     assembler can use $r1 to load just the high 16 bits, add	     in the register, and fold the low 16 bits into the memory	     reference, whereas the compiler generates a 4 instruction	     sequence.  On the other hand, CSE is not as effective.	     It would be a win to generate the lui directly, but the	     MIPS assembler does not have syntax to generate the	     appropriate relocation.  */	  /* Also accept CONST_INT addresses here, so no else.  */	  /* Reject combining an embedded PIC text segment reference	     with a register.  That requires an additional	     instruction.  */          /* ??? Reject combining an address with a register for the MIPS	     64 bit ABI, because the SGI assembler can not handle this.  */	  if (!TARGET_DEBUG_A_MODE	      && (mips_abi == ABI_32		  || mips_abi == ABI_O64		  || mips_abi == ABI_EABI)	      && CONSTANT_ADDRESS_P (xplus1)	      && ! mips_split_addresses	      && (!TARGET_EMBEDDED_PIC		  || code1 != CONST		  || GET_CODE (XEXP (xplus1, 0)) != MINUS)	      /* When assembling for machines with 64 bit registers,	         the assembler will sign-extend the constant "foo"		 in "la x, foo(x)" yielding the wrong result for:	         (set (blah:DI) (plus x y)).  */	      && (!TARGET_64BIT		  || (code1 == CONST_INT		      && trunc_int_for_mode (INTVAL (xplus1),					     SImode) == INTVAL (xplus1)))	      && !TARGET_MIPS16)	    return 1;	}    }  if (TARGET_DEBUG_B_MODE)    GO_PRINTF ("Not a legitimate address\n");  /* The address was not legitimate.  */  return 0;}/* We need a lot of little routines to check constant values on the   mips16.  These are used to figure out how long the instruction will   be.  It would be much better to do this using constraints, but   there aren't nearly enough letters available.  */static intm16_check_op (op, low, high, mask)     rtx op;     int low;     int high;     int mask;{  return (GET_CODE (op) == CONST_INT	  && INTVAL (op) >= low	  && INTVAL (op) <= high	  && (INTVAL (op) & mask) == 0);}intm16_uimm3_b (op, mode)     rtx op;     enum machine_mode mode ATTRIBUTE_UNUSED;{  return m16_check_op (op, 0x1, 0x8, 0);}intm16_simm4_1 (op, mode)     rtx op;     enum machine_mode mode ATTRIBUTE_UNUSED;{  return m16_check_op (op, - 0x8, 0x7, 0);}intm16_nsimm4_1 (op, mode)     rtx op;     enum machine_mode mode ATTRIBUTE_UNUSED;{  return m16_check_op (op, - 0x7, 0x8, 0);}intm16_simm5_1 (op, mode)     rtx op;     enum machine_mode mode ATTRIBUTE_UNUSED;{  return m16_check_op (op, - 0x10, 0xf, 0);}

⌨️ 快捷键说明

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