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

📄 m32r.c

📁 gcc编译工具没有什么特别
💻 C
📖 第 1 页 / 共 5 页
字号:
	  abort ();	REAL_VALUE_FROM_CONST_DOUBLE (d, x);	REAL_VALUE_TO_DECIMAL (d, "%.20e", str);	fprintf (file, "%s", str);	return;      }    case 'B' : /* Bottom half */    case 'T' : /* Top half */      /* Output the argument to a `seth' insn (sets the Top half-word).	 For constants output arguments to a seth/or3 pair to set Top and	 Bottom halves.  For symbols output arguments to a seth/add3 pair to	 set Top and Bottom halves.  The difference exists because for	 constants seth/or3 is more readable but for symbols we need to use	 the same scheme as `ld' and `st' insns (16 bit addend is signed).  */      switch (GET_CODE (x))	{	case CONST_INT :	case CONST_DOUBLE :	  {	    rtx first, second;	    split_double (x, &first, &second);	    x = WORDS_BIG_ENDIAN ? second : first;	    fprintf (file,#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT		     "0x%x",#else		     "0x%lx",#endif		     (code == 'B'		      ? INTVAL (x) & 0xffff		      : (INTVAL (x) >> 16) & 0xffff));	  }	  return;	case CONST :	case SYMBOL_REF :	  if (code == 'B'	      && small_data_operand (x, VOIDmode))	    {	      fputs ("sda(", file);	      output_addr_const (file, x);	      fputc (')', file);	      return;	    }	  /* fall through */	case LABEL_REF :	  fputs (code == 'T' ? "shigh(" : "low(", file);	  output_addr_const (file, x);	  fputc (')', file);	  return;	default :	  output_operand_lossage ("invalid operand to %T/%B code");	  return;	}      break;    case 'U' :      /* ??? wip */      /* Output a load/store with update indicator if appropriate.  */      if (GET_CODE (x) == MEM)	{	  if (GET_CODE (XEXP (x, 0)) == PRE_INC	      || GET_CODE (XEXP (x, 0)) == PRE_DEC)	    fputs (".a", file);	}      else	output_operand_lossage ("invalid operand to %U code");      return;    case 'N' :      /* Print a constant value negated.  */      if (GET_CODE (x) == CONST_INT)	output_addr_const (file, GEN_INT (- INTVAL (x)));      else	output_operand_lossage ("invalid operand to %N code");      return;    case 'X' :      /* Print a const_int in hex.  Used in comments.  */      if (GET_CODE (x) == CONST_INT)	fprintf (file,#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT		 "0x%x",#else		 "0x%lx",#endif		 INTVAL (x));      return;    case '#' :      fputs (IMMEDIATE_PREFIX, file);      return;#if 0 /* ??? no longer used */    case '@' :      fputs (reg_names[SDA_REGNUM], file);      return;#endif    case 0 :      /* Do nothing special.  */      break;    default :      /* Unknown flag.  */      output_operand_lossage ("invalid operand output code");    }  switch (GET_CODE (x))    {    case REG :      fputs (reg_names[REGNO (x)], file);      break;    case MEM :      addr = XEXP (x, 0);      if (GET_CODE (addr) == PRE_INC)	{	  if (GET_CODE (XEXP (addr, 0)) != REG)	    abort ();	  fprintf (file, "@+%s", reg_names[REGNO (XEXP (addr, 0))]);	}      else if (GET_CODE (addr) == PRE_DEC)	{	  if (GET_CODE (XEXP (addr, 0)) != REG)	    abort ();	  fprintf (file, "@-%s", reg_names[REGNO (XEXP (addr, 0))]);	}      else if (GET_CODE (addr) == POST_INC)	{	  if (GET_CODE (XEXP (addr, 0)) != REG)	    abort ();	  fprintf (file, "@%s+", reg_names[REGNO (XEXP (addr, 0))]);	}      else	{	  fputs ("@(", file);	  output_address (XEXP (x, 0));	  fputc (')', file);	}      break;    case CONST_DOUBLE :      /* We handle SFmode constants here as output_addr_const doesn't.  */      if (GET_MODE (x) == SFmode)	{	  REAL_VALUE_TYPE d;	  long l;	  REAL_VALUE_FROM_CONST_DOUBLE (d, x);	  REAL_VALUE_TO_TARGET_SINGLE (d, l);	  fprintf (file, "0x%08lx", l);	  break;	}      /* Fall through.  Let output_addr_const deal with it.  */    default :      output_addr_const (file, x);      break;    }}/* Print a memory address as an operand to reference that memory location.  */voidm32r_print_operand_address (file, addr)     FILE * file;     rtx    addr;{  register rtx base;  register rtx index = 0;  int          offset = 0;  switch (GET_CODE (addr))    {    case REG :      fputs (reg_names[REGNO (addr)], file);      break;    case PLUS :      if (GET_CODE (XEXP (addr, 0)) == CONST_INT)	offset = INTVAL (XEXP (addr, 0)), base = XEXP (addr, 1);      else if (GET_CODE (XEXP (addr, 1)) == CONST_INT)	offset = INTVAL (XEXP (addr, 1)), base = XEXP (addr, 0);      else	base = XEXP (addr, 0), index = XEXP (addr, 1);      if (GET_CODE (base) == REG)	{	  /* Print the offset first (if present) to conform to the manual.  */	  if (index == 0)	    {	      if (offset != 0)		fprintf (file, "%d,", offset);	      fputs (reg_names[REGNO (base)], file);	    }	  /* The chip doesn't support this, but left in for generality.  */	  else if (GET_CODE (index) == REG)	    fprintf (file, "%s,%s",		     reg_names[REGNO (base)], reg_names[REGNO (index)]);	  /* Not sure this can happen, but leave in for now.  */	  else if (GET_CODE (index) == SYMBOL_REF)	    {	      output_addr_const (file, index);	      fputc (',', file);	      fputs (reg_names[REGNO (base)], file);	    }	  else	    abort ();	}      else if (GET_CODE (base) == LO_SUM)	{	  if (index != 0	      || GET_CODE (XEXP (base, 0)) != REG)	    abort ();	  if (small_data_operand (XEXP (base, 1), VOIDmode))	    fputs ("sda(", file);	  else	    fputs ("low(", file);	  output_addr_const (file, plus_constant (XEXP (base, 1), offset));	  fputs ("),", file);	  fputs (reg_names[REGNO (XEXP (base, 0))], file);	}      else	abort ();      break;    case LO_SUM :      if (GET_CODE (XEXP (addr, 0)) != REG)	abort ();      if (small_data_operand (XEXP (addr, 1), VOIDmode))	fputs ("sda(", file);      else	fputs ("low(", file);      output_addr_const (file, XEXP (addr, 1));      fputs ("),", file);      fputs (reg_names[REGNO (XEXP (addr, 0))], file);      break;    case PRE_INC :	/* Assume SImode */      fprintf (file, "+%s", reg_names[REGNO (XEXP (addr, 0))]);      break;    case PRE_DEC :	/* Assume SImode */      fprintf (file, "-%s", reg_names[REGNO (XEXP (addr, 0))]);      break;    case POST_INC :	/* Assume SImode */      fprintf (file, "%s+", reg_names[REGNO (XEXP (addr, 0))]);      break;    default :      output_addr_const (file, addr);      break;    }}/* Return true if the operands are the constants 0 and 1.  */intzero_and_one (operand1, operand2)     rtx operand1;     rtx operand2;{  return       GET_CODE (operand1) == CONST_INT    && GET_CODE (operand2) == CONST_INT    && (  ((INTVAL (operand1) == 0) && (INTVAL (operand2) == 1))	||((INTVAL (operand1) == 1) && (INTVAL (operand2) == 0)));}/* Return non-zero if the operand is suitable for use in a conditional move sequence.  */intconditional_move_operand (operand, int_mode)     rtx operand;     int int_mode;{  enum machine_mode mode = (enum machine_mode)int_mode;  /* Only defined for simple integers so far... */  if (mode != SImode && mode != HImode && mode != QImode)    return FALSE;  /* At the moment we can hanndle moving registers and loading constants.  */  /* To be added: Addition/subtraction/bitops/multiplication of registers.  */  switch (GET_CODE (operand))    {    case REG:      return 1;    case CONST_INT:      return INT8_P (INTVAL (operand));    default:#if 0      fprintf (stderr, "Test for cond move op of type: %s\n",	       GET_RTX_NAME (GET_CODE (operand)));#endif      return 0;    }}/* Return true if the code is a test of the carry bit */intcarry_compare_operand (op, int_mode)     rtx op;     int int_mode;{  rtx x;  if (GET_MODE (op) != SImode && GET_MODE (op) != VOIDmode)    return FALSE;  if (GET_CODE (op) != NE && GET_CODE (op) != EQ)    return FALSE;  x = XEXP (op, 0);  if (GET_CODE (x) != REG || REGNO (x) != CARRY_REGNUM)    return FALSE;  x = XEXP (op, 1);  if (GET_CODE (x) != CONST_INT || INTVAL (x) != 0)    return FALSE;  return TRUE;}/* Generate the correct assembler code to handle the conditional loading of a   value into a register.  It is known that the operands satisfy the   conditional_move_operand() function above.  The destination is operand[0].   The condition is operand [1].  The 'true' value is operand [2] and the   'false' value is operand [3].  */char *emit_cond_move (operands, insn)     rtx * operands;     rtx   insn;{  static char buffer [100];  char * dest = reg_names [REGNO (operands [0])];    buffer [0] = 0;    /* Destination must be a register.  */  if (GET_CODE (operands [0]) != REG)    abort();  if (! conditional_move_operand (operands [2], SImode))    abort();  if (! conditional_move_operand (operands [3], SImode))    abort();        /* Check to see if the test is reversed.  */  if (GET_CODE (operands [1]) == NE)    {      rtx tmp = operands [2];      operands [2] = operands [3];      operands [3] = tmp;    }  sprintf (buffer, "mvfc %s, cbr", dest);    /* If the true value was '0' then we need to invert the results of the move.  */  if (INTVAL (operands [2]) == 0)    sprintf (buffer + strlen (buffer), "\n\txor3 %s, %s, #1",	     dest, dest);    return buffer;}/* Use a library function to move some bytes.  */static voidblock_move_call (dest_reg, src_reg, bytes_rtx)     rtx dest_reg;     rtx src_reg;     rtx bytes_rtx;{  /* We want to pass the size as Pmode, which will normally be SImode     but will be DImode if we are using 64 bit longs and pointers.  */  if (GET_MODE (bytes_rtx) != VOIDmode      && GET_MODE (bytes_rtx) != Pmode)    bytes_rtx = convert_to_mode (Pmode, bytes_rtx, 1);#ifdef TARGET_MEM_FUNCTIONS  emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "memcpy"), 0,		     VOIDmode, 3, dest_reg, Pmode, src_reg, Pmode,		     convert_to_mode (TYPE_MODE (sizetype), bytes_rtx,				      TREE_UNSIGNED (sizetype)),		     TYPE_MODE (sizetype));#else  emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "bcopy"), 0,		     VOIDmode, 3, src_reg, Pmode, dest_reg, Pmode,		     convert_to_mode (TYPE_MODE (integer_type_node), bytes_rtx,				      TREE_UNSIGNED (integer_type_node)),		     TYPE_MODE (integer_type_node));#endif}/* The maximum number of bytes to copy using pairs of load/store instructions.   If a block is larger than this then a loop will be generated to copy   MAX_MOVE_BYTES chunks at a time.  The value of 32 is a semi-arbitary choice.   A customer uses Dhrystome as their benchmark, and Dhrystone has a 31 byte   string copy in it.  */#define MAX_MOVE_BYTES 32/* Expand string/block move operations.   operands[0] is the pointer to the destination.   operands[1] is the pointer to the source.   operands[2] is the number of bytes to move.   operands[3] is the alignment.  */voidm32r_expand_block_move (operands)     rtx operands[];{  rtx           orig_dst  = operands[0];  rtx           orig_src  = operands[1];  rtx           bytes_rtx = operands[2];  rtx           align_rtx = operands[3];  int           constp    = GET_CODE (bytes_rtx) == CONST_INT;  HOST_WIDE_INT bytes     = constp ? INTVAL (bytes_rtx) : 0;  int           align     = INTVAL (align_rtx);  int           leftover;  rtx           src_reg;  rtx           dst_reg;  if (constp && bytes <= 0)    return;  /* Move the address into scratch registers.  */  dst_reg = copy_addr_to_reg (XEXP (orig_dst, 0));  src_reg = copy_addr_to_reg (XEXP (orig_src, 0));  if (align > UNITS_PER_WORD)    align = UNITS_PER_WORD;  /* If we prefer size over speed, always use a function call.     If we do not know the size, use a function call.     If the blocks are not word aligned, use a function call.  */  if (optimize_size || ! constp || align != UNITS_PER_WORD)    {      block_move_call (dst_reg, src_reg, bytes_rtx);      return;    }  leftover = bytes % MAX_MOVE_BYTES;  bytes   -= leftover;    /* If necessary, generate a loop to handle the bulk of the copy.  */  if (bytes)    {      rtx label;      rtx final_src;      rtx at_a_time = GEN_INT (MAX_MOVE_BYTES);      rtx rounded_total = GEN_INT (bytes);      /* If we are going to have to perform this loop more than	 once, then generate a label and compute the address the	 source register will contain upon completion of the final	 itteration.  */      if (bytes > MAX_MOVE_BYTES)	{	  final_src = gen_reg_rtx (Pmode);	  if (INT16_P(bytes))	    emit_insn (gen_addsi3 (final_src, src_reg, rounded_total));	  else	    {	      emit_insn (gen_movsi (final_src, rounded_t

⌨️ 快捷键说明

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