OSDN Git Service

* gcc.texi: Fixes for makeinfo 4.0 --html.
[pf3gnuchains/gcc-fork.git] / gcc / cse.c
index bc9e7b6..fe5e4a6 100644 (file)
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -1,5 +1,6 @@
 /* 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.
 
@@ -36,7 +37,6 @@ Boston, MA 02111-1307, USA.  */
 #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
@@ -246,7 +246,7 @@ struct qty_table_elem
   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;
 };
@@ -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 */
+  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.  */
@@ -323,11 +326,17 @@ 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.  */
-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 
@@ -363,6 +372,11 @@ static int max_uid;
 
 #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.  */
 
@@ -394,6 +408,9 @@ static int hash_arg_in_memory;
    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.
 
@@ -433,6 +450,7 @@ static int hash_arg_in_memory;
 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;
@@ -449,15 +467,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
@@ -515,19 +535,9 @@ struct table_elt
 /* 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.  */
@@ -635,62 +645,59 @@ struct cse_basic_block_data
           || 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.  */
@@ -711,11 +718,6 @@ dump_class (classp)
     }
 }
 
-/* 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.  */
 
@@ -744,6 +746,11 @@ notreg_cost (x)
 
 #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;
@@ -832,67 +839,77 @@ rtx_cost (x, outer_code)
   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 = &reg_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;
-
-  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;
-}
+  cached_cse_reg_info = p;
 
-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 +922,45 @@ new_basic_block ()
 
   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
@@ -949,8 +973,8 @@ new_basic_block ()
 
 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;
@@ -976,11 +1000,11 @@ make_new_qty (reg, mode)
 
 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];
 
@@ -1040,14 +1064,14 @@ make_regs_eqv (new, old)
 
 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];
@@ -1094,11 +1118,11 @@ mention_regs (x)
   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++)
        {
@@ -1117,7 +1141,7 @@ mention_regs (x)
   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))
        {
@@ -1193,8 +1217,8 @@ insert_regs (x, classp, modified)
 {
   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.  */
@@ -1237,7 +1261,7 @@ insert_regs (x, classp, modified)
   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
@@ -1258,31 +1282,6 @@ insert_regs (x, classp, modified)
 \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
@@ -1338,7 +1337,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;
       }
@@ -1349,6 +1348,7 @@ remove_from_table (elt, hash)
   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;
@@ -1356,7 +1356,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,
@@ -1397,7 +1399,8 @@ lookup_for_remove (x, hash, mode)
 
   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)
@@ -1423,8 +1426,9 @@ lookup_as_function (x, code)
      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.  */
@@ -1433,19 +1437,17 @@ 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)
     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;
 }
@@ -1493,12 +1495,12 @@ insert (x, classp, hash, mode)
   /* 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.  */
@@ -1509,8 +1511,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->canon_exp = NULL_RTX;
   elt->cost = COST (x);
   elt->next_same_value = 0;
   elt->prev_same_value = 0;
@@ -1551,12 +1562,15 @@ insert (x, classp, hash, mode)
          /* 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;
@@ -1604,7 +1618,8 @@ insert (x, classp, hash, mode)
              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;
            }
@@ -1628,7 +1643,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);
@@ -1674,7 +1689,7 @@ merge_equiv_classes (class1, class2)
 
   for (elt = class2; elt; elt = next)
     {
-      unsigned hash;
+      unsigned int hash;
       rtx exp = elt->exp;
       enum machine_mode mode = elt->mode;
 
@@ -1713,7 +1728,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
@@ -1725,6 +1740,24 @@ flush_hash_table ()
       }
 }
 \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
@@ -1753,8 +1786,8 @@ invalidate (x, full_mode)
           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
@@ -1781,22 +1814,23 @@ invalidate (x, full_mode)
          {
            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;
@@ -1831,23 +1865,37 @@ invalidate (x, full_mode)
       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;
@@ -1864,12 +1912,12 @@ invalidate (x, full_mode)
 
 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;
@@ -1882,15 +1930,15 @@ remove_invalid_refs (regno)
 /* 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;
@@ -1938,13 +1986,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;
@@ -1969,8 +2017,8 @@ rehash_using_reg (x)
 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;
@@ -1995,7 +2043,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 +2090,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));
     }
 
@@ -2124,7 +2172,7 @@ canon_hash (x, mode)
     {
     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
@@ -2149,6 +2197,7 @@ canon_hash (x, mode)
            do_not_record = 1;
            return 0;
          }
+
        hash += ((unsigned) REG << 7) + (unsigned) REG_QTY (regno);
        return hash;
       }
@@ -2265,7 +2314,9 @@ canon_hash (x, mode)
          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++;
@@ -2372,10 +2423,8 @@ exp_equiv_p (x, y, validate, equal_values)
     {
     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);
@@ -2385,11 +2434,11 @@ exp_equiv_p (x, y, validate, equal_values)
 
     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
@@ -2650,9 +2699,10 @@ canon_reg (x, insn)
   */
 
 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;
@@ -2664,6 +2714,7 @@ find_best_addr (insn, 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
@@ -2697,14 +2748,13 @@ find_best_addr (insn, loc)
     {
       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;
     }
@@ -2751,8 +2801,9 @@ find_best_addr (insn, loc)
 
       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;
@@ -2761,12 +2812,12 @@ find_best_addr (insn, loc)
              {
                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;
                  }
@@ -2820,7 +2871,7 @@ find_best_addr (insn, loc)
 
       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;
@@ -2842,13 +2893,15 @@ find_best_addr (insn, 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;
@@ -2918,7 +2971,8 @@ find_comparison_args (code, parg1, parg2, pmode1, pmode2)
                  && 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;
@@ -2927,7 +2981,8 @@ find_comparison_args (code, parg1, parg2, pmode1, pmode2)
                       && 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;
@@ -2942,7 +2997,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;
 
@@ -2973,7 +3028,8 @@ find_comparison_args (code, parg1, parg2, pmode1, pmode2)
 #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)) == '<'))
@@ -2992,7 +3048,8 @@ find_comparison_args (code, parg1, parg2, pmode1, pmode2)
 #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)) == '<')
@@ -3315,7 +3372,7 @@ fold_rtx (x, insn)
         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,
@@ -3658,8 +3715,8 @@ fold_rtx (x, insn)
 #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
@@ -3712,10 +3769,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)
@@ -3733,9 +3790,9 @@ fold_rtx (x, insn)
                      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,
@@ -3772,8 +3829,8 @@ fold_rtx (x, insn)
 #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
@@ -3803,8 +3860,13 @@ fold_rtx (x, insn)
                                           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;
 
@@ -3881,7 +3943,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 +4129,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;
 
@@ -4166,6 +4228,10 @@ record_jump_equiv (insn, taken)
     {
       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.  */
@@ -4456,7 +4522,7 @@ cse_insn (insn, libcall_insn)
   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;
 
@@ -5197,19 +5263,21 @@ cse_insn (insn, libcall_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;
            }
           
@@ -5309,6 +5377,7 @@ cse_insn (insn, libcall_insn)
       /* 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;
@@ -5694,7 +5763,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,
@@ -5703,11 +5772,11 @@ cse_insn (insn, libcall_insn)
                 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++)
                {
@@ -5886,13 +5955,12 @@ cse_insn (insn, libcall_insn)
          }
       }
 
-  /* 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
@@ -5916,19 +5984,18 @@ cse_insn (insn, libcall_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 ();
 
@@ -5950,10 +6017,14 @@ cse_insn (insn, libcall_insn)
                  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);
            }
        }
@@ -5997,7 +6068,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;
@@ -6704,7 +6775,7 @@ cse_main (f, nregs, after_loop, file)
   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
 
@@ -6780,6 +6851,7 @@ cse_main (f, nregs, after_loop, file)
   insn = f;
   while (insn)
     {
+      cse_altered = 0;
       cse_end_of_basic_block (insn, &val, flag_cse_follow_jumps, after_loop,
                              flag_cse_skip_blocks);
 
@@ -6830,7 +6902,7 @@ cse_main (f, nregs, after_loop, file)
          cse_jumps_altered |= old_cse_jumps_altered;
        }
 
-      if (ggc_p)
+      if (ggc_p && cse_altered)
        ggc_collect ();
 
 #ifdef USE_C_ALLOCA
@@ -6874,8 +6946,9 @@ cse_basic_block (from, to, next_branch, around_loop)
   /* 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 ();
@@ -6890,7 +6963,7 @@ cse_basic_block (from, to, next_branch, around_loop)
 
       /* 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.
@@ -6961,7 +7034,10 @@ cse_basic_block (from, to, next_branch, around_loop)
       if (simplejump_p (insn))
        {
          if (to == 0)
-           return 0;
+           {
+             free (qty_table + max_reg);
+             return 0;
+           }
 
          if (JUMP_LABEL (insn) == to)
            to_usage = 1;
@@ -6993,13 +7069,19 @@ cse_basic_block (from, to, next_branch, around_loop)
 
          /* If TO was the last insn in the function, we are done.  */
          if (insn == 0)
-           return 0;
+           {
+             free (qty_table + max_reg);
+             return 0;
+           }
 
          /* If TO was preceded by a BARRIER we are done with this block
             because it has no continuation.  */
          prev = prev_nonnote_insn (to);
          if (prev && GET_CODE (prev) == BARRIER)
-           return insn;
+           {
+             free (qty_table + max_reg);
+             return insn;
+           }
 
          /* Find the end of the following block.  Note that we won't be
             following branches in this case.  */
@@ -7233,6 +7315,10 @@ delete_trivially_dead_insns (insns, nreg)
              && 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