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

📄 calls.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 5 页
字号:
	  end_sequence ();	  /* PARTIAL referred only to the first register, so clear it for the	     next time.  */	  partial = 0;	}    }  /* Perform postincrements before actually calling the function.  */  emit_queue ();  /* All arguments and registers used for the call must be set up by now!  */  funexp = prepare_call_address (funexp, fndecl, &use_insns);  /* Generate the actual call instruction.  */  emit_call_1 (funexp, funtype, args_size.constant, struct_value_size,	       FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1),	       valreg, old_inhibit_defer_pop, use_insns, is_const);  /* If call is cse'able, make appropriate pair of reg-notes around it.     Test valreg so we don't crash; may safely ignore `const'     if return type is void.  */  if (is_const && valreg != 0)    {      rtx note = 0;      rtx temp = gen_reg_rtx (GET_MODE (valreg));      rtx insns;      /* Construct an "equal form" for the value which mentions all the	 arguments in order as well as the function name.  */#ifdef PUSH_ARGS_REVERSED      for (i = 0; i < num_actuals; i++)	note = gen_rtx (EXPR_LIST, VOIDmode, args[i].initial_value, note);#else      for (i = num_actuals - 1; i >= 0; i--)	note = gen_rtx (EXPR_LIST, VOIDmode, args[i].initial_value, note);#endif      note = gen_rtx (EXPR_LIST, VOIDmode, funexp, note);      insns = get_insns ();      end_sequence ();      emit_libcall_block (insns, temp, valreg, note);      valreg = temp;    }  /* For calls to `setjmp', etc., inform flow.c it should complain     if nonvolatile values are live.  */  if (returns_twice)    {      emit_note (name, NOTE_INSN_SETJMP);      current_function_calls_setjmp = 1;    }  if (is_longjmp)    current_function_calls_longjmp = 1;  /* Notice functions that cannot return.     If optimizing, insns emitted below will be dead.     If not optimizing, they will exist, which is useful     if the user uses the `return' command in the debugger.  */  if (is_volatile || is_longjmp)    emit_barrier ();  /* If value type not void, return an rtx for the value.  */  /* If there are cleanups to be called, don't use a hard reg as target.  */  if (cleanups_this_call != old_cleanups      && target && REG_P (target)      && REGNO (target) < FIRST_PSEUDO_REGISTER)    target = 0;  if (TYPE_MODE (TREE_TYPE (exp)) == VOIDmode      || ignore)    {      target = const0_rtx;    }  else if (structure_value_addr)    {      if (target == 0 || GET_CODE (target) != MEM)	{	  target = gen_rtx (MEM, TYPE_MODE (TREE_TYPE (exp)),			    memory_address (TYPE_MODE (TREE_TYPE (exp)),					    structure_value_addr));	  MEM_IN_STRUCT_P (target)	    = (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE	       || TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE	       || TREE_CODE (TREE_TYPE (exp)) == UNION_TYPE);	}    }  else if (pcc_struct_value)    {      if (target == 0)	{	  target = gen_rtx (MEM, TYPE_MODE (TREE_TYPE (exp)),			    copy_to_reg (valreg));	  MEM_IN_STRUCT_P (target)	    = (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE	       || TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE	       || TREE_CODE (TREE_TYPE (exp)) == UNION_TYPE);	}      else if (TYPE_MODE (TREE_TYPE (exp)) != BLKmode)	emit_move_insn (target, gen_rtx (MEM, TYPE_MODE (TREE_TYPE (exp)),					 copy_to_reg (valreg)));      else	emit_block_move (target, gen_rtx (MEM, BLKmode, copy_to_reg (valreg)),			 expr_size (exp),			 TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT);    }  else if (target && GET_MODE (target) == TYPE_MODE (TREE_TYPE (exp))	   && GET_MODE (target) == GET_MODE (valreg))    /* TARGET and VALREG cannot be equal at this point because the latter       would not have REG_FUNCTION_VALUE_P true, while the former would if       it were referring to the same register.       If they refer to the same register, this move will be a no-op, except       when function inlining is being done.  */    emit_move_insn (target, valreg);  else    target = copy_to_reg (valreg);#ifdef PROMOTE_FUNCTION_RETURN  /* If we promoted this return value, make the proper SUBREG.  */  if (GET_MODE (target) != TYPE_MODE (TREE_TYPE (exp)))    {      enum machine_mode mode = GET_MODE (target);      int unsignedp = TREE_UNSIGNED (TREE_TYPE (exp));      if (TREE_CODE (TREE_TYPE (exp)) == INTEGER_TYPE	  || TREE_CODE (TREE_TYPE (exp)) == ENUMERAL_TYPE	  || TREE_CODE (TREE_TYPE (exp)) == BOOLEAN_TYPE	  || TREE_CODE (TREE_TYPE (exp)) == CHAR_TYPE	  || TREE_CODE (TREE_TYPE (exp)) == REAL_TYPE	  || TREE_CODE (TREE_TYPE (exp)) == POINTER_TYPE	  || TREE_CODE (TREE_TYPE (exp)) == OFFSET_TYPE)	{	  PROMOTE_MODE (mode, unsignedp, TREE_TYPE (exp));	}      target = gen_rtx (SUBREG, TYPE_MODE (TREE_TYPE (exp)), target, 0);      SUBREG_PROMOTED_VAR_P (target) = 1;      SUBREG_PROMOTED_UNSIGNED_P (target) = unsignedp;    }#endif  /* Perform all cleanups needed for the arguments of this call     (i.e. destructors in C++).  */  expand_cleanups_to (old_cleanups);  /* If size of args is variable or this was a constructor call for a stack     argument, restore saved stack-pointer value.  */  if (old_stack_level)    {      emit_stack_restore (SAVE_BLOCK, old_stack_level, NULL_RTX);      pending_stack_adjust = old_pending_adj;#ifdef ACCUMULATE_OUTGOING_ARGS      stack_arg_under_construction = old_stack_arg_under_construction;      highest_outgoing_arg_in_use = initial_highest_arg_in_use;      stack_usage_map = initial_stack_usage_map;#endif    }#ifdef ACCUMULATE_OUTGOING_ARGS  else    {#ifdef REG_PARM_STACK_SPACE      if (save_area)	{	  enum machine_mode save_mode = GET_MODE (save_area);	  rtx stack_area	    = gen_rtx (MEM, save_mode,		       memory_address (save_mode,#ifdef ARGS_GROW_DOWNWARD				       plus_constant (argblock, - high_to_save)#else				       plus_constant (argblock, low_to_save)#endif				       ));	  if (save_mode != BLKmode)	    emit_move_insn (stack_area, save_area);	  else	    emit_block_move (stack_area, validize_mem (save_area),			     GEN_INT (high_to_save - low_to_save + 1),			     PARM_BOUNDARY / BITS_PER_UNIT);	}#endif	        /* If we saved any argument areas, restore them.  */      for (i = 0; i < num_actuals; i++)	if (args[i].save_area)	  {	    enum machine_mode save_mode = GET_MODE (args[i].save_area);	    rtx stack_area	      = gen_rtx (MEM, save_mode,			 memory_address (save_mode,					 XEXP (args[i].stack_slot, 0)));	    if (save_mode != BLKmode)	      emit_move_insn (stack_area, args[i].save_area);	    else	      emit_block_move (stack_area, validize_mem (args[i].save_area),			       GEN_INT (args[i].size.constant),			       PARM_BOUNDARY / BITS_PER_UNIT);	  }      highest_outgoing_arg_in_use = initial_highest_arg_in_use;      stack_usage_map = initial_stack_usage_map;    }#endif  /* If this was alloca, record the new stack level for nonlocal gotos.       Check for the handler slots since we might not have a save area     for non-local gotos. */  if (may_be_alloca && nonlocal_goto_handler_slot != 0)    emit_stack_save (SAVE_NONLOCAL, &nonlocal_goto_stack_level, NULL_RTX);  pop_temp_slots ();  return target;}#if 0/* Return an rtx which represents a suitable home on the stack   given TYPE, the type of the argument looking for a home.   This is called only for BLKmode arguments.   SIZE is the size needed for this target.   ARGS_ADDR is the address of the bottom of the argument block for this call.   OFFSET describes this parameter's offset into ARGS_ADDR.  It is meaningless   if this machine uses push insns.  */static rtxtarget_for_arg (type, size, args_addr, offset)     tree type;     rtx size;     rtx args_addr;     struct args_size offset;{  rtx target;  rtx offset_rtx = ARGS_SIZE_RTX (offset);  /* We do not call memory_address if possible,     because we want to address as close to the stack     as possible.  For non-variable sized arguments,     this will be stack-pointer relative addressing.  */  if (GET_CODE (offset_rtx) == CONST_INT)    target = plus_constant (args_addr, INTVAL (offset_rtx));  else    {      /* I have no idea how to guarantee that this	 will work in the presence of register parameters.  */      target = gen_rtx (PLUS, Pmode, args_addr, offset_rtx);      target = memory_address (QImode, target);    }  return gen_rtx (MEM, BLKmode, target);}#endif/* Store a single argument for a function call   into the register or memory area where it must be passed.   *ARG describes the argument value and where to pass it.   ARGBLOCK is the address of the stack-block for all the arguments,   or 0 on a machine where arguments are pushed individually.   MAY_BE_ALLOCA nonzero says this could be a call to `alloca'   so must be careful about how the stack is used.    VARIABLE_SIZE nonzero says that this was a variable-sized outgoing   argument stack.  This is used if ACCUMULATE_OUTGOING_ARGS to indicate   that we need not worry about saving and restoring the stack.   FNDECL is the declaration of the function we are calling.  */static voidstore_one_arg (arg, argblock, may_be_alloca, variable_size, fndecl,	       reg_parm_stack_space)     struct arg_data *arg;     rtx argblock;     int may_be_alloca;     int variable_size;     tree fndecl;     int reg_parm_stack_space;{  register tree pval = arg->tree_value;  rtx reg = 0;  int partial = 0;  int used = 0;  int i, lower_bound, upper_bound;  if (TREE_CODE (pval) == ERROR_MARK)    return;#ifdef ACCUMULATE_OUTGOING_ARGS  /* If this is being stored into a pre-allocated, fixed-size, stack area,     save any previous data at that location.  */  if (argblock && ! variable_size && arg->stack)    {#ifdef ARGS_GROW_DOWNWARD      /* stack_slot is negative, but we want to index stack_usage_map */      /* with positive values. */      if (GET_CODE (XEXP (arg->stack_slot, 0)) == PLUS)	upper_bound = -INTVAL (XEXP (XEXP (arg->stack_slot, 0), 1)) + 1;      else	abort ();      lower_bound = upper_bound - arg->size.constant;#else      if (GET_CODE (XEXP (arg->stack_slot, 0)) == PLUS)	lower_bound = INTVAL (XEXP (XEXP (arg->stack_slot, 0), 1));      else	lower_bound = 0;      upper_bound = lower_bound + arg->size.constant;#endif      for (i = lower_bound; i < upper_bound; i++)	if (stack_usage_map[i]#ifdef REG_PARM_STACK_SPACE	    /* Don't store things in the fixed argument area at this point;	       it has already been saved.  */	    && i > reg_parm_stack_space#endif	    )	  break;      if (i != upper_bound)	{	  /* We need to make a save area.  See what mode we can make it.  */	  enum machine_mode save_mode	    = mode_for_size (arg->size.constant * BITS_PER_UNIT, MODE_INT, 1);	  rtx stack_area	    = gen_rtx (MEM, save_mode,		       memory_address (save_mode, XEXP (arg->stack_slot, 0)));	  if (save_mode == BLKmode)	    {	      arg->save_area = assign_stack_temp (BLKmode,						  arg->size.constant, 1);	      emit_block_move (validize_mem (arg->save_area), stack_area,			       GEN_INT (arg->size.constant),			       PARM_BOUNDARY / BITS_PER_UNIT);	    }	  else	    {	      arg->save_area = gen_reg_rtx (save_mode);	      emit_move_insn (arg->save_area, stack_area);	    }	}    }#endif  /* If this isn't going to be placed on both the stack and in registers,     set up the register and number of words.  */  if (! arg->pass_on_stack)    reg = arg->reg, partial = arg->partial;  if (reg != 0 && partial == 0)    /* Being passed entirely in a register.  We shouldn't be called in       this case.   */    abort ();  /* If this is being partially passed in a register, but multiple locations     are specified, we assume that the one partially used is the one that is     listed first.  */  if (reg && GET_CODE (reg) == EXPR_LIST)    reg = XEXP (reg, 0);  /* If this is being passes partially in a register, we can't evaluate     it directly into its stack slot.  Otherwise, we can.  */  if (arg->value == 0)    {#ifdef ACCUMULATE_OUTGOING_ARGS      /* stack_arg_under_construction is nonzero if a function argument is	 being evaluated directly into the outgoing argument list and	 expand_call must take special action to preserve the argument list	 if it is called recursively.	 For scalar function arguments stack_usage_map is sufficient to	 determine which stack slots must be saved and restored.  Scalar	 arguments in general have pass_on_stack == 0.	 If this argument is initialized by a function which takes the	 address of the argument (a C++ constructor or a C function	 returning a BLKmode structure), then stack_usage_map is	 insufficient and expand_call must push the stack around the	 function call.  Such arguments have pass_on_stack == 1.	 Note that it is always sa

⌨️ 快捷键说明

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