integrate.c

来自「GCC编译器源代码」· C语言 代码 · 共 1,907 行 · 第 1/5 页

C
1,907
字号
	  XEXP (x, 0) = XEXP (x, 1);	  XEXP (x, 1) = t;	}      break;#endif    default:      break;    }  /* Replace this rtx with a copy of itself.  */  x = rtx_alloc (code);  bcopy ((char *) orig, (char *) x,	 (sizeof (*x) - sizeof (x->fld)	  + sizeof (x->fld[0]) * GET_RTX_LENGTH (code)));  /* Now scan the subexpressions recursively.     We can store any replaced subexpressions directly into X     since we know X is not shared!  Any vectors in X     must be copied if X was copied.  */  format_ptr = GET_RTX_FORMAT (code);  for (i = 0; i < GET_RTX_LENGTH (code); i++)    {      switch (*format_ptr++)	{	case 'e':	  XEXP (x, i) = copy_for_inline (XEXP (x, i));	  break;	case 'u':	  /* Change any references to old-insns to point to the	     corresponding copied insns.  */	  XEXP (x, i) = insn_map[INSN_UID (XEXP (x, i))];	  break;	case 'E':	  if (XVEC (x, i) != NULL && XVECLEN (x, i) != 0)	    {	      register int j;	      XVEC (x, i) = gen_rtvec_vv (XVECLEN (x, i), XVEC (x, i)->elem);	      for (j = 0; j < XVECLEN (x, i); j++)		XVECEXP (x, i, j)		  = copy_for_inline (XVECEXP (x, i, j));	    }	  break;	}    }  if (code == ASM_OPERANDS && orig_asm_operands_vector == 0)    {      orig_asm_operands_vector = XVEC (orig, 3);      copy_asm_operands_vector = XVEC (x, 3);      copy_asm_constraints_vector = XVEC (x, 4);    }  return x;}/* Unfortunately, we need a global copy of const_equiv map for communication   with a function called from note_stores.  Be *very* careful that this   is used properly in the presence of recursion.  */rtx *global_const_equiv_map;int global_const_equiv_map_size;#define FIXED_BASE_PLUS_P(X) \  (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == CONST_INT	\   && GET_CODE (XEXP (X, 0)) == REG				\   && REGNO (XEXP (X, 0)) >= FIRST_VIRTUAL_REGISTER		\   && REGNO (XEXP (X, 0)) <= LAST_VIRTUAL_REGISTER)/* Integrate the procedure defined by FNDECL.  Note that this function   may wind up calling itself.  Since the static variables are not   reentrant, we do not assign them until after the possibility   of recursion is eliminated.   If IGNORE is nonzero, do not produce a value.   Otherwise store the value in TARGET if it is nonzero and that is convenient.   Value is:   (rtx)-1 if we could not substitute the function   0 if we substituted it and it does not produce a value   else an rtx for where the value is stored.  */rtxexpand_inline_function (fndecl, parms, target, ignore, type,			structure_value_addr)     tree fndecl, parms;     rtx target;     int ignore;     tree type;     rtx structure_value_addr;{  tree formal, actual, block;  rtx header = DECL_SAVED_INSNS (fndecl);  rtx insns = FIRST_FUNCTION_INSN (header);  rtx parm_insns = FIRST_PARM_INSN (header);  tree *arg_trees;  rtx *arg_vals;  rtx insn;  int max_regno;  register int i;  int min_labelno = FIRST_LABELNO (header);  int max_labelno = LAST_LABELNO (header);  int nargs;  rtx local_return_label = 0;  rtx loc;  rtx stack_save = 0;  rtx temp;  struct inline_remap *map;  rtx cc0_insn = 0;  rtvec arg_vector = ORIGINAL_ARG_VECTOR (header);  rtx static_chain_value = 0;  /* The pointer used to track the true location of the memory used     for MAP->LABEL_MAP.  */  rtx *real_label_map = 0;  /* Allow for equivalences of the pseudos we make for virtual fp and ap.  */  max_regno = MAX_REGNUM (header) + 3;  if (max_regno < FIRST_PSEUDO_REGISTER)    abort ();  nargs = list_length (DECL_ARGUMENTS (fndecl));  /* Check that the parms type match and that sufficient arguments were     passed.  Since the appropriate conversions or default promotions have     already been applied, the machine modes should match exactly.  */  for (formal = DECL_ARGUMENTS (fndecl), actual = parms;       formal;       formal = TREE_CHAIN (formal), actual = TREE_CHAIN (actual))    {      tree arg;      enum machine_mode mode;      if (actual == 0)	return (rtx) (HOST_WIDE_INT) -1;      arg = TREE_VALUE (actual);      mode = TYPE_MODE (DECL_ARG_TYPE (formal));      if (mode != TYPE_MODE (TREE_TYPE (arg))	  /* If they are block mode, the types should match exactly.	     They don't match exactly if TREE_TYPE (FORMAL) == ERROR_MARK_NODE,	     which could happen if the parameter has incomplete type.  */	  || (mode == BLKmode	      && (TYPE_MAIN_VARIANT (TREE_TYPE (arg))		  != TYPE_MAIN_VARIANT (TREE_TYPE (formal)))))	return (rtx) (HOST_WIDE_INT) -1;    }  /* Extra arguments are valid, but will be ignored below, so we must     evaluate them here for side-effects.  */  for (; actual; actual = TREE_CHAIN (actual))    expand_expr (TREE_VALUE (actual), const0_rtx,		 TYPE_MODE (TREE_TYPE (TREE_VALUE (actual))), 0);  /* Make a binding contour to keep inline cleanups called at     outer function-scope level from looking like they are shadowing     parameter declarations.  */  pushlevel (0);  /* Expand the function arguments.  Do this first so that any     new registers get created before we allocate the maps.  */  arg_vals = (rtx *) alloca (nargs * sizeof (rtx));  arg_trees = (tree *) alloca (nargs * sizeof (tree));  for (formal = DECL_ARGUMENTS (fndecl), actual = parms, i = 0;       formal;       formal = TREE_CHAIN (formal), actual = TREE_CHAIN (actual), i++)    {      /* Actual parameter, converted to the type of the argument within the	 function.  */      tree arg = convert (TREE_TYPE (formal), TREE_VALUE (actual));      /* Mode of the variable used within the function.  */      enum machine_mode mode = TYPE_MODE (TREE_TYPE (formal));      int invisiref = 0;      arg_trees[i] = arg;      loc = RTVEC_ELT (arg_vector, i);      /* If this is an object passed by invisible reference, we copy the	 object into a stack slot and save its address.  If this will go	 into memory, we do nothing now.  Otherwise, we just expand the	 argument.  */      if (GET_CODE (loc) == MEM && GET_CODE (XEXP (loc, 0)) == REG	  && REGNO (XEXP (loc, 0)) > LAST_VIRTUAL_REGISTER)	{	  rtx stack_slot	    = assign_stack_temp (TYPE_MODE (TREE_TYPE (arg)),				 int_size_in_bytes (TREE_TYPE (arg)), 1);	  MEM_IN_STRUCT_P (stack_slot) = AGGREGATE_TYPE_P (TREE_TYPE (arg));	  store_expr (arg, stack_slot, 0);	  arg_vals[i] = XEXP (stack_slot, 0);	  invisiref = 1;	}      else if (GET_CODE (loc) != MEM)	{	  if (GET_MODE (loc) != TYPE_MODE (TREE_TYPE (arg)))	    /* The mode if LOC and ARG can differ if LOC was a variable	       that had its mode promoted via PROMOTED_MODE.  */	    arg_vals[i] = convert_modes (GET_MODE (loc),					 TYPE_MODE (TREE_TYPE (arg)),					 expand_expr (arg, NULL_RTX, mode,						      EXPAND_SUM),					 TREE_UNSIGNED (TREE_TYPE (formal)));	  else	    arg_vals[i] = expand_expr (arg, NULL_RTX, mode, EXPAND_SUM);	}      else	arg_vals[i] = 0;      if (arg_vals[i] != 0	  && (! TREE_READONLY (formal)	      /* If the parameter is not read-only, copy our argument through		 a register.  Also, we cannot use ARG_VALS[I] if it overlaps		 TARGET in any way.  In the inline function, they will likely		 be two different pseudos, and `safe_from_p' will make all		 sorts of smart assumptions about their not conflicting.		 But if ARG_VALS[I] overlaps TARGET, these assumptions are		 wrong, so put ARG_VALS[I] into a fresh register.		 Don't worry about invisible references, since their stack		 temps will never overlap the target.  */	      || (target != 0		  && ! invisiref		  && (GET_CODE (arg_vals[i]) == REG		      || GET_CODE (arg_vals[i]) == SUBREG		      || GET_CODE (arg_vals[i]) == MEM)		  && reg_overlap_mentioned_p (arg_vals[i], target))	      /* ??? We must always copy a SUBREG into a REG, because it might		 get substituted into an address, and not all ports correctly		 handle SUBREGs in addresses.  */	      || (GET_CODE (arg_vals[i]) == SUBREG)))	arg_vals[i] = copy_to_mode_reg (GET_MODE (loc), arg_vals[i]);      if (arg_vals[i] != 0 && GET_CODE (arg_vals[i]) == REG	  && TREE_CODE (TREE_TYPE (formal)) == POINTER_TYPE)	mark_reg_pointer (arg_vals[i],			  (TYPE_ALIGN (TREE_TYPE (TREE_TYPE (formal)))			   / BITS_PER_UNIT));    }	  /* Allocate the structures we use to remap things.  */  map = (struct inline_remap *) alloca (sizeof (struct inline_remap));  map->fndecl = fndecl;  map->reg_map = (rtx *) alloca (max_regno * sizeof (rtx));  bzero ((char *) map->reg_map, max_regno * sizeof (rtx));  /* We used to use alloca here, but the size of what it would try to     allocate would occasionally cause it to exceed the stack limit and     cause unpredictable core dumps.  */  real_label_map    = (rtx *) xmalloc ((max_labelno) * sizeof (rtx));  map->label_map = real_label_map;  map->insn_map = (rtx *) alloca (INSN_UID (header) * sizeof (rtx));  bzero ((char *) map->insn_map, INSN_UID (header) * sizeof (rtx));  map->min_insnno = 0;  map->max_insnno = INSN_UID (header);  map->integrating = 1;  /* const_equiv_map maps pseudos in our routine to constants, so it needs to     be large enough for all our pseudos.  This is the number we are currently     using plus the number in the called routine, plus 15 for each arg,     five to compute the virtual frame pointer, and five for the return value.     This should be enough for most cases.  We do not reference entries     outside the range of the map.     ??? These numbers are quite arbitrary and were obtained by     experimentation.  At some point, we should try to allocate the     table after all the parameters are set up so we an more accurately     estimate the number of pseudos we will need.  */  map->const_equiv_map_size    = max_reg_num () + (max_regno - FIRST_PSEUDO_REGISTER) + 15 * nargs + 10;  map->const_equiv_map    = (rtx *)alloca (map->const_equiv_map_size * sizeof (rtx));  bzero ((char *) map->const_equiv_map,	 map->const_equiv_map_size * sizeof (rtx));  map->const_age_map    = (unsigned *)alloca (map->const_equiv_map_size * sizeof (unsigned));  bzero ((char *) map->const_age_map,	 map->const_equiv_map_size * sizeof (unsigned));  map->const_age = 0;  /* Record the current insn in case we have to set up pointers to frame     and argument memory blocks.  If there are no insns yet, add a dummy     insn that can be used as an insertion point.  */  map->insns_at_start = get_last_insn ();  if (map->insns_at_start == 0)    map->insns_at_start = emit_note (NULL_PTR, NOTE_INSN_DELETED);  map->regno_pointer_flag = INLINE_REGNO_POINTER_FLAG (header);  map->regno_pointer_align = INLINE_REGNO_POINTER_ALIGN (header);  /* Update the outgoing argument size to allow for those in the inlined     function.  */  if (OUTGOING_ARGS_SIZE (header) > current_function_outgoing_args_size)    current_function_outgoing_args_size = OUTGOING_ARGS_SIZE (header);  /* If the inline function needs to make PIC references, that means     that this function's PIC offset table must be used.  */  if (FUNCTION_FLAGS (header) & FUNCTION_FLAGS_USES_PIC_OFFSET_TABLE)    current_function_uses_pic_offset_table = 1;  /* If this function needs a context, set it up.  */  if (FUNCTION_FLAGS (header) & FUNCTION_FLAGS_NEEDS_CONTEXT)    static_chain_value = lookup_static_chain (fndecl);  if (GET_CODE (parm_insns) == NOTE      && NOTE_LINE_NUMBER (parm_insns) > 0)    {      rtx note = emit_note (NOTE_SOURCE_FILE (parm_insns),			    NOTE_LINE_NUMBER (parm_insns));      if (note)	RTX_INTEGRATED_P (note) = 1;    }  /* Process each argument.  For each, set up things so that the function's     reference to the argument will refer to the argument being passed.     We only replace REG with REG here.  Any simplifications are done     via const_equiv_map.     We make two passes:  In the first, we deal with parameters that will     be placed into registers, since we need to ensure that the allocated     register number fits in const_equiv_map.  Then we store all non-register     parameters into their memory location.  */  /* Don't try to free temp stack slots here, because we may put one of the     parameters into a temp stack slot.  */  for (i = 0; i < nargs; i++)    {      rtx copy = arg_vals[i];      loc = RTVEC_ELT (arg_vector, i);      /* There are three cases, each handled separately.  */      if (GET_CODE (loc) == MEM && GET_CODE (XEXP (loc, 0)) == REG	  && REGNO (XEXP (loc, 0)) > LAST_VIRTUAL_REGISTER)	{	  /* This must be an object passed by invisible reference (it could	     also be a variable-sized object, but we forbid inlining functions	     with variable-sized arguments).  COPY is the address of the	     actual value (this computation will cause it to be copied).  We	     map that address for the register, noting the actual address as	     an equivalent in case it can be substituted into the insns.  */	  if (GET_CODE (copy) != REG)	    {	      temp = copy_addr_to_reg (copy);	      if ((CONSTANT_P (copy) || FIXED_BASE_PLUS_P (copy))		  && REGNO (temp) < map->const_equiv_map_size)		{		  map->const_equiv_map[REGNO (temp)] = copy;		  map->const_age_map[REGNO (temp)] = CONST_AGE_PARM;		}	      copy = temp;	    }	  map->reg_map[REGNO (XEXP (loc, 0))] = copy;	}      else if (GET_CODE (loc) == MEM)	{	  /* This is the case of a parameter that lives in memory.	     It will live in the block we allocate in the called routine's	     frame that simulates the incoming argument area.  Do nothing	     now; we will call store_expr later.  */	  ;	}      else if (GET_CODE (loc) == REG)

⌨️ 快捷键说明

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