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

📄 calls.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 5 页
字号:
  /* Declaration of the function being called,     or 0 if the function is computed (not known by name).  */  tree fndecl = 0;  char *name = 0;  /* Register in which non-BLKmode value will be returned,     or 0 if no value or if value is BLKmode.  */  rtx valreg;  /* Address where we should return a BLKmode value;     0 if value not BLKmode.  */  rtx structure_value_addr = 0;  /* Nonzero if that address is being passed by treating it as     an extra, implicit first parameter.  Otherwise,     it is passed by being copied directly into struct_value_rtx.  */  int structure_value_addr_parm = 0;  /* Size of aggregate value wanted, or zero if none wanted     or if we are using the non-reentrant PCC calling convention     or expecting the value in registers.  */  int struct_value_size = 0;  /* Nonzero if called function returns an aggregate in memory PCC style,     by returning the address of where to find it.  */  int pcc_struct_value = 0;  /* Number of actual parameters in this call, including struct value addr.  */  int num_actuals;  /* Number of named args.  Args after this are anonymous ones     and they must all go on the stack.  */  int n_named_args;  /* Count arg position in order args appear.  */  int argpos;  /* Vector of information about each argument.     Arguments are numbered in the order they will be pushed,     not the order they are written.  */  struct arg_data *args;  /* Total size in bytes of all the stack-parms scanned so far.  */  struct args_size args_size;  /* Size of arguments before any adjustments (such as rounding).  */  struct args_size original_args_size;  /* Data on reg parms scanned so far.  */  CUMULATIVE_ARGS args_so_far;  /* Nonzero if a reg parm has been scanned.  */  int reg_parm_seen;  /* Nonzero if we must avoid push-insns in the args for this call.      If stack space is allocated for register parameters, but not by the     caller, then it is preallocated in the fixed part of the stack frame.     So the entire argument block must then be preallocated (i.e., we     ignore PUSH_ROUNDING in that case).  */#if defined(REG_PARM_STACK_SPACE) && ! defined(OUTGOING_REG_PARM_STACK_SPACE)  int must_preallocate = 1;#else#ifdef PUSH_ROUNDING  int must_preallocate = 0;#else  int must_preallocate = 1;#endif#endif  /* Size of the stack reserved for parameter registers.  */  int reg_parm_stack_space = 0;  /* 1 if scanning parms front to back, -1 if scanning back to front.  */  int inc;  /* Address of space preallocated for stack parms     (on machines that lack push insns), or 0 if space not preallocated.  */  rtx argblock = 0;  /* Nonzero if it is plausible that this is a call to alloca.  */  int may_be_alloca;  /* Nonzero if this is a call to setjmp or a related function.  */  int returns_twice;  /* Nonzero if this is a call to `longjmp'.  */  int is_longjmp;  /* Nonzero if this is a call to an inline function.  */  int is_integrable = 0;  /* Nonzero if this is a call to a `const' function.     Note that only explicitly named functions are handled as `const' here.  */  int is_const = 0;  /* Nonzero if this is a call to a `volatile' function.  */  int is_volatile = 0;#if defined(ACCUMULATE_OUTGOING_ARGS) && defined(REG_PARM_STACK_SPACE)  /* Define the boundary of the register parm stack space that needs to be     save, if any.  */  int low_to_save = -1, high_to_save;  rtx save_area = 0;		/* Place that it is saved */#endif#ifdef ACCUMULATE_OUTGOING_ARGS  int initial_highest_arg_in_use = highest_outgoing_arg_in_use;  char *initial_stack_usage_map = stack_usage_map;#endif  rtx old_stack_level = 0;  int old_pending_adj;  int old_stack_arg_under_construction;  int old_inhibit_defer_pop = inhibit_defer_pop;  tree old_cleanups = cleanups_this_call;  rtx use_insns = 0;  register tree p;  register int i;  /* See if we can find a DECL-node for the actual function.     As a result, decide whether this is a call to an integrable function.  */  p = TREE_OPERAND (exp, 0);  if (TREE_CODE (p) == ADDR_EXPR)    {      fndecl = TREE_OPERAND (p, 0);      if (TREE_CODE (fndecl) != FUNCTION_DECL)	{	  /* May still be a `const' function if it is	     a call through a pointer-to-const.	     But we don't handle that.  */	  fndecl = 0;	}      else	{	  if (!flag_no_inline	      && fndecl != current_function_decl	      && DECL_SAVED_INSNS (fndecl))	    is_integrable = 1;	  else if (! TREE_ADDRESSABLE (fndecl))	    {	      /* In case this function later becomes inlineable,		 record that there was already a non-inline call to it.		 Use abstraction instead of setting TREE_ADDRESSABLE		 directly.  */	      if (DECL_INLINE (fndecl) && extra_warnings && !flag_no_inline)		warning_with_decl (fndecl, "can't inline call to `%s' which was declared inline");	      mark_addressable (fndecl);	    }	  if (TREE_READONLY (fndecl) && ! TREE_THIS_VOLATILE (fndecl)	      && TYPE_MODE (TREE_TYPE (exp)) != VOIDmode)	    is_const = 1;	}    }  is_volatile = TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (p)));#ifdef REG_PARM_STACK_SPACE#ifdef MAYBE_REG_PARM_STACK_SPACE  reg_parm_stack_space = MAYBE_REG_PARM_STACK_SPACE;#else  reg_parm_stack_space = REG_PARM_STACK_SPACE (fndecl);#endif#endif  /* Warn if this value is an aggregate type,     regardless of which calling convention we are using for it.  */  if (warn_aggregate_return      && (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE	  || TREE_CODE (TREE_TYPE (exp)) == UNION_TYPE	  || TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE))    warning ("function call has aggregate value");  /* Set up a place to return a structure.  */  /* Cater to broken compilers.  */  if (aggregate_value_p (exp))    {      /* This call returns a big structure.  */      is_const = 0;#ifdef PCC_STATIC_STRUCT_RETURN      if (flag_pcc_struct_return)	{	  pcc_struct_value = 1;	  is_integrable = 0;  /* Easier than making that case work right.  */	}      else#endif	{	  struct_value_size = int_size_in_bytes (TREE_TYPE (exp));	  if (struct_value_size < 0)	    abort ();	  if (target && GET_CODE (target) == MEM)	    structure_value_addr = XEXP (target, 0);	  else	    {	      /* Assign a temporary on the stack to hold the value.  */	      /* For variable-sized objects, we must be called with a target		 specified.  If we were to allocate space on the stack here,		 we would have no way of knowing when to free it.  */	      structure_value_addr		= XEXP (assign_stack_temp (BLKmode, struct_value_size, 1), 0);	      target = 0;	    }	}    }  /* If called function is inline, try to integrate it.  */  if (is_integrable)    {      rtx temp;      rtx before_call = get_last_insn ();      temp = expand_inline_function (fndecl, actparms, target,				     ignore, TREE_TYPE (exp),				     structure_value_addr);      /* If inlining succeeded, return.  */      if ((HOST_WIDE_INT) temp != -1)	{	  int i;	  /* Perform all cleanups needed for the arguments of this call	     (i.e. destructors in C++).  It is ok if these destructors	     clobber RETURN_VALUE_REG, because the only time we care about	     this is when TARGET is that register.  But in C++, we take	     care to never return that register directly.  */	  expand_cleanups_to (old_cleanups);#ifdef ACCUMULATE_OUTGOING_ARGS	  /* If the outgoing argument list must be preserved, push	     the stack before executing the inlined function if it	     makes any calls.  */	  for (i = reg_parm_stack_space - 1; i >= 0; i--)	    if (i < highest_outgoing_arg_in_use && stack_usage_map[i] != 0)	      break;	  if (stack_arg_under_construction || i >= 0)	    {	      rtx insn = NEXT_INSN (before_call), seq;	      /* Look for a call in the inline function code.		 If OUTGOING_ARGS_SIZE (DECL_SAVED_INSNS (fndecl)) is		 nonzero then there is a call and it is not necessary		 to scan the insns.  */	      if (OUTGOING_ARGS_SIZE (DECL_SAVED_INSNS (fndecl)) == 0)		for (; insn; insn = NEXT_INSN (insn))		  if (GET_CODE (insn) == CALL_INSN)		    break;	      if (insn)		{		  /* Reserve enough stack space so that the largest		     argument list of any function call in the inline		     function does not overlap the argument list being		     evaluated.  This is usually an overestimate because		     allocate_dynamic_stack_space reserves space for an		     outgoing argument list in addition to the requested		     space, but there is no way to ask for stack space such		     that an argument list of a certain length can be		     safely constructed.  */		  int adjust = OUTGOING_ARGS_SIZE (DECL_SAVED_INSNS (fndecl));#ifdef REG_PARM_STACK_SPACE		  /* Add the stack space reserved for register arguments		     in the inline function.  What is really needed is the		     largest value of reg_parm_stack_space in the inline		     function, but that is not available.  Using the current		     value of reg_parm_stack_space is wrong, but gives		     correct results on all supported machines.  */		  adjust += reg_parm_stack_space;#endif		  start_sequence ();		  emit_stack_save (SAVE_BLOCK, &old_stack_level, 0);		  allocate_dynamic_stack_space (GEN_INT (adjust),						NULL_RTX, BITS_PER_UNIT);		  seq = get_insns ();		  end_sequence ();		  emit_insns_before (seq, NEXT_INSN (before_call));		  emit_stack_restore (SAVE_BLOCK, old_stack_level, NULL_RTX);		}	    }#endif	  /* If the result is equivalent to TARGET, return TARGET to simplify	     checks in store_expr.  They can be equivalent but not equal in the	     case of a function that returns BLKmode.  */	  if (temp != target && rtx_equal_p (temp, target))	    return target;	  return temp;	}      /* If inlining failed, mark FNDECL as needing to be compiled	 separately after all.  */      mark_addressable (fndecl);    }  /* When calling a const function, we must pop the stack args right away,     so that the pop is deleted or moved with the call.  */  if (is_const)    NO_DEFER_POP;  function_call_count++;  if (fndecl && DECL_NAME (fndecl))    name = IDENTIFIER_POINTER (DECL_NAME (fndecl));#if 0  /* Unless it's a call to a specific function that isn't alloca,     if it has one argument, we must assume it might be alloca.  */  may_be_alloca =    (!(fndecl != 0 && strcmp (name, "alloca"))     && actparms != 0     && TREE_CHAIN (actparms) == 0);#else  /* We assume that alloca will always be called by name.  It     makes no sense to pass it as a pointer-to-function to     anything that does not understand its behavior.  */  may_be_alloca =    (name && ((IDENTIFIER_LENGTH (DECL_NAME (fndecl)) == 6		 && name[0] == 'a'		 && ! strcmp (name, "alloca"))		|| (IDENTIFIER_LENGTH (DECL_NAME (fndecl)) == 16		    && name[0] == '_'		    && ! strcmp (name, "__builtin_alloca"))));#endif  /* See if this is a call to a function that can return more than once     or a call to longjmp.  */  returns_twice = 0;  is_longjmp = 0;  if (name != 0 && IDENTIFIER_LENGTH (DECL_NAME (fndecl)) <= 15)    {      char *tname = name;      if (name[0] == '_')	tname += ((name[1] == '_' && name[2] == 'x') ? 3 : 1);      if (tname[0] == 's')	{	  returns_twice	    = ((tname[1] == 'e'		&& (! strcmp (tname, "setjmp")		    || ! strcmp (tname, "setjmp_syscall")))	       || (tname[1] == 'i'		   && ! strcmp (tname, "sigsetjmp"))	       || (tname[1] == 'a'		   && ! strcmp (tname, "savectx")));	  if (tname[1] == 'i'	      && ! strcmp (tname, "siglongjmp"))	    is_longjmp = 1;	}      else if ((tname[0] == 'q' && tname[1] == 's'		&& ! strcmp (tname, "qsetjmp"))	       || (tname[0] == 'v' && tname[1] == 'f'		   && ! strcmp (tname, "vfork")))	returns_twice = 1;      else if (tname[0] == 'l' && tname[1] == 'o'	       && ! strcmp (tname, "longjmp"))	is_longjmp = 1;    }  if (may_be_alloca)    current_function_calls_alloca = 1;  /* Don't let pending stack adjusts add up to too much.     Also, do all pending adjustments now     if there is any chance this might be a call to alloca.  */  if (pending_stack_adjust >= 32      || (pending_stack_adjust > 0 && may_be_alloca))    do_pending_stack_adjust ();  /* Operand 0 is a pointer-to-function; get the type of the function.  */  funtype = TREE_TYPE (TREE_OPERAND (exp, 0));  if (TREE_CODE (funtype) != POINTER_TYPE)    abort ();  funtype = TREE_TYPE (funtype);  /* Push the temporary stack slot level so that we can free temporaries used     by each of the arguments separately.  */  push_temp_slots ();  /* Start updating where the next arg would go.  */  INIT_CUMULATIVE_ARGS (args_so_far, funtype, NULL_PTR);  /* If struct_value_rtx is 0, it means pass the address     as if it were an extra parameter.  */  if (structure_value_addr && struct_value_rtx == 0)    {#ifdef ACCUMULATE_OUTGOING_ARGS      /* If the stack will be adjusted, make sure the structure address	 does not refer to virtual_outgoing_args_rtx.  */      rtx temp = (stack_arg_under_construction		  ? copy_addr_to_reg (structure_value_addr)		  : force_reg (Pmode, structure_value_addr));#else      rtx temp = force_reg (Pmode, structure_value_addr);

⌨️ 快捷键说明

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