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

📄 arm.c

📁 GUN开源阻止下的编译器GCC
💻 C
📖 第 1 页 / 共 5 页
字号:
/* Output a move between double words.   It must be REG<-REG, REG<-CONST_DOUBLE, REG<-CONST_INT, REG<-MEM   or MEM<-REG and all MEMs must be offsettable addresses.  */char *output_move_double (operands)     rtx *operands;{  enum rtx_code code0 = GET_CODE (operands[0]);  enum rtx_code code1 = GET_CODE (operands[1]);  rtx otherops[2];  if (code0 == REG)    {      int reg0 = REGNO (operands[0]);      otherops[0] = gen_rtx (REG, SImode, 1 + reg0);      if (code1 == REG)	{	  int reg1 = REGNO (operands[1]);	  if (reg1 == 12)	    abort();	  otherops[1] = gen_rtx (REG, SImode, 1 + reg1);	  /* Ensure the second source is not overwritten */	  if (reg0 == 1 + reg1)	    {	      output_asm_insn("mov%?\t%0, %1", otherops);	      output_asm_insn("mov%?\t%0, %1", operands);	    }	  else	    {	      output_asm_insn("mov%?\t%0, %1", operands);	      output_asm_insn("mov%?\t%0, %1", otherops);	    }	}      else if (code1 == CONST_DOUBLE)	{	  otherops[1] = gen_rtx (CONST_INT, VOIDmode,				 CONST_DOUBLE_HIGH (operands[1]));	  operands[1] = gen_rtx (CONST_INT, VOIDmode,				 CONST_DOUBLE_LOW (operands[1]));	  output_mov_immediate (operands, FALSE, "");	  output_mov_immediate (otherops, FALSE, "");	}      else if (code1 == CONST_INT)	{	  otherops[1] = const0_rtx;	  /* sign extend the intval into the high-order word */	  /* Note: output_mov_immediate may clobber operands[1], so we	     put this out first */	  if (INTVAL (operands[1]) < 0)	    output_asm_insn ("mvn%?\t%0, %1", otherops);	  else	    output_asm_insn ("mov%?\t%0, %1", otherops);	  output_mov_immediate (operands, FALSE, "");	}      else if (code1 == MEM)	{	  switch (GET_CODE (XEXP (operands[1], 0)))	    {	    case REG:	      /* Handle the simple case where address is [r, #0] more		 efficient.  */	      output_asm_insn ("ldm%?ia\t%m1, %M0", operands);	      break;  	    case PRE_INC:	      output_asm_insn ("add%?\t%m1, %m1, #8", operands);	      output_asm_insn ("ldm%?ia\t%m1, %M0", operands);	      break;	    case PRE_DEC:	      output_asm_insn ("sub%?\t%m1, %m1, #8", operands);	      output_asm_insn ("ldm%?ia\t%m1, %M0", operands);	      break;	    case POST_INC:	      output_asm_insn ("ldm%?ia\t%m1!, %M0", operands);	      break;	    case POST_DEC:	      output_asm_insn ("ldm%?ia\t%m1, %M0", operands);	      output_asm_insn ("sub%?\t%m1, %m1, #8", operands);	      break;	    default:	      otherops[1] = adj_offsettable_operand (operands[1], 4);	      /* Take care of overlapping base/data reg.  */	      if (reg_mentioned_p (operands[0], operands[1]))		{		  output_asm_insn ("ldr%?\t%0, %1", otherops);		  output_asm_insn ("ldr%?\t%0, %1", operands);		}	      else		{		  output_asm_insn ("ldr%?\t%0, %1", operands);		  output_asm_insn ("ldr%?\t%0, %1", otherops);		}	    }	}      else abort();  /* Constraints should prevent this */    }  else if (code0 == MEM && code1 == REG)    {      if (REGNO (operands[1]) == 12)	abort();      switch (GET_CODE (XEXP (operands[0], 0)))        {	case REG:	  output_asm_insn ("stm%?ia\t%m0, %M1", operands);	  break;        case PRE_INC:	  output_asm_insn ("add%?\t%m0, %m0, #8", operands);	  output_asm_insn ("stm%?ia\t%m0, %M1", operands);	  break;        case PRE_DEC:	  output_asm_insn ("sub%?\t%m0, %m0, #8", operands);	  output_asm_insn ("stm%?ia\t%m0, %M1", operands);	  break;        case POST_INC:	  output_asm_insn ("stm%?ia\t%m0!, %M1", operands);	  break;        case POST_DEC:	  output_asm_insn ("stm%?ia\t%m0, %M1", operands);	  output_asm_insn ("sub%?\t%m0, %m0, #8", operands);	  break;        default:	  otherops[0] = adj_offsettable_operand (operands[0], 4);	  otherops[1] = gen_rtx (REG, SImode, 1 + REGNO (operands[1]));	  output_asm_insn ("str%?\t%1, %0", operands);	  output_asm_insn ("str%?\t%1, %0", otherops);	}    }  else abort();  /* Constraints should prevent this */  return "";}/* Output an arbitrary MOV reg, #n.   OPERANDS[0] is a register.  OPERANDS[1] is a const_int.  */char *output_mov_immediate (operands)     rtx *operands;{  HOST_WIDE_INT n = INTVAL (operands[1]);  int n_ones = 0;  int i;  /* Try to use one MOV */  if (const_ok_for_arm (n))    {      output_asm_insn ("mov%?\t%0, %1", operands);      return "";    }  /* Try to use one MVN */  if (const_ok_for_arm (~n))    {      operands[1] = GEN_INT (~n);      output_asm_insn ("mvn%?\t%0, %1", operands);      return "";    }  /* If all else fails, make it out of ORRs or BICs as appropriate. */  for (i=0; i < 32; i++)    if (n & 1 << i)      n_ones++;  if (n_ones > 16)  /* Shorter to use MVN with BIC in this case. */    output_multi_immediate(operands, "mvn%?\t%0, %1", "bic%?\t%0, %0, %1", 1,			   ~n);  else    output_multi_immediate(operands, "mov%?\t%0, %1", "orr%?\t%0, %0, %1", 1,			   n);  return "";}/* Output an ADD r, s, #n where n may be too big for one instruction.  If   adding zero to one register, output nothing.  */char *output_add_immediate (operands)     rtx *operands;{  HOST_WIDE_INT n = INTVAL (operands[2]);  if (n != 0 || REGNO (operands[0]) != REGNO (operands[1]))    {      if (n < 0)	output_multi_immediate (operands,				"sub%?\t%0, %1, %2", "sub%?\t%0, %0, %2", 2,				-n);      else	output_multi_immediate (operands,				"add%?\t%0, %1, %2", "add%?\t%0, %0, %2", 2,				n);    }  return "";}/* Output a multiple immediate operation.   OPERANDS is the vector of operands referred to in the output patterns.   INSTR1 is the output pattern to use for the first constant.   INSTR2 is the output pattern to use for subsequent constants.   IMMED_OP is the index of the constant slot in OPERANDS.   N is the constant value.  */char *output_multi_immediate (operands, instr1, instr2, immed_op, n)     rtx *operands;     char *instr1, *instr2;     int immed_op;     HOST_WIDE_INT n;{#if HOST_BITS_PER_WIDE_INT > 32  n &= 0xffffffff;#endif  if (n == 0)    {      operands[immed_op] = const0_rtx;      output_asm_insn (instr1, operands); /* Quick and easy output */    }  else    {      int i;      char *instr = instr1;      /* Note that n is never zero here (which would give no output) */      for (i = 0; i < 32; i += 2)	{	  if (n & (3 << i))	    {	      operands[immed_op] = GEN_INT (n & (255 << i));	      output_asm_insn (instr, operands);	      instr = instr2;	      i += 6;	    }	}    }  return "";}/* Return the appropriate ARM instruction for the operation code.   The returned result should not be overwritten.  OP is the rtx of the   operation.  SHIFT_FIRST_ARG is TRUE if the first argument of the operator   was shifted.  */char *arithmetic_instr (op, shift_first_arg)     rtx op;     int shift_first_arg;{  switch (GET_CODE (op))    {    case PLUS:      return "add";    case MINUS:      return shift_first_arg ? "rsb" : "sub";    case IOR:      return "orr";    case XOR:      return "eor";    case AND:      return "and";    default:      abort ();    }}/* Ensure valid constant shifts and return the appropriate shift mnemonic   for the operation code.  The returned result should not be overwritten.   OP is the rtx code of the shift.   On exit, *AMOUNTP will be -1 if the shift is by a register, or a constant   shift. */static char *shift_op (op, amountp)     rtx op;     HOST_WIDE_INT *amountp;{  char *mnem;  enum rtx_code code = GET_CODE (op);  if (GET_CODE (XEXP (op, 1)) == REG || GET_CODE (XEXP (op, 1)) == SUBREG)    *amountp = -1;  else if (GET_CODE (XEXP (op, 1)) == CONST_INT)    *amountp = INTVAL (XEXP (op, 1));  else    abort ();  switch (code)    {    case ASHIFT:      mnem = "asl";      break;    case ASHIFTRT:      mnem = "asr";      break;    case LSHIFTRT:      mnem = "lsr";      break;    case ROTATERT:      mnem = "ror";      break;    case MULT:      /* We never have to worry about the amount being other than a	 power of 2, since this case can never be reloaded from a reg.  */      if (*amountp != -1)	*amountp = int_log2 (*amountp);      else	abort ();      return "asl";    default:      abort ();    }  if (*amountp != -1)    {      /* This is not 100% correct, but follows from the desire to merge	 multiplication by a power of 2 with the recognizer for a	 shift.  >=32 is not a valid shift for "asl", so we must try and	 output a shift that produces the correct arithmetical result.	 Using lsr #32 is identical except for the fact that the carry bit	 is not set correctly if we set the flags; but we never use the 	 carry bit from such an operation, so we can ignore that.  */      if (code == ROTATERT)	*amountp &= 31;		/* Rotate is just modulo 32 */      else if (*amountp != (*amountp & 31))	{	  if (code == ASHIFT)	    mnem = "lsr";	  *amountp = 32;	}      /* Shifts of 0 are no-ops.  */      if (*amountp == 0)	return NULL;    }	    return mnem;}/* Obtain the shift from the POWER of two. */HOST_WIDE_INTint_log2 (power)     HOST_WIDE_INT power;{  HOST_WIDE_INT shift = 0;  while (((1 << shift) & power) == 0)    {      if (shift > 31)	abort ();      shift++;    }  return shift;}/* Output a .ascii pseudo-op, keeping track of lengths.  This is because   /bin/as is horribly restrictive.  */voidoutput_ascii_pseudo_op (stream, p, len)     FILE *stream;     unsigned char *p;     int len;{  int i;  int len_so_far = 1000;  int chars_so_far = 0;  for (i = 0; i < len; i++)    {      register int c = p[i];      if (len_so_far > 50)	{	  if (chars_so_far)	    fputs ("\"\n", stream);	  fputs ("\t.ascii\t\"", stream);	  len_so_far = 0;	  arm_increase_location (chars_so_far);	  chars_so_far = 0;	}      if (c == '\"' || c == '\\')	{	  putc('\\', stream);	  len_so_far++;	}      if (c >= ' ' && c < 0177)	{	  putc (c, stream);	  len_so_far++;	}      else	{	  fprintf (stream, "\\%03o", c);	  len_so_far +=4;	}      chars_so_far++;    }  fputs ("\"\n", stream);  arm_increase_location (chars_so_far);}/* Try to determine whether a pattern really clobbers the link register.   This information is useful when peepholing, so that lr need not be pushed   if we combine a call followed by a return.   NOTE: This code does not check for side-effect expressions in a SET_SRC:   such a check should not be needed because these only update an existing   value within a register; the register must still be set elsewhere within   the function. */static intpattern_really_clobbers_lr (x)     rtx x;{  int i;    switch (GET_CODE (x))    {    case SET:      switch (GET_CODE (SET_DEST (x)))	{	case REG:	  return REGNO (SET_DEST (x)) == 14;        case SUBREG:	  if (GET_CODE (XEXP (SET_DEST (x), 0)) == REG)	    return REGNO (XEXP (SET_DEST (x), 0)) == 14;	  if (GET_CODE (XEXP (SET_DEST (x), 0)) == MEM)	    return 0;	  abort ();        default:	  return 0;        }    case PARALLEL:      for (i = 0; i < XVECLEN (x, 0); i++)	if (pattern_really_clobbers_lr (XVECEXP (x, 0, i)))	  return 1;      return 0;    case CLOBBER:      switch (GET_CODE (XEXP (x, 0)))        {	case REG:	  return REGNO (XEXP (x, 0)) == 14;        case SUBREG:	  if (GET_CODE (XEXP (XEXP (x, 0), 0)) == REG)	    return REGNO (XEXP (XEXP (x, 0), 0)) == 14;	  abort ();        default:	  return 0;        }    case UNSPEC:      return 1;    default:      return 0;    }}static intfunction_really_clobbers_lr (first)     rtx first;{  rtx insn, next;    for (insn = first; insn; insn = next_nonnote_insn (insn))    {      switch (GET_CODE (insn))        {	case BARRIER:	case NOTE:	case CODE_LABEL:	case JUMP_INSN:		/* Jump insns only change the PC (and conds) */	case INLINE_HEADER:	  break;        case INSN:	  if (pattern_really_clobbers_lr (PATTERN (insn)))	    return 1;	  break;        case CALL_INSN:	  /* Don't yet know how to handle those calls that are not to a 	     SYMBOL_REF */	  if (GET_CODE (PATTERN (insn)) != PARALLEL)	    abort ();	  switch (GET_CODE 

⌨️ 快捷键说明

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