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

📄 i386.c

📁 gcc编译工具没有什么特别
💻 C
📖 第 1 页 / 共 5 页
字号:
    optype0 = RNDOP;  if (REG_P (operands[1]))    optype1 = REGOP;  else if (CONSTANT_P (operands[1]))    optype1 = CNSTOP;  else if (offsettable_memref_p (operands[1]))    optype1 = OFFSOP;  else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)    optype1 = POPOP;  else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)    optype1 = PUSHOP;  else if (GET_CODE (operands[1]) == MEM)    optype1 = MEMOP;  else    optype1 = RNDOP;  /* Check for the cases that are not supposed to happen     either due to the operand constraints or the fact     that all memory operands on the x86 are offsettable.     Abort if we get one, because generating code for these     cases is painful.  */  if (optype0 == RNDOP || optype1 == RNDOP      || optype0 == MEMOP || optype1 == MEMOP)    abort ();  /* If one operand is decrementing and one is incrementing     decrement the former register explicitly     and change that operand into ordinary indexing.  */  if (optype0 == PUSHOP && optype1 == POPOP)    {      /* ??? Can this ever happen on i386? */      operands[0] = XEXP (XEXP (operands[0], 0), 0);      asm_add (-size, operands[0]);      if (GET_MODE (operands[1]) == XFmode)        operands[0] = gen_rtx_MEM (XFmode, operands[0]);      else if (GET_MODE (operands[0]) == DFmode)        operands[0] = gen_rtx_MEM (DFmode, operands[0]);      else        operands[0] = gen_rtx_MEM (DImode, operands[0]);      optype0 = OFFSOP;    }  if (optype0 == POPOP && optype1 == PUSHOP)    {      /* ??? Can this ever happen on i386? */      operands[1] = XEXP (XEXP (operands[1], 0), 0);      asm_add (-size, operands[1]);      if (GET_MODE (operands[1]) == XFmode)        operands[1] = gen_rtx_MEM (XFmode, operands[1]);      else if (GET_MODE (operands[1]) == DFmode)        operands[1] = gen_rtx_MEM (DFmode, operands[1]);      else        operands[1] = gen_rtx_MEM (DImode, operands[1]);      optype1 = OFFSOP;    }  /* Ok, we can do one word at a time.     Normally we do the low-numbered word first,     but if either operand is autodecrementing then we     do the high-numbered word first.     In either case, set up in LATEHALF the operands to use     for the high-numbered word and in some cases alter the     operands in OPERANDS to be suitable for the low-numbered word.  */  if (size == 12)    {      if (optype0 == REGOP)	{	  middlehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);	  latehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 2);	}      else if (optype0 == OFFSOP)	{	  middlehalf[0] = adj_offsettable_operand (operands[0], 4);	  latehalf[0] = adj_offsettable_operand (operands[0], 8);	}      else	{         middlehalf[0] = operands[0];         latehalf[0] = operands[0];	}      if (optype1 == REGOP)	{          middlehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);          latehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 2);	}      else if (optype1 == OFFSOP)	{          middlehalf[1] = adj_offsettable_operand (operands[1], 4);          latehalf[1] = adj_offsettable_operand (operands[1], 8);	}      else if (optype1 == CNSTOP)	{	  if (GET_CODE (operands[1]) == CONST_DOUBLE)	    {	      REAL_VALUE_TYPE r; long l[3];	      REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]);	      REAL_VALUE_TO_TARGET_LONG_DOUBLE (r, l);	      operands[1] = GEN_INT (l[0]);	      middlehalf[1] = GEN_INT (l[1]);	      latehalf[1] = GEN_INT (l[2]);	    }	  else if (CONSTANT_P (operands[1]))	    /* No non-CONST_DOUBLE constant should ever appear here.  */	    abort ();        }      else	{	  middlehalf[1] = operands[1];	  latehalf[1] = operands[1];	}    }  else    {      /* Size is not 12. */      if (optype0 == REGOP)	latehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);      else if (optype0 == OFFSOP)	latehalf[0] = adj_offsettable_operand (operands[0], 4);      else	latehalf[0] = operands[0];      if (optype1 == REGOP)	latehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);      else if (optype1 == OFFSOP)	latehalf[1] = adj_offsettable_operand (operands[1], 4);      else if (optype1 == CNSTOP)	split_double (operands[1], &operands[1], &latehalf[1]);      else	latehalf[1] = operands[1];    }  /* If insn is effectively movd N (sp),-(sp) then we will do the     high word first.  We should use the adjusted operand 1     (which is N+4 (sp) or N+8 (sp))     for the low word and middle word as well,     to compensate for the first decrement of sp.  */  if (optype0 == PUSHOP      && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM      && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))    middlehalf[1] = operands[1] = latehalf[1];  /* For (set (reg:DI N) (mem:DI ... (reg:SI N) ...)),     if the upper part of reg N does not appear in the MEM, arrange to     emit the move late-half first.  Otherwise, compute the MEM address     into the upper part of N and use that as a pointer to the memory     operand.  */  if (optype0 == REGOP && optype1 == OFFSOP)    {      if (reg_mentioned_p (operands[0], XEXP (operands[1], 0))	  && reg_mentioned_p (latehalf[0], XEXP (operands[1], 0)))	{	  /* If both halves of dest are used in the src memory address,	     compute the address into latehalf of dest.  */	compadr:	  xops[0] = latehalf[0];	  xops[1] = XEXP (operands[1], 0);	  output_asm_insn (AS2 (lea%L0,%a1,%0), xops);	  if (GET_MODE (operands[1]) == XFmode)	    {	      operands[1] = gen_rtx_MEM (XFmode, latehalf[0]);	      middlehalf[1] = adj_offsettable_operand (operands[1], size-8);	      latehalf[1] = adj_offsettable_operand (operands[1], size-4);	    }	  else	    {	      operands[1] = gen_rtx_MEM (DImode, latehalf[0]);	      latehalf[1] = adj_offsettable_operand (operands[1], size-4);	    }	}      else if (size == 12		 && reg_mentioned_p (middlehalf[0], XEXP (operands[1], 0)))	{	  /* Check for two regs used by both source and dest. */	  if (reg_mentioned_p (operands[0], XEXP (operands[1], 0))		|| reg_mentioned_p (latehalf[0], XEXP (operands[1], 0)))	    goto compadr;	  /* Only the middle reg conflicts; simply put it last. */	  output_asm_insn (singlemove_string (operands), operands);	  output_asm_insn (singlemove_string (latehalf), latehalf);	  output_asm_insn (singlemove_string (middlehalf), middlehalf);	  return "";	}      else if (reg_mentioned_p (operands[0], XEXP (operands[1], 0)))	/* If the low half of dest is mentioned in the source memory	   address, the arrange to emit the move late half first.  */	dest_overlapped_low = 1;    }  /* If one or both operands autodecrementing,     do the two words, high-numbered first.  */  /* Likewise,  the first move would clobber the source of the second one,     do them in the other order.  This happens only for registers;     such overlap can't happen in memory unless the user explicitly     sets it up, and that is an undefined circumstance.  */#if 0  if (optype0 == PUSHOP || optype1 == PUSHOP      || (optype0 == REGOP && optype1 == REGOP	  && REGNO (operands[0]) == REGNO (latehalf[1]))      || dest_overlapped_low)#endif  if (optype0 == PUSHOP || optype1 == PUSHOP      || (optype0 == REGOP && optype1 == REGOP	  && ((middlehalf[1] && REGNO (operands[0]) == REGNO (middlehalf[1]))	      || REGNO (operands[0]) == REGNO (latehalf[1])))      || dest_overlapped_low)    {      /* Do the high-numbered word.  */      output_asm_insn (singlemove_string (latehalf), latehalf);      if (size == 12)	output_asm_insn (singlemove_string (middlehalf), middlehalf);      /* Do low-numbered word.  */      return singlemove_string (operands);    }  /* Normal case: do the two words, low-numbered first.  */  output_asm_insn (singlemove_string (operands), operands);  /* Do the middle one of the three words for long double */  if (size == 12)    output_asm_insn (singlemove_string (middlehalf), middlehalf);  /* Do the high-numbered word.  */  output_asm_insn (singlemove_string (latehalf), latehalf);  return "";}#define MAX_TMPS 2		/* max temporary registers used *//* Output the appropriate code to move push memory on the stack */char *output_move_pushmem (operands, insn, length, tmp_start, n_operands)     rtx operands[];     rtx insn;     int length;     int tmp_start;     int n_operands;{  struct    {      char *load;      char *push;      rtx   xops[2];    } tmp_info[MAX_TMPS];  rtx src = operands[1];  int max_tmps = 0;  int offset = 0;  int stack_p = reg_overlap_mentioned_p (stack_pointer_rtx, src);  int stack_offset = 0;  int i, num_tmps;  rtx xops[1];  if (! offsettable_memref_p (src))    fatal_insn ("Source is not offsettable", insn);  if ((length & 3) != 0)    fatal_insn ("Pushing non-word aligned size", insn);  /* Figure out which temporary registers we have available */  for (i = tmp_start; i < n_operands; i++)    {      if (GET_CODE (operands[i]) == REG)	{	  if (reg_overlap_mentioned_p (operands[i], src))	    continue;	  tmp_info[ max_tmps++ ].xops[1] = operands[i];	  if (max_tmps == MAX_TMPS)	    break;	}    }  if (max_tmps == 0)    for (offset = length - 4; offset >= 0; offset -= 4)      {	xops[0] = adj_offsettable_operand (src, offset + stack_offset);	output_asm_insn (AS1(push%L0,%0), xops);	if (stack_p)	  stack_offset += 4;      }  else    for (offset = length - 4; offset >= 0; )      {	for (num_tmps = 0; num_tmps < max_tmps && offset >= 0; num_tmps++)	  {	    tmp_info[num_tmps].load    = AS2(mov%L0,%0,%1);	    tmp_info[num_tmps].push    = AS1(push%L0,%1);	    tmp_info[num_tmps].xops[0]	      = adj_offsettable_operand (src, offset + stack_offset);	    offset -= 4;	  }	for (i = 0; i < num_tmps; i++)	  output_asm_insn (tmp_info[i].load, tmp_info[i].xops);	for (i = 0; i < num_tmps; i++)	  output_asm_insn (tmp_info[i].push, tmp_info[i].xops);	if (stack_p)	  stack_offset += 4*num_tmps;      }  return "";}intstandard_80387_constant_p (x)     rtx x;{#if ! defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC)  REAL_VALUE_TYPE d;  jmp_buf handler;  int is0, is1;  if (setjmp (handler))    return 0;  set_float_handler (handler);  REAL_VALUE_FROM_CONST_DOUBLE (d, x);  is0 = REAL_VALUES_EQUAL (d, dconst0) && !REAL_VALUE_MINUS_ZERO (d);  is1 = REAL_VALUES_EQUAL (d, dconst1);  set_float_handler (NULL_PTR);  if (is0)    return 1;  if (is1)    return 2;  /* Note that on the 80387, other constants, such as pi,     are much slower to load as standard constants     than to load from doubles in memory!  */  /* ??? Not true on K6: all constants are equal cost.  */#endif  return 0;}char *output_move_const_single (operands)     rtx *operands;{  if (FP_REG_P (operands[0]))    {      int conval = standard_80387_constant_p (operands[1]);      if (conval == 1)	return "fldz";      if (conval == 2)	return "fld1";    }  if (GET_CODE (operands[1]) == CONST_DOUBLE)    {      REAL_VALUE_TYPE r; long l;      if (GET_MODE (operands[1]) == XFmode)	abort ();      REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]);      REAL_VALUE_TO_TARGET_SINGLE (r, l);      operands[1] = GEN_INT (l);    }  return singlemove_string (operands);}/* Returns 1 if OP is either a symbol reference or a sum of a symbol   reference and a constant.  */intsymbolic_operand (op, mode)     register rtx op;     enum machine_mode mode ATTRIBUTE_UNUSED;{  switch (GET_CODE (op))    {    case SYMBOL_REF:    case LABEL_REF:      return 1;    case CONST:      op = XEXP (op, 0);      return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF	       || GET_CODE (XEXP (op, 0)) == LABEL_REF)	      && GET_CODE (XEXP (op, 1)) == CONST_INT);    default:      return 0;    }}/* Return nonzero if OP is a constant shift count small enough to   encode into an lea instruction.  */intsmall_shift_operand (op, mode)     rtx op;     enum machine_mode mode ATTRIBUTE_UNUSED;{  return (GET_CODE (op) == CONST_INT && INTVAL (op) > 0 && INTVAL (op) < 4);}/* Test for a valid operand for a call instruction.   Don't allow the arg pointer register or virtual regs   since they may change into reg + const, which the patterns   can't handle yet.  */intcall_insn_operand (op, mode)     rtx op;     enum machine_mode mode ATTRIBUTE_UNUSED;{  if (GET_CODE (op) == MEM      && ((CONSTANT_ADDRESS_P (XEXP (op, 0))	   /* This makes a difference for PIC.  */	   && general_operand (XEXP (op, 0), Pmode))	  || (GET_CODE (XEXP (op, 0)) == REG	      && XEXP (op, 0) != arg_pointer_rtx	      && ! (REGNO (XEXP (op, 0)) >= FIRST_PSEUDO_REGISTER		    && REGNO (XEXP (op, 0)) <= LAST_VIRTUAL_REGISTER))))    return 1;  return 0;}/* Like call_insn_operand but allow (mem (symbol_ref ...))   even if pic.  */intexpander_call_insn_operand (op, mode)     rtx op;     enum machine_mode mode ATTRIBUTE_UNUSED;{  if (GET_CODE (op) == MEM      && (CONSTANT_ADDRESS_P (XEXP (op, 0))	  || (GET_CODE (XEXP (op, 0)) == REG	      && XEXP (op, 0) != arg_pointer_rtx	      && ! (REGNO (XEXP (op, 0)) >= FIRST_PSEUDO_REGISTER		    && REGNO (XEXP (op, 0)) <= LAST_VIRTUAL_REGISTER))))    return 1;  return 0;}/* Return 1 if OP is a comparison operator that can use the condition code   generated by an arithmetic operation. */intarithmetic_comparison_operator (op, mode)     register rtx op;     enum machine_mode mode;{  enum rtx_code code;

⌨️ 快捷键说明

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