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

📄 i960.c

📁 gcc-you can use this code to learn something about gcc, and inquire further into linux,
💻 C
📖 第 1 页 / 共 5 页
字号:
voidoutput_function_profiler (file, labelno)     FILE *file;     int labelno;{  /* The last used parameter register.  */  int last_parm_reg;  int i, j, increment;  int varargs_stdarg_function    = VARARGS_STDARG_FUNCTION (current_function_decl);  /* Figure out the last used parameter register.  The proper thing to do     is to walk incoming args of the function.  A function might have live     parameter registers even if it has no incoming args.  Note that we     don't have to save parameter registers g8 to g11 because they are     call preserved.  */  /* See also output_function_prologue, which tries to use local registers     for preserved call-saved global registers.  */  for (last_parm_reg = 7;       last_parm_reg >= 0 && ! regs_ever_live[last_parm_reg];       last_parm_reg--)    ;  /* Save parameter registers in regs r4 (20) to r11 (27).  */  for (i = 0, j = 4; i <= last_parm_reg; i += increment, j += increment)    {      if (i % 4 == 0 && (last_parm_reg - i) >= 3)	increment = 4;      else if (i % 4 == 0 && (last_parm_reg - i) >= 2)	increment = 3;      else if (i % 2 == 0 && (last_parm_reg - i) >= 1)	increment = 2;      else	increment = 1;      fprintf (file, "\tmov%s	g%d,r%d\n",	       (increment == 4 ? "q" : increment == 3 ? "t"		: increment == 2 ? "l": ""), i, j);      }  /* If this function uses the arg pointer, then save it in r3 and then     set it to zero.  */  if (current_function_args_size != 0 || varargs_stdarg_function)    fprintf (file, "\tmov	g14,r3\n\tmov	0,g14\n");  /* Load location address into g0 and call mcount.  */  fprintf (file, "\tlda\tLP%d,g0\n\tcallx\tmcount\n", labelno);  /* If this function uses the arg pointer, restore it.  */  if (current_function_args_size != 0 || varargs_stdarg_function)    fprintf (file, "\tmov	r3,g14\n");  /* Restore parameter registers.  */  for (i = 0, j = 4; i <= last_parm_reg; i += increment, j += increment)    {      if (i % 4 == 0 && (last_parm_reg - i) >= 3)	increment = 4;      else if (i % 4 == 0 && (last_parm_reg - i) >= 2)	increment = 3;      else if (i % 2 == 0 && (last_parm_reg - i) >= 1)	increment = 2;      else	increment = 1;      fprintf (file, "\tmov%s	r%d,g%d\n",	       (increment == 4 ? "q" : increment == 3 ? "t"		: increment == 2 ? "l": ""), j, i);    }}/* Output code for the function epilogue.  */static voidi960_output_function_epilogue (file, size)     FILE *file;     HOST_WIDE_INT size ATTRIBUTE_UNUSED;{  if (i960_leaf_ret_reg >= 0)    {      fprintf (file, "Li960R%d:	ret\n", ret_label);      return;    }  if (*epilogue_string == 0)    {      register rtx tmp;	      /* Emit a return insn, but only if control can fall through to here.  */      tmp = get_last_insn ();      while (tmp)	{	  if (GET_CODE (tmp) == BARRIER)	    return;	  if (GET_CODE (tmp) == CODE_LABEL)	    break;	  if (GET_CODE (tmp) == JUMP_INSN)	    {	      if (GET_CODE (PATTERN (tmp)) == RETURN)		return;	      break;	    }	  if (GET_CODE (tmp) == NOTE)	    {	      tmp = PREV_INSN (tmp);	      continue;	    }	  break;	}      fprintf (file, "Li960R%d:	ret\n", ret_label);      return;    }  fprintf (file, "Li960R%d:\n", ret_label);  fprintf (file, "\t#EPILOGUE#\n");  /* Output the string created by the prologue which will restore all     registers saved by the prologue.  */  if (epilogue_string[0] != '\0')    fprintf (file, "%s", epilogue_string);  /* Must clear g14 on return if this function set it.     Only varargs/stdarg functions modify g14.  */  if (VARARGS_STDARG_FUNCTION (current_function_decl))    fprintf (file, "\tmov	0,g14\n");  fprintf (file, "\tret\n");  fprintf (file, "\t#End Epilogue#\n");}/* Output code for a call insn.  */const char *i960_output_call_insn (target, argsize_rtx, arg_pointer, insn)     register rtx target, argsize_rtx, arg_pointer, insn;{  int argsize = INTVAL (argsize_rtx);  rtx nexti = next_real_insn (insn);  rtx operands[2];  int varargs_stdarg_function    = VARARGS_STDARG_FUNCTION (current_function_decl);  operands[0] = target;  operands[1] = arg_pointer;  if (current_function_args_size != 0 || varargs_stdarg_function)    output_asm_insn ("mov	g14,r3", operands);  if (argsize > 48)    output_asm_insn ("lda	%a1,g14", operands);  else if (current_function_args_size != 0 || varargs_stdarg_function)    output_asm_insn ("mov	0,g14", operands);  /* The code used to assume that calls to SYMBOL_REFs could not be more     than 24 bits away (b vs bx, callj vs callx).  This is not true.  This     feature is now implemented by relaxing in the GNU linker.  It can convert     bx to b if in range, and callx to calls/call/balx/bal as appropriate.  */  /* Nexti could be zero if the called routine is volatile.  */  if (optimize && (*epilogue_string == 0) && argsize == 0 && tail_call_ok       && (nexti == 0 || GET_CODE (PATTERN (nexti)) == RETURN))    {      /* Delete following return insn.  */      if (nexti && no_labels_between_p (insn, nexti))	delete_insn (nexti);      output_asm_insn ("bx	%0", operands);      return "# notreached";    }  output_asm_insn ("callx	%0", operands);  /* If the caller sets g14 to the address of the argblock, then the caller     must clear it after the return.  */  if (current_function_args_size != 0 || varargs_stdarg_function)    output_asm_insn ("mov	r3,g14", operands);  else if (argsize > 48)    output_asm_insn ("mov	0,g14", operands);  return "";}/* Output code for a return insn.  */const char *i960_output_ret_insn (insn)     register rtx insn;{  static char lbuf[20];    if (*epilogue_string != 0)    {      if (! TARGET_CODE_ALIGN && next_real_insn (insn) == 0)	return "";      sprintf (lbuf, "b	Li960R%d", ret_label);      return lbuf;    }  /* Must clear g14 on return if this function set it.     Only varargs/stdarg functions modify g14.  */  if (VARARGS_STDARG_FUNCTION (current_function_decl))    output_asm_insn ("mov	0,g14", 0);  if (i960_leaf_ret_reg >= 0)    {      sprintf (lbuf, "bx	(%s)", reg_names[i960_leaf_ret_reg]);      return lbuf;    }  return "ret";}/* Print the operand represented by rtx X formatted by code CODE.  */voidi960_print_operand (file, x, code)     FILE *file;     rtx x;     int code;{  enum rtx_code rtxcode = x ? GET_CODE (x) : NIL;  if (rtxcode == REG)    {      switch (code)	{	case 'D':	  /* Second reg of a double or quad.  */	  fprintf (file, "%s", reg_names[REGNO (x)+1]);	  break;	case 'E':	  /* Third reg of a quad.  */	  fprintf (file, "%s", reg_names[REGNO (x)+2]);	  break;	case 'F':	  /* Fourth reg of a quad.  */	  fprintf (file, "%s", reg_names[REGNO (x)+3]);	  break;	case 0:	  fprintf (file, "%s", reg_names[REGNO (x)]);	  break;	default:	  abort ();	}      return;    }  else if (rtxcode == MEM)    {      output_address (XEXP (x, 0));      return;    }  else if (rtxcode == CONST_INT)    {      HOST_WIDE_INT val = INTVAL (x);      if (code == 'C')	val = ~val;      if (val > 9999 || val < -999)	fprintf (file, "0x%x", val);      else	fprintf (file, "%d", val);      return;    }  else if (rtxcode == CONST_DOUBLE)    {      char dstr[30];      if (x == CONST0_RTX (GET_MODE (x)))	{	  fprintf (file, "0f0.0");	  return;	}      else if (x == CONST1_RTX (GET_MODE (x)))	{	  fprintf (file, "0f1.0");	  return;	}      real_to_decimal (dstr, CONST_DOUBLE_REAL_VALUE (x), sizeof (dstr), 0, 1);      fprintf (file, "0f%s", dstr);      return;    }  switch(code)    {    case 'B':      /* Branch or jump, depending on assembler.  */      if (TARGET_ASM_COMPAT)	fputs ("j", file);      else	fputs ("b", file);      break;    case 'S':      /* Sign of condition.  */      if ((rtxcode == EQ) || (rtxcode == NE) || (rtxcode == GTU)	  || (rtxcode == LTU) || (rtxcode == GEU) || (rtxcode == LEU))	fputs ("o", file);      else if ((rtxcode == GT) || (rtxcode == LT)	  || (rtxcode == GE) || (rtxcode == LE))	fputs ("i", file);      else	abort();      break;    case 'I':      /* Inverted condition.  */      rtxcode = reverse_condition (rtxcode);      goto normal;    case 'X':      /* Inverted condition w/ reversed operands.  */      rtxcode = reverse_condition (rtxcode);      /* Fallthrough.  */    case 'R':      /* Reversed operand condition.  */      rtxcode = swap_condition (rtxcode);      /* Fallthrough.  */    case 'C':      /* Normal condition.  */    normal:      if (rtxcode == EQ)  { fputs ("e", file); return; }      else if (rtxcode == NE)  { fputs ("ne", file); return; }      else if (rtxcode == GT)  { fputs ("g", file); return; }      else if (rtxcode == GTU) { fputs ("g", file); return; }      else if (rtxcode == LT)  { fputs ("l", file); return; }      else if (rtxcode == LTU) { fputs ("l", file); return; }      else if (rtxcode == GE)  { fputs ("ge", file); return; }      else if (rtxcode == GEU) { fputs ("ge", file); return; }      else if (rtxcode == LE)  { fputs ("le", file); return; }      else if (rtxcode == LEU) { fputs ("le", file); return; }      else abort ();      break;    case '+':      /* For conditional branches, substitute ".t" or ".f".  */      if (TARGET_BRANCH_PREDICT)	{	  x = find_reg_note (current_output_insn, REG_BR_PROB, 0);	  if (x)	    {	      int pred_val = INTVAL (XEXP (x, 0));	      fputs ((pred_val < REG_BR_PROB_BASE / 2 ? ".f" : ".t"), file);	    }	}      break;    case 0:      output_addr_const (file, x);      break;    default:      abort ();    }  return;}/* Print a memory address as an operand to reference that memory location.   This is exactly the same as legitimate_address_p, except that it the prints   addresses instead of recognizing them.  */voidi960_print_operand_addr (file, addr)     FILE *file;     register rtx addr;{  rtx breg, ireg;  rtx scale, offset;  ireg = 0;  breg = 0;  offset = 0;  scale = const1_rtx;  if (GET_CODE (addr) == REG)    breg = addr;  else if (CONSTANT_P (addr))    offset = addr;  else if (GET_CODE (addr) == PLUS)    {      rtx op0, op1;      op0 = XEXP (addr, 0);      op1 = XEXP (addr, 1);      if (GET_CODE (op0) == REG)	{	  breg = op0;	  if (GET_CODE (op1) == REG)	    ireg = op1;	  else if (CONSTANT_P (op1))	    offset = op1;	  else	    abort ();	}      else if (GET_CODE (op0) == PLUS)	{	  if (GET_CODE (XEXP (op0, 0)) == MULT)	    {	      ireg = XEXP (XEXP (op0, 0), 0);	      scale = XEXP (XEXP (op0, 0), 1);	      if (GET_CODE (XEXP (op0, 1)) == REG)		{		  breg = XEXP (op0, 1);		  offset = op1;		}	      else		abort ();	    }	  else if (GET_CODE (XEXP (op0, 0)) == REG)	    {	      breg = XEXP (op0, 0);	      if (GET_CODE (XEXP (op0, 1)) == REG)		{		  ireg = XEXP (op0, 1);		  offset = op1;		}	      else		abort ();	    }	  else	    abort ();	}      else if (GET_CODE (op0) == MULT)	{	  ireg = XEXP (op0, 0);	  scale = XEXP (op0, 1);	  if (GET_CODE (op1) == REG)	    breg = op1;	  else if (CONSTANT_P (op1))	    offset = op1;	  else	    abort ();	}      else	abort ();    }  else if (GET_CODE (addr) == MULT)    {      ireg = XEXP (addr, 0);      scale = XEXP (addr, 1);    }  else    abort ();  if (offset)    output_addr_const (file, offset);  if (breg)    fprintf (file, "(%s)", reg_names[REGNO (breg)]);  if (ireg)    fprintf (file, "[%s*%d]", reg_names[REGNO (ireg)], INTVAL (scale));}/* 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 80960, legitimate addresses are:		base				ld	(g0),r0		disp	(12 or 32 bit)		ld	foo,r0		base + index			ld	(g0)[g1*1],r0		base + displ			ld	0xf00(g0),r0		base + index*scale + displ	ld	0xf00(g0)[g1*4],r0		index*scale + base		ld	(g0)[g1*4],r0		index*scale + displ		ld	0xf00[g1*4],r0		index*scale			ld	[g1*4],r0		index + base + displ		ld	0xf00(g0)[g1*1],r0	In each case, scale can be 1, 2, 4, 8, or 16.  *//* This is exactly the same as i960_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.  *//* These two macros allow us to accept either a REG or a SUBREG anyplace   where a register is valid.  */#define RTX_OK_FOR_BASE_P(X, STRICT)					\  ((GET_CODE (X) == REG							\    && (STRICT ? REG_OK_FOR_BASE_P_STRICT (X) : REG_OK_FOR_BASE_P (X)))	\   || (GET_CODE (X) == SUBREG						\       && GET_CODE (SUBREG_REG (X)) == REG				\       && (STRICT ? REG_OK_FOR_BASE_P_STRICT (SUBREG_REG (X))		\

⌨️ 快捷键说明

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