This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

create less temporary rtl


Investigating GCC's memory allocation behaviour, I noticed there are a few
"hot" routines where RTL is generated just to call a function that expects
an rtx while, for example, we only have a register number.  The attached
patch fixes one of those places, namely, where call-clobbered registers get
marked as such.

I'm sure I got all the details wrong (and the indenting, too); but it
bootstraps fine (on gnu-linux-powerpc), and is a full minute faster on
bootstrap, too.  On some files (expr.c), it saves more than 10% compilation
time.

Of course, with a refcounting garbage collector, the impact would be much
less ;)

Comments?


Segher
*** flow.c.ORIG	Thu Apr 18 22:21:09 2002
--- flow.c	Tue Aug 13 05:05:14 2002
***************
*** 304,309 ****
--- 304,313 ----
  static void mark_set_1			PARAMS ((struct propagate_block_info *,
  						 enum rtx_code, rtx, rtx,
  						 rtx, int));
+ static void mark_invalidated_by_call	PARAMS ((struct propagate_block_info *,
+ 						 rtx, rtx));
+ static void mark_set_reg_invalidated_by_call PARAMS ((struct propagate_block_info *,
+ 						      int, rtx, rtx));
  static int find_regno_partial		PARAMS ((rtx *, void *));
  
  #ifdef HAVE_conditional_execution
***************
*** 339,344 ****
--- 343,350 ----
  						  rtx));
  static void invalidate_mems_from_set	PARAMS ((struct propagate_block_info *,
  						 rtx));
+ static void invalidate_mems_from_set_1	PARAMS ((struct propagate_block_info *,
+ 						 int));
  static void delete_dead_jumptables	PARAMS ((void));
  static void clear_log_links		PARAMS ((sbitmap));
  
***************
*** 1694,1700 ****
  
        if (GET_CODE (insn) == CALL_INSN)
  	{
- 	  int i;
  	  rtx note, cond;
  
  	  cond = NULL_RTX;
--- 1700,1705 ----
***************
*** 1717,1730 ****
  			  cond, insn, pbi->flags);
  
  	  /* Calls change all call-used and global registers.  */
! 	  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
! 	    if (TEST_HARD_REG_BIT (regs_invalidated_by_call, i))
! 	      {
! 		/* We do not want REG_UNUSED notes for these registers.  */
! 		mark_set_1 (pbi, CLOBBER, gen_rtx_REG (reg_raw_mode[i], i),
! 			    cond, insn,
! 			    pbi->flags & ~(PROP_DEATH_NOTES | PROP_REG_INFO));
! 	      }
  	}
  
        /* If an insn doesn't use CC0, it becomes dead since we assume
--- 1722,1728 ----
  			  cond, insn, pbi->flags);
  
  	  /* Calls change all call-used and global registers.  */
! 	  mark_invalidated_by_call(pbi, cond, insn);
  	}
  
        /* If an insn doesn't use CC0, it becomes dead since we assume
***************
*** 2416,2421 ****
--- 2414,2447 ----
      }
  }
  
+ static void
+ invalidate_mems_from_set_1 (pbi, regno)
+      struct propagate_block_info *pbi;
+      int regno;
+ {
+   rtx temp = pbi->mem_set_list;
+   rtx prev = NULL_RTX;
+   rtx next;
+ 
+   while (temp)
+     {
+       next = XEXP (temp, 1);
+       if (refers_to_regno_p (regno, regno, XEXP (temp, 0), (rtx *)0))
+ 	{
+ 	  /* Splice this entry out of the list.  */
+ 	  if (prev)
+ 	    XEXP (prev, 1) = next;
+ 	  else
+ 	    pbi->mem_set_list = next;
+ 	  free_EXPR_LIST_node (temp);
+ 	  pbi->mem_set_list_len--;
+ 	}
+       else
+ 	prev = temp;
+       temp = next;
+     }
+ }
+ 
  /* 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.
  
***************
*** 2802,2807 ****
--- 2828,2964 ----
  	REG_NOTES (insn)
  	  = alloc_EXPR_LIST (REG_UNUSED, reg, REG_NOTES (insn));
      }
+ }
+ 
+ static void
+ mark_set_reg_invalidated_by_call (pbi, regno, cond, insn)
+      struct propagate_block_info *pbi;
+      int regno;
+      rtx cond, insn;
+ {
+   unsigned long not_dead = 0;
+   int flags;
+ 
+   flags = pbi->flags;
+ 
+   if ( ! (regno == FRAME_POINTER_REGNUM
+ 	    && (! reload_completed || frame_pointer_needed))
+ #if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
+       && ! (regno == HARD_FRAME_POINTER_REGNUM
+ 	    && (! reload_completed || frame_pointer_needed))
+ #endif
+ #if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
+       && ! (regno == ARG_POINTER_REGNUM && fixed_regs[regno])
+ #endif
+       )
+     {
+       int some_was_live = 0, some_was_dead = 0;
+ 
+ 	{
+ 	  int needed_regno = REGNO_REG_SET_P (pbi->reg_live, regno);
+ 	  if (pbi->local_set)
+ 	    {
+ 	      /* Order of the set operation matters here since both
+ 		 sets may be the same.  */
+ 	      CLEAR_REGNO_REG_SET (pbi->cond_local_set, regno);
+ 	      if (cond != NULL_RTX
+ 		  && ! REGNO_REG_SET_P (pbi->local_set, regno))
+ 		SET_REGNO_REG_SET (pbi->cond_local_set, regno);
+ 	      else
+ 		SET_REGNO_REG_SET (pbi->local_set, regno);
+ 	    }
+ 
+ 	  some_was_live |= needed_regno;
+ 	  some_was_dead |= ! needed_regno;
+ 	}
+ 
+ #ifdef HAVE_conditional_execution
+       /* Consider conditional death in deciding that the register needs
+ 	 a death note.  */
+       if (some_was_live && ! not_dead
+ 	  /* The stack pointer is never dead.  Well, not strictly true,
+ 	     but it's very difficult to tell from here.  Hopefully
+ 	     combine_stack_adjustments will fix up the most egregious
+ 	     errors.  */
+ 	  && regno != STACK_POINTER_REGNUM)
+ 	{
+ 	    if (! mark_regno_cond_dead (pbi, regno, cond))
+ 	      not_dead |= 1;
+ 	}
+ #endif
+ 
+       /* Additional data to record if this is the final pass.  */
+       if (flags & (PROP_LOG_LINKS | PROP_AUTOINC))
+ 	{
+ 	  rtx y;
+ 	  int blocknum = pbi->bb->index;
+ 
+ 	  y = NULL_RTX;
+ 	  if (flags & (PROP_LOG_LINKS | PROP_AUTOINC))
+ 	    {
+ 	      y = pbi->reg_next_use[regno];
+ 
+ 	      /* The next use is no longer next, since a store intervenes.  */
+ 	      pbi->reg_next_use[regno] = 0;
+ 	    }
+ 
+ 	  if (! some_was_dead)
+ 	    {
+ 	      if (flags & PROP_LOG_LINKS)
+ 		{
+ 		  /* Make a logical link from the next following insn
+ 		     that uses this register, back to this insn.
+ 		     The following insns have already been processed.
+ 
+ 		     We don't build a LOG_LINK for hard registers containing
+ 		     in ASM_OPERANDs.  If these registers get replaced,
+ 		     we might wind up changing the semantics of the insn,
+ 		     even if reload can make what appear to be valid
+ 		     assignments later.  */
+ 		  if (y && (BLOCK_NUM (y) == blocknum)
+ 		      && (asm_noperands (PATTERN (y)) < 0))
+ 		    LOG_LINKS (y) = alloc_INSN_LIST (insn, LOG_LINKS (y));
+ 		}
+ 	    }
+ 	}
+ 
+       /* Mark the register as being dead.  */
+       if (some_was_live
+ 	  /* The stack pointer is never dead.  Well, not strictly true,
+ 	     but it's very difficult to tell from here.  Hopefully
+ 	     combine_stack_adjustments will fix up the most egregious
+ 	     errors.  */
+ 	  && regno != STACK_POINTER_REGNUM)
+ 	{
+ 	    if (!(not_dead & 1))
+ 	      CLEAR_REGNO_REG_SET (pbi->reg_live, regno);
+ 	}
+     }
+   else
+     {
+       if (flags & (PROP_LOG_LINKS | PROP_AUTOINC))
+ 	pbi->reg_next_use[regno] = 0;
+     }
+ }
+ 
+ /* Calls change all call-used and global registers.  */
+ static void
+ mark_invalidated_by_call (pbi, cond, insn)
+      struct propagate_block_info *pbi;
+      rtx cond;
+      rtx insn;
+ {
+   int i;
+   if (optimize && (pbi->flags & PROP_SCAN_DEAD_CODE))
+ 	  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ 	    if (TEST_HARD_REG_BIT (regs_invalidated_by_call, i))
+ 	      {
+ 		  /* This set is a REG, so it kills any MEMs which use the reg.  */
+ 		  invalidate_mems_from_set_1 (pbi, i);
+ 	      }
+   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+     if (TEST_HARD_REG_BIT (regs_invalidated_by_call, i))
+       mark_set_reg_invalidated_by_call (pbi, i, cond, insn);
  }
  
  #ifdef HAVE_conditional_execution

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]