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

📄 function.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 5 页
字号:
  enum machine_mode promoted_mode, decl_mode;  struct function *function = 0;  tree context = decl_function_context (decl);  /* 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);    }  if (GET_CODE (reg) != REG)    return;  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 (GET_MODE (reg),					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 (GET_MODE (reg),				  GET_MODE_SIZE (decl_mode), 0);    }  XEXP (reg, 0) = XEXP (new, 0);  /* `volatil' bit means one thing for MEMs, another entirely for REGs.  */  REG_USERVAR_P (reg) = 0;  PUT_CODE (reg, MEM);  PUT_MODE (reg, decl_mode);  /* If this is a memory ref that contains aggregate components,     mark it as such for cse and loop optimize.  */  MEM_IN_STRUCT_P (reg)    = (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE       || TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE       || TREE_CODE (TREE_TYPE (decl)) == UNION_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);      temp	= (struct var_refs_queue *) oballoc (sizeof (struct var_refs_queue));      temp->modified = reg;      temp->promoted_mode = promoted_mode;      temp->unsignedp = TREE_UNSIGNED (TREE_TYPE (decl));      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 (TREE_TYPE (decl)));}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 ();	}    }}/* This structure is used by the following two functions to record MEMs or   pseudos used to replace VAR, any SUBREGs of VAR, and any MEMs containing   VAR as an address.  We need to maintain this list in case two operands of   an insn were required to match; in that case we must ensure we use the   same replacement.  */struct fixup_replacement{  rtx old;  rtx new;  struct fixup_replacement *next;};   /* REPLACEMENTS is a pointer to a list of the above structures 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;{  while (insn)    {      rtx next = NEXT_INSN (insn);      rtx note;      if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN	  || GET_CODE (insn) == JUMP_INSN)	{	  /* The insn to load VAR from a home in the arglist	     is now a no-op.  When we see it, just delete it.  */	  if (toplevel	      && GET_CODE (PATTERN (insn)) == SET	      && SET_DEST (PATTERN (insn)) == var	      && 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	    {	      /* 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.  */	      struct fixup_replacement *replacements = 0;	      fixup_var_refs_1 (var, promoted_mode, &PATTERN (insn), insn,				&replacements);	      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);		      /* We can not separate USE insns from the CALL_INSN			 that they belong to.  If this is a CALL_INSN, insert			 the move insn before the USE insns preceding it			 instead of immediately before the insn.  */		      if (GET_CODE (insn) == CALL_INSN)			{			  insert_before = insn;			  while (GET_CODE (PREV_INSN (insert_before)) == INSN				 && GET_CODE (PATTERN (PREV_INSN (insert_before))) == USE)			    insert_before = PREV_INSN (insert_before);			}		      else			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);	}      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)	{	  /* If we already have a replacement, use it.  Otherwise, 	     try to fix up this address in case it is invalid.  */	  replacement = find_fixup_replacement (replacements, var);	  if (replacement->new)	    {	      *loc = replacement->new;	      return;	    }	  *loc = replacement->new = x = fixup_stack_1 (x, insn);	  /* Unless we are forcing memory to register or we changed the mode,	     we can leave things the way they are if the insn is valid.  */	     	  INSN_CODE (insn) = -1;	  if (! flag_force_mem && GET_MODE (x) == promoted_mode	      && recog_memoized (insn) >= 0)	    return;	  *loc = replacement->new = gen_reg_rtx (promoted_mode);	  return;	}      /* If X contains VAR, we need to unshare it here so that we update	 each occurrence separately.  But all identical MEMs in one insn	 must be replaced with the same rtx because of the possibility of	 MATCH_DUPs.  */      if (reg_mentioned_p (var, x))	{	  replacement = find_fixup_replacement (replacements, x);	  if (replacement->new == 0)	    replacement->new = copy_most_rtx (x, var);	  *loc = x = replacement->new;	}      break;    case REG:    case CC0:    case PC:    case CONST_INT:    case CONST:    case SYMBOL_REF:    case LABEL_REF:    case CONST_DOUBLE:      return;    case SIGN_EXTRACT:    case ZERO_EXTRACT:      /* Note that in some cases those types of expressions are altered	 by optimize_bit_field, and do not survive to get here.  */      if (XEXP (x, 0) == var	  || (GET_CODE (XEXP (x, 0)) == SUBREG	      && SUBREG_REG (XEXP (x, 0)) == var))	{	  /* Get TEM as a valid MEM in the mode presently in the insn.	     We don't worry about the possibility of MATCH_DUP here; it	     is highly unlikely and would be tricky to handle.  */	  tem = XEXP (x, 0);	  if (GET_CODE (tem) == SUBREG)	    tem = fixup_memory_subreg (tem, insn, 1);	  tem = fixup_stack_1 (tem, insn);	  /* Unless we want to load from memory, get TEM into the proper mode	     for an extract from memory.  This can only be done if the	     extract is at a constant position and length.  */	  if (! flag_force_mem && GET_CODE (XEXP (x, 1)) == CONST_INT	      && GET_CODE (XEXP (x, 2)) == CONST_INT	      && ! mode_dependent_address_p (XEXP (tem, 0))	      && ! MEM_VOLATILE_P (tem))	    {	      enum machine_mode wanted_mode = VOIDmode;	      enum machine_mode is_mode = GET_MODE (tem);	      int width = INTVAL (XEXP (x, 1));	      int pos = INTVAL (XEXP (x, 2));#ifdef HAVE_extzv	      if (GET_CODE (x) == ZERO_EXTRACT)		wanted_mode = insn_operand_mode[(int) CODE_FOR_extzv][1];#endif#ifdef HAVE_extv	      if (GET_CODE (x) == SIGN_EXTRACT)		wanted_mode = insn_operand_mode[(int) CODE_FOR_extv][1];#endif	      /* If we have a narrower mode, we can do something.  */

⌨️ 快捷键说明

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