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

📄 pa.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 5 页
字号:
      if (GET_CODE (operands[0]) == REG)	{	  rtx xoperands[3];	  xoperands[2] = operands[1];	  xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);	  xoperands[0] = operands[0];	  output_asm_insn	    ("fstds %2,-16(0,30)\n\tldw -12(0,30),%1\n\tldw -16(0,30),%0",	     xoperands);	}      else	output_asm_insn ("fstds%F0 %1,%0", operands);    }  else abort ();  return "";}/* Return a REG that occurs in ADDR with coefficient 1.   ADDR can be effectively incremented by incrementing REG.  */static rtxfind_addr_reg (addr)     rtx addr;{  while (GET_CODE (addr) == PLUS)    {      if (GET_CODE (XEXP (addr, 0)) == REG)	addr = XEXP (addr, 0);      else if (GET_CODE (XEXP (addr, 1)) == REG)	addr = XEXP (addr, 1);      else if (CONSTANT_P (XEXP (addr, 0)))	addr = XEXP (addr, 1);      else if (CONSTANT_P (XEXP (addr, 1)))	addr = XEXP (addr, 0);      else	abort ();    }  if (GET_CODE (addr) == REG)    return addr;  abort ();}/* Emit code to perform a block move.   Restriction: If the length argument is non-constant, alignment   must be 4.   OPERANDS[0] is the destination pointer as a REG, clobbered.   OPERANDS[1] is the source pointer as a REG, clobbered.   if SIZE_IS_CONSTANT     OPERANDS[2] is a register for temporary storage.     OPERANDS[4] is the size as a CONST_INT   else     OPERANDS[2] is a REG which will contain the size, clobbered.   OPERANDS[3] is a register for temporary storage.   OPERANDS[5] is the alignment safe to use, as a CONST_INT.  */char *output_block_move (operands, size_is_constant)     rtx *operands;     int size_is_constant;{  int align = INTVAL (operands[5]);  unsigned long n_bytes;  /* We can't move more than four bytes at a time because the PA     has no longer integer move insns.  (Could use fp mem ops?)  */  if (align > 4)    align = 4;  if (size_is_constant)    {      unsigned long n_items;      unsigned long offset;      rtx temp;      n_bytes = INTVAL (operands[4]);      if (n_bytes == 0)	return "";      if (align >= 4)	{	  /* Don't unroll too large blocks.  */	  if (n_bytes > 64)	    goto copy_with_loop;	  /* Read and store using two registers, and hide latency	     by deferring the stores until three instructions after	     the corresponding load.  The last load insn will read	     the entire word were the last bytes are, possibly past	     the end of the source block, but since loads are aligned,	     this is harmless.  */	  output_asm_insn ("ldws,ma 4(0,%1),%2", operands);	  for (offset = 4; offset < n_bytes; offset += 4)	    {	      output_asm_insn ("ldws,ma 4(0,%1),%3", operands);	      output_asm_insn ("stws,ma %2,4(0,%0)", operands);	      temp = operands[2];	      operands[2] = operands[3];	      operands[3] = temp;	    }	  if (n_bytes % 4 == 0)	    /* Store the last word.  */	    output_asm_insn ("stw %2,0(0,%0)", operands);	  else	    {	      /* Store the last, partial word.  */	      operands[4] = gen_rtx (CONST_INT, VOIDmode, n_bytes % 4);	      output_asm_insn ("stbys,e %2,%4(0,%0)", operands);	    }	  return "";	}      if (align >= 2 && n_bytes >= 2)	{	  output_asm_insn ("ldhs,ma 2(0,%1),%2", operands);	  for (offset = 2; offset + 2 <= n_bytes; offset += 2)	    {	      output_asm_insn ("ldhs,ma 2(0,%1),%3", operands);	      output_asm_insn ("sths,ma %2,2(0,%0)", operands);	      temp = operands[2];	      operands[2] = operands[3];	      operands[3] = temp;	    }	  if (n_bytes % 2 != 0)	    output_asm_insn ("ldb 0(0,%1),%3", operands);	  output_asm_insn ("sths,ma %2,2(0,%0)", operands);	  if (n_bytes % 2 != 0)	    output_asm_insn ("stb %3,0(0,%0)", operands);	  return "";	}      output_asm_insn ("ldbs,ma 1(0,%1),%2", operands);      for (offset = 1; offset + 1 <= n_bytes; offset += 1)	{	  output_asm_insn ("ldbs,ma 1(0,%1),%3", operands);	  output_asm_insn ("stbs,ma %2,1(0,%0)", operands);	  temp = operands[2];	  operands[2] = operands[3];	  operands[3] = temp;	}      output_asm_insn ("stb %2,0(0,%0)", operands);      return "";    }  if (align != 4)    abort();      copy_with_loop:  if (size_is_constant)    {      /* Size is compile-time determined, and also not	 very small (such small cases are handled above).  */      operands[4] = gen_rtx (CONST_INT, VOIDmode, n_bytes - 4);      output_asm_insn ("ldo %4(0),%2", operands);    }  else    {      /* Decrement counter by 4, and if it becomes negative, jump past the	 word copying loop.  */      output_asm_insn ("addib,<,n -4,%2,.+16", operands);    }  /* Copying loop.  Note that the first load is in the annulled delay slot     of addib.  Is it OK on PA to have a load in a delay slot, i.e. is a     possible page fault stopped in time?  */  output_asm_insn ("ldws,ma 4(0,%1),%3", operands);  output_asm_insn ("addib,>= -4,%2,.-4", operands);  output_asm_insn ("stws,ma %3,4(0,%0)", operands);  /* The counter is negative, >= -4.  The remaining number of bytes are     determined by the two least significant bits.  */  if (size_is_constant)    {      if (n_bytes % 4 != 0)	{	  /* Read the entire word of the source block tail.  */	  output_asm_insn ("ldw 0(0,%1),%3", operands);	  operands[4] = gen_rtx (CONST_INT, VOIDmode, n_bytes % 4);	  output_asm_insn ("stbys,e %3,%4(0,%0)", operands);	}    }  else    {      /* Add 4 to counter.  If it becomes zero, we're done.  */      output_asm_insn ("addib,=,n 4,%2,.+16", operands);      /* Read the entire word of the source block tail.  (Also this	 load is in an annulled delay slot.)  */      output_asm_insn ("ldw 0(0,%1),%3", operands);      /* Make %0 point at the first byte after the destination block.  */      output_asm_insn ("add %2,%0,%0", operands);      /* Store the leftmost bytes, up to, but not including, the address	 in %0.  */      output_asm_insn ("stbys,e %3,0(0,%0)", operands);    }  return "";}char *output_and (operands)     rtx *operands;{  if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) != 0)    {      unsigned mask = INTVAL (operands[2]);      int ls0, ls1, ms0, p, len;      for (ls0 = 0; ls0 < 32; ls0++)	if ((mask & (1 << ls0)) == 0)	  break;      for (ls1 = ls0; ls1 < 32; ls1++)	if ((mask & (1 << ls1)) != 0)	  break;      for (ms0 = ls1; ms0 < 32; ms0++)	if ((mask & (1 << ms0)) == 0)	  break;      if (ms0 != 32)	abort();      if (ls1 == 32)	{	  len = ls0;	  if (len == 0)	    abort ();	  operands[2] = gen_rtx (CONST_INT, VOIDmode, len);	  return "extru %1,31,%2,%0";	}      else	{	  /* We could use this `depi' for the case above as well, but `depi'	     requires one more register file access than an `extru'.  */	  p = 31 - ls0;	  len = ls1 - ls0;	  operands[2] = gen_rtx (CONST_INT, VOIDmode, p);	  operands[3] = gen_rtx (CONST_INT, VOIDmode, len);	  return "depi 0,%2,%3,%0";	}    }  else    return "and %1,%2,%0";}char *output_ior (operands)     rtx *operands;{  if (GET_CODE (operands[2]) == CONST_INT)    {      unsigned mask = INTVAL (operands[2]);      int bs0, bs1, bs2, p, len;       if (INTVAL (operands[2]) == 0)	return "copy %1,%0";      for (bs0 = 0; bs0 < 32; bs0++)	if ((mask & (1 << bs0)) != 0)	  break;      for (bs1 = bs0; bs1 < 32; bs1++)	if ((mask & (1 << bs1)) == 0)	  break;      if (bs1 != 32 && ((unsigned) 1 << bs1) <= mask)	abort();      p = 31 - bs0;      len = bs1 - bs0;      operands[2] = gen_rtx (CONST_INT, VOIDmode, p);      operands[3] = gen_rtx (CONST_INT, VOIDmode, len);      return "depi -1,%2,%3,%0";    }  else    return "or %1,%2,%0";}/* Output an ascii string.  */output_ascii (file, p, size)     FILE *file;     unsigned char *p;     int size;{  int i;  int chars_output;  unsigned char partial_output[16];	/* Max space 4 chars can occupy.   */  /* The HP assembler can only take strings of 256 characters at one     time.  This is a limitation on input line length, *not* the     length of the string.  Sigh.  Even worse, it seems that the     restriction is in number of input characters (see \xnn &     \whatever).  So we have to do this very carefully.  */  fprintf (file, "\t.STRING \"");  chars_output = 0;  for (i = 0; i < size; i += 4)    {      int co = 0;      int io = 0;      for (io = 0, co = 0; io < MIN (4, size - i); io++)	{	  register unsigned int c = p[i + io];	  if (c == '\"' || c == '\\')	    partial_output[co++] = '\\';	  if (c >= ' ' && c < 0177)	    partial_output[co++] = c;	  else	    {	      unsigned int hexd;	      partial_output[co++] = '\\';	      partial_output[co++] = 'x';	      hexd =  c  / 16 - 0 + '0';	      if (hexd > '9')		hexd -= '9' - 'a' + 1;	      partial_output[co++] = hexd;	      hexd =  c % 16 - 0 + '0';	      if (hexd > '9')		hexd -= '9' - 'a' + 1;	      partial_output[co++] = hexd;	    }	}      if (chars_output + co > 243)	{	  fprintf (file, "\"\n\t.STRING \"");	  chars_output = 0;	}      fwrite (partial_output, 1, co, file);      chars_output += co;      co = 0;    }  fprintf (file, "\"\n");}/* You may have trouble believing this, but this is the HP825 stack   layout.  Wow.   Offset		Contents   Variable arguments	(optional; any number may be allocated)   SP-(4*(N+9))		arg word N   	:		    :      SP-56		arg word 5      SP-52		arg word 4   Fixed arguments	(must be allocated; may remain unused)      SP-48		arg word 3      SP-44		arg word 2      SP-40		arg word 1      SP-36		arg word 0   Frame Marker      SP-32		External Data Pointer (DP)      SP-28		External sr4      SP-24		External/stub RP (RP')      SP-20		Current RP      SP-16		Static Link      SP-12		Clean up      SP-8		Calling Stub RP (RP'')      SP-4		Previous SP   Top of Frame      SP-0		Stack Pointer (points to next available address)*//* This function saves registers as follows.  Registers marked with ' are   this function's registers (as opposed to the previous function's).   If a frame_pointer isn't needed, r4 is saved as a general register;   the space for the frame pointer is still allocated, though, to keep   things simple.   Top of Frame       SP (FP')		Previous FP       SP + 4		Alignment filler (sigh)       SP + 8		Space for locals reserved here.       .       .       .       SP + n		All call saved register used.       .       .       .       SP + o		All call saved fp registers used.       .       .       .       SP + p (SP')	points to next available address.       *//* Helper functions */voidprint_stw (file, r, disp, base)     FILE *file;     int r, disp, base;{  if (VAL_14_BITS_P (disp))    fprintf (file, "\tstw %d,%d(0,%d)\n", r, disp, base);  else    fprintf (file, "\taddil L'%d,%d\n\tstw %d,R'%d(0,1)\n", disp, base,	     r, disp);}voidprint_ldw (file, r, disp, base)     FILE *file;     int r, disp, base;{  if (VAL_14_BITS_P (disp))    fprintf (file, "\tldw %d(0,%d),%d\n", disp, base, r);  else    fprintf (file, "\taddil L'%d,%d\n\tldw R'%d(0,1),%d\n", disp, base,	     disp, r);}/* Global variables set by FUNCTION_PROLOGUE.  *//* Size of frame.  Need to know this to emit return insns from   leaf procedures.  */int apparent_fsize;int actual_fsize;int local_fsize, save_fregs;intcompute_frame_size (size, leaf_function, fregs_live)     int size;     int leaf_function;     int *fregs_live;{  extern int current_function_outgoing_args_size;  int i;  /* 8 is space for frame pointer + filler */  local_fsize = actual_fsize = size + 8;  /* fp is stored in a special place. */  for (i = 18; i >= 5; i--)    if (regs_ever_live[i])      actual_fsize += 4;  if (regs_ever_live[3])    actual_fsize += 4;  actual_fsize = (actual_fsize + 7) & ~7;  if (!TARGET_SNAKE)    {      for (i = 47; i >= 44; i--)	if (regs_ever_live[i])	  {	    actual_fsize += 8;	    if (fregs_live)	      *fregs_live = 1;	  }    }  else    {      for (i = 90; i >= 72; i -= 2)	if (regs_ever_live[i] || regs_ever_live[i + 1])	  {	    actual_fsize += 8;	    if (fregs_live)	      *fregs_live = 1;	  }    }  return actual_fsize + current_function_outgoing_args_size;}     voidoutput_function_prologue (file, size, leaf_function)     FILE *file;     int size;     int leaf_function;{  extern char call_used_regs[];  extern int frame_pointer_needed;  extern int current_function_returns_struct;  int i, offset;  save_fregs = 0;

⌨️ 快捷键说明

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