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

📄 m88k.c

📁 linux下的gcc编译器
💻 C
📖 第 1 页 / 共 5 页
字号:
#define MOVSTR_DI	96 /* __movstrDI96x96 .. __movstrDI96x16 */#define MOVSTR_ODD_HI	16 /* __movstrHI15x15 .. __movstrHI15x5 */#define MOVSTR_ODD_SI	48 /* __movstrSI47x47 .. __movstrSI47x11,			      __movstrSI46x46 .. __movstrSI46x10,			      __movstrSI45x45 .. __movstrSI45x9 */#define MOVSTR_ODD_DI	48 /* __movstrDI47x47 .. __movstrDI47x23,			      __movstrDI46x46 .. __movstrDI46x22,			      __movstrDI45x45 .. __movstrDI45x21,			      __movstrDI44x44 .. __movstrDI44x20,			      __movstrDI43x43 .. __movstrDI43x19,			      __movstrDI42x42 .. __movstrDI42x18,			      __movstrDI41x41 .. __movstrDI41x17 *//* Limits for using the non-looping movstr functions.  For the m88100   processor, we assume the source and destination are word aligned.   The QImode and HImode limits are the break even points where memcpy   does just as well and beyond which memcpy does better.  For the   m88110, we tend to assume double word alignment, but also analyze   the word aligned cases.  The analysis is complicated because memcpy   may use the cache control instructions for better performance.  */#define MOVSTR_QI_LIMIT_88100   13#define MOVSTR_HI_LIMIT_88100   38#define MOVSTR_SI_LIMIT_88100   MOVSTR_SI#define MOVSTR_DI_LIMIT_88100   MOVSTR_SI  #define MOVSTR_QI_LIMIT_88000   16#define MOVSTR_HI_LIMIT_88000   38#define MOVSTR_SI_LIMIT_88000   72#define MOVSTR_DI_LIMIT_88000   72#define MOVSTR_QI_LIMIT_88110   16#define MOVSTR_HI_LIMIT_88110   38#define MOVSTR_SI_LIMIT_88110   72#define MOVSTR_DI_LIMIT_88110   72static const enum machine_mode mode_from_align[] =			      {VOIDmode, QImode, HImode, VOIDmode, SImode,			       VOIDmode, VOIDmode, VOIDmode, DImode};static const int max_from_align[] = {0, MOVSTR_QI, MOVSTR_HI, 0, MOVSTR_SI,				     0, 0, 0, MOVSTR_DI};static const int all_from_align[] = {0, MOVSTR_QI, MOVSTR_ODD_HI, 0,				     MOVSTR_ODD_SI, 0, 0, 0, MOVSTR_ODD_DI};static const int best_from_align[3][9] = {  {0, MOVSTR_QI_LIMIT_88100, MOVSTR_HI_LIMIT_88100, 0, MOVSTR_SI_LIMIT_88100,   0, 0, 0, MOVSTR_DI_LIMIT_88100},  {0, MOVSTR_QI_LIMIT_88110, MOVSTR_HI_LIMIT_88110, 0, MOVSTR_SI_LIMIT_88110,   0, 0, 0, MOVSTR_DI_LIMIT_88110},  {0, MOVSTR_QI_LIMIT_88000, MOVSTR_HI_LIMIT_88000, 0, MOVSTR_SI_LIMIT_88000,   0, 0, 0, MOVSTR_DI_LIMIT_88000}};static void block_move_loop PARAMS ((rtx, rtx, rtx, rtx, int, int));static void block_move_no_loop PARAMS ((rtx, rtx, rtx, rtx, int, int));static void block_move_sequence PARAMS ((rtx, rtx, rtx, rtx, int, int, int));static void output_short_branch_defs PARAMS ((FILE *));static int output_option PARAMS ((FILE *, const char *, const char *,				  const char *, const char *, int, int));/* Emit code to perform a block move.  Choose the best method.   OPERANDS[0] is the destination.   OPERANDS[1] is the source.   OPERANDS[2] is the size.   OPERANDS[3] is the alignment safe to use.  */voidexpand_block_move (dest_mem, src_mem, operands)     rtx dest_mem;     rtx src_mem;     rtx *operands;{  int align = INTVAL (operands[3]);  int constp = (GET_CODE (operands[2]) == CONST_INT);  int bytes = (constp ? INTVAL (operands[2]) : 0);  int target = (int) m88k_cpu;  if (! (PROCESSOR_M88100 == 0	 && PROCESSOR_M88110 == 1	 && PROCESSOR_M88000 == 2))    abort ();  if (constp && bytes <= 0)    return;  /* Determine machine mode to do move with.  */  if (align > 4 && !TARGET_88110)    align = 4;  else if (align <= 0 || align == 3)    abort ();	/* block move invalid alignment.  */  if (constp && bytes <= 3 * align)    block_move_sequence (operands[0], dest_mem, operands[1], src_mem,			 bytes, align, 0);  else if (constp && bytes <= best_from_align[target][align])    block_move_no_loop (operands[0], dest_mem, operands[1], src_mem,			bytes, align);  else if (constp && align == 4 && TARGET_88100)    block_move_loop (operands[0], dest_mem, operands[1], src_mem,		     bytes, align);  else    {#ifdef TARGET_MEM_FUNCTIONS      emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "memcpy"), 0,			 VOIDmode, 3,			 operands[0], Pmode,			 operands[1], Pmode,			 convert_to_mode (TYPE_MODE (sizetype), operands[2],					  TREE_UNSIGNED (sizetype)),			 TYPE_MODE (sizetype));#else      emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "bcopy"), 0,			 VOIDmode, 3,			 operands[1], Pmode,			 operands[0], Pmode,			 convert_to_mode (TYPE_MODE (integer_type_node),					  operands[2],					  TREE_UNSIGNED (integer_type_node)),			 TYPE_MODE (integer_type_node));#endif    }}/* Emit code to perform a block move by calling a looping movstr library   function.  SIZE and ALIGN are known constants.  DEST and SRC are   registers.  */static voidblock_move_loop (dest, dest_mem, src, src_mem, size, align)     rtx dest, dest_mem;     rtx src, src_mem;     int size;     int align;{  enum machine_mode mode;  int count;  int units;  int remainder;  rtx offset_rtx;  rtx value_rtx;  char entry[30];  tree entry_name;  /* Determine machine mode to do move with.  */  if (align != 4)    abort ();  /* Determine the structure of the loop.  */  count = size / MOVSTR_LOOP;  units = (size - count * MOVSTR_LOOP) / align;  if (units < 2)    {      count--;      units += MOVSTR_LOOP / align;    }  if (count <= 0)    {      block_move_no_loop (dest, dest_mem, src, src_mem, size, align);      return;    }  remainder = size - count * MOVSTR_LOOP - units * align;  mode = mode_from_align[align];  sprintf (entry, "__movstr%s%dn%d",	   GET_MODE_NAME (mode), MOVSTR_LOOP, units * align);  entry_name = get_identifier (entry);  offset_rtx = GEN_INT (MOVSTR_LOOP + (1 - units) * align);  value_rtx = gen_rtx_MEM (MEM_IN_STRUCT_P (src_mem) ? mode : BLKmode,			   gen_rtx_PLUS (Pmode,					 gen_rtx_REG (Pmode, 3),					 offset_rtx));  MEM_COPY_ATTRIBUTES (value_rtx, src_mem);  emit_insn (gen_call_movstrsi_loop	     (gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (entry_name)),	      dest, src, offset_rtx, value_rtx,	      gen_rtx_REG (mode, ((units & 1) ? 4 : 5)),	      GEN_INT (count)));  if (remainder)    block_move_sequence (gen_rtx_REG (Pmode, 2), dest_mem,			 gen_rtx_REG (Pmode, 3), src_mem,			 remainder, align, MOVSTR_LOOP + align);}/* Emit code to perform a block move by calling a non-looping library   function.  SIZE and ALIGN are known constants.  DEST and SRC are   registers.  OFFSET is the known starting point for the output pattern.  */static voidblock_move_no_loop (dest, dest_mem, src, src_mem, size, align)     rtx dest, dest_mem;     rtx src, src_mem;     int size;     int align;{  enum machine_mode mode = mode_from_align[align];  int units = size / align;  int remainder = size - units * align;  int most;  int value_reg;  rtx offset_rtx;  rtx value_rtx;  char entry[30];  tree entry_name;  if (remainder && size <= all_from_align[align])    {      most = all_from_align[align] - (align - remainder);      remainder = 0;    }  else    {      most = max_from_align[align];    }  sprintf (entry, "__movstr%s%dx%d",	   GET_MODE_NAME (mode), most, size - remainder);  entry_name = get_identifier (entry);  offset_rtx = GEN_INT (most - (size - remainder));  value_rtx = gen_rtx_MEM (MEM_IN_STRUCT_P (src_mem) ? mode : BLKmode,			   gen_rtx_PLUS (Pmode,					 gen_rtx_REG (Pmode, 3),					 offset_rtx));  MEM_COPY_ATTRIBUTES (value_rtx, src_mem);  value_reg = ((((most - (size - remainder)) / align) & 1) == 0	       ? (align == 8 ? 6 : 5) : 4);  emit_insn (gen_call_block_move	     (gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (entry_name)),	      dest, src, offset_rtx, value_rtx,	      gen_rtx_REG (mode, value_reg)));  if (remainder)    block_move_sequence (gen_rtx_REG (Pmode, 2), dest_mem,			 gen_rtx_REG (Pmode, 3), src_mem,			 remainder, align, most);}/* Emit code to perform a block move with an offset sequence of ld/st   instructions (..., ld 0, st 1, ld 1, st 0, ...).  SIZE and ALIGN are   known constants.  DEST and SRC are registers.  OFFSET is the known   starting point for the output pattern.  */static voidblock_move_sequence (dest, dest_mem, src, src_mem, size, align, offset)     rtx dest, dest_mem;     rtx src, src_mem;     int size;     int align;     int offset;{  rtx temp[2];  enum machine_mode mode[2];  int amount[2];  int active[2];  int phase = 0;  int next;  int offset_ld = offset;  int offset_st = offset;  active[0] = active[1] = FALSE;  /* Establish parameters for the first load and for the second load if     it is known to be the same mode as the first.  */  amount[0] = amount[1] = align;  mode[0] = mode_from_align[align];  temp[0] = gen_reg_rtx (mode[0]);  if (size >= 2 * align)    {      mode[1] = mode[0];      temp[1] = gen_reg_rtx (mode[1]);    }  do    {      rtx srcp, dstp;      next = phase;      phase = !phase;      if (size > 0)	{	  /* Change modes as the sequence tails off.  */	  if (size < amount[next])	    {	      amount[next] = (size >= 4 ? 4 : (size >= 2 ? 2 : 1));	      mode[next] = mode_from_align[amount[next]];	      temp[next] = gen_reg_rtx (mode[next]);	    }	  size -= amount[next];	  srcp = gen_rtx_MEM (MEM_IN_STRUCT_P (src_mem) ? mode[next] : BLKmode,			      plus_constant (src, offset_ld));	  MEM_COPY_ATTRIBUTES (srcp, src_mem);	  emit_insn (gen_rtx_SET (VOIDmode, temp[next], srcp));	  offset_ld += amount[next];	  active[next] = TRUE;	}      if (active[phase])	{	  active[phase] = FALSE;	  dstp	    = gen_rtx_MEM (MEM_IN_STRUCT_P (dest_mem) ? mode[phase] : BLKmode,			   plus_constant (dest, offset_st));	  MEM_COPY_ATTRIBUTES (dstp, dest_mem);	  emit_insn (gen_rtx_SET (VOIDmode, dstp, temp[phase]));	  offset_st += amount[phase];	}    }  while (active[next]);}/* Emit the code to do an AND operation.  */const char *output_and (operands)     rtx operands[];{  unsigned int value;  if (REG_P (operands[2]))    return "and %0,%1,%2";  value = INTVAL (operands[2]);  if (SMALL_INTVAL (value))    return "mask %0,%1,%2";  else if ((value & 0xffff0000) == 0xffff0000)    return "and %0,%1,%x2";  else if ((value & 0xffff) == 0xffff)    return "and.u %0,%1,%X2";  else if ((value & 0xffff) == 0)    return "mask.u %0,%1,%X2";  else if (integer_ok_for_set (~value))    return "clr %0,%1,%S2";  else    return "and.u %0,%1,%X2\n\tand %0,%0,%x2";}/* Emit the code to do an inclusive OR operation.  */const char *output_ior (operands)     rtx operands[];{  unsigned int value;  if (REG_P (operands[2]))    return "or %0,%1,%2";  value = INTVAL (operands[2]);  if (SMALL_INTVAL (value))    return "or %0,%1,%2";  else if ((value & 0xffff) == 0)    return "or.u %0,%1,%X2";  else if (integer_ok_for_set (value))    return "set %0,%1,%s2";  else    return "or.u %0,%1,%X2\n\tor %0,%0,%x2";}/* Emit the instructions for doing an XOR.  */const char *output_xor (operands)     rtx operands[];{  unsigned int value;  if (REG_P (operands[2]))    return "xor %0,%1,%2";  value = INTVAL (operands[2]);  if (SMALL_INTVAL (value))    return "xor %0,%1,%2";  else if ((value & 0xffff) == 0)    return "xor.u %0,%1,%X2";  else    return "xor.u %0,%1,%X2\n\txor %0,%0,%x2";}/* Output a call.  Normally this is just bsr or jsr, but this also deals with   accomplishing a branch after the call by incrementing r1.  This requires   that various assembler bugs be accommodated.  The 4.30 DG/UX assembler   requires that forward references not occur when computing the difference of   two labels.  The [version?] Motorola assembler computes a word difference.   No doubt there's more to come!   It would seem the same idea could be used to tail call, but in this case,   the epilogue will be non-null.  */static rtx sb_name = 0;static rtx sb_high = 0;static rtx sb_low = 0;const char *output_call (operands, addr)     rtx operands[];     rtx addr;{  operands[0] = addr;  if (final_sequence)    {      rtx jump;      rtx seq_insn;      /* This can be generalized, but there is currently no need.  */      if (XVECLEN (final_sequence, 0) != 2)	abort ();      /* The address of interior insns is not computed, so use the sequence.  */      seq_insn = NEXT_INSN (PREV_INSN (XVECEXP (final_sequence, 0, 0)));      jump = XVECEXP (final_sequence, 0, 1);      if (GET_CODE (jump) == JUMP_INSN)	{	  rtx low, high;	  const char *last;	  rtx dest = XEXP (SET_SRC (PATTERN (jump)), 0);	  int delta = 4 * (INSN_ADDRESSES (INSN_UID (dest))			   - INSN_ADDRESSES (INSN_UID (seq_insn))			   - 2);#if (MONITOR_GCC & 0x2) /* How often do long branches happen?  */	  if ((unsigned) (delta + 0x8000) >= 0x10000)	    warning ("internal gcc monitor: short-branch(%x)", delta);#endif	  /* Delete the jump.  */	  PUT_CODE (jump, NOTE);	  NOTE_LINE_NUMBER (jump) = NOTE_INSN_DELETED;	  NOTE_SOURCE_FILE (jump) = 0;	  /* We only do this optimization if -O2, modifying the value of	     r1 in the delay slot confuses debuggers and profilers on some	     systems.	     If we loose, we must use the non-delay form.  This is unlikely	     to ever happen.  If it becomes a problem, claim that a call	     has two delay slots and only the second can be filled with	     a jump.  	     The 88110 can lose when a jsr.n r1 is issued and a page fault	     occurs accessing the delay slot.  So don't use jsr.n form when	     jumping thru r1.	   */#ifdef AS_BUG_IMMEDIATE_LABEL /* The assembler restricts immediate values.  */	  if (optimize < 2	      || ! ADD_INTVAL (delta * 2)#else	  if (optimize < 2	      || ! ADD_INTVAL (delta)#endif

⌨️ 快捷键说明

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