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

📄 i386.c

📁 gcc库的原代码,对编程有很大帮助.
💻 C
📖 第 1 页 / 共 5 页
字号:
     int named;			/* whether or not the argument was named */{  int bytes = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);  int words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;  if (TARGET_DEBUG_ARG)    fprintf (stderr,	     "function_adv( size=%d, words=%2d, nregs=%d, mode=%4s, named=%d )\n\n",	     words, cum->words, cum->nregs, GET_MODE_NAME (mode), named);  cum->words += words;  cum->nregs -= words;  cum->regno += words;  if (cum->nregs <= 0)    {      cum->nregs = 0;      cum->regno = 0;    }  return;}/* Define where to put the arguments to a function.   Value is zero to push the argument on the stack,   or a hard register in which to store the argument.   MODE is the argument's machine mode.   TYPE is the data type of the argument (as a tree).    This is null for libcalls where that information may    not be available.   CUM is a variable of type CUMULATIVE_ARGS which gives info about    the preceding args and about the function being called.   NAMED is nonzero if this argument is a named parameter    (otherwise it is an extra parameter matching an ellipsis).  */struct rtx_def *function_arg (cum, mode, type, named)     CUMULATIVE_ARGS *cum;	/* current arg information */     enum machine_mode mode;	/* current arg mode */     tree type;			/* type of the argument or 0 if lib support */     int named;			/* != 0 for normal args, == 0 for ... args */{  rtx ret   = NULL_RTX;  int bytes = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);  int words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;  switch (mode)    {    default:			/* for now, pass fp/complex values on the stack */      break;    case BLKmode:    case DImode:    case SImode:    case HImode:    case QImode:      if (words <= cum->nregs)	ret = gen_rtx (REG, mode, cum->regno);      break;    }  if (TARGET_DEBUG_ARG)    {      fprintf (stderr,	       "function_arg( size=%d, words=%2d, nregs=%d, mode=%4s, named=%d",	       words, cum->words, cum->nregs, GET_MODE_NAME (mode), named);      if (ret)	fprintf (stderr, ", reg=%%e%s", reg_names[ REGNO(ret) ]);      else	fprintf (stderr, ", stack");      fprintf (stderr, " )\n");    }  return ret;}/* For an arg passed partly in registers and partly in memory,   this is the number of registers used.   For args passed entirely in registers or entirely in memory, zero.  */intfunction_arg_partial_nregs (cum, mode, type, named)     CUMULATIVE_ARGS *cum;	/* current arg information */     enum machine_mode mode;	/* current arg mode */     tree type;			/* type of the argument or 0 if lib support */     int named;			/* != 0 for normal args, == 0 for ... args */{  return 0;}/* Output an insn whose source is a 386 integer register.  SRC is the   rtx for the register, and TEMPLATE is the op-code template.  SRC may   be either SImode or DImode.   The template will be output with operands[0] as SRC, and operands[1]   as a pointer to the top of the 386 stack.  So a call from floatsidf2   would look like this:      output_op_from_reg (operands[1], AS1 (fild%z0,%1));   where %z0 corresponds to the caller's operands[1], and is used to   emit the proper size suffix.   ??? Extend this to handle HImode - a 387 can load and store HImode   values directly. */voidoutput_op_from_reg (src, template)     rtx src;     char *template;{  rtx xops[4];  int size = GET_MODE_SIZE (GET_MODE (src));  xops[0] = src;  xops[1] = AT_SP (Pmode);  xops[2] = GEN_INT (size);  xops[3] = stack_pointer_rtx;  if (size > UNITS_PER_WORD)    {      rtx high;      if (size > 2 * UNITS_PER_WORD)	{	  high = gen_rtx (REG, SImode, REGNO (src) + 2);	  output_asm_insn (AS1 (push%L0,%0), &high);	}      high = gen_rtx (REG, SImode, REGNO (src) + 1);      output_asm_insn (AS1 (push%L0,%0), &high);    }  output_asm_insn (AS1 (push%L0,%0), &src);  output_asm_insn (template, xops);  output_asm_insn (AS2 (add%L3,%2,%3), xops);}/* Output an insn to pop an value from the 387 top-of-stack to 386   register DEST. The 387 register stack is popped if DIES is true.  If   the mode of DEST is an integer mode, a `fist' integer store is done,   otherwise a `fst' float store is done. */voidoutput_to_reg (dest, dies)     rtx dest;     int dies;{  rtx xops[4];  int size = GET_MODE_SIZE (GET_MODE (dest));  xops[0] = AT_SP (Pmode);  xops[1] = stack_pointer_rtx;  xops[2] = GEN_INT (size);  xops[3] = dest;  output_asm_insn (AS2 (sub%L1,%2,%1), xops);  if (GET_MODE_CLASS (GET_MODE (dest)) == MODE_INT)    {      if (dies)	output_asm_insn (AS1 (fistp%z3,%y0), xops);      else	output_asm_insn (AS1 (fist%z3,%y0), xops);    }  else if (GET_MODE_CLASS (GET_MODE (dest)) == MODE_FLOAT)    {      if (dies)	output_asm_insn (AS1 (fstp%z3,%y0), xops);      else	{	  if (GET_MODE (dest) == XFmode)	    {	      output_asm_insn (AS1 (fstp%z3,%y0), xops);	      output_asm_insn (AS1 (fld%z3,%y0), xops);	    }	  else	    output_asm_insn (AS1 (fst%z3,%y0), xops);	}    }  else    abort ();  output_asm_insn (AS1 (pop%L0,%0), &dest);  if (size > UNITS_PER_WORD)    {      dest = gen_rtx (REG, SImode, REGNO (dest) + 1);      output_asm_insn (AS1 (pop%L0,%0), &dest);      if (size > 2 * UNITS_PER_WORD)	{	  dest = gen_rtx (REG, SImode, REGNO (dest) + 1);	  output_asm_insn (AS1 (pop%L0,%0), &dest);	}    }}char *singlemove_string (operands)     rtx *operands;{  rtx x;  if (GET_CODE (operands[0]) == MEM      && GET_CODE (x = XEXP (operands[0], 0)) == PRE_DEC)    {      if (XEXP (x, 0) != stack_pointer_rtx)	abort ();      return "push%L1 %1";    }  else if (GET_CODE (operands[1]) == CONST_DOUBLE)    {      return output_move_const_single (operands);    }  else if (GET_CODE (operands[0]) == REG || GET_CODE (operands[1]) == REG)    return AS2 (mov%L0,%1,%0);  else if (CONSTANT_P (operands[1]))    return AS2 (mov%L0,%1,%0);  else    {      output_asm_insn ("push%L1 %1", operands);      return "pop%L0 %0";    }}/* Return a REG that occurs in ADDR with coefficient 1.   ADDR can be effectively incremented by incrementing REG.  */static rtxfind_addr_reg (addr)     rtx addr;{  while (GET_CODE (addr) == PLUS)    {      if (GET_CODE (XEXP (addr, 0)) == REG)	addr = XEXP (addr, 0);      else if (GET_CODE (XEXP (addr, 1)) == REG)	addr = XEXP (addr, 1);      else if (CONSTANT_P (XEXP (addr, 0)))	addr = XEXP (addr, 1);      else if (CONSTANT_P (XEXP (addr, 1)))	addr = XEXP (addr, 0);      else	abort ();    }  if (GET_CODE (addr) == REG)    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)    {      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 )	    {/*	    abort (); */	      operands[1] = gen_rtx (MEM, XFmode, latehalf[0]);

⌨️ 快捷键说明

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