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

📄 i386.c

📁 GCC编译器源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
    return addr;  abort ();}/* Output an insn to add the constant N to the register X.  */static voidasm_add (n, x)     int n;     rtx x;{  rtx xops[2];  xops[0] = x;  if (n == -1)    output_asm_insn (AS1 (dec%L0,%0), xops);  else if (n == 1)    output_asm_insn (AS1 (inc%L0,%0), xops);  else if (n < 0 || n == 128)    {      xops[1] = GEN_INT (-n);      output_asm_insn (AS2 (sub%L0,%1,%0), xops);    }  else if (n > 0)    {      xops[1] = GEN_INT (n);      output_asm_insn (AS2 (add%L0,%1,%0), xops);    }}/* Output assembler code to perform a doubleword move insn   with operands OPERANDS.  */char *output_move_double (operands)     rtx *operands;{  enum {REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;  rtx latehalf[2];  rtx middlehalf[2];  rtx xops[2];  rtx addreg0 = 0, addreg1 = 0;  int dest_overlapped_low = 0;  int size = GET_MODE_SIZE (GET_MODE (operands[0]));  middlehalf[0] = 0;  middlehalf[1] = 0;  /* First classify both operands.  */  if (REG_P (operands[0]))    optype0 = REGOP;  else if (offsettable_memref_p (operands[0]))    optype0 = OFFSOP;  else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)    optype0 = POPOP;  else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)    optype0 = PUSHOP;  else if (GET_CODE (operands[0]) == MEM)    optype0 = MEMOP;  else    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 the operand constraints are not     supposed to allow to happen.  Abort if we get one,     because generating code for these cases is painful.  */  if (optype0 == RNDOP || optype1 == RNDOP)    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;    }  /* If an operand is an unoffsettable memory ref, find a register     we can increment temporarily to make it refer to the second word.  */  if (optype0 == MEMOP)    addreg0 = find_addr_reg (XEXP (operands[0], 0));  if (optype1 == MEMOP)    addreg1 = find_addr_reg (XEXP (operands[1], 0));  /* 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 || optype1 == MEMOP))    {      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;	  /* JRV says this can't happen: */	  if (addreg0 || addreg1)	      abort ();	  /* 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)    {      /* Make any unoffsettable addresses point at high-numbered word.  */      if (addreg0)	asm_add (size-4, addreg0);      if (addreg1)	asm_add (size-4, addreg1);      /* Do that word.  */      output_asm_insn (singlemove_string (latehalf), latehalf);      /* Undo the adds we just did.  */      if (addreg0)	asm_add (-4, addreg0);      if (addreg1)	asm_add (-4, addreg1);      if (size == 12)        {	  output_asm_insn (singlemove_string (middlehalf), middlehalf);	  if (addreg0)	    asm_add (-4, addreg0);	  if (addreg1)	    asm_add (-4, addreg1);	}      /* 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)    {      if (addreg0)        asm_add (4, addreg0);      if (addreg1)        asm_add (4, addreg1);      output_asm_insn (singlemove_string (middlehalf), middlehalf);    }  /* Make any unoffsettable addresses point at high-numbered word.  */  if (addreg0)    asm_add (4, addreg0);  if (addreg1)    asm_add (4, addreg1);  /* Do that word.  */  output_asm_insn (singlemove_string (latehalf), latehalf);  /* Undo the adds we just did.  */  if (addreg0)    asm_add (4-size, addreg0);  if (addreg1)    asm_add (4-size, addreg1);  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 "";}/* Output the appropriate code to move data between two memory locations */char *output_move_memory (operands, insn, length, tmp_start, n_operands)     rtx operands[];     rtx insn;     int length;     int tmp_start;     int n_operands;{  struct    {      char *load;      char *store;      rtx   xops[3];    } tmp_info[MAX_TMPS];  rtx dest = operands[0];  rtx src  = operands[1];  rtx qi_tmp = NULL_RTX;  int max_tmps = 0;  int offset = 0;  int i, num_tmps;  rtx xops[3];  if (GET_CODE (dest) == MEM      && GET_CODE (XEXP (dest, 0)) == PRE_INC      && XEXP (XEXP (dest, 0), 0) == stack_pointer_rtx)    return output_move_pushmem (operands, insn, length, tmp_start, n_operands);  if (! offsettable_memref_p (src))    fatal_insn ("Source is not offsettable", insn);  if (! offsettable_memref_p (dest))    fatal_insn ("Destination is not offsettable", insn);  /* Figure out which temporary registers we have available */  for (i = tmp_start; i < n_operands; i++)    {      if (GET_CODE (operands[i]) == REG)	{	  if ((length & 1) != 0 && qi_tmp == 0 && QI_REG_P (operands[i]))	    qi_tmp = operands[i];	  if (reg_overlap_mentioned_p (operands[i], dest))	    fatal_insn ("Temporary register overlaps the destination", insn);	  if (reg_overlap_mentioned_p (operands[i], src))	    fatal_insn ("Temporary register overlaps the source", insn);	  tmp_info[max_tmps++].xops[2] = operands[i];	  if (max_tmps == MAX_TMPS)	    break;	}

⌨️ 快捷键说明

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