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

📄 flow.c

📁 GUN开源阻止下的编译器GCC
💻 C
📖 第 1 页 / 共 5 页
字号:
	      cc0_live = 0;	      if (! insn_is_dead)		mark_used_regs (old, live, PATTERN (insn), final, insn);	      /* Sometimes we may have inserted something before INSN (such as		 a move) when we make an auto-inc.  So ensure we will scan		 those insns.  */#ifdef AUTO_INC_DEC	      prev = PREV_INSN (insn);#endif	      if (! insn_is_dead && GET_CODE (insn) == CALL_INSN)		{		  register int i;		  rtx note;	          for (note = CALL_INSN_FUNCTION_USAGE (insn);		       note;		       note = XEXP (note, 1))		    if (GET_CODE (XEXP (note, 0)) == USE)		      mark_used_regs (old, live, SET_DEST (XEXP (note, 0)),				      final, insn);		  /* Each call clobbers all call-clobbered regs that are not		     global.  Note that the function-value reg is a		     call-clobbered reg, and mark_set_regs has already had		     a chance to handle it.  */		  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)		    if (call_used_regs[i] && ! global_regs[i])		      dead[i / REGSET_ELT_BITS]			|= ((REGSET_ELT_TYPE) 1 << (i % REGSET_ELT_BITS));		  /* The stack ptr is used (honorarily) by a CALL insn.  */		  live[STACK_POINTER_REGNUM / REGSET_ELT_BITS]		    |= ((REGSET_ELT_TYPE) 1			<< (STACK_POINTER_REGNUM % REGSET_ELT_BITS));		  /* Calls may also reference any of the global registers,		     so they are made live.  */		  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)		    if (global_regs[i])		      mark_used_regs (old, live,				      gen_rtx (REG, reg_raw_mode[i], i),				      final, insn);		  /* Calls also clobber memory.  */		  last_mem_set = 0;		}	      /* Update OLD for the registers used or set.  */	      for (i = 0; i < regset_size; i++)		{		  old[i] &= ~dead[i];		  old[i] |= live[i];		}	      if (GET_CODE (insn) == CALL_INSN && final)		{		  /* Any regs live at the time of a call instruction		     must not go in a register clobbered by calls.		     Find all regs now live and record this for them.  */		  register struct sometimes *p = regs_sometimes_live;		  for (i = 0; i < sometimes_max; i++, p++)		    if (old[p->offset] & ((REGSET_ELT_TYPE) 1 << p->bit))		      reg_n_calls_crossed[p->offset * REGSET_ELT_BITS + p->bit]+= 1;		}	    }	  /* On final pass, add any additional sometimes-live regs	     into MAXLIVE and REGS_SOMETIMES_LIVE.	     Also update counts of how many insns each reg is live at.  */	  if (final)	    {	      for (i = 0; i < regset_size; i++)		{		  register REGSET_ELT_TYPE diff = live[i] & ~maxlive[i];		  if (diff)		    {		      register int regno;		      maxlive[i] |= diff;		      for (regno = 0; diff && regno < REGSET_ELT_BITS; regno++)			if (diff & ((REGSET_ELT_TYPE) 1 << regno))			  {			    regs_sometimes_live[sometimes_max].offset = i;			    regs_sometimes_live[sometimes_max].bit = regno;			    diff &= ~ ((REGSET_ELT_TYPE) 1 << regno);			    sometimes_max++;			  }		    }		}	      {		register struct sometimes *p = regs_sometimes_live;		for (i = 0; i < sometimes_max; i++, p++)		  {		    if (old[p->offset] & ((REGSET_ELT_TYPE) 1 << p->bit))		      reg_live_length[p->offset * REGSET_ELT_BITS + p->bit]++;		  }	      }	    }	}    flushed: ;      if (insn == first)	break;    }  if (num_scratch > max_scratch)    max_scratch = num_scratch;}/* Return 1 if X (the body of an insn, or part of it) is just dead stores   (SET expressions whose destinations are registers dead after the insn).   NEEDED is the regset that says which regs are alive after the insn.   Unless CALL_OK is non-zero, an insn is needed if it contains a CALL.  */static intinsn_dead_p (x, needed, call_ok)     rtx x;     regset needed;     int call_ok;{  register RTX_CODE code = GET_CODE (x);  /* If setting something that's a reg or part of one,     see if that register's altered value will be live.  */  if (code == SET)    {      register rtx r = SET_DEST (x);      /* A SET that is a subroutine call cannot be dead.  */      if (! call_ok && GET_CODE (SET_SRC (x)) == CALL)	return 0;#ifdef HAVE_cc0      if (GET_CODE (r) == CC0)	return ! cc0_live;#endif            if (GET_CODE (r) == MEM && last_mem_set && ! MEM_VOLATILE_P (r)	  && rtx_equal_p (r, last_mem_set))	return 1;      while (GET_CODE (r) == SUBREG	     || GET_CODE (r) == STRICT_LOW_PART	     || GET_CODE (r) == ZERO_EXTRACT	     || GET_CODE (r) == SIGN_EXTRACT)	r = SUBREG_REG (r);      if (GET_CODE (r) == REG)	{	  register int regno = REGNO (r);	  register int offset = regno / REGSET_ELT_BITS;	  register REGSET_ELT_TYPE bit	    = (REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS);	  /* Don't delete insns to set global regs.  */	  if ((regno < FIRST_PSEUDO_REGISTER && global_regs[regno])	      /* Make sure insns to set frame pointer aren't deleted.  */	      || regno == FRAME_POINTER_REGNUM#if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM	      || regno == HARD_FRAME_POINTER_REGNUM#endif#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM	      /* Make sure insns to set arg pointer are never deleted		 (if the arg pointer isn't fixed, there will be a USE for		 it, so we can treat it normally). */	      || (regno == ARG_POINTER_REGNUM && fixed_regs[regno])#endif	      || (needed[offset] & bit) != 0)	    return 0;	  /* If this is a hard register, verify that subsequent words are	     not needed.  */	  if (regno < FIRST_PSEUDO_REGISTER)	    {	      int n = HARD_REGNO_NREGS (regno, GET_MODE (r));	      while (--n > 0)		if ((needed[(regno + n) / REGSET_ELT_BITS]		     & ((REGSET_ELT_TYPE) 1			<< ((regno + n) % REGSET_ELT_BITS))) != 0)		  return 0;	    }	  return 1;	}    }  /* If performing several activities,     insn is dead if each activity is individually dead.     Also, CLOBBERs and USEs can be ignored; a CLOBBER or USE     that's inside a PARALLEL doesn't make the insn worth keeping.  */  else if (code == PARALLEL)    {      register int i = XVECLEN (x, 0);      for (i--; i >= 0; i--)	{	  rtx elt = XVECEXP (x, 0, i);	  if (!insn_dead_p (elt, needed, call_ok)	      && GET_CODE (elt) != CLOBBER	      && GET_CODE (elt) != USE)	    return 0;	}      return 1;    }  /* We do not check CLOBBER or USE here.     An insn consisting of just a CLOBBER or just a USE     should not be deleted.  */  return 0;}/* If X is the pattern of the last insn in a libcall, and assuming X is dead,   return 1 if the entire library call is dead.   This is true if X copies a register (hard or pseudo)   and if the hard return  reg of the call insn is dead.   (The caller should have tested the destination of X already for death.)   If this insn doesn't just copy a register, then we don't   have an ordinary libcall.  In that case, cse could not have   managed to substitute the source for the dest later on,   so we can assume the libcall is dead.   NEEDED is the bit vector of pseudoregs live before this insn.   NOTE is the REG_RETVAL note of the insn.  INSN is the insn itself.  */static intlibcall_dead_p (x, needed, note, insn)     rtx x;     regset needed;     rtx note;     rtx insn;{  register RTX_CODE code = GET_CODE (x);  if (code == SET)    {      register rtx r = SET_SRC (x);      if (GET_CODE (r) == REG)	{	  rtx call = XEXP (note, 0);	  register int i;	  /* Find the call insn.  */	  while (call != insn && GET_CODE (call) != CALL_INSN)	    call = NEXT_INSN (call);	  /* If there is none, do nothing special,	     since ordinary death handling can understand these insns.  */	  if (call == insn)	    return 0;	  /* See if the hard reg holding the value is dead.	     If this is a PARALLEL, find the call within it.  */	  call = PATTERN (call);	  if (GET_CODE (call) == PARALLEL)	    {	      for (i = XVECLEN (call, 0) - 1; i >= 0; i--)		if (GET_CODE (XVECEXP (call, 0, i)) == SET		    && GET_CODE (SET_SRC (XVECEXP (call, 0, i))) == CALL)		  break;	      /* This may be a library call that is returning a value		 via invisible pointer.  Do nothing special, since		 ordinary death handling can understand these insns.  */	      if (i < 0)		return 0;	      call = XVECEXP (call, 0, i);	    }	  return insn_dead_p (call, needed, 1);	}    }  return 1;}/* Return 1 if register REGNO was used before it was set.   In other words, if it is live at function entry.   Don't count global register variables, though.  */intregno_uninitialized (regno)     int regno;{  if (n_basic_blocks == 0      || (regno < FIRST_PSEUDO_REGISTER && global_regs[regno]))    return 0;  return (basic_block_live_at_start[0][regno / REGSET_ELT_BITS]	  & ((REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS)));}/* 1 if register REGNO was alive at a place where `setjmp' was called   and was set more than once or is an argument.   Such regs may be clobbered by `longjmp'.  */intregno_clobbered_at_setjmp (regno)     int regno;{  if (n_basic_blocks == 0)    return 0;  return ((reg_n_sets[regno] > 1	   || (basic_block_live_at_start[0][regno / REGSET_ELT_BITS]	       & ((REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS))))	  && (regs_live_at_setjmp[regno / REGSET_ELT_BITS]	      & ((REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS))));}/* Process the registers that are set within X.   Their bits are set to 1 in the regset DEAD,   because they are dead prior to this insn.   If INSN is nonzero, it is the insn being processed   and the fact that it is nonzero implies this is the FINAL pass   in propagate_block.  In this case, various info about register   usage is stored, LOG_LINKS fields of insns are set up.  */static voidmark_set_regs (needed, dead, x, insn, significant)     regset needed;     regset dead;     rtx x;     rtx insn;     regset significant;{  register RTX_CODE code = GET_CODE (x);  if (code == SET || code == CLOBBER)    mark_set_1 (needed, dead, x, insn, significant);  else if (code == PARALLEL)    {      register int i;      for (i = XVECLEN (x, 0) - 1; i >= 0; i--)	{	  code = GET_CODE (XVECEXP (x, 0, i));	  if (code == SET || code == CLOBBER)	    mark_set_1 (needed, dead, XVECEXP (x, 0, i), insn, significant);	}    }}/* Process a single SET rtx, X.  */static voidmark_set_1 (needed, dead, x, insn, significant)     regset needed;     regset dead;     rtx x;     rtx insn;     regset significant;{  register int regno;  register rtx reg = SET_DEST (x);  /* Modifying just one hardware register of a multi-reg value     or just a byte field of a register     does not mean the value from before this insn is now dead.     But it does mean liveness of that register at the end of the block     is significant.     Within mark_set_1, however, we treat it as if the register is     indeed modified.  mark_used_regs will, however, also treat this     register as being used.  Thus, we treat these insns as setting a     new value for the register as a function of its old value.  This     cases LOG_LINKS to be made appropriately and this will help combine.  */  while (GET_CODE (reg) == SUBREG || GET_CODE (reg) == ZERO_EXTRACT	 || GET_CODE (reg) == SIGN_EXTRACT	 || GET_CODE (reg) == STRICT_LOW_PART)    reg = XEXP (reg, 0);  /* If we are writing into memory or into a register mentioned in the     address of the last thing stored into memory, show we don't know     what the last store was.  If we are writing memory, save the address     unless it is volatile.  */  if (GET_CODE (reg) == MEM      || (GET_CODE (reg) == REG	  && last_mem_set != 0 && reg_overlap_mentioned_p (reg, last_mem_set)))    last_mem_set = 0;      if (GET_CODE (reg) == MEM && ! side_effects_p (reg)      /* There are no REG_INC notes for SP, so we can't assume we'll see 	 everything that invalidates it.  To be safe, don't eliminate any	 stores though SP; none of them should be redundant anyway.  */      && ! reg_mentioned_p (stack_pointer_rtx, reg))    last_mem_

⌨️ 快捷键说明

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