rtlanal.c

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

C
1,983
字号
}/* Similar to reg_set_between_p, but check all registers in X.  Return 0   only if none of them are modified between START and END.  Return 1 if   X contains a MEM; this routine does not perform any memory aliasing.  */intmodified_between_p (x, start, end)     rtx x;     rtx start, end;{  enum rtx_code code = GET_CODE (x);  char *fmt;  int i, j;  switch (code)    {    case CONST_INT:    case CONST_DOUBLE:    case CONST:    case SYMBOL_REF:    case LABEL_REF:      return 0;    case PC:    case CC0:      return 1;    case MEM:      /* If the memory is not constant, assume it is modified.  If it is	 constant, we still have to check the address.  */      if (! RTX_UNCHANGING_P (x))	return 1;      break;    case REG:      return reg_set_between_p (x, start, end);          default:      break;    }  fmt = GET_RTX_FORMAT (code);  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)    {      if (fmt[i] == 'e' && modified_between_p (XEXP (x, i), start, end))	return 1;      if (fmt[i] == 'E')	for (j = XVECLEN (x, i) - 1; j >= 0; j--)	  if (modified_between_p (XVECEXP (x, i, j), start, end))	    return 1;    }  return 0;}/* Similar to reg_set_p, but check all registers in X.  Return 0 only if none   of them are modified in INSN.  Return 1 if X contains a MEM; this routine   does not perform any memory aliasing.  */intmodified_in_p (x, insn)     rtx x;     rtx insn;{  enum rtx_code code = GET_CODE (x);  char *fmt;  int i, j;  switch (code)    {    case CONST_INT:    case CONST_DOUBLE:    case CONST:    case SYMBOL_REF:    case LABEL_REF:      return 0;    case PC:    case CC0:      return 1;    case MEM:      /* If the memory is not constant, assume it is modified.  If it is	 constant, we still have to check the address.  */      if (! RTX_UNCHANGING_P (x))	return 1;      break;    case REG:      return reg_set_p (x, insn);    default:      break;    }  fmt = GET_RTX_FORMAT (code);  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)    {      if (fmt[i] == 'e' && modified_in_p (XEXP (x, i), insn))	return 1;      if (fmt[i] == 'E')	for (j = XVECLEN (x, i) - 1; j >= 0; j--)	  if (modified_in_p (XVECEXP (x, i, j), insn))	    return 1;    }  return 0;}/* Given an INSN, return a SET expression if this insn has only a single SET.   It may also have CLOBBERs, USEs, or SET whose output   will not be used, which we ignore.  */rtxsingle_set (insn)     rtx insn;{  rtx set;  int i;    if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')    return 0;  if (GET_CODE (PATTERN (insn)) == SET)    return PATTERN (insn);    else if (GET_CODE (PATTERN (insn)) == PARALLEL)    {      for (i = 0, set = 0; i < XVECLEN (PATTERN (insn), 0); i++)	if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == SET	    && (! find_reg_note (insn, REG_UNUSED,				 SET_DEST (XVECEXP (PATTERN (insn), 0, i)))		|| side_effects_p (XVECEXP (PATTERN (insn), 0, i))))	  {	    if (set)	      return 0;	    else	      set = XVECEXP (PATTERN (insn), 0, i);	  }      return set;    }    return 0;}/* Return the last thing that X was assigned from before *PINSN.  Verify that   the object is not modified up to VALID_TO.  If it was, if we hit   a partial assignment to X, or hit a CODE_LABEL first, return X.  If we   found an assignment, update *PINSN to point to it.  */rtxfind_last_value (x, pinsn, valid_to)     rtx x;     rtx *pinsn;     rtx valid_to;{  rtx p;  for (p = PREV_INSN (*pinsn); p && GET_CODE (p) != CODE_LABEL;       p = PREV_INSN (p))    if (GET_RTX_CLASS (GET_CODE (p)) == 'i')      {	rtx set = single_set (p);	rtx note = find_reg_note (p, REG_EQUAL, NULL_RTX);	if (set && rtx_equal_p (x, SET_DEST (set)))	  {	    rtx src = SET_SRC (set);	    if (note && GET_CODE (XEXP (note, 0)) != EXPR_LIST)	      src = XEXP (note, 0);	    if (! modified_between_p (src, PREV_INSN (p), valid_to)		/* Reject hard registers because we don't usually want		   to use them; we'd rather use a pseudo.  */		&& ! (GET_CODE (src) == REG		      && REGNO (src) < FIRST_PSEUDO_REGISTER))	      {		*pinsn = p;		return src;	      }	  }	  	/* If set in non-simple way, we don't have a value.  */	if (reg_set_p (x, p))	  break;      }  return x;}     /* Return nonzero if register in range [REGNO, ENDREGNO)   appears either explicitly or implicitly in X   other than being stored into.   References contained within the substructure at LOC do not count.   LOC may be zero, meaning don't ignore anything.  */intrefers_to_regno_p (regno, endregno, x, loc)     int regno, endregno;     rtx x;     rtx *loc;{  register int i;  register RTX_CODE code;  register char *fmt; repeat:  /* The contents of a REG_NONNEG note is always zero, so we must come here     upon repeat in case the last REG_NOTE is a REG_NONNEG note.  */  if (x == 0)    return 0;  code = GET_CODE (x);  switch (code)    {    case REG:      i = REGNO (x);      /* If we modifying the stack, frame, or argument pointer, it will	 clobber a virtual register.  In fact, we could be more precise,	 but it isn't worth it.  */      if ((i == STACK_POINTER_REGNUM#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM	   || i == ARG_POINTER_REGNUM#endif	   || i == FRAME_POINTER_REGNUM)	  && regno >= FIRST_VIRTUAL_REGISTER && regno <= LAST_VIRTUAL_REGISTER)	return 1;      return (endregno > i	      && regno < i + (i < FIRST_PSEUDO_REGISTER 			      ? HARD_REGNO_NREGS (i, GET_MODE (x))			      : 1));    case SUBREG:      /* If this is a SUBREG of a hard reg, we can see exactly which	 registers are being modified.  Otherwise, handle normally.  */      if (GET_CODE (SUBREG_REG (x)) == REG	  && REGNO (SUBREG_REG (x)) < FIRST_PSEUDO_REGISTER)	{	  int inner_regno = REGNO (SUBREG_REG (x)) + SUBREG_WORD (x);	  int inner_endregno	    = inner_regno + (inner_regno < FIRST_PSEUDO_REGISTER			     ? HARD_REGNO_NREGS (regno, GET_MODE (x)) : 1);	  return endregno > inner_regno && regno < inner_endregno;	}      break;    case CLOBBER:    case SET:      if (&SET_DEST (x) != loc	  /* Note setting a SUBREG counts as referring to the REG it is in for	     a pseudo but not for hard registers since we can	     treat each word individually.  */	  && ((GET_CODE (SET_DEST (x)) == SUBREG	       && loc != &SUBREG_REG (SET_DEST (x))	       && GET_CODE (SUBREG_REG (SET_DEST (x))) == REG	       && REGNO (SUBREG_REG (SET_DEST (x))) >= FIRST_PSEUDO_REGISTER	       && refers_to_regno_p (regno, endregno,				     SUBREG_REG (SET_DEST (x)), loc))	      || (GET_CODE (SET_DEST (x)) != REG		  && refers_to_regno_p (regno, endregno, SET_DEST (x), loc))))	return 1;      if (code == CLOBBER || loc == &SET_SRC (x))	return 0;      x = SET_SRC (x);      goto repeat;    default:      break;    }  /* X does not match, so try its subexpressions.  */  fmt = GET_RTX_FORMAT (code);  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)    {      if (fmt[i] == 'e' && loc != &XEXP (x, i))	{	  if (i == 0)	    {	      x = XEXP (x, 0);	      goto repeat;	    }	  else	    if (refers_to_regno_p (regno, endregno, XEXP (x, i), loc))	      return 1;	}      else if (fmt[i] == 'E')	{	  register int j;	  for (j = XVECLEN (x, i) - 1; j >=0; j--)	    if (loc != &XVECEXP (x, i, j)		&& refers_to_regno_p (regno, endregno, XVECEXP (x, i, j), loc))	      return 1;	}    }  return 0;}/* Nonzero if modifying X will affect IN.  If X is a register or a SUBREG,   we check if any register number in X conflicts with the relevant register   numbers.  If X is a constant, return 0.  If X is a MEM, return 1 iff IN   contains a MEM (we don't bother checking for memory addresses that can't   conflict because we expect this to be a rare case.  */intreg_overlap_mentioned_p (x, in)     rtx x, in;{  int regno, endregno;  if (GET_CODE (x) == SUBREG)    {      regno = REGNO (SUBREG_REG (x));      if (regno < FIRST_PSEUDO_REGISTER)	regno += SUBREG_WORD (x);    }  else if (GET_CODE (x) == REG)    regno = REGNO (x);  else if (CONSTANT_P (x))    return 0;  else if (GET_CODE (x) == MEM)    {      char *fmt;      int i;      if (GET_CODE (in) == MEM)	return 1;      fmt = GET_RTX_FORMAT (GET_CODE (in));      for (i = GET_RTX_LENGTH (GET_CODE (in)) - 1; i >= 0; i--)	if (fmt[i] == 'e' && reg_overlap_mentioned_p (x, XEXP (in, i)))	  return 1;      return 0;    }  else if (GET_CODE (x) == SCRATCH || GET_CODE (x) == PC	   || GET_CODE (x) == CC0)    return reg_mentioned_p (x, in);  else    abort ();  endregno = regno + (regno < FIRST_PSEUDO_REGISTER		      ? HARD_REGNO_NREGS (regno, GET_MODE (x)) : 1);  return refers_to_regno_p (regno, endregno, in, NULL_PTR);}/* Used for communications between the next few functions.  */static int reg_set_last_unknown;static rtx reg_set_last_value;static int reg_set_last_first_regno, reg_set_last_last_regno;/* Called via note_stores from reg_set_last.  */static voidreg_set_last_1 (x, pat)     rtx x;     rtx pat;{  int first, last;  /* If X is not a register, or is not one in the range we care     about, ignore.  */  if (GET_CODE (x) != REG)    return;  first = REGNO (x);  last = first + (first < FIRST_PSEUDO_REGISTER		  ? HARD_REGNO_NREGS (first, GET_MODE (x)) : 1);  if (first >= reg_set_last_last_regno      || last <= reg_set_last_first_regno)    return;  /* If this is a CLOBBER or is some complex LHS, or doesn't modify     exactly the registers we care about, show we don't know the value.  */  if (GET_CODE (pat) == CLOBBER || SET_DEST (pat) != x      || first != reg_set_last_first_regno      || last != reg_set_last_last_regno)    reg_set_last_unknown = 1;  else    reg_set_last_value = SET_SRC (pat);}/* Return the last value to which REG was set prior to INSN.  If we can't   find it easily, return 0.   We only return a REG, SUBREG, or constant because it is too hard to   check if a MEM remains unchanged.  */rtxreg_set_last (x, insn)     rtx x;     rtx insn;{  rtx orig_insn = insn;  reg_set_last_first_regno = REGNO (x);  reg_set_last_last_regno    = reg_set_last_first_regno      + (reg_set_last_first_regno < FIRST_PSEUDO_REGISTER	 ? HARD_REGNO_NREGS (reg_set_last_first_regno, GET_MODE (x)) : 1);  reg_set_last_unknown = 0;  reg_set_last_value = 0;  /* Scan backwards until reg_set_last_1 changed one of the above flags.     Stop when we reach a label or X is a hard reg and we reach a     CALL_INSN (if reg_set_last_last_regno is a hard reg).     If we find a set of X, ensure that its SET_SRC remains unchanged.  */  /* We compare with <= here, because reg_set_last_last_regno     is actually the number of the first reg *not* in X.  */  for (;       insn && GET_CODE (insn) != CODE_LABEL       && ! (GET_CODE (insn) == CALL_INSN	     && reg_set_last_last_regno <= FIRST_PSEUDO_REGISTER);       insn = PREV_INSN (insn))    if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')      {	note_stores (PATTERN (insn), reg_set_last_1);	if (reg_set_last_unknown)	  return 0;	else if (reg_set_last_value)	  {	    if (CONSTANT_P (reg_set_last_value)		|| ((GET_CODE (reg_set_last_value) == REG		     || GET_CODE (reg_set_last_value) == SUBREG)		    && ! reg_set_between_p (reg_set_last_value,					    insn, orig_insn)))	      return reg_set_last_value;	    else	      return 0;	  }      }  return 0;}/* This is 1 until after the rtl generation pass.  */int rtx_equal_function_value_matters;/* Return 1 if X and Y are identical-looking rtx's.   This is the Lisp function EQUAL for rtx arguments.  */intrtx_equal_p (x, y)     rtx x, y;{  register int i;  register int j;  register enum rtx_code code;  register char *fmt;  if (x == y)    return 1;  if (x == 0 || y == 0)    return 0;  code = GET_CODE (x);  /* Rtx's of different codes cannot be equal.  */  if (code != GET_CODE (y))    return 0;  /* (MULT:SI x y) and (MULT:HI x y) are NOT equivalent.     (REG:SI x) and (REG:HI x) are NOT equivalent.  */  if (GET_MODE (x) != GET_MODE (y))    return 0;  /* REG, LABEL_REF, and SYMBOL_REF can be compared nonrecursively.  */  if (code == REG)    /* Until rtl generation is complete, don't consider a reference to the       return register of the current function the same as the return from a       called function.  This eases the job of function integration.  Once the       distinction is no longer needed, they can be considered equivalent.  */    return (REGNO (x) == REGNO (y)	    && (! rtx_equal_function_value_matters		|| REG_FUNCTION_VALUE_P (x) == REG_FUNCTION_VALUE_P (y)));  else if (code == LABEL_REF)    return XEXP (x, 0) == XEXP (y, 0);

⌨️ 快捷键说明

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