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

📄 flow.c

📁 GCC编译器源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
				   REG_BASIC_BLOCK (i) = -1;				 }			     });  free_regset_vector (basic_block_live_at_end, n_basic_blocks);  free_regset_vector (basic_block_new_live_at_end, n_basic_blocks);  free_regset_vector (basic_block_significant, n_basic_blocks);  basic_block_live_at_end = (regset *)0;  basic_block_new_live_at_end = (regset *)0;  basic_block_significant = (regset *)0;  obstack_free (&flow_obstack, NULL_PTR);}/* Subroutines of life analysis.  *//* Allocate the permanent data structures that represent the results   of life analysis.  Not static since used also for stupid life analysis.  */voidallocate_for_life_analysis (){  register int i;  /* Recalculate the register space, in case it has grown.  Old style     vector oriented regsets would set regset_{size,bytes} here also.  */  allocate_reg_info (max_regno, FALSE, FALSE);  /* Because both reg_scan and flow_analysis want to set up the REG_N_SETS     information, explicitly reset it here.  The allocation should have     already happened on the previous reg_scan pass.  Make sure in case     some more registers were allocated.  */  for (i = 0; i < max_regno; i++)    REG_N_SETS (i) = 0;  basic_block_live_at_start    = (regset *) oballoc (n_basic_blocks * sizeof (regset));  init_regset_vector (basic_block_live_at_start, n_basic_blocks,		      function_obstack);  regs_live_at_setjmp = OBSTACK_ALLOC_REG_SET (function_obstack);  CLEAR_REG_SET (regs_live_at_setjmp);}/* Make each element of VECTOR point at a regset.  The vector has   NELTS elements, and space is allocated from the ALLOC_OBSTACK   obstack.  */voidinit_regset_vector (vector, nelts, alloc_obstack)     regset *vector;     int nelts;     struct obstack *alloc_obstack;{  register int i;  for (i = 0; i < nelts; i++)    {      vector[i] = OBSTACK_ALLOC_REG_SET (alloc_obstack);      CLEAR_REG_SET (vector[i]);    }}/* Release any additional space allocated for each element of VECTOR point   other than the regset header itself.  The vector has NELTS elements.  */voidfree_regset_vector (vector, nelts)     regset *vector;     int nelts;{  register int i;  for (i = 0; i < nelts; i++)    FREE_REG_SET (vector[i]);}/* Compute the registers live at the beginning of a basic block   from those live at the end.   When called, OLD contains those live at the end.   On return, it contains those live at the beginning.   FIRST and LAST are the first and last insns of the basic block.   FINAL is nonzero if we are doing the final pass which is not   for computing the life info (since that has already been done)   but for acting on it.  On this pass, we delete dead stores,   set up the logical links and dead-variables lists of instructions,   and merge instructions for autoincrement and autodecrement addresses.   SIGNIFICANT is nonzero only the first time for each basic block.   If it is nonzero, it points to a regset in which we store   a 1 for each register that is set within the block.   BNUM is the number of the basic block.  */static voidpropagate_block (old, first, last, final, significant, bnum)     register regset old;     rtx first;     rtx last;     int final;     regset significant;     int bnum;{  register rtx insn;  rtx prev;  regset live;  regset dead;  /* The following variables are used only if FINAL is nonzero.  */  /* This vector gets one element for each reg that has been live     at any point in the basic block that has been scanned so far.     SOMETIMES_MAX says how many elements are in use so far.  */  register int *regs_sometimes_live;  int sometimes_max = 0;  /* This regset has 1 for each reg that we have seen live so far.     It and REGS_SOMETIMES_LIVE are updated together.  */  regset maxlive;  /* The loop depth may change in the middle of a basic block.  Since we     scan from end to beginning, we start with the depth at the end of the     current basic block, and adjust as we pass ends and starts of loops.  */  loop_depth = basic_block_loop_depth[bnum];  dead = ALLOCA_REG_SET ();  live = ALLOCA_REG_SET ();  cc0_live = 0;  last_mem_set = 0;  /* Include any notes at the end of the block in the scan.     This is in case the block ends with a call to setjmp.  */  while (NEXT_INSN (last) != 0 && GET_CODE (NEXT_INSN (last)) == NOTE)    {      /* Look for loop boundaries, we are going forward here.  */      last = NEXT_INSN (last);      if (NOTE_LINE_NUMBER (last) == NOTE_INSN_LOOP_BEG)	loop_depth++;      else if (NOTE_LINE_NUMBER (last) == NOTE_INSN_LOOP_END)	loop_depth--;    }  if (final)    {      register int i;      num_scratch = 0;      maxlive = ALLOCA_REG_SET ();      COPY_REG_SET (maxlive, old);      regs_sometimes_live = (int *) alloca (max_regno * sizeof (int));      /* Process the regs live at the end of the block.	 Enter them in MAXLIVE and REGS_SOMETIMES_LIVE.	 Also mark them as not local to any one basic block. */      EXECUTE_IF_SET_IN_REG_SET (old, 0, i,				 {				   REG_BASIC_BLOCK (i) = REG_BLOCK_GLOBAL;				   regs_sometimes_live[sometimes_max] = i;				   sometimes_max++;				 });    }  /* Scan the block an insn at a time from end to beginning.  */  for (insn = last; ; insn = prev)    {      prev = PREV_INSN (insn);      if (GET_CODE (insn) == NOTE)	{	  /* Look for loop boundaries, remembering that we are going	     backwards.  */	  if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)	    loop_depth++;	  else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)	    loop_depth--;	  /* If we have LOOP_DEPTH == 0, there has been a bookkeeping error. 	     Abort now rather than setting register status incorrectly.  */	  if (loop_depth == 0)	    abort ();	  /* If this is a call to `setjmp' et al,	     warn if any non-volatile datum is live.  */	  if (final && NOTE_LINE_NUMBER (insn) == NOTE_INSN_SETJMP)	    IOR_REG_SET (regs_live_at_setjmp, old);	}      /* Update the life-status of regs for this insn.	 First DEAD gets which regs are set in this insn	 then LIVE gets which regs are used in this insn.	 Then the regs live before the insn	 are those live after, with DEAD regs turned off,	 and then LIVE regs turned on.  */      else if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')	{	  register int i;	  rtx note = find_reg_note (insn, REG_RETVAL, NULL_RTX);	  int insn_is_dead	    = (insn_dead_p (PATTERN (insn), old, 0)	       /* Don't delete something that refers to volatile storage!  */	       && ! INSN_VOLATILE (insn));	  int libcall_is_dead 	    = (insn_is_dead && note != 0	       && libcall_dead_p (PATTERN (insn), old, note, insn));	  /* If an instruction consists of just dead store(s) on final pass,	     "delete" it by turning it into a NOTE of type NOTE_INSN_DELETED.	     We could really delete it with delete_insn, but that	     can cause trouble for first or last insn in a basic block.  */	  if (final && insn_is_dead)	    {	      PUT_CODE (insn, NOTE);	      NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;	      NOTE_SOURCE_FILE (insn) = 0;	      /* CC0 is now known to be dead.  Either this insn used it,		 in which case it doesn't anymore, or clobbered it,		 so the next insn can't use it.  */	      cc0_live = 0;	      /* If this insn is copying the return value from a library call,		 delete the entire library call.  */	      if (libcall_is_dead)		{		  rtx first = XEXP (note, 0);		  rtx p = insn;		  while (INSN_DELETED_P (first))		    first = NEXT_INSN (first);		  while (p != first)		    {		      p = PREV_INSN (p);		      PUT_CODE (p, NOTE);		      NOTE_LINE_NUMBER (p) = NOTE_INSN_DELETED;		      NOTE_SOURCE_FILE (p) = 0;		    }		}	      goto flushed;	    }	  CLEAR_REG_SET (dead);	  CLEAR_REG_SET (live);	  /* See if this is an increment or decrement that can be	     merged into a following memory address.  */#ifdef AUTO_INC_DEC	  {	    register rtx x = single_set (insn);	    /* Does this instruction increment or decrement a register?  */	    if (final && x != 0		&& GET_CODE (SET_DEST (x)) == REG		&& (GET_CODE (SET_SRC (x)) == PLUS		    || GET_CODE (SET_SRC (x)) == MINUS)		&& XEXP (SET_SRC (x), 0) == SET_DEST (x)		&& GET_CODE (XEXP (SET_SRC (x), 1)) == CONST_INT		/* Ok, look for a following memory ref we can combine with.		   If one is found, change the memory ref to a PRE_INC		   or PRE_DEC, cancel this insn, and return 1.		   Return 0 if nothing has been done.  */		&& try_pre_increment_1 (insn))	      goto flushed;	  }#endif /* AUTO_INC_DEC */	  /* If this is not the final pass, and this insn is copying the	     value of a library call and it's dead, don't scan the	     insns that perform the library call, so that the call's	     arguments are not marked live.  */	  if (libcall_is_dead)	    {	      /* Mark the dest reg as `significant'.  */	      mark_set_regs (old, dead, PATTERN (insn), NULL_RTX, significant);	      insn = XEXP (note, 0);	      prev = PREV_INSN (insn);	    }	  else if (GET_CODE (PATTERN (insn)) == SET		   && SET_DEST (PATTERN (insn)) == stack_pointer_rtx		   && GET_CODE (SET_SRC (PATTERN (insn))) == PLUS		   && XEXP (SET_SRC (PATTERN (insn)), 0) == stack_pointer_rtx		   && GET_CODE (XEXP (SET_SRC (PATTERN (insn)), 1)) == CONST_INT)	    /* We have an insn to pop a constant amount off the stack.	       (Such insns use PLUS regardless of the direction of the stack,	       and any insn to adjust the stack by a constant is always a pop.)	       These insns, if not dead stores, have no effect on life.  */	    ;	  else	    {	      /* LIVE gets the regs used in INSN;		 DEAD gets those set by it.  Dead insns don't make anything		 live.  */	      mark_set_regs (old, dead, PATTERN (insn),			     final ? insn : NULL_RTX, significant);	      /* If an insn doesn't use CC0, it becomes dead since we 		 assume that every insn clobbers it.  So show it dead here;		 mark_used_regs will set it live if it is referenced.  */	      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 or fixed.  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]			&& ! fixed_regs[i])		      SET_REGNO_REG_SET (dead, i);		  /* The stack ptr is used (honorarily) by a CALL insn.  */		  SET_REGNO_REG_SET (live, STACK_POINTER_REGNUM);		  /* 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.  */	      AND_COMPL_REG_SET (old, dead);	      IOR_REG_SET (old, live);	      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 int *p = regs_sometimes_live;		  for (i = 0; i < sometimes_max; i++, p++)		    if (REGNO_REG_SET_P (old, *p))		      REG_N_CALLS_CROSSED (*p)++;		}	    }	  /* 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)	    {	      register int regno;	      register int *p;	      EXECUTE_IF_AND_COMPL_IN_REG_SET		(live, maxlive, 0, regno,		 {		   regs_sometimes_live[sometimes_max++] = regno;		   SET_REGNO_REG_SET (maxlive, regno);		 });	      p = regs_sometimes_live;	      for (i = 0; i < sometimes_max; i++)		{		  regno = *p++;		  if (REGNO_REG_SET_P (old, regno))		    REG_LIVE_LENGTH (regno)++;		}	    }	}    flushed: ;      if (insn == first)	break;

⌨️ 快捷键说明

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