tc-i386.c

来自「基于4个mips核的noc设计」· C语言 代码 · 共 2,311 行 · 第 1/5 页

C
2,311
字号
	/* 1 if operand is pending after ','.  */	unsigned int expecting_operand = 0;	/* Non-zero if operand parens not balanced.  */	unsigned int paren_not_balanced;	do	  {	    /* Skip optional white space before operand.  */	    if (is_space_char (*l))	      ++l;	    if (!is_operand_char (*l) && *l != END_OF_INSN)	      {		as_bad (_("invalid character %s before operand %d"),			output_invalid (*l),			i.operands + 1);		return;	      }	    token_start = l;	/* after white space */	    paren_not_balanced = 0;	    while (paren_not_balanced || *l != ',')	      {		if (*l == END_OF_INSN)		  {		    if (paren_not_balanced)		      {			if (!intel_syntax)			  as_bad (_("unbalanced parenthesis in operand %d."),				  i.operands + 1);			else			  as_bad (_("unbalanced brackets in operand %d."),				  i.operands + 1);			return;		      }		    else		      break;	/* we are done */		  }		else if (!is_operand_char (*l) && !is_space_char (*l))		  {		    as_bad (_("invalid character %s in operand %d"),			    output_invalid (*l),			    i.operands + 1);		    return;		  }		if (!intel_syntax)		  {		    if (*l == '(')		      ++paren_not_balanced;		    if (*l == ')')		      --paren_not_balanced;		  }		else		  {		    if (*l == '[')		      ++paren_not_balanced;		    if (*l == ']')		      --paren_not_balanced;		  }		l++;	      }	    if (l != token_start)	      {			/* Yes, we've read in another operand.  */		unsigned int operand_ok;		this_operand = i.operands++;		if (i.operands > MAX_OPERANDS)		  {		    as_bad (_("spurious operands; (%d operands/instruction max)"),			    MAX_OPERANDS);		    return;		  }		/* Now parse operand adding info to 'i' as we go along.  */		END_STRING_AND_SAVE (l);		if (intel_syntax)		  operand_ok =		    i386_intel_operand (token_start,					intel_float_operand (mnemonic));		else		  operand_ok = i386_operand (token_start);		RESTORE_END_STRING (l);		if (!operand_ok)		  return;	      }	    else	      {		if (expecting_operand)		  {		  expecting_operand_after_comma:		    as_bad (_("expecting operand after ','; got nothing"));		    return;		  }		if (*l == ',')		  {		    as_bad (_("expecting operand before ','; got nothing"));		    return;		  }	      }	    /* Now *l must be either ',' or END_OF_INSN.  */	    if (*l == ',')	      {		if (*++l == END_OF_INSN)		  {		    /* Just skip it, if it's \n complain.  */		    goto expecting_operand_after_comma;		  }		expecting_operand = 1;	      }	  }	while (*l != END_OF_INSN);      }  }  /* Now we've parsed the mnemonic into a set of templates, and have the     operands at hand.     Next, we find a template that matches the given insn,     making sure the overlap of the given operands types is consistent     with the template operand types.  */#define MATCH(overlap, given, template) \  ((overlap & ~JumpAbsolute) \   && ((given) & (BaseIndex|JumpAbsolute)) == ((overlap) & (BaseIndex|JumpAbsolute)))  /* If given types r0 and r1 are registers they must be of the same type     unless the expected operand type register overlap is null.     Note that Acc in a template matches every size of reg.  */#define CONSISTENT_REGISTER_MATCH(m0, g0, t0, m1, g1, t1) \  ( ((g0) & Reg) == 0 || ((g1) & Reg) == 0 || \    ((g0) & Reg) == ((g1) & Reg) || \    ((((m0) & Acc) ? Reg : (t0)) & (((m1) & Acc) ? Reg : (t1)) & Reg) == 0 )  {    register unsigned int overlap0, overlap1;    unsigned int overlap2;    unsigned int found_reverse_match;    int suffix_check;    /* All intel opcodes have reversed operands except for "bound" and       "enter".  We also don't reverse intersegment "jmp" and "call"       instructions with 2 immediate operands so that the immediate segment       precedes the offset, as it does when in AT&T mode.  "enter" and the       intersegment "jmp" and "call" instructions are the only ones that       have two immediate operands.  */    if (intel_syntax && i.operands > 1	&& (strcmp (mnemonic, "bound") != 0)	&& !((i.types[0] & Imm) && (i.types[1] & Imm)))      {	union i386_op temp_op;	unsigned int temp_type;	RELOC_ENUM temp_reloc;	int xchg1 = 0;	int xchg2 = 0;	if (i.operands == 2)	  {	    xchg1 = 0;	    xchg2 = 1;	  }	else if (i.operands == 3)	  {	    xchg1 = 0;	    xchg2 = 2;	  }	temp_type = i.types[xchg2];	i.types[xchg2] = i.types[xchg1];	i.types[xchg1] = temp_type;	temp_op = i.op[xchg2];	i.op[xchg2] = i.op[xchg1];	i.op[xchg1] = temp_op;	temp_reloc = i.reloc[xchg2];	i.reloc[xchg2] = i.reloc[xchg1];	i.reloc[xchg1] = temp_reloc;	if (i.mem_operands == 2)	  {	    const seg_entry *temp_seg;	    temp_seg = i.seg[0];	    i.seg[0] = i.seg[1];	    i.seg[1] = temp_seg;	  }      }    if (i.imm_operands)      {	/* Try to ensure constant immediates are represented in the smallest	   opcode possible.  */	char guess_suffix = 0;	int op;	if (i.suffix)	  guess_suffix = i.suffix;	else if (i.reg_operands)	  {	    /* Figure out a suffix from the last register operand specified.	       We can't do this properly yet, ie. excluding InOutPortReg,	       but the following works for instructions with immediates.	       In any case, we can't set i.suffix yet.  */	    for (op = i.operands; --op >= 0;)	      if (i.types[op] & Reg)		{		  if (i.types[op] & Reg8)		    guess_suffix = BYTE_MNEM_SUFFIX;		  else if (i.types[op] & Reg16)		    guess_suffix = WORD_MNEM_SUFFIX;		  else if (i.types[op] & Reg32)		    guess_suffix = LONG_MNEM_SUFFIX;		  else if (i.types[op] & Reg64)		    guess_suffix = QWORD_MNEM_SUFFIX;		  break;		}	  }	else if ((flag_code == CODE_16BIT) ^ (i.prefix[DATA_PREFIX] != 0))	  guess_suffix = WORD_MNEM_SUFFIX;	for (op = i.operands; --op >= 0;)	  if (i.types[op] & Imm)	    {	      switch (i.op[op].imms->X_op)		{		  case O_constant:		    /* If a suffix is given, this operand may be shortened.  */		    switch (guess_suffix)		      {		      case LONG_MNEM_SUFFIX:			i.types[op] |= Imm32 | Imm64;			break;		      case WORD_MNEM_SUFFIX:			i.types[op] |= Imm16 | Imm32S | Imm32 | Imm64;			break;		      case BYTE_MNEM_SUFFIX:			i.types[op] |= Imm16 | Imm8 | Imm8S | Imm32S | Imm32 | Imm64;			break;		      }		    /* If this operand is at most 16 bits, convert it		       to a signed 16 bit number before trying to see		       whether it will fit in an even smaller size.		       This allows a 16-bit operand such as $0xffe0 to		       be recognised as within Imm8S range.  */		    if ((i.types[op] & Imm16)			&& (i.op[op].imms->X_add_number & ~(offsetT) 0xffff) == 0)		      {			i.op[op].imms->X_add_number =			  (((i.op[op].imms->X_add_number & 0xffff) ^ 0x8000) - 0x8000);		      }		    if ((i.types[op] & Imm32)			&& (i.op[op].imms->X_add_number & ~(((offsetT) 2 << 31) - 1)) == 0)		      {			i.op[op].imms->X_add_number =			  (i.op[op].imms->X_add_number ^ ((offsetT) 1 << 31)) - ((addressT) 1 << 31);		      }		    i.types[op] |= smallest_imm_type (i.op[op].imms->X_add_number);		    /* We must avoid matching of Imm32 templates when 64bit only immediate is available.  */		    if (guess_suffix == QWORD_MNEM_SUFFIX)		      i.types[op] &= ~Imm32;		    break;		  case O_absent:		  case O_register:		    abort ();		  /* Symbols and expressions.  */		  default:		    /* Convert symbolic operand to proper sizes for matching.  */		    switch (guess_suffix)		      {		        case QWORD_MNEM_SUFFIX:			  i.types[op] = Imm64 | Imm32S;			  break;		        case LONG_MNEM_SUFFIX:			  i.types[op] = Imm32 | Imm64;			  break;		        case WORD_MNEM_SUFFIX:			  i.types[op] = Imm16 | Imm32 | Imm64;			  break;			  break;		        case BYTE_MNEM_SUFFIX:			  i.types[op] = Imm8 | Imm8S | Imm16 | Imm32S | Imm32;				break;			  break;		      }		    break;		}	    }      }    if (i.disp_operands)      {	/* Try to use the smallest displacement type too.  */	int op;	for (op = i.operands; --op >= 0;)	  if ((i.types[op] & Disp)	      && i.op[op].disps->X_op == O_constant)	    {	      offsetT disp = i.op[op].disps->X_add_number;	      if (i.types[op] & Disp16)		{		  /* We know this operand is at most 16 bits, so		     convert to a signed 16 bit number before trying		     to see whether it will fit in an even smaller		     size.  */		  disp = (((disp & 0xffff) ^ 0x8000) - 0x8000);		}	      else if (i.types[op] & Disp32)		{		  /* We know this operand is at most 32 bits, so convert to a		     signed 32 bit number before trying to see whether it will		     fit in an even smaller size.  */		  disp &= (((offsetT) 2 << 31) - 1);		  disp = (disp ^ ((offsetT) 1 << 31)) - ((addressT) 1 << 31);		}	      if (flag_code == CODE_64BIT)		{		  if (fits_in_signed_long (disp))		    i.types[op] |= Disp32S;		  if (fits_in_unsigned_long (disp))		    i.types[op] |= Disp32;		}	      if ((i.types[op] & (Disp32 | Disp32S | Disp16))		  && fits_in_signed_byte (disp))		i.types[op] |= Disp8;	    }      }    overlap0 = 0;    overlap1 = 0;    overlap2 = 0;    found_reverse_match = 0;    suffix_check = (i.suffix == BYTE_MNEM_SUFFIX		    ? No_bSuf		    : (i.suffix == WORD_MNEM_SUFFIX		       ? No_wSuf		       : (i.suffix == SHORT_MNEM_SUFFIX			  ? No_sSuf			  : (i.suffix == LONG_MNEM_SUFFIX			     ? No_lSuf			     : (i.suffix == QWORD_MNEM_SUFFIX				? No_qSuf				: (i.suffix == LONG_DOUBLE_MNEM_SUFFIX ? No_xSuf : 0))))));    for (t = current_templates->start;	 t < current_templates->end;	 t++)      {	/* Must have right number of operands.  */	if (i.operands != t->operands)	  continue;	/* Check the suffix, except for some instructions in intel mode.  */	if ((t->opcode_modifier & suffix_check)	    && !(intel_syntax		 && (t->opcode_modifier & IgnoreSize))	    && !(intel_syntax		 && t->base_opcode == 0xd9		 && (t->extension_opcode == 5	     /* 0xd9,5 "fldcw"  */		     || t->extension_opcode == 7)))  /* 0xd9,7 "f{n}stcw"  */	  continue;	/* Do not verify operands when there are none.  */	else if (!t->operands)	  {	    if (t->cpu_flags & ~cpu_arch_flags)	      continue;	    /* We've found a match; break out of loop.  */	    break;	  }	overlap0 = i.types[0] & t->operand_types[0];	switch (t->operands)	  {	  case 1:	    if (!MATCH (overlap0, i.types[0], t->operand_types[0]))	      continue;	    break;	  case 2:	  case 3:	    overlap1 = i.types[1] & t->operand_types[1];	    if (!MATCH (overlap0, i.types[0], t->operand_types[0])		|| !MATCH (overlap1, i.types[1], t->operand_types[1])		|| !CONSISTENT_REGISTER_MATCH (overlap0, i.types[0],					       t->operand_types[0],					       overlap1, i.types[1],					       t->operand_types[1]))	      {		/* Check if other direction is valid ...  */		if ((t->opcode_modifier & (D|FloatD)) == 0)		  continue;		/* Try reversing direction of operands.  */		overlap0 = i.types[0] & t->operand_types[1];		overlap1 = i.types[1] & t->operand_types[0];		if (!MATCH (overlap0, i.types[0], t->operand_types[1])		    || !MATCH (overlap1, i.types[1], t->operand_types[0])		    || !CONSISTENT_REGISTER_MATCH (overlap0, i.types[0],						   t->operand_types[1],						   overlap1, i.types[1],						   t->operand_types[0]))		  {		    /* Does not match either direction.  */		    continue;		  }		/* found_reverse_match holds which of D or FloatDR		   we've found.  */		found_reverse_match = t->opcode_modifier & (D|FloatDR);	      }	    /* Found a forward 2 operand match here.  */	    else if (t->operands == 3)	      {		/* Here we make use of the fact that there are no		   reverse match 3 operand instructions, and all 3		   operand instructions only need to be checked for		   register consistency between operands 2 and 3.  */		overlap2 = i.types[2] & t->operand_types[2];		if (!MATCH (overlap2, i.types[2], t->operand_types[2])		    || !CONSISTENT_REGISTER_MATCH (overlap1, i.types[1],						   t->operand_types[1],						   overlap2, i.types[2],						   t->operand_types[2]))		  continue;	      }	    /* Found either forward/reverse 2 or 3 operand match here:	       slip through to break.  */	  }	if (t->cpu_flags & ~cpu_arch_flags)	  {	    found_reverse_match = 0;	    continue;	  }	/* We've found a match; break out of loop.  */	break;      }    if (t == current_templates->end)      {	/* We found no match.  */	as_bad (_("suffix or operands invalid for `%s'"),		current_templates->start->name);	return;      }    if (!quiet_warnings)      {	if (!intel_syntax	    && ((i.types[0] & JumpAbsolute)		!= (t->operand_types[0] & JumpAbsolute)))	  {	    as_warn (_("indirect %s without `*'"), t->name);	  }	if ((t->opcode_modifier & (IsPrefix|IgnoreSize))	    == (IsPrefix|IgnoreSize))	  {	    /* Warn them that a data or address size prefix doesn't	       affect assembly of the next line of code.  */	    as_warn (_("stand-alone `%s' prefix"), t->name);	  }      }    /* Copy the template we found.  */    i.tm = *t;

⌨️ 快捷键说明

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