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

📄 calls.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 5 页
字号:
#endif      actparms	= tree_cons (error_mark_node,		     make_tree (build_pointer_type (TREE_TYPE (funtype)),				temp),		     actparms);      structure_value_addr_parm = 1;    }  /* Count the arguments and set NUM_ACTUALS.  */  for (p = actparms, i = 0; p; p = TREE_CHAIN (p)) i++;  num_actuals = i;  /* Compute number of named args.     Normally, don't include the last named arg if anonymous args follow.     (If no anonymous args follow, the result of list_length     is actually one too large.)     If SETUP_INCOMING_VARARGS is defined, this machine will be able to     place unnamed args that were passed in registers into the stack.  So     treat all args as named.  This allows the insns emitting for a specific     argument list to be independent of the function declaration.     If SETUP_INCOMING_VARARGS is not defined, we do not have any reliable     way to pass unnamed args in registers, so we must force them into     memory.  */#ifndef SETUP_INCOMING_VARARGS  if (TYPE_ARG_TYPES (funtype) != 0)    n_named_args      = list_length (TYPE_ARG_TYPES (funtype)) - 1	/* Count the struct value address, if it is passed as a parm.  */	+ structure_value_addr_parm;  else#endif    /* If we know nothing, treat all args as named.  */    n_named_args = num_actuals;  /* Make a vector to hold all the information about each arg.  */  args = (struct arg_data *) alloca (num_actuals * sizeof (struct arg_data));  bzero (args, num_actuals * sizeof (struct arg_data));  args_size.constant = 0;  args_size.var = 0;  /* In this loop, we consider args in the order they are written.     We fill up ARGS from the front of from the back if necessary     so that in any case the first arg to be pushed ends up at the front.  */#ifdef PUSH_ARGS_REVERSED  i = num_actuals - 1, inc = -1;  /* In this case, must reverse order of args     so that we compute and push the last arg first.  */#else  i = 0, inc = 1;#endif  /* I counts args in order (to be) pushed; ARGPOS counts in order written.  */  for (p = actparms, argpos = 0; p; p = TREE_CHAIN (p), i += inc, argpos++)    {      tree type = TREE_TYPE (TREE_VALUE (p));      enum machine_mode mode;      args[i].tree_value = TREE_VALUE (p);      /* Replace erroneous argument with constant zero.  */      if (type == error_mark_node || TYPE_SIZE (type) == 0)	args[i].tree_value = integer_zero_node, type = integer_type_node;      /* Decide where to pass this arg.	 args[i].reg is nonzero if all or part is passed in registers.	 args[i].partial is nonzero if part but not all is passed in registers,	 and the exact value says how many words are passed in registers.	 args[i].pass_on_stack is nonzero if the argument must at least be	 computed on the stack.  It may then be loaded back into registers	 if args[i].reg is nonzero.	 These decisions are driven by the FUNCTION_... macros and must agree	 with those made by function.c.  */#ifdef FUNCTION_ARG_PASS_BY_REFERENCE      /* See if this argument should be passed by invisible reference.  */      if (FUNCTION_ARG_PASS_BY_REFERENCE (args_so_far, TYPE_MODE (type), type,					  argpos < n_named_args))	{	  /* We make a copy of the object and pass the address to the function	     being called.  */	  int size = int_size_in_bytes (type);	  rtx copy;	  if (size < 0)	    {	      /* This is a variable-sized object.  Make space on the stack		 for it.  */	      rtx size_rtx = expand_expr (size_in_bytes (type), NULL_RTX,					  VOIDmode, 0);	      if (old_stack_level == 0)		{		  emit_stack_save (SAVE_BLOCK, &old_stack_level, NULL_RTX);		  old_pending_adj = pending_stack_adjust;		  pending_stack_adjust = 0;		}	      copy = gen_rtx (MEM, BLKmode,			      allocate_dynamic_stack_space (size_rtx, NULL_RTX,							    TYPE_ALIGN (type)));	    }	  else	    copy = assign_stack_temp (TYPE_MODE (type), size, 1);	  store_expr (args[i].tree_value, copy, 0);	  args[i].tree_value = build1 (ADDR_EXPR, build_pointer_type (type),				       make_tree (type, copy));	  type = build_pointer_type (type);	}#endif      mode = TYPE_MODE (type);#ifdef PROMOTE_FUNCTION_ARGS      /* Compute the mode in which the arg is actually to be extended to.  */      if (TREE_CODE (type) == INTEGER_TYPE || TREE_CODE (type) == ENUMERAL_TYPE	  || TREE_CODE (type) == BOOLEAN_TYPE || TREE_CODE (type) == CHAR_TYPE	  || TREE_CODE (type) == REAL_TYPE || TREE_CODE (type) == POINTER_TYPE	  || TREE_CODE (type) == OFFSET_TYPE)	{	  int unsignedp = TREE_UNSIGNED (type);	  PROMOTE_MODE (mode, unsignedp, type);	  args[i].unsignedp = unsignedp;	}#endif      args[i].reg = FUNCTION_ARG (args_so_far, mode, type,				  argpos < n_named_args);#ifdef FUNCTION_ARG_PARTIAL_NREGS      if (args[i].reg)	args[i].partial	  = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, mode, type,					argpos < n_named_args);#endif      args[i].pass_on_stack = MUST_PASS_IN_STACK (mode, type);      /* If FUNCTION_ARG returned an (expr_list (nil) FOO), it means that	 we are to pass this arg in the register(s) designated by FOO, but	 also to pass it in the stack.  */      if (args[i].reg && GET_CODE (args[i].reg) == EXPR_LIST	  && XEXP (args[i].reg, 0) == 0)	args[i].pass_on_stack = 1, args[i].reg = XEXP (args[i].reg, 1);      /* If this is an addressable type, we must preallocate the stack	 since we must evaluate the object into its final location.	 If this is to be passed in both registers and the stack, it is simpler	 to preallocate.  */      if (TREE_ADDRESSABLE (type)	  || (args[i].pass_on_stack && args[i].reg != 0))	must_preallocate = 1;      /* If this is an addressable type, we cannot pre-evaluate it.  Thus,	 we cannot consider this function call constant.  */      if (TREE_ADDRESSABLE (type))	is_const = 0;      /* Compute the stack-size of this argument.  */      if (args[i].reg == 0 || args[i].partial != 0#ifdef REG_PARM_STACK_SPACE	  || reg_parm_stack_space > 0#endif	  || args[i].pass_on_stack)	locate_and_pad_parm (TYPE_MODE (type), type,#ifdef STACK_PARMS_IN_REG_PARM_AREA			     1,#else			     args[i].reg != 0,#endif			     fndecl, &args_size, &args[i].offset,			     &args[i].size);#ifndef ARGS_GROW_DOWNWARD      args[i].slot_offset = args_size;#endif#ifndef REG_PARM_STACK_SPACE      /* If a part of the arg was put into registers,	 don't include that part in the amount pushed.  */      if (! args[i].pass_on_stack)	args[i].size.constant -= ((args[i].partial * UNITS_PER_WORD)				  / (PARM_BOUNDARY / BITS_PER_UNIT)				  * (PARM_BOUNDARY / BITS_PER_UNIT));#endif            /* Update ARGS_SIZE, the total stack space for args so far.  */      args_size.constant += args[i].size.constant;      if (args[i].size.var)	{	  ADD_PARM_SIZE (args_size, args[i].size.var);	}      /* Since the slot offset points to the bottom of the slot,	 we must record it after incrementing if the args grow down.  */#ifdef ARGS_GROW_DOWNWARD      args[i].slot_offset = args_size;      args[i].slot_offset.constant = -args_size.constant;      if (args_size.var)	{	  SUB_PARM_SIZE (args[i].slot_offset, args_size.var);	}#endif      /* Increment ARGS_SO_FAR, which has info about which arg-registers	 have been used, etc.  */      FUNCTION_ARG_ADVANCE (args_so_far, TYPE_MODE (type), type,			    argpos < n_named_args);    }#ifdef FINAL_REG_PARM_STACK_SPACE  reg_parm_stack_space = FINAL_REG_PARM_STACK_SPACE (args_size.constant,						     args_size.var);#endif        /* Compute the actual size of the argument block required.  The variable     and constant sizes must be combined, the size may have to be rounded,     and there may be a minimum required size.  */  original_args_size = args_size;  if (args_size.var)    {      /* If this function requires a variable-sized argument list, don't try to	 make a cse'able block for this call.  We may be able to do this	 eventually, but it is too complicated to keep track of what insns go	 in the cse'able block and which don't.  */      is_const = 0;      must_preallocate = 1;      args_size.var = ARGS_SIZE_TREE (args_size);      args_size.constant = 0;#ifdef STACK_BOUNDARY      if (STACK_BOUNDARY != BITS_PER_UNIT)	args_size.var = round_up (args_size.var, STACK_BYTES);#endif#ifdef REG_PARM_STACK_SPACE      if (reg_parm_stack_space > 0)	{	  args_size.var	    = size_binop (MAX_EXPR, args_size.var,			  size_int (REG_PARM_STACK_SPACE (fndecl)));#ifndef OUTGOING_REG_PARM_STACK_SPACE	  /* The area corresponding to register parameters is not to count in	     the size of the block we need.  So make the adjustment.  */	  args_size.var	    = size_binop (MINUS_EXPR, args_size.var,			  size_int (reg_parm_stack_space));#endif	}#endif    }  else    {#ifdef STACK_BOUNDARY      args_size.constant = (((args_size.constant + (STACK_BYTES - 1))			     / STACK_BYTES) * STACK_BYTES);#endif#ifdef REG_PARM_STACK_SPACE      args_size.constant = MAX (args_size.constant,				reg_parm_stack_space);#ifndef OUTGOING_REG_PARM_STACK_SPACE      args_size.constant -= reg_parm_stack_space;#endif#endif    }  /* See if we have or want to preallocate stack space.     If we would have to push a partially-in-regs parm     before other stack parms, preallocate stack space instead.     If the size of some parm is not a multiple of the required stack     alignment, we must preallocate.     If the total size of arguments that would otherwise create a copy in     a temporary (such as a CALL) is more than half the total argument list     size, preallocation is faster.     Another reason to preallocate is if we have a machine (like the m88k)     where stack alignment is required to be maintained between every     pair of insns, not just when the call is made.  However, we assume here     that such machines either do not have push insns (and hence preallocation     would occur anyway) or the problem is taken care of with     PUSH_ROUNDING.  */  if (! must_preallocate)    {      int partial_seen = 0;      int copy_to_evaluate_size = 0;      for (i = 0; i < num_actuals && ! must_preallocate; i++)	{	  if (args[i].partial > 0 && ! args[i].pass_on_stack)	    partial_seen = 1;	  else if (partial_seen && args[i].reg == 0)	    must_preallocate = 1;	  if (TYPE_MODE (TREE_TYPE (args[i].tree_value)) == BLKmode	      && (TREE_CODE (args[i].tree_value) == CALL_EXPR		  || TREE_CODE (args[i].tree_value) == TARGET_EXPR		  || TREE_CODE (args[i].tree_value) == COND_EXPR		  || TREE_ADDRESSABLE (TREE_TYPE (args[i].tree_value))))	    copy_to_evaluate_size	      += int_size_in_bytes (TREE_TYPE (args[i].tree_value));	}      if (copy_to_evaluate_size * 2 >= args_size.constant	  && args_size.constant > 0)	must_preallocate = 1;    }  /* If the structure value address will reference the stack pointer, we must     stabilize it.  We don't need to do this if we know that we are not going     to adjust the stack pointer in processing this call.  */  if (structure_value_addr      && (reg_mentioned_p (virtual_stack_dynamic_rtx, structure_value_addr)       || reg_mentioned_p (virtual_outgoing_args_rtx, structure_value_addr))      && (args_size.var#ifndef ACCUMULATE_OUTGOING_ARGS	  || args_size.constant#endif	  ))    structure_value_addr = copy_to_reg (structure_value_addr);  /* If this function call is cse'able, precompute all the parameters.     Note that if the parameter is constructed into a temporary, this will     cause an additional copy because the parameter will be constructed     into a temporary location and then copied into the outgoing arguments.     If a parameter contains a call to alloca and this function uses the     stack, precompute the parameter.  */  for (i = 0; i < num_actuals; i++)    if (is_const	|| ((args_size.var != 0 || args_size.constant != 0)	    && calls_alloca (args[i].tree_value)))      {	args[i].initial_value = args[i].value	  = expand_expr (args[i].tree_value, NULL_RTX, VOIDmode, 0);	preserve_temp_slots (args[i].value);	free_temp_slots ();	/* ANSI doesn't require a sequence point here,	   but PCC has one, so this will avoid some problems.  */	emit_queue ();      }  /* Now we are about to start emitting insns that can be deleted     if a libcall is deleted.  */  if (is_const)    start_sequence ();  /* If we have no actual push instructions, or shouldn't use them,     make space for all args right now.  */  if (args_size.var != 0)    {      if (old_stack_level == 0)	{	  emit_stack_save (SAVE_BLOCK, &old_stack_level, NULL_RTX);	  old_pending_adj = pending_stack_adjust;	  pending_stack_adjust = 0;#ifdef ACCUMULATE_OUTGOING_ARGS	  /* stack_arg_under_construction says whether a stack arg is	     being constructed at the old stack level.  Pushing the stack	     gets a clean outgoing argument block.  */	  old_stack_arg_under_construction = stack_arg_under_construction;	  stack_arg_under_construction = 0;#endif	}      argblock = push_block (ARGS_SIZE_RTX (args_size), 0, 0);    }  else if (must_preallocate)    {      /* Note that we must go through the motions of allocating an argument	 block even if the size is zero because we may be storing args	 in the area reserved for register arguments, which may be part of	 the stack frame.  */      int needed = args_size.constant;

⌨️ 快捷键说明

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