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

📄 rtlanal.c

📁 gcc库的原代码,对编程有很大帮助.
💻 C
📖 第 1 页 / 共 3 页
字号:
/* Analyze RTL for C-Compiler   Copyright (C) 1987, 88, 91, 92, 93, 94, 1995 Free Software Foundation, Inc.This file is part of GNU CC.GNU CC is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 2, or (at your option)any later version.GNU CC is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU CC; see the file COPYING.  If not, write tothe Free Software Foundation, 59 Temple Place - Suite 330,Boston, MA 02111-1307, USA.  */#include "config.h"#include "rtl.h"void note_stores ();int reg_set_p ();/* Bit flags that specify the machine subtype we are compiling for.   Bits are tested using macros TARGET_... defined in the tm.h file   and set by `-m...' switches.  Must be defined in rtlanal.c.  */int target_flags;/* Return 1 if the value of X is unstable   (would be different at a different point in the program).   The frame pointer, arg pointer, etc. are considered stable   (within one function) and so is anything marked `unchanging'.  */intrtx_unstable_p (x)     rtx x;{  register RTX_CODE code = GET_CODE (x);  register int i;  register char *fmt;  if (code == MEM)    return ! RTX_UNCHANGING_P (x);  if (code == QUEUED)    return 1;  if (code == CONST || code == CONST_INT)    return 0;  if (code == REG)    return ! (REGNO (x) == FRAME_POINTER_REGNUM	      || REGNO (x) == HARD_FRAME_POINTER_REGNUM	      || REGNO (x) == ARG_POINTER_REGNUM	      || RTX_UNCHANGING_P (x));  fmt = GET_RTX_FORMAT (code);  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)    if (fmt[i] == 'e')      if (rtx_unstable_p (XEXP (x, i)))	return 1;  return 0;}/* Return 1 if X has a value that can vary even between two   executions of the program.  0 means X can be compared reliably   against certain constants or near-constants.   The frame pointer and the arg pointer are considered constant.  */intrtx_varies_p (x)     rtx x;{  register RTX_CODE code = GET_CODE (x);  register int i;  register char *fmt;  switch (code)    {    case MEM:    case QUEUED:      return 1;    case CONST:    case CONST_INT:    case CONST_DOUBLE:    case SYMBOL_REF:    case LABEL_REF:      return 0;    case REG:      /* Note that we have to test for the actual rtx used for the frame	 and arg pointers and not just the register number in case we have	 eliminated the frame and/or arg pointer and are using it	 for pseudos.  */      return ! (x == frame_pointer_rtx || x == hard_frame_pointer_rtx		|| x == arg_pointer_rtx);    case LO_SUM:      /* The operand 0 of a LO_SUM is considered constant	 (in fact is it related specifically to operand 1).  */      return rtx_varies_p (XEXP (x, 1));    }  fmt = GET_RTX_FORMAT (code);  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)    if (fmt[i] == 'e')      if (rtx_varies_p (XEXP (x, i)))	return 1;  return 0;}/* Return 0 if the use of X as an address in a MEM can cause a trap.  */intrtx_addr_can_trap_p (x)     register rtx x;{  register enum rtx_code code = GET_CODE (x);  switch (code)    {    case SYMBOL_REF:    case LABEL_REF:      /* SYMBOL_REF is problematic due to the possible presence of	 a #pragma weak, but to say that loads from symbols can trap is	 *very* costly.  It's not at all clear what's best here.  For	 now, we ignore the impact of #pragma weak.  */      return 0;    case REG:      /* As in rtx_varies_p, we have to use the actual rtx, not reg number.  */      return ! (x == frame_pointer_rtx || x == hard_frame_pointer_rtx		|| x == stack_pointer_rtx || x == arg_pointer_rtx);    case CONST:      return rtx_addr_can_trap_p (XEXP (x, 0));    case PLUS:      /* An address is assumed not to trap if it is an address that can't	 trap plus a constant integer.  */      return (rtx_addr_can_trap_p (XEXP (x, 0))	      || GET_CODE (XEXP (x, 1)) != CONST_INT);    case LO_SUM:      return rtx_addr_can_trap_p (XEXP (x, 1));    }  /* If it isn't one of the case above, it can cause a trap.  */  return 1;}/* Return 1 if X refers to a memory location whose address    cannot be compared reliably with constant addresses,   or if X refers to a BLKmode memory object.  */intrtx_addr_varies_p (x)     rtx x;{  register enum rtx_code code;  register int i;  register char *fmt;  if (x == 0)    return 0;  code = GET_CODE (x);  if (code == MEM)    return GET_MODE (x) == BLKmode || rtx_varies_p (XEXP (x, 0));  fmt = GET_RTX_FORMAT (code);  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)    if (fmt[i] == 'e')      if (rtx_addr_varies_p (XEXP (x, i)))	return 1;  return 0;}/* Return the value of the integer term in X, if one is apparent;   otherwise return 0.   Only obvious integer terms are detected.   This is used in cse.c with the `related_value' field.*/HOST_WIDE_INTget_integer_term (x)     rtx x;{  if (GET_CODE (x) == CONST)    x = XEXP (x, 0);  if (GET_CODE (x) == MINUS      && GET_CODE (XEXP (x, 1)) == CONST_INT)    return - INTVAL (XEXP (x, 1));  if (GET_CODE (x) == PLUS      && GET_CODE (XEXP (x, 1)) == CONST_INT)    return INTVAL (XEXP (x, 1));  return 0;}/* If X is a constant, return the value sans apparent integer term;   otherwise return 0.   Only obvious integer terms are detected.  */rtxget_related_value (x)     rtx x;{  if (GET_CODE (x) != CONST)    return 0;  x = XEXP (x, 0);  if (GET_CODE (x) == PLUS      && GET_CODE (XEXP (x, 1)) == CONST_INT)    return XEXP (x, 0);  else if (GET_CODE (x) == MINUS	   && GET_CODE (XEXP (x, 1)) == CONST_INT)    return XEXP (x, 0);  return 0;}/* Nonzero if register REG appears somewhere within IN.   Also works if REG is not a register; in this case it checks   for a subexpression of IN that is Lisp "equal" to REG.  */intreg_mentioned_p (reg, in)     register rtx reg, in;{  register char *fmt;  register int i;  register enum rtx_code code;  if (in == 0)    return 0;  if (reg == in)    return 1;  if (GET_CODE (in) == LABEL_REF)    return reg == XEXP (in, 0);  code = GET_CODE (in);  switch (code)    {      /* Compare registers by number.  */    case REG:      return GET_CODE (reg) == REG && REGNO (in) == REGNO (reg);      /* These codes have no constituent expressions	 and are unique.  */    case SCRATCH:    case CC0:    case PC:      return 0;    case CONST_INT:      return GET_CODE (reg) == CONST_INT && INTVAL (in) == INTVAL (reg);          case CONST_DOUBLE:      /* These are kept unique for a given value.  */      return 0;    }  if (GET_CODE (reg) == code && rtx_equal_p (reg, in))    return 1;  fmt = GET_RTX_FORMAT (code);  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)    {      if (fmt[i] == 'E')	{	  register int j;	  for (j = XVECLEN (in, i) - 1; j >= 0; j--)	    if (reg_mentioned_p (reg, XVECEXP (in, i, j)))	      return 1;	}      else if (fmt[i] == 'e'	       && reg_mentioned_p (reg, XEXP (in, i)))	return 1;    }  return 0;}/* Return 1 if in between BEG and END, exclusive of BEG and END, there is   no CODE_LABEL insn.  */intno_labels_between_p (beg, end)     rtx beg, end;{  register rtx p;  for (p = NEXT_INSN (beg); p != end; p = NEXT_INSN (p))    if (GET_CODE (p) == CODE_LABEL)      return 0;  return 1;}/* Nonzero if register REG is used in an insn between   FROM_INSN and TO_INSN (exclusive of those two).  */intreg_used_between_p (reg, from_insn, to_insn)     rtx reg, from_insn, to_insn;{  register rtx insn;  if (from_insn == to_insn)    return 0;  for (insn = NEXT_INSN (from_insn); insn != to_insn; insn = NEXT_INSN (insn))    if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'	&& (reg_overlap_mentioned_p (reg, PATTERN (insn))	   || (GET_CODE (insn) == CALL_INSN	      && (find_reg_fusage (insn, USE, reg)		  || find_reg_fusage (insn, CLOBBER, reg)))))      return 1;  return 0;}/* Nonzero if the old value of X, a register, is referenced in BODY.  If X   is entirely replaced by a new value and the only use is as a SET_DEST,   we do not consider it a reference.  */intreg_referenced_p (x, body)     rtx x;     rtx body;{  int i;  switch (GET_CODE (body))    {    case SET:      if (reg_overlap_mentioned_p (x, SET_SRC (body)))	return 1;      /* If the destination is anything other than CC0, PC, a REG or a SUBREG	 of a REG that occupies all of the REG, the insn references X if	 it is mentioned in the destination.  */      if (GET_CODE (SET_DEST (body)) != CC0	  && GET_CODE (SET_DEST (body)) != PC	  && GET_CODE (SET_DEST (body)) != REG	  && ! (GET_CODE (SET_DEST (body)) == SUBREG		&& GET_CODE (SUBREG_REG (SET_DEST (body))) == REG		&& (((GET_MODE_SIZE (GET_MODE (SUBREG_REG (SET_DEST (body))))		      + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)		    == ((GET_MODE_SIZE (GET_MODE (SET_DEST (body)))			 + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)))	  && reg_overlap_mentioned_p (x, SET_DEST (body)))	return 1;      break;    case ASM_OPERANDS:      for (i = ASM_OPERANDS_INPUT_LENGTH (body) - 1; i >= 0; i--)	if (reg_overlap_mentioned_p (x, ASM_OPERANDS_INPUT (body, i)))	  return 1;      break;    case CALL:    case USE:      return reg_overlap_mentioned_p (x, body);    case TRAP_IF:      return reg_overlap_mentioned_p (x, TRAP_CONDITION (body));    case UNSPEC:    case UNSPEC_VOLATILE:    case PARALLEL:      for (i = XVECLEN (body, 0) - 1; i >= 0; i--)	if (reg_referenced_p (x, XVECEXP (body, 0, i)))	  return 1;      break;    }  return 0;}/* Nonzero if register REG is referenced in an insn between   FROM_INSN and TO_INSN (exclusive of those two).  Sets of REG do   not count. */intreg_referenced_between_p (reg, from_insn, to_insn)     rtx reg, from_insn, to_insn;{  register rtx insn;  if (from_insn == to_insn)    return 0;  for (insn = NEXT_INSN (from_insn); insn != to_insn; insn = NEXT_INSN (insn))    if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'	&& (reg_referenced_p (reg, PATTERN (insn))	   || (GET_CODE (insn) == CALL_INSN	      && find_reg_fusage (insn, USE, reg))))      return 1;  return 0;}/* Nonzero if register REG is set or clobbered in an insn between   FROM_INSN and TO_INSN (exclusive of those two).  */intreg_set_between_p (reg, from_insn, to_insn)     rtx reg, from_insn, to_insn;{  register rtx insn;  if (from_insn == to_insn)    return 0;  for (insn = NEXT_INSN (from_insn); insn != to_insn; insn = NEXT_INSN (insn))    if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'	&& reg_set_p (reg, insn))      return 1;  return 0;}/* Internals of reg_set_between_p.  */static rtx reg_set_reg;static int reg_set_flag;static voidreg_set_p_1 (x, pat)     rtx x;{  /* We don't want to return 1 if X is a MEM that contains a register     within REG_SET_REG.  */  if ((GET_CODE (x) != MEM)      && reg_overlap_mentioned_p (reg_set_reg, x))    reg_set_flag = 1;}intreg_set_p (reg, insn)     rtx reg, insn;{  rtx body = insn;  /* We can be passed an insn or part of one.  If we are passed an insn,     check if a side-effect of the insn clobbers REG.  */  if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')    {      if (FIND_REG_INC_NOTE (insn, reg)	  || (GET_CODE (insn) == CALL_INSN	      /* We'd like to test call_used_regs here, but rtlanal.c can't		 reference that variable due to its use in genattrtab.  So		 we'll just be more conservative.		 ??? Unless we could ensure that the CALL_INSN_FUNCTION_USAGE		 information holds all clobbered registers.  */	      && ((GET_CODE (reg) == REG		   && REGNO (reg) < FIRST_PSEUDO_REGISTER)		  || GET_CODE (reg) == MEM		  || find_reg_fusage (insn, CLOBBER, reg))))	return 1;      body = PATTERN (insn);    }  reg_set_reg = reg;  reg_set_flag = 0;  note_stores (body, reg_set_p_1);  return reg_set_flag;}/* 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);    }  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);    }  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;}

⌨️ 快捷键说明

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