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

📄 function.c

📁 GUN开源阻止下的编译器GCC
💻 C
📖 第 1 页 / 共 5 页
字号:
  /* Get the current rtl used for this object and it's original mode.  */  reg = TREE_CODE (decl) == SAVE_EXPR ? SAVE_EXPR_RTL (decl) : DECL_RTL (decl);  /* No need to do anything if decl has no rtx yet     since in that case caller is setting TREE_ADDRESSABLE     and a stack slot will be assigned when the rtl is made.  */  if (reg == 0)    return;  /* Get the declared mode for this object.  */  decl_mode = (TREE_CODE (decl) == SAVE_EXPR ? TYPE_MODE (TREE_TYPE (decl))	       : DECL_MODE (decl));  /* Get the mode it's actually stored in.  */  promoted_mode = GET_MODE (reg);  /* If this variable comes from an outer function,     find that function's saved context.  */  if (context != current_function_decl)    for (function = outer_function_chain; function; function = function->next)      if (function->decl == context)	break;  /* If this is a variable-size object with a pseudo to address it,     put that pseudo into the stack, if the var is nonlocal.  */  if (DECL_NONLOCAL (decl)      && GET_CODE (reg) == MEM      && GET_CODE (XEXP (reg, 0)) == REG      && REGNO (XEXP (reg, 0)) > LAST_VIRTUAL_REGISTER)    {      reg = XEXP (reg, 0);      decl_mode = promoted_mode = GET_MODE (reg);    }  /* Now we should have a value that resides in one or more pseudo regs.  */  if (GET_CODE (reg) == REG)    put_reg_into_stack (function, reg, TREE_TYPE (decl),			promoted_mode, decl_mode, TREE_SIDE_EFFECTS (decl));  else if (GET_CODE (reg) == CONCAT)    {      /* A CONCAT contains two pseudos; put them both in the stack.	 We do it so they end up consecutive.  */      enum machine_mode part_mode = GET_MODE (XEXP (reg, 0));      tree part_type = TREE_TYPE (TREE_TYPE (decl));#ifdef FRAME_GROWS_DOWNWARD      /* Since part 0 should have a lower address, do it second.  */      put_reg_into_stack (function, XEXP (reg, 1), part_type, part_mode,			  part_mode, TREE_SIDE_EFFECTS (decl));      put_reg_into_stack (function, XEXP (reg, 0), part_type, part_mode,			  part_mode, TREE_SIDE_EFFECTS (decl));#else      put_reg_into_stack (function, XEXP (reg, 0), part_type, part_mode,			  part_mode, TREE_SIDE_EFFECTS (decl));      put_reg_into_stack (function, XEXP (reg, 1), part_type, part_mode,			  part_mode, TREE_SIDE_EFFECTS (decl));#endif      /* Change the CONCAT into a combined MEM for both parts.  */      PUT_CODE (reg, MEM);      MEM_VOLATILE_P (reg) = MEM_VOLATILE_P (XEXP (reg, 0));      /* The two parts are in memory order already.	 Use the lower parts address as ours.  */      XEXP (reg, 0) = XEXP (XEXP (reg, 0), 0);      /* Prevent sharing of rtl that might lose.  */      if (GET_CODE (XEXP (reg, 0)) == PLUS)	XEXP (reg, 0) = copy_rtx (XEXP (reg, 0));    }}/* Subroutine of put_var_into_stack.  This puts a single pseudo reg REG   into the stack frame of FUNCTION (0 means the current function).   DECL_MODE is the machine mode of the user-level data type.   PROMOTED_MODE is the machine mode of the register.   VOLATILE_P is nonzero if this is for a "volatile" decl.  */static voidput_reg_into_stack (function, reg, type, promoted_mode, decl_mode, volatile_p)     struct function *function;     rtx reg;     tree type;     enum machine_mode promoted_mode, decl_mode;     int volatile_p;{  rtx new = 0;  if (function)    {      if (REGNO (reg) < function->max_parm_reg)	new = function->parm_reg_stack_loc[REGNO (reg)];      if (new == 0)	new = assign_outer_stack_local (decl_mode, GET_MODE_SIZE (decl_mode),					0, function);    }  else    {      if (REGNO (reg) < max_parm_reg)	new = parm_reg_stack_loc[REGNO (reg)];      if (new == 0)	new = assign_stack_local (decl_mode, GET_MODE_SIZE (decl_mode), 0);    }  PUT_MODE (reg, decl_mode);  XEXP (reg, 0) = XEXP (new, 0);  /* `volatil' bit means one thing for MEMs, another entirely for REGs.  */  MEM_VOLATILE_P (reg) = volatile_p;  PUT_CODE (reg, MEM);  /* If this is a memory ref that contains aggregate components,     mark it as such for cse and loop optimize.  */  MEM_IN_STRUCT_P (reg) = AGGREGATE_TYPE_P (type);  /* Now make sure that all refs to the variable, previously made     when it was a register, are fixed up to be valid again.  */  if (function)    {      struct var_refs_queue *temp;      /* Variable is inherited; fix it up when we get back to its function.  */      push_obstacks (function->function_obstack,		     function->function_maybepermanent_obstack);      /* See comment in restore_tree_status in tree.c for why this needs to be	 on saveable obstack.  */      temp	= (struct var_refs_queue *) savealloc (sizeof (struct var_refs_queue));      temp->modified = reg;      temp->promoted_mode = promoted_mode;      temp->unsignedp = TREE_UNSIGNED (type);      temp->next = function->fixup_var_refs_queue;      function->fixup_var_refs_queue = temp;      pop_obstacks ();    }  else    /* Variable is local; fix it up now.  */    fixup_var_refs (reg, promoted_mode, TREE_UNSIGNED (type));}static voidfixup_var_refs (var, promoted_mode, unsignedp)     rtx var;     enum machine_mode promoted_mode;     int unsignedp;{  tree pending;  rtx first_insn = get_insns ();  struct sequence_stack *stack = sequence_stack;  tree rtl_exps = rtl_expr_chain;  /* Must scan all insns for stack-refs that exceed the limit.  */  fixup_var_refs_insns (var, promoted_mode, unsignedp, first_insn, stack == 0);  /* Scan all pending sequences too.  */  for (; stack; stack = stack->next)    {      push_to_sequence (stack->first);      fixup_var_refs_insns (var, promoted_mode, unsignedp,			    stack->first, stack->next != 0);      /* Update remembered end of sequence	 in case we added an insn at the end.  */      stack->last = get_last_insn ();      end_sequence ();    }  /* Scan all waiting RTL_EXPRs too.  */  for (pending = rtl_exps; pending; pending = TREE_CHAIN (pending))    {      rtx seq = RTL_EXPR_SEQUENCE (TREE_VALUE (pending));      if (seq != const0_rtx && seq != 0)	{	  push_to_sequence (seq);	  fixup_var_refs_insns (var, promoted_mode, unsignedp, seq, 0);	  end_sequence ();	}    }}/* REPLACEMENTS is a pointer to a list of the struct fixup_replacement and X is   some part of an insn.  Return a struct fixup_replacement whose OLD   value is equal to X.  Allocate a new structure if no such entry exists. */static struct fixup_replacement *find_fixup_replacement (replacements, x)     struct fixup_replacement **replacements;     rtx x;{  struct fixup_replacement *p;  /* See if we have already replaced this.  */  for (p = *replacements; p && p->old != x; p = p->next)    ;  if (p == 0)    {      p = (struct fixup_replacement *) oballoc (sizeof (struct fixup_replacement));      p->old = x;      p->new = 0;      p->next = *replacements;      *replacements = p;    }  return p;}/* Scan the insn-chain starting with INSN for refs to VAR   and fix them up.  TOPLEVEL is nonzero if this chain is the   main chain of insns for the current function.  */static voidfixup_var_refs_insns (var, promoted_mode, unsignedp, insn, toplevel)     rtx var;     enum machine_mode promoted_mode;     int unsignedp;     rtx insn;     int toplevel;{  rtx call_dest = 0;  while (insn)    {      rtx next = NEXT_INSN (insn);      rtx note;      if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')	{	  /* If this is a CLOBBER of VAR, delete it.	     If it has a REG_LIBCALL note, delete the REG_LIBCALL	     and REG_RETVAL notes too.  */ 	  if (GET_CODE (PATTERN (insn)) == CLOBBER	      && XEXP (PATTERN (insn), 0) == var)	    {	      if ((note = find_reg_note (insn, REG_LIBCALL, NULL_RTX)) != 0)		/* The REG_LIBCALL note will go away since we are going to		   turn INSN into a NOTE, so just delete the		   corresponding REG_RETVAL note.  */		remove_note (XEXP (note, 0),			     find_reg_note (XEXP (note, 0), REG_RETVAL,					    NULL_RTX));	      /* In unoptimized compilation, we shouldn't call delete_insn		 except in jump.c doing warnings.  */	      PUT_CODE (insn, NOTE);	      NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;	      NOTE_SOURCE_FILE (insn) = 0;	    }	  /* The insn to load VAR from a home in the arglist	     is now a no-op.  When we see it, just delete it.  */	  else if (toplevel		   && GET_CODE (PATTERN (insn)) == SET		   && SET_DEST (PATTERN (insn)) == var		   /* If this represents the result of an insn group,		      don't delete the insn.  */		   && find_reg_note (insn, REG_RETVAL, NULL_RTX) == 0		   && rtx_equal_p (SET_SRC (PATTERN (insn)), var))	    {	      /* In unoptimized compilation, we shouldn't call delete_insn		 except in jump.c doing warnings.  */	      PUT_CODE (insn, NOTE);	      NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;	      NOTE_SOURCE_FILE (insn) = 0;	      if (insn == last_parm_insn)		last_parm_insn = PREV_INSN (next);	    }	  else	    {	      struct fixup_replacement *replacements = 0;	      rtx next_insn = NEXT_INSN (insn);#ifdef SMALL_REGISTER_CLASSES	      /* If the insn that copies the results of a CALL_INSN		 into a pseudo now references VAR, we have to use an		 intermediate pseudo since we want the life of the		 return value register to be only a single insn.		 If we don't use an intermediate pseudo, such things as		 address computations to make the address of VAR valid		 if it is not can be placed between the CALL_INSN and INSN.		 To make sure this doesn't happen, we record the destination		 of the CALL_INSN and see if the next insn uses both that		 and VAR.  */	      if (call_dest != 0 && GET_CODE (insn) == INSN		  && reg_mentioned_p (var, PATTERN (insn))		  && reg_mentioned_p (call_dest, PATTERN (insn)))		{		  rtx temp = gen_reg_rtx (GET_MODE (call_dest));		  emit_insn_before (gen_move_insn (temp, call_dest), insn);		  PATTERN (insn) = replace_rtx (PATTERN (insn),						call_dest, temp);		}	      	      if (GET_CODE (insn) == CALL_INSN		  && GET_CODE (PATTERN (insn)) == SET)		call_dest = SET_DEST (PATTERN (insn));	      else if (GET_CODE (insn) == CALL_INSN		       && GET_CODE (PATTERN (insn)) == PARALLEL		       && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET)		call_dest = SET_DEST (XVECEXP (PATTERN (insn), 0, 0));	      else		call_dest = 0;#endif	      /* See if we have to do anything to INSN now that VAR is in		 memory.  If it needs to be loaded into a pseudo, use a single		 pseudo for the entire insn in case there is a MATCH_DUP		 between two operands.  We pass a pointer to the head of		 a list of struct fixup_replacements.  If fixup_var_refs_1		 needs to allocate pseudos or replacement MEMs (for SUBREGs),		 it will record them in this list.		 		 If it allocated a pseudo for any replacement, we copy into		 it here.  */	      fixup_var_refs_1 (var, promoted_mode, &PATTERN (insn), insn,				&replacements);	      /* If this is last_parm_insn, and any instructions were output		 after it to fix it up, then we must set last_parm_insn to		 the last such instruction emitted.  */	      if (insn == last_parm_insn)		last_parm_insn = PREV_INSN (next_insn);	      while (replacements)		{		  if (GET_CODE (replacements->new) == REG)		    {		      rtx insert_before;		      rtx seq;		      /* OLD might be a (subreg (mem)).  */		      if (GET_CODE (replacements->old) == SUBREG)			replacements->old			  = fixup_memory_subreg (replacements->old, insn, 0);		      else			replacements->old			  = fixup_stack_1 (replacements->old, insn);		      insert_before = insn;		      /* If we are changing the mode, do a conversion.			 This might be wasteful, but combine.c will			 eliminate much of the waste.  */		      if (GET_MODE (replacements->new)			  != GET_MODE (replacements->old))			{			  start_sequence ();			  convert_move (replacements->new,					replacements->old, unsignedp);			  seq = gen_sequence ();			  end_sequence ();			}		      else			seq = gen_move_insn (replacements->new,					     replacements->old);		      emit_insn_before (seq, insert_before);		    }		  replacements = replacements->next;		}	    }	  /* Also fix up any invalid exprs in the REG_NOTES of this insn.	     But don't touch other insns referred to by reg-notes;	     we will get them elsewhere.  */	  for (note = REG_NOTES (insn); note; note = XEXP (note, 1))	    if (GET_CODE (note) != INSN_LIST)	      XEXP (note, 0)		= walk_fixup_memory_subreg (XEXP (note, 0), insn, 1);	}      insn = next;    }}/* VAR is a MEM that used to be a pseudo register with mode PROMOTED_MODE.   See if the rtx expression at *LOC in INSN needs to be changed.     REPLACEMENTS is a pointer to a list head that starts out zero, but may   contain a list of original rtx's and replacements. If we find that we need   to modify this insn by replacing a memory reference with a pseudo or by   making a new MEM to implement a SUBREG, we consult that list to see if   we have already chosen a replacement. If none has already been allocated,   we allocate it and update the list.  fixup_var_refs_insns will copy VAR   or the SUBREG, as appropriate, to the pseudo.  */static voidfixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)     register rtx var;     enum machine_mode promoted_mode;     register rtx *loc;     rtx insn;     struct fixup_replacement **replacements;{  register int i;  register rtx x = *loc;  RTX_CODE code = GET_CODE (x);  register char *fmt;  register rtx tem, tem1;  struct fixup_replacement *replacement;  switch (code)    {    case MEM:      if (var == x)

⌨️ 快捷键说明

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