OSDN Git Service

* gcc.texi: Fixes for makeinfo 4.0 --html.
[pf3gnuchains/gcc-fork.git] / gcc / cse.c
index 822986f..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-99, 2000 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.
 
@@ -245,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;
 };
@@ -301,7 +302,7 @@ struct cse_reg_info
   struct cse_reg_info *next;
 
   /* Search key */
-  int regno;
+  unsigned int regno;
 
   /* The quantity number of the register's current contents.  */
   int reg_qty;
@@ -335,7 +336,7 @@ static struct cse_reg_info *reg_hash[REGHASH_SIZE];
 
 /* 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 
@@ -407,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.
 
@@ -446,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;
@@ -530,17 +535,7 @@ 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[HASH_SIZE];
 
@@ -652,9 +647,9 @@ struct cse_basic_block_data
 
 static int notreg_cost         PARAMS ((rtx));
 static void new_basic_block    PARAMS ((void));
-static void make_new_qty       PARAMS ((int, enum machine_mode));
-static void make_regs_eqv      PARAMS ((int, int));
-static void delete_reg_equiv   PARAMS ((int));
+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));
@@ -667,8 +662,9 @@ 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 ((int));
-static void remove_invalid_subreg_refs PARAMS ((int, int, enum machine_mode));
+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));
@@ -677,7 +673,7 @@ 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 *));
+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 *));
@@ -698,7 +694,8 @@ 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 ((int));
+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
@@ -842,9 +839,37 @@ 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 **hash_head = &reg_hash[REGHASH_FN (regno)];
   struct cse_reg_info *p;
@@ -948,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;
@@ -975,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];
 
@@ -1039,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];
@@ -1093,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++)
        {
@@ -1116,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))
        {
@@ -1192,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.  */
@@ -1236,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
@@ -1323,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;
@@ -1373,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)
@@ -1399,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) & HASH_MASK,
-                                        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.  */
@@ -1416,12 +1444,10 @@ lookup_as_function (x, code)
     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;
 }
@@ -1469,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.  */
@@ -1487,9 +1513,7 @@ insert (x, classp, hash, mode)
 
   elt = free_element_chain;
   if (elt)
-    {
-      free_element_chain = elt->next_same_hash;
-    }
+    free_element_chain = elt->next_same_hash;
   else
     {
       n_elements_made++;
@@ -1497,6 +1521,7 @@ insert (x, classp, hash, mode)
     }
 
   elt->exp = x;
+  elt->canon_exp = NULL_RTX;
   elt->cost = COST (x);
   elt->next_same_value = 0;
   elt->prev_same_value = 0;
@@ -1537,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;
@@ -1590,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;
            }
@@ -1660,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;
 
@@ -1711,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
@@ -1739,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
@@ -1767,18 +1814,19 @@ 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)
@@ -1817,6 +1865,10 @@ 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)
@@ -1829,11 +1881,21 @@ invalidate (x, full_mode)
          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;
@@ -1850,10 +1912,10 @@ 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 < HASH_SIZE; i++)
     for (p = table[i]; p; p = next)
@@ -1868,13 +1930,13 @@ 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 < HASH_SIZE; i++)
     for (p = table[i]; p; p = next)
@@ -1955,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;
@@ -2110,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
@@ -2135,6 +2197,7 @@ canon_hash (x, mode)
            do_not_record = 1;
            return 0;
          }
+
        hash += ((unsigned) REG << 7) + (unsigned) REG_QTY (regno);
        return hash;
       }
@@ -2251,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++;
@@ -2358,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);
@@ -2371,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
@@ -2636,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;
@@ -2650,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
@@ -2683,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;
     }
@@ -2737,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;
@@ -2747,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;
                  }
@@ -2806,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;
@@ -2828,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;
@@ -3305,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,
@@ -5196,17 +5263,6 @@ 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));
-
              if (trial == pc_rtx)
                {
                  SET_SRC (sets[i].rtl) = trial;
@@ -5214,11 +5270,14 @@ cse_insn (insn, libcall_insn)
                  break;
                }
 
-             /* We must actually validate the change.  Consider a target
-                where unconditional jumps are more complex than
-                (set (pc) (label_ref)) such as the fr30.  */
-             if (validate_change (insn, &SET_SRC (sets[i].rtl), trial, 0))
-               cse_jumps_altered = 1;
+             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;
            }
           
@@ -5713,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++)
                {
@@ -5896,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
@@ -5926,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 ();
 
@@ -5960,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);
            }
        }
@@ -6902,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.
@@ -7254,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