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

📄 local-alloc.c

📁 gcc库的原代码,对编程有很大帮助.
💻 C
📖 第 1 页 / 共 5 页
字号:
  register int b, i;  int max_qty;  /* Leaf functions and non-leaf functions have different needs.     If defined, let the machine say what kind of ordering we     should use.  */#ifdef ORDER_REGS_FOR_LOCAL_ALLOC  ORDER_REGS_FOR_LOCAL_ALLOC;#endif  /* Promote REG_EQUAL notes to REG_EQUIV notes and adjust status of affected     registers.  */  update_equiv_regs ();  /* This sets the maximum number of quantities we can have.  Quantity     numbers start at zero and we can have one for each pseudo plus the     number of SCRATCHes in the largest block, in the worst case.  */  max_qty = (max_regno - FIRST_PSEUDO_REGISTER) + max_scratch;  /* Allocate vectors of temporary data.     See the declarations of these variables, above,     for what they mean.  */  /* There can be up to MAX_SCRATCH * N_BASIC_BLOCKS SCRATCHes to allocate.     Instead of allocating this much memory from now until the end of     reload, only allocate space for MAX_QTY SCRATCHes.  If there are more     reload will allocate them.  */  scratch_list_length = max_qty;  scratch_list = (rtx *) xmalloc (scratch_list_length * sizeof (rtx));  bzero ((char *) scratch_list, scratch_list_length * sizeof (rtx));  scratch_block = (int *) xmalloc (scratch_list_length * sizeof (int));  bzero ((char *) scratch_block, scratch_list_length * sizeof (int));  scratch_index = 0;  qty_phys_reg = (short *) alloca (max_qty * sizeof (short));  qty_phys_copy_sugg    = (HARD_REG_SET *) alloca (max_qty * sizeof (HARD_REG_SET));  qty_phys_num_copy_sugg = (short *) alloca (max_qty * sizeof (short));  qty_phys_sugg = (HARD_REG_SET *) alloca (max_qty * sizeof (HARD_REG_SET));  qty_phys_num_sugg = (short *) alloca (max_qty * sizeof (short));  qty_birth = (int *) alloca (max_qty * sizeof (int));  qty_death = (int *) alloca (max_qty * sizeof (int));  qty_scratch_rtx = (rtx *) alloca (max_qty * sizeof (rtx));  qty_first_reg = (int *) alloca (max_qty * sizeof (int));  qty_size = (int *) alloca (max_qty * sizeof (int));  qty_mode    = (enum machine_mode *) alloca (max_qty * sizeof (enum machine_mode));  qty_n_calls_crossed = (int *) alloca (max_qty * sizeof (int));  qty_min_class    = (enum reg_class *) alloca (max_qty * sizeof (enum reg_class));  qty_alternate_class    = (enum reg_class *) alloca (max_qty * sizeof (enum reg_class));  qty_n_refs = (int *) alloca (max_qty * sizeof (int));  qty_changes_size = (char *) alloca (max_qty * sizeof (char));  reg_qty = (int *) alloca (max_regno * sizeof (int));  reg_offset = (char *) alloca (max_regno * sizeof (char));  reg_next_in_qty = (int *) alloca (max_regno * sizeof (int));  reg_renumber = (short *) oballoc (max_regno * sizeof (short));  for (i = 0; i < max_regno; i++)    reg_renumber[i] = -1;  /* Determine which pseudo-registers can be allocated by local-alloc.     In general, these are the registers used only in a single block and     which only die once.  However, if a register's preferred class has only     a few entries, don't allocate this register here unless it is preferred     or nothing since retry_global_alloc won't be able to move it to     GENERAL_REGS if a reload register of this class is needed.     We need not be concerned with which block actually uses the register     since we will never see it outside that block.  */  for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)    {      if (reg_basic_block[i] >= 0 && reg_n_deaths[i] == 1	  && (reg_alternate_class (i) == NO_REGS	      || ! CLASS_LIKELY_SPILLED_P (reg_preferred_class (i))))	reg_qty[i] = -2;      else	reg_qty[i] = -1;    }  /* Force loop below to initialize entire quantity array.  */  next_qty = max_qty;  /* Allocate each block's local registers, block by block.  */  for (b = 0; b < n_basic_blocks; b++)    {      /* NEXT_QTY indicates which elements of the `qty_...'	 vectors might need to be initialized because they were used	 for the previous block; it is set to the entire array before	 block 0.  Initialize those, with explicit loop if there are few,	 else with bzero and bcopy.  Do not initialize vectors that are	 explicit set by `alloc_qty'.  */      if (next_qty < 6)	{	  for (i = 0; i < next_qty; i++)	    {	      qty_scratch_rtx[i] = 0;	      CLEAR_HARD_REG_SET (qty_phys_copy_sugg[i]);	      qty_phys_num_copy_sugg[i] = 0;	      CLEAR_HARD_REG_SET (qty_phys_sugg[i]);	      qty_phys_num_sugg[i] = 0;	    }	}      else	{#define CLEAR(vector)  \	  bzero ((char *) (vector), (sizeof (*(vector))) * next_qty);	  CLEAR (qty_scratch_rtx);	  CLEAR (qty_phys_copy_sugg);	  CLEAR (qty_phys_num_copy_sugg);	  CLEAR (qty_phys_sugg);	  CLEAR (qty_phys_num_sugg);	}      next_qty = 0;      block_alloc (b);#ifdef USE_C_ALLOCA      alloca (0);#endif    }}/* Depth of loops we are in while in update_equiv_regs.  */static int loop_depth;/* Used for communication between the following two functions: contains   a MEM that we wish to ensure remains unchanged.  */static rtx equiv_mem;/* Set nonzero if EQUIV_MEM is modified.  */static int equiv_mem_modified;/* If EQUIV_MEM is modified by modifying DEST, indicate that it is modified.   Called via note_stores.  */static voidvalidate_equiv_mem_from_store (dest, set)     rtx dest;     rtx set;{  if ((GET_CODE (dest) == REG       && reg_overlap_mentioned_p (dest, equiv_mem))      || (GET_CODE (dest) == MEM	  && true_dependence (dest, equiv_mem)))    equiv_mem_modified = 1;}/* Verify that no store between START and the death of REG invalidates   MEMREF.  MEMREF is invalidated by modifying a register used in MEMREF,   by storing into an overlapping memory location, or with a non-const   CALL_INSN.   Return 1 if MEMREF remains valid.  */static intvalidate_equiv_mem (start, reg, memref)     rtx start;     rtx reg;     rtx memref;{  rtx insn;  rtx note;  equiv_mem = memref;  equiv_mem_modified = 0;  /* If the memory reference has side effects or is volatile, it isn't a     valid equivalence.  */  if (side_effects_p (memref))    return 0;  for (insn = start; insn && ! equiv_mem_modified; insn = NEXT_INSN (insn))    {      if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')	continue;      if (find_reg_note (insn, REG_DEAD, reg))	return 1;      if (GET_CODE (insn) == CALL_INSN && ! RTX_UNCHANGING_P (memref)	  && ! CONST_CALL_P (insn))	return 0;      note_stores (PATTERN (insn), validate_equiv_mem_from_store);      /* If a register mentioned in MEMREF is modified via an	 auto-increment, we lose the equivalence.  Do the same if one	 dies; although we could extend the life, it doesn't seem worth	 the trouble.  */      for (note = REG_NOTES (insn); note; note = XEXP (note, 1))	if ((REG_NOTE_KIND (note) == REG_INC	     || REG_NOTE_KIND (note) == REG_DEAD)	    && GET_CODE (XEXP (note, 0)) == REG	    && reg_overlap_mentioned_p (XEXP (note, 0), memref))	  return 0;    }  return 0;}/* TRUE if X references a memory location that would be affected by a store   to MEMREF.  */static intmemref_referenced_p (memref, x)     rtx x;     rtx memref;{  int i, j;  char *fmt;  enum rtx_code code = GET_CODE (x);  switch (code)    {    case REG:    case CONST_INT:    case CONST:    case LABEL_REF:    case SYMBOL_REF:    case CONST_DOUBLE:    case PC:    case CC0:    case HIGH:    case LO_SUM:      return 0;    case MEM:      if (true_dependence (memref, x))	return 1;      break;    case SET:      /* If we are setting a MEM, it doesn't count (its address does), but any	 other SET_DEST that has a MEM in it is referencing the MEM.  */      if (GET_CODE (SET_DEST (x)) == MEM)	{	  if (memref_referenced_p (memref, XEXP (SET_DEST (x), 0)))	    return 1;	}      else if (memref_referenced_p (memref, SET_DEST (x)))	return 1;      return memref_referenced_p (memref, SET_SRC (x));    }  fmt = GET_RTX_FORMAT (code);  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)    switch (fmt[i])      {      case 'e':	if (memref_referenced_p (memref, XEXP (x, i)))	  return 1;	break;      case 'E':	for (j = XVECLEN (x, i) - 1; j >= 0; j--)	  if (memref_referenced_p (memref, XVECEXP (x, i, j)))	    return 1;	break;      }  return 0;}/* TRUE if some insn in the range (START, END] references a memory location   that would be affected by a store to MEMREF.  */static intmemref_used_between_p (memref, start, end)     rtx memref;     rtx start;     rtx end;{  rtx insn;  for (insn = NEXT_INSN (start); insn != NEXT_INSN (end);       insn = NEXT_INSN (insn))    if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'	&& memref_referenced_p (memref, PATTERN (insn)))      return 1;  return 0;}/* INSN is a copy from SRC to DEST, both registers, and SRC does not die   in INSN.   Search forward to see if SRC dies before either it or DEST is modified,   but don't scan past the end of a basic block.  If so, we can replace SRC   with DEST and let SRC die in INSN.    This will reduce the number of registers live in that range and may enable   DEST to be tied to SRC, thus often saving one register in addition to a   register-register copy.  */static voidoptimize_reg_copy_1 (insn, dest, src)     rtx insn;     rtx dest;     rtx src;{  rtx p, q;  rtx note;  rtx dest_death = 0;  int sregno = REGNO (src);  int dregno = REGNO (dest);  if (sregno == dregno#ifdef SMALL_REGISTER_CLASSES      /* We don't want to mess with hard regs if register classes are small. */      || sregno < FIRST_PSEUDO_REGISTER || dregno < FIRST_PSEUDO_REGISTER#endif      /* We don't see all updates to SP if they are in an auto-inc memory	 reference, so we must disallow this optimization on them.  */      || sregno == STACK_POINTER_REGNUM || dregno == STACK_POINTER_REGNUM)    return;  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;      if (reg_set_p (src, p) || reg_set_p (dest, p)	  /* Don't change a USE of a register.  */	  || (GET_CODE (PATTERN (p)) == USE	      && reg_overlap_mentioned_p (src, XEXP (PATTERN (p), 0))))	break;      /* See if all of SRC dies in P.  This test is slightly more	 conservative than it needs to be. */      if ((note = find_regno_note (p, REG_DEAD, sregno)) != 0	  && GET_MODE (XEXP (note, 0)) == GET_MODE (src))	{	  int failed = 0;	  int length = 0;	  int d_length = 0;	  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;		    }		}

⌨️ 快捷键说明

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