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

📄 i386.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 4 页
字号:
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)    {      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_INT (u2.i);    }  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;    }}/* 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;}/* Return a legitimate reference for ORIG (an address) using the   register REG.  If REG is 0, a new pseudo is generated.   There are three types of references that must be handled:   1. Global data references must load the address from the GOT, via      the PIC reg.  An insn is emitted to do this load, and the reg is      returned.   2. Static data references must compute the address as an offset      from the GOT, whose base is in the PIC reg.  An insn is emitted to      compute the address into a reg, and the reg is returned.  Static      data objects have SYMBOL_REF_FLAG set to differentiate them from      global data objects.   3. Constant pool addresses must be handled special.  They are      considered legitimate addresses, but only if not used with regs.      When printed, the output routines know to print the reference with the      PIC reg, even though the PIC reg doesn't appear in the RTL.   GO_IF_LEGITIMATE_ADDRESS rejects symbolic references unless the PIC   reg also appears in the address (except for constant pool references,   noted above).   "switch" statements also require special handling when generating   PIC code.  See comments by the `casesi' insn in i386.md for details.  */rtxlegitimize_pic_address (orig, reg)     rtx orig;     rtx reg;{  rtx addr = orig;  rtx new = orig;  if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == LABEL_REF)    {      if (GET_CODE (addr) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (addr))	reg = new = orig;      else	{	  if (reg == 0)	    reg = gen_reg_rtx (Pmode);	  if (GET_CODE (addr) == SYMBOL_REF && SYMBOL_REF_FLAG (addr))	    new = gen_rtx (PLUS, Pmode, pic_offset_table_rtx, orig);	  else	    new = gen_rtx (MEM, Pmode,			   gen_rtx (PLUS, Pmode,				    pic_offset_table_rtx, orig));	  emit_move_insn (reg, new);	}      current_function_uses_pic_offset_table = 1;      return reg;    }  else if (GET_CODE (addr) == CONST || GET_CODE (addr) == PLUS)    {      rtx base;      if (GET_CODE (addr) == CONST)	{	  addr = XEXP (addr, 0);	  if (GET_CODE (addr) != PLUS)	    abort ();	}      if (XEXP (addr, 0) == pic_offset_table_rtx)	return orig;      if (reg == 0)	reg = gen_reg_rtx (Pmode);      base = legitimize_pic_address (XEXP (addr, 0), reg);      addr = legitimize_pic_address (XEXP (addr, 1),				     base == reg ? NULL_RTX : reg);      if (GET_CODE (addr) == CONST_INT)	return plus_constant (base, INTVAL (addr));      if (GET_CODE (addr) == PLUS && CONSTANT_P (XEXP (addr, 1)))	{	  base = gen_rtx (PLUS, Pmode, base, XEXP (addr, 0));	  addr = XEXP (addr, 1);	}	return gen_rtx (PLUS, Pmode, base, addr);    }  return new;}/* Emit insns to move operands[1] into operands[0].  */voidemit_pic_move (operands, mode)     rtx *operands;     enum machine_mode mode;{  rtx temp = reload_in_progress ? operands[0] : gen_reg_rtx (Pmode);  if (GET_CODE (operands[0]) == MEM && SYMBOLIC_CONST (operands[1]))    operands[1] = (rtx) force_reg (SImode, operands[1]);  else    operands[1] = legitimize_pic_address (operands[1], temp);}/* 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)     FILE *file;     int size;{  register int regno;  int limit;  rtx xops[4];  int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table				  || current_function_uses_const_pool);  xops[0] = stack_pointer_rtx;  xops[1] = frame_pointer_rtx;  xops[2] = GEN_INT (size);  if (frame_pointer_needed)    {      output_asm_insn ("push%L1 %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);     }     */  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);	output_asm_insn ("push%L0 %0", xops);      }  if (pic_reg_used)    {      xops[0] = pic_offset_table_rtx;      xops[1] = (rtx) gen_label_rtx ();      output_asm_insn (AS1 (call,%P1), xops);      ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (xops[1]));      output_asm_insn (AS1 (pop%L0,%0), xops);      output_asm_insn ("addl $_GLOBAL_OFFSET_TABLE_+[.-%P1],%0", xops);    }}/* 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.   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.  */intsimple_386_epilogue (){  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;     int size;{  register int regno;  register int nregs, limit;  int offset;  rtx xops[3];  int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table				  || current_function_uses_const_pool);  /* Compute the number of registers to pop */  limit = (frame_pointer_needed	   ? FRAME_POINTER_REGNUM	   : STACK_POINTER_REGNUM);  nregs = 0;  for (regno = limit - 1; regno >= 0; regno--)    if ((regs_ever_live[regno] && ! call_used_regs[regno])	|| (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))      nregs++;  /* sp is often  unreliable so we must go off the frame pointer,   */  /* In reality, we may not care if sp is unreliable, because we can     restore the register relative to the frame pointer.  In theory,     since each move is the same speed as a pop, and we don't need the     leal, this is faster.  For now restore multiple registers the old     way. */  offset = -size - (nregs * UNITS_PER_WORD);  xops[2] = stack_pointer_rtx;  if (nregs > 1 || ! frame_pointer_needed)    {      if (frame_pointer_needed)	{	  xops[0] = adj_offsettable_operand (AT_BP (Pmode), offset);	  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);	    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);	  output_asm_insn (AS2 (mov%L0,%1,%0), xops);	  offset += 4;	}  if (frame_pointer_needed)    {      /* On i486, mov & pop is faster than "leave". */      if (TARGET_486)	{	  xops[0] = frame_pointer_rtx;	  output_asm_insn (AS2 (mov%L2,%0,%2), xops);	  output_asm_insn ("pop%L0 %0", xops);	}      else	output_asm_insn ("leave", xops);    }  else if (size)    {      /* If there is no frame pointer, we must still release the frame. */      xops[0] = GEN_INT (size);      output_asm_insn (AS2 (add%L2,%0,%2), xops);    }  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);	  output_asm_insn ("pop%L0 %0", xops);	  output_asm_insn (AS2 (add%L2,%1,%2), xops);	  output_asm_insn ("jmp %*%0", xops);	}      else	  output_asm_insn ("ret %1", xops);    }  else    output_asm_insn ("ret", xops);}/* Print an integer constant expression in assembler syntax.  Addition   and subtraction are the only arithmetic that may appear in these   expressions.  FILE is the stdio stream to write to, X is the rtx, and   CODE is the operand print code from the output string.  */static voidoutput_pic_addr_const (file, x, code)     FILE *file;     rtx x;     int code;{  char buf[256];  switch (GET_CODE (x))    {    case PC:      if (flag_pic)	putc ('.', file);      else	abort ();      break;    case SYMBOL_REF:    case LABEL_REF:      if (GET_CODE (x) == SYMBOL_REF)	assemble_name (file, XSTR (x, 0));      else	{	  ASM_GENERATE_INTERNAL_LABEL (buf, "L",				       CODE_LABEL_NUMBER (XEXP (x, 0)));	  assemble_name (asm_out_file, buf);	}      if (GET_CODE (x) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (x))	fprintf (file, "@GOTOFF(%%ebx)");      else if (code == 'P')	fprintf (file, "@PLT");      else if (GET_CODE (x) == LABEL_REF || ! SYMBOL_REF_FLAG (x))	fprintf (file, "@GOT");      else	fprintf (file, "@GOTOFF");      break;    case CODE_LABEL:      ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));      assemble_name (asm_out_file, buf);      break;    case CONST_INT:      fprintf (file, "%d", INTVAL (x));      break;    case CONST:      /* This used to output parentheses around the expression,	 but that does not work on the 386 (either ATT or BSD assembler).  */      output_pic_addr_const (file, XEXP (x, 0), code);      break;    case CONST_DOUBLE:      if (GET_MODE (x) == VOIDmode)	{	  /* We can use %d if the number is <32 bits and positive.  */	  if (CONST_DOUBLE_HIGH (x) || CONST_DOUBLE_LOW (x) < 0)	    fprintf (file, "0x%x%08x",		     CONST_DOUBLE_HIGH (x), CONST_DOUBLE_LOW (x));	  else	    fprintf (file, "%d", CONST_DOUBLE_LOW (x));	}      else

⌨️ 快捷键说明

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