integrate.c

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

C
1,907
字号
	{	  /* This is the good case where the parameter is in a register.	     If it is read-only and our argument is a constant, set up the	     constant equivalence.	     If LOC is REG_USERVAR_P, the usual case, COPY must also have	     that flag set if it is a register.	     Also, don't allow hard registers here; they might not be valid	     when substituted into insns.  */	  if ((GET_CODE (copy) != REG && GET_CODE (copy) != SUBREG)	      || (GET_CODE (copy) == REG && REG_USERVAR_P (loc)		  && ! REG_USERVAR_P (copy))	      || (GET_CODE (copy) == REG		  && REGNO (copy) < FIRST_PSEUDO_REGISTER))	    {	      temp = copy_to_mode_reg (GET_MODE (loc), copy);	      REG_USERVAR_P (temp) = REG_USERVAR_P (loc);	      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 (loc)] = copy;	}      else if (GET_CODE (loc) == CONCAT)	{	  /* This is the good case where the parameter is in a	     pair of separate pseudos.	     If it is read-only and our argument is a constant, set up the	     constant equivalence.	     If LOC is REG_USERVAR_P, the usual case, COPY must also have	     that flag set if it is a register.	     Also, don't allow hard registers here; they might not be valid	     when substituted into insns.  */	  rtx locreal = gen_realpart (GET_MODE (XEXP (loc, 0)), loc);	  rtx locimag = gen_imagpart (GET_MODE (XEXP (loc, 0)), loc);	  rtx copyreal = gen_realpart (GET_MODE (locreal), copy);	  rtx copyimag = gen_imagpart (GET_MODE (locimag), copy);	  if ((GET_CODE (copyreal) != REG && GET_CODE (copyreal) != SUBREG)	      || (GET_CODE (copyreal) == REG && REG_USERVAR_P (locreal)		  && ! REG_USERVAR_P (copyreal))	      || (GET_CODE (copyreal) == REG		  && REGNO (copyreal) < FIRST_PSEUDO_REGISTER))	    {	      temp = copy_to_mode_reg (GET_MODE (locreal), copyreal);	      REG_USERVAR_P (temp) = REG_USERVAR_P (locreal);	      if ((CONSTANT_P (copyreal) || FIXED_BASE_PLUS_P (copyreal))		  && REGNO (temp) < map->const_equiv_map_size)		{		  map->const_equiv_map[REGNO (temp)] = copyreal;		  map->const_age_map[REGNO (temp)] = CONST_AGE_PARM;		}	      copyreal = temp;	    }	  map->reg_map[REGNO (locreal)] = copyreal;	  if ((GET_CODE (copyimag) != REG && GET_CODE (copyimag) != SUBREG)	      || (GET_CODE (copyimag) == REG && REG_USERVAR_P (locimag)		  && ! REG_USERVAR_P (copyimag))	      || (GET_CODE (copyimag) == REG		  && REGNO (copyimag) < FIRST_PSEUDO_REGISTER))	    {	      temp = copy_to_mode_reg (GET_MODE (locimag), copyimag);	      REG_USERVAR_P (temp) = REG_USERVAR_P (locimag);	      if ((CONSTANT_P (copyimag) || FIXED_BASE_PLUS_P (copyimag))		  && REGNO (temp) < map->const_equiv_map_size)		{		  map->const_equiv_map[REGNO (temp)] = copyimag;		  map->const_age_map[REGNO (temp)] = CONST_AGE_PARM;		}	      copyimag = temp;	    }	  map->reg_map[REGNO (locimag)] = copyimag;	}      else	abort ();    }  /* Now do the parameters that will be placed in memory.  */  for (formal = DECL_ARGUMENTS (fndecl), i = 0;       formal; formal = TREE_CHAIN (formal), i++)    {      loc = RTVEC_ELT (arg_vector, i);      if (GET_CODE (loc) == MEM	  /* Exclude case handled above.  */	  && ! (GET_CODE (XEXP (loc, 0)) == REG		&& REGNO (XEXP (loc, 0)) > LAST_VIRTUAL_REGISTER))	{	  rtx note = emit_note (DECL_SOURCE_FILE (formal),				DECL_SOURCE_LINE (formal));	  if (note)	    RTX_INTEGRATED_P (note) = 1;	  /* Compute the address in the area we reserved and store the	     value there.  */	  temp = copy_rtx_and_substitute (loc, map);	  subst_constants (&temp, NULL_RTX, map);	  apply_change_group ();	  if (! memory_address_p (GET_MODE (temp), XEXP (temp, 0)))	    temp = change_address (temp, VOIDmode, XEXP (temp, 0));	  store_expr (arg_trees[i], temp, 0);	}    }  /* Deal with the places that the function puts its result.     We are driven by what is placed into DECL_RESULT.     Initially, we assume that we don't have anything special handling for     REG_FUNCTION_RETURN_VALUE_P.  */  map->inline_target = 0;  loc = DECL_RTL (DECL_RESULT (fndecl));  if (TYPE_MODE (type) == VOIDmode)    /* There is no return value to worry about.  */    ;  else if (GET_CODE (loc) == MEM)    {      if (! structure_value_addr || ! aggregate_value_p (DECL_RESULT (fndecl)))	abort ();        /* Pass the function the address in which to return a structure value.	 Note that a constructor can cause someone to call us with	 STRUCTURE_VALUE_ADDR, but the initialization takes place	 via the first parameter, rather than the struct return address.	 We have two cases:  If the address is a simple register indirect,	 use the mapping mechanism to point that register to our structure	 return address.  Otherwise, store the structure return value into	 the place that it will be referenced from.  */      if (GET_CODE (XEXP (loc, 0)) == REG)	{	  temp = force_reg (Pmode,			    force_operand (structure_value_addr, NULL_RTX));	  map->reg_map[REGNO (XEXP (loc, 0))] = temp;	  if ((CONSTANT_P (structure_value_addr)	       || GET_CODE (structure_value_addr) == ADDRESSOF	       || (GET_CODE (structure_value_addr) == PLUS		   && XEXP (structure_value_addr, 0) == virtual_stack_vars_rtx		   && GET_CODE (XEXP (structure_value_addr, 1)) == CONST_INT))	      && REGNO (temp) < map->const_equiv_map_size)	    {	      map->const_equiv_map[REGNO (temp)] = structure_value_addr;	      map->const_age_map[REGNO (temp)] = CONST_AGE_PARM;	    }	}      else	{	  temp = copy_rtx_and_substitute (loc, map);	  subst_constants (&temp, NULL_RTX, map);	  apply_change_group ();	  emit_move_insn (temp, structure_value_addr);	}    }  else if (ignore)    /* We will ignore the result value, so don't look at its structure.       Note that preparations for an aggregate return value       do need to be made (above) even if it will be ignored.  */    ;  else if (GET_CODE (loc) == REG)    {      /* The function returns an object in a register and we use the return	 value.  Set up our target for remapping.  */      /* Machine mode function was declared to return.   */      enum machine_mode departing_mode = TYPE_MODE (type);      /* (Possibly wider) machine mode it actually computes	 (for the sake of callers that fail to declare it right).	 We have to use the mode of the result's RTL, rather than	 its type, since expand_function_start may have promoted it.  */      enum machine_mode arriving_mode	= GET_MODE (DECL_RTL (DECL_RESULT (fndecl)));      rtx reg_to_map;      /* Don't use MEMs as direct targets because on some machines	 substituting a MEM for a REG makes invalid insns.	 Let the combiner substitute the MEM if that is valid.  */      if (target == 0 || GET_CODE (target) != REG	  || GET_MODE (target) != departing_mode)	target = gen_reg_rtx (departing_mode);      /* If function's value was promoted before return,	 avoid machine mode mismatch when we substitute INLINE_TARGET.	 But TARGET is what we will return to the caller.  */      if (arriving_mode != departing_mode)	{	  /* Avoid creating a paradoxical subreg wider than	     BITS_PER_WORD, since that is illegal.  */	  if (GET_MODE_BITSIZE (arriving_mode) > BITS_PER_WORD)	    {	      if (!TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (departing_mode),					  GET_MODE_BITSIZE (arriving_mode)))		/* Maybe could be handled by using convert_move () ?  */		abort ();	      reg_to_map = gen_reg_rtx (arriving_mode);	      target = gen_lowpart (departing_mode, reg_to_map);	    }	  else	    reg_to_map = gen_rtx (SUBREG, arriving_mode, target, 0);	}      else	reg_to_map = target;      /* Usually, the result value is the machine's return register.	 Sometimes it may be a pseudo. Handle both cases.  */      if (REG_FUNCTION_VALUE_P (loc))	map->inline_target = reg_to_map;      else	map->reg_map[REGNO (loc)] = reg_to_map;    }  else    abort ();  /* Make a fresh binding contour that we can easily remove.  Do this after     expanding our arguments so cleanups are properly scoped.  */  pushlevel (0);  expand_start_bindings (0);  /* Make new label equivalences for the labels in the called function.  */  for (i = min_labelno; i < max_labelno; i++)    map->label_map[i] = gen_label_rtx ();  /* Perform postincrements before actually calling the function.  */  emit_queue ();  /* Clean up stack so that variables might have smaller offsets.  */  do_pending_stack_adjust ();  /* Save a copy of the location of const_equiv_map for mark_stores, called     via note_stores.  */  global_const_equiv_map = map->const_equiv_map;  global_const_equiv_map_size = map->const_equiv_map_size;  /* If the called function does an alloca, save and restore the     stack pointer around the call.  This saves stack space, but     also is required if this inline is being done between two     pushes.  */  if (FUNCTION_FLAGS (header) & FUNCTION_FLAGS_CALLS_ALLOCA)    emit_stack_save (SAVE_BLOCK, &stack_save, NULL_RTX);  /* Now copy the insns one by one.  Do this in two passes, first the insns and     then their REG_NOTES, just like save_for_inline.  */  /* This loop is very similar to the loop in copy_loop_body in unroll.c.  */  for (insn = insns; insn; insn = NEXT_INSN (insn))    {      rtx copy, pattern, set;      map->orig_asm_operands_vector = 0;      switch (GET_CODE (insn))	{	case INSN:	  pattern = PATTERN (insn);	  set = single_set (insn);	  copy = 0;	  if (GET_CODE (pattern) == USE	      && GET_CODE (XEXP (pattern, 0)) == REG	      && REG_FUNCTION_VALUE_P (XEXP (pattern, 0)))	    /* The (USE (REG n)) at return from the function should	       be ignored since we are changing (REG n) into	       inline_target.  */	    break;	  /* Ignore setting a function value that we don't want to use.  */	  if (map->inline_target == 0	      && set != 0	      && GET_CODE (SET_DEST (set)) == REG	      && REG_FUNCTION_VALUE_P (SET_DEST (set)))	    {	      if (volatile_refs_p (SET_SRC (set)))		{		  rtx new_set;		  /* If we must not delete the source,		     load it into a new temporary.  */		  copy = emit_insn (copy_rtx_and_substitute (pattern, map));		  new_set = single_set (copy);		  if (new_set == 0)		    abort ();		  SET_DEST (new_set)		    = gen_reg_rtx (GET_MODE (SET_DEST (new_set)));		}	      /* If the source and destination are the same and it		 has a note on it, keep the insn.  */	      else if (rtx_equal_p (SET_DEST (set), SET_SRC (set))		       && REG_NOTES (insn) != 0)		copy = emit_insn (copy_rtx_and_substitute (pattern, map));	      else		break;	    }	  /* If this is setting the static chain rtx, omit it.  */	  else if (static_chain_value != 0		   && set != 0		   && GET_CODE (SET_DEST (set)) == REG		   && rtx_equal_p (SET_DEST (set),				   static_chain_incoming_rtx))	    break;	  /* If this is setting the static chain pseudo, set it from	     the value we want to give it instead.  */	  else if (static_chain_value != 0		   && set != 0		   && rtx_equal_p (SET_SRC (set),				   static_chain_incoming_rtx))	    {	      rtx newdest = copy_rtx_and_substitute (SET_DEST (set), map);	      copy = emit_move_insn (newdest, static_chain_value);	      static_chain_value = 0;	    }	  else	    copy = emit_insn (copy_rtx_and_substitute (pattern, map));	  /* REG_NOTES will be copied later.  */#ifdef HAVE_cc0	  /* If this insn is setting CC0, it may need to look at	     the insn that uses CC0 to see what type of insn it is.	     In that case, the call to recog via validate_change will	     fail.  So don't substitute constants here.  Instead,	     do it when we emit the following insn.	     For example, see the pyr.md file.  That machine has signed and	     unsigned compares.  The compare patterns must check the	     following branch insn to see which what kind of compare to	     emit.	     If the previous insn set CC0, substitute constants on it as	     well.  */	  if (sets_cc0_p (PATTERN (copy)) != 0)	    cc0_insn = copy;	  else	    {	      if (cc0_insn)		try_constants (cc0_insn, map);	      cc0_insn = 0;	      try_constants (copy, map);	    }#else	  try_constants (copy, map);#endif	  break;	case JUMP_INSN:	  if (GET_CODE (PATTERN (insn)) == RETURN	      || (GET_CODE (PATTERN (insn)) == PARALLEL		  && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == RETURN))	    {	      if (local_return_label == 0)		local_return_label = gen_label_rtx ();	      pattern = gen_jump (local_return_label);	    }	  else	    pattern = copy_rtx_and_substitute (PATTERN (insn), map);	  copy = emit_jump_insn (pattern);#ifdef HAVE_cc0	  if (cc0_insn)	    try_constants (cc0_insn, map);	  cc0_insn = 0;#endif	  try_constants (copy, map);	  /* If this used to be a conditional jump in

⌨️ 快捷键说明

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