Daily bump.
[platform/upstream/gcc.git] / gcc / cse.c
index b41d47a..330c1e9 100644 (file)
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -1,7 +1,5 @@
 /* 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, 2008, 2009, 2010,
-   2011 Free Software Foundation, Inc.
+   Copyright (C) 1987-2021 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -22,28 +20,30 @@ along with GCC; see the file COPYING3.  If not see
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
-#include "tm.h"
+#include "backend.h"
+#include "target.h"
 #include "rtl.h"
+#include "tree.h"
+#include "cfghooks.h"
+#include "df.h"
+#include "memmodel.h"
 #include "tm_p.h"
-#include "hard-reg-set.h"
-#include "regs.h"
-#include "basic-block.h"
-#include "flags.h"
 #include "insn-config.h"
+#include "regs.h"
+#include "emit-rtl.h"
 #include "recog.h"
-#include "function.h"
-#include "expr.h"
-#include "diagnostic-core.h"
+#include "cfgrtl.h"
+#include "cfganal.h"
+#include "cfgcleanup.h"
+#include "alias.h"
 #include "toplev.h"
-#include "ggc.h"
-#include "except.h"
-#include "target.h"
-#include "params.h"
 #include "rtlhooks-def.h"
 #include "tree-pass.h"
-#include "df.h"
 #include "dbgcnt.h"
-#include "pointer-set.h"
+#include "rtl-iter.h"
+#include "regs.h"
+#include "function-abi.h"
+#include "rtlanal.h"
 
 /* The basic idea of common subexpression elimination is to go
    through the code, keeping a record of expressions that would
@@ -243,7 +243,7 @@ static int next_qty;
 struct qty_table_elem
 {
   rtx const_rtx;
-  rtx const_insn;
+  rtx_insn *const_insn;
   rtx comparison_const;
   int comparison_qty;
   unsigned int first_reg, last_reg;
@@ -256,31 +256,9 @@ struct qty_table_elem
 /* The table of all qtys, indexed by qty number.  */
 static struct qty_table_elem *qty_table;
 
-/* Structure used to pass arguments via for_each_rtx to function
-   cse_change_cc_mode.  */
-struct change_cc_mode_args
-{
-  rtx insn;
-  rtx newreg;
-};
-
-#ifdef HAVE_cc0
-/* For machines that have a CC0, we do not record its value in the hash
-   table since its use is guaranteed to be the insn immediately following
-   its definition and any other insn is presumed to invalidate it.
-
-   Instead, we store below the current and last value assigned to CC0.
-   If it should happen to be a constant, it is stored in preference
-   to the actual assigned value.  In case it is a constant, we store
-   the mode in which the constant should be interpreted.  */
-
-static rtx this_insn_cc0, prev_insn_cc0;
-static enum machine_mode this_insn_cc0_mode, prev_insn_cc0_mode;
-#endif
-
 /* Insn being scanned.  */
 
-static rtx this_insn;
+static rtx_insn *this_insn;
 static bool optimize_this_for_speed_p;
 
 /* Index by register number, gives the number of the next (or
@@ -359,9 +337,8 @@ static bool cse_jumps_altered;
    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
-   subexpression.  */
+/* canon_hash stores 1 in do_not_record if it notices a reference to PC or
+   some other volatile subexpression.  */
 
 static int do_not_record;
 
@@ -470,12 +447,14 @@ struct table_elt
    a cost of 2.  Aside from these special cases, call `rtx_cost'.  */
 
 #define CHEAP_REGNO(N)                                                 \
-  (REGNO_PTR_FRAME_P(N)                                                        \
+  (REGNO_PTR_FRAME_P (N)                                               \
    || (HARD_REGISTER_NUM_P (N)                                         \
        && FIXED_REGNO_P (N) && REGNO_REG_CLASS (N) != NO_REGS))
 
-#define COST(X) (REG_P (X) ? 0 : notreg_cost (X, SET, 1))
-#define COST_IN(X, OUTER, OPNO) (REG_P (X) ? 0 : notreg_cost (X, OUTER, OPNO))
+#define COST(X, MODE)                                                  \
+  (REG_P (X) ? 0 : notreg_cost (X, MODE, SET, 1))
+#define COST_IN(X, MODE, OUTER, OPNO)                                  \
+  (REG_P (X) ? 0 : notreg_cost (X, MODE, OUTER, OPNO))
 
 /* Get the number of times this register has been updated in this
    basic block.  */
@@ -551,67 +530,60 @@ static bitmap cse_ebb_live_in, cse_ebb_live_out;
 static sbitmap cse_visited_basic_blocks;
 
 static bool fixed_base_plus_p (rtx x);
-static int notreg_cost (rtx, enum rtx_code, int);
-static int approx_reg_cost_1 (rtx *, void *);
-static int approx_reg_cost (rtx);
+static int notreg_cost (rtx, machine_mode, enum rtx_code, int);
 static int preferable (int, int, int, int);
 static void new_basic_block (void);
-static void make_new_qty (unsigned int, enum machine_mode);
+static void make_new_qty (unsigned int, machine_mode);
 static void make_regs_eqv (unsigned int, unsigned int);
 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 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 struct table_elt *lookup (rtx, unsigned, machine_mode);
+static struct table_elt *lookup_for_remove (rtx, unsigned, machine_mode);
 static rtx lookup_as_function (rtx, enum rtx_code);
 static struct table_elt *insert_with_costs (rtx, struct table_elt *, unsigned,
-                                           enum machine_mode, int, int);
+                                           machine_mode, int, int);
 static struct table_elt *insert (rtx, struct table_elt *, unsigned,
-                                enum machine_mode);
+                                machine_mode);
 static void merge_equiv_classes (struct table_elt *, struct table_elt *);
-static void invalidate (rtx, enum machine_mode);
+static void invalidate (rtx, machine_mode);
 static void remove_invalid_refs (unsigned int);
-static void remove_invalid_subreg_refs (unsigned int, unsigned int,
-                                       enum machine_mode);
+static void remove_invalid_subreg_refs (unsigned int, poly_uint64,
+                                       machine_mode);
 static void rehash_using_reg (rtx);
 static void invalidate_memory (void);
-static void invalidate_for_call (void);
 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 inline unsigned canon_hash (rtx, machine_mode);
+static inline unsigned safe_hash (rtx, machine_mode);
 static inline unsigned hash_rtx_string (const char *);
 
-static rtx canon_reg (rtx, rtx);
+static rtx canon_reg (rtx, rtx_insn *);
 static enum rtx_code find_comparison_args (enum rtx_code, rtx *, rtx *,
-                                          enum machine_mode *,
-                                          enum machine_mode *);
-static rtx fold_rtx (rtx, rtx);
+                                          machine_mode *,
+                                          machine_mode *);
+static rtx fold_rtx (rtx, rtx_insn *);
 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,
+static void record_jump_equiv (rtx_insn *, bool);
+static void record_jump_cond (enum rtx_code, machine_mode, rtx, rtx,
                              int);
-static void cse_insn (rtx);
+static void cse_insn (rtx_insn *);
 static void cse_prescan_path (struct cse_basic_block_data *);
-static void invalidate_from_clobbers (rtx);
-static void invalidate_from_sets_and_clobbers (rtx);
-static rtx cse_process_notes (rtx, rtx, bool *);
+static void invalidate_from_clobbers (rtx_insn *);
+static void invalidate_from_sets_and_clobbers (rtx_insn *);
 static void cse_extended_basic_block (struct cse_basic_block_data *);
-static int check_for_label_ref (rtx *, void *);
 extern void dump_class (struct table_elt*);
 static void get_cse_reg_info_1 (unsigned int regno);
 static struct cse_reg_info * get_cse_reg_info (unsigned int regno);
-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 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, basic_block, rtx, rtx,
+static bool insn_live_p (rtx_insn *, int *);
+static bool set_live_p (rtx, int *);
+static void cse_change_cc_mode_insn (rtx_insn *, rtx);
+static void cse_change_cc_mode_insns (rtx_insn *, rtx_insn *, rtx);
+static machine_mode cse_cc_succs (basic_block, basic_block, rtx, rtx,
                                       bool);
 \f
 
@@ -662,47 +634,35 @@ dump_class (struct table_elt *classp)
     }
 }
 
-/* Subroutine of approx_reg_cost; called through for_each_rtx.  */
+/* Return an estimate of the cost of the registers used in an rtx.
+   This is mostly the number of different REG expressions in the rtx;
+   however for some exceptions like fixed registers we use a cost of
+   0.  If any other hard register reference occurs, return MAX_COST.  */
 
 static int
-approx_reg_cost_1 (rtx *xp, void *data)
+approx_reg_cost (const_rtx x)
 {
-  rtx x = *xp;
-  int *cost_p = (int *) data;
-
-  if (x && REG_P (x))
+  int cost = 0;
+  subrtx_iterator::array_type array;
+  FOR_EACH_SUBRTX (iter, array, x, NONCONST)
     {
-      unsigned int regno = REGNO (x);
-
-      if (! CHEAP_REGNO (regno))
+      const_rtx x = *iter;
+      if (REG_P (x))
        {
-         if (regno < FIRST_PSEUDO_REGISTER)
+         unsigned int regno = REGNO (x);
+         if (!CHEAP_REGNO (regno))
            {
-             if (targetm.small_register_classes_for_mode_p (GET_MODE (x)))
-               return 1;
-             *cost_p += 2;
+             if (regno < FIRST_PSEUDO_REGISTER)
+               {
+                 if (targetm.small_register_classes_for_mode_p (GET_MODE (x)))
+                   return MAX_COST;
+                 cost += 2;
+               }
+             else
+               cost += 1;
            }
-         else
-           *cost_p += 1;
        }
     }
-
-  return 0;
-}
-
-/* Return an estimate of the cost of the registers used in an rtx.
-   This is mostly the number of different REG expressions in the rtx;
-   however for some exceptions like fixed registers we use a cost of
-   0.  If any other hard register reference occurs, return MAX_COST.  */
-
-static int
-approx_reg_cost (rtx x)
-{
-  int cost = 0;
-
-  if (for_each_rtx (&x, approx_reg_cost_1, (void *) &cost))
-    return MAX_COST;
-
   return cost;
 }
 
@@ -745,19 +705,18 @@ preferable (int cost_a, int regcost_a, int cost_b, int regcost_b)
    from COST macro to keep it simple.  */
 
 static int
-notreg_cost (rtx x, enum rtx_code outer, int opno)
+notreg_cost (rtx x, machine_mode mode, enum rtx_code outer, int opno)
 {
+  scalar_int_mode int_mode, inner_mode;
   return ((GET_CODE (x) == SUBREG
           && REG_P (SUBREG_REG (x))
-          && GET_MODE_CLASS (GET_MODE (x)) == MODE_INT
-          && GET_MODE_CLASS (GET_MODE (SUBREG_REG (x))) == MODE_INT
-          && (GET_MODE_SIZE (GET_MODE (x))
-              < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
+          && is_int_mode (mode, &int_mode)
+          && is_int_mode (GET_MODE (SUBREG_REG (x)), &inner_mode)
+          && GET_MODE_SIZE (int_mode) < GET_MODE_SIZE (inner_mode)
           && subreg_lowpart_p (x)
-          && TRULY_NOOP_TRUNCATION_MODES_P (GET_MODE (x),
-                                            GET_MODE (SUBREG_REG (x))))
+          && TRULY_NOOP_TRUNCATION_MODES_P (int_mode, inner_mode))
          ? 0
-         : rtx_cost (x, outer, opno, optimize_this_for_speed_p) * 2);
+         : rtx_cost (x, mode, outer, opno, optimize_this_for_speed_p) * 2);
 }
 
 \f
@@ -883,17 +842,13 @@ new_basic_block (void)
          free_element_chain = first;
        }
     }
-
-#ifdef HAVE_cc0
-  prev_insn_cc0 = 0;
-#endif
 }
 
 /* Say that register REG contains a quantity in mode MODE not in any
    register before and initialize that quantity.  */
 
 static void
-make_new_qty (unsigned int reg, enum machine_mode mode)
+make_new_qty (unsigned int reg, machine_mode mode)
 {
   int q;
   struct qty_table_elem *ent;
@@ -906,7 +861,7 @@ make_new_qty (unsigned int reg, enum machine_mode mode)
   ent->first_reg = reg;
   ent->last_reg = reg;
   ent->mode = mode;
-  ent->const_rtx = ent->const_insn = NULL_RTX;
+  ent->const_rtx = ent->const_insn = NULL;
   ent->comparison_code = UNKNOWN;
 
   eqv = &reg_eqv_table[reg];
@@ -1238,7 +1193,7 @@ compute_const_anchors (rtx cst,
 
 static void
 insert_const_anchor (HOST_WIDE_INT anchor, rtx reg, HOST_WIDE_INT offs,
-                    enum machine_mode mode)
+                    machine_mode mode)
 {
   struct table_elt *elt;
   unsigned hash;
@@ -1263,7 +1218,7 @@ insert_const_anchor (HOST_WIDE_INT anchor, rtx reg, HOST_WIDE_INT offs,
      don't prefer pseudos over hard regs so that we derive constants in
      argument registers from other argument registers rather than from the
      original pseudo that was used to synthesize the constant.  */
-  insert_with_costs (exp, elt, hash, mode, COST (reg), 1);
+  insert_with_costs (exp, elt, hash, mode, COST (reg, mode), 1);
 }
 
 /* The constant CST is equivalent to the register REG.  Create
@@ -1271,7 +1226,7 @@ insert_const_anchor (HOST_WIDE_INT anchor, rtx reg, HOST_WIDE_INT offs,
    register-offset expressions using REG.  */
 
 static void
-insert_const_anchors (rtx reg, rtx cst, enum machine_mode mode)
+insert_const_anchors (rtx reg, rtx cst, machine_mode mode)
 {
   HOST_WIDE_INT lower_base, lower_offs, upper_base, upper_offs;
 
@@ -1348,7 +1303,7 @@ find_reg_offset_for_const (struct table_elt *anchor_elt, HOST_WIDE_INT offs,
    otherwise.  */
 
 static rtx
-try_const_anchors (rtx src_const, enum machine_mode mode)
+try_const_anchors (rtx src_const, machine_mode mode)
 {
   struct table_elt *lower_elt, *upper_elt;
   HOST_WIDE_INT lower_base, lower_offs, upper_base, upper_offs;
@@ -1356,6 +1311,11 @@ try_const_anchors (rtx src_const, enum machine_mode mode)
   rtx lower_exp = NULL_RTX, upper_exp = NULL_RTX;
   unsigned lower_old, upper_old;
 
+  /* CONST_INT is used for CC modes, but we should leave those alone.  */
+  if (GET_MODE_CLASS (mode) == MODE_CC)
+    return NULL_RTX;
+
+  gcc_assert (SCALAR_INT_MODE_P (mode));
   if (!compute_const_anchors (src_const, &lower_base, &lower_offs,
                              &upper_base, &upper_offs))
     return NULL_RTX;
@@ -1483,7 +1443,7 @@ remove_pseudo_from_table (rtx x, unsigned int hash)
    looks like X.  */
 
 static struct table_elt *
-lookup (rtx x, unsigned int hash, enum machine_mode mode)
+lookup (rtx x, unsigned int hash, machine_mode mode)
 {
   struct table_elt *p;
 
@@ -1499,7 +1459,7 @@ lookup (rtx x, unsigned int hash, enum machine_mode mode)
    Also ignore discrepancies in the machine mode of a register.  */
 
 static struct table_elt *
-lookup_for_remove (rtx x, unsigned int hash, enum machine_mode mode)
+lookup_for_remove (rtx x, unsigned int hash, machine_mode mode)
 {
   struct table_elt *p;
 
@@ -1572,7 +1532,7 @@ lookup_as_function (rtx x, enum rtx_code code)
 
 static struct table_elt *
 insert_with_costs (rtx x, struct table_elt *classp, unsigned int hash,
-                  enum machine_mode mode, int cost, int reg_cost)
+                  machine_mode mode, int cost, int reg_cost)
 {
   struct table_elt *elt;
 
@@ -1737,10 +1697,10 @@ insert_with_costs (rtx x, struct table_elt *classp, unsigned int hash,
 
 static struct table_elt *
 insert (rtx x, struct table_elt *classp, unsigned int hash,
-       enum machine_mode mode)
+       machine_mode mode)
 {
-  return
-    insert_with_costs (x, classp, hash, mode, COST (x), approx_reg_cost (x));
+  return insert_with_costs (x, classp, hash, mode,
+                           COST (x, mode), approx_reg_cost (x));
 }
 
 \f
@@ -1770,7 +1730,7 @@ merge_equiv_classes (struct table_elt *class1, struct table_elt *class2)
     {
       unsigned int hash;
       rtx exp = elt->exp;
-      enum machine_mode mode = elt->mode;
+      machine_mode mode = elt->mode;
 
       next = elt->next_same_value;
 
@@ -1802,6 +1762,8 @@ merge_equiv_classes (struct table_elt *class1, struct table_elt *class2)
            }
          new_elt = insert (exp, class1, hash, mode);
          new_elt->in_memory = hash_arg_in_memory;
+         if (GET_CODE (exp) == ASM_OPERANDS && elt->cost == MAX_COST)
+           new_elt->cost = MAX_COST;
        }
     }
 }
@@ -1826,24 +1788,87 @@ flush_hash_table (void)
       }
 }
 \f
-/* Function called for each rtx to check whether true dependence exist.  */
-struct check_dependence_data
+/* Check whether an anti dependence exists between X and EXP.  MODE and
+   ADDR are as for canon_anti_dependence.  */
+
+static bool
+check_dependence (const_rtx x, rtx exp, machine_mode mode, rtx addr)
 {
-  enum machine_mode mode;
-  rtx exp;
-  rtx addr;
-};
+  subrtx_iterator::array_type array;
+  FOR_EACH_SUBRTX (iter, array, x, NONCONST)
+    {
+      const_rtx x = *iter;
+      if (MEM_P (x) && canon_anti_dependence (x, true, exp, mode, addr))
+       return true;
+    }
+  return false;
+}
 
-static int
-check_dependence (rtx *x, void *data)
+/* Remove from the hash table, or mark as invalid, all expressions whose
+   values could be altered by storing in register X.  */
+
+static void
+invalidate_reg (rtx x)
 {
-  struct check_dependence_data *d = (struct check_dependence_data *) data;
-  if (*x && MEM_P (*x))
-    return canon_true_dependence (d->exp, d->mode, d->addr, *x, NULL_RTX);
+  gcc_assert (GET_CODE (x) == REG);
+
+  /* If X is a register, dependencies on its contents are recorded
+     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.  */
+  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
+     entry from the hash table.
+
+     For a hard register, we do the first two actions above for any
+     additional hard registers corresponding to X.  Then, if any of these
+     registers are in the table, we must remove any REG entries that
+     overlap these registers.  */
+
+  delete_reg_equiv (regno);
+  REG_TICK (regno)++;
+  SUBREG_TICKED (regno) = -1;
+
+  if (regno >= FIRST_PSEUDO_REGISTER)
+    remove_pseudo_from_table (x, hash);
   else
-    return 0;
+    {
+      HOST_WIDE_INT in_table = TEST_HARD_REG_BIT (hard_regs_in_table, regno);
+      unsigned int endregno = END_REGNO (x);
+      unsigned int rn;
+      struct table_elt *p, *next;
+
+      CLEAR_HARD_REG_BIT (hard_regs_in_table, regno);
+
+      for (rn = regno + 1; rn < endregno; rn++)
+       {
+         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)++;
+         SUBREG_TICKED (rn) = -1;
+       }
+
+      if (in_table)
+       for (hash = 0; hash < HASH_SIZE; hash++)
+         for (p = table[hash]; p; p = next)
+           {
+             next = p->next_same_hash;
+
+             if (!REG_P (p->exp) || REGNO (p->exp) >= FIRST_PSEUDO_REGISTER)
+               continue;
+
+             unsigned int tregno = REGNO (p->exp);
+             unsigned int tendregno = END_REGNO (p->exp);
+             if (tendregno > regno && tregno < endregno)
+               remove_from_table (p, hash);
+           }
+    }
 }
-\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
@@ -1857,7 +1882,7 @@ check_dependence (rtx *x, void *data)
    or it may be either of those plus a numeric offset.  */
 
 static void
-invalidate (rtx x, enum machine_mode full_mode)
+invalidate (rtx x, machine_mode full_mode)
 {
   int i;
   struct table_elt *p;
@@ -1866,65 +1891,7 @@ invalidate (rtx x, enum machine_mode full_mode)
   switch (GET_CODE (x))
     {
     case REG:
-      {
-       /* If X is a register, dependencies on its contents are recorded
-          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.  */
-       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
-          entry from the hash table.
-
-          For a hard register, we do the first two actions above for any
-          additional hard registers corresponding to X.  Then, if any of these
-          registers are in the table, we must remove any REG entries that
-          overlap these registers.  */
-
-       delete_reg_equiv (regno);
-       REG_TICK (regno)++;
-       SUBREG_TICKED (regno) = -1;
-
-       if (regno >= FIRST_PSEUDO_REGISTER)
-         remove_pseudo_from_table (x, hash);
-       else
-         {
-           HOST_WIDE_INT in_table
-             = TEST_HARD_REG_BIT (hard_regs_in_table, regno);
-           unsigned int endregno = END_HARD_REGNO (x);
-           unsigned int tregno, tendregno, rn;
-           struct table_elt *p, *next;
-
-           CLEAR_HARD_REG_BIT (hard_regs_in_table, regno);
-
-           for (rn = regno + 1; rn < endregno; rn++)
-             {
-               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)++;
-               SUBREG_TICKED (rn) = -1;
-             }
-
-           if (in_table)
-             for (hash = 0; hash < HASH_SIZE; hash++)
-               for (p = table[hash]; p; p = next)
-                 {
-                   next = p->next_same_hash;
-
-                   if (!REG_P (p->exp)
-                       || REGNO (p->exp) >= FIRST_PSEUDO_REGISTER)
-                     continue;
-
-                   tregno = REGNO (p->exp);
-                   tendregno = END_HARD_REGNO (p->exp);
-                   if (tendregno > regno && tregno < endregno)
-                     remove_from_table (p, hash);
-                 }
-         }
-      }
+      invalidate_reg (x);
       return;
 
     case SUBREG:
@@ -1962,18 +1929,13 @@ invalidate (rtx x, enum machine_mode full_mode)
              next = p->next_same_hash;
              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.addr = addr;
-                 d.mode = full_mode;
-                 if (for_each_rtx (&p->canon_exp, check_dependence, &d))
+                 if (check_dependence (p->canon_exp, x, full_mode, addr))
                    remove_from_table (p, i);
                }
            }
@@ -1984,6 +1946,22 @@ invalidate (rtx x, enum machine_mode full_mode)
       gcc_unreachable ();
     }
 }
+
+/* Invalidate DEST.  Used when DEST is not going to be added
+   into the hash table for some reason, e.g. do_not_record
+   flagged on it.  */
+
+static void
+invalidate_dest (rtx dest)
+{
+  if (REG_P (dest)
+      || GET_CODE (dest) == SUBREG
+      || MEM_P (dest))
+    invalidate (dest, VOIDmode);
+  else if (GET_CODE (dest) == STRICT_LOW_PART
+          || GET_CODE (dest) == ZERO_EXTRACT)
+    invalidate (XEXP (dest, 0), GET_MODE (dest));
+}
 \f
 /* Remove all expressions that refer to register REGNO,
    since they are already invalid, and we are about to
@@ -2000,8 +1978,7 @@ remove_invalid_refs (unsigned int regno)
     for (p = table[i]; p; p = next)
       {
        next = p->next_same_hash;
-       if (!REG_P (p->exp)
-           && refers_to_regno_p (regno, regno + 1, p->exp, (rtx *) 0))
+       if (!REG_P (p->exp) && refers_to_regno_p (regno, p->exp))
          remove_from_table (p, i);
       }
 }
@@ -2009,12 +1986,11 @@ remove_invalid_refs (unsigned int regno)
 /* Likewise for a subreg with subreg_reg REGNO, subreg_byte OFFSET,
    and mode MODE.  */
 static void
-remove_invalid_subreg_refs (unsigned int regno, unsigned int offset,
-                           enum machine_mode mode)
+remove_invalid_subreg_refs (unsigned int regno, poly_uint64 offset,
+                           machine_mode mode)
 {
   unsigned int i;
   struct table_elt *p, *next;
-  unsigned int end = offset + (GET_MODE_SIZE (mode) - 1);
 
   for (i = 0; i < HASH_SIZE; i++)
     for (p = table[i]; p; p = next)
@@ -2026,10 +2002,10 @@ remove_invalid_subreg_refs (unsigned int regno, unsigned int offset,
            && (GET_CODE (exp) != SUBREG
                || !REG_P (SUBREG_REG (exp))
                || REGNO (SUBREG_REG (exp)) != regno
-               || (((SUBREG_BYTE (exp)
-                     + (GET_MODE_SIZE (GET_MODE (exp)) - 1)) >= offset)
-                   && SUBREG_BYTE (exp) <= end))
-           && refers_to_regno_p (regno, regno + 1, p->exp, (rtx *) 0))
+               || ranges_maybe_overlap_p (SUBREG_BYTE (exp),
+                                          GET_MODE_SIZE (GET_MODE (exp)),
+                                          offset, GET_MODE_SIZE (mode)))
+           && refers_to_regno_p (regno, p->exp))
          remove_from_table (p, i);
       }
 }
@@ -2086,23 +2062,31 @@ rehash_using_reg (rtx x)
 }
 \f
 /* Remove from the hash table any expression that is a call-clobbered
-   register.  Also update their TICK values.  */
+   register in INSN.  Also update their TICK values.  */
 
 static void
-invalidate_for_call (void)
+invalidate_for_call (rtx_insn *insn)
 {
-  unsigned int regno, endregno;
-  unsigned int i;
+  unsigned int regno;
   unsigned hash;
   struct table_elt *p, *next;
   int in_table = 0;
   hard_reg_set_iterator hrsi;
 
-  /* Go through all the hard registers.  For each that is clobbered in
-     a CALL_INSN, remove the register from quantity chains and update
+  /* Go through all the hard registers.  For each that might be clobbered
+     in call insn INSN, remove the register from quantity chains and update
      reg_tick if defined.  Also see if any of these registers is currently
-     in the table.  */
-  EXECUTE_IF_SET_IN_HARD_REG_SET (regs_invalidated_by_call, 0, regno, hrsi)
+     in the table.
+
+     ??? We could be more precise for partially-clobbered registers,
+     and only invalidate values that actually occupy the clobbered part
+     of the registers.  It doesn't seem worth the effort though, since
+     we shouldn't see this situation much before RA.  Whatever choice
+     we make here has to be consistent with the table walk below,
+     so any change to this test will require a change there too.  */
+  HARD_REG_SET callee_clobbers
+    = insn_callee_abi (insn).full_and_partial_reg_clobbers ();
+  EXECUTE_IF_SET_IN_HARD_REG_SET (callee_clobbers, 0, regno, hrsi)
     {
       delete_reg_equiv (regno);
       if (REG_TICK (regno) >= 0)
@@ -2127,15 +2111,11 @@ invalidate_for_call (void)
              || REGNO (p->exp) >= FIRST_PSEUDO_REGISTER)
            continue;
 
-         regno = REGNO (p->exp);
-         endregno = END_HARD_REGNO (p->exp);
-
-         for (i = regno; i < endregno; i++)
-           if (TEST_HARD_REG_BIT (regs_invalidated_by_call, i))
-             {
-               remove_from_table (p, hash);
-               break;
-             }
+         /* This must use the same test as above rather than the
+            more accurate clobbers_reg_p.  */
+         if (overlaps_hard_reg_set_p (callee_clobbers, GET_MODE (p->exp),
+                                      REGNO (p->exp)))
+           remove_from_table (p, hash);
        }
 }
 \f
@@ -2231,7 +2211,7 @@ hash_rtx_string (const char *ps)
    When the callback returns true, we continue with the new rtx.  */
 
 unsigned
-hash_rtx_cb (const_rtx x, enum machine_mode mode,
+hash_rtx_cb (const_rtx x, machine_mode mode,
              int *do_not_record_p, int *hash_arg_in_memory_p,
              bool have_reg_qty, hash_rtx_callback_function cb)
 {
@@ -2239,7 +2219,7 @@ hash_rtx_cb (const_rtx x, enum machine_mode mode,
   unsigned hash = 0;
   enum rtx_code code;
   const char *fmt;
-  enum machine_mode newmode;
+  machine_mode newmode;
   rtx newx;
 
   /* Used to turn recursion into iteration.  We can't rely on GCC's
@@ -2322,7 +2302,8 @@ hash_rtx_cb (const_rtx x, enum machine_mode mode,
          {
            hash += (((unsigned int) SUBREG << 7)
                     + REGNO (SUBREG_REG (x))
-                    + (SUBREG_BYTE (x) / UNITS_PER_WORD));
+                    + (constant_lower_bound (SUBREG_BYTE (x))
+                       / UNITS_PER_WORD));
            return hash;
          }
        break;
@@ -2333,15 +2314,29 @@ hash_rtx_cb (const_rtx x, enum machine_mode mode,
                + (unsigned int) INTVAL (x));
       return hash;
 
+    case CONST_WIDE_INT:
+      for (i = 0; i < CONST_WIDE_INT_NUNITS (x); i++)
+       hash += CONST_WIDE_INT_ELT (x, i);
+      return hash;
+
+    case CONST_POLY_INT:
+      {
+       inchash::hash h;
+       h.add_int (hash);
+       for (unsigned int i = 0; i < NUM_POLY_INT_COEFFS; ++i)
+         h.add_wide_int (CONST_POLY_INT_COEFFS (x)[i]);
+       return h.end ();
+      }
+
     case CONST_DOUBLE:
       /* This is like the general case, except that it only counts
         the integers representing the constant.  */
       hash += (unsigned int) code + (unsigned int) GET_MODE (x);
-      if (GET_MODE (x) != VOIDmode)
-       hash += real_hash (CONST_DOUBLE_REAL_VALUE (x));
-      else
+      if (TARGET_SUPPORTS_WIDE_INT == 0 && GET_MODE (x) == VOIDmode)
        hash += ((unsigned int) CONST_DOUBLE_LOW (x)
                 + (unsigned int) CONST_DOUBLE_HIGH (x));
+      else
+       hash += real_hash (CONST_DOUBLE_REAL_VALUE (x));
       return hash;
 
     case CONST_FIXED:
@@ -2354,11 +2349,11 @@ hash_rtx_cb (const_rtx x, enum machine_mode mode,
        int units;
        rtx elt;
 
-       units = CONST_VECTOR_NUNITS (x);
+       units = const_vector_encoded_nelts (x);
 
        for (i = 0; i < units; ++i)
          {
-           elt = CONST_VECTOR_ELT (x, i);
+           elt = CONST_VECTOR_ENCODED_ELT (x, i);
            hash += hash_rtx_cb (elt, GET_MODE (elt),
                                  do_not_record_p, hash_arg_in_memory_p,
                                  have_reg_qty, cb);
@@ -2372,7 +2367,7 @@ hash_rtx_cb (const_rtx x, enum machine_mode mode,
       /* We don't hash on the address of the CODE_LABEL to avoid bootstrap
         differences and differences between each stage's debugging dumps.  */
         hash += (((unsigned int) LABEL_REF << 7)
-                 + CODE_LABEL_NUMBER (XEXP (x, 0)));
+                 + CODE_LABEL_NUMBER (label_ref_label (x)));
       return hash;
 
     case SYMBOL_REF:
@@ -2439,7 +2434,6 @@ hash_rtx_cb (const_rtx x, enum machine_mode mode,
     case PRE_MODIFY:
     case POST_MODIFY:
     case PC:
-    case CC0:
     case CALL:
     case UNSPEC_VOLATILE:
       if (do_not_record_p) {
@@ -2527,6 +2521,10 @@ hash_rtx_cb (const_rtx x, enum machine_mode mode,
          hash += (unsigned int) XINT (x, i);
          break;
 
+       case 'p':
+         hash += constant_lower_bound (SUBREG_BYTE (x));
+         break;
+
        case '0': case 't':
          /* Unused.  */
          break;
@@ -2553,7 +2551,7 @@ hash_rtx_cb (const_rtx x, enum machine_mode mode,
    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,
+hash_rtx (const_rtx x, 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,
@@ -2566,7 +2564,7 @@ hash_rtx (const_rtx x, enum machine_mode mode, int *do_not_record_p,
    does not have the MEM_READONLY_P flag set.  */
 
 static inline unsigned
-canon_hash (rtx x, enum machine_mode mode)
+canon_hash (rtx x, machine_mode mode)
 {
   return hash_rtx (x, mode, &do_not_record, &hash_arg_in_memory, true);
 }
@@ -2575,7 +2573,7 @@ canon_hash (rtx x, enum machine_mode mode)
    and hash_arg_in_memory are not changed.  */
 
 static inline unsigned
-safe_hash (rtx x, enum machine_mode mode)
+safe_hash (rtx x, machine_mode mode)
 {
   int dummy_do_not_record;
   return hash_rtx (x, mode, &dummy_do_not_record, NULL, true);
@@ -2620,12 +2618,16 @@ exp_equiv_p (const_rtx x, const_rtx y, int validate, bool for_gcse)
   switch (code)
     {
     case PC:
-    case CC0:
     CASE_CONST_UNIQUE:
       return x == y;
 
+    case CONST_VECTOR:
+      if (!same_vector_encodings_p (x, y))
+       return false;
+      break;
+
     case LABEL_REF:
-      return XEXP (x, 0) == XEXP (y, 0);
+      return label_ref_label (x) == label_ref_label (y);
 
     case SYMBOL_REF:
       return XSTR (x, 0) == XSTR (y, 0);
@@ -2677,7 +2679,14 @@ exp_equiv_p (const_rtx x, const_rtx y, int validate, bool for_gcse)
             But because really all MEM attributes should be the same for
             equivalent MEMs, we just use the invariant that MEMs that have
             the same attributes share the same mem_attrs data structure.  */
-         if (MEM_ATTRS (x) != MEM_ATTRS (y))
+         if (!mem_attrs_eq_p (MEM_ATTRS (x), MEM_ATTRS (y)))
+           return 0;
+
+         /* If we are handling exceptions, we cannot consider two expressions
+            with different trapping status as equivalent, because simple_mem
+            might accept one and reject the other.  */
+         if (cfun->can_throw_non_call_exceptions
+             && (MEM_NOTRAP_P (x) != MEM_NOTRAP_P (y)))
            return 0;
        }
       break;
@@ -2770,6 +2779,11 @@ exp_equiv_p (const_rtx x, const_rtx y, int validate, bool for_gcse)
            return 0;
          break;
 
+       case 'p':
+         if (maybe_ne (SUBREG_BYTE (x), SUBREG_BYTE (y)))
+           return 0;
+         break;
+
        case '0':
        case 't':
          break;
@@ -2786,7 +2800,7 @@ exp_equiv_p (const_rtx x, const_rtx y, int validate, bool for_gcse)
    the result if necessary.  INSN is as for canon_reg.  */
 
 static void
-validate_canon_reg (rtx *xloc, rtx insn)
+validate_canon_reg (rtx *xloc, rtx_insn *insn)
 {
   if (*xloc)
     {
@@ -2810,7 +2824,7 @@ validate_canon_reg (rtx *xloc, rtx insn)
    generally be discarded since the changes we are making are optional.  */
 
 static rtx
-canon_reg (rtx x, rtx insn)
+canon_reg (rtx x, rtx_insn *insn)
 {
   int i;
   enum rtx_code code;
@@ -2823,7 +2837,6 @@ canon_reg (rtx x, rtx insn)
   switch (code)
     {
     case PC:
-    case CC0:
     case CONST:
     CASE_CONST_ANY:
     case SYMBOL_REF:
@@ -2879,19 +2892,19 @@ canon_reg (rtx x, rtx insn)
    what values are being compared.
 
    *PARG1 and *PARG2 are updated to contain the rtx representing the values
-   actually being compared.  For example, if *PARG1 was (cc0) and *PARG2
-   was (const_int 0), *PARG1 and *PARG2 will be set to the objects that were
-   compared to produce cc0.
+   actually being compared.  For example, if *PARG1 was (reg:CC CC_REG) and
+   *PARG2 was (const_int 0), *PARG1 and *PARG2 will be set to the objects that
+   were compared to produce (reg:CC CC_REG).
 
    The return value is the comparison operator and is either the code of
    A or the code corresponding to the inverse of the comparison.  */
 
 static enum rtx_code
 find_comparison_args (enum rtx_code code, rtx *parg1, rtx *parg2,
-                     enum machine_mode *pmode1, enum machine_mode *pmode2)
+                     machine_mode *pmode1, machine_mode *pmode2)
 {
   rtx arg1, arg2;
-  struct pointer_set_t *visited = NULL;
+  hash_set<rtx> *visited = NULL;
   /* Set nonzero when we find something of interest.  */
   rtx x = NULL;
 
@@ -2908,15 +2921,12 @@ find_comparison_args (enum rtx_code code, rtx *parg1, rtx *parg2,
       if (x)
        {
          if (!visited)
-           visited = pointer_set_create ();
-         pointer_set_insert (visited, x);
+           visited = new hash_set<rtx>;
+         visited->add (x);
          x = 0;
        }
 
-      /* If arg1 is a COMPARE, extract the comparison arguments from it.
-        On machines with CC0, this is the only case that can occur, since
-        fold_rtx will return the COMPARE or item being compared with zero
-        when given CC0.  */
+      /* If arg1 is a COMPARE, extract the comparison arguments from it.  */
 
       if (GET_CODE (arg1) == COMPARE && arg2 == const0_rtx)
        x = arg1;
@@ -2980,7 +2990,7 @@ find_comparison_args (enum rtx_code code, rtx *parg1, rtx *parg2,
 
       for (; p; p = p->next_same_value)
        {
-         enum machine_mode inner_mode = GET_MODE (p->exp);
+         machine_mode inner_mode = GET_MODE (p->exp);
 #ifdef FLOAT_STORE_FLAG_VALUE
          REAL_VALUE_TYPE fsfv;
 #endif
@@ -2990,7 +3000,7 @@ find_comparison_args (enum rtx_code code, rtx *parg1, rtx *parg2,
            continue;
 
          /* If it's a comparison we've used before, skip it.  */
-         if (visited && pointer_set_contains (visited, p->exp))
+         if (visited && visited->contains (p->exp))
            continue;
 
          if (GET_CODE (p->exp) == COMPARE
@@ -3050,12 +3060,12 @@ find_comparison_args (enum rtx_code code, rtx *parg1, rtx *parg2,
       if (x == 0)
        break;
 
-      /* If we need to reverse the comparison, make sure that that is
+      /* If we need to reverse the comparison, make sure that is
         possible -- we can't necessarily infer the value of GE from LT
         with floating-point operands.  */
       if (reverse_code)
        {
-         enum rtx_code reversed = reversed_comparison_code (x, NULL_RTX);
+         enum rtx_code reversed = reversed_comparison_code (x, NULL);
          if (reversed == UNKNOWN)
            break;
          else
@@ -3072,7 +3082,7 @@ find_comparison_args (enum rtx_code code, rtx *parg1, rtx *parg2,
   *parg1 = fold_rtx (arg1, 0), *parg2 = fold_rtx (arg2, 0);
 
   if (visited)
-    pointer_set_destroy (visited);
+    delete visited;
   return code;
 }
 \f
@@ -3089,18 +3099,21 @@ find_comparison_args (enum rtx_code code, rtx *parg1, rtx *parg2,
    of X before modifying it.  */
 
 static rtx
-fold_rtx (rtx x, rtx insn)
+fold_rtx (rtx x, rtx_insn *insn)
 {
   enum rtx_code code;
-  enum machine_mode mode;
+  machine_mode mode;
   const char *fmt;
   int i;
   rtx new_rtx = 0;
   int changed = 0;
+  poly_int64 xval;
 
   /* Operands of X.  */
-  rtx folded_arg0;
-  rtx folded_arg1;
+  /* Workaround -Wmaybe-uninitialized false positive during
+     profiledbootstrap by initializing them.  */
+  rtx folded_arg0 = NULL_RTX;
+  rtx folded_arg1 = NULL_RTX;
 
   /* Constant equivalents of first three operands of X;
      0 when no such equivalent is known.  */
@@ -3110,7 +3123,7 @@ fold_rtx (rtx x, rtx insn)
 
   /* The mode of the first operand of X.  We need this for sign and zero
      extends.  */
-  enum machine_mode mode_arg0;
+  machine_mode mode_arg0;
 
   if (x == 0)
     return x;
@@ -3121,6 +3134,15 @@ fold_rtx (rtx x, rtx insn)
     {
     case MEM:
     case SUBREG:
+    /* The first operand of a SIGN/ZERO_EXTRACT has a different meaning
+       than it would in other contexts.  Basically its mode does not
+       signify the size of the object read.  That information is carried
+       by size operand.    If we happen to have a MEM of the appropriate
+       mode in our tables with a constant value we could simplify the
+       extraction incorrectly if we allowed substitution of that value
+       for the MEM.   */
+    case ZERO_EXTRACT:
+    case SIGN_EXTRACT:
       if ((new_rtx = equiv_constant (x)) != NULL_RTX)
         return new_rtx;
       return x;
@@ -3137,11 +3159,6 @@ fold_rtx (rtx x, rtx insn)
     case EXPR_LIST:
       return x;
 
-#ifdef HAVE_cc0
-    case CC0:
-      return prev_insn_cc0;
-#endif
-
     case ASM_OPERANDS:
       if (insn)
        {
@@ -3151,12 +3168,23 @@ fold_rtx (rtx x, rtx insn)
        }
       return x;
 
-#ifdef NO_FUNCTION_CSE
     case CALL:
-      if (CONSTANT_P (XEXP (XEXP (x, 0), 0)))
+      if (NO_FUNCTION_CSE && CONSTANT_P (XEXP (XEXP (x, 0), 0)))
        return x;
       break;
-#endif
+    case VEC_SELECT:
+      {
+       rtx trueop0 = XEXP (x, 0);
+       mode = GET_MODE (trueop0);
+       rtx trueop1 = XEXP (x, 1);
+       /* If we select a low-part subreg, return that.  */
+       if (vec_series_lowpart_p (GET_MODE (x), mode, trueop1))
+         {
+           rtx new_rtx = lowpart_subreg (GET_MODE (x), trueop0, mode);
+           if (new_rtx != NULL_RTX)
+             return new_rtx;
+         }
+      }
 
     /* Anything else goes through the loop below.  */
     default:
@@ -3177,7 +3205,7 @@ fold_rtx (rtx x, rtx insn)
     if (fmt[i] == 'e')
       {
        rtx folded_arg = XEXP (x, i), const_arg;
-       enum machine_mode mode_arg = GET_MODE (folded_arg);
+       machine_mode mode_arg = GET_MODE (folded_arg);
 
        switch (GET_CODE (folded_arg))
          {
@@ -3194,14 +3222,6 @@ fold_rtx (rtx x, rtx insn)
            const_arg = folded_arg;
            break;
 
-#ifdef HAVE_cc0
-         case CC0:
-           folded_arg = prev_insn_cc0;
-           mode_arg = prev_insn_cc0_mode;
-           const_arg = equiv_constant (folded_arg);
-           break;
-#endif
-
          default:
            folded_arg = fold_rtx (folded_arg, insn);
            const_arg = equiv_constant (folded_arg);
@@ -3230,7 +3250,8 @@ fold_rtx (rtx x, rtx insn)
           argument.  */
        if (const_arg != 0
            && const_arg != folded_arg
-           && COST_IN (const_arg, code, i) <= COST_IN (folded_arg, code, i)
+           && (COST_IN (const_arg, mode_arg, code, i)
+               <= COST_IN (folded_arg, mode_arg, code, i))
 
            /* It's not safe to substitute the operand of a conversion
               operator with a constant, as the conversion's identity
@@ -3264,9 +3285,8 @@ fold_rtx (rtx x, rtx insn)
         consistent with the order in X.  */
       if (canonicalize_change_group (insn, x))
        {
-         rtx tem;
-         tem = const_arg0, const_arg0 = const_arg1, const_arg1 = tem;
-         tem = folded_arg0, folded_arg0 = folded_arg1, folded_arg1 = tem;
+         std::swap (const_arg0, const_arg1);
+         std::swap (folded_arg0, folded_arg1);
        }
 
       apply_change_group ();
@@ -3285,8 +3305,8 @@ fold_rtx (rtx x, rtx insn)
          break;
 
        new_rtx = simplify_unary_operation (code, mode,
-                                       const_arg0 ? const_arg0 : folded_arg0,
-                                       mode_arg0);
+                                           const_arg0 ? const_arg0 : folded_arg0,
+                                           mode_arg0);
       }
       break;
 
@@ -3305,12 +3325,12 @@ fold_rtx (rtx x, rtx insn)
        {
          struct table_elt *p0, *p1;
          rtx true_rtx, false_rtx;
-         enum machine_mode mode_arg1;
+         machine_mode mode_arg1;
 
          if (SCALAR_FLOAT_MODE_P (mode))
            {
 #ifdef FLOAT_STORE_FLAG_VALUE
-             true_rtx = (CONST_DOUBLE_FROM_REAL_VALUE
+             true_rtx = (const_double_from_real_value
                          (FLOAT_STORE_FLAG_VALUE (mode), mode));
 #else
              true_rtx = NULL_RTX;
@@ -3357,7 +3377,7 @@ fold_rtx (rtx x, rtx insn)
                  if (p != NULL)
                    {
                      cheapest_simplification = x;
-                     cheapest_cost = COST (x);
+                     cheapest_cost = COST (x, mode);
 
                      for (p = p->first_same_value; p != NULL; p = p->next_same_value)
                        {
@@ -3377,7 +3397,7 @@ fold_rtx (rtx x, rtx insn)
                          if (simp_result == NULL)
                            continue;
 
-                         cost = COST (simp_result);
+                         cost = COST (simp_result, mode);
                          if (cost < cheapest_cost)
                            {
                              cheapest_cost = cost;
@@ -3484,7 +3504,7 @@ fold_rtx (rtx x, rtx insn)
                : lookup_as_function (folded_arg0, MINUS);
 
              if (y != 0 && GET_CODE (XEXP (y, 1)) == LABEL_REF
-                 && XEXP (XEXP (y, 1), 0) == XEXP (const_arg1, 0))
+                 && label_ref_label (XEXP (y, 1)) == label_ref_label (const_arg1))
                return XEXP (y, 0);
 
              /* Now try for a CONST of a MINUS like the above.  */
@@ -3492,7 +3512,7 @@ fold_rtx (rtx x, rtx insn)
                        : lookup_as_function (folded_arg0, CONST))) != 0
                  && GET_CODE (XEXP (y, 0)) == MINUS
                  && GET_CODE (XEXP (XEXP (y, 0), 1)) == LABEL_REF
-                 && XEXP (XEXP (XEXP (y, 0), 1), 0) == XEXP (const_arg1, 0))
+                 && label_ref_label (XEXP (XEXP (y, 0), 1)) == label_ref_label (const_arg1))
                return XEXP (XEXP (y, 0), 0);
            }
 
@@ -3504,7 +3524,7 @@ fold_rtx (rtx x, rtx insn)
                : lookup_as_function (folded_arg1, MINUS);
 
              if (y != 0 && GET_CODE (XEXP (y, 1)) == LABEL_REF
-                 && XEXP (XEXP (y, 1), 0) == XEXP (const_arg0, 0))
+                 && label_ref_label (XEXP (y, 1)) == label_ref_label (const_arg0))
                return XEXP (y, 0);
 
              /* Now try for a CONST of a MINUS like the above.  */
@@ -3512,7 +3532,7 @@ fold_rtx (rtx x, rtx insn)
                        : lookup_as_function (folded_arg1, CONST))) != 0
                  && GET_CODE (XEXP (y, 0)) == MINUS
                  && GET_CODE (XEXP (XEXP (y, 0), 1)) == LABEL_REF
-                 && XEXP (XEXP (XEXP (y, 0), 1), 0) == XEXP (const_arg0, 0))
+                 && label_ref_label (XEXP (XEXP (y, 0), 1)) == label_ref_label (const_arg0))
                return XEXP (XEXP (y, 0), 0);
            }
 
@@ -3536,7 +3556,7 @@ fold_rtx (rtx x, rtx insn)
                 instead we test for the problematic value in a more direct
                 manner and hope the Sun compilers get it correct.  */
              && INTVAL (const_arg1) !=
-               ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1))
+               (HOST_WIDE_INT_1 << (HOST_BITS_PER_WIDE_INT - 1))
              && REG_P (folded_arg1))
            {
              rtx new_const = GEN_INT (-INTVAL (const_arg1));
@@ -3547,20 +3567,19 @@ fold_rtx (rtx x, rtx insn)
                for (p = p->first_same_value; p; p = p->next_same_value)
                  if (REG_P (p->exp))
                    return simplify_gen_binary (MINUS, mode, folded_arg0,
-                                               canon_reg (p->exp, NULL_RTX));
+                                               canon_reg (p->exp, NULL));
            }
          goto from_plus;
 
        case MINUS:
          /* If we have (MINUS Y C), see if Y is known to be (PLUS Z C2).
             If so, produce (PLUS Z C2-C).  */
-         if (const_arg1 != 0 && CONST_INT_P (const_arg1))
+         if (const_arg1 != 0 && poly_int_rtx_p (const_arg1, &xval))
            {
              rtx y = lookup_as_function (XEXP (x, 0), PLUS);
-             if (y && CONST_INT_P (XEXP (y, 1)))
-               return fold_rtx (plus_constant (mode, copy_rtx (y),
-                                               -INTVAL (const_arg1)),
-                                NULL_RTX);
+             if (y && poly_int_rtx_p (XEXP (y, 1)))
+               return fold_rtx (plus_constant (mode, copy_rtx (y), -xval),
+                                NULL);
            }
 
          /* Fall through.  */
@@ -3587,13 +3606,13 @@ fold_rtx (rtx x, rtx insn)
              enum rtx_code associate_code;
 
              if (is_shift
-                 && (INTVAL (const_arg1) >= GET_MODE_PRECISION (mode)
+                 && (INTVAL (const_arg1) >= GET_MODE_UNIT_PRECISION (mode)
                      || INTVAL (const_arg1) < 0))
                {
                  if (SHIFT_COUNT_TRUNCATED)
-                   canon_const_arg1 = GEN_INT (INTVAL (const_arg1)
-                                               & (GET_MODE_BITSIZE (mode)
-                                                  - 1));
+                   canon_const_arg1 = gen_int_shift_amount
+                     (mode, (INTVAL (const_arg1)
+                             & (GET_MODE_UNIT_BITSIZE (mode) - 1)));
                  else
                    break;
                }
@@ -3621,13 +3640,13 @@ fold_rtx (rtx x, rtx insn)
 
              if (code == PLUS && const_arg1 == inner_const
                  && ((HAVE_PRE_INCREMENT
-                         && exact_log2 (INTVAL (const_arg1)) >= 0)
+                         && pow2p_hwi (INTVAL (const_arg1)))
                      || (HAVE_POST_INCREMENT
-                         && exact_log2 (INTVAL (const_arg1)) >= 0)
+                         && pow2p_hwi (INTVAL (const_arg1)))
                      || (HAVE_PRE_DECREMENT
-                         && exact_log2 (- INTVAL (const_arg1)) >= 0)
+                         && pow2p_hwi (- INTVAL (const_arg1)))
                      || (HAVE_POST_DECREMENT
-                         && exact_log2 (- INTVAL (const_arg1)) >= 0)))
+                         && pow2p_hwi (- INTVAL (const_arg1)))))
                break;
 
              /* ??? Vector mode shifts by scalar
@@ -3636,12 +3655,13 @@ fold_rtx (rtx x, rtx insn)
                 break;
 
              if (is_shift
-                 && (INTVAL (inner_const) >= GET_MODE_PRECISION (mode)
+                 && (INTVAL (inner_const) >= GET_MODE_UNIT_PRECISION (mode)
                      || INTVAL (inner_const) < 0))
                {
                  if (SHIFT_COUNT_TRUNCATED)
-                   inner_const = GEN_INT (INTVAL (inner_const)
-                                          & (GET_MODE_BITSIZE (mode) - 1));
+                   inner_const = gen_int_shift_amount
+                     (mode, (INTVAL (inner_const)
+                             & (GET_MODE_UNIT_BITSIZE (mode) - 1)));
                  else
                    break;
                }
@@ -3666,12 +3686,13 @@ fold_rtx (rtx x, rtx insn)
 
              if (is_shift
                  && CONST_INT_P (new_const)
-                 && INTVAL (new_const) >= GET_MODE_PRECISION (mode))
+                 && INTVAL (new_const) >= GET_MODE_UNIT_PRECISION (mode))
                {
                  /* As an exception, we can turn an ASHIFTRT of this
                     form into a shift of the number of bits - 1.  */
                  if (code == ASHIFTRT)
-                   new_const = GEN_INT (GET_MODE_BITSIZE (mode) - 1);
+                   new_const = gen_int_shift_amount
+                     (mode, GET_MODE_UNIT_BITSIZE (mode) - 1);
                  else if (!side_effects_p (XEXP (y, 0)))
                    return CONST0_RTX (mode);
                  else
@@ -3752,23 +3773,27 @@ equiv_constant (rtx x)
 
   if (GET_CODE (x) == SUBREG)
     {
-      enum machine_mode mode = GET_MODE (x);
-      enum machine_mode imode = GET_MODE (SUBREG_REG (x));
+      machine_mode mode = GET_MODE (x);
+      machine_mode imode = GET_MODE (SUBREG_REG (x));
       rtx new_rtx;
 
       /* See if we previously assigned a constant value to this SUBREG.  */
       if ((new_rtx = lookup_as_function (x, CONST_INT)) != 0
+         || (new_rtx = lookup_as_function (x, CONST_WIDE_INT)) != 0
+         || (NUM_POLY_INT_COEFFS > 1
+             && (new_rtx = lookup_as_function (x, CONST_POLY_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))
+      if (known_lt (GET_MODE_SIZE (mode), UNITS_PER_WORD)
+         && known_lt (UNITS_PER_WORD, GET_MODE_SIZE (imode)))
        {
-         int byte = SUBREG_BYTE (x) - subreg_lowpart_offset (mode, word_mode);
-         if (byte >= 0 && (byte % UNITS_PER_WORD) == 0)
+         poly_int64 byte = (SUBREG_BYTE (x)
+                            - subreg_lowpart_offset (mode, word_mode));
+         if (known_ge (byte, 0) && multiple_p (byte, UNITS_PER_WORD))
            {
              rtx y = gen_rtx_SUBREG (word_mode, SUBREG_REG (x), byte);
              new_rtx = lookup_as_function (y, CONST_INT);
@@ -3782,7 +3807,7 @@ equiv_constant (rtx x)
         the subreg.  Note that the upper bits of paradoxical subregs
         are undefined, so they cannot be said to equal anything.  */
       if (REG_P (SUBREG_REG (x))
-         && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (imode)
+         && !paradoxical_subreg_p (x)
          && (new_rtx = equiv_constant (SUBREG_REG (x))) != 0)
         return simplify_subreg (mode, new_rtx, imode, SUBREG_BYTE (x));
 
@@ -3824,12 +3849,12 @@ equiv_constant (rtx x)
    comparison is seen later, we will know its value.  */
 
 static void
-record_jump_equiv (rtx insn, bool taken)
+record_jump_equiv (rtx_insn *insn, bool taken)
 {
   int cond_known_true;
   rtx op0, op1;
   rtx set;
-  enum machine_mode mode, mode0, mode1;
+  machine_mode mode, mode0, mode1;
   int reversed_nonequality = 0;
   enum rtx_code code;
 
@@ -3851,6 +3876,10 @@ record_jump_equiv (rtx insn, bool taken)
   op0 = fold_rtx (XEXP (XEXP (SET_SRC (set), 0), 0), insn);
   op1 = fold_rtx (XEXP (XEXP (SET_SRC (set), 0), 1), insn);
 
+  /* If fold_rtx returns NULL_RTX, there's nothing to record.  */
+  if (op0 == NULL_RTX || op1 == NULL_RTX)
+    return;
+
   code = find_comparison_args (code, &op0, &op1, &mode0, &mode1);
   if (! cond_known_true)
     {
@@ -3873,9 +3902,9 @@ record_jump_equiv (rtx insn, bool taken)
    MODE, and we should assume OP has MODE iff it is naturally modeless.  */
 
 static rtx
-record_jump_cond_subreg (enum machine_mode mode, rtx op)
+record_jump_cond_subreg (machine_mode mode, rtx op)
 {
-  enum machine_mode op_mode = GET_MODE (op);
+  machine_mode op_mode = GET_MODE (op);
   if (op_mode == mode || op_mode == VOIDmode)
     return op;
   return lowpart_subreg (mode, op, op_mode);
@@ -3887,7 +3916,7 @@ record_jump_cond_subreg (enum machine_mode mode, rtx op)
    above function and called recursively.  */
 
 static void
-record_jump_cond (enum rtx_code code, enum machine_mode mode, rtx op0,
+record_jump_cond (enum rtx_code code, machine_mode mode, rtx op0,
                  rtx op1, int reversed_nonequality)
 {
   unsigned op0_hash, op1_hash;
@@ -3902,7 +3931,7 @@ record_jump_cond (enum rtx_code code, enum machine_mode mode, rtx op0,
   /* Note that GET_MODE (op0) may not equal MODE.  */
   if (code == EQ && paradoxical_subreg_p (op0))
     {
-      enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op0));
+      machine_mode inner_mode = GET_MODE (SUBREG_REG (op0));
       rtx tem = record_jump_cond_subreg (inner_mode, op1);
       if (tem)
        record_jump_cond (code, mode, SUBREG_REG (op0), tem,
@@ -3911,7 +3940,7 @@ record_jump_cond (enum rtx_code code, enum machine_mode mode, rtx op0,
 
   if (code == EQ && paradoxical_subreg_p (op1))
     {
-      enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op1));
+      machine_mode inner_mode = GET_MODE (SUBREG_REG (op1));
       rtx tem = record_jump_cond_subreg (inner_mode, op0);
       if (tem)
        record_jump_cond (code, mode, SUBREG_REG (op1), tem,
@@ -3925,24 +3954,22 @@ record_jump_cond (enum rtx_code code, enum machine_mode mode, rtx op0,
      if we test MODE instead, we can get an infinite recursion
      alternating between two modes each wider than MODE.  */
 
-  if (code == NE && GET_CODE (op0) == SUBREG
-      && subreg_lowpart_p (op0)
-      && (GET_MODE_SIZE (GET_MODE (op0))
-         < GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0)))))
+  if (code == NE
+      && partial_subreg_p (op0)
+      && subreg_lowpart_p (op0))
     {
-      enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op0));
+      machine_mode inner_mode = GET_MODE (SUBREG_REG (op0));
       rtx tem = record_jump_cond_subreg (inner_mode, op1);
       if (tem)
        record_jump_cond (code, mode, SUBREG_REG (op0), tem,
                          reversed_nonequality);
     }
 
-  if (code == NE && GET_CODE (op1) == SUBREG
-      && subreg_lowpart_p (op1)
-      && (GET_MODE_SIZE (GET_MODE (op1))
-         < GET_MODE_SIZE (GET_MODE (SUBREG_REG (op1)))))
+  if (code == NE
+      && partial_subreg_p (op1)
+      && subreg_lowpart_p (op1))
     {
-      enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op1));
+      machine_mode inner_mode = GET_MODE (SUBREG_REG (op1));
       rtx tem = record_jump_cond_subreg (inner_mode, op0);
       if (tem)
        record_jump_cond (code, mode, SUBREG_REG (op1), tem,
@@ -4127,10 +4154,10 @@ struct set
      The size of this field should match the size of the mode
      field of struct rtx_def (see rtl.h).  */
   ENUM_BITFIELD(machine_mode) mode : 8;
-  /* A constant equivalent for SET_SRC, if any.  */
-  rtx src_const;
   /* Hash value of constant equivalent for SET_SRC.  */
   unsigned src_const_hash;
+  /* A constant equivalent for SET_SRC, if any.  */
+  rtx src_const;
   /* Table entry for constant equivalent for SET_SRC, if any.  */
   struct table_elt *src_const_elt;
   /* Table entry for the destination address.  */
@@ -4151,7 +4178,7 @@ struct set
    This is the last transformation that cse_insn will try to do.  */
 
 static void
-try_back_substitute_reg (rtx set, rtx insn)
+try_back_substitute_reg (rtx set, rtx_insn *insn)
 {
   rtx dest = SET_DEST (set);
   rtx src = SET_SRC (set);
@@ -4167,8 +4194,8 @@ try_back_substitute_reg (rtx set, rtx insn)
        {
          /* Scan for the previous nonnote insn, but stop at a basic
             block boundary.  */
-         rtx prev = insn;
-         rtx bb_head = BB_HEAD (BLOCK_FOR_INSN (insn));
+         rtx_insn *prev = insn;
+         rtx_insn *bb_head = BB_HEAD (BLOCK_FOR_INSN (insn));
          do
            {
              prev = PREV_INSN (prev);
@@ -4207,6 +4234,15 @@ try_back_substitute_reg (rtx set, rtx insn)
                  && (reg_mentioned_p (dest, XEXP (note, 0))
                      || rtx_equal_p (src, XEXP (note, 0))))
                remove_note (insn, note);
+
+             /* If INSN has a REG_ARGS_SIZE note, move it to PREV.  */
+             note = find_reg_note (insn, REG_ARGS_SIZE, NULL_RTX);
+             if (note != 0)
+               {
+                 remove_note (insn, note);
+                 gcc_assert (!find_reg_note (prev, REG_ARGS_SIZE, NULL_RTX));
+                 set_unique_reg_note (prev, REG_ARGS_SIZE, XEXP (note, 0));
+               }
            }
        }
     }
@@ -4215,7 +4251,7 @@ try_back_substitute_reg (rtx set, rtx insn)
 /* Record all the SETs in this instruction into SETS_PTR,
    and return the number of recorded sets.  */
 static int
-find_sets_in_insn (rtx insn, struct set **psets)
+find_sets_in_insn (rtx_insn *insn, struct set **psets)
 {
   struct set *sets = *psets;
   int n_sets = 0;
@@ -4245,7 +4281,7 @@ find_sets_in_insn (rtx insn, struct set **psets)
     {
       int i, lim = XVECLEN (x, 0);
 
-      /* Go over the epressions of the PARALLEL in forward order, to
+      /* Go over the expressions of the PARALLEL in forward order, to
         put them in the same order in the SETS array.  */
       for (i = 0; i < lim; i++)
        {
@@ -4268,8 +4304,24 @@ find_sets_in_insn (rtx insn, struct set **psets)
   return n_sets;
 }
 \f
+/* Subroutine of canonicalize_insn.  X is an ASM_OPERANDS in INSN.  */
+
+static void
+canon_asm_operands (rtx x, rtx_insn *insn)
+{
+  for (int i = ASM_OPERANDS_INPUT_LENGTH (x) - 1; i >= 0; i--)
+    {
+      rtx input = ASM_OPERANDS_INPUT (x, i);
+      if (!(REG_P (input) && HARD_REGISTER_P (input)))
+       {
+         input = canon_reg (input, insn);
+         validate_change (insn, &ASM_OPERANDS_INPUT (x, i), input, 1);
+       }
+    }
+}
+
 /* Where possible, substitute every register reference in the N_SETS
-   number of SETS in INSN with the the canonical register.
+   number of SETS in INSN with the canonical register.
 
    Register canonicalization propagatest the earliest register (i.e.
    one that is set before INSN) with the same value.  This is a very
@@ -4297,7 +4349,7 @@ find_sets_in_insn (rtx insn, struct set **psets)
    see canon_reg.  */
 
 static void
-canonicalize_insn (rtx insn, struct set **psets, int n_sets)
+canonicalize_insn (rtx_insn *insn, struct set **psets, int n_sets)
 {
   struct set *sets = *psets;
   rtx tem;
@@ -4331,17 +4383,7 @@ canonicalize_insn (rtx insn, struct set **psets, int n_sets)
     /* Canonicalize a USE of a pseudo register or memory location.  */
     canon_reg (x, insn);
   else if (GET_CODE (x) == ASM_OPERANDS)
-    {
-      for (i = ASM_OPERANDS_INPUT_LENGTH (x) - 1; i >= 0; i--)
-       {
-         rtx input = ASM_OPERANDS_INPUT (x, i);
-         if (!(REG_P (input) && REGNO (input) < FIRST_PSEUDO_REGISTER))
-           {
-             input = canon_reg (input, insn);
-             validate_change (insn, &ASM_OPERANDS_INPUT (x, i), input, 1);
-           }
-       }
-    }
+    canon_asm_operands (x, insn);
   else if (GET_CODE (x) == CALL)
     {
       canon_reg (x, insn);
@@ -4370,6 +4412,8 @@ canonicalize_insn (rtx insn, struct set **psets, int n_sets)
                   && ! (REG_P (XEXP (y, 0))
                         && REGNO (XEXP (y, 0)) < FIRST_PSEUDO_REGISTER))
            canon_reg (y, insn);
+         else if (GET_CODE (y) == ASM_OPERANDS)
+           canon_asm_operands (y, insn);
          else if (GET_CODE (y) == CALL)
            {
              canon_reg (y, insn);
@@ -4453,7 +4497,7 @@ canonicalize_insn (rtx insn, struct set **psets, int n_sets)
    of available values.  */
 
 static void
-cse_insn (rtx insn)
+cse_insn (rtx_insn *insn)
 {
   rtx x = PATTERN (insn);
   int i;
@@ -4474,11 +4518,6 @@ cse_insn (rtx insn)
     sets = XALLOCAVEC (struct set, XVECLEN (x, 0));
 
   this_insn = insn;
-#ifdef HAVE_cc0
-  /* Records what this insn does to set CC0.  */
-  this_insn_cc0 = 0;
-  this_insn_cc0_mode = VOIDmode;
-#endif
 
   /* Find all regs explicitly clobbered in this insn,
      to ensure they are not replaced with any other regs
@@ -4492,14 +4531,53 @@ cse_insn (rtx insn)
   canonicalize_insn (insn, &sets, n_sets);
 
   /* If this insn has a REG_EQUAL note, store the equivalent value in SRC_EQV,
-     if different, or if the DEST is a STRICT_LOW_PART.  The latter condition
-     is necessary because SRC_EQV is handled specially for this case, and if
-     it isn't set, then there will be no equivalence for the destination.  */
+     if different, or if the DEST is a STRICT_LOW_PART/ZERO_EXTRACT.  The
+     latter condition is necessary because SRC_EQV is handled specially for
+     this case, and if it isn't set, then there will be no equivalence
+     for the destination.  */
   if (n_sets == 1 && REG_NOTES (insn) != 0
-      && (tem = find_reg_note (insn, REG_EQUAL, NULL_RTX)) != 0
-      && (! rtx_equal_p (XEXP (tem, 0), SET_SRC (sets[0].rtl))
-         || GET_CODE (SET_DEST (sets[0].rtl)) == STRICT_LOW_PART))
-    src_eqv = copy_rtx (XEXP (tem, 0));
+      && (tem = find_reg_note (insn, REG_EQUAL, NULL_RTX)) != 0)
+    {
+
+      if (GET_CODE (SET_DEST (sets[0].rtl)) != ZERO_EXTRACT
+         && (! rtx_equal_p (XEXP (tem, 0), SET_SRC (sets[0].rtl))
+             || GET_CODE (SET_DEST (sets[0].rtl)) == STRICT_LOW_PART))
+       src_eqv = copy_rtx (XEXP (tem, 0));
+      /* If DEST is of the form ZERO_EXTACT, as in:
+        (set (zero_extract:SI (reg:SI 119)
+                 (const_int 16 [0x10])
+                 (const_int 16 [0x10]))
+             (const_int 51154 [0xc7d2]))
+        REG_EQUAL note will specify the value of register (reg:SI 119) at this
+        point.  Note that this is different from SRC_EQV. We can however
+        calculate SRC_EQV with the position and width of ZERO_EXTRACT.  */
+      else if (GET_CODE (SET_DEST (sets[0].rtl)) == ZERO_EXTRACT
+              && CONST_INT_P (XEXP (tem, 0))
+              && CONST_INT_P (XEXP (SET_DEST (sets[0].rtl), 1))
+              && CONST_INT_P (XEXP (SET_DEST (sets[0].rtl), 2)))
+       {
+         rtx dest_reg = XEXP (SET_DEST (sets[0].rtl), 0);
+         /* This is the mode of XEXP (tem, 0) as well.  */
+         scalar_int_mode dest_mode
+           = as_a <scalar_int_mode> (GET_MODE (dest_reg));
+         rtx width = XEXP (SET_DEST (sets[0].rtl), 1);
+         rtx pos = XEXP (SET_DEST (sets[0].rtl), 2);
+         HOST_WIDE_INT val = INTVAL (XEXP (tem, 0));
+         HOST_WIDE_INT mask;
+         unsigned int shift;
+         if (BITS_BIG_ENDIAN)
+           shift = (GET_MODE_PRECISION (dest_mode)
+                    - INTVAL (pos) - INTVAL (width));
+         else
+           shift = INTVAL (pos);
+         if (INTVAL (width) == HOST_BITS_PER_WIDE_INT)
+           mask = HOST_WIDE_INT_M1;
+         else
+           mask = (HOST_WIDE_INT_1 << INTVAL (width)) - 1;
+         val = (val >> shift) & mask;
+         src_eqv = GEN_INT (val);
+       }
+    }
 
   /* Set sets[i].src_elt to the class each source belongs to.
      Detect assignments from or to volatile things
@@ -4511,10 +4589,11 @@ cse_insn (rtx insn)
   for (i = 0; i < n_sets; i++)
     {
       bool repeat = false;
+      bool noop_insn = false;
       rtx src, dest;
       rtx src_folded;
       struct table_elt *elt = 0, *p;
-      enum machine_mode mode;
+      machine_mode mode;
       rtx src_eqv_here;
       rtx src_const = 0;
       rtx src_related = 0;
@@ -4533,6 +4612,7 @@ cse_insn (rtx insn)
       /* Set nonzero if we need to call force_const_mem on with the
         contents of src_folded before using it.  */
       int src_folded_force_flag = 0;
+      scalar_int_mode int_mode;
 
       dest = SET_DEST (sets[i].rtl);
       src = SET_SRC (sets[i].rtl);
@@ -4546,7 +4626,7 @@ cse_insn (rtx insn)
 
       if (src_eqv)
        {
-         enum machine_mode eqvmode = mode;
+         machine_mode eqvmode = mode;
          if (GET_CODE (dest) == STRICT_LOW_PART)
            eqvmode = GET_MODE (SUBREG_REG (XEXP (dest, 0)));
          do_not_record = 0;
@@ -4572,7 +4652,7 @@ cse_insn (rtx insn)
 
       /* Simplify and foldable subexpressions in SRC.  Then get the fully-
         simplified result, which may not necessarily be valid.  */
-      src_folded = fold_rtx (src, insn);
+      src_folded = fold_rtx (src, NULL);
 
 #if 0
       /* ??? This caused bad code to be generated for the m68k port with -O2.
@@ -4592,15 +4672,27 @@ cse_insn (rtx insn)
              && INTVAL (width) < HOST_BITS_PER_WIDE_INT
              && (INTVAL (src) & ((HOST_WIDE_INT) (-1) << INTVAL (width))))
            src_folded
-             = GEN_INT (INTVAL (src) & (((HOST_WIDE_INT) 1
+             = GEN_INT (INTVAL (src) & ((HOST_WIDE_INT_1
                                          << INTVAL (width)) - 1));
        }
 #endif
 
       /* Compute SRC's hash code, and also notice if it
         should not be recorded at all.  In that case,
-        prevent any further processing of this assignment.  */
-      do_not_record = 0;
+        prevent any further processing of this assignment.
+
+        We set DO_NOT_RECORD if the destination has a REG_UNUSED note.
+        This avoids getting the source register into the tables, where it
+        may be invalidated later (via REG_QTY), then trigger an ICE upon
+        re-insertion.
+
+        This is only a problem in multi-set insns.  If it were a single
+        set the dead copy would have been removed.  If the RHS were anything
+        but a simple REG, then we won't call insert_regs and thus there's
+        no potential for triggering the ICE.  */
+      do_not_record = (REG_P (dest)
+                      && REG_P (src)
+                      && find_reg_note (insn, REG_UNUSED, dest));
       hash_arg_in_memory = 0;
 
       sets[i].src = src;
@@ -4621,6 +4713,28 @@ cse_insn (rtx insn)
          && REGNO (dest) >= FIRST_PSEUDO_REGISTER)
        sets[i].src_volatile = 1;
 
+      else if (GET_CODE (src) == ASM_OPERANDS
+              && GET_CODE (x) == PARALLEL)
+       {
+         /* Do not record result of a non-volatile inline asm with
+            more than one result.  */
+         if (n_sets > 1)
+           sets[i].src_volatile = 1;
+
+         int j, lim = XVECLEN (x, 0);
+         for (j = 0; j < lim; j++)
+           {
+             rtx y = XVECEXP (x, 0, j);
+             /* And do not record result of a non-volatile inline asm
+                with "memory" clobber.  */
+             if (GET_CODE (y) == CLOBBER && MEM_P (XEXP (y, 0)))
+               {
+                 sets[i].src_volatile = 1;
+                 break;
+               }
+           }
+       }
+
 #if 0
       /* It is no longer clear why we used to do this, but it doesn't
         appear to still be needed.  So let's try without it since this
@@ -4748,17 +4862,16 @@ cse_insn (rtx insn)
         wider mode.  */
 
       if (src_const && src_related == 0 && CONST_INT_P (src_const)
-         && GET_MODE_CLASS (mode) == MODE_INT
-         && GET_MODE_PRECISION (mode) < BITS_PER_WORD)
+         && is_int_mode (mode, &int_mode)
+         && GET_MODE_PRECISION (int_mode) < BITS_PER_WORD)
        {
-         enum machine_mode wider_mode;
-
-         for (wider_mode = GET_MODE_WIDER_MODE (mode);
-              wider_mode != VOIDmode
-              && GET_MODE_PRECISION (wider_mode) <= BITS_PER_WORD
-              && src_related == 0;
-              wider_mode = GET_MODE_WIDER_MODE (wider_mode))
+         opt_scalar_int_mode wider_mode_iter;
+         FOR_EACH_WIDER_MODE (wider_mode_iter, int_mode)
            {
+             scalar_int_mode wider_mode = wider_mode_iter.require ();
+             if (GET_MODE_PRECISION (wider_mode) > BITS_PER_WORD)
+               break;
+
              struct table_elt *const_elt
                = lookup (src_const, HASH (src_const, wider_mode), wider_mode);
 
@@ -4769,9 +4882,12 @@ cse_insn (rtx insn)
                   const_elt; const_elt = const_elt->next_same_value)
                if (REG_P (const_elt->exp))
                  {
-                   src_related = gen_lowpart (mode, const_elt->exp);
+                   src_related = gen_lowpart (int_mode, const_elt->exp);
                    break;
                  }
+
+             if (src_related != 0)
+               break;
            }
        }
 
@@ -4782,16 +4898,19 @@ cse_insn (rtx insn)
         value.  */
 
       if (flag_expensive_optimizations && ! src_related
+         && is_a <scalar_int_mode> (mode, &int_mode)
          && GET_CODE (src) == AND && CONST_INT_P (XEXP (src, 1))
-         && GET_MODE_SIZE (mode) < UNITS_PER_WORD)
+         && GET_MODE_SIZE (int_mode) < UNITS_PER_WORD)
        {
-         enum machine_mode tmode;
+         opt_scalar_int_mode tmode_iter;
          rtx new_and = gen_rtx_AND (VOIDmode, NULL_RTX, XEXP (src, 1));
 
-         for (tmode = GET_MODE_WIDER_MODE (mode);
-              GET_MODE_SIZE (tmode) <= UNITS_PER_WORD;
-              tmode = GET_MODE_WIDER_MODE (tmode))
+         FOR_EACH_WIDER_MODE (tmode_iter, int_mode)
            {
+             scalar_int_mode tmode = tmode_iter.require ();
+             if (GET_MODE_SIZE (tmode) > UNITS_PER_WORD)
+               break;
+
              rtx inner = gen_lowpart (tmode, XEXP (src, 0));
              struct table_elt *larger_elt;
 
@@ -4808,7 +4927,7 @@ cse_insn (rtx insn)
                    if (REG_P (larger_elt->exp))
                      {
                        src_related
-                         = gen_lowpart (mode, larger_elt->exp);
+                         = gen_lowpart (int_mode, larger_elt->exp);
                        break;
                      }
 
@@ -4818,34 +4937,35 @@ cse_insn (rtx insn)
            }
        }
 
-#ifdef LOAD_EXTEND_OP
       /* See if a MEM has already been loaded with a widening operation;
         if it has, we can use a subreg of that.  Many CISC machines
         also have such operations, but this is only likely to be
         beneficial on these machines.  */
 
+      rtx_code extend_op;
       if (flag_expensive_optimizations && src_related == 0
-         && (GET_MODE_SIZE (mode) < UNITS_PER_WORD)
-         && GET_MODE_CLASS (mode) == MODE_INT
          && MEM_P (src) && ! do_not_record
-         && LOAD_EXTEND_OP (mode) != UNKNOWN)
+         && is_a <scalar_int_mode> (mode, &int_mode)
+         && (extend_op = load_extend_op (int_mode)) != UNKNOWN)
        {
          struct rtx_def memory_extend_buf;
          rtx memory_extend_rtx = &memory_extend_buf;
-         enum machine_mode tmode;
 
          /* Set what we are trying to extend and the operation it might
             have been extended with.  */
-         memset (memory_extend_rtx, 0, sizeof(*memory_extend_rtx));
-         PUT_CODE (memory_extend_rtx, LOAD_EXTEND_OP (mode));
+         memset (memory_extend_rtx, 0, sizeof (*memory_extend_rtx));
+         PUT_CODE (memory_extend_rtx, extend_op);
          XEXP (memory_extend_rtx, 0) = src;
 
-         for (tmode = GET_MODE_WIDER_MODE (mode);
-              GET_MODE_SIZE (tmode) <= UNITS_PER_WORD;
-              tmode = GET_MODE_WIDER_MODE (tmode))
+         opt_scalar_int_mode tmode_iter;
+         FOR_EACH_WIDER_MODE (tmode_iter, int_mode)
            {
              struct table_elt *larger_elt;
 
+             scalar_int_mode tmode = tmode_iter.require ();
+             if (GET_MODE_SIZE (tmode) > UNITS_PER_WORD)
+               break;
+
              PUT_MODE (memory_extend_rtx, tmode);
              larger_elt = lookup (memory_extend_rtx,
                                   HASH (memory_extend_rtx, tmode), tmode);
@@ -4856,7 +4976,7 @@ cse_insn (rtx insn)
                   larger_elt; larger_elt = larger_elt->next_same_value)
                if (REG_P (larger_elt->exp))
                  {
-                   src_related = gen_lowpart (mode, larger_elt->exp);
+                   src_related = gen_lowpart (int_mode, larger_elt->exp);
                    break;
                  }
 
@@ -4864,7 +4984,6 @@ cse_insn (rtx insn)
                break;
            }
        }
-#endif /* LOAD_EXTEND_OP */
 
       /* Try to express the constant using a register+offset expression
         derived from a constant anchor.  */
@@ -4911,8 +5030,8 @@ cse_insn (rtx insn)
              && ! (src != 0
                    && GET_CODE (src) == SUBREG
                    && GET_MODE (src) == GET_MODE (p->exp)
-                   && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (src)))
-                       < GET_MODE_SIZE (GET_MODE (SUBREG_REG (p->exp))))))
+                   && partial_subreg_p (GET_MODE (SUBREG_REG (src)),
+                                        GET_MODE (SUBREG_REG (p->exp)))))
            continue;
 
          if (src && GET_CODE (src) == code && rtx_equal_p (src, p->exp))
@@ -4931,7 +5050,7 @@ cse_insn (rtx insn)
             to prefer it.  Copy it to src_related.  The code below will
             then give it a negative cost.  */
          if (GET_CODE (dest) == code && rtx_equal_p (p->exp, dest))
-           src_related = dest;
+           src_related = p->exp;
        }
 
       /* Find the cheapest valid equivalent, trying all the available
@@ -4946,7 +5065,7 @@ cse_insn (rtx insn)
            src_cost = src_regcost = -1;
          else
            {
-             src_cost = COST (src);
+             src_cost = COST (src, mode);
              src_regcost = approx_reg_cost (src);
            }
        }
@@ -4957,7 +5076,7 @@ cse_insn (rtx insn)
            src_eqv_cost = src_eqv_regcost = -1;
          else
            {
-             src_eqv_cost = COST (src_eqv_here);
+             src_eqv_cost = COST (src_eqv_here, mode);
              src_eqv_regcost = approx_reg_cost (src_eqv_here);
            }
        }
@@ -4968,7 +5087,7 @@ cse_insn (rtx insn)
            src_folded_cost = src_folded_regcost = -1;
          else
            {
-             src_folded_cost = COST (src_folded);
+             src_folded_cost = COST (src_folded, mode);
              src_folded_regcost = approx_reg_cost (src_folded);
            }
        }
@@ -4979,7 +5098,7 @@ cse_insn (rtx insn)
            src_related_cost = src_related_regcost = -1;
          else
            {
-             src_related_cost = COST (src_related);
+             src_related_cost = COST (src_related, mode);
              src_related_regcost = approx_reg_cost (src_related);
 
              /* If a const-anchor is used to synthesize a constant that
@@ -5022,8 +5141,8 @@ cse_insn (rtx insn)
              && ! (src != 0
                    && GET_CODE (src) == SUBREG
                    && GET_MODE (src) == GET_MODE (elt->exp)
-                   && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (src)))
-                       < GET_MODE_SIZE (GET_MODE (SUBREG_REG (elt->exp))))))
+                   && partial_subreg_p (GET_MODE (SUBREG_REG (src)),
+                                        GET_MODE (SUBREG_REG (elt->exp)))))
            {
              elt = elt->next_same_value;
              continue;
@@ -5081,23 +5200,6 @@ cse_insn (rtx insn)
              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, false))
-               break;
-           }
-
          /* Try to optimize
             (set (reg:M N) (const_int A))
             (set (reg:M2 O) (const_int B))
@@ -5108,8 +5210,9 @@ cse_insn (rtx insn)
              && CONST_INT_P (XEXP (SET_DEST (sets[i].rtl), 1))
              && CONST_INT_P (XEXP (SET_DEST (sets[i].rtl), 2))
              && REG_P (XEXP (SET_DEST (sets[i].rtl), 0))
-             && (GET_MODE_PRECISION (GET_MODE (SET_DEST (sets[i].rtl)))
-                 >= INTVAL (XEXP (SET_DEST (sets[i].rtl), 1)))
+             && (known_ge
+                 (GET_MODE_PRECISION (GET_MODE (SET_DEST (sets[i].rtl))),
+                  INTVAL (XEXP (SET_DEST (sets[i].rtl), 1))))
              && ((unsigned) INTVAL (XEXP (SET_DEST (sets[i].rtl), 1))
                  + (unsigned) INTVAL (XEXP (SET_DEST (sets[i].rtl), 2))
                  <= HOST_BITS_PER_WIDE_INT))
@@ -5134,18 +5237,21 @@ cse_insn (rtx insn)
                  HOST_WIDE_INT val = INTVAL (dest_cst);
                  HOST_WIDE_INT mask;
                  unsigned int shift;
+                 /* This is the mode of DEST_CST as well.  */
+                 scalar_int_mode dest_mode
+                   = as_a <scalar_int_mode> (GET_MODE (dest_reg));
                  if (BITS_BIG_ENDIAN)
-                   shift = GET_MODE_PRECISION (GET_MODE (dest_reg))
+                   shift = GET_MODE_PRECISION (dest_mode)
                            - INTVAL (pos) - INTVAL (width);
                  else
                    shift = INTVAL (pos);
                  if (INTVAL (width) == HOST_BITS_PER_WIDE_INT)
-                   mask = ~(HOST_WIDE_INT) 0;
+                   mask = HOST_WIDE_INT_M1;
                  else
-                   mask = ((HOST_WIDE_INT) 1 << INTVAL (width)) - 1;
+                   mask = (HOST_WIDE_INT_1 << INTVAL (width)) - 1;
                  val &= ~(mask << shift);
                  val |= (INTVAL (trial) & mask) << shift;
-                 val = trunc_int_for_mode (val, GET_MODE (dest_reg));
+                 val = trunc_int_for_mode (val, dest_mode);
                  validate_unshare_change (insn, &SET_DEST (sets[i].rtl),
                                           dest_reg, 1);
                  validate_unshare_change (insn, &SET_SRC (sets[i].rtl),
@@ -5193,6 +5299,31 @@ cse_insn (rtx insn)
              break;
            }
 
+         /* Similarly, lots of targets don't allow no-op
+            (set (mem x) (mem x)) moves.  Even (set (reg x) (reg x))
+            might be impossible for certain registers (like CC registers).  */
+         else if (n_sets == 1
+                  && !CALL_P (insn)
+                  && (MEM_P (trial) || REG_P (trial))
+                  && rtx_equal_p (trial, dest)
+                  && !side_effects_p (dest)
+                  && (cfun->can_delete_dead_exceptions
+                      || insn_nothrow_p (insn))
+                  /* We can only remove the later store if the earlier aliases
+                     at least all accesses the later one.  */
+                  && (!MEM_P (trial)
+                      || ((MEM_ALIAS_SET (dest) == MEM_ALIAS_SET (trial)
+                           || alias_set_subset_of (MEM_ALIAS_SET (dest),
+                                                   MEM_ALIAS_SET (trial)))
+                           && (!MEM_EXPR (trial)
+                               || refs_same_for_tbaa_p (MEM_EXPR (trial),
+                                                        MEM_EXPR (dest))))))
+           {
+             SET_SRC (sets[i].rtl) = trial;
+             noop_insn = true;
+             break;
+           }
+
          /* Reject certain invalid forms of CONST that we create.  */
          else if (CONSTANT_P (trial)
                   && GET_CODE (trial) == CONST
@@ -5209,9 +5340,15 @@ cse_insn (rtx insn)
            /* Do nothing for this case.  */
            ;
 
+         /* Do not replace anything with a MEM, except the replacement
+            is a no-op.  This allows this loop to terminate.  */
+         else if (MEM_P (trial) && !rtx_equal_p (trial, SET_SRC(sets[i].rtl)))
+           /* Do nothing for this case.  */
+           ;
+
          /* Look for a substitution that makes a valid insn.  */
-         else if (validate_unshare_change
-                    (insn, &SET_SRC (sets[i].rtl), trial, 0))
+         else if (validate_unshare_change (insn, &SET_SRC (sets[i].rtl),
+                                           trial, 0))
            {
              rtx new_rtx = canon_reg (SET_SRC (sets[i].rtl), insn);
 
@@ -5292,7 +5429,7 @@ cse_insn (rtx insn)
                  /* If we had a constant that is cheaper than what we are now
                     setting SRC to, use that constant.  We ignored it when we
                     thought we could make this into a no-op.  */
-                 if (src_const && COST (src_const) < COST (src)
+                 if (src_const && COST (src_const, mode) < COST (src, mode)
                      && validate_change (insn, &SET_SRC (sets[i].rtl),
                                          src_const, 0))
                    src = src_const;
@@ -5313,33 +5450,33 @@ cse_insn (rtx insn)
        }
 
       /* If this is a single SET, we are setting a register, and we have an
-        equivalent constant, we want to add a REG_NOTE.   We don't want
-        to write a REG_EQUAL note for a constant pseudo since verifying that
-        that pseudo hasn't been eliminated is a pain.  Such a note also
-        won't help anything.
+        equivalent constant, we want to add a REG_EQUAL note if the constant
+        is different from the source.  We don't want to do it for a constant
+        pseudo since verifying that this pseudo hasn't been eliminated is a
+        pain; moreover such a note won't help anything.
 
         Avoid a REG_EQUAL note for (CONST (MINUS (LABEL_REF) (LABEL_REF)))
         which can be created for a reference to a compile time computable
         entry in a jump table.  */
-
-      if (n_sets == 1 && src_const && REG_P (dest)
+      if (n_sets == 1
+         && REG_P (dest)
+         && src_const
          && !REG_P (src_const)
-         && ! (GET_CODE (src_const) == CONST
-               && GET_CODE (XEXP (src_const, 0)) == MINUS
-               && GET_CODE (XEXP (XEXP (src_const, 0), 0)) == LABEL_REF
-               && GET_CODE (XEXP (XEXP (src_const, 0), 1)) == LABEL_REF))
+         && !(GET_CODE (src_const) == SUBREG
+              && REG_P (SUBREG_REG (src_const)))
+         && !(GET_CODE (src_const) == CONST
+              && GET_CODE (XEXP (src_const, 0)) == MINUS
+              && GET_CODE (XEXP (XEXP (src_const, 0), 0)) == LABEL_REF
+              && GET_CODE (XEXP (XEXP (src_const, 0), 1)) == LABEL_REF)
+         && !rtx_equal_p (src, src_const))
        {
-         /* We only want a REG_EQUAL note if src_const != src.  */
-         if (! rtx_equal_p (src, src_const))
-           {
-             /* Make sure that the rtx is not shared.  */
-             src_const = copy_rtx (src_const);
+         /* Make sure that the rtx is not shared.  */
+         src_const = copy_rtx (src_const);
 
-             /* 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);
-           }
+         /* 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);
        }
 
       /* Now deal with the destination.  */
@@ -5383,7 +5520,7 @@ cse_insn (rtx insn)
              && CONST_INT_P (width)
              && INTVAL (width) < HOST_BITS_PER_WIDE_INT
              && ! (INTVAL (src_const)
-                   & ((HOST_WIDE_INT) (-1) << INTVAL (width))))
+                   & (HOST_WIDE_INT_M1U << INTVAL (width))))
            /* Exception: if the value is constant,
               and it won't be truncated, record it.  */
            ;
@@ -5405,12 +5542,22 @@ cse_insn (rtx insn)
       else if (n_sets == 1 && dest == pc_rtx && src == pc_rtx)
        {
          /* One less use of the label this insn used to jump to.  */
-         delete_insn_and_edges (insn);
+         cse_cfg_altered |= delete_insn_and_edges (insn);
          cse_jumps_altered = true;
          /* No more processing for this set.  */
          sets[i].rtl = 0;
        }
 
+      /* Similarly for no-op moves.  */
+      else if (noop_insn)
+       {
+         if (cfun->can_throw_non_call_exceptions && can_throw_internal (insn))
+           cse_cfg_altered = true;
+         cse_cfg_altered |= delete_insn_and_edges (insn);
+         /* No more processing for this set.  */
+         sets[i].rtl = 0;
+       }
+
       /* If this SET is now setting PC to a label, we know it used to
         be a conditional or computed branch.  */
       else if (dest == pc_rtx && GET_CODE (src) == LABEL_REF
@@ -5425,9 +5572,11 @@ cse_insn (rtx insn)
             and hope for the best.  */
          if (n_sets == 1)
            {
-             rtx new_rtx, note;
+             rtx_jump_insn *new_rtx;
+             rtx note;
 
-             new_rtx = emit_jump_insn_before (gen_jump (XEXP (src, 0)), insn);
+             rtx_insn *seq = targetm.gen_jump (XEXP (src, 0));
+             new_rtx = emit_jump_insn_before (seq, insn);
              JUMP_LABEL (new_rtx) = XEXP (src, 0);
              LABEL_NUSES (XEXP (src, 0))++;
 
@@ -5439,7 +5588,7 @@ cse_insn (rtx insn)
                  REG_NOTES (new_rtx) = note;
                }
 
-             delete_insn_and_edges (insn);
+             cse_cfg_altered |= delete_insn_and_edges (insn);
              insn = new_rtx;
            }
          else
@@ -5455,35 +5604,20 @@ cse_insn (rtx insn)
 
       else if (do_not_record)
        {
-         if (REG_P (dest) || GET_CODE (dest) == SUBREG)
-           invalidate (dest, VOIDmode);
-         else if (MEM_P (dest))
-           invalidate (dest, VOIDmode);
-         else if (GET_CODE (dest) == STRICT_LOW_PART
-                  || GET_CODE (dest) == ZERO_EXTRACT)
-           invalidate (XEXP (dest, 0), GET_MODE (dest));
+         invalidate_dest (dest);
          sets[i].rtl = 0;
        }
 
       if (sets[i].rtl != 0 && dest != SET_DEST (sets[i].rtl))
-       sets[i].dest_hash = HASH (SET_DEST (sets[i].rtl), mode);
-
-#ifdef HAVE_cc0
-      /* If setting CC0, record what it was set to, or a constant, if it
-        is equivalent to a constant.  If it is being set to a floating-point
-        value, make a COMPARE with the appropriate constant of 0.  If we
-        don't do this, later code can interpret this as a test against
-        const0_rtx, which can cause problems if we try to put it into an
-        insn as a floating-point operand.  */
-      if (dest == cc0_rtx)
        {
-         this_insn_cc0 = src_const && mode != VOIDmode ? src_const : src;
-         this_insn_cc0_mode = mode;
-         if (FLOAT_MODE_P (mode))
-           this_insn_cc0 = gen_rtx_COMPARE (VOIDmode, this_insn_cc0,
-                                            CONST0_RTX (mode));
+         do_not_record = 0;
+         sets[i].dest_hash = HASH (SET_DEST (sets[i].rtl), mode);
+         if (do_not_record)
+           {
+             invalidate_dest (SET_DEST (sets[i].rtl));
+             sets[i].rtl = 0;
+           }
        }
-#endif
     }
 
   /* Now enter all non-volatile source expressions in the hash table
@@ -5499,7 +5633,7 @@ cse_insn (rtx insn)
       struct table_elt *elt;
       struct table_elt *classp = sets[0].src_elt;
       rtx dest = SET_DEST (sets[0].rtl);
-      enum machine_mode eqvmode = GET_MODE (dest);
+      machine_mode eqvmode = GET_MODE (dest);
 
       if (GET_CODE (dest) == STRICT_LOW_PART)
        {
@@ -5545,7 +5679,7 @@ cse_insn (rtx insn)
            struct table_elt *classp = src_eqv_elt;
            rtx src = sets[i].src;
            rtx dest = SET_DEST (sets[i].rtl);
-           enum machine_mode mode
+           machine_mode mode
              = GET_MODE (src) == VOIDmode ? GET_MODE (dest) : GET_MODE (src);
 
            /* It's possible that we have a source value known to be
@@ -5572,6 +5706,12 @@ cse_insn (rtx insn)
                  }
                elt = insert (src, classp, sets[i].src_hash, mode);
                elt->in_memory = sets[i].src_in_memory;
+               /* If inline asm has any clobbers, ensure we only reuse
+                  existing inline asms and never try to put the ASM_OPERANDS
+                  into an insn that isn't inline asm.  */
+               if (GET_CODE (src) == ASM_OPERANDS
+                   && GET_CODE (x) == PARALLEL)
+                 elt->cost = MAX_COST;
                sets[i].src_elt = classp = elt;
              }
            if (sets[i].src_const && sets[i].src_const_elt == 0
@@ -5595,7 +5735,7 @@ cse_insn (rtx insn)
        {
          rtx x = sets[i].inner_dest;
          struct table_elt *elt;
-         enum machine_mode mode;
+         machine_mode mode;
          unsigned hash;
 
          if (MEM_P (x))
@@ -5633,7 +5773,14 @@ cse_insn (rtx insn)
     {
       if (!(RTL_CONST_OR_PURE_CALL_P (insn)))
        invalidate_memory ();
-      invalidate_for_call ();
+      else
+       /* For const/pure calls, invalidate any argument slots, because
+          those are owned by the callee.  */
+       for (tem = CALL_INSN_FUNCTION_USAGE (insn); tem; tem = XEXP (tem, 1))
+         if (GET_CODE (XEXP (tem, 0)) == USE
+             && MEM_P (XEXP (XEXP (tem, 0), 0)))
+           invalidate (XEXP (XEXP (tem, 0), 0), VOIDmode);
+      invalidate_for_call (insn);
     }
 
   /* Now invalidate everything set by this instruction.
@@ -5661,12 +5808,6 @@ cse_insn (rtx insn)
          invalidate (XEXP (dest, 0), GET_MODE (dest));
       }
 
-  /* A volatile ASM invalidates everything.  */
-  if (NONJUMP_INSN_P (insn)
-      && GET_CODE (PATTERN (insn)) == ASM_OPERANDS
-      && MEM_VOLATILE_P (PATTERN (insn)))
-    flush_hash_table ();
-
   /* Don't cse over a call to setjmp; on some machines (eg VAX)
      the regs restored by the longjmp come from a later time
      than the setjmp.  */
@@ -5771,15 +5912,7 @@ cse_insn (rtx insn)
            || GET_MODE (dest) == BLKmode
            /* 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
-           /* If DEST is a paradoxical SUBREG and SRC is a ZERO_EXTEND
-              or SIGN_EXTEND, don't record DEST since it can cause
-              some tracking to be wrong.
-
-              ??? Think about this more later.  */
-           || (paradoxical_subreg_p (dest)
-               && (GET_CODE (sets[i].src) == SIGN_EXTEND
-                   || GET_CODE (sets[i].src) == ZERO_EXTEND)))
+           || sets[i].src_elt == 0)
          continue;
 
        /* STRICT_LOW_PART isn't part of the value BEING set,
@@ -5798,6 +5931,11 @@ cse_insn (rtx insn)
              sets[i].dest_hash = HASH (dest, GET_MODE (dest));
            }
 
+       /* If DEST is a paradoxical SUBREG, don't record DEST since the bits
+          outside the mode of GET_MODE (SUBREG_REG (dest)) are undefined.  */
+       if (paradoxical_subreg_p (dest))
+         continue;
+
        elt = insert (dest, sets[i].src_elt,
                      sets[i].dest_hash, GET_MODE (dest));
 
@@ -5828,14 +5966,14 @@ cse_insn (rtx insn)
           already entered SRC and DEST of the SET in the table.  */
 
        if (GET_CODE (dest) == SUBREG
-           && (((GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest))) - 1)
-                / UNITS_PER_WORD)
-               == (GET_MODE_SIZE (GET_MODE (dest)) - 1) / UNITS_PER_WORD)
-           && (GET_MODE_SIZE (GET_MODE (dest))
-               >= GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest))))
+           && (known_equal_after_align_down
+               (GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest))) - 1,
+                GET_MODE_SIZE (GET_MODE (dest)) - 1,
+                UNITS_PER_WORD))
+           && !partial_subreg_p (dest)
            && sets[i].src_elt != 0)
          {
-           enum machine_mode new_mode = GET_MODE (SUBREG_REG (dest));
+           machine_mode new_mode = GET_MODE (SUBREG_REG (dest));
            struct table_elt *elt, *classp = 0;
 
            for (elt = sets[i].src_elt->first_same_value; elt;
@@ -5844,7 +5982,6 @@ cse_insn (rtx insn)
                rtx new_src = 0;
                unsigned src_hash;
                struct table_elt *src_elt;
-               int byte = 0;
 
                /* Ignore invalid entries.  */
                if (!REG_P (elt->exp)
@@ -5857,13 +5994,8 @@ cse_insn (rtx insn)
                  new_src = elt->exp;
                else
                  {
-                   /* Calculate big endian correction for the SUBREG_BYTE.
-                      We have already checked that M1 (GET_MODE (dest))
-                      is not narrower than M2 (new_mode).  */
-                   if (BYTES_BIG_ENDIAN)
-                     byte = (GET_MODE_SIZE (GET_MODE (dest))
-                             - GET_MODE_SIZE (new_mode));
-
+                   poly_uint64 byte
+                     = subreg_lowpart_offset (new_mode, GET_MODE (dest));
                    new_src = simplify_gen_subreg (new_mode, elt->exp,
                                                   GET_MODE (dest), byte);
                  }
@@ -5891,6 +6023,9 @@ cse_insn (rtx insn)
                      }
                    src_elt = insert (new_src, classp, src_hash, new_mode);
                    src_elt->in_memory = elt->in_memory;
+                   if (GET_CODE (new_src) == ASM_OPERANDS
+                       && elt->cost == MAX_COST)
+                     src_elt->cost = MAX_COST;
                  }
                else if (classp && classp != src_elt->first_same_value)
                  /* Show that two things that we've seen before are
@@ -5949,7 +6084,7 @@ invalidate_memory (void)
    alias with something that is SET or CLOBBERed.  */
 
 static void
-invalidate_from_clobbers (rtx insn)
+invalidate_from_clobbers (rtx_insn *insn)
 {
   rtx x = PATTERN (insn);
 
@@ -5991,7 +6126,7 @@ invalidate_from_clobbers (rtx insn)
    alias with something that is SET or CLOBBERed.  */
 
 static void
-invalidate_from_sets_and_clobbers (rtx insn)
+invalidate_from_sets_and_clobbers (rtx_insn *insn)
 {
   rtx tem;
   rtx x = PATTERN (insn);
@@ -5999,8 +6134,11 @@ invalidate_from_sets_and_clobbers (rtx insn)
   if (CALL_P (insn))
     {
       for (tem = CALL_INSN_FUNCTION_USAGE (insn); tem; tem = XEXP (tem, 1))
-       if (GET_CODE (XEXP (tem, 0)) == CLOBBER)
-         invalidate (SET_DEST (XEXP (tem, 0)), VOIDmode);
+       {
+         rtx temx = XEXP (tem, 0);
+         if (GET_CODE (temx) == CLOBBER)
+           invalidate (SET_DEST (temx), VOIDmode);
+       }
     }
 
   /* Ensure we invalidate the destination register of a CALL insn.
@@ -6033,60 +6171,28 @@ invalidate_from_sets_and_clobbers (rtx insn)
     }
 }
 \f
-/* Process X, part of the REG_NOTES of an insn.  Look at any REG_EQUAL notes
-   and replace any registers in them with either an equivalent constant
-   or the canonical form of the register.  If we are inside an address,
-   only do this if the address remains valid.
+static rtx cse_process_note (rtx);
 
-   OBJECT is 0 except when within a MEM in which case it is the MEM.
+/* A simplify_replace_fn_rtx callback for cse_process_note.  Process X,
+   part of the REG_NOTES of an insn.  Replace any registers with either
+   an equivalent constant or the canonical form of the register.
+   Only replace addresses if the containing MEM remains valid.
 
-   Return the replacement for X.  */
+   Return the replacement for X, or null if it should be simplified
+   recursively.  */
 
 static rtx
-cse_process_notes_1 (rtx x, rtx object, bool *changed)
+cse_process_note_1 (rtx x, const_rtx, void *)
 {
-  enum rtx_code code = GET_CODE (x);
-  const char *fmt = GET_RTX_FORMAT (code);
-  int i;
-
-  switch (code)
+  if (MEM_P (x))
     {
-    case CONST:
-    case SYMBOL_REF:
-    case LABEL_REF:
-    CASE_CONST_ANY:
-    case PC:
-    case CC0:
-    case LO_SUM:
-      return x;
-
-    case MEM:
-      validate_change (x, &XEXP (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, changed);
-      if (XEXP (x, 1))
-       XEXP (x, 1) = cse_process_notes (XEXP (x, 1), NULL_RTX, changed);
+      validate_change (x, &XEXP (x, 0), cse_process_note (XEXP (x, 0)), false);
       return x;
+    }
 
-    case SIGN_EXTEND:
-    case ZERO_EXTEND:
-    case SUBREG:
-      {
-       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_rtx) != VOIDmode)
-         validate_change (object, &XEXP (x, 0), new_rtx, 0);
-       return x;
-      }
-
-    case REG:
-      i = REG_QTY (REGNO (x));
+  if (REG_P (x))
+    {
+      int i = REG_QTY (REGNO (x));
 
       /* Return a constant or a constant register.  */
       if (REGNO_QTY_VALID_P (REGNO (x)))
@@ -6104,27 +6210,20 @@ cse_process_notes_1 (rtx x, rtx object, bool *changed)
        }
 
       /* Otherwise, canonicalize this register.  */
-      return canon_reg (x, NULL_RTX);
-
-    default:
-      break;
+      return canon_reg (x, NULL);
     }
 
-  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, changed), 0);
-
-  return x;
+  return NULL_RTX;
 }
 
+/* Process X, part of the REG_NOTES of an insn.  Replace any registers in it
+   with either an equivalent constant or the canonical form of the register.
+   Only replace addresses if the containing MEM remains valid.  */
+
 static rtx
-cse_process_notes (rtx x, rtx object, bool *changed)
+cse_process_note (rtx x)
 {
-  rtx new_rtx = cse_process_notes_1 (x, object, changed);
-  if (new_rtx != x)
-    *changed = true;
-  return new_rtx;
+  return simplify_replace_fn_rtx (x, NULL_RTX, cse_process_note_1, NULL);
 }
 
 \f
@@ -6151,7 +6250,7 @@ cse_find_path (basic_block first_bb, struct cse_basic_block_data *data,
   edge e;
   int path_size;
 
-  SET_BIT (cse_visited_basic_blocks, first_bb->index);
+  bitmap_set_bit (cse_visited_basic_blocks, first_bb->index);
 
   /* See if there is a previous path.  */
   path_size = data->path_size;
@@ -6195,7 +6294,7 @@ cse_find_path (basic_block first_bb, struct cse_basic_block_data *data,
              && e == BRANCH_EDGE (previous_bb_in_path))
            {
              bb = FALLTHRU_EDGE (previous_bb_in_path)->dest;
-             if (bb != EXIT_BLOCK_PTR
+             if (bb != EXIT_BLOCK_PTR_FOR_FN (cfun)
                  && single_pred_p (bb)
                  /* We used to assert here that we would only see blocks
                     that we have not visited yet.  But we may end up
@@ -6208,9 +6307,9 @@ cse_find_path (basic_block first_bb, struct cse_basic_block_data *data,
 
                     We still want to visit each basic block only once, so
                     halt the path here if we have already visited BB.  */
-                 && !TEST_BIT (cse_visited_basic_blocks, bb->index))
+                 && !bitmap_bit_p (cse_visited_basic_blocks, bb->index))
                {
-                 SET_BIT (cse_visited_basic_blocks, bb->index);
+                 bitmap_set_bit (cse_visited_basic_blocks, bb->index);
                  data->path[path_size++].bb = bb;
                  break;
                }
@@ -6231,7 +6330,7 @@ cse_find_path (basic_block first_bb, struct cse_basic_block_data *data,
   if (follow_jumps)
     {
       bb = data->path[path_size - 1].bb;
-      while (bb && path_size < PARAM_VALUE (PARAM_MAX_CSE_PATH_LENGTH))
+      while (bb && path_size < param_max_cse_path_length)
        {
          if (single_succ_p (bb))
            e = single_succ_edge (bb);
@@ -6249,14 +6348,14 @@ cse_find_path (basic_block first_bb, struct cse_basic_block_data *data,
 
          if (e
              && !((e->flags & EDGE_ABNORMAL_CALL) && cfun->has_nonlocal_label)
-             && e->dest != EXIT_BLOCK_PTR
+             && e->dest != EXIT_BLOCK_PTR_FOR_FN (cfun)
              && single_pred_p (e->dest)
              /* Avoid visiting basic blocks twice.  The large comment
                 above explains why this can happen.  */
-             && !TEST_BIT (cse_visited_basic_blocks, e->dest->index))
+             && !bitmap_bit_p (cse_visited_basic_blocks, e->dest->index))
            {
              basic_block bb2 = e->dest;
-             SET_BIT (cse_visited_basic_blocks, bb2->index);
+             bitmap_set_bit (cse_visited_basic_blocks, bb2->index);
              data->path[path_size++].bb = bb2;
              bb = bb2;
            }
@@ -6281,7 +6380,7 @@ cse_dump_path (struct cse_basic_block_data *data, int nsets, FILE *f)
   fprintf (f, ";; Following path with %d sets: ", nsets);
   for (path_entry = 0; path_entry < data->path_size; path_entry++)
     fprintf (f, "%d ", (data->path[path_entry].bb)->index);
-  fputc ('\n', dump_file);
+  fputc ('\n', f);
   fflush (f);
 }
 
@@ -6316,7 +6415,7 @@ cse_prescan_path (struct cse_basic_block_data *data)
   for (path_entry = 0; path_entry < path_size; path_entry++)
     {
       basic_block bb;
-      rtx insn;
+      rtx_insn *insn;
 
       bb = data->path[path_entry].bb;
 
@@ -6337,6 +6436,32 @@ cse_prescan_path (struct cse_basic_block_data *data)
   data->nsets = nsets;
 }
 \f
+/* Return true if the pattern of INSN uses a LABEL_REF for which
+   there isn't a REG_LABEL_OPERAND note.  */
+
+static bool
+check_for_label_ref (rtx_insn *insn)
+{
+  /* 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.  */
+  subrtx_iterator::array_type array;
+  FOR_EACH_SUBRTX (iter, array, PATTERN (insn), ALL)
+    {
+      const_rtx x = *iter;
+      if (GET_CODE (x) == LABEL_REF
+         && !LABEL_REF_NONLOCAL_P (x)
+         && (!JUMP_P (insn)
+             || !label_is_jump_target_p (label_ref_label (x), insn))
+         && LABEL_P (label_ref_label (x))
+         && INSN_UID (label_ref_label (x)) != 0
+         && !find_reg_note (insn, REG_LABEL_OPERAND, label_ref_label (x)))
+       return true;
+    }
+  return false;
+}
+
 /* Process a single extended basic block described by EBB_DATA.  */
 
 static void
@@ -6355,7 +6480,7 @@ cse_extended_basic_block (struct cse_basic_block_data *ebb_data)
   for (path_entry = 0; path_entry < path_size; path_entry++)
     {
       basic_block bb;
-      rtx insn;
+      rtx_insn *insn;
 
       bb = ebb_data->path[path_entry].bb;
 
@@ -6363,14 +6488,11 @@ cse_extended_basic_block (struct cse_basic_block_data *ebb_data)
         edge pointing to that bb.  */
       if (bb_has_eh_pred (bb))
        {
-         df_ref *def_rec;
+         df_ref def;
 
-         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_EACH_ARTIFICIAL_DEF (def, bb->index)
+           if (DF_REF_FLAGS (def) & DF_REF_AT_TOP)
+             invalidate (DF_REF_REG (def), GET_MODE (DF_REF_REG (def)));
        }
 
       optimize_this_for_speed_p = optimize_bb_for_speed_p (bb);
@@ -6386,7 +6508,7 @@ cse_extended_basic_block (struct cse_basic_block_data *ebb_data)
             FIXME: This is a real kludge and needs to be done some other
                    way.  */
          if (NONDEBUG_INSN_P (insn)
-             && num_insns++ > PARAM_VALUE (PARAM_MAX_CSE_INSNS))
+             && num_insns++ > param_max_cse_insns)
            {
              flush_hash_table ();
              num_insns = 0;
@@ -6396,52 +6518,27 @@ 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))
-               {
-                 bool changed = false;
-                 REG_NOTES (insn) = cse_process_notes (REG_NOTES (insn),
-                                                       NULL_RTX, &changed);
-                 if (changed)
-                   df_notes_rescan (insn);
-               }
+             bool changed = false;
+             for (rtx note = REG_NOTES (insn); note; note = XEXP (note, 1))
+               if (REG_NOTE_KIND (note) == REG_EQUAL)
+                 {
+                   rtx newval = cse_process_note (XEXP (note, 0));
+                   if (newval != XEXP (note, 0))
+                     {
+                       XEXP (note, 0) = newval;
+                       changed = true;
+                     }
+                 }
+             if (changed)
+               df_notes_rescan (insn);
 
              cse_insn (insn);
 
              /* If we haven't already found an insn where we added a LABEL_REF,
                 check this one.  */
              if (INSN_P (insn) && !recorded_label_ref
-                 && for_each_rtx (&PATTERN (insn), check_for_label_ref,
-                                  (void *) insn))
+                 && check_for_label_ref (insn))
                recorded_label_ref = true;
-
-#ifdef HAVE_cc0
-             if (NONDEBUG_INSN_P (insn))
-               {
-                 /* If the previous insn sets CC0 and this insn no
-                    longer references CC0, delete the previous insn.
-                    Here we use fact that nothing expects CC0 to be
-                    valid over an insn, which is true until the final
-                    pass.  */
-                 rtx prev_insn, tem;
-
-                 prev_insn = prev_nonnote_nondebug_insn (insn);
-                 if (prev_insn && NONJUMP_INSN_P (prev_insn)
-                     && (tem = single_set (prev_insn)) != NULL_RTX
-                     && SET_DEST (tem) == cc0_rtx
-                     && ! reg_mentioned_p (cc0_rtx, PATTERN (insn)))
-                   delete_insn (prev_insn);
-
-                 /* If this insn is not the last insn in the basic
-                    block, it will be PREV_INSN(insn) in the next
-                    iteration.  If we recorded any CC0-related
-                    information for this insn, remember it.  */
-                 if (insn != BB_END (bb))
-                   {
-                     prev_insn_cc0 = this_insn_cc0;
-                     prev_insn_cc0_mode = this_insn_cc0_mode;
-                   }
-               }
-#endif
            }
        }
 
@@ -6468,7 +6565,7 @@ cse_extended_basic_block (struct cse_basic_block_data *ebb_data)
                  /* If we truncate the path, we must also reset the
                     visited bit on the remaining blocks in the path,
                     or we will never visit them at all.  */
-                 RESET_BIT (cse_visited_basic_blocks,
+                 bitmap_clear_bit (cse_visited_basic_blocks,
                             ebb_data->path[path_size].bb->index);
                  ebb_data->path[path_size].bb = NULL;
                }
@@ -6481,6 +6578,7 @@ cse_extended_basic_block (struct cse_basic_block_data *ebb_data)
         equivalences due to the condition being tested.  */
       insn = BB_END (bb);
       if (path_entry < path_size - 1
+         && EDGE_COUNT (bb->succs) == 2
          && JUMP_P (insn)
          && single_set (insn)
          && any_condjump_p (insn))
@@ -6489,12 +6587,6 @@ cse_extended_basic_block (struct cse_basic_block_data *ebb_data)
          bool taken = (next_bb == BRANCH_EDGE (bb)->dest);
          record_jump_equiv (insn, taken);
        }
-
-#ifdef HAVE_cc0
-      /* Clear the CC0-tracking related insns, they can't provide
-        useful information across basic block boundaries.  */
-      prev_insn_cc0 = 0;
-#endif
     }
 
   gcc_assert (next_qty <= max_qty);
@@ -6513,14 +6605,19 @@ cse_extended_basic_block (struct cse_basic_block_data *ebb_data)
    Return 0 otherwise.  */
 
 static int
-cse_main (rtx f ATTRIBUTE_UNUSED, int nregs)
+cse_main (rtx_insn *f ATTRIBUTE_UNUSED, int nregs)
 {
   struct cse_basic_block_data ebb_data;
   basic_block bb;
-  int *rc_order = XNEWVEC (int, last_basic_block);
+  int *rc_order = XNEWVEC (int, last_basic_block_for_fn (cfun));
   int i, n_blocks;
 
+  /* CSE doesn't use dominane info but can invalidate it in different ways.
+     For simplicity free dominance info here.  */
+  free_dominance_info (CDI_DOMINATORS);
+
   df_set_flags (DF_LR_RUN_DCE);
+  df_note_add_problem ();
   df_analyze ();
   df_set_flags (DF_DEFER_INSN_RESCAN);
 
@@ -6528,7 +6625,7 @@ cse_main (rtx f ATTRIBUTE_UNUSED, int nregs)
   init_cse_reg_info (nregs);
 
   ebb_data.path = XNEWVEC (struct branch_path,
-                          PARAM_VALUE (PARAM_MAX_CSE_PATH_LENGTH));
+                          param_max_cse_path_length);
 
   cse_cfg_altered = false;
   cse_jumps_altered = false;
@@ -6545,7 +6642,7 @@ cse_main (rtx f ATTRIBUTE_UNUSED, int nregs)
   reg_eqv_table = XNEWVEC (struct reg_eqv_elem, nregs);
 
   /* Set up the table of already visited basic blocks.  */
-  cse_visited_basic_blocks = sbitmap_alloc (last_basic_block);
+  cse_visited_basic_blocks = sbitmap_alloc (last_basic_block_for_fn (cfun));
   bitmap_clear (cse_visited_basic_blocks);
 
   /* Loop over basic blocks in reverse completion order (RPO),
@@ -6558,9 +6655,9 @@ cse_main (rtx f ATTRIBUTE_UNUSED, int nregs)
         processed before.  */
       do
        {
-         bb = BASIC_BLOCK (rc_order[i++]);
+         bb = BASIC_BLOCK_FOR_FN (cfun, rc_order[i++]);
        }
-      while (TEST_BIT (cse_visited_basic_blocks, bb->index)
+      while (bitmap_bit_p (cse_visited_basic_blocks, bb->index)
             && i < n_blocks);
 
       /* Find all paths starting with BB, and process them.  */
@@ -6602,28 +6699,6 @@ cse_main (rtx f ATTRIBUTE_UNUSED, int nregs)
     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_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_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_OPERAND, XEXP (*rtl, 0)));
-}
-\f
 /* Count the number of times registers are used (not set) in X.
    COUNTS is an array in which we accumulate the count, INCR is how much
    we count each register usage.
@@ -6654,7 +6729,6 @@ count_reg_usage (rtx x, int *counts, rtx dest, int incr)
       return;
 
     case PC:
-    case CC0:
     case CONST:
     CASE_CONST_ANY:
     case SYMBOL_REF:
@@ -6733,6 +6807,7 @@ count_reg_usage (rtx x, int *counts, rtx dest, int incr)
       return;
 
     case INSN_LIST:
+    case INT_LIST:
       gcc_unreachable ();
 
     default:
@@ -6753,7 +6828,7 @@ count_reg_usage (rtx x, int *counts, rtx dest, int incr)
 /* Return true if X is a dead register.  */
 
 static inline int
-is_dead_reg (rtx x, int *counts)
+is_dead_reg (const_rtx x, int *counts)
 {
   return (REG_P (x)
          && REGNO (x) >= FIRST_PSEUDO_REGISTER
@@ -6762,40 +6837,28 @@ is_dead_reg (rtx x, int *counts)
 
 /* Return true if set is live.  */
 static bool
-set_live_p (rtx set, rtx insn ATTRIBUTE_UNUSED, /* Only used with HAVE_cc0.  */
-           int *counts)
+set_live_p (rtx set, int *counts)
 {
-#ifdef HAVE_cc0
-  rtx tem;
-#endif
-
   if (set_noop_p (set))
-    ;
-
-#ifdef HAVE_cc0
-  else if (GET_CODE (SET_DEST (set)) == CC0
-          && !side_effects_p (SET_SRC (set))
-          && ((tem = next_nonnote_nondebug_insn (insn)) == NULL_RTX
-              || !INSN_P (tem)
-              || !reg_referenced_p (cc0_rtx, PATTERN (tem))))
     return false;
-#endif
-  else if (!is_dead_reg (SET_DEST (set), counts)
-          || side_effects_p (SET_SRC (set)))
+
+  if (!is_dead_reg (SET_DEST (set), counts)
+      || side_effects_p (SET_SRC (set)))
     return true;
+
   return false;
 }
 
 /* Return true if insn is live.  */
 
 static bool
-insn_live_p (rtx insn, int *counts)
+insn_live_p (rtx_insn *insn, int *counts)
 {
   int i;
   if (!cfun->can_delete_dead_exceptions && !insn_nothrow_p (insn))
     return true;
   else if (GET_CODE (PATTERN (insn)) == SET)
-    return set_live_p (PATTERN (insn), insn, counts);
+    return set_live_p (PATTERN (insn), counts);
   else if (GET_CODE (PATTERN (insn)) == PARALLEL)
     {
       for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
@@ -6804,7 +6867,7 @@ insn_live_p (rtx insn, int *counts)
 
          if (GET_CODE (elt) == SET)
            {
-             if (set_live_p (elt, insn, counts))
+             if (set_live_p (elt, counts))
                return true;
            }
          else if (GET_CODE (elt) != CLOBBER && GET_CODE (elt) != USE)
@@ -6814,13 +6877,20 @@ insn_live_p (rtx insn, int *counts)
     }
   else if (DEBUG_INSN_P (insn))
     {
-      rtx next;
+      rtx_insn *next;
+
+      if (DEBUG_MARKER_INSN_P (insn))
+       return true;
 
       for (next = NEXT_INSN (insn); next; next = NEXT_INSN (next))
        if (NOTE_P (next))
          continue;
        else if (!DEBUG_INSN_P (next))
          return true;
+       /* If we find an inspection point, such as a debug begin stmt,
+          we want to keep the earlier debug insn.  */
+       else if (DEBUG_MARKER_INSN_P (next))
+         return true;
        else if (INSN_VAR_LOCATION_DECL (insn) == INSN_VAR_LOCATION_DECL (next))
          return false;
 
@@ -6840,30 +6910,29 @@ count_stores (rtx x, const_rtx set ATTRIBUTE_UNUSED, void *data)
     counts[REGNO (x)]++;
 }
 
-struct dead_debug_insn_data
-{
-  int *counts;
-  rtx *replacements;
-  bool seen_repl;
-};
-
-/* Return if a DEBUG_INSN needs to be reset because some dead
-   pseudo doesn't have a replacement.  Callback for for_each_rtx.  */
+/* Return if DEBUG_INSN pattern PAT needs to be reset because some dead
+   pseudo doesn't have a replacement.  COUNTS[X] is zero if register X
+   is dead and REPLACEMENTS[X] is null if it has no replacemenet.
+   Set *SEEN_REPL to true if we see a dead register that does have
+   a replacement.  */
 
-static int
-is_dead_debug_insn (rtx *loc, void *data)
+static bool
+is_dead_debug_insn (const_rtx pat, int *counts, rtx *replacements,
+                   bool *seen_repl)
 {
-  rtx x = *loc;
-  struct dead_debug_insn_data *ddid = (struct dead_debug_insn_data *) data;
-
-  if (is_dead_reg (x, ddid->counts))
+  subrtx_iterator::array_type array;
+  FOR_EACH_SUBRTX (iter, array, pat, NONCONST)
     {
-      if (ddid->replacements && ddid->replacements[REGNO (x)] != NULL_RTX)
-       ddid->seen_repl = true;
-      else
-       return 1;
+      const_rtx x = *iter;
+      if (is_dead_reg (x, counts))
+       {
+         if (replacements && replacements[REGNO (x)] != NULL_RTX)
+           *seen_repl = true;
+         else
+           return true;
+       }
     }
-  return 0;
+  return false;
 }
 
 /* Replace a dead pseudo in a DEBUG_INSN with replacement DEBUG_EXPR.
@@ -6895,26 +6964,26 @@ replace_dead_reg (rtx x, const_rtx old_rtx ATTRIBUTE_UNUSED, void *data)
    remaining passes of the compilation are also sped up.  */
 
 int
-delete_trivially_dead_insns (rtx insns, int nreg)
+delete_trivially_dead_insns (rtx_insn *insns, int nreg)
 {
   int *counts;
-  rtx insn, prev;
+  rtx_insn *insn, *prev;
   rtx *replacements = NULL;
   int ndead = 0;
 
   timevar_push (TV_DELETE_TRIVIALLY_DEAD);
   /* First count the number of times each register is used.  */
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     {
       counts = XCNEWVEC (int, nreg * 3);
       for (insn = insns; insn; insn = NEXT_INSN (insn))
-       if (DEBUG_INSN_P (insn))
+       if (DEBUG_BIND_INSN_P (insn))
          count_reg_usage (INSN_VAR_LOCATION_LOC (insn), counts + nreg,
                           NULL_RTX, 1);
        else if (INSN_P (insn))
          {
            count_reg_usage (insn, counts, NULL_RTX, 1);
-           note_stores (PATTERN (insn), count_stores, counts + nreg * 2);
+           note_stores (insn, count_stores, counts + nreg * 2);
          }
       /* If there can be debug insns, COUNTS are 3 consecutive arrays.
         First one counts how many times each pseudo is used outside
@@ -6931,6 +7000,12 @@ delete_trivially_dead_insns (rtx insns, int nreg)
       /* If no debug insns can be present, COUNTS is just an array
         which counts how many times each pseudo is used.  */
     }
+  /* Pseudo PIC register should be considered as used due to possible
+     new usages generated.  */
+  if (!reload_completed
+      && pic_offset_table_rtx
+      && REGNO (pic_offset_table_rtx) >= FIRST_PSEUDO_REGISTER)
+    counts[REGNO (pic_offset_table_rtx)]++;
   /* Go from the last insn to the first and delete insns that only set unused
      registers or copy a register to itself.  As we delete an insn, remove
      usage counts for registers it uses.
@@ -6960,12 +7035,15 @@ delete_trivially_dead_insns (rtx insns, int nreg)
       if (! live_insn && dbg_cnt (delete_trivial_dead))
        {
          if (DEBUG_INSN_P (insn))
-           count_reg_usage (INSN_VAR_LOCATION_LOC (insn), counts + nreg,
-                            NULL_RTX, -1);
+           {
+             if (DEBUG_BIND_INSN_P (insn))
+               count_reg_usage (INSN_VAR_LOCATION_LOC (insn), counts + nreg,
+                                NULL_RTX, -1);
+           }
          else
            {
              rtx set;
-             if (MAY_HAVE_DEBUG_INSNS
+             if (MAY_HAVE_DEBUG_BIND_INSNS
                  && (set = single_set (insn)) != NULL_RTX
                  && is_dead_reg (SET_DEST (set), counts)
                  /* Used at least once in some DEBUG_INSN.  */
@@ -6975,20 +7053,22 @@ delete_trivially_dead_insns (rtx insns, int nreg)
                  && !side_effects_p (SET_SRC (set))
                  && asm_noperands (PATTERN (insn)) < 0)
                {
-                 rtx dval, bind;
+                 rtx dval, bind_var_loc;
+                 rtx_insn *bind;
 
                  /* Create DEBUG_EXPR (and DEBUG_EXPR_DECL).  */
                  dval = make_debug_expr_from_rtl (SET_DEST (set));
 
                  /* Emit a debug bind insn before the insn in which
                     reg dies.  */
-                 bind = gen_rtx_VAR_LOCATION (GET_MODE (SET_DEST (set)),
-                                              DEBUG_EXPR_TREE_DECL (dval),
-                                              SET_SRC (set),
-                                              VAR_INIT_STATUS_INITIALIZED);
-                 count_reg_usage (bind, counts + nreg, NULL_RTX, 1);
-
-                 bind = emit_debug_insn_before (bind, insn);
+                 bind_var_loc =
+                   gen_rtx_VAR_LOCATION (GET_MODE (SET_DEST (set)),
+                                         DEBUG_EXPR_TREE_DECL (dval),
+                                         SET_SRC (set),
+                                         VAR_INIT_STATUS_INITIALIZED);
+                 count_reg_usage (bind_var_loc, counts + nreg, NULL_RTX, 1);
+
+                 bind = emit_debug_insn_before (bind_var_loc, insn);
                  df_insn_rescan (bind);
 
                  if (replacements == NULL)
@@ -6999,28 +7079,25 @@ delete_trivially_dead_insns (rtx insns, int nreg)
              count_reg_usage (insn, counts, NULL_RTX, -1);
              ndead++;
            }
-         delete_insn_and_edges (insn);
+         cse_cfg_altered |= delete_insn_and_edges (insn);
        }
     }
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     {
-      struct dead_debug_insn_data ddid;
-      ddid.counts = counts;
-      ddid.replacements = replacements;
       for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
-       if (DEBUG_INSN_P (insn))
+       if (DEBUG_BIND_INSN_P (insn))
          {
            /* If this debug insn references a dead register that wasn't replaced
               with an DEBUG_EXPR, reset the DEBUG_INSN.  */
-           ddid.seen_repl = false;
-           if (for_each_rtx (&INSN_VAR_LOCATION_LOC (insn),
-                             is_dead_debug_insn, &ddid))
+           bool seen_repl = false;
+           if (is_dead_debug_insn (INSN_VAR_LOCATION_LOC (insn),
+                                   counts, replacements, &seen_repl))
              {
                INSN_VAR_LOCATION_LOC (insn) = gen_rtx_UNKNOWN_VAR_LOC ();
                df_insn_rescan (insn);
              }
-           else if (ddid.seen_repl)
+           else if (seen_repl)
              {
                INSN_VAR_LOCATION_LOC (insn)
                  = simplify_replace_fn_rtx (INSN_VAR_LOCATION_LOC (insn),
@@ -7041,45 +7118,42 @@ delete_trivially_dead_insns (rtx insns, int nreg)
   return ndead;
 }
 
-/* This function is called via for_each_rtx.  The argument, NEWREG, is
-   a condition code register with the desired mode.  If we are looking
-   at the same register in a different mode, replace it with
-   NEWREG.  */
+/* If LOC contains references to NEWREG in a different mode, change them
+   to use NEWREG instead.  */
 
-static int
-cse_change_cc_mode (rtx *loc, void *data)
+static void
+cse_change_cc_mode (subrtx_ptr_iterator::array_type &array,
+                   rtx *loc, rtx_insn *insn, rtx newreg)
 {
-  struct change_cc_mode_args* args = (struct change_cc_mode_args*)data;
-
-  if (*loc
-      && REG_P (*loc)
-      && REGNO (*loc) == REGNO (args->newreg)
-      && GET_MODE (*loc) != GET_MODE (args->newreg))
+  FOR_EACH_SUBRTX_PTR (iter, array, loc, NONCONST)
     {
-      validate_change (args->insn, loc, args->newreg, 1);
-
-      return -1;
+      rtx *loc = *iter;
+      rtx x = *loc;
+      if (x
+         && REG_P (x)
+         && REGNO (x) == REGNO (newreg)
+         && GET_MODE (x) != GET_MODE (newreg))
+       {
+         validate_change (insn, loc, newreg, 1);
+         iter.skip_subrtxes ();
+       }
     }
-  return 0;
 }
 
 /* Change the mode of any reference to the register REGNO (NEWREG) to
    GET_MODE (NEWREG) in INSN.  */
 
 static void
-cse_change_cc_mode_insn (rtx insn, rtx newreg)
+cse_change_cc_mode_insn (rtx_insn *insn, rtx newreg)
 {
-  struct change_cc_mode_args args;
   int success;
 
   if (!INSN_P (insn))
     return;
 
-  args.insn = insn;
-  args.newreg = newreg;
-
-  for_each_rtx (&PATTERN (insn), cse_change_cc_mode, &args);
-  for_each_rtx (&REG_NOTES (insn), cse_change_cc_mode, &args);
+  subrtx_ptr_iterator::array_type array;
+  cse_change_cc_mode (array, &PATTERN (insn), insn, newreg);
+  cse_change_cc_mode (array, &REG_NOTES (insn), insn, newreg);
 
   /* If the following assertion was triggered, there is most probably
      something wrong with the cc_modes_compatible back end function.
@@ -7094,9 +7168,9 @@ cse_change_cc_mode_insn (rtx insn, rtx newreg)
    any instruction which modifies NEWREG.  */
 
 static void
-cse_change_cc_mode_insns (rtx start, rtx end, rtx newreg)
+cse_change_cc_mode_insns (rtx_insn *start, rtx_insn *end, rtx newreg)
 {
-  rtx insn;
+  rtx_insn *insn;
 
   for (insn = start; insn != end; insn = NEXT_INSN (insn))
     {
@@ -7126,17 +7200,17 @@ cse_change_cc_mode_insns (rtx start, rtx end, rtx newreg)
    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
+static machine_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;
+  machine_mode mode;
   unsigned int insn_count;
   edge e;
-  rtx insns[2];
-  enum machine_mode modes[2];
-  rtx last_insns[2];
+  rtx_insn *insns[2];
+  machine_mode modes[2];
+  rtx_insn *last_insns[2];
   unsigned int i;
   rtx newreg;
   edge_iterator ei;
@@ -7152,14 +7226,14 @@ cse_cc_succs (basic_block bb, basic_block orig_bb, rtx cc_reg, rtx cc_src,
   insn_count = 0;
   FOR_EACH_EDGE (e, ei, bb->succs)
     {
-      rtx insn;
-      rtx end;
+      rtx_insn *insn;
+      rtx_insn *end;
 
       if (e->flags & EDGE_COMPLEX)
        continue;
 
       if (EDGE_COUNT (e->dest->preds) != 1
-         || e->dest == EXIT_BLOCK_PTR
+         || e->dest == EXIT_BLOCK_PTR_FOR_FN (cfun)
          /* Avoid endless recursion on unreachable blocks.  */
          || e->dest == orig_bb)
        continue;
@@ -7184,8 +7258,8 @@ cse_cc_succs (basic_block bb, basic_block orig_bb, rtx cc_reg, rtx cc_src,
              && REGNO (SET_DEST (set)) == REGNO (cc_reg))
            {
              bool found;
-             enum machine_mode set_mode;
-             enum machine_mode comp_mode;
+             machine_mode set_mode;
+             machine_mode comp_mode;
 
              found = false;
              set_mode = GET_MODE (SET_SRC (set));
@@ -7264,7 +7338,7 @@ cse_cc_succs (basic_block bb, basic_block orig_bb, rtx cc_reg, rtx cc_src,
         further blocks and this block.  */
       if (insn == end)
        {
-         enum machine_mode submode;
+         machine_mode submode;
 
          submode = cse_cc_succs (e->dest, orig_bb, cc_reg, cc_src, false);
          if (submode != VOIDmode)
@@ -7301,7 +7375,7 @@ cse_cc_succs (basic_block bb, basic_block orig_bb, rtx cc_reg, rtx cc_src,
                                    newreg);
        }
 
-      delete_insn_and_edges (insns[i]);
+      cse_cfg_altered |= delete_insn_and_edges (insns[i]);
     }
 
   return mode;
@@ -7328,15 +7402,15 @@ cse_condition_code_reg (void)
   else
     cc_reg_2 = NULL_RTX;
 
-  FOR_EACH_BB (bb)
+  FOR_EACH_BB_FN (bb, cfun)
     {
-      rtx last_insn;
+      rtx_insn *last_insn;
       rtx cc_reg;
-      rtx insn;
-      rtx cc_src_insn;
+      rtx_insn *insn;
+      rtx_insn *cc_src_insn;
       rtx cc_src;
-      enum machine_mode mode;
-      enum machine_mode orig_mode;
+      machine_mode mode;
+      machine_mode orig_mode;
 
       /* Look for blocks which end with a conditional jump based on a
         condition code register.  Then look for the instruction which
@@ -7358,7 +7432,7 @@ cse_condition_code_reg (void)
       else
        continue;
 
-      cc_src_insn = NULL_RTX;
+      cc_src_insn = NULL;
       cc_src = NULL_RTX;
       for (insn = PREV_INSN (last_insn);
           insn && insn != PREV_INSN (BB_HEAD (bb));
@@ -7418,12 +7492,6 @@ cse_condition_code_reg (void)
 /* Perform common subexpression elimination.  Nonzero value from
    `cse_main' means that jumps were simplified and some code may now
    be unreachable, so do jump optimization again.  */
-static bool
-gate_handle_cse (void)
-{
-  return optimize > 0;
-}
-
 static unsigned int
 rest_of_handle_cse (void)
 {
@@ -7442,43 +7510,52 @@ rest_of_handle_cse (void)
     {
       timevar_push (TV_JUMP);
       rebuild_jump_labels (get_insns ());
-      cleanup_cfg (CLEANUP_CFG_CHANGED);
+      cse_cfg_altered |= cleanup_cfg (CLEANUP_CFG_CHANGED);
       timevar_pop (TV_JUMP);
     }
   else if (tem == 1 || optimize > 1)
-    cleanup_cfg (0);
+    cse_cfg_altered |= cleanup_cfg (0);
 
   return 0;
 }
 
-struct rtl_opt_pass pass_cse =
+namespace {
+
+const pass_data pass_data_cse =
 {
- {
-  RTL_PASS,
-  "cse1",                               /* name */
-  gate_handle_cse,                      /* gate */
-  rest_of_handle_cse,                  /* execute */
-  NULL,                                 /* sub */
-  NULL,                                 /* next */
-  0,                                    /* static_pass_number */
-  TV_CSE,                               /* tv_id */
-  0,                                    /* properties_required */
-  0,                                    /* properties_provided */
-  0,                                    /* properties_destroyed */
-  0,                                    /* todo_flags_start */
-  TODO_df_finish | TODO_verify_rtl_sharing |
-  TODO_ggc_collect |
-  TODO_verify_flow,                     /* todo_flags_finish */
- }
+  RTL_PASS, /* type */
+  "cse1", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_CSE, /* tv_id */
+  0, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  TODO_df_finish, /* todo_flags_finish */
 };
 
+class pass_cse : public rtl_opt_pass
+{
+public:
+  pass_cse (gcc::context *ctxt)
+    : rtl_opt_pass (pass_data_cse, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  virtual bool gate (function *) { return optimize > 0; }
+  virtual unsigned int execute (function *) { return rest_of_handle_cse (); }
 
-static bool
-gate_handle_cse2 (void)
+}; // class pass_cse
+
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_cse (gcc::context *ctxt)
 {
-  return optimize > 0 && flag_rerun_cse_after_loop;
+  return new pass_cse (ctxt);
 }
 
+
 /* Run second CSE pass after loop optimizations.  */
 static unsigned int
 rest_of_handle_cse2 (void)
@@ -7502,42 +7579,55 @@ rest_of_handle_cse2 (void)
     {
       timevar_push (TV_JUMP);
       rebuild_jump_labels (get_insns ());
-      cleanup_cfg (CLEANUP_CFG_CHANGED);
+      cse_cfg_altered |= cleanup_cfg (CLEANUP_CFG_CHANGED);
       timevar_pop (TV_JUMP);
     }
-  else if (tem == 1)
-    cleanup_cfg (0);
+  else if (tem == 1 || cse_cfg_altered)
+    cse_cfg_altered |= cleanup_cfg (0);
 
   cse_not_expected = 1;
   return 0;
 }
 
 
-struct rtl_opt_pass pass_cse2 =
+namespace {
+
+const pass_data pass_data_cse2 =
 {
- {
-  RTL_PASS,
-  "cse2",                               /* name */
-  gate_handle_cse2,                     /* gate */
-  rest_of_handle_cse2,                 /* execute */
-  NULL,                                 /* sub */
-  NULL,                                 /* next */
-  0,                                    /* static_pass_number */
-  TV_CSE2,                              /* tv_id */
-  0,                                    /* properties_required */
-  0,                                    /* properties_provided */
-  0,                                    /* properties_destroyed */
-  0,                                    /* todo_flags_start */
-  TODO_df_finish | TODO_verify_rtl_sharing |
-  TODO_ggc_collect |
-  TODO_verify_flow                      /* todo_flags_finish */
- }
+  RTL_PASS, /* type */
+  "cse2", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_CSE2, /* tv_id */
+  0, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  TODO_df_finish, /* todo_flags_finish */
 };
 
-static bool
-gate_handle_cse_after_global_opts (void)
+class pass_cse2 : public rtl_opt_pass
+{
+public:
+  pass_cse2 (gcc::context *ctxt)
+    : rtl_opt_pass (pass_data_cse2, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  virtual bool gate (function *)
+    {
+      return optimize > 0 && flag_rerun_cse_after_loop;
+    }
+
+  virtual unsigned int execute (function *) { return rest_of_handle_cse2 (); }
+
+}; // class pass_cse2
+
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_cse2 (gcc::context *ctxt)
 {
-  return optimize > 0 && flag_rerun_cse_after_global_opts;
+  return new pass_cse2 (ctxt);
 }
 
 /* Run second CSE pass after loop optimizations.  */
@@ -7553,7 +7643,7 @@ rest_of_handle_cse_after_global_opts (void)
 
   rebuild_jump_labels (get_insns ());
   tem = cse_main (get_insns (), max_reg_num ());
-  purge_all_dead_edges ();
+  cse_cfg_altered |= purge_all_dead_edges ();
   delete_trivially_dead_insns (get_insns (), max_reg_num ());
 
   cse_not_expected = !flag_rerun_cse_after_loop;
@@ -7563,33 +7653,55 @@ rest_of_handle_cse_after_global_opts (void)
     {
       timevar_push (TV_JUMP);
       rebuild_jump_labels (get_insns ());
-      cleanup_cfg (CLEANUP_CFG_CHANGED);
+      cse_cfg_altered |= cleanup_cfg (CLEANUP_CFG_CHANGED);
       timevar_pop (TV_JUMP);
     }
-  else if (tem == 1)
-    cleanup_cfg (0);
+  else if (tem == 1 || cse_cfg_altered)
+    cse_cfg_altered |= cleanup_cfg (0);
 
   flag_cse_follow_jumps = save_cfj;
   return 0;
 }
 
-struct rtl_opt_pass pass_cse_after_global_opts =
+namespace {
+
+const pass_data pass_data_cse_after_global_opts =
 {
- {
-  RTL_PASS,
-  "cse_local",                          /* name */
-  gate_handle_cse_after_global_opts,    /* gate */
-  rest_of_handle_cse_after_global_opts, /* execute */
-  NULL,                                 /* sub */
-  NULL,                                 /* next */
-  0,                                    /* static_pass_number */
-  TV_CSE,                               /* tv_id */
-  0,                                    /* properties_required */
-  0,                                    /* properties_provided */
-  0,                                    /* properties_destroyed */
-  0,                                    /* todo_flags_start */
-  TODO_df_finish | TODO_verify_rtl_sharing |
-  TODO_ggc_collect |
-  TODO_verify_flow                      /* todo_flags_finish */
- }
+  RTL_PASS, /* type */
+  "cse_local", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_CSE, /* tv_id */
+  0, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  TODO_df_finish, /* todo_flags_finish */
 };
+
+class pass_cse_after_global_opts : public rtl_opt_pass
+{
+public:
+  pass_cse_after_global_opts (gcc::context *ctxt)
+    : rtl_opt_pass (pass_data_cse_after_global_opts, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  virtual bool gate (function *)
+    {
+      return optimize > 0 && flag_rerun_cse_after_global_opts;
+    }
+
+  virtual unsigned int execute (function *)
+    {
+      return rest_of_handle_cse_after_global_opts ();
+    }
+
+}; // class pass_cse_after_global_opts
+
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_cse_after_global_opts (gcc::context *ctxt)
+{
+  return new pass_cse_after_global_opts (ctxt);
+}