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;
}