cse.c (struct cse_reg_info): Add hash_next member, reorder rest of struct for better packing on 64-bit hosts.
* cse.c (struct cse_reg_info): Add hash_next member, reorder rest of struct for better packing on 64-bit hosts. (cse_reg_info_tree): Kill. (REGHASH_SHIFT, REGHASH_SIZE, REGHASH_MASK, reg_hash, REGHASH_FN): New custom pow2 hash mechanism. (NBUCKETS): Kill. (HASH_SHIFT, HASH_SIZE, HASH_MASK, HASH, table): Rework to use a pow2 hash table. (get_cse_reg_info): Rework to use new REGHASH. (new_basic_block): Likewise, use HASH_SIZE, and inline free_element call. (remove_from_table): Rework to use HASH_SIZE/HASH_MASK, and inline free_element call. (lookup_as_function, insert, flush_hash_table, invalidate, remove_invalid_refs, remove_invalid_subreg_refs, rehash_using_reg, invalidate_for_call, use_related_value, find_comparison_args, fold_rtx, equiv_constant, cse_insn, invalidate_memory): Likewise. (hash_cse_reg_info, cse_reg_info_equal_p, free_element, get_element): Kill. From-SVN: r30883
This commit is contained in:
parent
fa0933ba25
commit
9b1549b811
2 changed files with 133 additions and 123 deletions
|
@ -1,3 +1,26 @@
|
|||
1999-12-12 David S. Miller <davem@redhat.com>
|
||||
|
||||
* cse.c (struct cse_reg_info): Add hash_next member,
|
||||
reorder rest of struct for better packing on 64-bit
|
||||
hosts.
|
||||
(cse_reg_info_tree): Kill.
|
||||
(REGHASH_SHIFT, REGHASH_SIZE, REGHASH_MASK, reg_hash,
|
||||
REGHASH_FN): New custom pow2 hash mechanism.
|
||||
(NBUCKETS): Kill.
|
||||
(HASH_SHIFT, HASH_SIZE, HASH_MASK, HASH, table): Rework to
|
||||
use a pow2 hash table.
|
||||
(get_cse_reg_info): Rework to use new REGHASH.
|
||||
(new_basic_block): Likewise, use HASH_SIZE, and inline
|
||||
free_element call.
|
||||
(remove_from_table): Rework to use HASH_SIZE/HASH_MASK,
|
||||
and inline free_element call.
|
||||
(lookup_as_function, insert, flush_hash_table, invalidate,
|
||||
remove_invalid_refs, remove_invalid_subreg_refs, rehash_using_reg,
|
||||
invalidate_for_call, use_related_value, find_comparison_args,
|
||||
fold_rtx, equiv_constant, cse_insn, invalidate_memory): Likewise.
|
||||
(hash_cse_reg_info, cse_reg_info_equal_p, free_element,
|
||||
get_element): Kill.
|
||||
|
||||
Sun Dec 12 21:31:44 1999 Jeffrey A Law (law@cygnus.com)
|
||||
|
||||
* cse.c (cse_basic_block): Free qty_table consistently.
|
||||
|
|
233
gcc/cse.c
233
gcc/cse.c
|
@ -295,24 +295,27 @@ static struct reg_eqv_elem *reg_eqv_table;
|
|||
|
||||
struct cse_reg_info
|
||||
{
|
||||
/* The number of times the register has been altered in the current
|
||||
basic block. */
|
||||
int reg_tick;
|
||||
/* Next in hash chain. */
|
||||
struct cse_reg_info *hash_next;
|
||||
|
||||
/* The next cse_reg_info structure in the free or used list. */
|
||||
struct cse_reg_info *next;
|
||||
|
||||
/* Search key */
|
||||
int regno;
|
||||
|
||||
/* The quantity number of the register's current contents. */
|
||||
int reg_qty;
|
||||
|
||||
/* The number of times the register has been altered in the current
|
||||
basic block. */
|
||||
int reg_tick;
|
||||
|
||||
/* The REG_TICK value at which rtx's containing this register are
|
||||
valid in the hash table. If this does not equal the current
|
||||
reg_tick value, such expressions existing in the hash table are
|
||||
invalid. */
|
||||
int reg_in_table;
|
||||
|
||||
/* The quantity number of the register's current contents. */
|
||||
int reg_qty;
|
||||
|
||||
/* Search key */
|
||||
int regno;
|
||||
};
|
||||
|
||||
/* A free list of cse_reg_info entries. */
|
||||
|
@ -323,7 +326,13 @@ static struct cse_reg_info *cse_reg_info_used_list;
|
|||
static struct cse_reg_info *cse_reg_info_used_list_end;
|
||||
|
||||
/* A mapping from registers to cse_reg_info data structures. */
|
||||
static hash_table_t cse_reg_info_tree;
|
||||
#define REGHASH_SHIFT 7
|
||||
#define REGHASH_SIZE (1 << REGHASH_SHIFT)
|
||||
#define REGHASH_MASK (REGHASH_SIZE - 1)
|
||||
static struct cse_reg_info *reg_hash[REGHASH_SIZE];
|
||||
|
||||
#define REGHASH_FN(REGNO) \
|
||||
(((REGNO) ^ ((REGNO) >> REGHASH_SHIFT)) & REGHASH_MASK)
|
||||
|
||||
/* The last lookup we did into the cse_reg_info_tree. This allows us
|
||||
to cache repeated lookups. */
|
||||
|
@ -449,15 +458,17 @@ struct table_elt
|
|||
/* We don't want a lot of buckets, because we rarely have very many
|
||||
things stored in the hash table, and a lot of buckets slows
|
||||
down a lot of loops that happen frequently. */
|
||||
#define NBUCKETS 31
|
||||
#define HASH_SHIFT 5
|
||||
#define HASH_SIZE (1 << HASH_SHIFT)
|
||||
#define HASH_MASK (HASH_SIZE - 1)
|
||||
|
||||
/* Compute hash code of X in mode M. Special-case case where X is a pseudo
|
||||
register (hard registers may require `do_not_record' to be set). */
|
||||
|
||||
#define HASH(X, M) \
|
||||
(GET_CODE (X) == REG && REGNO (X) >= FIRST_PSEUDO_REGISTER \
|
||||
? (((unsigned) REG << 7) + (unsigned) REG_QTY (REGNO (X))) % NBUCKETS \
|
||||
: canon_hash (X, M) % NBUCKETS)
|
||||
((GET_CODE (X) == REG && REGNO (X) >= FIRST_PSEUDO_REGISTER \
|
||||
? (((unsigned) REG << 7) + (unsigned) REG_QTY (REGNO (X))) \
|
||||
: canon_hash (X, M)) & HASH_MASK)
|
||||
|
||||
/* Determine whether register number N is considered a fixed register for CSE.
|
||||
It is desirable to replace other regs with fixed regs, to reduce need for
|
||||
|
@ -527,7 +538,7 @@ struct table_elt
|
|||
? -1 : ADDRESS_COST(RTX))
|
||||
#endif
|
||||
|
||||
static struct table_elt *table[NBUCKETS];
|
||||
static struct table_elt *table[HASH_SIZE];
|
||||
|
||||
/* Chain of `struct table_elt's made so far for this function
|
||||
but currently removed from the table. */
|
||||
|
@ -836,63 +847,45 @@ static struct cse_reg_info *
|
|||
get_cse_reg_info (regno)
|
||||
int regno;
|
||||
{
|
||||
struct cse_reg_info *cri;
|
||||
struct cse_reg_info **entry;
|
||||
struct cse_reg_info temp;
|
||||
struct cse_reg_info **hash_head = ®_hash[REGHASH_FN (regno)];
|
||||
struct cse_reg_info *p;
|
||||
|
||||
/* See if we already have this entry. */
|
||||
temp.regno = regno;
|
||||
entry = (struct cse_reg_info **) find_hash_table_entry (cse_reg_info_tree,
|
||||
&temp, TRUE);
|
||||
for (p = *hash_head ; p != NULL; p = p->hash_next)
|
||||
if (p->regno == regno)
|
||||
break;
|
||||
|
||||
if (*entry)
|
||||
cri = *entry;
|
||||
else
|
||||
if (p == NULL)
|
||||
{
|
||||
/* Get a new cse_reg_info structure. */
|
||||
if (cse_reg_info_free_list)
|
||||
if (cse_reg_info_free_list)
|
||||
{
|
||||
cri = cse_reg_info_free_list;
|
||||
cse_reg_info_free_list = cri->next;
|
||||
p = cse_reg_info_free_list;
|
||||
cse_reg_info_free_list = p->next;
|
||||
}
|
||||
else
|
||||
cri = (struct cse_reg_info *) xmalloc (sizeof (struct cse_reg_info));
|
||||
p = (struct cse_reg_info *) xmalloc (sizeof (struct cse_reg_info));
|
||||
|
||||
/* Insert into hash table. */
|
||||
p->hash_next = *hash_head;
|
||||
*hash_head = p;
|
||||
|
||||
/* Initialize it. */
|
||||
cri->reg_tick = 0;
|
||||
cri->reg_in_table = -1;
|
||||
cri->reg_qty = regno;
|
||||
cri->regno = regno;
|
||||
cri->next = cse_reg_info_used_list;
|
||||
cse_reg_info_used_list = cri;
|
||||
p->reg_tick = 1;
|
||||
p->reg_in_table = -1;
|
||||
p->reg_qty = regno;
|
||||
p->regno = regno;
|
||||
p->next = cse_reg_info_used_list;
|
||||
cse_reg_info_used_list = p;
|
||||
if (!cse_reg_info_used_list_end)
|
||||
cse_reg_info_used_list_end = cri;
|
||||
|
||||
*entry = cri;
|
||||
cse_reg_info_used_list_end = p;
|
||||
}
|
||||
|
||||
/* Cache this lookup; we tend to be looking up information about the
|
||||
same register several times in a row. */
|
||||
cached_regno = regno;
|
||||
cached_cse_reg_info = cri;
|
||||
cached_cse_reg_info = p;
|
||||
|
||||
return cri;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
hash_cse_reg_info (el_ptr)
|
||||
hash_table_entry_t el_ptr;
|
||||
{
|
||||
return ((const struct cse_reg_info *) el_ptr)->regno;
|
||||
}
|
||||
|
||||
static int
|
||||
cse_reg_info_equal_p (el_ptr1, el_ptr2)
|
||||
hash_table_entry_t el_ptr1;
|
||||
hash_table_entry_t el_ptr2;
|
||||
{
|
||||
return (((const struct cse_reg_info *) el_ptr1)->regno
|
||||
== ((const struct cse_reg_info *) el_ptr2)->regno);
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Clear the hash table and initialize each register with its own quantity,
|
||||
|
@ -905,38 +898,45 @@ new_basic_block ()
|
|||
|
||||
next_qty = max_reg;
|
||||
|
||||
if (cse_reg_info_tree)
|
||||
{
|
||||
delete_hash_table (cse_reg_info_tree);
|
||||
if (cse_reg_info_used_list)
|
||||
{
|
||||
cse_reg_info_used_list_end->next = cse_reg_info_free_list;
|
||||
cse_reg_info_free_list = cse_reg_info_used_list;
|
||||
cse_reg_info_used_list = cse_reg_info_used_list_end = 0;
|
||||
}
|
||||
cached_cse_reg_info = 0;
|
||||
}
|
||||
/* Clear out hash table state for this pass. */
|
||||
|
||||
cse_reg_info_tree = create_hash_table (0, hash_cse_reg_info,
|
||||
cse_reg_info_equal_p);
|
||||
bzero ((char *) reg_hash, sizeof reg_hash);
|
||||
|
||||
if (cse_reg_info_used_list)
|
||||
{
|
||||
cse_reg_info_used_list_end->next = cse_reg_info_free_list;
|
||||
cse_reg_info_free_list = cse_reg_info_used_list;
|
||||
cse_reg_info_used_list = cse_reg_info_used_list_end = 0;
|
||||
}
|
||||
cached_cse_reg_info = 0;
|
||||
|
||||
CLEAR_HARD_REG_SET (hard_regs_in_table);
|
||||
|
||||
/* The per-quantity values used to be initialized here, but it is
|
||||
much faster to initialize each as it is made in `make_new_qty'. */
|
||||
|
||||
for (i = 0; i < NBUCKETS; i++)
|
||||
for (i = 0; i < HASH_SIZE; i++)
|
||||
{
|
||||
register struct table_elt *this, *next;
|
||||
for (this = table[i]; this; this = next)
|
||||
struct table_elt *first;
|
||||
|
||||
first = table[i];
|
||||
if (first != NULL)
|
||||
{
|
||||
next = this->next_same_hash;
|
||||
free_element (this);
|
||||
struct table_elt *last = first;
|
||||
|
||||
table[i] = NULL;
|
||||
|
||||
while (last->next_same_hash != NULL)
|
||||
last = last->next_same_hash;
|
||||
|
||||
/* Now relink this hash entire chain into
|
||||
the free element list. */
|
||||
|
||||
last->next_same_hash = free_element_chain;
|
||||
free_element_chain = first;
|
||||
}
|
||||
}
|
||||
|
||||
bzero ((char *) table, sizeof table);
|
||||
|
||||
prev_insn = 0;
|
||||
|
||||
#ifdef HAVE_cc0
|
||||
|
@ -1258,31 +1258,6 @@ insert_regs (x, classp, modified)
|
|||
|
||||
/* Look in or update the hash table. */
|
||||
|
||||
/* Put the element ELT on the list of free elements. */
|
||||
|
||||
static void
|
||||
free_element (elt)
|
||||
struct table_elt *elt;
|
||||
{
|
||||
elt->next_same_hash = free_element_chain;
|
||||
free_element_chain = elt;
|
||||
}
|
||||
|
||||
/* Return an element that is free for use. */
|
||||
|
||||
static struct table_elt *
|
||||
get_element ()
|
||||
{
|
||||
struct table_elt *elt = free_element_chain;
|
||||
if (elt)
|
||||
{
|
||||
free_element_chain = elt->next_same_hash;
|
||||
return elt;
|
||||
}
|
||||
n_elements_made++;
|
||||
return (struct table_elt *) oballoc (sizeof (struct table_elt));
|
||||
}
|
||||
|
||||
/* Remove table element ELT from use in the table.
|
||||
HASH is its hash code, made using the HASH macro.
|
||||
It's an argument because often that is known in advance
|
||||
|
@ -1338,7 +1313,7 @@ remove_from_table (elt, hash)
|
|||
when two classes were merged by `merge_equiv_classes'. Search
|
||||
for the hash bucket that it heads. This happens only very
|
||||
rarely, so the cost is acceptable. */
|
||||
for (hash = 0; hash < NBUCKETS; hash++)
|
||||
for (hash = 0; hash < HASH_SIZE; hash++)
|
||||
if (table[hash] == elt)
|
||||
table[hash] = next;
|
||||
}
|
||||
|
@ -1356,7 +1331,9 @@ remove_from_table (elt, hash)
|
|||
p->related_value = 0;
|
||||
}
|
||||
|
||||
free_element (elt);
|
||||
/* Now add it to the free element chain. */
|
||||
elt->next_same_hash = free_element_chain;
|
||||
free_element_chain = elt;
|
||||
}
|
||||
|
||||
/* Look up X in the hash table and return its table element,
|
||||
|
@ -1423,7 +1400,7 @@ lookup_as_function (x, code)
|
|||
rtx x;
|
||||
enum rtx_code code;
|
||||
{
|
||||
register struct table_elt *p = lookup (x, safe_hash (x, VOIDmode) % NBUCKETS,
|
||||
register struct table_elt *p = lookup (x, safe_hash (x, VOIDmode) & HASH_MASK,
|
||||
GET_MODE (x));
|
||||
/* If we are looking for a CONST_INT, the mode doesn't really matter, as
|
||||
long as we are narrowing. So if we looked in vain for a mode narrower
|
||||
|
@ -1433,7 +1410,7 @@ lookup_as_function (x, code)
|
|||
{
|
||||
x = copy_rtx (x);
|
||||
PUT_MODE (x, word_mode);
|
||||
p = lookup (x, safe_hash (x, VOIDmode) % NBUCKETS, word_mode);
|
||||
p = lookup (x, safe_hash (x, VOIDmode) & HASH_MASK, word_mode);
|
||||
}
|
||||
|
||||
if (p == 0)
|
||||
|
@ -1509,7 +1486,17 @@ insert (x, classp, hash, mode)
|
|||
|
||||
/* Put an element for X into the right hash bucket. */
|
||||
|
||||
elt = get_element ();
|
||||
elt = free_element_chain;
|
||||
if (elt)
|
||||
{
|
||||
free_element_chain = elt->next_same_hash;
|
||||
}
|
||||
else
|
||||
{
|
||||
n_elements_made++;
|
||||
elt = (struct table_elt *) oballoc (sizeof (struct table_elt));
|
||||
}
|
||||
|
||||
elt->exp = x;
|
||||
elt->cost = COST (x);
|
||||
elt->next_same_value = 0;
|
||||
|
@ -1628,7 +1615,7 @@ insert (x, classp, hash, mode)
|
|||
if (subexp != 0)
|
||||
{
|
||||
/* Get the integer-free subexpression in the hash table. */
|
||||
subhash = safe_hash (subexp, mode) % NBUCKETS;
|
||||
subhash = safe_hash (subexp, mode) & HASH_MASK;
|
||||
subelt = lookup (subexp, subhash, mode);
|
||||
if (subelt == 0)
|
||||
subelt = insert (subexp, NULL_PTR, subhash, mode);
|
||||
|
@ -1713,7 +1700,7 @@ flush_hash_table ()
|
|||
int i;
|
||||
struct table_elt *p;
|
||||
|
||||
for (i = 0; i < NBUCKETS; i++)
|
||||
for (i = 0; i < HASH_SIZE; i++)
|
||||
for (p = table[i]; p; p = table[i])
|
||||
{
|
||||
/* Note that invalidate can remove elements
|
||||
|
@ -1796,7 +1783,7 @@ invalidate (x, full_mode)
|
|||
}
|
||||
|
||||
if (in_table)
|
||||
for (hash = 0; hash < NBUCKETS; hash++)
|
||||
for (hash = 0; hash < HASH_SIZE; hash++)
|
||||
for (p = table[hash]; p; p = next)
|
||||
{
|
||||
next = p->next_same_hash;
|
||||
|
@ -1836,7 +1823,7 @@ invalidate (x, full_mode)
|
|||
if (full_mode == VOIDmode)
|
||||
full_mode = GET_MODE (x);
|
||||
|
||||
for (i = 0; i < NBUCKETS; i++)
|
||||
for (i = 0; i < HASH_SIZE; i++)
|
||||
{
|
||||
register struct table_elt *next;
|
||||
|
||||
|
@ -1869,7 +1856,7 @@ remove_invalid_refs (regno)
|
|||
register int i;
|
||||
register struct table_elt *p, *next;
|
||||
|
||||
for (i = 0; i < NBUCKETS; i++)
|
||||
for (i = 0; i < HASH_SIZE; i++)
|
||||
for (p = table[i]; p; p = next)
|
||||
{
|
||||
next = p->next_same_hash;
|
||||
|
@ -1890,7 +1877,7 @@ remove_invalid_subreg_refs (regno, word, mode)
|
|||
register struct table_elt *p, *next;
|
||||
int end = word + (GET_MODE_SIZE (mode) - 1) / UNITS_PER_WORD;
|
||||
|
||||
for (i = 0; i < NBUCKETS; i++)
|
||||
for (i = 0; i < HASH_SIZE; i++)
|
||||
for (p = table[i]; p; p = next)
|
||||
{
|
||||
rtx exp;
|
||||
|
@ -1938,13 +1925,13 @@ rehash_using_reg (x)
|
|||
If we find one and it is in the wrong hash chain, move it. We can skip
|
||||
objects that are registers, since they are handled specially. */
|
||||
|
||||
for (i = 0; i < NBUCKETS; i++)
|
||||
for (i = 0; i < HASH_SIZE; i++)
|
||||
for (p = table[i]; p; p = next)
|
||||
{
|
||||
next = p->next_same_hash;
|
||||
if (GET_CODE (p->exp) != REG && reg_mentioned_p (x, p->exp)
|
||||
&& exp_equiv_p (p->exp, p->exp, 1, 0)
|
||||
&& i != (hash = safe_hash (p->exp, p->mode) % NBUCKETS))
|
||||
&& i != (hash = safe_hash (p->exp, p->mode) & HASH_MASK))
|
||||
{
|
||||
if (p->next_same_hash)
|
||||
p->next_same_hash->prev_same_hash = p->prev_same_hash;
|
||||
|
@ -1995,7 +1982,7 @@ invalidate_for_call ()
|
|||
entry that overlaps a call-clobbered register. */
|
||||
|
||||
if (in_table)
|
||||
for (hash = 0; hash < NBUCKETS; hash++)
|
||||
for (hash = 0; hash < HASH_SIZE; hash++)
|
||||
for (p = table[hash]; p; p = next)
|
||||
{
|
||||
next = p->next_same_hash;
|
||||
|
@ -2042,7 +2029,7 @@ use_related_value (x, elt)
|
|||
rtx subexp = get_related_value (x);
|
||||
if (subexp != 0)
|
||||
relt = lookup (subexp,
|
||||
safe_hash (subexp, GET_MODE (subexp)) % NBUCKETS,
|
||||
safe_hash (subexp, GET_MODE (subexp)) & HASH_MASK,
|
||||
GET_MODE (subexp));
|
||||
}
|
||||
|
||||
|
@ -2942,7 +2929,7 @@ find_comparison_args (code, parg1, parg2, pmode1, pmode2)
|
|||
if (x == 0)
|
||||
/* Look up ARG1 in the hash table and see if it has an equivalence
|
||||
that lets us see what is being compared. */
|
||||
p = lookup (arg1, safe_hash (arg1, GET_MODE (arg1)) % NBUCKETS,
|
||||
p = lookup (arg1, safe_hash (arg1, GET_MODE (arg1)) & HASH_MASK,
|
||||
GET_MODE (arg1));
|
||||
if (p) p = p->first_same_value;
|
||||
|
||||
|
@ -3712,10 +3699,10 @@ fold_rtx (x, insn)
|
|||
== REG_QTY (REGNO (folded_arg1))))
|
||||
|| ((p0 = lookup (folded_arg0,
|
||||
(safe_hash (folded_arg0, mode_arg0)
|
||||
% NBUCKETS), mode_arg0))
|
||||
& HASH_MASK), mode_arg0))
|
||||
&& (p1 = lookup (folded_arg1,
|
||||
(safe_hash (folded_arg1, mode_arg0)
|
||||
% NBUCKETS), mode_arg0))
|
||||
& HASH_MASK), mode_arg0))
|
||||
&& p0->first_same_value == p1->first_same_value)))
|
||||
return ((code == EQ || code == LE || code == GE
|
||||
|| code == LEU || code == GEU)
|
||||
|
@ -3881,7 +3868,7 @@ fold_rtx (x, insn)
|
|||
{
|
||||
rtx new_const = GEN_INT (- INTVAL (const_arg1));
|
||||
struct table_elt *p
|
||||
= lookup (new_const, safe_hash (new_const, mode) % NBUCKETS,
|
||||
= lookup (new_const, safe_hash (new_const, mode) & HASH_MASK,
|
||||
mode);
|
||||
|
||||
if (p)
|
||||
|
@ -4067,7 +4054,7 @@ equiv_constant (x)
|
|||
if (CONSTANT_P (x))
|
||||
return x;
|
||||
|
||||
elt = lookup (x, safe_hash (x, GET_MODE (x)) % NBUCKETS, GET_MODE (x));
|
||||
elt = lookup (x, safe_hash (x, GET_MODE (x)) & HASH_MASK, GET_MODE (x));
|
||||
if (elt == 0)
|
||||
return 0;
|
||||
|
||||
|
@ -5694,7 +5681,7 @@ cse_insn (insn, libcall_insn)
|
|||
/* We used to rely on all references to a register becoming
|
||||
inaccessible when a register changes to a new quantity,
|
||||
since that changes the hash code. However, that is not
|
||||
safe, since after NBUCKETS new quantities we get a
|
||||
safe, since after HASH_SIZE new quantities we get a
|
||||
hash 'collision' of a register with its own invalid
|
||||
entries. And since SUBREGs have been changed not to
|
||||
change their hash code with the hash code of the register,
|
||||
|
@ -5997,7 +5984,7 @@ invalidate_memory ()
|
|||
register int i;
|
||||
register struct table_elt *p, *next;
|
||||
|
||||
for (i = 0; i < NBUCKETS; i++)
|
||||
for (i = 0; i < HASH_SIZE; i++)
|
||||
for (p = table[i]; p; p = next)
|
||||
{
|
||||
next = p->next_same_hash;
|
||||
|
|
Loading…
Add table
Reference in a new issue