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

📄 function.c

📁 GCC编译器源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
  /* If SIZE is -1 it means that somebody tried to allocate a temporary     of a variable size.  */  if (size == -1)    abort ();  /* First try to find an available, already-allocated temporary that is the     exact size we require.  */  for (p = temp_slots; p; p = p->next)    if (p->size == size && GET_MODE (p->slot) == mode && ! p->in_use)      break;  /* If we didn't find, one, try one that is larger than what we want.  We     find the smallest such.  */  if (p == 0)    for (p = temp_slots; p; p = p->next)      if (p->size > size && GET_MODE (p->slot) == mode && ! p->in_use	  && (best_p == 0 || best_p->size > p->size))	best_p = p;  /* Make our best, if any, the one to use.  */  if (best_p)    {      /* If there are enough aligned bytes left over, make them into a new	 temp_slot so that the extra bytes don't get wasted.  Do this only	 for BLKmode slots, so that we can be sure of the alignment.  */      if (GET_MODE (best_p->slot) == BLKmode)	{	  int alignment = BIGGEST_ALIGNMENT / BITS_PER_UNIT;	  int rounded_size = CEIL_ROUND (size, alignment);	  if (best_p->size - rounded_size >= alignment)	    {	      p = (struct temp_slot *) oballoc (sizeof (struct temp_slot));	      p->in_use = p->addr_taken = 0;	      p->size = best_p->size - rounded_size;	      p->base_offset = best_p->base_offset + rounded_size;	      p->full_size = best_p->full_size - rounded_size;	      p->slot = gen_rtx (MEM, BLKmode,				 plus_constant (XEXP (best_p->slot, 0),						rounded_size));	      p->address = 0;	      p->rtl_expr = 0;	      p->next = temp_slots;	      temp_slots = p;	      stack_slot_list = gen_rtx (EXPR_LIST, VOIDmode, p->slot,					 stack_slot_list);	      best_p->size = rounded_size;	      best_p->full_size = rounded_size;	    }	}      p = best_p;    }	        /* If we still didn't find one, make a new temporary.  */  if (p == 0)    {      int frame_offset_old = frame_offset;      p = (struct temp_slot *) oballoc (sizeof (struct temp_slot));      /* If the temp slot mode doesn't indicate the alignment,	 use the largest possible, so no one will be disappointed.  */      p->slot = assign_stack_local (mode, size, mode == BLKmode ? -1 : 0);      /* The following slot size computation is necessary because we don't	 know the actual size of the temporary slot until assign_stack_local	 has performed all the frame alignment and size rounding for the	 requested temporary.  Note that extra space added for alignment	 can be either above or below this stack slot depending on which	 way the frame grows.  We include the extra space if and only if it	 is above this slot.  */#ifdef FRAME_GROWS_DOWNWARD      p->size = frame_offset_old - frame_offset;#else      p->size = size;#endif      /* Now define the fields used by combine_temp_slots.  */#ifdef FRAME_GROWS_DOWNWARD      p->base_offset = frame_offset;      p->full_size = frame_offset_old - frame_offset;#else      p->base_offset = frame_offset_old;      p->full_size = frame_offset - frame_offset_old;#endif      p->address = 0;      p->next = temp_slots;      temp_slots = p;    }  p->in_use = 1;  p->addr_taken = 0;  p->rtl_expr = sequence_rtl_expr;  if (keep == 2)    {      p->level = target_temp_slot_level;      p->keep = 0;    }  else    {      p->level = temp_slot_level;      p->keep = keep;    }  /* We may be reusing an old slot, so clear any MEM flags that may have been     set from before.  */  RTX_UNCHANGING_P (p->slot) = 0;  MEM_IN_STRUCT_P (p->slot) = 0;  return p->slot;}/* Assign a temporary of given TYPE.   KEEP is as for assign_stack_temp.   MEMORY_REQUIRED is 1 if the result must be addressable stack memory;   it is 0 if a register is OK.   DONT_PROMOTE is 1 if we should not promote values in register   to wider modes.  */rtxassign_temp (type, keep, memory_required, dont_promote)     tree type;     int keep;     int memory_required;     int dont_promote;{  enum machine_mode mode = TYPE_MODE (type);  int unsignedp = TREE_UNSIGNED (type);  if (mode == BLKmode || memory_required)    {      int size = int_size_in_bytes (type);      rtx tmp;      /* Unfortunately, we don't yet know how to allocate variable-sized	 temporaries.  However, sometimes we have a fixed upper limit on	 the size (which is stored in TYPE_ARRAY_MAX_SIZE) and can use that	 instead.  This is the case for Chill variable-sized strings.  */      if (size == -1 && TREE_CODE (type) == ARRAY_TYPE	  && TYPE_ARRAY_MAX_SIZE (type) != NULL_TREE	  && TREE_CODE (TYPE_ARRAY_MAX_SIZE (type)) == INTEGER_CST)	size = TREE_INT_CST_LOW (TYPE_ARRAY_MAX_SIZE (type));      tmp = assign_stack_temp (mode, size, keep);      MEM_IN_STRUCT_P (tmp) = AGGREGATE_TYPE_P (type);      return tmp;    }#ifndef PROMOTE_FOR_CALL_ONLY  if (! dont_promote)    mode = promote_mode (type, mode, &unsignedp, 0);#endif  return gen_reg_rtx (mode);}/* Combine temporary stack slots which are adjacent on the stack.   This allows for better use of already allocated stack space.  This is only   done for BLKmode slots because we can be sure that we won't have alignment   problems in this case.  */voidcombine_temp_slots (){  struct temp_slot *p, *q;  struct temp_slot *prev_p, *prev_q;  /* Determine where to free back to after this function.  */  rtx free_pointer = rtx_alloc (CONST_INT);  for (p = temp_slots, prev_p = 0; p; p = prev_p ? prev_p->next : temp_slots)    {      int delete_p = 0;      if (! p->in_use && GET_MODE (p->slot) == BLKmode)	for (q = p->next, prev_q = p; q; q = prev_q->next)	  {	    int delete_q = 0;	    if (! q->in_use && GET_MODE (q->slot) == BLKmode)	      {		if (p->base_offset + p->full_size == q->base_offset)		  {		    /* Q comes after P; combine Q into P.  */		    p->size += q->size;		    p->full_size += q->full_size;		    delete_q = 1;		  }		else if (q->base_offset + q->full_size == p->base_offset)		  {		    /* P comes after Q; combine P into Q.  */		    q->size += p->size;		    q->full_size += p->full_size;		    delete_p = 1;		    break;		  }	      }	    /* Either delete Q or advance past it.  */	    if (delete_q)	      prev_q->next = q->next;	    else	      prev_q = q;	  }      /* Either delete P or advance past it.  */      if (delete_p)	{	  if (prev_p)	    prev_p->next = p->next;	  else	    temp_slots = p->next;	}      else	prev_p = p;    }  /* Free all the RTL made by plus_constant.  */   rtx_free (free_pointer);}/* Find the temp slot corresponding to the object at address X.  */static struct temp_slot *find_temp_slot_from_address (x)     rtx x;{  struct temp_slot *p;  rtx next;  for (p = temp_slots; p; p = p->next)    {      if (! p->in_use)	continue;      else if (XEXP (p->slot, 0) == x	       || p->address == x	       || (GET_CODE (x) == PLUS		   && XEXP (x, 0) == virtual_stack_vars_rtx		   && GET_CODE (XEXP (x, 1)) == CONST_INT		   && INTVAL (XEXP (x, 1)) >= p->base_offset		   && INTVAL (XEXP (x, 1)) < p->base_offset + p->full_size))	return p;      else if (p->address != 0 && GET_CODE (p->address) == EXPR_LIST)	for (next = p->address; next; next = XEXP (next, 1))	  if (XEXP (next, 0) == x)	    return p;    }  return 0;}      /* Indicate that NEW is an alternate way of referring to the temp slot   that previous was known by OLD.  */voidupdate_temp_slot_address (old, new)     rtx old, new;{  struct temp_slot *p = find_temp_slot_from_address (old);  /* If none, return.  Else add NEW as an alias.  */  if (p == 0)    return;  else if (p->address == 0)    p->address = new;  else    {      if (GET_CODE (p->address) != EXPR_LIST)	p->address = gen_rtx (EXPR_LIST, VOIDmode, p->address, NULL_RTX);      p->address = gen_rtx (EXPR_LIST, VOIDmode, new, p->address);    }}/* If X could be a reference to a temporary slot, mark the fact that its   address was taken.  */voidmark_temp_addr_taken (x)     rtx x;{  struct temp_slot *p;  if (x == 0)    return;  /* If X is not in memory or is at a constant address, it cannot be in     a temporary slot.  */  if (GET_CODE (x) != MEM || CONSTANT_P (XEXP (x, 0)))    return;  p = find_temp_slot_from_address (XEXP (x, 0));  if (p != 0)    p->addr_taken = 1;}/* If X could be a reference to a temporary slot, mark that slot as   belonging to the to one level higher than the current level.  If X   matched one of our slots, just mark that one.  Otherwise, we can't   easily predict which it is, so upgrade all of them.  Kept slots   need not be touched.   This is called when an ({...}) construct occurs and a statement   returns a value in memory.  */voidpreserve_temp_slots (x)     rtx x;{  struct temp_slot *p = 0;  /* If there is no result, we still might have some objects whose address     were taken, so we need to make sure they stay around.  */  if (x == 0)    {      for (p = temp_slots; p; p = p->next)	if (p->in_use && p->level == temp_slot_level && p->addr_taken)	  p->level--;      return;    }  /* If X is a register that is being used as a pointer, see if we have     a temporary slot we know it points to.  To be consistent with     the code below, we really should preserve all non-kept slots     if we can't find a match, but that seems to be much too costly.  */  if (GET_CODE (x) == REG && REGNO_POINTER_FLAG (REGNO (x)))    p = find_temp_slot_from_address (x);  /* If X is not in memory or is at a constant address, it cannot be in     a temporary slot, but it can contain something whose address was     taken.  */  if (p == 0 && (GET_CODE (x) != MEM || CONSTANT_P (XEXP (x, 0))))    {      for (p = temp_slots; p; p = p->next)	if (p->in_use && p->level == temp_slot_level && p->addr_taken)	  p->level--;      return;    }  /* First see if we can find a match.  */  if (p == 0)    p = find_temp_slot_from_address (XEXP (x, 0));  if (p != 0)    {      /* Move everything at our level whose address was taken to our new	 level in case we used its address.  */      struct temp_slot *q;      if (p->level == temp_slot_level)	{	  for (q = temp_slots; q; q = q->next)	    if (q != p && q->addr_taken && q->level == p->level)	      q->level--;	  p->level--;	  p->addr_taken = 0;	}      return;    }  /* Otherwise, preserve all non-kept slots at this level.  */  for (p = temp_slots; p; p = p->next)    if (p->in_use && p->level == temp_slot_level && ! p->keep)      p->level--;}/* X is the result of an RTL_EXPR.  If it is a temporary slot associated   with that RTL_EXPR, promote it into a temporary slot at the present   level so it will not be freed when we free slots made in the   RTL_EXPR.  */voidpreserve_rtl_expr_result (x)     rtx x;{  struct temp_slot *p;  /* If X is not in memory or is at a constant address, it cannot be in     a temporary slot.  */  if (x == 0 || GET_CODE (x) != MEM || CONSTANT_P (XEXP (x, 0)))    return;  /* If we can find a match, move it to our level unless it is already at     an upper level.  */  p = find_temp_slot_from_address (XEXP (x, 0));  if (p != 0)    {      p->level = MIN (p->level, temp_slot_level);      p->rtl_expr = 0;    }  return;}/* Free all temporaries used so far.  This is normally called at the end   of generating code for a statement.  Don't free any temporaries   currently in use for an RTL_EXPR that hasn't yet been emitted.   We could eventually do better than this since it can be reused while   generating the same RTL_EXPR, but this is complex and probably not   worthwhile.  */voidfree_temp_slots (){  struct temp_slot *p;  for (p = temp_slots; p; p = p->next)    if (p->in_use && p->level == temp_slot_level && ! p->keep	&& p->rtl_expr == 0)      p->in_use = 0;  combine_temp_slots ();

⌨️ 快捷键说明

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