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

📄 local-alloc.c

📁 这是完整的gcc源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	      if (GET_CODE (r0) == REG || GET_CODE (r0) == SUBREG)		{		  if (GET_RTX_FORMAT (GET_CODE (SET_SRC (body)))[0] == 'e'		      && (r1 = XEXP (SET_SRC (body), 0),			  GET_CODE (r1) == REG || GET_CODE (r1) == SUBREG))		    win = combine_regs (r1, r0, b, insn_number, insn);		  if (win == 0 && commutative		      && GET_RTX_FORMAT (GET_CODE (SET_SRC (body)))[1] == 'e'		      && (r1 = XEXP (SET_SRC (body), 1),			  GET_CODE (r1) == REG || GET_CODE (r1) == SUBREG))		    win = combine_regs (r1, r0, b, insn_number, insn);		}	    }	  else if (GET_CODE (body) == PARALLEL)	    {	      rtx set1 = XVECEXP (body, 0, 0);	      if (GET_CODE (set1) == SET 		  && (r0 = SET_DEST (set1),		      GET_CODE (r0) == REG || GET_CODE (r0) == SUBREG)		  && GET_RTX_FORMAT (GET_CODE (SET_SRC (set1)))[0] == 'e'		  && (r1 = XEXP (SET_SRC (set1), 0),		      GET_CODE (r1) == REG || GET_CODE (r1) == SUBREG))		win = combine_regs (r1, r0, b, insn_number, insn);	      if (win == 0 && commutative && GET_CODE (set1) == SET 		  && (r0 = SET_DEST (set1),		      GET_CODE (r0) == REG || GET_CODE (r0) == SUBREG)		  && GET_RTX_FORMAT (GET_CODE (SET_SRC (set1)))[1] == 'e'		  && (r1 = XEXP (SET_SRC (set1), 1),		      GET_CODE (r1) == REG || GET_CODE (r1) == SUBREG))		win = combine_regs (r1, r0, b, insn_number, insn);	    }	  /* If registers were just tied, set COMBINED_REGNO	     to the number of the register used in this insn	     that was tied to the register set in this insn.	     This register's qty should not be "killed".  */	  if (win)	    {	      while (GET_CODE (r1) == SUBREG)		r1 = SUBREG_REG (r1);	      combined_regno = REGNO (r1);	    }	  for (link = REG_NOTES (insn); link; link = XEXP (link, 1))	    {	      /* Mark the death of everything that dies in this instruction,		 except for anything that was just combined.  */	      if (XEXP (link, 0)		  && REG_NOTE_KIND (link) == REG_DEAD		  && combined_regno != REGNO (XEXP (link, 0)))		{#if 0  /* The mechanism in reg_is_set that checks whether the qty dies here	  ought to handle this case properly.  */		  if (combined_regno >= 0 &&		      reg_qty[combined_regno] == reg_qty[REGNO (XEXP (link, 0))])		    /* Here for the death of the quotient in a divmod insn:		       something that was born and dead in this insn		       but combined with something else that also dies here.		       Mark the qty as dying one instruction later.  */		    wipe_dead_reg (XEXP (link, 0), insn_number,				   insn_number + 1);		  else#endif		    wipe_dead_reg (XEXP (link, 0), insn_number, insn_number);		}	      /* Also, if this insn introduces a "constant" register,		 that could just be replaced by the value it is given here		 (which can legitimately be an immediate operand),		 tell global-alloc not to allocate it		 unless it is used at least twice more.  */	      else if (REG_NOTE_KIND (link) == REG_EQUIV		       && GET_CODE (SET_DEST (body)) == REG		       && general_operand (XEXP (link, 0), VOIDmode)		       /* Don't inhibit allocation of a "constant" register			  that we have already tied to something else!  */		       && combined_regno < 0		       /* Don't mess with things live during setjmp.  */		       && reg_live_length[REGNO (SET_DEST (body))] >= 0)		{		  i = REGNO (SET_DEST (body));		  if (reg_n_sets[i] > 1)		    {		      /* Register is set in another place => not really constant.			 cse or flow can cause this to happen.			 Ok, forget we ever thought it was constant.  */		      GET_MODE (link) = VOIDmode;		    }		  else if (reg_n_refs[i] <= 2)		    {		      /* For a parameter copy, do let global-alloc			 allocate it; otherwise we would be forced to			 have a frame pointer.  */		      if (! frame_pointer_needed			  && GET_CODE (SET_SRC (PATTERN (insn))) == MEM)			reg_live_length[i] = -2;		      else			reg_live_length[i] = -1;		      /* If value is not constant, we have a parameter			 or a static chain pointer.  Tell local-alloc			 as well not to allocate it.  */		      if (! CONSTANT_P (SET_SRC (PATTERN (insn))))			{			  reg_basic_block[i] = REG_BLOCK_GLOBAL;			  reg_qty[i] = -1;			}		    }		  else		    /* In any case, lower its priority for global-alloc.  */		    reg_live_length[i] *= 2;		}	    }	  /* Allocate qty numbers for all registers local to this block	     that are born (set) in this instruction.	     A pseudo that already has a qty is not changed.  */	  note_stores (PATTERN (insn), reg_is_set);	}      if (GET_CODE (insn) == CALL_INSN)	call_seen = 1;      if (insn == basic_block_end[b])	break;      /* We don't need this for the block's first instruction	 since no regs we care about are live before that instruction.	 Also we do not allocate space in regs_live_at for that instruction. */      IOR_HARD_REG_SET (regs_live_at[insn_number], regs_live);      insn = NEXT_INSN (insn);    }  /* Now every register that is local to this basic block     should have been given a quantity, or else -1 meaning ignore it.     Every quantity should have a known birth (verify this now).     If a qty's death has not been established, it indicates a dead store.     That is ok if the insn is not entirely dead.     So set the qty'd death to just after its birth.  */  for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)    if (reg_basic_block[i] == b && reg_qty[i] >= 0)      {	/* In the case of a register that is used uninitialized,	   the code above will miss the actual first use.	   So count that first use as the birth.  */  	if (qty_birth[reg_qty[i]] > insn_map[INSN_UID (reg_first_use[i])])	  qty_birth[reg_qty[i]] = insn_map[INSN_UID (reg_first_use[i])];      }  for (i = FIRST_PSEUDO_REGISTER; i < next_qty; i++)    {      if (qty_birth[i] == -1)	abort ();      if (qty_death[i] == -1)	qty_death[i] = qty_birth[i] + 1;    }  /* Now order the qtys so we assign them registers     in order of decreasing length of life.  */  qty_order = (short *) alloca (next_qty * sizeof (short));  for (i = FIRST_PSEUDO_REGISTER; i < next_qty; i++)    qty_order[i] = i;#define EXCHANGE(I1, I2)  \  { i = qty_order[I1]; qty_order[I1] = qty_order[I2]; qty_order[I2] = i; }  if (next_qty == 2 + FIRST_PSEUDO_REGISTER)    {      if (qty_compare (FIRST_PSEUDO_REGISTER, FIRST_PSEUDO_REGISTER + 1) > 0)	EXCHANGE (FIRST_PSEUDO_REGISTER, FIRST_PSEUDO_REGISTER + 1);    }  else if (next_qty == 3 + FIRST_PSEUDO_REGISTER)    {      if (qty_compare (FIRST_PSEUDO_REGISTER, FIRST_PSEUDO_REGISTER + 1) > 0)	EXCHANGE (FIRST_PSEUDO_REGISTER, FIRST_PSEUDO_REGISTER + 1);      if (qty_compare (FIRST_PSEUDO_REGISTER + 1, FIRST_PSEUDO_REGISTER + 2) > 0)	EXCHANGE (FIRST_PSEUDO_REGISTER + 2, FIRST_PSEUDO_REGISTER + 1);      if (qty_compare (FIRST_PSEUDO_REGISTER, FIRST_PSEUDO_REGISTER + 1) > 0)	EXCHANGE (FIRST_PSEUDO_REGISTER, FIRST_PSEUDO_REGISTER + 1);    }  else if (next_qty > 3 + FIRST_PSEUDO_REGISTER)    qsort (qty_order + FIRST_PSEUDO_REGISTER,	   next_qty - FIRST_PSEUDO_REGISTER, sizeof (short), qty_compare_1);  /* Now for each qty that is not a hardware register,     look for a hardware register to put it in.     First try the register class that is cheapest for this qty,     if there is more than one class.  */  for (i = FIRST_PSEUDO_REGISTER; i < next_qty; i++)    {      q = qty_order[i];      if (qty_size[q] >= 0)	{	  if (N_REG_CLASSES > 1)	    {	      qty_phys_reg[q] = find_free_reg (qty_min_class[q], 					       qty_mode[q], q, 0,					       qty_birth[q], qty_death[q]);	      if (qty_phys_reg[q] >= 0)		continue;	    }	  if (!qty_preferred_or_nothing[q])	    qty_phys_reg[q] = find_free_reg (GENERAL_REGS, 					     qty_mode[q], q, 0,					     qty_birth[q], qty_death[q]);	}    }  /* Now propagate the register assignments     to the pseudo regs belonging to the qtys.  */  for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)    if (reg_qty[i] >= 0 && qty_phys_reg[reg_qty[i]] >= 0)      {	reg_renumber[i] = qty_phys_reg[reg_qty[i]] + reg_offset[i];      }}/* Compare two quantities' priority for getting real registers.   We give quantities with hard-reg suggestions priority over all others.   We give longer-lived quantities higher priority   so that the shorter-lived ones will tend to be in the same places   which gives in general the maximum room for the regs to   be allocated by global-alloc.   Regs with more references are also preferred.  */static intqty_compare (q1, q2)     int q1, q2;{  register int tem = (qty_phys_sugg[q2] >= 0) - (qty_phys_sugg[q1] >= 0);  if (tem != 0) return tem;  return -((qty_n_refs[q1] + qty_death[q1] - qty_birth[q1]) * qty_size[q2]	   - (qty_n_refs[q2] + qty_death[q2] - qty_birth[q2]) * qty_size[q1]);}static intqty_compare_1 (q1, q2)     short *q1, *q2;{  register int tem = (qty_phys_sugg[*q2] >= 0) - (qty_phys_sugg[*q1] >= 0);  if (tem != 0) return tem;  tem = -((qty_n_refs[*q1] + qty_death[*q1] - qty_birth[*q1]) * qty_size[*q2]	  - (qty_n_refs[*q2] + qty_death[*q2] - qty_birth[*q2]) * qty_size[*q1]);  if (tem != 0) return tem;  /* If qtys are equally good, sort by qty number,     so that the results of qsort leave nothing to chance.  */  return *q1 - *q2;}/* Attempt to combine the two registers (rtx's) USEDREG and SETREG.   Returns 1 if have done so, or 0 if cannot.   Combining registers means marking them as having the same quantity   and adjusting the offsets within the quantity if either of   them is a SUBREG).   We don't actually combine a hard reg with a pseudo; instead   we just record the hard reg as the suggestion for the pseudo's quantity.   If we really combined them, we could lose if the pseudo lives   across an insn that clobbers the hard reg (eg, movstr).   There are elaborate checks for the validity of combining.  */   static intcombine_regs (usedreg, setreg, b, insn_number, insn)     rtx usedreg, setreg;     int b;     int insn_number;     rtx insn;{  register int ureg, sreg;  register int offset = 0;  int usize, ssize;  register int sqty;  /* Determine the numbers and sizes of registers being used.  */  while (GET_CODE (usedreg) == SUBREG)    {      offset += SUBREG_WORD (usedreg);      usedreg = SUBREG_REG (usedreg);    }  if (GET_CODE (usedreg) != REG)    return 0;  ureg = REGNO (usedreg);  usize = REG_SIZE (usedreg);  while (GET_CODE (setreg) == SUBREG)    {      offset -= SUBREG_WORD (setreg);      setreg = SUBREG_REG (setreg);    }  if (GET_CODE (setreg) != REG)    return 0;  sreg = REGNO (setreg);  ssize = REG_SIZE (setreg);  /* Do not combine registers unless one fits within the other.  */  if (offset > 0 && usize + offset > ssize)    return 0;  if (offset < 0 && usize + offset < ssize)    return 0;  /* Do not combine with a smaller already-assigned object     if that smaller object is already combined with something bigger     or if that smaller object is a hard reg.     In the latter case, we would implicitly be using consecutive     hard regs, and there is no code to keep track of that.     (This is overcautious; we could check that ssize actually     requires more hard regs at this spot.)  */  if (ssize > usize && reg_qty[ureg] >= FIRST_PSEUDO_REGISTER      && usize < qty_size[reg_qty[ureg]])    return 0;  /* Don't do anything with the non-allocatable registers.     Also, don't suggest a call-clobberable register     for something that must live across calls.     Also, don't suggest a hardware register for anything larger than it.  */  if (ureg < FIRST_PSEUDO_REGISTER)    {      if (fixed_regs[ureg])	return 0;      if (reg_n_calls_crossed[sreg] != 0 && call_used_regs[ureg])	return 0;      if (usize < ssize)	return 0;    }  if (sreg < FIRST_PSEUDO_REGISTER)    {      if (fixed_regs[sreg])	return 0;      if (reg_n_calls_crossed[ureg] != 0 && call_used_regs[sreg])	return 0;      if (ssize < usize)	return 0;    }  /* Don't tie something to itself.  In most cases it would make no     difference, but it would screw up if the reg being tied to itself     also dies in this insn.  */  if (ureg == sreg)    return 0;   /* Don't try to connect two different hardware registers.  */  if (ureg < FIRST_PSEUDO_REGISTER && sreg < FIRST_PSEUDO_REGISTER)    return 0;  /* Don't connect two different machine modes if they have different     implications as to which registers may be used.  */  if (!MODES_TIEABLE_P (GET_MODE (usedreg), GET_MODE (setreg)))    return 0;  /* Now, if one of UREG and SREG is a hard reg and the other is     a pseudo, record the hard reg as the qty_phys_sugg for the pseudo     instead of tying them.  */  /* Return "failure" so that the lifespan of UREG is terminated here;     that way the two lifespans will be disjoint and nothing will prevent     the pseudo reg from being given this hard reg.  */  if (ureg < FIRST_PSEUDO_REGISTER)    {      if (reg_qty[sreg] == -2)	reg_is_born (setreg, insn_number);      if (reg_qty[ureg] == -2)	reg_is_born (usedreg, insn_number);      if (reg_qty[sreg] >= 0)	qty_phys_sugg[reg_qty[sreg]] = ureg;      return 0;    }  if (sreg < FIRST_PSEUDO_REGISTER)    {      if (reg_qty[sreg] == -2)	reg_is_born (setreg, insn_number);      if (reg_qty[ureg] == -2)	reg_is_born (usedreg, insn_number);      /* If UREG already has a suggested hard reg, don't override it,	 since the most likely case is on a risc machine	 when a pseudo gets a subroutine result and is then returned by	 this function.  In this case, the outgoing register window	 is probably a better place to use.  */      if (reg_qty[ureg] >= 0	  && (qty_phys_sugg[reg_qty[ureg]] < 0	      /* If the old suggestion is no good, override it.  */	      || (qty_n_calls_crossed[reg_qty[ureg]] != 0		  && call_used_regs[qty_phys_sugg[reg_qty[ureg]]])))	qty_phys_sugg[reg_qty[ureg]] = sreg;      return 0;    }  /* Do nothing if SREG is a pseudo that already has a quantity     or if it isn't local to this basic block or dies more than once.  */  if (reg_qty[sreg] != -2)    return 0;  /* Do nothing if UREG isn't local to this block or dies more than once.     We do this because global_alloc has no idea of tying,     so there is no use noting those local pseudos that could     profitably be delayed till global_alloc and get tied to global ones.  */  if (reg_qty[ureg] == -1)    return 0;

⌨️ 快捷键说明

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