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

📄 c4x.c

📁 Mac OS X 10.4.9 for x86 Source Code gcc 实现源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
     extended registers.  */  if (IS_EXT_REGNO (regno1) && ! IS_EXT_REGNO (regno2))    return 0;  if (IS_EXT_REGNO (regno2) && ! IS_EXT_REGNO (regno1))    return 0;  return 1;}/* The TI C3x C compiler register argument runtime model uses 6 registers,   AR2, R2, R3, RC, RS, RE.   The first two floating point arguments (float, double, long double)   that are found scanning from left to right are assigned to R2 and R3.   The remaining integer (char, short, int, long) or pointer arguments   are assigned to the remaining registers in the order AR2, R2, R3,   RC, RS, RE when scanning left to right, except for the last named   argument prior to an ellipsis denoting variable number of   arguments.  We don't have to worry about the latter condition since   function.c treats the last named argument as anonymous (unnamed).   All arguments that cannot be passed in registers are pushed onto   the stack in reverse order (right to left).  GCC handles that for us.   c4x_init_cumulative_args() is called at the start, so we can parse   the args to see how many floating point arguments and how many   integer (or pointer) arguments there are.  c4x_function_arg() is   then called (sometimes repeatedly) for each argument (parsed left   to right) to obtain the register to pass the argument in, or zero   if the argument is to be passed on the stack.  Once the compiler is   happy, c4x_function_arg_advance() is called.   Don't use R0 to pass arguments in, we use 0 to indicate a stack   argument.  */static const int c4x_int_reglist[3][6] ={  {AR2_REGNO, R2_REGNO, R3_REGNO, RC_REGNO, RS_REGNO, RE_REGNO},  {AR2_REGNO, R3_REGNO, RC_REGNO, RS_REGNO, RE_REGNO, 0},  {AR2_REGNO, RC_REGNO, RS_REGNO, RE_REGNO, 0, 0}};static const int c4x_fp_reglist[2] = {R2_REGNO, R3_REGNO};/* Initialize a variable CUM of type CUMULATIVE_ARGS for a call to a   function whose data type is FNTYPE.   For a library call, FNTYPE is  0.  */voidc4x_init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype, rtx libname){  tree param, next_param;  cum->floats = cum->ints = 0;  cum->init = 0;  cum->var = 0;  cum->args = 0;  if (TARGET_DEBUG)    {      fprintf (stderr, "\nc4x_init_cumulative_args (");      if (fntype)	{	  tree ret_type = TREE_TYPE (fntype);	  fprintf (stderr, "fntype code = %s, ret code = %s",		   tree_code_name[(int) TREE_CODE (fntype)],		   tree_code_name[(int) TREE_CODE (ret_type)]);	}      else	fprintf (stderr, "no fntype");      if (libname)	fprintf (stderr, ", libname = %s", XSTR (libname, 0));    }  cum->prototype = (fntype && TYPE_ARG_TYPES (fntype));  for (param = fntype ? TYPE_ARG_TYPES (fntype) : 0;       param; param = next_param)    {      tree type;      next_param = TREE_CHAIN (param);      type = TREE_VALUE (param);      if (type && type != void_type_node)	{	  enum machine_mode mode;	  /* If the last arg doesn't have void type then we have	     variable arguments.  */	  if (! next_param)	    cum->var = 1;	  if ((mode = TYPE_MODE (type)))	    {	      if (! targetm.calls.must_pass_in_stack (mode, type))		{		  /* Look for float, double, or long double argument.  */		  if (mode == QFmode || mode == HFmode)		    cum->floats++;		  /* Look for integer, enumeral, boolean, char, or pointer		     argument.  */		  else if (mode == QImode || mode == Pmode)		    cum->ints++;		}	    }	  cum->args++;	}    }  if (TARGET_DEBUG)    fprintf (stderr, "%s%s, args = %d)\n",	     cum->prototype ? ", prototype" : "",	     cum->var ? ", variable args" : "",	     cum->args);}/* Update the data in CUM to advance over an argument   of mode MODE and data type TYPE.   (TYPE is null for libcalls where that information may not be available.)  */voidc4x_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,			  tree type, int named){  if (TARGET_DEBUG)    fprintf (stderr, "c4x_function_adv(mode=%s, named=%d)\n\n",	     GET_MODE_NAME (mode), named);  if (! TARGET_MEMPARM       && named      && type      && ! targetm.calls.must_pass_in_stack (mode, type))    {      /* Look for float, double, or long double argument.  */      if (mode == QFmode || mode == HFmode)	cum->floats++;      /* Look for integer, enumeral, boolean, char, or pointer argument.  */      else if (mode == QImode || mode == Pmode)	cum->ints++;    }  else if (! TARGET_MEMPARM && ! type)    {      /* Handle libcall arguments.  */      if (mode == QFmode || mode == HFmode)	cum->floats++;      else if (mode == QImode || mode == Pmode)	cum->ints++;    }  return;}/* Define where to put the arguments to a function.  Value is zero to   push the argument on the stack, or a hard register in which to   store the argument.   MODE is the argument's machine mode.   TYPE is the data type of the argument (as a tree).   This is null for libcalls where that information may   not be available.   CUM is a variable of type CUMULATIVE_ARGS which gives info about   the preceding args and about the function being called.   NAMED is nonzero if this argument is a named parameter   (otherwise it is an extra parameter matching an ellipsis).  */struct rtx_def *c4x_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,		  tree type, int named){  int reg = 0;			/* Default to passing argument on stack.  */  if (! cum->init)    {      /* We can handle at most 2 floats in R2, R3.  */      cum->maxfloats = (cum->floats > 2) ? 2 : cum->floats;      /* We can handle at most 6 integers minus number of floats passed 	 in registers.  */      cum->maxints = (cum->ints > 6 - cum->maxfloats) ? 	6 - cum->maxfloats : cum->ints;      /* If there is no prototype, assume all the arguments are integers.  */      if (! cum->prototype)	cum->maxints = 6;      cum->ints = cum->floats = 0;      cum->init = 1;    }  /* This marks the last argument.  We don't need to pass this through     to the call insn.  */  if (type == void_type_node)    return 0;  if (! TARGET_MEMPARM       && named       && type      && ! targetm.calls.must_pass_in_stack (mode, type))    {      /* Look for float, double, or long double argument.  */      if (mode == QFmode || mode == HFmode)	{	  if (cum->floats < cum->maxfloats)	    reg = c4x_fp_reglist[cum->floats];	}      /* Look for integer, enumeral, boolean, char, or pointer argument.  */      else if (mode == QImode || mode == Pmode)	{	  if (cum->ints < cum->maxints)	    reg = c4x_int_reglist[cum->maxfloats][cum->ints];	}    }  else if (! TARGET_MEMPARM && ! type)    {      /* We could use a different argument calling model for libcalls,         since we're only calling functions in libgcc.  Thus we could         pass arguments for long longs in registers rather than on the         stack.  In the meantime, use the odd TI format.  We make the         assumption that we won't have more than two floating point         args, six integer args, and that all the arguments are of the         same mode.  */      if (mode == QFmode || mode == HFmode)	reg = c4x_fp_reglist[cum->floats];      else if (mode == QImode || mode == Pmode)	reg = c4x_int_reglist[0][cum->ints];    }  if (TARGET_DEBUG)    {      fprintf (stderr, "c4x_function_arg(mode=%s, named=%d",	       GET_MODE_NAME (mode), named);      if (reg)	fprintf (stderr, ", reg=%s", reg_names[reg]);      else	fprintf (stderr, ", stack");      fprintf (stderr, ")\n");    }  if (reg)    return gen_rtx_REG (mode, reg);  else    return NULL_RTX;}/* C[34]x arguments grow in weird ways (downwards) that the standard   varargs stuff can't handle..  */static treec4x_gimplify_va_arg_expr (tree valist, tree type,			  tree *pre_p ATTRIBUTE_UNUSED,			  tree *post_p ATTRIBUTE_UNUSED){  tree t;  bool indirect;  indirect = pass_by_reference (NULL, TYPE_MODE (type), type, false);  if (indirect)    type = build_pointer_type (type);  t = build (PREDECREMENT_EXPR, TREE_TYPE (valist), valist,	     build_int_cst (NULL_TREE, int_size_in_bytes (type)));  t = fold_convert (build_pointer_type (type), t);  t = build_fold_indirect_ref (t);  if (indirect)    t = build_fold_indirect_ref (t);  return t;}static intc4x_isr_reg_used_p (unsigned int regno){  /* Don't save/restore FP or ST, we handle them separately.  */  if (regno == FRAME_POINTER_REGNUM      || IS_ST_REGNO (regno))    return 0;  /* We could be a little smarter abut saving/restoring DP.     We'll only save if for the big memory model or if     we're paranoid. ;-)  */  if (IS_DP_REGNO (regno))    return ! TARGET_SMALL || TARGET_PARANOID;  /* Only save/restore regs in leaf function that are used.  */  if (c4x_leaf_function)    return regs_ever_live[regno] && fixed_regs[regno] == 0;  /* Only save/restore regs that are used by the ISR and regs     that are likely to be used by functions the ISR calls     if they are not fixed.  */  return IS_EXT_REGNO (regno)    || ((regs_ever_live[regno] || call_used_regs[regno]) 	&& fixed_regs[regno] == 0);}static intc4x_leaf_function_p (void){  /* A leaf function makes no calls, so we only need     to save/restore the registers we actually use.     For the global variable leaf_function to be set, we need     to define LEAF_REGISTERS and all that it entails.     Let's check ourselves....  */  if (lookup_attribute ("leaf_pretend",			TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl))))    return 1;  /* Use the leaf_pretend attribute at your own risk.  This is a hack     to speed up ISRs that call a function infrequently where the     overhead of saving and restoring the additional registers is not     warranted.  You must save and restore the additional registers     required by the called function.  Caveat emptor.  Here's enough     rope...  */  if (leaf_function_p ())    return 1;  return 0;}static intc4x_naked_function_p (void){  tree type;  type = TREE_TYPE (current_function_decl);  return lookup_attribute ("naked", TYPE_ATTRIBUTES (type)) != NULL;}intc4x_interrupt_function_p (void){  const char *cfun_name;  if (lookup_attribute ("interrupt",			TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl))))    return 1;  /* Look for TI style c_intnn.  */  cfun_name = current_function_name ();  return cfun_name[0] == 'c'    && cfun_name[1] == '_'    && cfun_name[2] == 'i'    && cfun_name[3] == 'n'     && cfun_name[4] == 't'    && ISDIGIT (cfun_name[5])    && ISDIGIT (cfun_name[6]);}voidc4x_expand_prologue (void){  unsigned int regno;  int size = get_frame_size ();  rtx insn;  /* In functions where ar3 is not used but frame pointers are still     specified, frame pointers are not adjusted (if >= -O2) and this     is used so it won't needlessly push the frame pointer.  */  int dont_push_ar3;  /* For __naked__ function don't build a prologue.  */  if (c4x_naked_function_p ())    {      return;    }    /* For __interrupt__ function build specific prologue.  */  if (c4x_interrupt_function_p ())    {      c4x_leaf_function = c4x_leaf_function_p ();            insn = emit_insn (gen_push_st ());      RTX_FRAME_RELATED_P (insn) = 1;      if (size)	{          insn = emit_insn (gen_pushqi ( gen_rtx_REG (QImode, AR3_REGNO)));          RTX_FRAME_RELATED_P (insn) = 1;	  insn = emit_insn (gen_movqi (gen_rtx_REG (QImode, AR3_REGNO),				       gen_rtx_REG (QImode, SP_REGNO)));          RTX_FRAME_RELATED_P (insn) = 1;	  /* We require that an ISR uses fewer than 32768 words of	     local variables, otherwise we have to go to lots of	     effort to save a register, load it with the desired size,	     adjust the stack pointer, and then restore the modified	     register.  Frankly, I think it is a poor ISR that	     requires more than 32767 words of local temporary	     storage!  */	  if (size > 32767)	    error ("ISR %s requires %d words of local vars, max is 32767",		   current_function_name (), size);	  insn = emit_insn (gen_addqi3 (gen_rtx_REG (QImode, SP_REGNO),				        gen_rtx_REG (QImode, SP_REGNO),					GEN_INT (size)));          RTX_FRAME_RELATED_P (insn) = 1;	}      for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)	{	  if (c4x_isr_reg_used_p (regno))	    {	      if (regno == DP_REGNO)		{		  insn = emit_insn (gen_push_dp ());                  RTX_FRAME_RELATED_P (insn) = 1;		}	      else		{                  insn = emit_insn (gen_pushqi (gen_rtx_REG (QImode, regno)));                  RTX_FRAME_RELATED_P (insn) = 1;		  if (IS_EXT_REGNO (regno))		    {                      insn = emit_insn (gen_pushqf					(gen_rtx_REG (QFmode, regno)));                      RTX_FRAME_RELATED_P (insn) = 1;		    }		}	    }	}      /* We need to clear the repeat mode flag if the ISR is         going to use a RPTB instruction or uses the RC, RS, or RE         registers.  */      if (regs_ever_live[RC_REGNO] 	  || regs_ever_live[RS_REGNO] 	  || regs_ever_live[RE_REGNO])	{          insn = emit_insn (gen_andn_st (GEN_INT(~0x100)));          RTX_FRAME_RELATED_P (insn) = 1;	}      /* Reload DP reg if we are paranoid about some turkey         violating small memory model rules.  */      if (TARGET_SMALL && TARGET_PARANOID)	{          insn = emit_insn (gen_set_ldp_prologue			    (gen_rtx_REG (QImode, DP_REGNO),			     gen_rtx_SYMBOL_REF (QImode, "data_sec")));          RTX_FRAME_RELATED_P (insn) = 1;	}    }  else    {      if (frame_pointer_needed)	{	  if ((size != 0)	      || (current_function_args_size != 0)	      || (optimize < 2))	    {              insn = emit_insn (gen_pushqi ( gen_rtx_REG (QImode, AR3_REGNO)));              RTX_FRAME_RELATED_P (insn) = 1;	      insn = emit_insn (gen_movqi (gen_rtx_REG (QImode, AR3_REGNO),				           gen_rtx_REG (QImode, SP_REGNO)));              RTX_FRAME_RELATED_P (insn) = 1;	      dont_push_ar3 = 1;	    }	  else	    {	      /* Since ar3 is not used, we don't need to push it.  */	      dont_push_ar3 = 1;	    }	}      else	{	  /* If we use ar3, we need to push it.  */	  dont_push_ar3 = 0;	  if ((size != 0) || (current_function_args_size != 0))	    {	      /* If we are omitting the frame pointer, we still have

⌨️ 快捷键说明

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