OSDN Git Service

PR bootstrap/39454
[pf3gnuchains/gcc-fork.git] / gcc / cse.c
index e166ce9..04f52fb 100644 (file)
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -1,13 +1,13 @@
 /* Common subexpression elimination for GNU compiler.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998
-   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
    Free Software Foundation, Inc.
 
 This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
@@ -16,9 +16,8 @@ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 /* stdio.h must precede rtl.h for FFS.  */
@@ -45,6 +44,8 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "params.h"
 #include "rtlhooks-def.h"
 #include "tree-pass.h"
+#include "df.h"
+#include "dbgcnt.h"
 
 /* The basic idea of common subexpression elimination is to go
    through the code, keeping a record of expressions that would
@@ -282,6 +283,7 @@ static enum machine_mode this_insn_cc0_mode, prev_insn_cc0_mode;
 /* Insn being scanned.  */
 
 static rtx this_insn;
+static bool optimize_this_for_speed_p;
 
 /* Index by register number, gives the number of the next (or
    previous) register in the chain of registers sharing the same
@@ -347,35 +349,17 @@ static unsigned int cse_reg_info_timestamp;
 
 static HARD_REG_SET hard_regs_in_table;
 
-/* CUID of insn that starts the basic block currently being cse-processed.  */
+/* True if CSE has altered the CFG.  */
+static bool cse_cfg_altered;
 
-static int cse_basic_block_start;
+/* True if CSE has altered conditional jump insns in such a way
+   that jump optimization should be redone.  */
+static bool cse_jumps_altered;
 
-/* CUID of insn that ends the basic block currently being cse-processed.  */
-
-static int cse_basic_block_end;
-
-/* Vector mapping INSN_UIDs to cuids.
-   The cuids are like uids but increase monotonically always.
-   We use them to see whether a reg is used outside a given basic block.  */
-
-static int *uid_cuid;
-
-/* Highest UID in UID_CUID.  */
-static int max_uid;
-
-/* Get the cuid of an insn.  */
-
-#define INSN_CUID(INSN) (uid_cuid[INSN_UID (INSN)])
-
-/* Nonzero if cse has altered conditional jump insns
-   in such a way that jump optimization should be redone.  */
-
-static int cse_jumps_altered;
-
-/* Nonzero if we put a LABEL_REF into the hash table for an INSN without a
-   REG_LABEL, we have to rerun jump after CSE to put in the note.  */
-static int recorded_label_ref;
+/* True if we put a LABEL_REF into the hash table for an INSN
+   without a REG_LABEL_OPERAND, we have to rerun jump after CSE
+   to put in the note.  */
+static bool recorded_label_ref;
 
 /* canon_hash stores 1 in do_not_record
    if it notices a reference to CC0, PC, or some other volatile
@@ -538,10 +522,6 @@ static int constant_pool_entries_regcost;
 
 struct cse_basic_block_data
 {
-  /* Lowest CUID value of insns in block.  */
-  int low_cuid;
-  /* Highest CUID value of insns in block.  */
-  int high_cuid;
   /* Total number of SETs in block.  */
   int nsets;
   /* Size of current branch path, if any.  */
@@ -554,6 +534,11 @@ struct cse_basic_block_data
     } *path;
 };
 
+
+/* Pointers to the live in/live out bitmaps for the boundaries of the
+   current EBB.  */
+static bitmap cse_ebb_live_in, cse_ebb_live_out;
+
 /* A simple bitmap to track which basic blocks have been visited
    already as part of an already processed extended basic block.  */
 static sbitmap cse_visited_basic_blocks;
@@ -570,14 +555,15 @@ static void delete_reg_equiv (unsigned int);
 static int mention_regs (rtx);
 static int insert_regs (rtx, struct table_elt *, int);
 static void remove_from_table (struct table_elt *, unsigned);
-static struct table_elt *lookup        (rtx, unsigned, enum machine_mode);
+static void remove_pseudo_from_table (rtx, unsigned);
+static struct table_elt *lookup (rtx, unsigned, enum machine_mode);
 static struct table_elt *lookup_for_remove (rtx, unsigned, enum machine_mode);
 static rtx lookup_as_function (rtx, enum rtx_code);
 static struct table_elt *insert (rtx, struct table_elt *, unsigned,
                                 enum machine_mode);
 static void merge_equiv_classes (struct table_elt *, struct table_elt *);
 static void invalidate (rtx, enum machine_mode);
-static int cse_rtx_varies_p (rtx, int);
+static bool cse_rtx_varies_p (const_rtx, bool);
 static void remove_invalid_refs (unsigned int);
 static void remove_invalid_subreg_refs (unsigned int, unsigned int,
                                        enum machine_mode);
@@ -588,7 +574,7 @@ static rtx use_related_value (rtx, struct table_elt *);
 
 static inline unsigned canon_hash (rtx, enum machine_mode);
 static inline unsigned safe_hash (rtx, enum machine_mode);
-static unsigned hash_rtx_string (const char *);
+static inline unsigned hash_rtx_string (const char *);
 
 static rtx canon_reg (rtx, rtx);
 static enum rtx_code find_comparison_args (enum rtx_code, rtx *, rtx *,
@@ -599,10 +585,10 @@ static rtx equiv_constant (rtx);
 static void record_jump_equiv (rtx, bool);
 static void record_jump_cond (enum rtx_code, enum machine_mode, rtx, rtx,
                              int);
-static void cse_insn (rtx, rtx);
+static void cse_insn (rtx);
 static void cse_prescan_path (struct cse_basic_block_data *);
 static void invalidate_from_clobbers (rtx);
-static rtx cse_process_notes (rtx, rtx);
+static rtx cse_process_notes (rtx, rtx, bool *);
 static void cse_extended_basic_block (struct cse_basic_block_data *);
 static void count_reg_usage (rtx, int *, rtx, int);
 static int check_for_label_ref (rtx *, void *);
@@ -614,11 +600,11 @@ static int check_dependence (rtx *, void *);
 static void flush_hash_table (void);
 static bool insn_live_p (rtx, int *);
 static bool set_live_p (rtx, rtx, int *);
-static bool dead_libcall_p (rtx, int *);
 static int cse_change_cc_mode (rtx *, void *);
 static void cse_change_cc_mode_insn (rtx, rtx);
 static void cse_change_cc_mode_insns (rtx, rtx, rtx);
-static enum machine_mode cse_cc_succs (basic_block, rtx, rtx, bool);
+static enum machine_mode cse_cc_succs (basic_block, basic_block, rtx, rtx,
+                                      bool);
 \f
 
 #undef RTL_HOOKS_GEN_LOWPART
@@ -679,7 +665,7 @@ static int
 approx_reg_cost_1 (rtx *xp, void *data)
 {
   rtx x = *xp;
-  int *cost_p = data;
+  int *cost_p = (int *) data;
 
   if (x && REG_P (x))
     {
@@ -768,7 +754,7 @@ notreg_cost (rtx x, enum rtx_code outer)
           && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (GET_MODE (x)),
                                     GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x)))))
          ? 0
-         : rtx_cost (x, outer) * 2);
+         : rtx_cost (x, outer, optimize_this_for_speed_p) * 2);
 }
 
 \f
@@ -929,18 +915,18 @@ make_new_qty (unsigned int reg, enum machine_mode mode)
    OLD is not changing; NEW is.  */
 
 static void
-make_regs_eqv (unsigned int new, unsigned int old)
+make_regs_eqv (unsigned int new_reg, unsigned int old_reg)
 {
   unsigned int lastr, firstr;
-  int q = REG_QTY (old);
+  int q = REG_QTY (old_reg);
   struct qty_table_elem *ent;
 
   ent = &qty_table[q];
 
   /* Nothing should become eqv until it has a "non-invalid" qty number.  */
-  gcc_assert (REGNO_QTY_VALID_P (old));
+  gcc_assert (REGNO_QTY_VALID_P (old_reg));
 
-  REG_QTY (new) = q;
+  REG_QTY (new_reg) = q;
   firstr = ent->first_reg;
   lastr = ent->last_reg;
 
@@ -953,20 +939,19 @@ make_regs_eqv (unsigned int new, unsigned int old)
         that not only can they not be allocated by the compiler, but
         they cannot be used in substitutions or canonicalizations
         either.  */
-      && (new >= FIRST_PSEUDO_REGISTER || REGNO_REG_CLASS (new) != NO_REGS)
-      && ((new < FIRST_PSEUDO_REGISTER && FIXED_REGNO_P (new))
-         || (new >= FIRST_PSEUDO_REGISTER
+      && (new_reg >= FIRST_PSEUDO_REGISTER || REGNO_REG_CLASS (new_reg) != NO_REGS)
+      && ((new_reg < FIRST_PSEUDO_REGISTER && FIXED_REGNO_P (new_reg))
+         || (new_reg >= FIRST_PSEUDO_REGISTER
              && (firstr < FIRST_PSEUDO_REGISTER
-                 || ((uid_cuid[REGNO_LAST_UID (new)] > cse_basic_block_end
-                      || (uid_cuid[REGNO_FIRST_UID (new)]
-                          < cse_basic_block_start))
-                     && (uid_cuid[REGNO_LAST_UID (new)]
-                         > uid_cuid[REGNO_LAST_UID (firstr)]))))))
+                 || (bitmap_bit_p (cse_ebb_live_out, new_reg)
+                     && !bitmap_bit_p (cse_ebb_live_out, firstr))
+                 || (bitmap_bit_p (cse_ebb_live_in, new_reg)
+                     && !bitmap_bit_p (cse_ebb_live_in, firstr))))))
     {
-      reg_eqv_table[firstr].prev = new;
-      reg_eqv_table[new].next = firstr;
-      reg_eqv_table[new].prev = -1;
-      ent->first_reg = new;
+      reg_eqv_table[firstr].prev = new_reg;
+      reg_eqv_table[new_reg].next = firstr;
+      reg_eqv_table[new_reg].prev = -1;
+      ent->first_reg = new_reg;
     }
   else
     {
@@ -976,15 +961,15 @@ make_regs_eqv (unsigned int new, unsigned int old)
         equivalent for anything.  */
       while (lastr < FIRST_PSEUDO_REGISTER && reg_eqv_table[lastr].prev >= 0
             && (REGNO_REG_CLASS (lastr) == NO_REGS || ! FIXED_REGNO_P (lastr))
-            && new >= FIRST_PSEUDO_REGISTER)
+            && new_reg >= FIRST_PSEUDO_REGISTER)
        lastr = reg_eqv_table[lastr].prev;
-      reg_eqv_table[new].next = reg_eqv_table[lastr].next;
+      reg_eqv_table[new_reg].next = reg_eqv_table[lastr].next;
       if (reg_eqv_table[lastr].next >= 0)
-       reg_eqv_table[reg_eqv_table[lastr].next].prev = new;
+       reg_eqv_table[reg_eqv_table[lastr].next].prev = new_reg;
       else
-       qty_table[q].last_reg = new;
-      reg_eqv_table[lastr].next = new;
-      reg_eqv_table[new].prev = lastr;
+       qty_table[q].last_reg = new_reg;
+      reg_eqv_table[lastr].next = new_reg;
+      reg_eqv_table[new_reg].prev = lastr;
     }
 }
 
@@ -1305,6 +1290,19 @@ remove_from_table (struct table_elt *elt, unsigned int hash)
   free_element_chain = elt;
 }
 
+/* Same as above, but X is a pseudo-register.  */
+
+static void
+remove_pseudo_from_table (rtx x, unsigned int hash)
+{
+  struct table_elt *elt;
+
+  /* Because a pseudo-register can be referenced in more than one
+     mode, we might have to remove more than one table entry.  */
+  while ((elt = lookup_for_remove (x, hash, VOIDmode)))
+    remove_from_table (elt, hash);
+}
+
 /* Look up X in the hash table and return its table element,
    or 0 if X is not in the table.
 
@@ -1366,17 +1364,6 @@ lookup_as_function (rtx x, enum rtx_code code)
   struct table_elt *p
     = lookup (x, SAFE_HASH (x, VOIDmode), 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.  */
-  if (p == 0 && code == CONST_INT
-      && GET_MODE_SIZE (GET_MODE (x)) < GET_MODE_SIZE (word_mode))
-    {
-      x = copy_rtx (x);
-      PUT_MODE (x, word_mode);
-      p = lookup (x, SAFE_HASH (x, VOIDmode), word_mode);
-    }
-
   if (p == 0)
     return 0;
 
@@ -1588,7 +1575,7 @@ insert (rtx x, struct table_elt *classp, unsigned int hash, enum machine_mode mo
 static void
 merge_equiv_classes (struct table_elt *class1, struct table_elt *class2)
 {
-  struct table_elt *elt, *next, *new;
+  struct table_elt *elt, *next, *new_elt;
 
   /* Ensure we start with the head of the classes.  */
   class1 = class1->first_same_value;
@@ -1622,15 +1609,18 @@ merge_equiv_classes (struct table_elt *class1, struct table_elt *class2)
              delete_reg_equiv (REGNO (exp));
            }
 
-         remove_from_table (elt, hash);
+         if (REG_P (exp) && REGNO (exp) >= FIRST_PSEUDO_REGISTER)
+           remove_pseudo_from_table (exp, hash);
+         else
+           remove_from_table (elt, hash);
 
          if (insert_regs (exp, class1, 0) || need_rehash)
            {
              rehash_using_reg (exp);
              hash = HASH (exp, mode);
            }
-         new = insert (exp, class1, hash, mode);
-         new->in_memory = hash_arg_in_memory;
+         new_elt = insert (exp, class1, hash, mode);
+         new_elt->in_memory = hash_arg_in_memory;
        }
     }
 }
@@ -1718,14 +1708,7 @@ invalidate (rtx x, enum machine_mode full_mode)
        SUBREG_TICKED (regno) = -1;
 
        if (regno >= FIRST_PSEUDO_REGISTER)
-         {
-           /* Because a register can be referenced in more than one mode,
-              we might have to remove more than one table entry.  */
-           struct table_elt *elt;
-
-           while ((elt = lookup_for_remove (x, hash, GET_MODE (x))))
-             remove_from_table (elt, hash);
-         }
+         remove_pseudo_from_table (x, hash);
        else
          {
            HOST_WIDE_INT in_table
@@ -2051,6 +2034,7 @@ use_related_value (rtx x, struct table_elt *elt)
   return plus_constant (q->exp, offset);
 }
 \f
+
 /* Hash a string.  Just add its bytes up.  */
 static inline unsigned
 hash_rtx_string (const char *ps)
@@ -2065,27 +2049,20 @@ hash_rtx_string (const char *ps)
   return hash;
 }
 
-/* Hash an rtx.  We are careful to make sure the value is never negative.
-   Equivalent registers hash identically.
-   MODE is used in hashing for CONST_INTs only;
-   otherwise the mode of X is used.
-
-   Store 1 in DO_NOT_RECORD_P if any subexpression is volatile.
-
-   If HASH_ARG_IN_MEMORY_P is not NULL, store 1 in it if X contains
-   a MEM rtx which does not have the RTX_UNCHANGING_P bit set.
-
-   Note that cse_insn knows that the hash code of a MEM expression
-   is just (int) MEM plus the hash code of the address.  */
+/* Same as hash_rtx, but call CB on each rtx if it is not NULL.  
+   When the callback returns true, we continue with the new rtx.  */
 
 unsigned
-hash_rtx (rtx x, enum machine_mode mode, int *do_not_record_p,
-         int *hash_arg_in_memory_p, bool have_reg_qty)
+hash_rtx_cb (const_rtx x, enum machine_mode mode,
+             int *do_not_record_p, int *hash_arg_in_memory_p,
+             bool have_reg_qty, hash_rtx_callback_function cb)
 {
   int i, j;
   unsigned hash = 0;
   enum rtx_code code;
   const char *fmt;
+  enum machine_mode newmode;
+  rtx newx;
 
   /* Used to turn recursion into iteration.  We can't rely on GCC's
      tail-recursion elimination since we need to keep accumulating values
@@ -2094,6 +2071,15 @@ hash_rtx (rtx x, enum machine_mode mode, int *do_not_record_p,
   if (x == 0)
     return hash;
 
+  /* Invoke the callback first.  */
+  if (cb != NULL 
+      && ((*cb) (x, mode, &newx, &newmode)))
+    {
+      hash += hash_rtx_cb (newx, newmode, do_not_record_p,
+                           hash_arg_in_memory_p, have_reg_qty, cb);
+      return hash;
+    }
+
   code = GET_CODE (x);
   switch (code)
     {
@@ -2101,7 +2087,7 @@ hash_rtx (rtx x, enum machine_mode mode, int *do_not_record_p,
       {
        unsigned int regno = REGNO (x);
 
-       if (!reload_completed)
+       if (do_not_record_p && !reload_completed)
          {
            /* On some machines, we can't record any non-fixed hard register,
               because extending its life will cause reload problems.  We
@@ -2180,6 +2166,11 @@ hash_rtx (rtx x, enum machine_mode mode, int *do_not_record_p,
                 + (unsigned int) CONST_DOUBLE_HIGH (x));
       return hash;
 
+    case CONST_FIXED:
+      hash += (unsigned int) code + (unsigned int) GET_MODE (x);
+      hash += fixed_hash (CONST_FIXED_VALUE (x));
+      return hash;
+
     case CONST_VECTOR:
       {
        int units;
@@ -2190,8 +2181,9 @@ hash_rtx (rtx x, enum machine_mode mode, int *do_not_record_p,
        for (i = 0; i < units; ++i)
          {
            elt = CONST_VECTOR_ELT (x, i);
-           hash += hash_rtx (elt, GET_MODE (elt), do_not_record_p,
-                             hash_arg_in_memory_p, have_reg_qty);
+           hash += hash_rtx_cb (elt, GET_MODE (elt),
+                                 do_not_record_p, hash_arg_in_memory_p, 
+                                 have_reg_qty, cb);
          }
 
        return hash;
@@ -2225,7 +2217,7 @@ hash_rtx (rtx x, enum machine_mode mode, int *do_not_record_p,
     case MEM:
       /* We don't record if marked volatile or if BLKmode since we don't
         know the size of the move.  */
-      if (MEM_VOLATILE_P (x) || GET_MODE (x) == BLKmode)
+      if (do_not_record_p && (MEM_VOLATILE_P (x) || GET_MODE (x) == BLKmode))
        {
          *do_not_record_p = 1;
          return 0;
@@ -2272,11 +2264,16 @@ hash_rtx (rtx x, enum machine_mode mode, int *do_not_record_p,
     case CC0:
     case CALL:
     case UNSPEC_VOLATILE:
-      *do_not_record_p = 1;
-      return 0;
+      if (do_not_record_p) {
+        *do_not_record_p = 1;
+        return 0;
+      }
+      else
+        return hash;
+      break;
 
     case ASM_OPERANDS:
-      if (MEM_VOLATILE_P (x))
+      if (do_not_record_p && MEM_VOLATILE_P (x))
        {
          *do_not_record_p = 1;
          return 0;
@@ -2293,12 +2290,12 @@ hash_rtx (rtx x, enum machine_mode mode, int *do_not_record_p,
            {
              for (i = 1; i < ASM_OPERANDS_INPUT_LENGTH (x); i++)
                {
-                 hash += (hash_rtx (ASM_OPERANDS_INPUT (x, i),
-                                    GET_MODE (ASM_OPERANDS_INPUT (x, i)),
-                                    do_not_record_p, hash_arg_in_memory_p,
-                                    have_reg_qty)
+                 hash += (hash_rtx_cb (ASM_OPERANDS_INPUT (x, i),
+                                        GET_MODE (ASM_OPERANDS_INPUT (x, i)),
+                                        do_not_record_p, hash_arg_in_memory_p,
+                                        have_reg_qty, cb)
                           + hash_rtx_string
-                               (ASM_OPERANDS_INPUT_CONSTRAINT (x, i)));
+                           (ASM_OPERANDS_INPUT_CONSTRAINT (x, i)));
                }
 
              hash += hash_rtx_string (ASM_OPERANDS_INPUT_CONSTRAINT (x, 0));
@@ -2331,15 +2328,17 @@ hash_rtx (rtx x, enum machine_mode mode, int *do_not_record_p,
              x = XEXP (x, i);
              goto repeat;
            }
-
-         hash += hash_rtx (XEXP (x, i), 0, do_not_record_p,
-                           hash_arg_in_memory_p, have_reg_qty);
+          
+         hash += hash_rtx_cb (XEXP (x, i), 0, do_not_record_p,
+                               hash_arg_in_memory_p,
+                               have_reg_qty, cb);
          break;
 
        case 'E':
          for (j = 0; j < XVECLEN (x, i); j++)
-           hash += hash_rtx (XVECEXP (x, i, j), 0, do_not_record_p,
-                             hash_arg_in_memory_p, have_reg_qty);
+           hash += hash_rtx_cb (XVECEXP (x, i, j), 0, do_not_record_p,
+                                 hash_arg_in_memory_p,
+                                 have_reg_qty, cb);
          break;
 
        case 's':
@@ -2362,6 +2361,27 @@ hash_rtx (rtx x, enum machine_mode mode, int *do_not_record_p,
   return hash;
 }
 
+/* Hash an rtx.  We are careful to make sure the value is never negative.
+   Equivalent registers hash identically.
+   MODE is used in hashing for CONST_INTs only;
+   otherwise the mode of X is used.
+
+   Store 1 in DO_NOT_RECORD_P if any subexpression is volatile.
+
+   If HASH_ARG_IN_MEMORY_P is not NULL, store 1 in it if X contains
+   a MEM rtx which does not have the RTX_UNCHANGING_P bit set.
+
+   Note that cse_insn knows that the hash code of a MEM expression
+   is just (int) MEM plus the hash code of the address.  */
+
+unsigned
+hash_rtx (const_rtx x, enum machine_mode mode, int *do_not_record_p,
+         int *hash_arg_in_memory_p, bool have_reg_qty)
+{
+  return hash_rtx_cb (x, mode, do_not_record_p,
+                      hash_arg_in_memory_p, have_reg_qty, NULL);
+}
+
 /* Hash an rtx X for cse via hash_rtx.
    Stores 1 in do_not_record if any subexpression is volatile.
    Stores 1 in hash_arg_in_memory if X contains a mem rtx which
@@ -2393,7 +2413,7 @@ safe_hash (rtx x, enum machine_mode mode)
    If FOR_GCSE is true, we compare X and Y for equivalence for GCSE.  */
 
 int
-exp_equiv_p (rtx x, rtx y, int validate, bool for_gcse)
+exp_equiv_p (const_rtx x, const_rtx y, int validate, bool for_gcse)
 {
   int i, j;
   enum rtx_code code;
@@ -2421,6 +2441,7 @@ exp_equiv_p (rtx x, rtx y, int validate, bool for_gcse)
     case CC0:
     case CONST_INT:
     case CONST_DOUBLE:
+    case CONST_FIXED:
       return x == y;
 
     case LABEL_REF:
@@ -2585,8 +2606,8 @@ exp_equiv_p (rtx x, rtx y, int validate, bool for_gcse)
    executions of the program.  0 means X can be compared reliably
    against certain constants or near-constants.  */
 
-static int
-cse_rtx_varies_p (rtx x, int from_alias)
+static bool
+cse_rtx_varies_p (const_rtx x, bool from_alias)
 {
   /* We need not check for X and the equivalence class being of the same
      mode because if X is equivalent to a constant in some mode, it
@@ -2648,14 +2669,15 @@ cse_rtx_varies_p (rtx x, int from_alias)
 static void
 validate_canon_reg (rtx *xloc, rtx insn)
 {
-  rtx new = canon_reg (*xloc, insn);
+  if (*xloc)
+    {
+      rtx new_rtx = canon_reg (*xloc, insn);
 
-  /* If replacing pseudo with hard reg or vice versa, ensure the
-     insn remains valid.  Likewise if the insn has MATCH_DUPs.  */
-  if (insn != 0 && new != 0)
-    validate_change (insn, xloc, new, 1);
-  else
-    *xloc = new;
+      /* If replacing pseudo with hard reg or vice versa, ensure the
+         insn remains valid.  Likewise if the insn has MATCH_DUPs.  */
+      gcc_assert (insn && new_rtx);
+      validate_change (insn, xloc, new_rtx, 1);
+    }
 }
 
 /* Canonicalize an expression:
@@ -2686,6 +2708,7 @@ canon_reg (rtx x, rtx insn)
     case CONST:
     case CONST_INT:
     case CONST_DOUBLE:
+    case CONST_FIXED:
     case CONST_VECTOR:
     case SYMBOL_REF:
     case LABEL_REF:
@@ -2948,7 +2971,7 @@ fold_rtx (rtx x, rtx insn)
   enum machine_mode mode;
   const char *fmt;
   int i;
-  rtx new = 0;
+  rtx new_rtx = 0;
   int changed = 0;
 
   /* Operands of X.  */
@@ -2974,13 +2997,14 @@ fold_rtx (rtx x, rtx insn)
     {
     case MEM:
     case SUBREG:
-      if ((new = equiv_constant (x)) != NULL_RTX)
-        return new;
+      if ((new_rtx = equiv_constant (x)) != NULL_RTX)
+        return new_rtx;
       return x;
 
     case CONST:
     case CONST_INT:
     case CONST_DOUBLE:
+    case CONST_FIXED:
     case CONST_VECTOR:
     case SYMBOL_REF:
     case LABEL_REF:
@@ -3047,6 +3071,7 @@ fold_rtx (rtx x, rtx insn)
          case SYMBOL_REF:
          case LABEL_REF:
          case CONST_DOUBLE:
+         case CONST_FIXED:
          case CONST_VECTOR:
            const_arg = folded_arg;
            break;
@@ -3112,7 +3137,7 @@ fold_rtx (rtx x, rtx insn)
        if (insn == NULL_RTX && !changed)
          x = copy_rtx (x);
        changed = 1;
-       validate_change (insn, &XEXP (x, i), folded_arg, 1);
+       validate_unshare_change (insn, &XEXP (x, i), folded_arg, 1);
       }
 
   if (changed)
@@ -3135,33 +3160,15 @@ fold_rtx (rtx x, rtx insn)
     {
     case RTX_UNARY:
       {
-       int is_const = 0;
-
        /* We can't simplify extension ops unless we know the
           original mode.  */
        if ((code == ZERO_EXTEND || code == SIGN_EXTEND)
            && mode_arg0 == VOIDmode)
          break;
 
-       /* If we had a CONST, strip it off and put it back later if we
-          fold.  */
-       if (const_arg0 != 0 && GET_CODE (const_arg0) == CONST)
-         is_const = 1, const_arg0 = XEXP (const_arg0, 0);
-
-       new = simplify_unary_operation (code, mode,
+       new_rtx = simplify_unary_operation (code, mode,
                                        const_arg0 ? const_arg0 : folded_arg0,
                                        mode_arg0);
-       /* NEG of PLUS could be converted into MINUS, but that causes
-          expressions of the form
-          (CONST (MINUS (CONST_INT) (SYMBOL_REF)))
-          which many ports mistakenly treat as LEGITIMATE_CONSTANT_P.
-          FIXME: those ports should be fixed.  */
-       if (new != 0 && is_const
-           && GET_CODE (new) == PLUS
-           && (GET_CODE (XEXP (new, 0)) == SYMBOL_REF
-               || GET_CODE (XEXP (new, 0)) == LABEL_REF)
-           && GET_CODE (XEXP (new, 1)) == CONST_INT)
-         new = gen_rtx_CONST (mode, new);
       }
       break;
 
@@ -3179,17 +3186,24 @@ fold_rtx (rtx x, rtx insn)
       if (const_arg0 == 0 || const_arg1 == 0)
        {
          struct table_elt *p0, *p1;
-         rtx true_rtx = const_true_rtx, false_rtx = const0_rtx;
+         rtx true_rtx, false_rtx;
          enum machine_mode mode_arg1;
 
-#ifdef FLOAT_STORE_FLAG_VALUE
          if (SCALAR_FLOAT_MODE_P (mode))
            {
+#ifdef FLOAT_STORE_FLAG_VALUE
              true_rtx = (CONST_DOUBLE_FROM_REAL_VALUE
                          (FLOAT_STORE_FLAG_VALUE (mode), mode));
+#else
+             true_rtx = NULL_RTX;
+#endif
              false_rtx = CONST0_RTX (mode);
            }
-#endif
+         else
+           {
+             true_rtx = const_true_rtx;
+             false_rtx = const0_rtx;
+           }
 
          code = find_comparison_args (code, &folded_arg0, &folded_arg1,
                                       &mode_arg0, &mode_arg1);
@@ -3256,28 +3270,17 @@ fold_rtx (rtx x, rtx insn)
                      /* If we have a cheaper expression now, use that
                         and try folding it further, from the top.  */
                      if (cheapest_simplification != x)
-                       return fold_rtx (cheapest_simplification, insn);
+                       return fold_rtx (copy_rtx (cheapest_simplification),
+                                        insn);
                    }
                }
 
-             /* Some addresses are known to be nonzero.  We don't know
-                their sign, but equality comparisons are known.  */
-             if (const_arg1 == const0_rtx
-                 && nonzero_address_p (folded_arg0))
-               {
-                 if (code == EQ)
-                   return false_rtx;
-                 else if (code == NE)
-                   return true_rtx;
-               }
-
              /* See if the two operands are the same.  */
 
-             if (folded_arg0 == folded_arg1
-                 || (REG_P (folded_arg0)
-                     && REG_P (folded_arg1)
-                     && (REG_QTY (REGNO (folded_arg0))
-                         == REG_QTY (REGNO (folded_arg1))))
+             if ((REG_P (folded_arg0)
+                  && REG_P (folded_arg1)
+                  && (REG_QTY (REGNO (folded_arg0))
+                      == REG_QTY (REGNO (folded_arg1))))
                  || ((p0 = lookup (folded_arg0,
                                    SAFE_HASH (folded_arg0, mode_arg0),
                                    mode_arg0))
@@ -3285,20 +3288,7 @@ fold_rtx (rtx x, rtx insn)
                                       SAFE_HASH (folded_arg1, mode_arg0),
                                       mode_arg0))
                      && p0->first_same_value == p1->first_same_value))
-               {
-                 /* Sadly two equal NaNs are not equivalent.  */
-                 if (!HONOR_NANS (mode_arg0))
-                   return ((code == EQ || code == LE || code == GE
-                            || code == LEU || code == GEU || code == UNEQ
-                            || code == UNLE || code == UNGE
-                            || code == ORDERED)
-                           ? true_rtx : false_rtx);
-                 /* Take care for the FP compares we can resolve.  */
-                 if (code == UNEQ || code == UNLE || code == UNGE)
-                   return true_rtx;
-                 if (code == LTGT || code == LT || code == GT)
-                   return false_rtx;
-               }
+               folded_arg1 = folded_arg0;
 
              /* If FOLDED_ARG0 is a register, see if the comparison we are
                 doing now is either the same as we did before or the reverse
@@ -3321,8 +3311,17 @@ fold_rtx (rtx x, rtx insn)
                                                  const_arg1))
                              || (REG_P (folded_arg1)
                                  && (REG_QTY (REGNO (folded_arg1)) == ent->comparison_qty))))
-                       return (comparison_dominates_p (ent->comparison_code, code)
-                               ? true_rtx : false_rtx);
+                       {
+                         if (comparison_dominates_p (ent->comparison_code, code))
+                           {
+                             if (true_rtx)
+                               return true_rtx;
+                             else
+                               break;
+                           }
+                         else
+                           return false_rtx;
+                       }
                    }
                }
            }
@@ -3331,8 +3330,7 @@ fold_rtx (rtx x, rtx insn)
       /* If we are comparing against zero, see if the first operand is
         equivalent to an IOR with a constant.  If so, we may be able to
         determine the result of this comparison.  */
-
-      if (const_arg1 == const0_rtx)
+      if (const_arg1 == const0_rtx && !const_arg0)
        {
          rtx y = lookup_as_function (folded_arg0, IOR);
          rtx inner_const;
@@ -3341,46 +3339,13 @@ fold_rtx (rtx x, rtx insn)
              && (inner_const = equiv_constant (XEXP (y, 1))) != 0
              && GET_CODE (inner_const) == CONST_INT
              && INTVAL (inner_const) != 0)
-           {
-             int sign_bitnum = GET_MODE_BITSIZE (mode_arg0) - 1;
-             int has_sign = (HOST_BITS_PER_WIDE_INT >= sign_bitnum
-                             && (INTVAL (inner_const)
-                                 & ((HOST_WIDE_INT) 1 << sign_bitnum)));
-             rtx true_rtx = const_true_rtx, false_rtx = const0_rtx;
-
-#ifdef FLOAT_STORE_FLAG_VALUE
-             if (SCALAR_FLOAT_MODE_P (mode))
-               {
-                 true_rtx = (CONST_DOUBLE_FROM_REAL_VALUE
-                         (FLOAT_STORE_FLAG_VALUE (mode), mode));
-                 false_rtx = CONST0_RTX (mode);
-               }
-#endif
-
-             switch (code)
-               {
-               case EQ:
-                 return false_rtx;
-               case NE:
-                 return true_rtx;
-               case LT:  case LE:
-                 if (has_sign)
-                   return true_rtx;
-                 break;
-               case GT:  case GE:
-                 if (has_sign)
-                   return false_rtx;
-                 break;
-               default:
-                 break;
-               }
-           }
+           folded_arg0 = gen_rtx_IOR (mode_arg0, XEXP (y, 0), inner_const);
        }
 
       {
        rtx op0 = const_arg0 ? const_arg0 : folded_arg0;
        rtx op1 = const_arg1 ? const_arg1 : folded_arg1;
-        new = simplify_relational_operation (code, mode, mode_arg0, op0, op1);
+        new_rtx = simplify_relational_operation (code, mode, mode_arg0, op0, op1);
       }
       break;
 
@@ -3499,6 +3464,7 @@ fold_rtx (rtx x, rtx insn)
              int is_shift
                = (code == ASHIFT || code == ASHIFTRT || code == LSHIFTRT);
              rtx y, inner_const, new_const;
+             rtx canon_const_arg1 = const_arg1;
              enum rtx_code associate_code;
 
              if (is_shift
@@ -3506,8 +3472,9 @@ fold_rtx (rtx x, rtx insn)
                      || INTVAL (const_arg1) < 0))
                {
                  if (SHIFT_COUNT_TRUNCATED)
-                   const_arg1 = GEN_INT (INTVAL (const_arg1)
-                                         & (GET_MODE_BITSIZE (mode) - 1));
+                   canon_const_arg1 = GEN_INT (INTVAL (const_arg1)
+                                               & (GET_MODE_BITSIZE (mode)
+                                                  - 1));
                  else
                    break;
                }
@@ -3544,6 +3511,11 @@ fold_rtx (rtx x, rtx insn)
                          && exact_log2 (- INTVAL (const_arg1)) >= 0)))
                break;
 
+             /* ??? Vector mode shifts by scalar
+                shift operand are not supported yet.  */
+             if (is_shift && VECTOR_MODE_P (mode))
+                break;
+
              if (is_shift
                  && (INTVAL (inner_const) >= GET_MODE_BITSIZE (mode)
                      || INTVAL (inner_const) < 0))
@@ -3561,7 +3533,8 @@ fold_rtx (rtx x, rtx insn)
              associate_code = (is_shift || code == MINUS ? PLUS : code);
 
              new_const = simplify_binary_operation (associate_code, mode,
-                                                    const_arg1, inner_const);
+                                                    canon_const_arg1,
+                                                    inner_const);
 
              if (new_const == 0)
                break;
@@ -3611,7 +3584,7 @@ fold_rtx (rtx x, rtx insn)
          break;
        }
 
-      new = simplify_binary_operation (code, mode,
+      new_rtx = simplify_binary_operation (code, mode,
                                       const_arg0 ? const_arg0 : folded_arg0,
                                       const_arg1 ? const_arg1 : folded_arg1);
       break;
@@ -3626,7 +3599,7 @@ fold_rtx (rtx x, rtx insn)
 
     case RTX_TERNARY:
     case RTX_BITFIELD_OPS:
-      new = simplify_ternary_operation (code, mode, mode_arg0,
+      new_rtx = simplify_ternary_operation (code, mode, mode_arg0,
                                        const_arg0 ? const_arg0 : folded_arg0,
                                        const_arg1 ? const_arg1 : folded_arg1,
                                        const_arg2 ? const_arg2 : XEXP (x, 2));
@@ -3636,7 +3609,7 @@ fold_rtx (rtx x, rtx insn)
       break;
     }
 
-  return new ? new : x;
+  return new_rtx ? new_rtx : x;
 }
 \f
 /* Return a constant value currently equivalent to X.
@@ -3660,17 +3633,35 @@ equiv_constant (rtx x)
 
   if (GET_CODE (x) == SUBREG)
     {
-      rtx new;
+      enum machine_mode mode = GET_MODE (x);
+      enum machine_mode imode = GET_MODE (SUBREG_REG (x));
+      rtx new_rtx;
 
       /* See if we previously assigned a constant value to this SUBREG.  */
-      if ((new = lookup_as_function (x, CONST_INT)) != 0
-          || (new = lookup_as_function (x, CONST_DOUBLE)) != 0)
-        return new;
+      if ((new_rtx = lookup_as_function (x, CONST_INT)) != 0
+          || (new_rtx = lookup_as_function (x, CONST_DOUBLE)) != 0
+          || (new_rtx = lookup_as_function (x, CONST_FIXED)) != 0)
+        return new_rtx;
+
+      /* If we didn't and if doing so makes sense, see if we previously
+        assigned a constant value to the enclosing word mode SUBREG.  */
+      if (GET_MODE_SIZE (mode) < GET_MODE_SIZE (word_mode)
+         && GET_MODE_SIZE (word_mode) < GET_MODE_SIZE (imode))
+       {
+         int byte = SUBREG_BYTE (x) - subreg_lowpart_offset (mode, word_mode);
+         if (byte >= 0 && (byte % UNITS_PER_WORD) == 0)
+           {
+             rtx y = gen_rtx_SUBREG (word_mode, SUBREG_REG (x), byte);
+             new_rtx = lookup_as_function (y, CONST_INT);
+             if (new_rtx)
+               return gen_lowpart (mode, new_rtx);
+           }
+       }
 
+      /* Otherwise see if we already have a constant for the inner REG.  */
       if (REG_P (SUBREG_REG (x))
-         && (new = equiv_constant (SUBREG_REG (x))) != 0)
-        return simplify_subreg (GET_MODE (x), SUBREG_REG (x),
-                               GET_MODE (SUBREG_REG (x)), SUBREG_BYTE (x));
+         && (new_rtx = equiv_constant (SUBREG_REG (x))) != 0)
+        return simplify_subreg (mode, new_rtx, imode, SUBREG_BYTE (x));
 
       return 0;
     }
@@ -3978,11 +3969,7 @@ record_jump_cond (enum rtx_code code, enum machine_mode mode, rtx op0,
    First simplify sources and addresses of all assignments
    in the instruction, using previously-computed equivalents values.
    Then install the new sources and destinations in the table
-   of available values.
-
-   If LIBCALL_INSN is nonzero, don't record any equivalence made in
-   the insn.  It means that INSN is inside libcall block.  In this
-   case LIBCALL_INSN is the corresponding insn with REG_LIBCALL.  */
+   of available values.  */
 
 /* Data on one SET contained in the instruction.  */
 
@@ -4011,8 +3998,6 @@ struct set
   ENUM_BITFIELD(machine_mode) mode : 8;
   /* A constant equivalent for SET_SRC, if any.  */
   rtx src_const;
-  /* Original SET_SRC value used for libcall notes.  */
-  rtx orig_src;
   /* Hash value of constant equivalent for SET_SRC.  */
   unsigned src_const_hash;
   /* Table entry for constant equivalent for SET_SRC, if any.  */
@@ -4022,7 +4007,7 @@ struct set
 };
 
 static void
-cse_insn (rtx insn, rtx libcall_insn)
+cse_insn (rtx insn)
 {
   rtx x = PATTERN (insn);
   int i;
@@ -4061,7 +4046,7 @@ cse_insn (rtx insn, rtx libcall_insn)
 
   if (GET_CODE (x) == SET)
     {
-      sets = alloca (sizeof (struct set));
+      sets = XALLOCA (struct set);
       sets[0].rtl = x;
 
       /* Ignore SETs that are unconditional jumps.
@@ -4096,7 +4081,7 @@ cse_insn (rtx insn, rtx libcall_insn)
     {
       int lim = XVECLEN (x, 0);
 
-      sets = alloca (lim * sizeof (struct set));
+      sets = XALLOCAVEC (struct set, lim);
 
       /* Find all regs explicitly clobbered in this insn,
         and ensure they are not replaced with any other regs
@@ -4151,12 +4136,12 @@ cse_insn (rtx insn, rtx libcall_insn)
                 This does nothing when a register is clobbered
                 because we have already invalidated the reg.  */
              if (MEM_P (XEXP (y, 0)))
-               canon_reg (XEXP (y, 0), NULL_RTX);
+               canon_reg (XEXP (y, 0), insn);
            }
          else if (GET_CODE (y) == USE
                   && ! (REG_P (XEXP (y, 0))
                         && REGNO (XEXP (y, 0)) < FIRST_PSEUDO_REGISTER))
-           canon_reg (y, NULL_RTX);
+           canon_reg (y, insn);
          else if (GET_CODE (y) == CALL)
            {
              /* The result of apply_change_group can be ignored; see
@@ -4170,14 +4155,14 @@ cse_insn (rtx insn, rtx libcall_insn)
   else if (GET_CODE (x) == CLOBBER)
     {
       if (MEM_P (XEXP (x, 0)))
-       canon_reg (XEXP (x, 0), NULL_RTX);
+       canon_reg (XEXP (x, 0), insn);
     }
 
   /* Canonicalize a USE of a pseudo register or memory location.  */
   else if (GET_CODE (x) == USE
           && ! (REG_P (XEXP (x, 0))
                 && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER))
-    canon_reg (XEXP (x, 0), NULL_RTX);
+    canon_reg (XEXP (x, 0), insn);
   else if (GET_CODE (x) == CALL)
     {
       /* The result of apply_change_group can be ignored; see canon_reg.  */
@@ -4195,8 +4180,12 @@ cse_insn (rtx insn, rtx libcall_insn)
       && (! rtx_equal_p (XEXP (tem, 0), SET_SRC (sets[0].rtl))
          || GET_CODE (SET_DEST (sets[0].rtl)) == STRICT_LOW_PART))
     {
-      src_eqv = fold_rtx (canon_reg (XEXP (tem, 0), NULL_RTX), insn);
-      XEXP (tem, 0) = src_eqv;
+      /* The result of apply_change_group can be ignored; see canon_reg.  */
+      canon_reg (XEXP (tem, 0), insn);
+      apply_change_group ();
+      src_eqv = fold_rtx (XEXP (tem, 0), insn);
+      XEXP (tem, 0) = copy_rtx (src_eqv);
+      df_notes_rescan (insn);
     }
 
   /* Canonicalize sources and addresses of destinations.
@@ -4213,10 +4202,9 @@ cse_insn (rtx insn, rtx libcall_insn)
     {
       rtx dest = SET_DEST (sets[i].rtl);
       rtx src = SET_SRC (sets[i].rtl);
-      rtx new = canon_reg (src, insn);
+      rtx new_rtx = canon_reg (src, insn);
 
-      sets[i].orig_src = src;
-      validate_change (insn, &SET_SRC (sets[i].rtl), new, 1);
+      validate_change (insn, &SET_SRC (sets[i].rtl), new_rtx, 1);
 
       if (GET_CODE (dest) == ZERO_EXTRACT)
        {
@@ -4498,7 +4486,8 @@ cse_insn (rtx insn, rtx libcall_insn)
          enum machine_mode wider_mode;
 
          for (wider_mode = GET_MODE_WIDER_MODE (mode);
-              GET_MODE_BITSIZE (wider_mode) <= BITS_PER_WORD
+              wider_mode != VOIDmode
+              && GET_MODE_BITSIZE (wider_mode) <= BITS_PER_WORD
               && src_related == 0;
               wider_mode = GET_MODE_WIDER_MODE (wider_mode))
            {
@@ -4791,18 +4780,35 @@ cse_insn (rtx insn, rtx libcall_insn)
                                  src_related_cost, src_related_regcost) <= 0
                   && preferable (src_eqv_cost, src_eqv_regcost,
                                  src_elt_cost, src_elt_regcost) <= 0)
-           trial = copy_rtx (src_eqv_here), src_eqv_cost = MAX_COST;
+           trial = src_eqv_here, src_eqv_cost = MAX_COST;
          else if (src_related
                   && preferable (src_related_cost, src_related_regcost,
                                  src_elt_cost, src_elt_regcost) <= 0)
-           trial = copy_rtx (src_related), src_related_cost = MAX_COST;
+           trial = src_related, src_related_cost = MAX_COST;
          else
            {
-             trial = copy_rtx (elt->exp);
+             trial = elt->exp;
              elt = elt->next_same_value;
              src_elt_cost = MAX_COST;
            }
 
+         /* Avoid creation of overlapping memory moves.  */
+         if (MEM_P (trial) && MEM_P (SET_DEST (sets[i].rtl)))
+           {
+             rtx src, dest;
+
+             /* BLKmode moves are not handled by cse anyway.  */
+             if (GET_MODE (trial) == BLKmode)
+               break;
+
+             src = canon_rtx (trial);
+             dest = canon_rtx (SET_DEST (sets[i].rtl));
+
+             if (!MEM_P (src) || !MEM_P (dest)
+                 || !nonoverlapping_memrefs_p (src, dest))
+               break;
+           }
+
          /* We don't normally have an insn matching (set (pc) (pc)), so
             check for this separately here.  We will delete such an
             insn below.
@@ -4823,7 +4829,7 @@ cse_insn (rtx insn, rtx libcall_insn)
                continue;
 
              SET_SRC (sets[i].rtl) = trial;
-             cse_jumps_altered = 1;
+             cse_jumps_altered = true;
              break;
            }
 
@@ -4844,29 +4850,15 @@ cse_insn (rtx insn, rtx libcall_insn)
            ;
 
          /* Look for a substitution that makes a valid insn.  */
-         else if (validate_change (insn, &SET_SRC (sets[i].rtl), trial, 0))
+         else if (validate_unshare_change
+                    (insn, &SET_SRC (sets[i].rtl), trial, 0))
            {
-             rtx new = canon_reg (SET_SRC (sets[i].rtl), insn);
-
-             /* If we just made a substitution inside a libcall, then we
-                need to make the same substitution in any notes attached
-                to the RETVAL insn.  */
-             if (libcall_insn
-                 && (REG_P (sets[i].orig_src)
-                     || GET_CODE (sets[i].orig_src) == SUBREG
-                     || MEM_P (sets[i].orig_src)))
-               {
-                 rtx note = find_reg_equal_equiv_note (libcall_insn);
-                 if (note != 0)
-                   XEXP (note, 0) = simplify_replace_rtx (XEXP (note, 0),
-                                                          sets[i].orig_src,
-                                                          copy_rtx (new));
-               }
+             rtx new_rtx = canon_reg (SET_SRC (sets[i].rtl), insn);
 
              /* The result of apply_change_group can be ignored; see
                 canon_reg.  */
 
-             validate_change (insn, &SET_SRC (sets[i].rtl), new, 1);
+             validate_change (insn, &SET_SRC (sets[i].rtl), new_rtx, 1);
              apply_change_group ();
 
              break;
@@ -4979,6 +4971,7 @@ cse_insn (rtx insn, rtx libcall_insn)
              /* Record the actual constant value in a REG_EQUAL note,
                 making a new one if one does not already exist.  */
              set_unique_reg_note (insn, REG_EQUAL, src_const);
+             df_notes_rescan (insn);
            }
        }
 
@@ -5046,7 +5039,7 @@ cse_insn (rtx insn, rtx libcall_insn)
        {
          /* One less use of the label this insn used to jump to.  */
          delete_insn_and_edges (insn);
-         cse_jumps_altered = 1;
+         cse_jumps_altered = true;
          /* No more processing for this set.  */
          sets[i].rtl = 0;
        }
@@ -5056,11 +5049,6 @@ cse_insn (rtx insn, rtx libcall_insn)
       else if (dest == pc_rtx && GET_CODE (src) == LABEL_REF
               && !LABEL_REF_NONLOCAL_P (src))
        {
-         /* Now emit a BARRIER after the unconditional jump.  */
-         if (NEXT_INSN (insn) == 0
-             || !BARRIER_P (NEXT_INSN (insn)))
-           emit_barrier_after (insn);
-
          /* We reemit the jump in as many cases as possible just in
             case the form of an unconditional jump is significantly
             different than a computed jump or conditional jump.
@@ -5070,10 +5058,10 @@ cse_insn (rtx insn, rtx libcall_insn)
             and hope for the best.  */
          if (n_sets == 1)
            {
-             rtx new, note;
+             rtx new_rtx, note;
 
-             new = emit_jump_insn_before (gen_jump (XEXP (src, 0)), insn);
-             JUMP_LABEL (new) = XEXP (src, 0);
+             new_rtx = emit_jump_insn_before (gen_jump (XEXP (src, 0)), insn);
+             JUMP_LABEL (new_rtx) = XEXP (src, 0);
              LABEL_NUSES (XEXP (src, 0))++;
 
              /* Make sure to copy over REG_NON_LOCAL_GOTO.  */
@@ -5081,24 +5069,17 @@ cse_insn (rtx insn, rtx libcall_insn)
              if (note)
                {
                  XEXP (note, 1) = NULL_RTX;
-                 REG_NOTES (new) = note;
+                 REG_NOTES (new_rtx) = note;
                }
 
              delete_insn_and_edges (insn);
-             insn = new;
-
-             /* Now emit a BARRIER after the unconditional jump.  */
-             if (NEXT_INSN (insn) == 0
-                 || !BARRIER_P (NEXT_INSN (insn)))
-               emit_barrier_after (insn);
+             insn = new_rtx;
            }
          else
            INSN_CODE (insn) = -1;
 
-         /* Do not bother deleting any unreachable code,
-            let jump/flow do that.  */
-
-         cse_jumps_altered = 1;
+         /* Do not bother deleting any unreachable code, let jump do it.  */
+         cse_jumps_altered = true;
          sets[i].rtl = 0;
        }
 
@@ -5212,27 +5193,19 @@ cse_insn (rtx insn, rtx libcall_insn)
 
            if (sets[i].src_elt == 0)
              {
-               /* Don't put a hard register source into the table if this is
-                  the last insn of a libcall.  In this case, we only need
-                  to put src_eqv_elt in src_elt.  */
-               if (! find_reg_note (insn, REG_RETVAL, NULL_RTX))
-                 {
-                   struct table_elt *elt;
+               struct table_elt *elt;
 
-                   /* Note that these insert_regs calls cannot remove
-                      any of the src_elt's, because they would have failed to
-                      match if not still valid.  */
-                   if (insert_regs (src, classp, 0))
-                     {
-                       rehash_using_reg (src);
-                       sets[i].src_hash = HASH (src, mode);
-                     }
-                   elt = insert (src, classp, sets[i].src_hash, mode);
-                   elt->in_memory = sets[i].src_in_memory;
-                   sets[i].src_elt = classp = elt;
+               /* Note that these insert_regs calls cannot remove
+                  any of the src_elt's, because they would have failed to
+                  match if not still valid.  */
+               if (insert_regs (src, classp, 0))
+                 {
+                   rehash_using_reg (src);
+                   sets[i].src_hash = HASH (src, mode);
                  }
-               else
-                 sets[i].src_elt = classp;
+               elt = insert (src, classp, sets[i].src_hash, mode);
+               elt->in_memory = sets[i].src_in_memory;
+               sets[i].src_elt = classp = elt;
              }
            if (sets[i].src_const && sets[i].src_const_elt == 0
                && src != sets[i].src_const
@@ -5291,7 +5264,7 @@ cse_insn (rtx insn, rtx libcall_insn)
 
   if (CALL_P (insn))
     {
-      if (! CONST_OR_PURE_CALL_P (insn))
+      if (!(RTL_CONST_OR_PURE_CALL_P (insn)))
        invalidate_memory ();
       invalidate_for_call ();
     }
@@ -5429,11 +5402,6 @@ cse_insn (rtx insn, rtx libcall_insn)
               size of it, and can't be sure that other BLKmode values
               have the same or smaller size.  */
            || GET_MODE (dest) == BLKmode
-           /* Don't record values of destinations set inside a libcall block
-              since we might delete the libcall.  Things should have been set
-              up so we won't want to reuse such a value, but we play it safe
-              here.  */
-           || libcall_insn
            /* If we didn't put a REG_EQUAL value or a source into the hash
               table, there is no point is recording DEST.  */
            || sets[i].src_elt == 0
@@ -5577,11 +5545,7 @@ cse_insn (rtx insn, rtx libcall_insn)
      then be used in the sequel and we may be changing a two-operand insn
      into a three-operand insn.
 
-     Also do not do this if we are operating on a copy of INSN.
-
-     Also don't do this if INSN ends a libcall; this would cause an unrelated
-     register to be set in the middle of a libcall, and we then get bad code
-     if the libcall is deleted.  */
+     Also do not do this if we are operating on a copy of INSN.  */
 
   if (n_sets == 1 && sets[0].rtl && REG_P (SET_DEST (sets[0].rtl))
       && NEXT_INSN (PREV_INSN (insn)) == insn
@@ -5592,8 +5556,7 @@ cse_insn (rtx insn, rtx libcall_insn)
       int src_q = REG_QTY (REGNO (SET_SRC (sets[0].rtl)));
       struct qty_table_elem *src_ent = &qty_table[src_q];
 
-      if ((src_ent->first_reg == REGNO (SET_DEST (sets[0].rtl)))
-         && ! find_reg_note (insn, REG_RETVAL, NULL_RTX))
+      if (src_ent->first_reg == REGNO (SET_DEST (sets[0].rtl)))
        {
          /* Scan for the previous nonnote insn, but stop at a basic
             block boundary.  */
@@ -5716,7 +5679,7 @@ invalidate_from_clobbers (rtx x)
    Return the replacement for X.  */
 
 static rtx
-cse_process_notes (rtx x, rtx object)
+cse_process_notes_1 (rtx x, rtx object, bool *changed)
 {
   enum rtx_code code = GET_CODE (x);
   const char *fmt = GET_RTX_FORMAT (code);
@@ -5729,6 +5692,7 @@ cse_process_notes (rtx x, rtx object)
     case SYMBOL_REF:
     case LABEL_REF:
     case CONST_DOUBLE:
+    case CONST_FIXED:
     case CONST_VECTOR:
     case PC:
     case CC0:
@@ -5737,26 +5701,26 @@ cse_process_notes (rtx x, rtx object)
 
     case MEM:
       validate_change (x, &XEXP (x, 0),
-                      cse_process_notes (XEXP (x, 0), x), 0);
+                      cse_process_notes (XEXP (x, 0), x, changed), 0);
       return x;
 
     case EXPR_LIST:
     case INSN_LIST:
       if (REG_NOTE_KIND (x) == REG_EQUAL)
-       XEXP (x, 0) = cse_process_notes (XEXP (x, 0), NULL_RTX);
+       XEXP (x, 0) = cse_process_notes (XEXP (x, 0), NULL_RTX, changed);
       if (XEXP (x, 1))
-       XEXP (x, 1) = cse_process_notes (XEXP (x, 1), NULL_RTX);
+       XEXP (x, 1) = cse_process_notes (XEXP (x, 1), NULL_RTX, changed);
       return x;
 
     case SIGN_EXTEND:
     case ZERO_EXTEND:
     case SUBREG:
       {
-       rtx new = cse_process_notes (XEXP (x, 0), object);
+       rtx new_rtx = cse_process_notes (XEXP (x, 0), object, changed);
        /* We don't substitute VOIDmode constants into these rtx,
           since they would impede folding.  */
-       if (GET_MODE (new) != VOIDmode)
-         validate_change (object, &XEXP (x, 0), new, 0);
+       if (GET_MODE (new_rtx) != VOIDmode)
+         validate_change (object, &XEXP (x, 0), new_rtx, 0);
        return x;
       }
 
@@ -5772,9 +5736,9 @@ cse_process_notes (rtx x, rtx object)
              && (CONSTANT_P (ent->const_rtx)
                  || REG_P (ent->const_rtx)))
            {
-             rtx new = gen_lowpart (GET_MODE (x), ent->const_rtx);
-             if (new)
-               return copy_rtx (new);
+             rtx new_rtx = gen_lowpart (GET_MODE (x), ent->const_rtx);
+             if (new_rtx)
+               return copy_rtx (new_rtx);
            }
        }
 
@@ -5788,10 +5752,20 @@ cse_process_notes (rtx x, rtx object)
   for (i = 0; i < GET_RTX_LENGTH (code); i++)
     if (fmt[i] == 'e')
       validate_change (object, &XEXP (x, i),
-                      cse_process_notes (XEXP (x, i), object), 0);
+                      cse_process_notes (XEXP (x, i), object, changed), 0);
 
   return x;
 }
+
+static rtx
+cse_process_notes (rtx x, rtx object, bool *changed)
+{
+  rtx new_rtx = cse_process_notes_1 (x, object, changed);
+  if (new_rtx != x)
+    *changed = true;
+  return new_rtx;
+}
+
 \f
 /* Find a path in the CFG, starting with FIRST_BB to perform CSE on.
 
@@ -5966,14 +5940,12 @@ have_eh_succ_edges (basic_block bb)
 
 \f
 /* Scan to the end of the path described by DATA.  Return an estimate of
-   the total number of SETs, and the lowest and highest insn CUID, of all
-   insns in the path.  */
+   the total number of SETs of all insns in the path.  */
 
 static void
 cse_prescan_path (struct cse_basic_block_data *data)
 {
   int nsets = 0;
-  int low_cuid = -1, high_cuid = -1; /* FIXME low_cuid not computed correctly */
   int path_size = data->path_size;
   int path_entry;
 
@@ -5996,21 +5968,9 @@ cse_prescan_path (struct cse_basic_block_data *data)
            nsets += XVECLEN (PATTERN (insn), 0);
          else
            nsets += 1;
-
-         /* Ignore insns made by CSE in a previous traversal of this
-            basic block.  They cannot affect the boundaries of the
-            basic block.
-            FIXME: When we only visit each basic block at most once,
-                   this can go away.  */
-         if (INSN_UID (insn) <= max_uid && INSN_CUID (insn) > high_cuid)
-           high_cuid = INSN_CUID (insn);
-         if (INSN_UID (insn) <= max_uid && INSN_CUID (insn) < low_cuid)
-           low_cuid = INSN_CUID (insn);
        }
     }
 
-  data->low_cuid = low_cuid;
-  data->high_cuid = high_cuid;
   data->nsets = nsets;
 }
 \f
@@ -6027,16 +5987,32 @@ cse_extended_basic_block (struct cse_basic_block_data *ebb_data)
   qty_table = XNEWVEC (struct qty_table_elem, max_qty);
 
   new_basic_block ();
+  cse_ebb_live_in = df_get_live_in (ebb_data->path[0].bb);
+  cse_ebb_live_out = df_get_live_out (ebb_data->path[path_size - 1].bb);
   for (path_entry = 0; path_entry < path_size; path_entry++)
     {
       basic_block bb;
       rtx insn;
-      rtx libcall_insn = NULL_RTX;
-      int no_conflict = 0;
 
       bb = ebb_data->path[path_entry].bb;
+
+      /* Invalidate recorded information for eh regs if there is an EH
+        edge pointing to that bb.  */
+      if (bb_has_eh_pred (bb))
+       {
+         df_ref *def_rec;
+
+         for (def_rec = df_get_artificial_defs (bb->index); *def_rec; def_rec++)
+           {
+             df_ref def = *def_rec;
+             if (DF_REF_FLAGS (def) & DF_REF_AT_TOP)
+               invalidate (DF_REF_REG (def), GET_MODE (DF_REF_REG (def)));
+           }
+       }
+
       FOR_BB_INSNS (bb, insn)
        {
+         optimize_this_for_speed_p = optimize_bb_for_speed_p (bb);
          /* 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 of them when generating
@@ -6058,50 +6034,22 @@ cse_extended_basic_block (struct cse_basic_block_data *ebb_data)
              /* Process notes first so we have all notes in canonical forms
                 when looking for duplicate operations.  */
              if (REG_NOTES (insn))
-               REG_NOTES (insn) = cse_process_notes (REG_NOTES (insn),
-                                                     NULL_RTX);
-
-             /* Track when we are inside in LIBCALL block.  Inside such
-                a block we do not want to record destinations.  The last
-                insn of a LIBCALL block is not considered to be part of
-                the block, since its destination is the result of the
-                block and hence should be recorded.  */
-             if (REG_NOTES (insn) != 0)
                {
-                 rtx p;
-
-                 if ((p = find_reg_note (insn, REG_LIBCALL, NULL_RTX)))
-                   libcall_insn = XEXP (p, 0);
-                 else if (find_reg_note (insn, REG_RETVAL, NULL_RTX))
-                   {
-                     /* Keep libcall_insn for the last SET insn of
-                        a no-conflict block to prevent changing the
-                        destination.  */
-                     if (!no_conflict)
-                       libcall_insn = NULL_RTX;
-                     else
-                       no_conflict = -1;
-                   }
-                 else if (find_reg_note (insn, REG_NO_CONFLICT, NULL_RTX))
-                   no_conflict = 1;
+                 bool changed = false;
+                 REG_NOTES (insn) = cse_process_notes (REG_NOTES (insn),
+                                                       NULL_RTX, &changed);
+                 if (changed)
+                   df_notes_rescan (insn);
                }
 
-             cse_insn (insn, libcall_insn);
+             cse_insn (insn);
 
-             /* If we kept libcall_insn for a no-conflict bock,
-                clear it here.  */
-             if (no_conflict == -1)
-               {
-                 libcall_insn = NULL_RTX;
-                 no_conflict = 0;
-               }
-           
              /* If we haven't already found an insn where we added a LABEL_REF,
                 check this one.  */
-             if (NONJUMP_INSN_P (insn) && ! recorded_label_ref
+             if (INSN_P (insn) && !recorded_label_ref
                  && for_each_rtx (&PATTERN (insn), check_for_label_ref,
                                   (void *) insn))
-               recorded_label_ref = 1;
+               recorded_label_ref = true;
 
 #ifdef HAVE_cc0
              /* If the previous insn set CC0 and this insn no longer
@@ -6132,14 +6080,11 @@ cse_extended_basic_block (struct cse_basic_block_data *ebb_data)
            }
        }
 
-      /* Make sure that libcalls don't span multiple basic blocks.  */
-      gcc_assert (libcall_insn == NULL_RTX);
-
       /* With non-call exceptions, we are not always able to update
         the CFG properly inside cse_insn.  So clean up possibly
         redundant EH edges here.  */
       if (flag_non_call_exceptions && have_eh_succ_edges (bb))
-       purge_dead_edges (bb);
+       cse_cfg_altered |= purge_dead_edges (bb);
 
       /* If we changed a conditional jump, we may have terminated
         the path we are following.  Check that by verifying that
@@ -6191,13 +6136,16 @@ cse_extended_basic_block (struct cse_basic_block_data *ebb_data)
 
   free (qty_table);
 }
+
 \f
 /* Perform cse on the instructions of a function.
    F is the first instruction.
    NREGS is one plus the highest pseudo-reg number used in the instruction.
 
-   Returns 1 if jump_optimize should be redone due to simplifications
-   in conditional jump instructions.  */
+   Return 2 if jump optimizations should be redone due to simplifications
+   in conditional jump instructions.
+   Return 1 if the CFG should be cleaned up because it has been modified.
+   Return 0 otherwise.  */
 
 int
 cse_main (rtx f ATTRIBUTE_UNUSED, int nregs)
@@ -6207,13 +6155,19 @@ cse_main (rtx f ATTRIBUTE_UNUSED, int nregs)
   int *rc_order = XNEWVEC (int, last_basic_block);
   int i, n_blocks;
 
+  df_set_flags (DF_LR_RUN_DCE);
+  df_analyze ();
+  df_set_flags (DF_DEFER_INSN_RESCAN);
+
+  reg_scan (get_insns (), max_reg_num ());
   init_cse_reg_info (nregs);
 
   ebb_data.path = XNEWVEC (struct branch_path,
                           PARAM_VALUE (PARAM_MAX_CSE_PATH_LENGTH));
 
-  cse_jumps_altered = 0;
-  recorded_label_ref = 0;
+  cse_cfg_altered = false;
+  cse_jumps_altered = false;
+  recorded_label_ref = false;
   constant_pool_entries_cost = 0;
   constant_pool_entries_regcost = 0;
   ebb_data.path_size = 0;
@@ -6229,19 +6183,6 @@ cse_main (rtx f ATTRIBUTE_UNUSED, int nregs)
   cse_visited_basic_blocks = sbitmap_alloc (last_basic_block);
   sbitmap_zero (cse_visited_basic_blocks);
 
-  /* Compute the mapping from uids to cuids.
-     CUIDs are numbers assigned to insns, like uids, except that
-     that cuids increase monotonically through the code.  */
-  max_uid = get_max_uid ();
-  uid_cuid = XCNEWVEC (int, max_uid + 1);
-  i = 0;
-  FOR_EACH_BB (bb)
-    {
-      rtx insn;
-      FOR_BB_INSNS (bb, insn)
-       INSN_CUID (insn) = ++i;
-    }
-
   /* Loop over basic blocks in reverse completion order (RPO),
      excluding the ENTRY and EXIT blocks.  */
   n_blocks = pre_and_rev_post_order_compute (NULL, rc_order, false);
@@ -6271,8 +6212,6 @@ cse_main (rtx f ATTRIBUTE_UNUSED, int nregs)
             needed for this path.  For this, we take the number of sets
             and multiply that by MAX_RECOG_OPERANDS.  */
          max_qty = ebb_data.nsets * MAX_RECOG_OPERANDS;
-         cse_basic_block_start = ebb_data.low_cuid;
-         cse_basic_block_end = ebb_data.high_cuid;
 
          /* Dump the path we're about to process.  */
          if (dump_file)
@@ -6284,33 +6223,40 @@ cse_main (rtx f ATTRIBUTE_UNUSED, int nregs)
 
   /* Clean up.  */
   end_alias_analysis ();
-  free (uid_cuid);
   free (reg_eqv_table);
   free (ebb_data.path);
   sbitmap_free (cse_visited_basic_blocks);
   free (rc_order);
   rtl_hooks = general_rtl_hooks;
 
-  return cse_jumps_altered || recorded_label_ref;
+  if (cse_jumps_altered || recorded_label_ref)
+    return 2;
+  else if (cse_cfg_altered)
+    return 1;
+  else
+    return 0;
 }
 \f
-/* Called via for_each_rtx to see if an insn is using a LABEL_REF for which
-   there isn't a REG_LABEL note.  Return one if so.  DATA is the insn.  */
+/* Called via for_each_rtx to see if an insn is using a LABEL_REF for
+   which there isn't a REG_LABEL_OPERAND note.
+   Return one if so.  DATA is the insn.  */
 
 static int
 check_for_label_ref (rtx *rtl, void *data)
 {
   rtx insn = (rtx) data;
 
-  /* If this insn uses a LABEL_REF and there isn't a REG_LABEL note for it,
-     we must rerun jump since it needs to place the note.  If this is a
-     LABEL_REF for a CODE_LABEL that isn't in the insn chain, don't do this
-     since no REG_LABEL will be added.  */
+  /* If this insn uses a LABEL_REF and there isn't a REG_LABEL_OPERAND
+     note for it, we must rerun jump since it needs to place the note.  If
+     this is a LABEL_REF for a CODE_LABEL that isn't in the insn chain,
+     don't do this since no REG_LABEL_OPERAND will be added.  */
   return (GET_CODE (*rtl) == LABEL_REF
          && ! LABEL_REF_NONLOCAL_P (*rtl)
+         && (!JUMP_P (insn)
+             || !label_is_jump_target_p (XEXP (*rtl, 0), insn))
          && LABEL_P (XEXP (*rtl, 0))
          && INSN_UID (XEXP (*rtl, 0)) != 0
-         && ! find_reg_note (insn, REG_LABEL, XEXP (*rtl, 0)));
+         && ! find_reg_note (insn, REG_LABEL_OPERAND, XEXP (*rtl, 0)));
 }
 \f
 /* Count the number of times registers are used (not set) in X.
@@ -6346,6 +6292,7 @@ count_reg_usage (rtx x, int *counts, rtx dest, int incr)
     case CONST:
     case CONST_INT:
     case CONST_DOUBLE:
+    case CONST_FIXED:
     case CONST_VECTOR:
     case SYMBOL_REF:
     case LABEL_REF:
@@ -6497,57 +6444,6 @@ insn_live_p (rtx insn, int *counts)
     return true;
 }
 
-/* Return true if libcall is dead as a whole.  */
-
-static bool
-dead_libcall_p (rtx insn, int *counts)
-{
-  rtx note, set, new;
-
-  /* See if there's a REG_EQUAL note on this insn and try to
-     replace the source with the REG_EQUAL expression.
-
-     We assume that insns with REG_RETVALs can only be reg->reg
-     copies at this point.  */
-  note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
-  if (!note)
-    return false;
-
-  set = single_set (insn);
-  if (!set)
-    return false;
-
-  new = simplify_rtx (XEXP (note, 0));
-  if (!new)
-    new = XEXP (note, 0);
-
-  /* While changing insn, we must update the counts accordingly.  */
-  count_reg_usage (insn, counts, NULL_RTX, -1);
-
-  if (validate_change (insn, &SET_SRC (set), new, 0))
-    {
-      count_reg_usage (insn, counts, NULL_RTX, 1);
-      remove_note (insn, find_reg_note (insn, REG_RETVAL, NULL_RTX));
-      remove_note (insn, note);
-      return true;
-    }
-
-  if (CONSTANT_P (new))
-    {
-      new = force_const_mem (GET_MODE (SET_DEST (set)), new);
-      if (new && validate_change (insn, &SET_SRC (set), new, 0))
-       {
-         count_reg_usage (insn, counts, NULL_RTX, 1);
-         remove_note (insn, find_reg_note (insn, REG_RETVAL, NULL_RTX));
-         remove_note (insn, note);
-         return true;
-       }
-    }
-
-  count_reg_usage (insn, counts, NULL_RTX, 1);
-  return false;
-}
-
 /* Scan all the insns and delete any that are dead; i.e., they store a register
    that is never used or they copy a register to itself.
 
@@ -6561,7 +6457,6 @@ delete_trivially_dead_insns (rtx insns, int nreg)
 {
   int *counts;
   rtx insn, prev;
-  int in_libcall = 0, dead_libcall = 0;
   int ndead = 0;
 
   timevar_push (TV_DELETE_TRIVIALLY_DEAD);
@@ -6586,37 +6481,17 @@ delete_trivially_dead_insns (rtx insns, int nreg)
       if (!INSN_P (insn))
        continue;
 
-      /* Don't delete any insns that are part of a libcall block unless
-        we can delete the whole libcall block.
-
-        Flow or loop might get confused if we did that.  Remember
-        that we are scanning backwards.  */
-      if (find_reg_note (insn, REG_RETVAL, NULL_RTX))
-       {
-         in_libcall = 1;
-         live_insn = 1;
-         dead_libcall = dead_libcall_p (insn, counts);
-       }
-      else if (in_libcall)
-       live_insn = ! dead_libcall;
-      else
-       live_insn = insn_live_p (insn, counts);
+      live_insn = insn_live_p (insn, counts);
 
       /* If this is a dead insn, delete it and show registers in it aren't
         being used.  */
 
-      if (! live_insn)
+      if (! live_insn && dbg_cnt (delete_trivial_dead))
        {
          count_reg_usage (insn, counts, NULL_RTX, -1);
          delete_insn_and_edges (insn);
          ndead++;
        }
-
-      if (in_libcall && find_reg_note (insn, REG_LIBCALL, NULL_RTX))
-       {
-         in_libcall = 0;
-         dead_libcall = 0;
-       }
     }
 
   if (dump_file && ndead)
@@ -6705,13 +6580,17 @@ cse_change_cc_mode_insns (rtx start, rtx end, rtx newreg)
    permitted to change the mode of CC_SRC to a compatible mode.  This
    returns VOIDmode if no equivalent assignments were found.
    Otherwise it returns the mode which CC_SRC should wind up with.
+   ORIG_BB should be the same as BB in the outermost cse_cc_succs call,
+   but is passed unmodified down to recursive calls in order to prevent
+   endless recursion.
 
    The main complexity in this function is handling the mode issues.
    We may have more than one duplicate which we can eliminate, and we
    try to find a mode which will work for multiple duplicates.  */
 
 static enum machine_mode
-cse_cc_succs (basic_block bb, rtx cc_reg, rtx cc_src, bool can_change_mode)
+cse_cc_succs (basic_block bb, basic_block orig_bb, rtx cc_reg, rtx cc_src,
+             bool can_change_mode)
 {
   bool found_equiv;
   enum machine_mode mode;
@@ -6742,7 +6621,9 @@ cse_cc_succs (basic_block bb, rtx cc_reg, rtx cc_src, bool can_change_mode)
        continue;
 
       if (EDGE_COUNT (e->dest->preds) != 1
-         || e->dest == EXIT_BLOCK_PTR)
+         || e->dest == EXIT_BLOCK_PTR
+         /* Avoid endless recursion on unreachable blocks.  */
+         || e->dest == orig_bb)
        continue;
 
       end = NEXT_INSN (BB_END (e->dest));
@@ -6847,7 +6728,7 @@ cse_cc_succs (basic_block bb, rtx cc_reg, rtx cc_src, bool can_change_mode)
        {
          enum machine_mode submode;
 
-         submode = cse_cc_succs (e->dest, cc_reg, cc_src, false);
+         submode = cse_cc_succs (e->dest, orig_bb, cc_reg, cc_src, false);
          if (submode != VOIDmode)
            {
              gcc_assert (submode == mode);
@@ -6882,7 +6763,7 @@ cse_cc_succs (basic_block bb, rtx cc_reg, rtx cc_src, bool can_change_mode)
                                    newreg);
        }
 
-      delete_insn (insns[i]);
+      delete_insn_and_edges (insns[i]);
     }
 
   return mode;
@@ -6975,7 +6856,7 @@ cse_condition_code_reg (void)
         the basic block.  */
 
       orig_mode = GET_MODE (cc_src);
-      mode = cse_cc_succs (bb, cc_reg, cc_src, true);
+      mode = cse_cc_succs (bb, bb, cc_reg, cc_src, true);
       if (mode != VOIDmode)
        {
          gcc_assert (mode == GET_MODE (cc_src));
@@ -7009,28 +6890,33 @@ static unsigned int
 rest_of_handle_cse (void)
 {
   int tem;
+
   if (dump_file)
     dump_flow_info (dump_file, dump_flags);
 
-  reg_scan (get_insns (), max_reg_num ());
-
   tem = cse_main (get_insns (), max_reg_num ());
 
   /* If we are not running more CSE passes, then we are no longer
      expecting CSE to be run.  But always rerun it in a cheap mode.  */
   cse_not_expected = !flag_rerun_cse_after_loop && !flag_gcse;
 
-  if (tem)
-    rebuild_jump_labels (get_insns ());
-
-  if (tem || optimize > 1)
-    cleanup_cfg (CLEANUP_EXPENSIVE);
+  if (tem == 2)
+    {
+      timevar_push (TV_JUMP);
+      rebuild_jump_labels (get_insns ());
+      cleanup_cfg (0);
+      timevar_pop (TV_JUMP);
+    }
+  else if (tem == 1 || optimize > 1)
+    cleanup_cfg (0);
 
   return 0;
 }
 
-struct tree_opt_pass pass_cse =
+struct rtl_opt_pass pass_cse =
 {
+ {
+  RTL_PASS,
   "cse1",                               /* name */
   gate_handle_cse,                      /* gate */   
   rest_of_handle_cse,                  /* execute */       
@@ -7042,10 +6928,11 @@ struct tree_opt_pass pass_cse =
   0,                                    /* properties_provided */
   0,                                    /* properties_destroyed */
   0,                                    /* todo_flags_start */
+  TODO_df_finish | TODO_verify_rtl_sharing |
   TODO_dump_func |
   TODO_ggc_collect |
   TODO_verify_flow,                     /* todo_flags_finish */
-  's'                                   /* letter */
+ }
 };
 
 
@@ -7074,22 +6961,25 @@ rest_of_handle_cse2 (void)
 
   delete_trivially_dead_insns (get_insns (), max_reg_num ());
 
-  if (tem)
+  if (tem == 2)
     {
       timevar_push (TV_JUMP);
       rebuild_jump_labels (get_insns ());
-      delete_dead_jumptables ();
-      cleanup_cfg (CLEANUP_EXPENSIVE);
+      cleanup_cfg (0);
       timevar_pop (TV_JUMP);
     }
-  reg_scan (get_insns (), max_reg_num ());
+  else if (tem == 1)
+    cleanup_cfg (0);
+
   cse_not_expected = 1;
   return 0;
 }
 
 
-struct tree_opt_pass pass_cse2 =
+struct rtl_opt_pass pass_cse2 =
 {
+ {
+  RTL_PASS,
   "cse2",                               /* name */
   gate_handle_cse2,                     /* gate */   
   rest_of_handle_cse2,                 /* execute */       
@@ -7101,9 +6991,10 @@ struct tree_opt_pass pass_cse2 =
   0,                                    /* properties_provided */
   0,                                    /* properties_destroyed */
   0,                                    /* todo_flags_start */
+  TODO_df_finish | TODO_verify_rtl_sharing |
   TODO_dump_func |
   TODO_ggc_collect |
-  TODO_verify_flow,                     /* todo_flags_finish */
-  't'                                   /* letter */
+  TODO_verify_flow                      /* todo_flags_finish */
+ }
 };