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

📄 mips.c

📁 GUN开源阻止下的编译器GCC
💻 C
📖 第 1 页 / 共 5 页
字号:
#if 0  /* Don't generate unaligned moves here, rather defer those to the     general movestrsi_internal pattern.     If this gets commented back in, then should add the dword equivalent.  */  else if (bytes >= UNITS_PER_MIPS_WORD)    {      mode = SImode;      size = UNITS_PER_MIPS_WORD;      load_func = gen_movsi_ulw;      store_func = gen_movsi_usw;    }#endif  else if (bytes >= UNITS_PER_MIPS_SHORT && align >= UNITS_PER_MIPS_SHORT)    {      mode = HImode;      size = UNITS_PER_MIPS_SHORT;      load_func = gen_movhi;      store_func = gen_movhi;    }  else    {      mode = QImode;      size = 1;      load_func = gen_movqi;      store_func = gen_movqi;    }  offset = *p_offset;  *p_offset = offset + size;  *p_bytes = bytes - size;  if (offset == 0)    {      src_addr  = src_reg;      dest_addr = dest_reg;    }  else    {      src_addr  = gen_rtx (PLUS, Pmode, src_reg,  GEN_INT (offset));      dest_addr = gen_rtx (PLUS, Pmode, dest_reg, GEN_INT (offset));    }  reg = gen_reg_rtx (mode);  insn = emit_insn ((*load_func) (reg, gen_rtx (MEM, mode, src_addr)));  orig_src_addr = XEXP (orig_src, 0);  if (CONSTANT_P (orig_src_addr))    REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_EQUIV,				plus_constant (orig_src_addr, offset),				REG_NOTES (insn));  return (*store_func) (gen_rtx (MEM, mode, dest_addr), reg);}#endif/* Write a series of loads/stores to move some bytes.  Generate load/stores as follows:   load  1   load  2   load  3   store 1   load  4   store 2   load  5   store 3   ...   This way, no NOP's are needed, except at the end, and only   two temp registers are needed.  Two delay slots are used   in deference to the R4000.  */#if 0static voidblock_move_sequence (dest_reg, src_reg, bytes, align, orig_src)     rtx dest_reg;		/* register holding destination address */     rtx src_reg;		/* register holding source address */     int bytes;			/* # bytes to move */     int align;			/* max alignment to assume */     rtx orig_src;		/* original source for making a reg note */{  int offset		= 0;  rtx prev2_store	= (rtx)0;  rtx prev_store	= (rtx)0;  rtx cur_store		= (rtx)0;  while (bytes > 0)    {      /* Is there a store to do? */      if (prev2_store)	emit_insn (prev2_store);      prev2_store = prev_store;      prev_store = cur_store;      cur_store = block_move_load_store (dest_reg, src_reg,					 &bytes, &offset,					 align, orig_src);    }  /* Finish up last three stores.  */  if (prev2_store)    emit_insn (prev2_store);  if (prev_store)    emit_insn (prev_store);  if (cur_store)    emit_insn (cur_store);}#endif/* Write a loop to move a constant number of bytes.  Generate load/stores as follows:   do {     temp1 = src[0];     temp2 = src[1];     ...     temp<last> = src[MAX_MOVE_REGS-1];     dest[0] = temp1;     dest[1] = temp2;     ...     dest[MAX_MOVE_REGS-1] = temp<last>;     src += MAX_MOVE_REGS;     dest += MAX_MOVE_REGS;   } while (src != final);   This way, no NOP's are needed, and only MAX_MOVE_REGS+3 temp   registers are needed.   Aligned moves move MAX_MOVE_REGS*4 bytes every (2*MAX_MOVE_REGS)+3   cycles, unaligned moves move MAX_MOVE_REGS*4 bytes every   (4*MAX_MOVE_REGS)+3 cycles, assuming no cache misses.  */#define MAX_MOVE_REGS 4#define MAX_MOVE_BYTES (MAX_MOVE_REGS * UNITS_PER_WORD)/* ??? Should add code to use DWORD load/stores.  */static voidblock_move_loop (dest_reg, src_reg, bytes, align, orig_src)     rtx dest_reg;		/* register holding destination address */     rtx src_reg;		/* register holding source address */     int bytes;			/* # bytes to move */     int align;			/* alignment */     rtx orig_src;		/* original source for making a reg note */{  rtx dest_mem		= gen_rtx (MEM, BLKmode, dest_reg);  rtx src_mem		= gen_rtx (MEM, BLKmode, src_reg);  rtx align_rtx		= GEN_INT (align);  rtx label;  rtx final_src;  rtx bytes_rtx;  int leftover;  if (bytes < 2*MAX_MOVE_BYTES)    abort ();  leftover = bytes % MAX_MOVE_BYTES;  bytes -= leftover;  label = gen_label_rtx ();  final_src = gen_reg_rtx (Pmode);  bytes_rtx = GEN_INT (bytes);  if (bytes > 0x7fff)    {      if (TARGET_LONG64)	{	  emit_insn (gen_movdi (final_src, bytes_rtx));	  emit_insn (gen_adddi3 (final_src, final_src, src_reg));	}      else	{	  emit_insn (gen_movsi (final_src, bytes_rtx));	  emit_insn (gen_addsi3 (final_src, final_src, src_reg));	}    }  else    {      if (TARGET_LONG64)	emit_insn (gen_adddi3 (final_src, src_reg, bytes_rtx));      else	emit_insn (gen_addsi3 (final_src, src_reg, bytes_rtx));    }  emit_label (label);  bytes_rtx = GEN_INT (MAX_MOVE_BYTES);  emit_insn (gen_movstrsi_internal (dest_mem, src_mem, bytes_rtx, align_rtx));  if (TARGET_LONG64)    {      emit_insn (gen_adddi3 (src_reg, src_reg, bytes_rtx));      emit_insn (gen_adddi3 (dest_reg, dest_reg, bytes_rtx));      emit_insn (gen_cmpdi (src_reg, final_src));    }  else    {      emit_insn (gen_addsi3 (src_reg, src_reg, bytes_rtx));      emit_insn (gen_addsi3 (dest_reg, dest_reg, bytes_rtx));      emit_insn (gen_cmpsi (src_reg, final_src));    }  emit_jump_insn (gen_bne (label));  if (leftover)    emit_insn (gen_movstrsi_internal (dest_mem, src_mem,				      GEN_INT (leftover),				      align_rtx));}/* 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, TRUE);#ifdef TARGET_MEM_FUNCTIONS  emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "memcpy"), 0,		     VOIDmode, 3,		     dest_reg, Pmode,		     src_reg, Pmode,		     bytes_rtx, Pmode);#else  emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "bcopy"), 0,		     VOIDmode, 3,		     src_reg, Pmode,		     dest_reg, Pmode,		     bytes_rtx, Pmode);#endif}/* 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.  */voidexpand_block_move (operands)     rtx operands[];{  rtx bytes_rtx	= operands[2];  rtx align_rtx = operands[3];  int constp	= (GET_CODE (bytes_rtx) == CONST_INT);  int bytes	= (constp ? INTVAL (bytes_rtx) : 0);  int align	= INTVAL (align_rtx);  rtx orig_src	= operands[1];  rtx src_reg;  rtx dest_reg;  if (constp && bytes <= 0)    return;  if (align > UNITS_PER_WORD)    align = UNITS_PER_WORD;  /* Move the address into scratch registers.  */  dest_reg = copy_addr_to_reg (XEXP (operands[0], 0));  src_reg  = copy_addr_to_reg (XEXP (orig_src, 0));  if (TARGET_MEMCPY)    block_move_call (dest_reg, src_reg, bytes_rtx);#if 0  else if (constp && bytes <= 3*align)    block_move_sequence (dest_reg, src_reg, bytes, align, orig_src);#endif  else if (constp && bytes <= 2*MAX_MOVE_BYTES)    emit_insn (gen_movstrsi_internal (gen_rtx (MEM, BLKmode, dest_reg),				      gen_rtx (MEM, BLKmode, src_reg),				      bytes_rtx, align_rtx));  else if (constp && align >= UNITS_PER_WORD && optimize)    block_move_loop (dest_reg, src_reg, bytes, align, orig_src);  else if (constp && optimize)    {      /* If the alignment is not word aligned, generate a test at	 runtime, to see whether things wound up aligned, and we	 can use the faster lw/sw instead ulw/usw.  */      rtx temp		= gen_reg_rtx (Pmode);      rtx aligned_label = gen_label_rtx ();      rtx join_label	= gen_label_rtx ();      int leftover	= bytes % MAX_MOVE_BYTES;      bytes -= leftover;      if (TARGET_LONG64)	{	  emit_insn (gen_iordi3 (temp, src_reg, dest_reg));	  emit_insn (gen_anddi3 (temp, temp, GEN_INT (UNITS_PER_WORD-1)));	  emit_insn (gen_cmpdi (temp, const0_rtx));	}      else	{	  emit_insn (gen_iorsi3 (temp, src_reg, dest_reg));	  emit_insn (gen_andsi3 (temp, temp, GEN_INT (UNITS_PER_WORD-1)));	  emit_insn (gen_cmpsi (temp, const0_rtx));	}      emit_jump_insn (gen_beq (aligned_label));      /* Unaligned loop.  */      block_move_loop (dest_reg, src_reg, bytes, 1, orig_src);      emit_jump_insn (gen_jump (join_label));      emit_barrier ();      /* Aligned loop.  */      emit_label (aligned_label);      block_move_loop (dest_reg, src_reg, bytes, UNITS_PER_WORD, orig_src);      emit_label (join_label);      /* Bytes at the end of the loop.  */      if (leftover)	{#if 0	  if (leftover <= 3*align)	    block_move_sequence (dest_reg, src_reg, leftover, align, orig_src);	  else#endif	    emit_insn (gen_movstrsi_internal (gen_rtx (MEM, BLKmode, dest_reg),					      gen_rtx (MEM, BLKmode, src_reg),					      GEN_INT (leftover),					      GEN_INT (align)));	}    }  else    block_move_call (dest_reg, src_reg, bytes_rtx);}/* Emit load/stores for a small constant block_move.    operands[0] is the memory address of the destination.   operands[1] is the memory address of the source.   operands[2] is the number of bytes to move.   operands[3] is the alignment.   operands[4] is a temp register.   operands[5] is a temp register.   ...   operands[3+num_regs] is the last temp register.   The block move type can be one of the following:	BLOCK_MOVE_NORMAL	Do all of the block move.	BLOCK_MOVE_NOT_LAST	Do all but the last store.	BLOCK_MOVE_LAST		Do just the last store. */char *output_block_move (insn, operands, num_regs, move_type)     rtx insn;     rtx operands[];     int num_regs;     enum block_move_type move_type;{  rtx dest_reg		= XEXP (operands[0], 0);  rtx src_reg		= XEXP (operands[1], 0);  int bytes		= INTVAL (operands[2]);  int align		= INTVAL (operands[3]);  int num		= 0;  int offset		= 0;  int use_lwl_lwr	= FALSE;  int last_operand	= num_regs+4;  int safe_regs		= 4;  int i;  rtx xoperands[10];  struct {    char *load;			/* load insn without nop */    char *load_nop;		/* load insn with trailing nop */    char *store;		/* store insn */    char *final;		/* if last_store used: NULL or swr */    char *last_store;		/* last store instruction */    int offset;			/* current offset */    enum machine_mode mode;	/* mode to use on (MEM) */  } load_store[4];  /* Detect a bug in GCC, where it can give us a register     the same as one of the addressing registers and reduce     the number of registers available.  */  for (i = 4;       i < last_operand && safe_regs < (sizeof(xoperands) / sizeof(xoperands[0]));       i++)    {      if (!reg_mentioned_p (operands[i], operands[0])	  && !reg_mentioned_p (operands[i], operands[1]))	xoperands[safe_regs++] = operands[i];    }  if (safe_regs < last_operand)    {      xoperands[0] = operands[0];      xoperands[1] = operands[1];      xoperands[2] = operands[2];      xoperands[3] = operands[3];      return output_block_move (insn, xoperands, safe_regs-4, move_type);    }  /* If we are given global or static addresses, and we would be     emitting a few instructions, try to save time by using a     temporary register for the pointer.  */  if (num_regs > 2 && (bytes > 2*align || move_type != BLOCK_MOVE_NORMAL))    {      if (CONSTANT_P (src_reg))	{	  if (TARGET_STATS)	    mips_count_memory_refs (operands[1], 1);	  src_reg = operands[ 3 + num_regs-- ];	  if (move_type != BLOCK_MOVE_LAST)	    {	      xoperands[1] = operands[1];	      xoperands[0] = src_reg;	      if (Pmode == DImode)		output_asm_insn ("dla\t%0,%1", xoperands);	      else		output_asm_insn ("la\t%0,%1", xoperands);	    }	}      if (CONSTANT_P (dest_reg))	{	  if (TARGET_STATS)	    mips_count_memory_refs (operands[0], 1);	  dest_reg = operands[ 3 + num_regs-- ];	  if (move_type != BLOCK_MOVE_LAST)	    {	      xoperands[1] = operands[0];	      xoperands[0] = dest_reg;	      if (Pmode == DImode)		output_asm_insn ("dla\t%0,%1", xoperands);	      else		output_asm_insn ("la\t%0,%1", xoperands);	    }	}    }  if (num_regs > (sizeof (load_store) / sizeof (load_store[0])))    num_regs = (sizeof (load_store) / sizeof (load_store[0]));  else if (num_regs < 1)    abort_with_insn (insn, "Cannot do block move, not enough scratch registers");  while (bytes > 0)    {      load_store[num].offset = offset;      if (TARGET_64BIT && bytes >= 8 && align >= 8)	{	  load_store[num].load       = "ld\t%0,%1";	  load_store[num].load_nop   = "ld\t%0,%1%#";	  load_store[num].store      = "sd\t%0,%1";	  load_store[num].last_store = "sd\t%0,%1";	  load_store[num].final      = (char *)0;	  load_store[num].mode       = DImode;	  offset += 8;	  bytes -= 8;	}      /* ??? Fails because of a MIPS assembler bug?  */      else if (TARGET_64BIT && bytes >= 8)	{	  if (BYTES_BIG_ENDIAN)	    {	      load_store[num].load       = "ldl\t%0,%1\n\tldr\t%0,%2";	      load_store[num].load_nop   = "ldl\t%0,%1\n\tldr\t%0,%2%#";	      load_store[num].store      = "sdl\t%0,%1\n\tsdr\t%0,%2";	      load_store[num].last_store = "sdr\t%0,%2";	      load_store[num].final      = "sdl\t%0,%1";	    }	  else	    {	      load_store[num].load	     = "ldl\t%0,%2\n\tldr\t%0,%1";	      load_store[num].load_nop   = "ldl\t%0,%2\n\tldr\t%0,%1%#";	      load_store[num].store	     = "sdl\t%0,%2\n\tsdr\t%0,%1";	      load_store[num].last_store = "sdr\t%0,%1";	      load_store[num].final      = "sdl\t%0,%2";	    }	  load_store[num].mode = DImode;	  offset += 8;	  bytes -= 8;	  use_lwl_lwr = TRUE;	}      else if (bytes >= 4 && align >= 4)	{	  load_store[num].load       = "lw\t%0,%1";	  load_store[num].load_nop   = "lw\t%0,%1%#";	  load_store[num].store      = "sw\t%0,%1";	  load_store[num].last_store = "sw\t%0,%1";	  load_store[num].final      = (char *)0;	  load_store[num].mode       = SImode;	  offset += 4;	  bytes -= 4;	}      else if (bytes >= 4)	{	  if (BYTES_BIG_ENDIAN)	    {	      load_store[num].load       =

⌨️ 快捷键说明

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