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

📄 i960.c

📁 GUN开源阻止下的编译器GCC
💻 C
📖 第 1 页 / 共 5 页
字号:
  if (get_frame_size () != 0)    leaf_proc_ok = 0;  /* I don't understand this condition, and do not think that it is correct.     Apparently this is just checking whether the frame pointer is used, and     we can't trust regs_ever_live[fp] since it is (almost?) always set.  */  if (tail_call_ok)    for (insn = get_insns (); insn; insn = NEXT_INSN (insn))      if (GET_CODE (insn) == INSN	  && reg_mentioned_p (frame_pointer_rtx, insn))	{	  tail_call_ok = 0;	  break;	}  /* Check for CALL insns.  Can not be a leaf routine if there are any.  */  if (leaf_proc_ok)    for (insn = get_insns (); insn; insn = NEXT_INSN (insn))      if (GET_CODE (insn) == CALL_INSN)	{	  leaf_proc_ok = 0;	  break;	}  /* Can not be a leaf routine if any non-call clobbered registers are     used in this function.  */  if (leaf_proc_ok)    for (i = 0, j = 0; i < FIRST_PSEUDO_REGISTER; i++)      if (regs_ever_live[i]	  && ((! call_used_regs[i]) || (i > 7 && i < 12)))	{	  /* Global registers.  */	  if (i < 16 && i > 7 && i != 13)	    leaf_proc_ok = 0;	  /* Local registers.  */	  else if (i < 32)	    leaf_proc_ok = 0;	}  /* Now choose a leaf return register, if we can find one, and if it is     OK for this to be a leaf routine.  */  i960_leaf_ret_reg = -1;  if (optimize && leaf_proc_ok)    {      for (i960_leaf_ret_reg = -1, i = 0; i < 8; i++)	if (regs_ever_live[i] == 0)	  {	    i960_leaf_ret_reg = i;	    regs_ever_live[i] = 1;	    break;	  }    }  /* Do this after choosing the leaf return register, so it will be listed     if one was chosen.  */  fprintf (file, "\t#  Function '%s'\n", (name[0] == '*' ? &name[1] : name));  fprintf (file, "\t#  Registers used: ");  for (i = 0, j = 0; i < FIRST_PSEUDO_REGISTER; i++)    {      if (regs_ever_live[i])	{	  fprintf (file, "%s%s ", reg_names[i], call_used_regs[i] ? "" : "*");	  if (i > 15 && j == 0)	    {	      fprintf (file,"\n\t#\t\t   ");	      j++;            }        }    }  fprintf (file, "\n");  if (i960_leaf_ret_reg >= 0)    {      /* Make it a leaf procedure.  */      if (TREE_PUBLIC (fndecl))	fprintf (file,"\t.globl\t%s.lf\n", (name[0] == '*' ? &name[1] : name));      fprintf (file, "\t.leafproc\t");      assemble_name (file, name);      fprintf (file, ",%s.lf\n", (name[0] == '*' ? &name[1] : name));      ASM_OUTPUT_LABEL (file, name);      fprintf (file, "\tlda    LR%d,g14\n", ret_label);      fprintf (file, "%s.lf:\n", (name[0] == '*' ? &name[1] : name));      fprintf (file, "\tmov    g14,g%d\n", i960_leaf_ret_reg);      if (TARGET_C_SERIES)	{	  fprintf (file, "\tlda    0,g14\n");	  i960_last_insn_type = I_TYPE_MEM;	}      else	{	  fprintf (file, "\tmov    0,g14\n");	  i960_last_insn_type = I_TYPE_REG;	}    }  else    {      ASM_OUTPUT_LABEL (file, name);      i960_last_insn_type = I_TYPE_CTRL;     }}/* Compute and return the frame size.  */intcompute_frame_size (size)     int size;{  int actual_fsize;  int outgoing_args_size = current_function_outgoing_args_size;  /* The STARTING_FRAME_OFFSET is totally hidden to us as far     as size is concerned.  */  actual_fsize = (size + 15) & -16;  actual_fsize += (outgoing_args_size + 15) & -16;  return actual_fsize;}/* Output code for the function prologue.  */voidi960_function_prologue (file, size)     FILE *file;     unsigned int size;{  register int i, j, nr;  int n_iregs = 0;  int rsize = 0;  int actual_fsize, offset;  char tmpstr[1000];  /* -1 if reg must be saved on proc entry, 0 if available, 1 if saved     somewhere.  */  int regs[FIRST_PSEUDO_REGISTER];  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)    if (regs_ever_live[i]	&& ((! call_used_regs[i]) || (i > 7 && i < 12)))      {	regs[i] = -1;        /* Count global registers that need saving.  */	if (i < 16)	  n_iregs++;      }    else      regs[i] = 0;  epilogue_string[0] = '\0';  if (profile_flag || profile_block_flag)    {      /* When profiling, we may use registers 20 to 27 to save arguments, so	 they can't be used here for saving globals.  J is the number of	 argument registers the mcount call will save.  */      for (j = 7; j >= 0 && ! regs_ever_live[j]; j--)	;      for (i = 20; i <= j + 20; i++)	regs[i] = -1;    }  /* First look for local registers to save globals in.  */  for (i = 0; i < 16; i++)    {      if (regs[i] == 0)	continue;      /* Start at r4, not r3.  */      for (j = 20; j < 32; j++)	{	  if (regs[j] != 0)	    continue;	  regs[i] = 1;	  regs[j] = -1;	  regs_ever_live[j] = 1;	  nr = 1;	  if (i <= 14 && i % 2 == 0 && j <= 30 && j % 2 == 0	      && regs[i+1] != 0 && regs[j+1] == 0)	    {	      nr = 2;	      regs[i+1] = 1;	      regs[j+1] = -1;	      regs_ever_live[j+1] = 1;	    }	  if (nr == 2 && i <= 12 && i % 4 == 0 && j <= 28 && j % 4 == 0	      && regs[i+2] != 0 && regs[j+2] == 0)	    {	      nr = 3;	      regs[i+2] = 1;	      regs[j+2] = -1;	      regs_ever_live[j+2] = 1;	    }	  if (nr == 3 && regs[i+3] != 0 && regs[j+3] == 0)	    {	      nr = 4;	      regs[i+3] = 1;	      regs[j+3] = -1;	      regs_ever_live[j+3] = 1;	    }	  fprintf (file, "\tmov%s	%s,%s\n",		   ((nr == 4) ? "q" :		    (nr == 3) ? "t" :		    (nr == 2) ? "l" : ""),		   reg_names[i], reg_names[j]);	  sprintf (tmpstr, "\tmov%s	%s,%s\n",		   ((nr == 4) ? "q" :		    (nr == 3) ? "t" :		    (nr == 2) ? "l" : ""),		   reg_names[j], reg_names[i]);	  strcat (epilogue_string, tmpstr);	  n_iregs -= nr;	  i += nr-1;	  break;	}    }  /* N_iregs is now the number of global registers that haven't been saved     yet.  */  rsize = (n_iregs * 4);  actual_fsize = compute_frame_size (size) + rsize;#if 0  /* ??? The 1.2.1 compiler does this also.  This is meant to round the frame     size up to the nearest multiple of 16.  I don't know whether this is     necessary, or even desirable.     The frame pointer must be aligned, but the call instruction takes care of     that.  If we leave the stack pointer unaligned, we may save a little on     dynamic stack allocation.  And we don't lose, at least according to the     i960CA manual.  */  actual_fsize = (actual_fsize + 15) & ~0xF;#endif  /* Allocate space for register save and locals.  */  if (actual_fsize > 0)    {      if (actual_fsize < 32)	fprintf (file, "\taddo	%d,sp,sp\n", actual_fsize);      else	fprintf (file, "\tlda\t%d(sp),sp\n", actual_fsize);    }  /* Take hardware register save area created by the call instruction     into account, but store them before the argument block area.  */  offset = 64 + actual_fsize - compute_frame_size (0) - rsize;  /* Save registers on stack if needed.  */  for (i = 0, j = n_iregs; j > 0 && i < 16; i++)    {      if (regs[i] != -1)	continue;      nr = 1;      if (i <= 14 && i % 2 == 0 && regs[i+1] == -1 && offset % 2 == 0)	nr = 2;      if (nr == 2 && i <= 12 && i % 4 == 0 && regs[i+2] == -1	  && offset % 4 == 0)	nr = 3;      if (nr == 3 && regs[i+3] == -1)	nr = 4;      fprintf (file,"\tst%s	%s,%d(fp)\n",	       ((nr == 4) ? "q" :		(nr == 3) ? "t" :		(nr == 2) ? "l" : ""),	       reg_names[i], offset);      sprintf (tmpstr,"\tld%s	%d(fp),%s\n",	       ((nr == 4) ? "q" :		(nr == 3) ? "t" :		(nr == 2) ? "l" : ""),	       offset, reg_names[i]);      strcat (epilogue_string, tmpstr);      i += nr-1;      j -= nr;      offset += nr * 4;    }  if (actual_fsize == 0 && size == 0 && rsize == 0)    return;  fprintf (file, "\t#Prologue stats:\n");  fprintf (file, "\t#  Total Frame Size: %d bytes\n", actual_fsize);  if (size)    fprintf (file, "\t#  Local Variable Size: %d bytes\n", size);  if (rsize)    fprintf (file, "\t#  Register Save Size: %d regs, %d bytes\n",	     n_iregs, rsize);  fprintf (file, "\t#End Prologue#\n");}/* Output code for the function profiler.  */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.  */voidi960_function_epilogue (file, size)     FILE *file;     unsigned int size;{  if (i960_leaf_ret_reg >= 0)    {      fprintf (file, "LR%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, "LR%d:	ret\n", ret_label);      return;    }  fprintf (file, "LR%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.  */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.  */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 "";

⌨️ 快捷键说明

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