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

📄 i386.c

📁 gcc库的原代码,对编程有很大帮助.
💻 C
📖 第 1 页 / 共 5 页
字号:
	      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 (optype0 == PUSHOP || optype1 == PUSHOP      || (optype0 == REGOP && optype1 == REGOP	  && REGNO (operands[0]) == REGNO (latehalf[1]))      || dest_overlapped_low)*/  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 && 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;	}    }  if (max_tmps == 0)    fatal_insn ("No scratch registers were found to do memory->memory moves", insn);  if ((length & 1) != 0)    {      if (!qi_tmp)	fatal_insn ("No byte register found when moving odd # of bytes.", insn);    }  while (length > 1)    {      for (num_tmps = 0; num_tmps < max_tmps; num_tmps++)	{	  if (length >= 4)	    {	      tmp_info[num_tmps].load    = AS2(mov%L0,%1,%2);	      tmp_info[num_tmps].store   = AS2(mov%L0,%2,%0);	      tmp_info[num_tmps].xops[0] = adj_offsettable_operand (dest, offset);	      tmp_info[num_tmps].xops[1] = adj_offsettable_operand (src, offset);	      offset += 4;	      length -= 4;	    }	  else if (length >= 2)	    {	      tmp_info[num_tmps].load    = AS2(mov%W0,%1,%2);	      tmp_info[num_tmps].store   = AS2(mov%W0,%2,%0);	      tmp_info[num_tmps].xops[0] = adj_offsettable_operand (dest, offset);	      tmp_info[num_tmps].xops[1] = adj_offsettable_operand (src, offset);	      offset += 2;	      length -= 2;	    }	  else	    break;	}      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].store, tmp_info[i].xops);    }  if (length == 1)    {      xops[0] = adj_offsettable_operand (dest, offset);      xops[1] = adj_offsettable_operand (src, offset);      xops[2] = qi_tmp;      output_asm_insn (AS2(mov%B0,%1,%2), xops);      output_asm_insn (AS2(mov%B0,%2,%0), xops);    }  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);  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!  */#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;{  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;    }}/* 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;{  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;{  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;  if (mode != VOIDmode && mode != GET_MODE (op))    return 0;  code = GET_CODE (op);  if (GET_RTX_CLASS (code) != '<')    return 0;  return (code != GT && code != LE);}/* Returns 1 if OP contains a symbol reference */intsymbolic_reference_mentioned_p (op)     rtx op;{  register char *fmt;  register int i;  if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF)    return 1;  fmt = GET_RTX_FORMAT (GET_CODE (op));  for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)    {      if (fmt[i] == 'E')	{	  register int j;	  for (j = XVECLEN (op, i) - 1; j >= 0; j--)	    if (symbolic_reference_mentioned_p (XVECEXP (op, i, j)))	      return 1;	}      else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i)))	return 1;    }  return 0;}/* This function generates the assembly code for function entry.   FILE is an stdio stream to output the code to.   SIZE is an int: how many units of temporary storage to allocate. */voidfunction_prologue (file, size)

⌨️ 快捷键说明

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