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

📄 i386.c

📁 gcc编译工具没有什么特别
💻 C
📖 第 1 页 / 共 5 页
字号:
 		  cfa_offset = cfa_store_offset; 		  dwarf2out_def_cfa ("", STACK_POINTER_REGNUM, cfa_offset); 		} 	    }#endif	}    }  else    {      xops[3] = gen_rtx_REG (SImode, 0);      if (do_rtl)      emit_move_insn (xops[3], xops[2]);      else	output_asm_insn (AS2 (mov%L0,%2,%3), xops);      xops[3] = gen_rtx_MEM (FUNCTION_MODE,			 gen_rtx (SYMBOL_REF, Pmode, "_alloca"));      if (do_rtl)	emit_call_insn (gen_rtx (CALL, VOIDmode, xops[3], const0_rtx));      else	output_asm_insn (AS1 (call,%P3), 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);     }     */  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])	|| (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))      {	xops[0] = gen_rtx_REG (SImode, regno);	if (do_rtl)	  {	    insn = emit_insn (gen_rtx (SET, VOIDmode,				       gen_rtx_MEM (SImode,						gen_rtx (PRE_DEC, SImode,							 stack_pointer_rtx)),				       xops[0]));	    RTX_FRAME_RELATED_P (insn) = 1;	  }	else	  {	    output_asm_insn ("push%L0 %0", xops);#ifdef INCOMING_RETURN_ADDR_RTX 	    if (dwarf2out_do_frame ()) 	      { 		char *l = dwarf2out_cfi_label (); 		cfa_store_offset += 4; 		if (! frame_pointer_needed) 		  { 		    cfa_offset = cfa_store_offset; 		    dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, cfa_offset); 		  } 		dwarf2out_reg_save (l, regno, - cfa_store_offset); 	      }#endif 	  }      }#ifdef SUBTARGET_PROLOGUE  SUBTARGET_PROLOGUE;#endif    if (pic_reg_used)    load_pic_register (do_rtl);  /* If we are profiling, make sure no instructions are scheduled before     the call to mcount.  However, if -fpic, the above call will have     done that.  */  if ((profile_flag || profile_block_flag)      && ! pic_reg_used && do_rtl)    emit_insn (gen_blockage ());}/* Return 1 if it is appropriate to emit `ret' instructions in the   body of a function.  Do this only if the epilogue is simple, needing a   couple of insns.  Prior to reloading, we can't tell how many registers   must be saved, so return 0 then.  Return 0 if there is no frame   marker to de-allocate.   If NON_SAVING_SETJMP is defined and true, then it is not possible   for the epilogue to be simple, so return 0.  This is a special case   since NON_SAVING_SETJMP will not cause regs_ever_live to change   until final, but jump_optimize may need to know sooner if a   `return' is OK.  */intix86_can_use_return_insn_p (){  int regno;  int nregs = 0;  int reglimit = (frame_pointer_needed		  ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);  int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table				  || current_function_uses_const_pool);#ifdef NON_SAVING_SETJMP  if (NON_SAVING_SETJMP && current_function_calls_setjmp)    return 0;#endif  if (! reload_completed)    return 0;  for (regno = reglimit - 1; regno >= 0; regno--)    if ((regs_ever_live[regno] && ! call_used_regs[regno])	|| (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))      nregs++;  return nregs == 0 || ! frame_pointer_needed;}/* This function generates the assembly code for function exit.   FILE is an stdio stream to output the code to.   SIZE is an int: how many units of temporary storage to deallocate. */voidfunction_epilogue (file, size)     FILE *file ATTRIBUTE_UNUSED;     int size ATTRIBUTE_UNUSED;{    return;}/* Restore function stack, frame, and registers. */voidix86_expand_epilogue (){  ix86_epilogue (1);}static voidix86_epilogue (do_rtl)     int do_rtl;{  register int regno;  register int limit;  int nregs;  rtx xops[3];  int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table				  || current_function_uses_const_pool);  int sp_valid = !frame_pointer_needed || current_function_sp_is_unchanging;  HOST_WIDE_INT offset;  HOST_WIDE_INT tsize = ix86_compute_frame_size (get_frame_size (), &nregs);  /* sp is often unreliable so we may have to go off the frame pointer. */  offset = -(tsize + nregs * UNITS_PER_WORD);  xops[2] = stack_pointer_rtx;  /* When -fpic, we must emit a scheduling barrier, so that the instruction     that restores %ebx (which is PIC_OFFSET_TABLE_REGNUM), does not get     moved before any instruction which implicitly uses the got.  This     includes any instruction which uses a SYMBOL_REF or a LABEL_REF.     Alternatively, this could be fixed by making the dependence on the     PIC_OFFSET_TABLE_REGNUM explicit in the RTL.  */  if (flag_pic || profile_flag || profile_block_flag)    emit_insn (gen_blockage ());  /* If we're only restoring one register and sp is not valid then     using a move instruction to restore the register since it's     less work than reloading sp and popping the register.  Otherwise,     restore sp (if necessary) and pop the registers. */  limit = frame_pointer_needed	  ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM;  if (nregs > 1 || sp_valid)    {      if ( !sp_valid )	{	  xops[0] = adj_offsettable_operand (AT_BP (QImode), offset);	  if (do_rtl)	    emit_insn (gen_movsi_lea (xops[2], XEXP (xops[0], 0)));	  else	    output_asm_insn (AS2 (lea%L2,%0,%2), xops);	}      for (regno = 0; regno < limit; regno++)	if ((regs_ever_live[regno] && ! call_used_regs[regno])	    || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))	  {	    xops[0] = gen_rtx_REG (SImode, regno);	    if (do_rtl)	      emit_insn (gen_pop (xops[0]));	    else	      output_asm_insn ("pop%L0 %0", xops);	  }    }  else    for (regno = 0; regno < limit; regno++)      if ((regs_ever_live[regno] && ! call_used_regs[regno])	  || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))	{	  xops[0] = gen_rtx_REG (SImode, regno);	  xops[1] = adj_offsettable_operand (AT_BP (Pmode), offset);	  if (do_rtl)	    emit_move_insn (xops[0], xops[1]);	  else	    output_asm_insn (AS2 (mov%L0,%1,%0), xops);	  offset += 4;	}  if (frame_pointer_needed)    {      /* If not an i386, mov & pop is faster than "leave". */      if (TARGET_USE_LEAVE)	{	  if (do_rtl)	    emit_insn (gen_leave());	  else	    output_asm_insn ("leave", xops);	}      else	{	  xops[0] = frame_pointer_rtx;	  xops[1] = stack_pointer_rtx;	  if (do_rtl)	    {	      emit_insn (gen_epilogue_set_stack_ptr());	      emit_insn (gen_pop (xops[0]));	    }	  else	    {	      output_asm_insn (AS2 (mov%L2,%0,%2), xops);	      output_asm_insn ("pop%L0 %0", xops);	    }	}    }  else if (tsize)    {      /* Intel's docs say that for 4 or 8 bytes of stack frame one should	 use `pop' and not `add'.  */      int use_pop = tsize == 4;      /* Use two pops only for the Pentium processors.  */      if (tsize == 8 && !TARGET_386 && !TARGET_486)	{	  rtx retval = current_function_return_rtx;	  xops[1] = gen_rtx_REG (SImode, 1);	/* %edx */	  /* This case is a bit more complex.  Since we cannot pop into	     %ecx twice we need a second register.  But this is only	     available if the return value is not of DImode in which	     case the %edx register is not available.  */	  use_pop = (retval == NULL		     || ! reg_overlap_mentioned_p (xops[1], retval));	}      if (use_pop)	{	  xops[0] = gen_rtx_REG (SImode, 2);	/* %ecx */	  if (do_rtl)	    {	      /* We have to prevent the two pops here from being scheduled.		 GCC otherwise would try in some situation to put other		 instructions in between them which has a bad effect.  */	      emit_insn (gen_blockage ());	      emit_insn (gen_pop (xops[0]));	      if (tsize == 8)		emit_insn (gen_pop (xops[1]));	    }	  else	    {	      output_asm_insn ("pop%L0 %0", xops);	      if (tsize == 8)		output_asm_insn ("pop%L1 %1", xops);	    }	}      else	{	  /* If there is no frame pointer, we must still release the frame. */	  xops[0] = GEN_INT (tsize);	  if (do_rtl)	    emit_insn (gen_rtx (SET, VOIDmode, xops[2],				gen_rtx (PLUS, SImode, xops[2], xops[0])));	  else	    output_asm_insn (AS2 (add%L2,%0,%2), xops);	}    }#ifdef FUNCTION_BLOCK_PROFILER_EXIT  if (profile_block_flag == 2)    {      FUNCTION_BLOCK_PROFILER_EXIT(file);    }#endif  if (current_function_pops_args && current_function_args_size)    {      xops[1] = GEN_INT (current_function_pops_args);      /* i386 can only pop 32K bytes (maybe 64K?  Is it signed?).  If	 asked to pop more, pop return address, do explicit add, and jump	 indirectly to the caller. */      if (current_function_pops_args >= 32768)	{	  /* ??? Which register to use here? */	  xops[0] = gen_rtx_REG (SImode, 2);	  if (do_rtl)	    {	      emit_insn (gen_pop (xops[0]));	      emit_insn (gen_rtx (SET, VOIDmode, xops[2],				  gen_rtx (PLUS, SImode, xops[1], xops[2])));	      emit_jump_insn (xops[0]);	    }	  else	    {	      output_asm_insn ("pop%L0 %0", xops);	      output_asm_insn (AS2 (add%L2,%1,%2), xops);	      output_asm_insn ("jmp %*%0", xops);	    }	}      else	{	  if (do_rtl)	    emit_jump_insn (gen_return_pop_internal (xops[1]));	  else	    output_asm_insn ("ret %1", xops);	}    }  else    {      if (do_rtl)	emit_jump_insn (gen_return_internal ());      else	output_asm_insn ("ret", xops);    }}/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression   that is a valid memory address for an instruction.   The MODE argument is the machine mode for the MEM expression   that wants to use this address.   On x86, legitimate addresses are:	base				movl (base),reg	displacement			movl disp,reg	base + displacement		movl disp(base),reg	index + base			movl (base,index),reg	(index + base) + displacement	movl disp(base,index),reg	index*scale			movl (,index,scale),reg	index*scale + disp		movl disp(,index,scale),reg	index*scale + base 		movl (base,index,scale),reg	(index*scale + base) + disp	movl disp(base,index,scale),reg	In each case, scale can be 1, 2, 4, 8.  *//* This is exactly the same as print_operand_addr, except that   it recognizes addresses instead of printing them.   It only recognizes address in canonical form.  LEGITIMIZE_ADDRESS should   convert common non-canonical forms to canonical form so that they will   be recognized.  */#define ADDR_INVALID(msg,insn)						\do {									\  if (TARGET_DEBUG_ADDR)						\    {									\      fprintf (stderr, msg);						\      debug_rtx (insn);							\    }									\} while (0)intlegitimate_pic_address_disp_p (disp)     register rtx disp;{  if (GET_CODE (disp) != CONST)    return 0;  disp = XEXP (disp, 0);  if (GET_CODE (disp) == PLUS)    {      if (GET_CODE (XEXP (disp, 1)) != CONST_INT)	return 0;      disp = XEXP (disp, 0);    }  if (GET_CODE (disp) != UNSPEC      || XVECLEN (disp, 0) != 1)    return 0;  /* Must be @GOT or @GOTOFF.  */  if (XINT (disp, 1) != 6      && XINT (disp, 1) != 7)    return 0;  if (GET_CODE (XVECEXP (disp, 0, 0)) != SYMBOL_REF      && GET_CODE (XVECEXP (disp, 0, 0)) != LABEL_REF)    return 0;  return 1;}intlegitimate_address_p (mode, addr, strict)     enum machine_mode mode;     register rtx addr;     int strict;{  rtx base  = NULL_RTX;  rtx indx  = NULL_RTX;  rtx scale = NULL_RTX;  rtx disp  = NULL_RTX;  if (TARGET_DEBUG_ADDR)    {      fprintf (stderr,	       "\n======\nGO_IF_LEGITIMATE_ADDRESS, mode = %s, strict = %d\n",	       GET_MODE_NAME (mode), strict);      debug_rtx (addr);    }  if (GET_CODE (addr) == REG || GET_CODE (addr) == SUBREG)    base = addr;  else if (GET_CODE (addr) == PLUS)    {      rtx op0 = XEXP (addr, 0);      rtx op1 = XEXP (addr, 1);      enum rtx_code code0 = GET_CODE (op0);      enum rtx_code code1 = GET_CODE (op1);      if (code0 == REG || code0 == SUBREG)	{	  if (code1 == REG || code1 == SUBREG)	    {	      indx = op0;	/* index + base */	      base = op1;	    }	  else	    {	      base = op0;	/* base + displacement */	      disp = op1;	    }	}      else if (code0 == MULT)	{	  indx  = XEXP (op0, 0);	  scale = XEXP (op0, 1);	  i

⌨️ 快捷键说明

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