Hi Jeff,

> The second thought is to initialize all of cse_reg_info entries at the
> beginning of cse_main.  Set aside a bitmap with as many bits as
> max_regs.  Whenever we use one of these accessor macros for register
> k, set a bit k saying "cse_reg_info_table[k] is in use."  This way,
> when we are done with a basic block, we can walk the bitmap and
> reinitialize those that are used.  Again, a good optimizer should be
> able to eliminate most of these bit sets, but a non-pure/const
> function call will block the cleanup opportunities.  Of course, this
> bitmap walk is far more expensive than cse_reg_info_timestamp++.

I just tried this.  It comes very close to the current timestamp
approach but loses by 0.3% or so in compile time.  I'm attaching a
patch for completeness.

Kazu Hirata

Index: cse.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cse.c,v
retrieving revision 1.343
diff -c -d -p -r1.343 cse.c
*** cse.c       21 Feb 2005 02:02:19 -0000      1.343
--- cse.c       21 Feb 2005 19:41:04 -0000
*************** struct cse_reg_info
*** 328,346 ****
  /* A table of cse_reg_info indexed by register numbers.  */
  struct cse_reg_info *cse_reg_info_table;
  
! /* The size of the above table.  */
! static unsigned int cse_reg_info_table_size;
! 
! /* The index of the first entry that has not been initialized.  */
! static unsigned int cse_reg_info_table_first_uninitialized;
! 
! /* The timestamp at the beginning of the current run of
!    cse_basic_block.  We increment this variable at the beginning of
!    the current run of cse_basic_block.  The timestamp field of a
!    cse_reg_info entry matches the value of this variable if and only
!    if the entry has been initialized during the current run of
!    cse_basic_block.  */
! static unsigned int cse_reg_info_timestamp;
  
  /* A HARD_REG_SET containing all the hard registers for which there is
     currently a REG expression in the hash table.  Note the difference
--- 328,334 ----
  /* A table of cse_reg_info indexed by register numbers.  */
  struct cse_reg_info *cse_reg_info_table;
  
! static sbitmap cse_reg_info_init_bitmap;
  
  /* A HARD_REG_SET containing all the hard registers for which there is
     currently a REG expression in the hash table.  Note the difference
*************** notreg_cost (rtx x, enum rtx_code outer)
*** 841,908 ****
  static void
  init_cse_reg_info (unsigned int nregs)
  {
!   /* Do we need to grow the table?  */
!   if (nregs > cse_reg_info_table_size)
!     {
!       unsigned int new_size;
! 
!       if (cse_reg_info_table_size < 2048)
!       {
!         /* Compute a new size that is a power of 2 and no smaller
!            than the large of NREGS and 64.  */
!         new_size = (cse_reg_info_table_size
!                     ? cse_reg_info_table_size : 64);
! 
!         while (new_size < nregs)
!           new_size *= 2;
!       }
!       else
!       {
!         /* If we need a big table, allocate just enough to hold
!            NREGS registers.  */
!         new_size = nregs;
!       }
  
!       /* Reallocate the table with NEW_SIZE entries.  */
!       if (cse_reg_info_table)
!       free (cse_reg_info_table);
!       cse_reg_info_table = xmalloc (sizeof (struct cse_reg_info)
!                                    * new_size);
!       cse_reg_info_table_size = new_size;
!       cse_reg_info_table_first_uninitialized = 0;
!     }
  
!   /* Do we have all of the first NREGS entries initialized?  */
!   if (cse_reg_info_table_first_uninitialized < nregs)
      {
!       unsigned int old_timestamp = cse_reg_info_timestamp - 1;
!       unsigned int i;
! 
!       /* Put the old timestamp on newly allocated entries so that they
!        will all be considered out of date.  We do not touch those
!        entries beyond the first NREGS entries to be nice to the
!        virtual memory.  */
!       for (i = cse_reg_info_table_first_uninitialized; i < nregs; i++)
!       cse_reg_info_table[i].timestamp = old_timestamp;
! 
!       cse_reg_info_table_first_uninitialized = nregs;
      }
  }
  
! /* Given REGNO, initialize the cse_reg_info entry for REGNO.  */
  
  static void
! get_cse_reg_info_1 (unsigned int regno)
  {
!   /* Set TIMESTAMP field to CSE_REG_INFO_TIMESTAMP so that this
!      entry will be considered to have been initialized.  */
!   cse_reg_info_table[regno].timestamp = cse_reg_info_timestamp;
! 
!   /* Initialize the rest of the entry.  */
!   cse_reg_info_table[regno].reg_tick = 1;
!   cse_reg_info_table[regno].reg_in_table = -1;
!   cse_reg_info_table[regno].subreg_ticked = -1;
!   cse_reg_info_table[regno].reg_qty = -regno - 1;
  }
  
  /* Find a cse_reg_info entry for REGNO.  */
--- 829,857 ----
  static void
  init_cse_reg_info (unsigned int nregs)
  {
!   unsigned int i;
  
!   cse_reg_info_table = xmalloc (sizeof (struct cse_reg_info) * nregs);
  
!   for (i = 0; i < nregs; i++)
      {
!       cse_reg_info_table[i].reg_tick = 1;
!       cse_reg_info_table[i].reg_in_table = -1;
!       cse_reg_info_table[i].subreg_ticked = -1;
!       cse_reg_info_table[i].reg_qty = -i - 1;
      }
+ 
+   cse_reg_info_init_bitmap = sbitmap_alloc (nregs);
+   sbitmap_zero (cse_reg_info_init_bitmap);
  }
  
! /* Free CSE_REG_INFO_TABLE.  */
  
  static void
! fini_cse_reg_info (void)
  {
!   free (cse_reg_info_table);
!   sbitmap_free (cse_reg_info_init_bitmap);
  }
  
  /* Find a cse_reg_info entry for REGNO.  */
*************** get_cse_reg_info_1 (unsigned int regno)
*** 910,923 ****
  static inline struct cse_reg_info *
  get_cse_reg_info (unsigned int regno)
  {
!   struct cse_reg_info *p = &cse_reg_info_table[regno];
! 
!   /* If this entry has not been initialized, go ahead and initialize
!      it.  */
!   if (p->timestamp != cse_reg_info_timestamp)
!     get_cse_reg_info_1 (regno);
! 
!   return p;
  }
  
  /* Clear the hash table and initialize each register with its own quantity,
--- 859,866 ----
  static inline struct cse_reg_info *
  get_cse_reg_info (unsigned int regno)
  {
!   SET_BIT (cse_reg_info_init_bitmap, regno);
!   return &cse_reg_info_table[regno];
  }
  
  /* Clear the hash table and initialize each register with its own quantity,
*************** new_basic_block (void)
*** 930,937 ****
  
    next_qty = 0;
  
!   /* Invalidate cse_reg_info_table.  */
!   cse_reg_info_timestamp++;
  
    /* Clear out hash table state for this pass.  */
    CLEAR_HARD_REG_SET (hard_regs_in_table);
--- 873,887 ----
  
    next_qty = 0;
  
!   /* Initialize those entries that have been used in the previous run.  */
!   EXECUTE_IF_SET_IN_SBITMAP (cse_reg_info_init_bitmap, 0, i,
!     {
!       cse_reg_info_table[i].reg_tick = 1;
!       cse_reg_info_table[i].reg_in_table = -1;
!       cse_reg_info_table[i].subreg_ticked = -1;
!       cse_reg_info_table[i].reg_qty = -i - 1;
!       RESET_BIT (cse_reg_info_init_bitmap, i);
!     });
  
    /* Clear out hash table state for this pass.  */
    CLEAR_HARD_REG_SET (hard_regs_in_table);
*************** cse_main (rtx f, int nregs, FILE *file)
*** 6814,6819 ****
--- 6764,6770 ----
    free (reg_eqv_table);
    free (val.path);
    rtl_hooks = general_rtl_hooks;
+   fini_cse_reg_info ();
  
    return cse_jumps_altered || recorded_label_ref;
  }

Reply via email to