local-alloc.c

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

C
1,992
字号
	  int n_calls = 0;	  int d_n_calls = 0;	  /* We can do the optimization.  Scan forward from INSN again,	     replacing regs as we go.  Set FAILED if a replacement can't	     be done.  In that case, we can't move the death note for SRC.	     This should be rare.  */	  /* Set to stop at next insn.  */	  for (q = next_real_insn (insn);	       q != next_real_insn (p);	       q = next_real_insn (q))	    {	      if (reg_overlap_mentioned_p (src, PATTERN (q)))		{		  /* If SRC is a hard register, we might miss some		     overlapping registers with validate_replace_rtx,		     so we would have to undo it.  We can't if DEST is		     present in the insn, so fail in that combination		     of cases.  */		  if (sregno < FIRST_PSEUDO_REGISTER		      && reg_mentioned_p (dest, PATTERN (q)))		    failed = 1;		  /* Replace all uses and make sure that the register		     isn't still present.  */		  else if (validate_replace_rtx (src, dest, q)			   && (sregno >= FIRST_PSEUDO_REGISTER			       || ! reg_overlap_mentioned_p (src,							     PATTERN (q))))		    {		      /* We assume that a register is used exactly once per			 insn in the updates below.  If this is not correct,			 no great harm is done.  */		      if (sregno >= FIRST_PSEUDO_REGISTER)			REG_N_REFS (sregno) -= loop_depth;		      if (dregno >= FIRST_PSEUDO_REGISTER)			REG_N_REFS (dregno) += loop_depth;		    }		  else		    {		      validate_replace_rtx (dest, src, q);		      failed = 1;		    }		}	      /* Count the insns and CALL_INSNs passed.  If we passed the		 death note of DEST, show increased live length.  */	      length++;	      if (dest_death)		d_length++;	      /* If the insn in which SRC dies is a CALL_INSN, don't count it		 as a call that has been crossed.  Otherwise, count it.  */	      if (q != p && GET_CODE (q) == CALL_INSN)		{		  n_calls++;		  if (dest_death)		    d_n_calls++;		}	      /* If DEST dies here, remove the death note and save it for		 later.  Make sure ALL of DEST dies here; again, this is		 overly conservative.  */	      if (dest_death == 0		  && (dest_death = find_regno_note (q, REG_DEAD, dregno)) != 0		  && GET_MODE (XEXP (dest_death, 0)) == GET_MODE (dest))		remove_note (q, dest_death);	    }	  if (! failed)	    {	      if (sregno >= FIRST_PSEUDO_REGISTER)		{		  if (REG_LIVE_LENGTH (sregno) >= 0)		    {		      REG_LIVE_LENGTH (sregno) -= length;		      /* reg_live_length is only an approximation after			 combine if sched is not run, so make sure that we			 still have a reasonable value.  */		      if (REG_LIVE_LENGTH (sregno) < 2)			REG_LIVE_LENGTH (sregno) = 2;		    }		  REG_N_CALLS_CROSSED (sregno) -= n_calls;		}	      if (dregno >= FIRST_PSEUDO_REGISTER)		{		  if (REG_LIVE_LENGTH (dregno) >= 0)		    REG_LIVE_LENGTH (dregno) += d_length;		  REG_N_CALLS_CROSSED (dregno) += d_n_calls;		}	      /* Move death note of SRC from P to INSN.  */	      remove_note (p, note);	      XEXP (note, 1) = REG_NOTES (insn);	      REG_NOTES (insn) = note;	    }	  /* Put death note of DEST on P if we saw it die.  */	  if (dest_death)	    {	      XEXP (dest_death, 1) = REG_NOTES (p);	      REG_NOTES (p) = dest_death;	    }	  return;	}      /* If SRC is a hard register which is set or killed in some other	 way, we can't do this optimization.  */      else if (sregno < FIRST_PSEUDO_REGISTER	       && dead_or_set_p (p, src))	break;    }}/* INSN is a copy of SRC to DEST, in which SRC dies.  See if we now have   a sequence of insns that modify DEST followed by an insn that sets   SRC to DEST in which DEST dies, with no prior modification of DEST.   (There is no need to check if the insns in between actually modify   DEST.  We should not have cases where DEST is not modified, but   the optimization is safe if no such modification is detected.)   In that case, we can replace all uses of DEST, starting with INSN and   ending with the set of SRC to DEST, with SRC.  We do not do this   optimization if a CALL_INSN is crossed unless SRC already crosses a   call or if DEST dies before the copy back to SRC.   It is assumed that DEST and SRC are pseudos; it is too complicated to do   this for hard registers since the substitutions we may make might fail.  */static voidoptimize_reg_copy_2 (insn, dest, src)     rtx insn;     rtx dest;     rtx src;{  rtx p, q;  rtx set;  int sregno = REGNO (src);  int dregno = REGNO (dest);  for (p = NEXT_INSN (insn); p; p = NEXT_INSN (p))    {      if (GET_CODE (p) == CODE_LABEL || GET_CODE (p) == JUMP_INSN	  || (GET_CODE (p) == NOTE	      && (NOTE_LINE_NUMBER (p) == NOTE_INSN_LOOP_BEG		  || NOTE_LINE_NUMBER (p) == NOTE_INSN_LOOP_END)))	break;      if (GET_RTX_CLASS (GET_CODE (p)) != 'i')	continue;      set = single_set (p);      if (set && SET_SRC (set) == dest && SET_DEST (set) == src	  && find_reg_note (p, REG_DEAD, dest))	{	  /* We can do the optimization.  Scan forward from INSN again,	     replacing regs as we go.  */	  /* Set to stop at next insn.  */	  for (q = insn; q != NEXT_INSN (p); q = NEXT_INSN (q))	    if (GET_RTX_CLASS (GET_CODE (q)) == 'i')	      {		if (reg_mentioned_p (dest, PATTERN (q)))		  {		    PATTERN (q) = replace_rtx (PATTERN (q), dest, src);		    /* We assume that a register is used exactly once per		       insn in the updates below.  If this is not correct,		       no great harm is done.  */		    REG_N_REFS (dregno) -= loop_depth;		    REG_N_REFS (sregno) += loop_depth;		  }	      if (GET_CODE (q) == CALL_INSN)		{		  REG_N_CALLS_CROSSED (dregno)--;		  REG_N_CALLS_CROSSED (sregno)++;		}	      }	  remove_note (p, find_reg_note (p, REG_DEAD, dest));	  REG_N_DEATHS (dregno)--;	  remove_note (insn, find_reg_note (insn, REG_DEAD, src));	  REG_N_DEATHS (sregno)--;	  return;	}      if (reg_set_p (src, p)	  || find_reg_note (p, REG_DEAD, dest)	  || (GET_CODE (p) == CALL_INSN && REG_N_CALLS_CROSSED (sregno) == 0))	break;    }}	      /* Find registers that are equivalent to a single value throughout the   compilation (either because they can be referenced in memory or are set once   from a single constant).  Lower their priority for a register.   If such a register is only referenced once, try substituting its value   into the using insn.  If it succeeds, we can eliminate the register   completely.  */static voidupdate_equiv_regs (){  rtx *reg_equiv_init_insn = (rtx *) alloca (max_regno * sizeof (rtx *));  /* Set when an attempt should be made to replace a register with the     associated reg_equiv_replacement entry at the end of this function.  */  char *reg_equiv_replace    = (char *) alloca (max_regno * sizeof *reg_equiv_replace);  rtx insn;  int block, depth;  reg_equiv_replacement = (rtx *) alloca (max_regno * sizeof (rtx *));  bzero ((char *) reg_equiv_init_insn, max_regno * sizeof (rtx *));  bzero ((char *) reg_equiv_replacement, max_regno * sizeof (rtx *));  bzero ((char *) reg_equiv_replace, max_regno * sizeof *reg_equiv_replace);  init_alias_analysis ();  loop_depth = 1;  /* Scan the insns and find which registers have equivalences.  Do this     in a separate scan of the insns because (due to -fcse-follow-jumps)     a register can be set below its use.  */  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))    {      rtx note;      rtx set = single_set (insn);      rtx dest, src;      int regno;      if (GET_CODE (insn) == NOTE)	{	  if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)	    loop_depth++;	  else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)	    loop_depth--;	}      /* If this insn contains more (or less) than a single SET, ignore it.  */      if (set == 0)	continue;      dest = SET_DEST (set);      src = SET_SRC (set);      /* If this sets a MEM to the contents of a REG that is only used	 in a single basic block, see if the register is always equivalent	 to that memory location and if moving the store from INSN to the	 insn that set REG is safe.  If so, put a REG_EQUIV note on the	 initializing insn.	 Don't add a REG_EQUIV note if the insn already has one.  The existing	 REG_EQUIV is likely more useful than the one we are adding.	 If one of the regs in the address is marked as reg_equiv_replace,	 then we can't add this REG_EQUIV note.  The reg_equiv_replace	 optimization may move the set of this register immediately before	 insn, which puts it after reg_equiv_init_insn[regno], and hence	 the mention in the REG_EQUIV note would be to an uninitialized	 pseudo.  */      if (GET_CODE (dest) == MEM && GET_CODE (SET_SRC (set)) == REG	  && (regno = REGNO (SET_SRC (set))) >= FIRST_PSEUDO_REGISTER	  && REG_BASIC_BLOCK (regno) >= 0	  && reg_equiv_init_insn[regno] != 0	  && ! find_reg_note (insn, REG_EQUIV, NULL_RTX)	  && ! contains_replace_regs (XEXP (dest, 0), reg_equiv_replace)	  && validate_equiv_mem (reg_equiv_init_insn[regno], SET_SRC (set),				 dest)	  && ! memref_used_between_p (SET_DEST (set),				      reg_equiv_init_insn[regno], insn))	REG_NOTES (reg_equiv_init_insn[regno])	  = gen_rtx (EXPR_LIST, REG_EQUIV, dest,		     REG_NOTES (reg_equiv_init_insn[regno]));      /* If this is a register-register copy where SRC is not dead, see if we	 can optimize it.  */      if (flag_expensive_optimizations && GET_CODE (dest) == REG	  && GET_CODE (SET_SRC (set)) == REG	  && ! find_reg_note (insn, REG_DEAD, SET_SRC (set)))	optimize_reg_copy_1 (insn, dest, SET_SRC (set));      /* Similarly for a pseudo-pseudo copy when SRC is dead.  */      else if (flag_expensive_optimizations && GET_CODE (dest) == REG	       && REGNO (dest) >= FIRST_PSEUDO_REGISTER	       && GET_CODE (SET_SRC (set)) == REG	       && REGNO (SET_SRC (set)) >= FIRST_PSEUDO_REGISTER	       && find_reg_note (insn, REG_DEAD, SET_SRC (set)))	optimize_reg_copy_2 (insn, dest, SET_SRC (set));      /* Otherwise, we only handle the case of a pseudo register being set	 once and only if neither the source nor the destination are	 in a register class that's likely to be spilled.  */      if (GET_CODE (dest) != REG	  || (regno = REGNO (dest)) < FIRST_PSEUDO_REGISTER	  || REG_N_SETS (regno) != 1	  || CLASS_LIKELY_SPILLED_P (reg_preferred_class (REGNO (dest)))	  || (GET_CODE (src) == REG	      && REGNO (src) >= FIRST_PSEUDO_REGISTER	      && CLASS_LIKELY_SPILLED_P (reg_preferred_class (REGNO (src)))))	continue;      note = find_reg_note (insn, REG_EQUAL, NULL_RTX);      /* Record this insn as initializing this register.  */      reg_equiv_init_insn[regno] = insn;      /* If this register is known to be equal to a constant, record that	 it is always equivalent to the constant.  */      if (note && CONSTANT_P (XEXP (note, 0)))	PUT_MODE (note, (enum machine_mode) REG_EQUIV);      /* If this insn introduces a "constant" register, decrease the priority	 of that register.  Record this insn if the register is only used once	 more and the equivalence value is the same as our source.	 The latter condition is checked for two reasons:  First, it is an	 indication that it may be more efficient to actually emit the insn	 as written (if no registers are available, reload will substitute	 the equivalence).  Secondly, it avoids problems with any registers	 dying in this insn whose death notes would be missed.	 If we don't have a REG_EQUIV note, see if this insn is loading	 a register used only in one basic block from a MEM.  If so, and the	 MEM remains unchanged for the life of the register, add a REG_EQUIV	 note.  */	       note = find_reg_note (insn, REG_EQUIV, NULL_RTX);      if (note == 0 && REG_BASIC_BLOCK (regno) >= 0	  && GET_CODE (SET_SRC (set)) == MEM	  && validate_equiv_mem (insn, dest, SET_SRC (set)))	REG_NOTES (insn) = note = gen_rtx (EXPR_LIST, REG_EQUIV, SET_SRC (set),					   REG_NOTES (insn));      if (note)	{	  int regno = REGNO (dest);	  reg_equiv_replacement[regno] = XEXP (note, 0);	  /* Don't mess with things live during setjmp.  */	  if (REG_LIVE_LENGTH (regno) >= 0)	    {	      /* Note that the statement below does not affect the priority		 in local-alloc!  */	      REG_LIVE_LENGTH (regno) *= 2;	      /* If the register is referenced exactly twice, meaning it is		 set once and used once, indicate that the reference may be		 replaced by the equivalence we computed above.  If the		 register is only used in one basic block, this can't succeed		 or combine would have done it.		 It would be nice to use "loop_depth * 2" in the compare		 below.  Unfortunately, LOOP_DEPTH need not be constant within		 a basic block so this would be too complicated.		 This case normally occurs when a parameter is read from		 memory and then used exactly once, not in a loop.  */		if (REG_N_REFS (regno) == 2		    && REG_BASIC_BLOCK (regno) < 0		    && rtx_equal_p (XEXP (note, 0), SET_SRC (set)))		  reg_equiv_replace[regno] = 1;	    }	}    }  /* Now scan all regs killed in an insn to see if any of them are     registers only used that once.  If so, see if we can replace the     reference with the equivalent from.  If we can, delete the     initializing reference and this register will go away.  If we     can't replace the reference, and the instruction is not in a     loop, then move the register initialization just before the use,     so that they are in the same basic block.  */  block = -1;  depth = 0;  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))    {      rtx link;      /* Keep track of which basic block we are in.  */      if (block + 1 < n_basic_blocks	  && basic_block_head[block + 1] == insn)	++block;      if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')	{	  if (GET_CODE (insn) == NOTE)

⌨️ 快捷键说明

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