This is the mail archive of the gcc-patches@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]

condexec merge part 14


This changes how data structure updates happen within the
propagate_block subroutines.  Previously we had two regsets
(new_live and new_dead) that accumulated data for the insn,
and we applied this data to reg_live all at once at the end.

This scheme works fine when all we need to modify are some
sets, but the conditional life code (not merged yet) of course
requires more complex data structures.  Given that we need to
keep everything in sync, this means we have to be more careful
about how we update reg_live and where.

The new scheme dispenses with new_live and new_dead and updates
reg_live directly.  We also keep a new_set that tracks what
registers are SET (as opposed to CLOBBERed) in the current insn.
This allows us to remove some of the hacks wrt REG_DEAD note
creation that were identified with the 2000-04-08 flow changes.

I think I'll stop here for the evening and give people a chance
to scream that I broke target gimcrack for test case wibble.
I did just finish re-testing what I just merged (x86 and alpha),
and I did have good results for other targets on the branch, so
I don't expect problems.  Famous last words...


r~


        * flow.c (struct propagate_block_info): Remove new_dead, new_live;
        add new_set.
        (propagate_one_insn): Clear it.  Don't update reg_live here.
        (init_propagate_block_info): Update for pbi member changes.
        (free_propagate_block_info): Likewise.
        (mark_set_1): Know that zero_extract, sign_extract, and
        strict_low_part don't kill their argument.  Alter hard subregs.
        Update new_set for non-CLOBBER sets.  Update reg_live.
        (find_auto_inc): Update reg_live, not new_dead.
        (mark_used_reg): Update reg_live, not new_live.  Examine new_set
        to determine if the reg in question was set this insn.  Only update
        reg info with PROP_REG_INFO. 

Index: flow.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/flow.c,v
retrieving revision 1.267
diff -c -p -d -r1.267 flow.c
*** flow.c	2000/04/27 07:39:51	1.267
--- flow.c	2000/04/27 10:56:14
*************** struct propagate_block_info
*** 264,274 ****
    /* Bit N is set if register N is conditionally or unconditionally live.  */
    regset reg_live;
  
!   /* Bit N is set if register N is unconditionally dead this insn.  */
!   regset new_dead;
! 
!   /* Bit N is set if register N is live this insn.  */
!   regset new_live;
  
    /* Element N is the next insn that uses (hard or pseudo) register N
       within the current basic block; or zero, if there is no such insn.  */
--- 264,271 ----
    /* Bit N is set if register N is conditionally or unconditionally live.  */
    regset reg_live;
  
!   /* Bit N is set if register N is set this insn.  */
!   regset new_set;
  
    /* Element N is the next insn that uses (hard or pseudo) register N
       within the current basic block; or zero, if there is no such insn.  */
*************** propagate_one_insn (pbi, insn)
*** 3376,3383 ****
    }
  #endif /* AUTO_INC_DEC */
  
!   CLEAR_REG_SET (pbi->new_live);
!   CLEAR_REG_SET (pbi->new_dead);
  
    /* 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
--- 3373,3379 ----
    }
  #endif /* AUTO_INC_DEC */
  
!   CLEAR_REG_SET (pbi->new_set);
  
    /* 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
*************** propagate_one_insn (pbi, insn)
*** 3490,3499 ****
  	}
      }
  
-   /* Update reg_live for the registers killed and used.  */
-   AND_COMPL_REG_SET (pbi->reg_live, pbi->new_dead);
-   IOR_REG_SET (pbi->reg_live, pbi->new_live);
- 
    /* On final pass, update counts of how many insns in which each reg
       is live.  */
    if (flags & PROP_REG_INFO)
--- 3486,3491 ----
*************** init_propagate_block_info (bb, live, loc
*** 3528,3535 ****
    else
      pbi->reg_next_use = NULL;
  
!   pbi->new_live = BITMAP_XMALLOC ();
!   pbi->new_dead = BITMAP_XMALLOC ();
  
    return pbi;
  }
--- 3520,3526 ----
    else
      pbi->reg_next_use = NULL;
  
!   pbi->new_set = BITMAP_XMALLOC ();
  
    return pbi;
  }
*************** free_propagate_block_info (pbi)
*** 3542,3549 ****
  {
    free_EXPR_LIST_list (&pbi->mem_set_list);
  
!   BITMAP_XFREE (pbi->new_live);
!   BITMAP_XFREE (pbi->new_dead);
  
    if (pbi->reg_next_use)
      free (pbi->reg_next_use);
--- 3533,3539 ----
  {
    free_EXPR_LIST_list (&pbi->mem_set_list);
  
!   BITMAP_XFREE (pbi->new_set);
  
    if (pbi->reg_next_use)
      free (pbi->reg_next_use);
*************** mark_set_1 (pbi, code, reg, cond, insn, 
*** 3980,3985 ****
--- 3970,3976 ----
       int flags;
  {
    int regno_first = -1, regno_last = -1;
+   int not_dead = 0;
    int i;
  
    /* Some targets place small structures in registers for
*************** mark_set_1 (pbi, code, reg, cond, insn, 
*** 3995,4018 ****
  
    /* 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. 
  
!      ??? This is all done incorrectly.  We should not be setting bits in
!      new_dead for these registers, since, as we just explained, they are
!      not dead.  We should be setting bits in local_set, and updating
!      LOG_LINKS, but that is different.  */
  
!   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 this set is a MEM, then it kills any aliased writes. 
       If this set is a REG, then it kills any MEMs which use the reg.  */
--- 3986,4065 ----
  
    /* 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.  Of course, if it was dead after it's unused now.  */
  
!   switch (GET_CODE (reg))
!     {
!     case ZERO_EXTRACT:
!     case SIGN_EXTRACT:
!     case STRICT_LOW_PART:
!       /* ??? Assumes STRICT_LOW_PART not used on multi-word registers.  */
!       do
! 	reg = XEXP (reg, 0);
!       while (GET_CODE (reg) == SUBREG
! 	     || GET_CODE (reg) == ZERO_EXTRACT
! 	     || GET_CODE (reg) == SIGN_EXTRACT
! 	     || GET_CODE (reg) == STRICT_LOW_PART);
!       not_dead = REGNO_REG_SET_P (pbi->reg_live, REGNO (reg));
!       /* FALLTHRU */
  
!     case REG:
!       regno_last = regno_first = REGNO (reg);
!       if (regno_first < FIRST_PSEUDO_REGISTER)
! 	regno_last += HARD_REGNO_NREGS (regno_first, GET_MODE (reg)) - 1;
!       break;
  
!     case SUBREG:
!       if (GET_CODE (SUBREG_REG (reg)) == REG)
! 	{
! 	  enum machine_mode outer_mode = GET_MODE (reg);
! 	  enum machine_mode inner_mode = GET_MODE (SUBREG_REG (reg));
! 
! 	  /* Identify the range of registers affected.  This is moderately
! 	     tricky for hard registers.  See alter_subreg.  */
! 
! 	  regno_last = regno_first = REGNO (SUBREG_REG (reg));
! 	  if (regno_first < FIRST_PSEUDO_REGISTER)
! 	    {
! #ifdef ALTER_HARD_SUBREG
! 	      regno_first = ALTER_HARD_SUBREG (outer_mode, SUBREG_WORD (reg),
! 					       inner_mode, regno_first);
! #else
! 	      regno_first += SUBREG_WORD (reg);
! #endif
! 	      regno_last = (regno_first
! 			    + HARD_REGNO_NREGS (regno_first, outer_mode) - 1);
! 
! 	      /* Since we've just adjusted the register number ranges, make
! 		 sure REG matches.  Otherwise some_was_live will be clear
! 		 when it shouldn't have been, and we'll create incorrect
! 		 REG_UNUSED notes.  */
! 	      reg = gen_rtx_REG (outer_mode, regno_first);
! 	    }
! 	  else
! 	    {
! 	      /* If the number of words in the subreg is less than the number
! 		 of words in the full register, we have a well-defined partial
! 		 set.  Otherwise the high bits are undefined.
! 
! 		 This is only really applicable to pseudos, since we just took
! 		 care of multi-word hard registers.  */
! 	      if (((GET_MODE_SIZE (outer_mode)
! 		    + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
! 		  < ((GET_MODE_SIZE (inner_mode)
! 		      + UNITS_PER_WORD - 1) / UNITS_PER_WORD))
! 		not_dead = REGNO_REG_SET_P (pbi->reg_live, regno_first);
! 
! 	      reg = SUBREG_REG (reg);
! 	    }
! 	}
!       else
! 	reg = SUBREG_REG (reg);
!       break;
! 
!     default:
!       break;
!     }
  
    /* If this set is a MEM, then it kills any aliased writes. 
       If this set is a REG, then it kills any MEMs which use the reg.  */
*************** mark_set_1 (pbi, code, reg, cond, insn, 
*** 4063,4071 ****
      }
  
    if (GET_CODE (reg) == REG
!       && (regno_first = REGNO (reg),
! 	  ! (regno_first == FRAME_POINTER_REGNUM
! 	     && (! reload_completed || frame_pointer_needed)))
  #if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
        && ! (regno_first == HARD_FRAME_POINTER_REGNUM
  	    && (! reload_completed || frame_pointer_needed))
--- 4110,4117 ----
      }
  
    if (GET_CODE (reg) == REG
!       && ! (regno_first == FRAME_POINTER_REGNUM
! 	    && (! reload_completed || frame_pointer_needed))
  #if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
        && ! (regno_first == HARD_FRAME_POINTER_REGNUM
  	    && (! reload_completed || frame_pointer_needed))
*************** mark_set_1 (pbi, code, reg, cond, insn, 
*** 4077,4093 ****
      {
        int some_was_live = 0, some_was_dead = 0;
  
-       if (regno_first < FIRST_PSEUDO_REGISTER)
- 	regno_last = (regno_first
- 		      + HARD_REGNO_NREGS (regno_first, GET_MODE (reg)) - 1);
-       else
-         regno_last = regno_first;
- 
        for (i = regno_first; i <= regno_last; ++i)
  	{
  	  int needed_regno = REGNO_REG_SET_P (pbi->reg_live, i);
  	  if (pbi->local_set)
  	    SET_REGNO_REG_SET (pbi->local_set, i);
  
  	  some_was_live |= needed_regno;
  	  some_was_dead |= ! needed_regno;
--- 4123,4135 ----
      {
        int some_was_live = 0, some_was_dead = 0;
  
        for (i = regno_first; i <= regno_last; ++i)
  	{
  	  int needed_regno = REGNO_REG_SET_P (pbi->reg_live, i);
  	  if (pbi->local_set)
  	    SET_REGNO_REG_SET (pbi->local_set, i);
+ 	  if (code != CLOBBER)
+ 	    SET_REGNO_REG_SET (pbi->new_set, i);
  
  	  some_was_live |= needed_regno;
  	  some_was_dead |= ! needed_regno;
*************** mark_set_1 (pbi, code, reg, cond, insn, 
*** 4162,4167 ****
--- 4204,4211 ----
  		    LOG_LINKS (y) = alloc_INSN_LIST (insn, LOG_LINKS (y));
  		}
  	    }
+ 	  else if (not_dead)
+ 	    ;
  	  else if (! some_was_live)
  	    {
  	      if (flags & PROP_REG_INFO)
*************** mark_set_1 (pbi, code, reg, cond, insn, 
*** 4207,4213 ****
  	  && regno_first != STACK_POINTER_REGNUM)
  	{
  	  for (i = regno_first; i <= regno_last; ++i)
! 	    SET_REGNO_REG_SET (pbi->new_dead, i);
  	}
      }
    else if (GET_CODE (reg) == REG)
--- 4251,4257 ----
  	  && regno_first != STACK_POINTER_REGNUM)
  	{
  	  for (i = regno_first; i <= regno_last; ++i)
! 	    CLEAR_REGNO_REG_SET (pbi->reg_live, i);
  	}
      }
    else if (GET_CODE (reg) == REG)
*************** find_auto_inc (pbi, x, insn)
*** 4389,4395 ****
  	      /* If the original source was dead, it's dead now.  */
  	      rtx note = find_reg_note (incr, REG_DEAD, NULL_RTX);
  	      if (note && XEXP (note, 0) != addr)
! 		SET_REGNO_REG_SET (pbi->new_dead, REGNO (XEXP (note, 0)));
  	      
  	      PUT_CODE (incr, NOTE);
  	      NOTE_LINE_NUMBER (incr) = NOTE_INSN_DELETED;
--- 4433,4439 ----
  	      /* If the original source was dead, it's dead now.  */
  	      rtx note = find_reg_note (incr, REG_DEAD, NULL_RTX);
  	      if (note && XEXP (note, 0) != addr)
! 		CLEAR_REGNO_REG_SET (pbi->reg_live, REGNO (XEXP (note, 0)));
  	      
  	      PUT_CODE (incr, NOTE);
  	      NOTE_LINE_NUMBER (incr) = NOTE_INSN_DELETED;
*************** mark_used_reg (pbi, reg, cond, insn)
*** 4422,4441 ****
    int regno = REGNO (reg);
    int some_was_live = REGNO_REG_SET_P (pbi->reg_live, regno);
    int some_was_dead = ! some_was_live;
! 
!   SET_REGNO_REG_SET (pbi->new_live, regno);
  
    /* A hard reg in a wide mode may really be multiple registers.
       If so, mark all of them just like the first.  */
    if (regno < FIRST_PSEUDO_REGISTER)
      {
!       int n = HARD_REGNO_NREGS (regno, GET_MODE (reg));
        while (--n > 0)
  	{
! 	  int regno_n = regno + n;
! 	  int needed_regno = REGNO_REG_SET_P (pbi->reg_live, regno_n);
! 
! 	  SET_REGNO_REG_SET (pbi->new_live, regno_n);
  	  some_was_live |= needed_regno;
  	  some_was_dead |= ! needed_regno;
  	}
--- 4466,4482 ----
    int regno = REGNO (reg);
    int some_was_live = REGNO_REG_SET_P (pbi->reg_live, regno);
    int some_was_dead = ! some_was_live;
!   int some_not_set;
!   int n;
  
    /* A hard reg in a wide mode may really be multiple registers.
       If so, mark all of them just like the first.  */
    if (regno < FIRST_PSEUDO_REGISTER)
      {
!       n = HARD_REGNO_NREGS (regno, GET_MODE (reg));
        while (--n > 0)
  	{
! 	  int needed_regno = REGNO_REG_SET_P (pbi->reg_live, regno + n);
  	  some_was_live |= needed_regno;
  	  some_was_dead |= ! needed_regno;
  	}
*************** mark_used_reg (pbi, reg, cond, insn)
*** 4489,4518 ****
  	}
      }
  
    /* Record and count the insns in which a reg dies.  If it is used in
       this insn and was dead below the insn then it dies in this insn.
       If it was set in this insn, we do not make a REG_DEAD note;
!      likewise if we already made such a note. 
! 
!      ??? This could be done better.  In new_dead we have a record of 
!      which registers are set or clobbered this insn (which in itself is
!      slightly incorrect, see the commentary near strict_low_part in
!      mark_set_1), which should be the set of registers that we do not
!      wish to create death notes for under the above rule.  Note that
!      we have not yet processed the call-clobbered/call-used registers,
!      and they do not quite follow the above rule, since we do want death
!      notes for call-clobbered register arguments.  Which begs the whole
!      question of whether we should in fact have death notes for registers
!      used and clobbered (but not set) in the same insn.  The only useful
!      thing we ought to be getting from dead_or_set_p is detection of
!      duplicate death notes.  */
! 
!   if ((pbi->flags & PROP_DEATH_NOTES)
        && some_was_dead
!       && ! dead_or_set_p (insn, reg))
      {
-       int n;
- 
        /* Check for the case where the register dying partially
  	 overlaps the register set by this insn.  */
        if (regno < FIRST_PSEUDO_REGISTER
--- 4530,4552 ----
  	}
      }
  
+   /* Find out if any of the register was set this insn.  */
+   some_not_set = ! REGNO_REG_SET_P (pbi->new_set, regno);
+   if (regno < FIRST_PSEUDO_REGISTER)
+     {
+       n = HARD_REGNO_NREGS (regno, GET_MODE (reg));
+       while (--n > 0)
+ 	some_not_set |= ! REGNO_REG_SET_P (pbi->new_set, regno + n);
+     }
+ 
    /* Record and count the insns in which a reg dies.  If it is used in
       this insn and was dead below the insn then it dies in this insn.
       If it was set in this insn, we do not make a REG_DEAD note;
!      likewise if we already made such a note.  */
!   if ((pbi->flags & (PROP_DEATH_NOTES | PROP_REG_INFO))
        && some_was_dead
!       && some_not_set)
      {
        /* Check for the case where the register dying partially
  	 overlaps the register set by this insn.  */
        if (regno < FIRST_PSEUDO_REGISTER
*************** mark_used_reg (pbi, reg, cond, insn)
*** 4520,4535 ****
  	{
  	  n = HARD_REGNO_NREGS (regno, GET_MODE (reg));
  	  while (--n >= 0)
! 	    some_was_live |= dead_or_set_regno_p (insn, regno + n);
  	}
  
        /* If none of the words in X is needed, make a REG_DEAD note.
  	 Otherwise, we must make partial REG_DEAD notes.  */
        if (! some_was_live)
  	{
! 	  REG_NOTES (insn)
! 	    = alloc_EXPR_LIST (REG_DEAD, reg, REG_NOTES (insn));
! 	  REG_N_DEATHS (regno)++;
  	}
        else
  	{
--- 4554,4573 ----
  	{
  	  n = HARD_REGNO_NREGS (regno, GET_MODE (reg));
  	  while (--n >= 0)
! 	    some_was_live |= REGNO_REG_SET_P (pbi->new_set, regno + n);
  	}
  
        /* If none of the words in X is needed, make a REG_DEAD note.
  	 Otherwise, we must make partial REG_DEAD notes.  */
        if (! some_was_live)
  	{
! 	  if ((pbi->flags & PROP_DEATH_NOTES)
! 	      && ! find_regno_note (insn, REG_DEAD, regno))
! 	    REG_NOTES (insn)
! 	      = alloc_EXPR_LIST (REG_DEAD, reg, REG_NOTES (insn));
! 
! 	  if (pbi->flags & PROP_REG_INFO)
! 	    REG_N_DEATHS (regno)++;
  	}
        else
  	{
*************** mark_used_reg (pbi, reg, cond, insn)
*** 4538,4550 ****
  
  	  n = regno + HARD_REGNO_NREGS (regno, GET_MODE (reg)) - 1;
  	  for (; n >= regno; n--)
! 	    if (!REGNO_REG_SET_P (pbi->reg_live, n)
  		&& ! dead_or_set_regno_p (insn, n))
  	      REG_NOTES (insn)
  		= alloc_EXPR_LIST (REG_DEAD,
  				   gen_rtx_REG (reg_raw_mode[n], n),
  				   REG_NOTES (insn));
  	}
      }
  }
  
--- 4576,4596 ----
  
  	  n = regno + HARD_REGNO_NREGS (regno, GET_MODE (reg)) - 1;
  	  for (; n >= regno; n--)
! 	    if (! REGNO_REG_SET_P (pbi->reg_live, n)
  		&& ! dead_or_set_regno_p (insn, n))
  	      REG_NOTES (insn)
  		= alloc_EXPR_LIST (REG_DEAD,
  				   gen_rtx_REG (reg_raw_mode[n], n),
  				   REG_NOTES (insn));
  	}
+     }
+ 
+   SET_REGNO_REG_SET (pbi->reg_live, regno);
+   if (regno < FIRST_PSEUDO_REGISTER)
+     {
+       n = HARD_REGNO_NREGS (regno, GET_MODE (reg));
+       while (--n > 0)
+ 	SET_REGNO_REG_SET (pbi->reg_live, regno + n);
      }
  }
  

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