/* Common subexpression elimination for GNU compiler.
- Copyright (C) 1987, 88, 89, 92-7, 1998, 1999 Free Software Foundation, Inc.
+ Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998
+ 1999, 2000 Free Software Foundation, Inc.
This file is part of GNU CC.
#include "expr.h"
#include "toplev.h"
#include "output.h"
-#include "hashtab.h"
#include "ggc.h"
/* The basic idea of common subexpression elimination is to go
rtx const_insn;
rtx comparison_const;
int comparison_qty;
- int first_reg, last_reg;
+ unsigned int first_reg, last_reg;
enum machine_mode mode;
enum rtx_code comparison_code;
};
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 */
+ unsigned 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. */
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. */
-static int cached_regno;
+static unsigned int cached_regno;
static struct cse_reg_info *cached_cse_reg_info;
/* A HARD_REG_SET containing all the hard registers for which there is
#define INSN_CUID(INSN) (uid_cuid[INSN_UID (INSN)])
+/* Nonzero if this pass has made changes, and therefore it's
+ worthwhile to run the garbage collector. */
+
+static int cse_altered;
+
/* Nonzero if cse has altered conditional jump insns
in such a way that jump optimization should be redone. */
each recording one expression's information.
That expression is in the `exp' field.
+ The canon_exp field contains a canonical (from the point of view of
+ alias analysis) version of the `exp' field.
+
Those elements with the same hash code are chained in both directions
through the `next_same_hash' and `prev_same_hash' fields.
struct table_elt
{
rtx exp;
+ rtx canon_exp;
struct table_elt *next_same_hash;
struct table_elt *prev_same_hash;
struct table_elt *next_same_value;
/* 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
/* Determine if the quantity number for register X represents a valid index
into the qty_table. */
-#define REGNO_QTY_VALID_P(N) (REG_QTY (N) != (N))
-
-#ifdef ADDRESS_COST
-/* The ADDRESS_COST macro does not deal with ADDRESSOF nodes. But,
- during CSE, such nodes are present. Using an ADDRESSOF node which
- refers to the address of a REG is a good thing because we can then
- turn (MEM (ADDRESSSOF (REG))) into just plain REG. */
-#define CSE_ADDRESS_COST(RTX) \
- ((GET_CODE (RTX) == ADDRESSOF && REG_P (XEXP ((RTX), 0))) \
- ? -1 : ADDRESS_COST(RTX))
-#endif
+#define REGNO_QTY_VALID_P(N) (REG_QTY (N) != (int) (N))
-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. */
|| XEXP (X, 0) == virtual_outgoing_args_rtx)) \
|| GET_CODE (X) == ADDRESSOF)
-static int notreg_cost PROTO((rtx));
-static void new_basic_block PROTO((void));
-static void make_new_qty PROTO((int, enum machine_mode));
-static void make_regs_eqv PROTO((int, int));
-static void delete_reg_equiv PROTO((int));
-static int mention_regs PROTO((rtx));
-static int insert_regs PROTO((rtx, struct table_elt *, int));
-static void free_element PROTO((struct table_elt *));
-static void remove_from_table PROTO((struct table_elt *, unsigned));
-static struct table_elt *get_element PROTO((void));
-static struct table_elt *lookup PROTO((rtx, unsigned, enum machine_mode)),
- *lookup_for_remove PROTO((rtx, unsigned, enum machine_mode));
-static rtx lookup_as_function PROTO((rtx, enum rtx_code));
-static struct table_elt *insert PROTO((rtx, struct table_elt *, unsigned,
- enum machine_mode));
-static void merge_equiv_classes PROTO((struct table_elt *,
- struct table_elt *));
-static void invalidate PROTO((rtx, enum machine_mode));
-static int cse_rtx_varies_p PROTO((rtx));
-static void remove_invalid_refs PROTO((int));
-static void remove_invalid_subreg_refs PROTO((int, int, enum machine_mode));
-static void rehash_using_reg PROTO((rtx));
-static void invalidate_memory PROTO((void));
-static void invalidate_for_call PROTO((void));
-static rtx use_related_value PROTO((rtx, struct table_elt *));
-static unsigned canon_hash PROTO((rtx, enum machine_mode));
-static unsigned safe_hash PROTO((rtx, enum machine_mode));
-static int exp_equiv_p PROTO((rtx, rtx, int, int));
-static rtx canon_reg PROTO((rtx, rtx));
-static void find_best_addr PROTO((rtx, rtx *));
-static enum rtx_code find_comparison_args PROTO((enum rtx_code, rtx *, rtx *,
- enum machine_mode *,
- enum machine_mode *));
-static rtx fold_rtx PROTO((rtx, rtx));
-static rtx equiv_constant PROTO((rtx));
-static void record_jump_equiv PROTO((rtx, int));
-static void record_jump_cond PROTO((enum rtx_code, enum machine_mode,
- rtx, rtx, int));
-static void cse_insn PROTO((rtx, rtx));
-static int addr_affects_sp_p PROTO((rtx));
-static void invalidate_from_clobbers PROTO((rtx));
-static rtx cse_process_notes PROTO((rtx, rtx));
-static void cse_around_loop PROTO((rtx));
-static void invalidate_skipped_set PROTO((rtx, rtx, void *));
-static void invalidate_skipped_block PROTO((rtx));
-static void cse_check_loop_start PROTO((rtx, rtx, void *));
-static void cse_set_around_loop PROTO((rtx, rtx, rtx));
-static rtx cse_basic_block PROTO((rtx, rtx, struct branch_path *, int));
-static void count_reg_usage PROTO((rtx, int *, rtx, int));
-extern void dump_class PROTO((struct table_elt*));
-static struct cse_reg_info* get_cse_reg_info PROTO((int));
-static unsigned int hash_cse_reg_info PROTO((hash_table_entry_t));
-static int cse_reg_info_equal_p PROTO((hash_table_entry_t,
- hash_table_entry_t));
-
-static void flush_hash_table PROTO((void));
+static int notreg_cost PARAMS ((rtx));
+static void new_basic_block PARAMS ((void));
+static void make_new_qty PARAMS ((unsigned int, enum machine_mode));
+static void make_regs_eqv PARAMS ((unsigned int, unsigned int));
+static void delete_reg_equiv PARAMS ((unsigned int));
+static int mention_regs PARAMS ((rtx));
+static int insert_regs PARAMS ((rtx, struct table_elt *, int));
+static void remove_from_table PARAMS ((struct table_elt *, unsigned));
+static struct table_elt *lookup PARAMS ((rtx, unsigned, enum machine_mode)),
+ *lookup_for_remove PARAMS ((rtx, unsigned, enum machine_mode));
+static rtx lookup_as_function PARAMS ((rtx, enum rtx_code));
+static struct table_elt *insert PARAMS ((rtx, struct table_elt *, unsigned,
+ enum machine_mode));
+static void merge_equiv_classes PARAMS ((struct table_elt *,
+ struct table_elt *));
+static void invalidate PARAMS ((rtx, enum machine_mode));
+static int cse_rtx_varies_p PARAMS ((rtx));
+static void remove_invalid_refs PARAMS ((unsigned int));
+static void remove_invalid_subreg_refs PARAMS ((unsigned int, unsigned int,
+ enum machine_mode));
+static void rehash_using_reg PARAMS ((rtx));
+static void invalidate_memory PARAMS ((void));
+static void invalidate_for_call PARAMS ((void));
+static rtx use_related_value PARAMS ((rtx, struct table_elt *));
+static unsigned canon_hash PARAMS ((rtx, enum machine_mode));
+static unsigned safe_hash PARAMS ((rtx, enum machine_mode));
+static int exp_equiv_p PARAMS ((rtx, rtx, int, int));
+static rtx canon_reg PARAMS ((rtx, rtx));
+static void find_best_addr PARAMS ((rtx, rtx *, enum machine_mode));
+static enum rtx_code find_comparison_args PARAMS ((enum rtx_code, rtx *, rtx *,
+ enum machine_mode *,
+ enum machine_mode *));
+static rtx fold_rtx PARAMS ((rtx, rtx));
+static rtx equiv_constant PARAMS ((rtx));
+static void record_jump_equiv PARAMS ((rtx, int));
+static void record_jump_cond PARAMS ((enum rtx_code, enum machine_mode,
+ rtx, rtx, int));
+static void cse_insn PARAMS ((rtx, rtx));
+static int addr_affects_sp_p PARAMS ((rtx));
+static void invalidate_from_clobbers PARAMS ((rtx));
+static rtx cse_process_notes PARAMS ((rtx, rtx));
+static void cse_around_loop PARAMS ((rtx));
+static void invalidate_skipped_set PARAMS ((rtx, rtx, void *));
+static void invalidate_skipped_block PARAMS ((rtx));
+static void cse_check_loop_start PARAMS ((rtx, rtx, void *));
+static void cse_set_around_loop PARAMS ((rtx, rtx, rtx));
+static rtx cse_basic_block PARAMS ((rtx, rtx, struct branch_path *, int));
+static void count_reg_usage PARAMS ((rtx, int *, rtx, int));
+extern void dump_class PARAMS ((struct table_elt*));
+static struct cse_reg_info * get_cse_reg_info PARAMS ((unsigned int));
+static int check_dependence PARAMS ((rtx *, void *));
+
+static void flush_hash_table PARAMS ((void));
\f
/* Dump the expressions in the equivalence class indicated by CLASSP.
This function is used only for debugging. */
}
}
-/* Return an estimate of the cost of computing rtx X.
- One use is in cse, to decide which expression to keep in the hash table.
- Another is in rtl generation, to pick the cheapest way to multiply.
- Other uses like the latter are expected in the future. */
-
/* Internal function, to compute cost when X is not a register; called
from COST macro to keep it simple. */
#define COSTS_N_INSNS(N) ((N) * 4 - 2)
+/* Return an estimate of the cost of computing rtx X.
+ One use is in cse, to decide which expression to keep in the hash table.
+ Another is in rtl generation, to pick the cheapest way to multiply.
+ Other uses like the latter are expected in the future. */
+
int
rtx_cost (x, outer_code)
rtx x;
return total;
}
\f
+/* Return cost of address expression X. Expect that X is propertly formed address
+ reference. */
+int
+address_cost (x, mode)
+ rtx x;
+ enum machine_mode mode;
+{
+ /* The ADDRESS_COST macro does not deal with ADDRESSOF nodes. But,
+ during CSE, such nodes are present. Using an ADDRESSOF node which
+ refers to the address of a REG is a good thing because we can then
+ turn (MEM (ADDRESSSOF (REG))) into just plain REG. */
+
+ if (GET_CODE (x) == ADDRESSOF && REG_P (XEXP ((x), 0)))
+ return -1;
+
+ /* We may be asked for cost of various unusual addresses, such as operands
+ of push instruction. It is not worthwhile to complicate writting
+ of ADDRESS_COST macro by such cases. */
+
+ if (!memory_address_p (mode, x))
+ return 1000;
+#ifdef ADDRESS_COST
+ return ADDRESS_COST (x);
+#else
+ return rtx_cost (x, MEM);
+#endif
+}
+\f
static struct cse_reg_info *
get_cse_reg_info (regno)
- int regno;
+ unsigned int regno;
{
- struct cse_reg_info *cri;
- struct cse_reg_info **entry;
- struct cse_reg_info temp;
-
- /* 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);
-
- if (*entry)
- cri = *entry;
- else
+ struct cse_reg_info **hash_head = ®_hash[REGHASH_FN (regno)];
+ struct cse_reg_info *p;
+
+ for (p = *hash_head ; p != NULL; p = p->hash_next)
+ if (p->regno == regno)
+ break;
+
+ 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,
next_qty = max_reg;
- if (cse_reg_info_tree)
+ /* Clear out hash table state for this pass. */
+
+ bzero ((char *) reg_hash, sizeof reg_hash);
+
+ if (cse_reg_info_used_list)
{
- 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;
+ 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;
}
-
- cse_reg_info_tree = create_hash_table (0, hash_cse_reg_info,
- cse_reg_info_equal_p);
+ 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
static void
make_new_qty (reg, mode)
- register int reg;
- register enum machine_mode mode;
+ unsigned int reg;
+ enum machine_mode mode;
{
register int q;
register struct qty_table_elem *ent;
static void
make_regs_eqv (new, old)
- register int new, old;
+ unsigned int new, old;
{
- register int lastr, firstr;
- register int q = REG_QTY (old);
- register struct qty_table_elem *ent;
+ unsigned int lastr, firstr;
+ int q = REG_QTY (old);
+ struct qty_table_elem *ent;
ent = &qty_table[q];
static void
delete_reg_equiv (reg)
- register int reg;
+ unsigned int reg;
{
register struct qty_table_elem *ent;
register int q = REG_QTY (reg);
register int p, n;
/* If invalid, do nothing. */
- if (q == reg)
+ if (q == (int) reg)
return;
ent = &qty_table[q];
code = GET_CODE (x);
if (code == REG)
{
- register int regno = REGNO (x);
- register int endregno
+ unsigned int regno = REGNO (x);
+ unsigned int endregno
= regno + (regno >= FIRST_PSEUDO_REGISTER ? 1
: HARD_REGNO_NREGS (regno, GET_MODE (x)));
- int i;
+ unsigned int i;
for (i = regno; i < endregno; i++)
{
if (code == SUBREG && GET_CODE (SUBREG_REG (x)) == REG
&& REGNO (SUBREG_REG (x)) >= FIRST_PSEUDO_REGISTER)
{
- int i = REGNO (SUBREG_REG (x));
+ unsigned int i = REGNO (SUBREG_REG (x));
if (REG_IN_TABLE (i) >= 0 && REG_IN_TABLE (i) != REG_TICK (i))
{
{
if (GET_CODE (x) == REG)
{
- register int regno = REGNO (x);
- register int qty_valid;
+ unsigned int regno = REGNO (x);
+ int qty_valid;
/* If REGNO is in the equivalence table already but is of the
wrong mode for that equivalence, don't do anything here. */
else if (GET_CODE (x) == SUBREG && GET_CODE (SUBREG_REG (x)) == REG
&& ! REGNO_QTY_VALID_P (REGNO (SUBREG_REG (x))))
{
- int regno = REGNO (SUBREG_REG (x));
+ unsigned int regno = REGNO (SUBREG_REG (x));
insert_regs (SUBREG_REG (x), NULL_PTR, 0);
/* Mention_regs checks if REG_TICK is exactly one larger than
\f
/* 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
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;
}
if (elt->related_value != 0 && elt->related_value != elt)
{
register struct table_elt *p = elt->related_value;
+
while (p->related_value != elt)
p = p->related_value;
p->related_value = elt->related_value;
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,
if (GET_CODE (x) == REG)
{
- int regno = REGNO (x);
+ unsigned int regno = REGNO (x);
+
/* Don't check the machine mode when comparing registers;
invalidating (REG:SI 0) also invalidates (REG:DF 0). */
for (p = table[hash]; p; p = p->next_same_hash)
rtx x;
enum rtx_code code;
{
- register struct table_elt *p = lookup (x, safe_hash (x, VOIDmode) % NBUCKETS,
- GET_MODE (x));
+ 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
than word_mode before, look for word_mode now. */
{
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)
return 0;
for (p = p->first_same_value; p; p = p->next_same_value)
- {
- if (GET_CODE (p->exp) == code
- /* Make sure this is a valid entry in the table. */
- && exp_equiv_p (p->exp, p->exp, 1, 0))
- return p->exp;
- }
+ if (GET_CODE (p->exp) == code
+ /* Make sure this is a valid entry in the table. */
+ && exp_equiv_p (p->exp, p->exp, 1, 0))
+ return p->exp;
return 0;
}
/* If X is a hard register, show it is being put in the table. */
if (GET_CODE (x) == REG && REGNO (x) < FIRST_PSEUDO_REGISTER)
{
- int regno = REGNO (x);
- int endregno = regno + HARD_REGNO_NREGS (regno, GET_MODE (x));
- int i;
+ unsigned int regno = REGNO (x);
+ unsigned int endregno = regno + HARD_REGNO_NREGS (regno, GET_MODE (x));
+ unsigned int i;
for (i = regno; i < endregno; i++)
- SET_HARD_REG_BIT (hard_regs_in_table, i);
+ SET_HARD_REG_BIT (hard_regs_in_table, i);
}
/* If X is a label, show we recorded it. */
/* 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->canon_exp = NULL_RTX;
elt->cost = COST (x);
elt->next_same_value = 0;
elt->prev_same_value = 0;
/* Insert not at head of the class. */
/* Put it after the last element cheaper than X. */
register struct table_elt *p, *next;
+
for (p = classp; (next = p->next_same_value) && CHEAPER (next, elt);
p = next);
+
/* Put it after P and before NEXT. */
elt->next_same_value = next;
if (next)
next->prev_same_value = elt;
+
elt->prev_same_value = p;
p->next_same_value = elt;
elt->first_same_value = classp;
int x_q = REG_QTY (REGNO (x));
struct qty_table_elem *x_ent = &qty_table[x_q];
- x_ent->const_rtx = gen_lowpart_if_possible (GET_MODE (x), p->exp);
+ x_ent->const_rtx
+ = gen_lowpart_if_possible (GET_MODE (x), p->exp);
x_ent->const_insn = this_insn;
break;
}
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);
for (elt = class2; elt; elt = next)
{
- unsigned hash;
+ unsigned int hash;
rtx exp = elt->exp;
enum machine_mode mode = elt->mode;
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
}
}
\f
+/* Function called for each rtx to check whether true dependence exist. */
+struct check_dependence_data
+{
+ enum machine_mode mode;
+ rtx exp;
+};
+static int
+check_dependence (x, data)
+ rtx *x;
+ void *data;
+{
+ struct check_dependence_data *d = (struct check_dependence_data *) data;
+ if (*x && GET_CODE (*x) == MEM)
+ return true_dependence (d->exp, d->mode, *x, cse_rtx_varies_p);
+ else
+ return 0;
+}
+\f
/* Remove from the hash table, or mark as invalid, all expressions whose
values could be altered by storing in X. X is a register, a subreg, or
a memory reference with nonvarying address (because, when a memory
through the qty number mechanism. Just change the qty number of
the register, mark it as invalid for expressions that refer to it,
and remove it itself. */
- register int regno = REGNO (x);
- register unsigned hash = HASH (x, GET_MODE (x));
+ unsigned int regno = REGNO (x);
+ unsigned int hash = HASH (x, GET_MODE (x));
/* Remove REGNO from any quantity list it might be on and indicate
that its value might have changed. If it is a pseudo, remove its
{
HOST_WIDE_INT in_table
= TEST_HARD_REG_BIT (hard_regs_in_table, regno);
- int endregno = regno + HARD_REGNO_NREGS (regno, GET_MODE (x));
- int tregno, tendregno;
+ unsigned int endregno
+ = regno + HARD_REGNO_NREGS (regno, GET_MODE (x));
+ unsigned int tregno, tendregno, rn;
register struct table_elt *p, *next;
CLEAR_HARD_REG_BIT (hard_regs_in_table, regno);
- for (i = regno + 1; i < endregno; i++)
+ for (rn = regno + 1; rn < endregno; rn++)
{
- in_table |= TEST_HARD_REG_BIT (hard_regs_in_table, i);
- CLEAR_HARD_REG_BIT (hard_regs_in_table, i);
- delete_reg_equiv (i);
- REG_TICK (i)++;
+ in_table |= TEST_HARD_REG_BIT (hard_regs_in_table, rn);
+ CLEAR_HARD_REG_BIT (hard_regs_in_table, rn);
+ delete_reg_equiv (rn);
+ REG_TICK (rn)++;
}
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;
return;
case MEM:
+ /* Calculate the canonical version of X here so that
+ true_dependence doesn't generate new RTL for X on each call. */
+ x = canon_rtx (x);
+
/* Remove all hash table elements that refer to overlapping pieces of
memory. */
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;
for (p = table[i]; p; p = next)
{
next = p->next_same_hash;
- if (p->in_memory
- && (GET_CODE (p->exp) != MEM
- || true_dependence (x, full_mode, p->exp,
- cse_rtx_varies_p)))
- remove_from_table (p, i);
+ if (p->in_memory)
+ {
+ struct check_dependence_data d;
+
+ /* Just canonicalize the expression once;
+ otherwise each time we call invalidate
+ true_dependence will canonicalize the
+ expression again. */
+ if (!p->canon_exp)
+ p->canon_exp = canon_rtx (p->exp);
+ d.exp = x;
+ d.mode = full_mode;
+ if (for_each_rtx (&p->canon_exp, check_dependence, &d))
+ remove_from_table (p, i);
+ }
}
}
return;
static void
remove_invalid_refs (regno)
- int regno;
+ unsigned int regno;
{
- register int i;
- register struct table_elt *p, *next;
+ unsigned int i;
+ 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;
/* Likewise for a subreg with subreg_reg WORD and mode MODE. */
static void
remove_invalid_subreg_refs (regno, word, mode)
- int regno;
- int word;
+ unsigned int regno;
+ unsigned int word;
enum machine_mode mode;
{
- register int i;
- register struct table_elt *p, *next;
- int end = word + (GET_MODE_SIZE (mode) - 1) / UNITS_PER_WORD;
+ unsigned int i;
+ struct table_elt *p, *next;
+ unsigned 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;
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;
static void
invalidate_for_call ()
{
- int regno, endregno;
- int i;
+ unsigned int regno, endregno;
+ unsigned int i;
unsigned hash;
struct table_elt *p, *next;
int in_table = 0;
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;
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));
}
{
case REG:
{
- register int regno = REGNO (x);
+ unsigned int regno = REGNO (x);
/* On some machines, we can't record any non-fixed hard register,
because extending its life will cause reload problems. We
do_not_record = 1;
return 0;
}
+
hash += ((unsigned) REG << 7) + (unsigned) REG_QTY (regno);
return hash;
}
hash += canon_hash (XVECEXP (x, i, j), 0);
else if (fmt[i] == 's')
{
- register unsigned char *p = (unsigned char *) XSTR (x, i);
+ register const unsigned char *p =
+ (const unsigned char *) XSTR (x, i);
+
if (p)
while (*p)
hash += *p++;
{
case PC:
case CC0:
- return x == y;
-
case CONST_INT:
- return INTVAL (x) == INTVAL (y);
+ return x == y;
case LABEL_REF:
return XEXP (x, 0) == XEXP (y, 0);
case REG:
{
- int regno = REGNO (y);
- int endregno
+ unsigned int regno = REGNO (y);
+ unsigned int endregno
= regno + (regno >= FIRST_PSEUDO_REGISTER ? 1
: HARD_REGNO_NREGS (regno, GET_MODE (y)));
- int i;
+ unsigned int i;
/* If the quantities are not the same, the expressions are not
equivalent. If there are and we are not to validate, they
*/
static void
-find_best_addr (insn, loc)
+find_best_addr (insn, loc, mode)
rtx insn;
rtx *loc;
+ enum machine_mode mode;
{
struct table_elt *elt;
rtx addr = *loc;
int save_hash_arg_in_memory = hash_arg_in_memory;
int addr_volatile;
int regno;
+ int folded_cost, addr_cost;
unsigned hash;
/* Do not try to replace constant addresses or addresses of local and
{
rtx folded = fold_rtx (copy_rtx (addr), NULL_RTX);
- if (1
-#ifdef ADDRESS_COST
- && (CSE_ADDRESS_COST (folded) < CSE_ADDRESS_COST (addr)
- || (CSE_ADDRESS_COST (folded) == CSE_ADDRESS_COST (addr)
- && rtx_cost (folded, MEM) > rtx_cost (addr, MEM)))
-#else
+ folded_cost = address_cost (folded, mode);
+ addr_cost = address_cost (addr, mode);
+
+ if ((folded_cost < addr_cost
+ || (folded_cost == addr_cost
+ && rtx_cost (folded, MEM) > rtx_cost (addr, MEM)))
&& rtx_cost (folded, MEM) < rtx_cost (addr, MEM)
-#endif
&& validate_change (insn, loc, folded, 0))
addr = folded;
}
while (found_better)
{
- int best_addr_cost = CSE_ADDRESS_COST (*loc);
+ int best_addr_cost = address_cost (*loc, mode);
int best_rtx_cost = (elt->cost + 1) >> 1;
+ int exp_cost;
struct table_elt *best_elt = elt;
found_better = 0;
{
if ((GET_CODE (p->exp) == REG
|| exp_equiv_p (p->exp, p->exp, 1, 0))
- && (CSE_ADDRESS_COST (p->exp) < best_addr_cost
- || (CSE_ADDRESS_COST (p->exp) == best_addr_cost
- && (p->cost + 1) >> 1 > best_rtx_cost)))
+ && ((exp_cost = address_cost (p->exp, mode)) < best_addr_cost
+ || (exp_cost == best_addr_cost
+ && (p->cost + 1) >> 1 < best_rtx_cost)))
{
found_better = 1;
- best_addr_cost = CSE_ADDRESS_COST (p->exp);
+ best_addr_cost = exp_cost;
best_rtx_cost = (p->cost + 1) >> 1;
best_elt = p;
}
while (found_better)
{
- int best_addr_cost = CSE_ADDRESS_COST (*loc);
+ int best_addr_cost = address_cost (*loc, mode);
int best_rtx_cost = (COST (*loc) + 1) >> 1;
struct table_elt *best_elt = elt;
rtx best_rtx = *loc;
{
rtx new = simplify_gen_binary (GET_CODE (*loc), Pmode,
p->exp, c);
+ int new_cost;
+ new_cost = address_cost (new, mode);
- if ((CSE_ADDRESS_COST (new) < best_addr_cost
- || (CSE_ADDRESS_COST (new) == best_addr_cost
- && (COST (new) + 1) >> 1 > best_rtx_cost)))
+ if (new_cost < best_addr_cost
+ || (new_cost == best_addr_cost
+ && (COST (new) + 1) >> 1 > best_rtx_cost))
{
found_better = 1;
- best_addr_cost = CSE_ADDRESS_COST (new);
+ best_addr_cost = new_cost;
best_rtx_cost = (COST (new) + 1) >> 1;
best_elt = p;
best_rtx = new;
&& code == LT && STORE_FLAG_VALUE == -1)
#ifdef FLOAT_STORE_FLAG_VALUE
|| (GET_MODE_CLASS (GET_MODE (arg1)) == MODE_FLOAT
- && FLOAT_STORE_FLAG_VALUE < 0)
+ && (REAL_VALUE_NEGATIVE
+ (FLOAT_STORE_FLAG_VALUE (GET_MODE (arg1)))))
#endif
)
x = arg1;
&& code == GE && STORE_FLAG_VALUE == -1)
#ifdef FLOAT_STORE_FLAG_VALUE
|| (GET_MODE_CLASS (GET_MODE (arg1)) == MODE_FLOAT
- && FLOAT_STORE_FLAG_VALUE < 0)
+ && (REAL_VALUE_NEGATIVE
+ (FLOAT_STORE_FLAG_VALUE (GET_MODE (arg1)))))
#endif
)
x = arg1, reverse_code = 1;
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;
#ifdef FLOAT_STORE_FLAG_VALUE
|| (code == LT
&& GET_MODE_CLASS (inner_mode) == MODE_FLOAT
- && FLOAT_STORE_FLAG_VALUE < 0)
+ && (REAL_VALUE_NEGATIVE
+ (FLOAT_STORE_FLAG_VALUE (GET_MODE (arg1)))))
#endif
)
&& GET_RTX_CLASS (GET_CODE (p->exp)) == '<'))
#ifdef FLOAT_STORE_FLAG_VALUE
|| (code == GE
&& GET_MODE_CLASS (inner_mode) == MODE_FLOAT
- && FLOAT_STORE_FLAG_VALUE < 0)
+ && (REAL_VALUE_NEGATIVE
+ (FLOAT_STORE_FLAG_VALUE (GET_MODE (arg1)))))
#endif
)
&& GET_RTX_CLASS (GET_CODE (p->exp)) == '<')
best address. Not only don't we care, but we could modify the
MEM in an invalid way since we have no insn to validate against. */
if (insn != 0)
- find_best_addr (insn, &XEXP (x, 0));
+ find_best_addr (insn, &XEXP (x, 0), GET_MODE (x));
{
/* Even if we don't fold in the insn itself,
#ifdef FLOAT_STORE_FLAG_VALUE
if (GET_MODE_CLASS (mode) == MODE_FLOAT)
{
- true = CONST_DOUBLE_FROM_REAL_VALUE (FLOAT_STORE_FLAG_VALUE,
- mode);
+ true = (CONST_DOUBLE_FROM_REAL_VALUE
+ (FLOAT_STORE_FLAG_VALUE (mode), mode));
false = CONST0_RTX (mode);
}
#endif
== 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)
struct qty_table_elem *ent = &qty_table[qty];
if ((comparison_dominates_p (ent->comparison_code, code)
- || (comparison_dominates_p (ent->comparison_code,
- reverse_condition (code))
- && ! FLOAT_MODE_P (mode_arg0)))
+ || (! FLOAT_MODE_P (mode_arg0)
+ && comparison_dominates_p (ent->comparison_code,
+ reverse_condition (code))))
&& (rtx_equal_p (ent->comparison_const, folded_arg1)
|| (const_arg1
&& rtx_equal_p (ent->comparison_const,
#ifdef FLOAT_STORE_FLAG_VALUE
if (GET_MODE_CLASS (mode) == MODE_FLOAT)
{
- true = CONST_DOUBLE_FROM_REAL_VALUE (FLOAT_STORE_FLAG_VALUE,
- mode);
+ true = (CONST_DOUBLE_FROM_REAL_VALUE
+ (FLOAT_STORE_FLAG_VALUE (mode), mode));
false = CONST0_RTX (mode);
}
#endif
const_arg1 ? const_arg1 : folded_arg1);
#ifdef FLOAT_STORE_FLAG_VALUE
if (new != 0 && GET_MODE_CLASS (mode) == MODE_FLOAT)
- new = ((new == const0_rtx) ? CONST0_RTX (mode)
- : CONST_DOUBLE_FROM_REAL_VALUE (FLOAT_STORE_FLAG_VALUE, mode));
+ {
+ if (new == const0_rtx)
+ new = CONST0_RTX (mode);
+ else
+ new = (CONST_DOUBLE_FROM_REAL_VALUE
+ (FLOAT_STORE_FLAG_VALUE (mode), mode));
+ }
#endif
break;
{
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)
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;
{
reversed_nonequality = (code != EQ && code != NE);
code = reverse_condition (code);
+
+ /* Don't remember if we can't find the inverse. */
+ if (code == UNKNOWN)
+ return;
}
/* The mode is the mode of the non-constant. */
int src_eqv_in_memory = 0;
unsigned src_eqv_hash = 0;
- struct set *sets = NULL_PTR;
+ struct set *sets = (struct set *) NULL_PTR;
this_insn = insn;
|| (GET_CODE (trial) == LABEL_REF
&& ! condjump_p (insn))))
{
- /* If TRIAL is a label in front of a jump table, we are
- really falling through the switch (this is how casesi
- insns work), so we must branch around the table. */
- if (GET_CODE (trial) == CODE_LABEL
- && NEXT_INSN (trial) != 0
- && GET_CODE (NEXT_INSN (trial)) == JUMP_INSN
- && (GET_CODE (PATTERN (NEXT_INSN (trial))) == ADDR_DIFF_VEC
- || GET_CODE (PATTERN (NEXT_INSN (trial))) == ADDR_VEC))
-
- trial = gen_rtx_LABEL_REF (Pmode, get_label_after (trial));
-
- SET_SRC (sets[i].rtl) = trial;
- cse_jumps_altered = 1;
+ if (trial == pc_rtx)
+ {
+ SET_SRC (sets[i].rtl) = trial;
+ cse_jumps_altered = 1;
+ break;
+ }
+
+ PATTERN (insn) = gen_jump (XEXP (trial, 0));
+ INSN_CODE (insn) = -1;
+
+ if (NEXT_INSN (insn) != 0
+ && GET_CODE (NEXT_INSN (insn)) != BARRIER)
+ emit_barrier_after (insn);
+
+ cse_jumps_altered = 1;
break;
}
/* If we made a change, recompute SRC values. */
if (src != sets[i].src)
{
+ cse_altered = 1;
do_not_record = 0;
hash_arg_in_memory = 0;
sets[i].src = src;
/* 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,
This code is similar to the REG case in mention_regs,
but it knows that reg_tick has been incremented, and
it leaves reg_in_table as -1 . */
- register int regno = REGNO (x);
- register int endregno
+ unsigned int regno = REGNO (x);
+ unsigned int endregno
= regno + (regno >= FIRST_PSEUDO_REGISTER ? 1
: HARD_REGNO_NREGS (regno, GET_MODE (x)));
- int i;
+ unsigned int i;
for (i = regno; i < endregno; i++)
{
}
}
- /* Special handling for (set REG0 REG1)
- where REG0 is the "cheapest", cheaper than REG1.
- After cse, REG1 will probably not be used in the sequel,
- so (if easily done) change this insn to (set REG1 REG0) and
- replace REG1 with REG0 in the previous insn that computed their value.
- Then REG1 will become a dead store and won't cloud the situation
- for later optimizations.
+ /* Special handling for (set REG0 REG1) where REG0 is the
+ "cheapest", cheaper than REG1. After cse, REG1 will probably not
+ be used in the sequel, so (if easily done) change this insn to
+ (set REG1 REG0) and replace REG1 with REG0 in the previous insn
+ that computed their value. Then REG1 will become a dead store
+ and won't cloud the situation for later optimizations.
Do not make this change if REG1 is a hard register, because it will
then be used in the sequel and we may be changing a two-operand insn
if ((src_ent->first_reg == REGNO (SET_DEST (sets[0].rtl)))
&& ! find_reg_note (insn, REG_RETVAL, NULL_RTX))
{
- rtx prev = PREV_INSN (insn);
- while (prev && GET_CODE (prev) == NOTE)
- prev = PREV_INSN (prev);
+ rtx prev = prev_nonnote_insn (insn);
- if (prev && GET_CODE (prev) == INSN && GET_CODE (PATTERN (prev)) == SET
+ if (prev != 0 && GET_CODE (prev) == INSN
+ && GET_CODE (PATTERN (prev)) == SET
&& SET_DEST (PATTERN (prev)) == SET_SRC (sets[0].rtl))
{
rtx dest = SET_DEST (sets[0].rtl);
+ rtx src = SET_SRC (sets[0].rtl);
rtx note = find_reg_note (prev, REG_EQUIV, NULL_RTX);
validate_change (prev, & SET_DEST (PATTERN (prev)), dest, 1);
- validate_change (insn, & SET_DEST (sets[0].rtl),
- SET_SRC (sets[0].rtl), 1);
+ validate_change (insn, & SET_DEST (sets[0].rtl), src, 1);
validate_change (insn, & SET_SRC (sets[0].rtl), dest, 1);
apply_change_group ();
REG_NOTES (prev) = note;
}
- /* If INSN has a REG_EQUAL note, and this note mentions REG0,
- then we must delete it, because the value in REG0 has changed. */
+ /* If INSN has a REG_EQUAL note, and this note mentions
+ REG0, then we must delete it, because the value in
+ REG0 has changed. If the note's value is REG1, we must
+ also delete it because that is now this insn's dest. */
note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
- if (note && reg_mentioned_p (dest, XEXP (note, 0)))
+ if (note != 0
+ && (reg_mentioned_p (dest, XEXP (note, 0))
+ || rtx_equal_p (src, XEXP (note, 0))))
remove_note (insn, note);
}
}
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;
max_insn_uid = get_max_uid ();
reg_eqv_table = (struct reg_eqv_elem *)
- xmalloc(nregs * sizeof(struct reg_eqv_elem));
+ xmalloc (nregs * sizeof (struct reg_eqv_elem));
#ifdef LOAD_EXTEND_OP
insn = f;
while (insn)
{
+ cse_altered = 0;
cse_end_of_basic_block (insn, &val, flag_cse_follow_jumps, after_loop,
flag_cse_skip_blocks);
cse_jumps_altered |= old_cse_jumps_altered;
}
- if (ggc_p)
+ if (ggc_p && cse_altered)
ggc_collect ();
#ifdef USE_C_ALLOCA
/* This array is undefined before max_reg, so only allocate
the space actually needed and adjust the start. */
- qty_table = (struct qty_table_elem *) xmalloc ((max_qty - max_reg)
- * sizeof(struct qty_table_elem));
+ qty_table
+ = (struct qty_table_elem *) xmalloc ((max_qty - max_reg)
+ * sizeof (struct qty_table_elem));
qty_table -= max_reg;
new_basic_block ();
/* If we have processed 1,000 insns, flush the hash table to
avoid extreme quadratic behavior. We must not include NOTEs
- in the count since there may be more or them when generating
+ in the count since there may be more of them when generating
debugging information. If we clear the table at different
times, code generated with -g -O might be different than code
generated with -O but not -g.
&& rtx_equal_p (SET_DEST (PATTERN (insn)),
SET_SRC (PATTERN (insn))))
;
+ else if (GET_CODE (SET_DEST (PATTERN (insn))) == STRICT_LOW_PART
+ && rtx_equal_p (XEXP (SET_DEST (PATTERN (insn)), 0),
+ SET_SRC (PATTERN (insn))))
+ ;
#ifdef HAVE_cc0
else if (GET_CODE (SET_DEST (PATTERN (insn))) == CC0