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

📄 out-i386.c

📁 这是完整的gcc源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
    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)    {      operands[0] = XEXP (XEXP (operands[0], 0), 0);      asm_add (-8, operands[0]);      operands[0] = gen_rtx (MEM, DImode, operands[0]);      optype0 = OFFSOP;    }  if (optype0 == POPOP && optype1 == PUSHOP)    {      operands[1] = XEXP (XEXP (operands[1], 0), 0);      asm_add (-8, operands[1]);      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 (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)    {      if (CONSTANT_P (operands[1]))	latehalf[1] = const0_rtx;      else if (GET_CODE (operands[1]) == CONST_DOUBLE)	{	  latehalf[1] = gen_rtx (CONST_INT, VOIDmode,				 CONST_DOUBLE_HIGH (operands[1]));	  operands[1] = gen_rtx (CONST_INT, VOIDmode,				 CONST_DOUBLE_LOW (operands[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))     for the low 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]))    operands[1] = latehalf[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])))    {      /* 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, 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);  /* 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, addreg0);  if (addreg1)    asm_add (-4, addreg1);  return "";}intstandard_80387_constant_p (x)     rtx x;{  union { double d; int i[2];} u;  register double d;  u.i[0] = XINT (x, 0);  u.i[1] = XINT (x, 1);  d = u.d;  if (d == 0)    return 1;  if (d == 1)    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!  */  return 0;}static char *output_move_const_double (operands)     rtx *operands;{  if (FP_REG_P (operands[0]))    {      int conval = standard_80387_constant_p (operands[1]);      /* fp_pop_level++; */      if (conval == 1)	return "fldz";      if (conval == 2)	return "fld1";      /* fp_pop_level--; */    }  output_move_double (operands);}static char *output_move_const_single (operands)     rtx *operands;{  if (FP_REG_P (operands[0]))    {      int conval = standard_80387_constant_p (operands[1]);      /* fp_pop_level++; */      if (conval == 1)	return "fldz";      if (conval == 2)	return "fld1";      /* fp_pop_level--; */    }  if (GET_CODE (operands[1]) == CONST_DOUBLE)    {      union { int i[2]; double d;} u1;      union { int i; float f;} u2;      u1.i[0] = CONST_DOUBLE_LOW (operands[1]);      u1.i[1] = CONST_DOUBLE_HIGH (operands[1]);      u2.f = u1.d;      operands[1] = gen_rtx (CONST_INT, VOIDmode, u2.i);    }  return singlemove_string (operands);}/* Output an insn to move an SF value from FROM to TO.   The kinds of operands are not restricted   except that they may not both be in memory.  */voidoutput_movsf (to, from)     rtx from, to;{  rtx xops[2];  xops[0] = to;  xops[1] = from;  if (FP_REG_P (from) || FP_REG_P (to))    {      from = xops[1];    }  if (FP_REG_P (from))    {#if 0	{	  if (REGNO (from) != REGNO (to))	    {	      output_asm_insn ("fld%S0 %1 \n\tfstp%S0 %0", xops);	    }	}      else#endif      if (! FP_REG_P (to))	fp_pop_sf (to);    }  else if (FP_REG_P (to))    fp_push_sf (from);  else    output_asm_insn (singlemove_string (xops), xops);}/* Output an insn to move a DF value from FROM to TO.   The kinds of operands are not restricted   except that they may not both be in memory.  */voidoutput_movdf (to, from)     rtx from, to;{  rtx xops[2];  xops[0] = to;  xops[1] = from;  if (FP_REG_P (from) || FP_REG_P (to))    {      from = xops[1];      to = xops[0];    }  if (FP_REG_P (from))    {#if 0	{	  if (REGNO (from) != REGNO (to))	    abort ();/*	    output_asm_insn ("fld%Q0 %1 \n\t fstp%Q0 %0", xops);*/	}      else	{#endif      if (! FP_REG_P (to))	fp_pop_df (to);    }  else if (FP_REG_P (to))    fp_push_df (from);  else    output_asm_insn (output_move_double (xops), xops);}/* does move of FROM to TO where the mode is the minimum of thetwo */static voidoutput_movf (to, from)     rtx to, from;{  if (GET_MODE (from) == SFmode || GET_MODE (to) == SFmode)    output_movsf (to, from);  else    output_movdf (to, from);}/* Return the best assembler insn template   for moving operands[1] into operands[0] as a fullword.  */voidfunction_prologue (file, size)     FILE *file;     int size;{  register int regno;  int nregs, limit;  rtx xops[4];  extern int frame_pointer_needed;  /* fp_pop_level = 0; */  xops[0] = stack_pointer_rtx;  xops[1] = frame_pointer_rtx;  xops[2] = gen_rtx (CONST_INT, VOIDmode, size);  if (frame_pointer_needed)    {      output_asm_insn ("push%L0 %1", xops);      output_asm_insn (AS2 (mov%L0,%0,%1), xops);      if (size)	output_asm_insn (AS2 (sub%L0,%2,%0), xops);    }  /* Note If use enter it is NOT reversed args.     This one is not reversed from intel!!     I think enter is slower.  Also sdb doesn't like it.     But if you want it the code is:     {     xops[3] = const0_rtx;     output_asm_insn ("enter %2,%3", xops);     }     */  nregs = 0;  limit = (frame_pointer_needed ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);  for (regno = limit - 1; regno >= 0; regno--)    if (regs_ever_live[regno] && ! call_used_regs[regno])      {	fprintf (file, "\tpush%s %se%s\n", L_SIZE, RP, hi_reg_name[regno]);      }}voidfunction_epilogue (file, size)     FILE *file;     int size;{  register int regno;  register int nregs, limit;  int assure_sp_pos;  int return_struct_adjust;  extern int frame_pointer_needed;  extern int current_function_pops_args;  extern int current_function_args_size;  extern int flag_pcc_struct_return;  limit = (frame_pointer_needed ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);  nregs = 0;  return_struct_adjust =    (current_function_returns_struct#ifdef STRUCT_RETURN_CALLER_POP     && !flag_pcc_struct_return#endif     ? 4 : 0);  for (regno = (limit -1); regno >= 0; regno--)    if (regs_ever_live[regno] && ! call_used_regs[regno])      nregs++;  /* sp is often  unreliable so we must go off the frame pointer,   */  if (nregs && frame_pointer_needed)    {      rtx xops[2];      xops[0] = adj_offsettable_operand (AT_BP (Pmode),					 -size -(nregs*(UNITS_PER_WORD)));      xops[1] = stack_pointer_rtx;      output_asm_insn (AS2 (lea%L0,%0,%1), xops);    }  for (regno = 0; regno < limit; regno++)    {      if (regs_ever_live[regno] && ! call_used_regs[regno])	{	  fprintf (file, "\tpop%s ", L_SIZE);	  fprintf (file, "%se%s\n", RP, hi_reg_name[regno]);	}    }  if (frame_pointer_needed)    fprintf (file, "\tleave\n");  if (current_function_pops_args && current_function_args_size)    fprintf (file, "\tret %s%d\n", IP,	     (current_function_args_size + return_struct_adjust));  else if (return_struct_adjust)    fprintf (file, "\tret %s%d\n", IP, return_struct_adjust);  else    fprintf (file, "\tret\n");}inthard_regno_mode_ok (regno, mode)     int regno;     enum machine_mode mode;{  return    (regno < 2 ? 1     /* Used to reject floating modes here */     : regno < 4 ? 1     : regno >= 8 ? mode == DFmode || mode == SFmode     : mode != QImode);}/* Print the name of a register based on its machine mode and number.   If CODE is 'w', pretend the mode is HImode.   If CODE is 'b', pretend the mode is QImode.   If CODE is 'k', pretend the mode is SImode.  */#define PRINT_REG(X, CODE, FILE) \  do { fprintf (FILE, "%s", RP);			\       switch ((CODE == 'w' ? 2 			\		: CODE == 'b' ? 1			\		: CODE == 'k' ? 4			\		: GET_MODE_SIZE (GET_MODE (X))))	\	 {						\	 case 4:					\	 case 8:					\	   if (!FP_REG_P (X)) fputs ("e", FILE);	\	 case 2:					\	   fputs (hi_reg_name[REGNO (X)], FILE);	\	   break;					\	 case 1:					\	   fputs (qi_reg_name[REGNO (X)], FILE);	\	   break;					\	 }						\     } while (0)/* Meaning of CODE:   f -- float insn (print a CONST_DOUBLE as a float rather than in hex).   L,W,B,Q,S -- print the opcode suffix for specified size of operand.   R -- print the prefix for register names.   z -- print the opcode suffix for the size of the current operand.   * -- print a star (in certain assembler syntax)   w -- print the operand as if it's a "word" (HImode) even if it isn't.   c -- don't print special prefixes before constant operands.*/voidprint_operand (file, x, code)     FILE *file;     rtx x;     int code;{  if (code)    {      switch (code)	{	case '*':	  if (USE_STAR)	    putc ('*', file);	  return;	case 'L':	  PUT_OP_SIZE (code, 'l', file);	  return;	case 'W':	  PUT_OP_SIZE (code, 'w', file);	  return;	case 'B':	  PUT_OP_SIZE (code, 'b', file);	  return;	case 'Q':	  PUT_OP_SIZE (code, 'l', file);	  return;	case 'S':	  PUT_OP_SIZE (code, 's', file);	  return;

⌨️ 快捷键说明

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