pa.c

来自「GCC编译器源代码」· C语言 代码 · 共 2,308 行 · 第 1/5 页

C
2,308
字号
/* 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.   OPERANDS[0] is the destination pointer as a REG, clobbered.   OPERANDS[1] is the source pointer as a REG, clobbered.   OPERANDS[2] is a register for temporary storage.   OPERANDS[4] is the size as a CONST_INT   OPERANDS[3] is a register for temporary storage.   OPERANDS[5] is the alignment safe to use, as a CONST_INT.    OPERANDS[6] is another temporary register.   */char *output_block_move (operands, size_is_constant)     rtx *operands;     int size_is_constant;{  int align = INTVAL (operands[5]);  unsigned long n_bytes = INTVAL (operands[4]);  /* 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;  /* Note that we know each loop below will execute at least twice     (else we would have open-coded the copy).  */  switch (align)    {      case 4:	/* Pre-adjust the loop counter.  */	operands[4] = GEN_INT (n_bytes - 8);	output_asm_insn ("ldi %4,%2", operands);	/* Copying loop.  */	output_asm_insn ("ldws,ma 4(0,%1),%3", operands);	output_asm_insn ("ldws,ma 4(0,%1),%6", operands);	output_asm_insn ("stws,ma %3,4(0,%0)", operands);	output_asm_insn ("addib,>= -8,%2,.-12", operands);	output_asm_insn ("stws,ma %6,4(0,%0)", operands);	/* Handle the residual.  There could be up to 7 bytes of	   residual to copy!  */	if (n_bytes % 8 != 0)	  {	    operands[4] = GEN_INT (n_bytes % 4);	    if (n_bytes % 8 >= 4)	      output_asm_insn ("ldws,ma 4(0,%1),%3", operands);	    if (n_bytes % 4 != 0)	      output_asm_insn ("ldw 0(0,%1),%6", operands);	    if (n_bytes % 8 >= 4)	      output_asm_insn ("stws,ma %3,4(0,%0)", operands);	    if (n_bytes % 4 != 0)	      output_asm_insn ("stbys,e %6,%4(0,%0)", operands);	  }	return "";      case 2:	/* Pre-adjust the loop counter.  */	operands[4] = GEN_INT (n_bytes - 4);	output_asm_insn ("ldi %4,%2", operands);	/* Copying loop.  */	output_asm_insn ("ldhs,ma 2(0,%1),%3", operands);	output_asm_insn ("ldhs,ma 2(0,%1),%6", operands);	output_asm_insn ("sths,ma %3,2(0,%0)", operands);	output_asm_insn ("addib,>= -4,%2,.-12", operands);	output_asm_insn ("sths,ma %6,2(0,%0)", operands);	/* Handle the residual.  */	if (n_bytes % 4 != 0)	  {	    if (n_bytes % 4 >= 2)	      output_asm_insn ("ldhs,ma 2(0,%1),%3", operands);	    if (n_bytes % 2 != 0)	      output_asm_insn ("ldb 0(0,%1),%6", operands);	    if (n_bytes % 4 >= 2)	      output_asm_insn ("sths,ma %3,2(0,%0)", operands);	    if (n_bytes % 2 != 0)	      output_asm_insn ("stb %6,0(0,%0)", operands);	  }	return "";      case 1:	/* Pre-adjust the loop counter.  */	operands[4] = GEN_INT (n_bytes - 2);	output_asm_insn ("ldi %4,%2", operands);	/* Copying loop.  */	output_asm_insn ("ldbs,ma 1(0,%1),%3", operands);	output_asm_insn ("ldbs,ma 1(0,%1),%6", operands);	output_asm_insn ("stbs,ma %3,1(0,%0)", operands);	output_asm_insn ("addib,>= -2,%2,.-12", operands);	output_asm_insn ("stbs,ma %6,1(0,%0)", operands);	/* Handle the residual.  */	if (n_bytes % 2 != 0)	  {	    output_asm_insn ("ldb 0(0,%1),%3", operands);	    output_asm_insn ("stb %3,0(0,%0)", operands);	  }	return "";      default:	abort ();    }}/* Count the number of insns necessary to handle this block move.   Basic structure is the same as emit_block_move, except that we   count insns rather than emit them.  */intcompute_movstrsi_length (insn)     rtx insn;{  rtx pat = PATTERN (insn);  int align = INTVAL (XEXP (XVECEXP (pat, 0, 6), 0));  unsigned long n_bytes = INTVAL (XEXP (XVECEXP (pat, 0, 5), 0));  unsigned int n_insns = 0;  /* 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;  /* The basic copying loop.  */  n_insns = 6;  /* Residuals.  */  if (n_bytes % (2 * align) != 0)    {      if ((n_bytes % (2 * align)) >= align)	n_insns += 2;      if ((n_bytes % align) != 0)	n_insns += 2;    }  /* Lengths are expressed in bytes now; each insn is 4 bytes.  */  return n_insns * 4;}char *output_and (operands)     rtx *operands;{  if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) != 0)    {      unsigned HOST_WIDE_INT 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_INT (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_INT (p);	  operands[3] = GEN_INT (len);	  return "depi 0,%2,%3,%0";	}    }  else    return "and %1,%2,%0";}char *output_ior (operands)     rtx *operands;{  unsigned HOST_WIDE_INT mask = INTVAL (operands[2]);  int bs0, bs1, 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 HOST_WIDE_INT) 1 << bs1) <= mask)    abort();  p = 31 - bs0;  len = bs1 - bs0;  operands[2] = GEN_INT (p);  operands[3] = GEN_INT (len);  return "depi -1,%2,%3,%0";}/* Output an ascii string.  */voidoutput_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.  */  fputs ("\t.STRING \"", file);  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)	{	  fputs ("\"\n\t.STRING \"", file);	  chars_output = 0;	}      fwrite (partial_output, 1, co, file);      chars_output += co;      co = 0;    }  fputs ("\"\n", file);}/* Try to rewrite floating point comparisons & branches to avoid   useless add,tr insns.   CHECK_NOTES is nonzero if we should examine REG_DEAD notes   to see if FPCC is dead.  CHECK_NOTES is nonzero for the   first attempt to remove useless add,tr insns.  It is zero   for the second pass as reorg sometimes leaves bogus REG_DEAD   notes lying around.   When CHECK_NOTES is zero we can only eliminate add,tr insns   when there's a 1:1 correspondence between fcmp and ftest/fbranch   instructions.  */voidremove_useless_addtr_insns (insns, check_notes)     rtx insns;     int check_notes;{  rtx insn;  int all;  static int pass = 0;  /* This is fairly cheap, so always run it when optimizing.  */  if (optimize > 0)    {      int fcmp_count = 0;      int fbranch_count = 0;      /* Walk all the insns in this function looking for fcmp & fbranch	 instructions.  Keep track of how many of each we find.  */      insns = get_insns ();      for (insn = insns; insn; insn = next_insn (insn))	{	  rtx tmp;	  /* Ignore anything that isn't an INSN or a JUMP_INSN.  */	  if (GET_CODE (insn) != INSN && GET_CODE (insn) != JUMP_INSN)	    continue;	  tmp = PATTERN (insn);	  /* It must be a set.  */	  if (GET_CODE (tmp) != SET)	    continue;	  /* If the destination is CCFP, then we've found an fcmp insn.  */	  tmp = SET_DEST (tmp);	  if (GET_CODE (tmp) == REG && REGNO (tmp) == 0)	    {	      fcmp_count++;	      continue;	    }	    	  tmp = PATTERN (insn);	  /* If this is an fbranch instruction, bump the fbranch counter.  */	  if (GET_CODE (tmp) == SET	      && SET_DEST (tmp) == pc_rtx	      && GET_CODE (SET_SRC (tmp)) == IF_THEN_ELSE	      && GET_CODE (XEXP (SET_SRC (tmp), 0)) == NE	      && GET_CODE (XEXP (XEXP (SET_SRC (tmp), 0), 0)) == REG	      && REGNO (XEXP (XEXP (SET_SRC (tmp), 0), 0)) == 0)	    {	      fbranch_count++;	      continue;	    }	}      /* Find all floating point compare + branch insns.  If possible,	 reverse the comparison & the branch to avoid add,tr insns.  */      for (insn = insns; insn; insn = next_insn (insn))	{	  rtx tmp, next;	  /* Ignore anything that isn't an INSN.  */	  if (GET_CODE (insn) != INSN)	    continue;	  tmp = PATTERN (insn);	  /* It must be a set.  */	  if (GET_CODE (tmp) != SET)	    continue;	  /* The destination must be CCFP, which is register zero.  */	  tmp = SET_DEST (tmp);	  if (GET_CODE (tmp) != REG || REGNO (tmp) != 0)	    continue;	  /* INSN should be a set of CCFP.	     See if the result of this insn is used in a reversed FP	     conditional branch.  If so, reverse our condition and	     the branch.  Doing so avoids useless add,tr insns.  */	  next = next_insn (insn);	  while (next)	    {	      /* Jumps, calls and labels stop our search.  */	      if (GET_CODE (next) == JUMP_INSN		  || GET_CODE (next) == CALL_INSN		  || GET_CODE (next) == CODE_LABEL)		break;	      /* As does another fcmp insn.  */	      if (GET_CODE (next) == INSN		  && GET_CODE (PATTERN (next)) == SET		  && GET_CODE (SET_DEST (PATTERN (next))) == REG		  && REGNO (SET_DEST (PATTERN (next))) == 0)		break;	      next = next_insn (next);	    }	  /* Is NEXT_INSN a branch?  */	  if (next	      && GET_CODE (next) == JUMP_INSN)	    {	      rtx pattern = PATTERN (next);	      /* If it a reversed fp conditional branch (eg uses add,tr)		 and CCFP dies, then reverse our conditional and the branch		 to avoid the add,tr.  */	      if (GET_CODE (pattern) == SET		  && SET_DEST (pattern) == pc_rtx		  && GET_CODE (SET_SRC (pattern)) == IF_THEN_ELSE		  && GET_CODE (XEXP (SET_SRC (pattern), 0)) == NE		  && GET_CODE (XEXP (XEXP (SET_SRC (pattern), 0), 0)) == REG		  && REGNO (XEXP (XEXP (SET_SRC (pattern), 0), 0)) == 0		  && GET_CODE (XEXP (SET_SRC (pattern), 1)) == PC		  && (fcmp_count == fbranch_count		      || (check_notes			  && find_regno_note (next, REG_DEAD, 0))))		{		  /* Reverse the branch.  */		  tmp = XEXP (SET_SRC (pattern), 1);		  XEXP (SET_SRC (pattern), 1) = XEXP (SET_SRC (pattern), 2);		  XEXP (SET_SRC (pattern), 2) = tmp;		  INSN_CODE (next) = -1;		  /* Reverse our condition.  */		  tmp = PATTERN (insn);		  PUT_CODE (XEXP (tmp, 1),			    reverse_condition (GET_CODE (XEXP (tmp, 1))));		}	    }	}    }  pass = !pass;}/* You may have trouble believing 

⌨️ 快捷键说明

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