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

📄 mips.c

📁 GUN开源阻止下的编译器GCC
💻 C
📖 第 1 页 / 共 5 页
字号:
	    ret = "sd\t%.,%0";	  else	    {	      operands[2] = adj_offsettable_operand (op0, 4);	      ret = "sw\t%.,%0\n\tsw\t%.,%2";	    }	}      if (TARGET_STATS)	mips_count_memory_refs (op0, 2);      if (ret != (char *)0 && MEM_VOLATILE_P (op0))	{	  int i = strlen (ret);	  if (i > sizeof (volatile_buffer) - sizeof ("%{%}"))	    abort ();	  	  sprintf (volatile_buffer, "%%{%s%%}", ret);	  ret = volatile_buffer;	}    }  if (ret == (char *)0)    {      abort_with_insn (insn, "Bad move");      return 0;    }  if (delay != DELAY_NONE)    return mips_fill_delay_slot (ret, delay, operands, insn);  return ret;}/* Provide the costs of an addressing mode that contains ADDR.   If ADDR is not a valid address, its cost is irrelevant.  */intmips_address_cost (addr)     rtx addr;{  switch (GET_CODE (addr))    {    default:      break;    case LO_SUM:    case HIGH:      return 1;    case LABEL_REF:      return 2;    case CONST:      {	rtx offset = const0_rtx;	addr = eliminate_constant_term (XEXP (addr, 0), &offset);	if (GET_CODE (addr) == LABEL_REF)	  return 2;	if (GET_CODE (addr) != SYMBOL_REF)	  return 4;	if (! SMALL_INT (offset))	  return 2;      }      /* fall through */    case SYMBOL_REF:      return SYMBOL_REF_FLAG (addr) ? 1 : 2;    case PLUS:      {	register rtx plus0 = XEXP (addr, 0);	register rtx plus1 = XEXP (addr, 1);	if (GET_CODE (plus0) != REG && GET_CODE (plus1) == REG)	  {	    plus0 = XEXP (addr, 1);	    plus1 = XEXP (addr, 0);	  }	if (GET_CODE (plus0) != REG)	  break;	switch (GET_CODE (plus1))	  {	  default:	    break;	  case CONST_INT:	    return (SMALL_INT (plus1) ? 1 : 2);	  case CONST:	  case SYMBOL_REF:	  case LABEL_REF:	  case HIGH:	  case LO_SUM:	    return mips_address_cost (plus1) + 1;	  }      }    }  return 4;}/* Return true if X is an address which needs a temporary register when    reloaded while generating PIC code.  */intpic_address_needs_scratch (x)     rtx x;{  /* An address which is a symbolic plus a non SMALL_INT needs a temp reg.  */  if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS      && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF      && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT      && ! SMALL_INT (XEXP (XEXP (x, 0), 1)))    return 1;  return 0;}/* Make normal rtx_code into something we can index from an array */static enum internal_testmap_test_to_internal_test (test_code)     enum rtx_code test_code;{  enum internal_test test = ITEST_MAX;  switch (test_code)    {    default:			break;    case EQ:  test = ITEST_EQ;  break;    case NE:  test = ITEST_NE;  break;    case GT:  test = ITEST_GT;  break;    case GE:  test = ITEST_GE;  break;    case LT:  test = ITEST_LT;  break;    case LE:  test = ITEST_LE;  break;    case GTU: test = ITEST_GTU; break;    case GEU: test = ITEST_GEU; break;    case LTU: test = ITEST_LTU; break;    case LEU: test = ITEST_LEU; break;    }  return test;}/* Generate the code to compare two integer values.  The return value is:   (reg:SI xx)		The pseudo register the comparison is in   (rtx)0	       	No register, generate a simple branch.   ??? This is called with result nonzero by the Scond patterns in   mips.md.  These patterns are called with a target in the mode of   the Scond instruction pattern.  Since this must be a constant, we   must use SImode.  This means that if RESULT is non-zero, it will   always be an SImode register, even if TARGET_64BIT is true.  We   cope with this by calling convert_move rather than emit_move_insn.   This will sometimes lead to an unnecessary extension of the result;   for example:   long long   foo (long long i)   {     return i < 5;   }   */rtxgen_int_relational (test_code, result, cmp0, cmp1, p_invert)     enum rtx_code test_code;	/* relational test (EQ, etc) */     rtx result;		/* result to store comp. or 0 if branch */     rtx cmp0;			/* first operand to compare */     rtx cmp1;			/* second operand to compare */     int *p_invert;		/* NULL or ptr to hold whether branch needs */				/* to reverse its test */{  struct cmp_info {    enum rtx_code test_code;	/* code to use in instruction (LT vs. LTU) */    int const_low;		/* low bound of constant we can accept */    int const_high;		/* high bound of constant we can accept */    int const_add;		/* constant to add (convert LE -> LT) */    int reverse_regs;		/* reverse registers in test */    int invert_const;		/* != 0 if invert value if cmp1 is constant */    int invert_reg;		/* != 0 if invert value if cmp1 is register */    int unsignedp;		/* != 0 for unsigned comparisons.  */  };  static struct cmp_info info[ (int)ITEST_MAX ] = {    { XOR,	 0,  65535,  0,	 0,  0,	 0, 0 },	/* EQ  */    { XOR,	 0,  65535,  0,	 0,  1,	 1, 0 },	/* NE  */    { LT,   -32769,  32766,  1,	 1,  1,	 0, 0 },	/* GT  */    { LT,   -32768,  32767,  0,	 0,  1,	 1, 0 },	/* GE  */    { LT,   -32768,  32767,  0,	 0,  0,	 0, 0 },	/* LT  */    { LT,   -32769,  32766,  1,	 1,  0,	 1, 0 },	/* LE  */    { LTU,  -32769,  32766,  1,	 1,  1,	 0, 1 },	/* GTU */    { LTU,  -32768,  32767,  0,	 0,  1,	 1, 1 },	/* GEU */    { LTU,  -32768,  32767,  0,	 0,  0,	 0, 1 },	/* LTU */    { LTU,  -32769,  32766,  1,	 1,  0,	 1, 1 },	/* LEU */  };  enum internal_test test;  enum machine_mode mode;  struct cmp_info *p_info;  int branch_p;  int eqne_p;  int invert;  rtx reg;  rtx reg2;  test = map_test_to_internal_test (test_code);  if (test == ITEST_MAX)    abort ();  p_info = &info[ (int)test ];  eqne_p = (p_info->test_code == XOR);  mode = GET_MODE (cmp0);  if (mode == VOIDmode)    mode = GET_MODE (cmp1);  /* Eliminate simple branches */  branch_p = (result == (rtx)0);  if (branch_p)    {      if (GET_CODE (cmp0) == REG || GET_CODE (cmp0) == SUBREG)	{	  /* Comparisons against zero are simple branches */	  if (GET_CODE (cmp1) == CONST_INT && INTVAL (cmp1) == 0)	    return (rtx)0;	  /* Test for beq/bne.  */	  if (eqne_p)	    return (rtx)0;	}      /* allocate a pseudo to calculate the value in.  */      result = gen_reg_rtx (mode);    }  /* Make sure we can handle any constants given to us.  */  if (GET_CODE (cmp0) == CONST_INT)    cmp0 = force_reg (mode, cmp0);  if (GET_CODE (cmp1) == CONST_INT)    {      HOST_WIDE_INT value = INTVAL (cmp1);      if (value < p_info->const_low	  || value > p_info->const_high	  /* ??? Why?  And why wasn't the similar code below modified too?  */	  || (TARGET_64BIT	      && HOST_BITS_PER_WIDE_INT < 64	      && p_info->const_add != 0	      && ((p_info->unsignedp		   ? ((unsigned HOST_WIDE_INT) (value + p_info->const_add)		      > INTVAL (cmp1))		   : (value + p_info->const_add) > INTVAL (cmp1))		  != (p_info->const_add > 0))))	cmp1 = force_reg (mode, cmp1);    }  /* See if we need to invert the result.  */  invert = (GET_CODE (cmp1) == CONST_INT)		? p_info->invert_const		: p_info->invert_reg;  if (p_invert != (int *)0)    {      *p_invert = invert;      invert = FALSE;    }  /* Comparison to constants, may involve adding 1 to change a LT into LE.     Comparison between two registers, may involve switching operands.  */  if (GET_CODE (cmp1) == CONST_INT)    {      if (p_info->const_add != 0)	{	  HOST_WIDE_INT new = INTVAL (cmp1) + p_info->const_add;	  /* If modification of cmp1 caused overflow,	     we would get the wrong answer if we follow the usual path;	     thus, x > 0xffffffffU would turn into x > 0U.  */	  if ((p_info->unsignedp	       ? (unsigned HOST_WIDE_INT) new > INTVAL (cmp1)	       : new > INTVAL (cmp1))	      != (p_info->const_add > 0))	    {	      /* This test is always true, but if INVERT is true then		 the result of the test needs to be inverted so 0 should		 be returned instead.  */	      emit_move_insn (result, invert ? const0_rtx : const_true_rtx);	      return result;	    }	  else	    cmp1 = GEN_INT (new);	}    }  else if (p_info->reverse_regs)    {      rtx temp = cmp0;      cmp0 = cmp1;      cmp1 = temp;    }  if (test == ITEST_NE && GET_CODE (cmp1) == CONST_INT && INTVAL (cmp1) == 0)    reg = cmp0;  else    {      reg = (invert || eqne_p) ? gen_reg_rtx (mode) : result;      convert_move (reg, gen_rtx (p_info->test_code, mode, cmp0, cmp1), 0);    }  if (test == ITEST_NE)    {      convert_move (result, gen_rtx (GTU, mode, reg, const0_rtx), 0);      invert = FALSE;    }  else if (test == ITEST_EQ)    {      reg2 = (invert) ? gen_reg_rtx (mode) : result;      convert_move (reg2, gen_rtx (LTU, mode, reg, const1_rtx), 0);      reg = reg2;    }  if (invert)    convert_move (result, gen_rtx (XOR, mode, reg, const1_rtx), 0);  return result;}/* Emit the common code for doing conditional branches.   operand[0] is the label to jump to.   The comparison operands are saved away by cmp{si,di,sf,df}.  */voidgen_conditional_branch (operands, test_code)     rtx operands[];     enum rtx_code test_code;{  static enum machine_mode mode_map[(int)CMP_MAX][(int)ITEST_MAX] = {    {				/* CMP_SI */      SImode,			/* eq  */      SImode,			/* ne  */      SImode,			/* gt  */      SImode,			/* ge  */      SImode,			/* lt  */      SImode,			/* le  */      SImode,			/* gtu */      SImode,			/* geu */      SImode,			/* ltu */      SImode,			/* leu */    },    {				/* CMP_DI */      DImode,			/* eq  */      DImode,			/* ne  */      DImode,			/* gt  */      DImode,			/* ge  */      DImode,			/* lt  */      DImode,			/* le  */      DImode,			/* gtu */      DImode,			/* geu */      DImode,			/* ltu */      DImode,			/* leu */    },    {				/* CMP_SF */      CC_FPmode,		/* eq  */      CC_REV_FPmode,		/* ne  */      CC_FPmode,		/* gt  */      CC_FPmode,		/* ge  */      CC_FPmode,		/* lt  */      CC_FPmode,		/* le  */      VOIDmode,			/* gtu */      VOIDmode,			/* geu */      VOIDmode,			/* ltu */      VOIDmode,			/* leu */    },    {				/* CMP_DF */      CC_FPmode,		/* eq  */      CC_REV_FPmode,		/* ne  */      CC_FPmode,		/* gt  */      CC_FPmode,		/* ge  */      CC_FPmode,		/* lt  */      CC_FPmode,		/* le  */      VOIDmode,			/* gtu */      VOIDmode,			/* geu */      VOIDmode,			/* ltu */      VOIDmode,			/* leu */    },  };  enum machine_mode mode;  enum cmp_type type	  = branch_type;  rtx cmp0		  = branch_cmp[0];  rtx cmp1		  = branch_cmp[1];  rtx label1		  = gen_rtx (LABEL_REF, VOIDmode, operands[0]);  rtx label2		  = pc_rtx;  rtx reg		  = (rtx)0;  int invert		  = 0;  enum internal_test test = map_test_to_internal_test (test_code);  if (test == ITEST_MAX)    {      mode = word_mode;      goto fail;    }  /* Get the machine mode to use (CCmode, CC_EQmode, CC_FPmode, or CC_REV_FPmode).  */  mode = mode_map[(int)type][(int)test];  if (mode == VOIDmode)    goto fail;  switch (type)    {    default:      goto fail;    case CMP_SI:    case CMP_DI:      reg = gen_int_relational (test_code, (rtx)0, cmp0, cmp1, &invert);      if (reg != (rtx)0)	{	  cmp0 = reg;	  cmp1 = const0_rtx;	  test_code = NE;	}      /* Make sure not non-zero constant if ==/!= */      else if (GET_CODE (cmp1) == CONST_INT && INTVAL (cmp1) != 0)	cmp1 = force_reg (mode, cmp1);      break;    case CMP_DF:    case CMP_SF:      {	rtx reg = gen_rtx (REG, mode, FPSW_REGNUM);	emit_insn (gen_rtx (SET, VOIDmode, reg, gen_rtx (test_code, mode, cmp0, cmp1)));	cmp0 = reg;	cmp1 = const0_rtx;	test_code = NE;      }      break;    }  /* Generate the jump */  if (invert)    {      label2 = label1;      label1 = pc_rtx;    }  emit_jump_insn (gen_rtx (SET, VOIDmode,			   pc_rtx,			   gen_rtx (IF_THEN_ELSE, VOIDmode,				    gen_rtx (test_code, mode, cmp0, cmp1),				    label1,				    label2)));  return;fail:  abort_with_insn (gen_rtx (test_code, mode, cmp0, cmp1), "bad test");}#if 0/* Internal code to generate the load and store of one word/short/byte.   The load is emitted directly, and the store insn is returned.  */#define UNITS_PER_MIPS_DWORD	8#define UNITS_PER_MIPS_WORD	4#define UNITS_PER_MIPS_HWORD	2static rtxblock_move_load_store (dest_reg, src_reg, p_bytes, p_offset, align, orig_src)     rtx src_reg;		/* register holding source memory address */     rtx dest_reg;		/* register holding dest. memory address */     int *p_bytes;		/* pointer to # bytes remaining */     int *p_offset;		/* pointer to current offset */     int align;			/* alignment */     rtx orig_src;		/* original source for making a reg note */{  int bytes;			/* # bytes remaining */  int offset;			/* offset to use */  int size;			/* size in bytes of load/store */  enum machine_mode mode;	/* mode to use for load/store */  rtx reg;			/* temporary register */  rtx src_addr;			/* source address */  rtx dest_addr;		/* destination address */  rtx insn;			/* insn of the load */  rtx orig_src_addr;		/* original source address */  rtx (*load_func)();		/* function to generate load insn */  rtx (*store_func)();		/* function to generate destination insn */  bytes = *p_bytes;  if (bytes <= 0 || align <= 0)    abort ();  if (bytes >= UNITS_PER_MIPS_DWORD && align >= UNIS_PER_MIPS_DWORD)    {      mode = DImode;      size = UNITS_PER_MIPS_DWORD;      load_func = gen_movdi;      store_func = gen_movdi;    }  else if (bytes >= UNITS_PER_MIPS_WORD && align >= UNITS_PER_MIPS_WORD)    {      mode = SImode;      size = UNITS_PER_MIPS_WORD;      load_func = gen_movsi;      store_func = gen_movsi;    }

⌨️ 快捷键说明

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