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

📄 recog.c

📁 这是完整的gcc源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
      if (operand_locs)	operand_locs[0] = &SET_DEST (body);      if (constraints)	constraints[0] = XSTR (asmop, 1);      if (modes)	modes[0] = GET_MODE (SET_DEST (body));      template = XSTR (asmop, 0);    }  else if (GET_CODE (body) == ASM_OPERANDS)    {      rtx asmop = body;      /* No output operands: BODY is (asm_operands ....).  */      noperands = XVECLEN (asmop, 3);      /* The input operands are found in the 1st element vector.  */      /* Constraints for inputs are in the 2nd element vector.  */      for (i = 0; i < noperands; i++)	{	  if (operand_locs)	    operand_locs[i] = &XVECEXP (asmop, 3, i);	  if (operands)	    operands[i] = XVECEXP (asmop, 3, i);	  if (constraints)	    constraints[i] = XSTR (XVECEXP (asmop, 4, i), 0);	  if (modes)	    modes[i] = GET_MODE (XVECEXP (asmop, 4, i));	}      template = XSTR (asmop, 0);    }  else if (GET_CODE (body) == PARALLEL	   && GET_CODE (XVECEXP (body, 0, 0)) == SET)    {      rtx asmop = SET_SRC (XVECEXP (body, 0, 0));      int nparallel = XVECLEN (body, 0); /* Includes CLOBBERs.  */      int nin = XVECLEN (asmop, 3);      int nout = 0;		/* Does not include CLOBBERs.  */      /* At least one output, plus some CLOBBERs.  */      /* The outputs are in the SETs.	 Their constraints are in the ASM_OPERANDS itself.  */      for (i = 0; i < nparallel; i++)	{	  if (GET_CODE (XVECEXP (body, 0, i)) == CLOBBER)	    break;		/* Past last SET */	  	  if (operands)	    operands[i] = SET_DEST (XVECEXP (body, 0, i));	  if (operand_locs)	    operand_locs[i] = &SET_DEST (XVECEXP (body, 0, i));	  if (constraints)	    constraints[i] = XSTR (SET_SRC (XVECEXP (body, 0, i)), 1);	  if (modes)	    modes[i] = GET_MODE (SET_DEST (XVECEXP (body, 0, i)));	  nout++;	}      /* The input operands are found in the 1st element vector.  */      /* Constraints for inputs are in the 2nd element vector.  */      for (i = 0; i < nin; i++)	{	  if (operand_locs)	    operand_locs[i + nout] = &XVECEXP (asmop, 3, i);	  if (operands)	    operands[i + nout] = XVECEXP (asmop, 3, i);	  if (constraints)	    constraints[i + nout] = XSTR (XVECEXP (asmop, 4, i), 0);	  if (modes)	    modes[i + nout] = GET_MODE (XVECEXP (asmop, 4, i));	}      template = XSTR (asmop, 0);    }  else if (GET_CODE (body) == PARALLEL	   && GET_CODE (XVECEXP (body, 0, 0)) == ASM_OPERANDS)    {      /* No outputs, but some CLOBBERs.  */      rtx asmop = XVECEXP (body, 0, 0);      int nin = XVECLEN (asmop, 3);      /* The input operands are found in the 1st element vector.  */      /* Constraints for inputs are in the 2nd element vector.  */      for (i = 0; i < nin; i++)	{	  if (operand_locs)	    operand_locs[i] = &XVECEXP (asmop, 3, i);	  if (operands)	    operands[i] = XVECEXP (asmop, 3, i);	  if (constraints)	    constraints[i] = XSTR (XVECEXP (asmop, 4, i), 0);	  if (modes)	    modes[i] = GET_MODE (XVECEXP (asmop, 4, i));	}      template = XSTR (asmop, 0);    }  return template;}extern rtx plus_constant ();extern rtx copy_rtx ();/* Given an rtx *P, if it is a sum containing an integer constant term,   return the location (type rtx *) of the pointer to that constant term.   Otherwise, return a null pointer.  */static rtx *find_constant_term_loc (p)     rtx *p;{  register rtx *tem;  register enum rtx_code code = GET_CODE (*p);  /* If *P IS such a constant term, P is its location.  */  if (code == CONST_INT || code == SYMBOL_REF || code == LABEL_REF      || code == CONST)    return p;  /* Otherwise, if not a sum, it has no constant term.  */  if (GET_CODE (*p) != PLUS)    return 0;  /* If one of the summands is constant, return its location.  */  if (XEXP (*p, 0) && CONSTANT_P (XEXP (*p, 0))      && XEXP (*p, 1) && CONSTANT_P (XEXP (*p, 1)))    return p;  /* Otherwise, check each summand for containing a constant term.  */  if (XEXP (*p, 0) != 0)    {      tem = find_constant_term_loc (&XEXP (*p, 0));      if (tem != 0)	return tem;    }  if (XEXP (*p, 1) != 0)    {      tem = find_constant_term_loc (&XEXP (*p, 1));      if (tem != 0)	return tem;    }  return 0;}/* Return 1 if OP is a memory reference   whose address contains no side effects   and remains valid after the addition   of a positive integer less than the   size of the object being referenced.   We assume that the original address is valid and do not check it.   This uses strict_memory_address_p as a subroutine, so   don't use it before reload.  */intoffsettable_memref_p (op)     rtx op;{  return ((GET_CODE (op) == MEM)	  && offsettable_address_p (1, GET_MODE (op), XEXP (op, 0)));}/* Return 1 if Y is a memory address which contains no side effects   and would remain valid for mode MODE   after the addition of a positive integer less than the   size of that mode.   We assume that the original address is valid and do not check it.   If STRICTP is nonzero, we require a strictly valid address,   for the sake of use in reload.c.  */intoffsettable_address_p (strictp, mode, y)     int strictp;     enum machine_mode mode;     register rtx y;{  register enum rtx_code ycode = GET_CODE (y);  register rtx z;  rtx y1 = y;  rtx *y2;  int (*addressp) () = (strictp ? strict_memory_address_p : memory_address_p);  if (CONSTANT_ADDRESS_P (y))    return 1;#ifdef OFFSETTABLE_ADDRESS_P  return OFFSETTABLE_ADDRESS_P (mode, y);#else  /* If the expression contains a constant term,     see if it remains valid when max possible offset is added.  */  if ((ycode == PLUS) && (y2 = find_constant_term_loc (&y1)))    {      int old = INTVAL (y1 = *y2);      int good;      INTVAL (y1) += GET_MODE_SIZE (mode) - 1;      good = (*addressp) (mode, y);      /* In any case, restore old contents of memory.  */      INTVAL (y1) = old;      return good;    }  if (ycode == PRE_DEC || ycode == PRE_INC      || ycode == POST_DEC || ycode == POST_INC)    return 0;  /* The offset added here is chosen as the maximum offset that     any instruction could need to add when operating on something     of the specified mode.  We assume that if Y and Y+c are     valid addresses then so is Y+d for all 0<d<c.  */  z = plus_constant (y, GET_MODE_SIZE (mode) - 1);  return (*addressp) (mode, z);#endif}/* Return 1 if ADDR is an address-expression whose effect depends   on the mode of the memory reference it is used in.   Autoincrement addressing is a typical example of mode-dependence   because the amount of the increment depends on the mode.  */intmode_dependent_address_p (addr)     rtx addr;{  GO_IF_MODE_DEPENDENT_ADDRESS (addr, win);  return 0; win:  return 1;}/* Return 1 if OP is a general operand   other than a memory ref with a mode dependent address.  */intmode_independent_operand (op, mode)     enum machine_mode mode;     rtx op;{  rtx addr;  if (! general_operand (op, mode))    return 0;  if (GET_CODE (op) != MEM)    return 1;  addr = XEXP (op, 0);  GO_IF_MODE_DEPENDENT_ADDRESS (addr, lose);  return 1; lose:  return 0;}/* Given an operand OP that is a valid memory reference   which satisfies offsettable_memref_p,   return a new memory reference whose address has been adjusted by OFFSET.   OFFSET should be positive and less than the size of the object referenced.*/rtxadj_offsettable_operand (op, offset)     rtx op;     int offset;{  register enum rtx_code code = GET_CODE (op);  if (code == MEM)     {      register rtx y = XEXP (op, 0);      if (CONSTANT_ADDRESS_P (y))	return gen_rtx (MEM, GET_MODE (op), plus_constant (y, offset));      if (GET_CODE (y) == PLUS)	{	  rtx z = y;	  register rtx *const_loc;	  op = copy_rtx (op);	  z = XEXP (op, 0);	  const_loc = find_constant_term_loc (&z);	  if (const_loc)	    {	      *const_loc = plus_constant (*const_loc, offset);	      return op;	    }	}      return gen_rtx (MEM, GET_MODE (op), plus_constant (y, offset));    }  abort ();}#ifdef REGISTER_CONSTRAINTS/* Check the operands of an insn (found in recog_operands)   against the insn's operand constraints (found via INSN_CODE_NUM)   and return 1 if they are valid.   WHICH_ALTERNATIVE is set to a number which indicates which   alternative of constraints was matched: 0 for the first alternative,   1 for the next, etc.   In addition, when two operands are match   and it happens that the output operand is (reg) while the   input operand is --(reg) or ++(reg) (a pre-inc or pre-dec),   make the output operand look like the input.   This is because the output operand is the one the template will print.   This is used in final, just before printing the assembler code.  */struct funny_match{  int this, other;};intconstrain_operands (insn_code_num)     int insn_code_num;{  char *constraints[MAX_RECOG_OPERANDS];  register int c;  int noperands = insn_n_operands[insn_code_num];  struct funny_match funny_match[MAX_RECOG_OPERANDS];  int funny_match_index;  int nalternatives = insn_n_alternatives[insn_code_num];  if (noperands == 0 || nalternatives == 0)    return 1;  for (c = 0; c < noperands; c++)    constraints[c] = insn_operand_constraint[insn_code_num][c];  which_alternative = 0;  while (which_alternative < nalternatives)    {      register int opno;      int lose = 0;      funny_match_index = 0;      for (opno = 0; opno < noperands; opno++)	{	  register rtx op = recog_operand[opno];	  register char *p = constraints[opno];	  int win = 0;	  int val;	  /* `alter_subreg' should already have converted any SUBREG	     that appears at the level of an operand.  */	  while (GET_CODE (op) == SUBREG)	    abort ();	  /* An empty constraint or empty alternative	     allows anything which matched the pattern.  */	  if (*p == 0 || *p == ',')	    win = 1;	  while (*p && (c = *p++) != ',')	    switch (c)	      {	      case '=':	      case '+':	      case '?':	      case '#':	      case '&':	      case '!':	      case '*':	      case '%':		break;	      case '0':	      case '1':	      case '2':	      case '3':	      case '4':		/* This operand must be the same as a previous one.  */		/* This kind of constraint is used for instructions such		   as add when they take only two operands.  */		/* Note that the lower-numbered operand is passed first.  */		val = operands_match_p (recog_operand[c - '0'],					recog_operand[opno]);		if (val != 0)		  win = 1;		/* If output is *x and input is *--x,		   arrange later to change the output to *--x as well,		   since the output op is the one that will be printed.  */		if (val == 2)		  {		    funny_match[funny_match_index].this = opno;		    funny_match[funny_match_index++].other = c - '0';		  }		break;	      case 'p':		/* p is used for address_operands, and everything		   that must be checked was checked already.  */		win = 1;		break;		/* No need to check general_operand again;		   it was done in insn-recog.c.  */	      case 'g':		/* Anything goes unless it is a REG and really has a hard reg		   but the hard reg is not in the class GENERAL_REGS.  */		if (GENERAL_REGS == ALL_REGS		    || GET_CODE (op) != REG		    || reg_fits_class_p (op, GENERAL_REGS, 0, GET_MODE (op)))		  win = 1;		break;	      case 'r':		if (GET_CODE (op) == REG		    && (GENERAL_REGS == ALL_REGS			|| reg_fits_class_p (op, GENERAL_REGS, 0, GET_MODE (op))))		  win = 1;		break;	      case 'm':		if (GET_CODE (op) == MEM)		  win = 1;		break;	      case '<':		if (GET_CODE (op) == MEM		    && (GET_CODE (XEXP (op, 0)) == PRE_DEC			|| GET_CODE (XEXP (op, 0)) == POST_DEC))		  win = 1;		break;	      case '>':		if (GET_CODE (op) == MEM		    && (GET_CODE (XEXP (op, 0)) == PRE_INC			|| GET_CODE (XEXP (op, 0)) == POST_INC))		  win = 1;		break;	      case 'F':		if (GET_CODE (op) == CONST_DOUBLE)		  win = 1;		break;	      case 'G':	      case 'H':		if (GET_CODE (op) == CONST_DOUBLE		    && CONST_DOUBLE_OK_FOR_LETTER_P (op, c))		  win = 1;		break;	      case 's':		if (GET_CODE (op) == CONST_INT)		  break;	      case 'i':		if (CONSTANT_P (op))		  win = 1;		break;	      case 'n':		if (GET_CODE (op) == CONST_INT)		  win = 1;		break;	      case 'I':	      case 'J':	      case 'K':	      case 'L':	      case 'M':		if (GET_CODE (op) == CONST_INT		    && CONST_OK_FOR_LETTER_P (INTVAL (op), c))		  win = 1;		break;	      case 'o':		if (offsettable_memref_p (op))		  win = 1;		break;	      default:		if (GET_CODE (op) == REG		    && reg_fits_class_p (op, REG_CLASS_FROM_LETTER (c),					 0, GET_MODE (op)))		  win = 1;	      }	  constraints[opno] = p;	  /* If this operand did not win somehow,	     this alternative loses.  */	  if (! win)	    lose = 1;	}      /* This alternative won; the operands are ok.	 Change whichever operands this alternative says to change.  */      if (! lose)	{	  while (--funny_match_index >= 0)	    {	      recog_operand[funny_match[funny_match_index].other]		= recog_operand[funny_match[funny_match_index].this];	    }	  return 1;	}      which_alternative++;    }  return 0;}/* Return 1 iff OPERAND (assumed to be a REG rtx)   is a hard reg in class CLASS when its regno is offsetted by OFFSET   and changed to mode MODE.   If REG occupies multiple hard regs, all of them must be in CLASS.  */intreg_fits_class_p (operand, class, offset, mode)     rtx operand;     register enum reg_class class;     int offset;     enum machine_mode mode;{  register int regno = REGNO (operand);  if (regno < FIRST_PSEUDO_REGISTER      && TEST_HARD_REG_BIT (reg_class_contents[(int) class],			    regno + offset))    {      register int sr;      regno += offset;      for (sr = HARD_REGNO_NREGS (regno, mode) - 1;	   sr > 0; sr--)	if (! TEST_HARD_REG_BIT (reg_class_contents[(int) class],				 regno + sr))	  break;      return sr == 0;    }  return 0;}#endif /* REGISTER_CONSTRAINTS */

⌨️ 快捷键说明

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