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

📄 calls.c

📁 GCC编译器源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	    addr = gen_rtx (PLUS, Pmode, arg_reg, slot_offset);	  addr = plus_constant (addr, arg_offset);	  args[i].stack_slot = gen_rtx (MEM, args[i].mode, addr);	}    }					       #ifdef PUSH_ARGS_REVERSED#ifdef STACK_BOUNDARY  /* If we push args individually in reverse order, perform stack alignment     before the first push (the last arg).  */  if (argblock == 0)    anti_adjust_stack (GEN_INT (args_size.constant				- original_args_size.constant));#endif#endif  /* Don't try to defer pops if preallocating, not even from the first arg,     since ARGBLOCK probably refers to the SP.  */  if (argblock)    NO_DEFER_POP;  /* Get the function to call, in the form of RTL.  */  if (fndecl)    {      /* If this is the first use of the function, see if we need to	 make an external definition for it.  */      if (! TREE_USED (fndecl))	{	  assemble_external (fndecl);	  TREE_USED (fndecl) = 1;	}      /* Get a SYMBOL_REF rtx for the function address.  */      funexp = XEXP (DECL_RTL (fndecl), 0);    }  else    /* Generate an rtx (probably a pseudo-register) for the address.  */    {      push_temp_slots ();      funexp = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0);      pop_temp_slots ();	/* FUNEXP can't be BLKmode */      /* Check the function is executable.  */      if (flag_check_memory_usage)	emit_library_call (chkr_check_exec_libfunc, 1,			   VOIDmode, 1,			   funexp, ptr_mode);      emit_queue ();    }  /* Figure out the register where the value, if any, will come back.  */  valreg = 0;  if (TYPE_MODE (TREE_TYPE (exp)) != VOIDmode      && ! structure_value_addr)    {      if (pcc_struct_value)	valreg = hard_function_value (build_pointer_type (TREE_TYPE (exp)),				      fndecl);      else	valreg = hard_function_value (TREE_TYPE (exp), fndecl);    }  /* Precompute all register parameters.  It isn't safe to compute anything     once we have started filling any specific hard regs.  */  reg_parm_seen = 0;  for (i = 0; i < num_actuals; i++)    if (args[i].reg != 0 && ! args[i].pass_on_stack)      {	reg_parm_seen = 1;	if (args[i].value == 0)	  {	    push_temp_slots ();	    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 ();	  }	/* If we are to promote the function arg to a wider mode,	   do it now.  */	if (args[i].mode != TYPE_MODE (TREE_TYPE (args[i].tree_value)))	  args[i].value	    = convert_modes (args[i].mode,			     TYPE_MODE (TREE_TYPE (args[i].tree_value)),			     args[i].value, args[i].unsignedp);	/* If the value is expensive, and we are inside an appropriately 	   short loop, put the value into a pseudo and then put the pseudo	   into the hard reg.	   For small register classes, also do this if this call uses	   register parameters.  This is to avoid reload conflicts while	   loading the parameters registers.  */	if ((! (GET_CODE (args[i].value) == REG		|| (GET_CODE (args[i].value) == SUBREG		    && GET_CODE (SUBREG_REG (args[i].value)) == REG)))	    && args[i].mode != BLKmode	    && rtx_cost (args[i].value, SET) > 2	    && ((SMALL_REGISTER_CLASSES && reg_parm_seen)		|| preserve_subexpressions_p ()))	  args[i].value = copy_to_mode_reg (args[i].mode, args[i].value);      }#if defined(ACCUMULATE_OUTGOING_ARGS) && defined(REG_PARM_STACK_SPACE)  /* The argument list is the property of the called routine and it     may clobber it.  If the fixed area has been used for previous     parameters, we must save and restore it.     Here we compute the boundary of the that needs to be saved, if any.  */#ifdef ARGS_GROW_DOWNWARD  for (i = 0; i < reg_parm_stack_space + 1; i++)#else  for (i = 0; i < reg_parm_stack_space; i++)#endif    {      if (i >=  highest_outgoing_arg_in_use	  || stack_usage_map[i] == 0)	continue;      if (low_to_save == -1)	low_to_save = i;      high_to_save = i;    }  if (low_to_save >= 0)    {      int num_to_save = high_to_save - low_to_save + 1;      enum machine_mode save_mode	= mode_for_size (num_to_save * BITS_PER_UNIT, MODE_INT, 1);      rtx stack_area;      /* If we don't have the required alignment, must do this in BLKmode.  */      if ((low_to_save & (MIN (GET_MODE_SIZE (save_mode),			       BIGGEST_ALIGNMENT / UNITS_PER_WORD) - 1)))	save_mode = BLKmode;      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)	{	  save_area = assign_stack_temp (BLKmode, num_to_save, 0);	  MEM_IN_STRUCT_P (save_area) = 0;	  emit_block_move (validize_mem (save_area), stack_area,			   GEN_INT (num_to_save),			   PARM_BOUNDARY / BITS_PER_UNIT);	}      else	{	  save_area = gen_reg_rtx (save_mode);	  emit_move_insn (save_area, stack_area);	}    }#endif	    /* Now store (and compute if necessary) all non-register parms.     These come before register parms, since they can require block-moves,     which could clobber the registers used for register parms.     Parms which have partial registers are not stored here,     but we do preallocate space here if they want that.  */  for (i = 0; i < num_actuals; i++)    if (args[i].reg == 0 || args[i].pass_on_stack)      store_one_arg (&args[i], argblock, may_be_alloca,		     args_size.var != 0, fndecl, reg_parm_stack_space);  /* If we have a parm that is passed in registers but not in memory     and whose alignment does not permit a direct copy into registers,     make a group of pseudos that correspond to each register that we     will later fill.  */  if (STRICT_ALIGNMENT)    for (i = 0; i < num_actuals; i++)      if (args[i].reg != 0 && ! args[i].pass_on_stack	&& args[i].mode == BLKmode	  && (TYPE_ALIGN (TREE_TYPE (args[i].tree_value))	      < MIN (BIGGEST_ALIGNMENT, BITS_PER_WORD)))	{	  int bytes = int_size_in_bytes (TREE_TYPE (args[i].tree_value));	  int big_endian_correction = 0;	  args[i].n_aligned_regs	    = args[i].partial ? args[i].partial	      : (bytes + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD;	  args[i].aligned_regs = (rtx *) alloca (sizeof (rtx)						 * args[i].n_aligned_regs);	  /* Structures smaller than a word are aligned to the least	     significant byte (to the right).  On a BYTES_BIG_ENDIAN machine,	     this means we must skip the empty high order bytes when	     calculating the bit offset.  */	  if (BYTES_BIG_ENDIAN && bytes < UNITS_PER_WORD)	    big_endian_correction = (BITS_PER_WORD  - (bytes * BITS_PER_UNIT));	  for (j = 0; j < args[i].n_aligned_regs; j++)	    {	      rtx reg = gen_reg_rtx (word_mode);	      rtx word = operand_subword_force (args[i].value, j, BLKmode);	      int bitsize = TYPE_ALIGN (TREE_TYPE (args[i].tree_value));	      int bitpos;	      args[i].aligned_regs[j] = reg;	      /* Clobber REG and move each partword into it.  Ensure we don't		 go past the end of the structure.  Note that the loop below		 works because we've already verified that padding		 and endianness are compatible.		 We use to emit a clobber here but that doesn't let later		 passes optimize the instructions we emit.  By storing 0 into		 the register later passes know the first AND to zero out the		 bitfield being set in the register is unnecessary.  The store		 of 0 will be deleted as will at least the first AND.  */	      emit_move_insn (reg, const0_rtx);	      for (bitpos = 0;		   bitpos < BITS_PER_WORD && bytes > 0;		   bitpos += bitsize, bytes -= bitsize / BITS_PER_UNIT)		{		  int xbitpos = bitpos + big_endian_correction;		  store_bit_field (reg, bitsize, xbitpos, word_mode,				   extract_bit_field (word, bitsize, bitpos, 1,						      NULL_RTX, word_mode,						      word_mode,						      bitsize / BITS_PER_UNIT,						      BITS_PER_WORD),				   bitsize / BITS_PER_UNIT, BITS_PER_WORD);		}	    }	}  /* Now store any partially-in-registers parm.     This is the last place a block-move can happen.  */  if (reg_parm_seen)    for (i = 0; i < num_actuals; i++)      if (args[i].partial != 0 && ! args[i].pass_on_stack)	store_one_arg (&args[i], argblock, may_be_alloca,		       args_size.var != 0, fndecl, reg_parm_stack_space);#ifndef PUSH_ARGS_REVERSED#ifdef STACK_BOUNDARY  /* If we pushed args in forward order, perform stack alignment     after pushing the last arg.  */  if (argblock == 0)    anti_adjust_stack (GEN_INT (args_size.constant				- original_args_size.constant));#endif#endif  /* If register arguments require space on the stack and stack space     was not preallocated, allocate stack space here for arguments     passed in registers.  */#if ! defined(ACCUMULATE_OUTGOING_ARGS) && defined(OUTGOING_REG_PARM_STACK_SPACE)  if (must_preallocate == 0 && reg_parm_stack_space > 0)    anti_adjust_stack (GEN_INT (reg_parm_stack_space));#endif  /* Pass the function the address in which to return a structure value.  */  if (structure_value_addr && ! structure_value_addr_parm)    {      emit_move_insn (struct_value_rtx,		      force_reg (Pmode,				 force_operand (structure_value_addr,						NULL_RTX)));      /* Mark the memory for the aggregate as write-only.  */      if (flag_check_memory_usage)	emit_library_call (chkr_set_right_libfunc, 1,			   VOIDmode, 3,			   structure_value_addr, ptr_mode, 			   GEN_INT (struct_value_size), TYPE_MODE (sizetype),			   GEN_INT (MEMORY_USE_WO),			   TYPE_MODE (integer_type_node));      if (GET_CODE (struct_value_rtx) == REG)	  use_reg (&call_fusage, struct_value_rtx);    }  funexp = prepare_call_address (funexp, fndecl, &call_fusage, reg_parm_seen);  /* Now do the register loads required for any wholly-register parms or any     parms which are passed both on the stack and in a register.  Their     expressions were already evaluated.      Mark all register-parms as living through the call, putting these USE     insns in the CALL_INSN_FUNCTION_USAGE field.  */  for (i = 0; i < num_actuals; i++)    {      rtx reg = args[i].reg;      int partial = args[i].partial;      int nregs;      if (reg)	{	  /* Set to non-negative if must move a word at a time, even if just	     one word (e.g, partial == 1 && mode == DFmode).  Set to -1 if	     we just use a normal move insn.  This value can be zero if the	     argument is a zero size structure with no fields.  */	  nregs = (partial ? partial		   : (TYPE_MODE (TREE_TYPE (args[i].tree_value)) == BLKmode		      ? ((int_size_in_bytes (TREE_TYPE (args[i].tree_value))			  + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)		      : -1));	  /* Handle calls that pass values in multiple non-contiguous	     locations.  The Irix 6 ABI has examples of this.  */	  if (GET_CODE (reg) == PARALLEL)	    emit_group_load (reg, args[i].value);	  /* If simple case, just do move.  If normal partial, store_one_arg	     has already loaded the register for us.  In all other cases,	     load the register(s) from memory.  */	  else if (nregs == -1)	    emit_move_insn (reg, args[i].value);	  /* If we have pre-computed the values to put in the registers in	     the case of non-aligned structures, copy them in now.  */	  else if (args[i].n_aligned_regs != 0)	    for (j = 0; j < args[i].n_aligned_regs; j++)	      emit_move_insn (gen_rtx (REG, word_mode, REGNO (reg) + j),			      args[i].aligned_regs[j]);	  else if (partial == 0 || args[i].pass_on_stack)	    move_block_to_reg (REGNO (reg),			       validize_mem (args[i].value), nregs,			       args[i].mode);	  /* Handle calls that pass values in multiple non-contiguous	     locations.  The Irix 6 ABI has examples of this.  */	  if (GET_CODE (reg) == PARALLEL)	    use_group_regs (&call_fusage, reg);	  else if (nregs == -1)	    use_reg (&call_fusage, reg);	  else	    use_regs (&call_fusage, REGNO (reg), nregs == 0 ? 1 : nregs);	}    }  /* Perform postincrements before actually calling the function.  */  emit_queue ();  /* All arguments and registers used for the call must be set up by now!  */  /* Generate the actual call instruction.  */  emit_call_1 (funexp, fndecl, funtype, args_size.constant, struct_value_size,	       FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1),	       valreg, old_inhibit_defer_pop, call_fusage, 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.  Disable for PARALLEL return values, because     we have no way to move such values into a pseudo register.  */  if (is_const && valreg != 0 && GET_CODE (valreg) != PARALLEL)    {      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].in

⌨️ 快捷键说明

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