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

📄 calls.c

📁 GCC编译器源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
      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);#ifdef MAYBE_REG_PARM_STACK_SPACE      if (reg_parm_stack_space == 0)	args_size.constant = 0;#endif#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.  */  /* If we preallocated the stack space, and some arguments must be passed     on the stack, then we must precompute any parameter which contains a     function call which will store arguments on the stack.     Otherwise, evaluating the parameter may clobber previous parameters     which have already been stored into the stack.  */  for (i = 0; i < num_actuals; i++)    if (is_const	|| ((args_size.var != 0 || args_size.constant != 0)	    && calls_function (args[i].tree_value, 1))	|| (must_preallocate && (args_size.var != 0 || args_size.constant != 0)	    && calls_function (args[i].tree_value, 0)))      {	/* If this is an addressable type, we cannot pre-evaluate it.  */	if (TREE_ADDRESSABLE (TREE_TYPE (args[i].tree_value)))	  abort ();	push_temp_slots ();	args[i].initial_value = args[i].value	  = expand_expr (args[i].tree_value, NULL_RTX, VOIDmode, 0);	preserve_temp_slots (args[i].value);	pop_temp_slots ();	/* ANSI doesn't require a sequence point here,	   but PCC has one, so this will avoid some problems.  */	emit_queue ();	args[i].initial_value = args[i].value	  = protect_from_queue (args[i].initial_value, 0);	if (TYPE_MODE (TREE_TYPE (args[i].tree_value)) != args[i].mode)	  args[i].value	    = convert_modes (args[i].mode, 			     TYPE_MODE (TREE_TYPE (args[i].tree_value)),			     args[i].value, args[i].unsignedp);      }  /* 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    {      /* 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;      /* Store the maximum argument space used.  It will be pushed by	 the prologue (if ACCUMULATE_OUTGOING_ARGS, or stack overflow	 checking).  */      if (needed > current_function_outgoing_args_size)	current_function_outgoing_args_size = needed;      if (must_preallocate)	{#ifdef ACCUMULATE_OUTGOING_ARGS	  /* Since the stack pointer will never be pushed, it is possible for	     the evaluation of a parm to clobber something we have already	     written to the stack.  Since most function calls on RISC machines	     do not use the stack, this is uncommon, but must work correctly.	     Therefore, we save any area of the stack that was already written	     and that we are using.  Here we set up to do this by making a new	     stack usage map from the old one.  The actual save will be done	     by store_one_arg. 	     Another approach might be to try to reorder the argument	     evaluations to avoid this conflicting stack usage.  */#if defined(REG_PARM_STACK_SPACE) && ! defined(OUTGOING_REG_PARM_STACK_SPACE)	  /* Since we will be writing into the entire argument area, the	     map must be allocated for its entire size, not just the part that	     is the responsibility of the caller.  */	  needed += reg_parm_stack_space;#endif#ifdef ARGS_GROW_DOWNWARD	  highest_outgoing_arg_in_use = MAX (initial_highest_arg_in_use,					     needed + 1);#else	  highest_outgoing_arg_in_use = MAX (initial_highest_arg_in_use,					     needed);#endif	  stack_usage_map = (char *) alloca (highest_outgoing_arg_in_use);	  if (initial_highest_arg_in_use)	    bcopy (initial_stack_usage_map, stack_usage_map,		   initial_highest_arg_in_use);	  if (initial_highest_arg_in_use != highest_outgoing_arg_in_use)	    bzero (&stack_usage_map[initial_highest_arg_in_use],		   highest_outgoing_arg_in_use - initial_highest_arg_in_use);	  needed = 0;	  /* The address of the outgoing argument list must not be copied to a	     register here, because argblock would be left pointing to the	     wrong place after the call to allocate_dynamic_stack_space below.	     */	  argblock = virtual_outgoing_args_rtx;#else /* not ACCUMULATE_OUTGOING_ARGS */	  if (inhibit_defer_pop == 0)	    {	      /* Try to reuse some or all of the pending_stack_adjust		 to get this space.  Maybe we can avoid any pushing.  */	      if (needed > pending_stack_adjust)		{		  needed -= pending_stack_adjust;		  pending_stack_adjust = 0;		}	      else		{		  pending_stack_adjust -= needed;		  needed = 0;		}	    }	  /* Special case this because overhead of `push_block' in this	     case is non-trivial.  */	  if (needed == 0)	    argblock = virtual_outgoing_args_rtx;	  else	    argblock = push_block (GEN_INT (needed), 0, 0);	  /* We only really need to call `copy_to_reg' in the case where push	     insns are going to be used to pass ARGBLOCK to a function	     call in ARGS.  In that case, the stack pointer changes value	     from the allocation point to the call point, and hence	     the value of VIRTUAL_OUTGOING_ARGS_RTX changes as well.	     But might as well always do it.  */	  argblock = copy_to_reg (argblock);#endif /* not ACCUMULATE_OUTGOING_ARGS */	}    }#ifdef ACCUMULATE_OUTGOING_ARGS  /* The save/restore code in store_one_arg handles all cases except one:     a constructor call (including a C function returning a BLKmode struct)     to initialize an argument.  */  if (stack_arg_under_construction)    {#if defined(REG_PARM_STACK_SPACE) && ! defined(OUTGOING_REG_PARM_STACK_SPACE)      rtx push_size = GEN_INT (reg_parm_stack_space + args_size.constant);#else      rtx push_size = GEN_INT (args_size.constant);#endif      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;	  /* 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;	  /* Make a new map for the new argument list.  */	  stack_usage_map = (char *)alloca (highest_outgoing_arg_in_use);	  bzero (stack_usage_map, highest_outgoing_arg_in_use);	  highest_outgoing_arg_in_use = 0;	}      allocate_dynamic_stack_space (push_size, NULL_RTX, BITS_PER_UNIT);    }  /* If argument evaluation might modify the stack pointer, copy the     address of the argument list to a register.  */  for (i = 0; i < num_actuals; i++)    if (args[i].pass_on_stack)      {	argblock = copy_addr_to_reg (argblock);	break;      }#endif  /* If we preallocated stack space, compute the address of each argument.     We need not ensure it is a valid memory address here; it will be      validized when it is used.  */  if (argblock)    {      rtx arg_reg = argblock;      int arg_offset = 0;      if (GET_CODE (argblock) == PLUS)	arg_reg = XEXP (argblock, 0), arg_offset = INTVAL (XEXP (argblock, 1));      for (i = 0; i < num_actuals; i++)	{	  rtx offset = ARGS_SIZE_RTX (args[i].offset);	  rtx slot_offset = ARGS_SIZE_RTX (args[i].slot_offset);	  rtx addr;	  /* Skip this parm if it will not be passed on the stack.  */	  if (! args[i].pass_on_stack && args[i].reg != 0)	    continue;	  if (GET_CODE (offset) == CONST_INT)	    addr = plus_constant (arg_reg, INTVAL (offset));	  else	    addr = gen_rtx (PLUS, Pmode, arg_reg, offset);	  addr = plus_constant (addr, arg_offset);	  args[i].stack = gen_rtx (MEM, args[i].mode, addr);	  MEM_IN_STRUCT_P (args[i].stack)	    = AGGREGATE_TYPE_P (TREE_TYPE (args[i].tree_value));	  if (GET_CODE (slot_offset) == CONST_INT)	    addr = plus_constant (arg_reg, INTVAL (slot_offset));	  else

⌨️ 快捷键说明

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