Fixup whitespace.
[gcc.git] / gcc / cse.c
index 2b814937535225e32f736ad0b9c5b977bcb47778..d5357f0272a3b2f0bfb5245a06e71696a214ece1 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
-   Free Software Foundation, Inc.
+   Copyright (C) 1987-2013 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -20,7 +18,6 @@ along with GCC; see the file COPYING3.  If not see
 <http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
-/* stdio.h must precede rtl.h for FFS.  */
 #include "system.h"
 #include "coretypes.h"
 #include "tm.h"
@@ -30,15 +27,13 @@ along with GCC; see the file COPYING3.  If not see
 #include "regs.h"
 #include "basic-block.h"
 #include "flags.h"
-#include "real.h"
 #include "insn-config.h"
 #include "recog.h"
 #include "function.h"
 #include "expr.h"
+#include "diagnostic-core.h"
 #include "toplev.h"
-#include "output.h"
 #include "ggc.h"
-#include "timevar.h"
 #include "except.h"
 #include "target.h"
 #include "params.h"
@@ -46,6 +41,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-pass.h"
 #include "df.h"
 #include "dbgcnt.h"
+#include "pointer-set.h"
 
 /* The basic idea of common subexpression elimination is to go
    through the code, keeping a record of expressions that would
@@ -472,12 +468,12 @@ 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))
-#define COST_IN(X,OUTER) (REG_P (X) ? 0 : notreg_cost (X, OUTER))
+#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))
 
 /* Get the number of times this register has been updated in this
    basic block.  */
@@ -502,6 +498,11 @@ struct table_elt
 
 #define REGNO_QTY_VALID_P(N) (REG_QTY (N) >= 0)
 
+/* Compare table_elt X and Y and return true iff X is cheaper than Y.  */
+
+#define CHEAPER(X, Y) \
+ (preferable ((X)->cost, (X)->regcost, (Y)->cost, (Y)->regcost) < 0)
+
 static struct table_elt *table[HASH_SIZE];
 
 /* Chain of `struct table_elt's made so far for this function
@@ -517,6 +518,14 @@ static struct table_elt *free_element_chain;
 static int constant_pool_entries_cost;
 static int constant_pool_entries_regcost;
 
+/* Trace a patch through the CFG.  */
+
+struct branch_path
+{
+  /* The basic block for this path entry.  */
+  basic_block bb;
+};
+
 /* This data describes a block that will be processed by
    cse_extended_basic_block.  */
 
@@ -527,11 +536,7 @@ struct cse_basic_block_data
   /* Size of current branch path, if any.  */
   int path_size;
   /* Current path, indicating which basic_blocks will be processed.  */
-  struct branch_path
-    {
-      /* The basic block for this path entry.  */
-      basic_block bb;
-    } *path;
+  struct branch_path *path;
 };
 
 
@@ -544,7 +549,7 @@ 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);
+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 preferable (int, int, int, int);
@@ -559,11 +564,12 @@ static void remove_pseudo_from_table (rtx, unsigned);
 static struct table_elt *lookup (rtx, unsigned, enum machine_mode);
 static struct table_elt *lookup_for_remove (rtx, unsigned, enum machine_mode);
 static rtx lookup_as_function (rtx, enum rtx_code);
+static struct table_elt *insert_with_costs (rtx, struct table_elt *, unsigned,
+                                           enum machine_mode, int, int);
 static struct table_elt *insert (rtx, struct table_elt *, unsigned,
                                 enum machine_mode);
 static void merge_equiv_classes (struct table_elt *, struct table_elt *);
 static void invalidate (rtx, enum machine_mode);
-static bool cse_rtx_varies_p (const_rtx, bool);
 static void remove_invalid_refs (unsigned int);
 static void remove_invalid_subreg_refs (unsigned int, unsigned int,
                                        enum machine_mode);
@@ -588,9 +594,9 @@ static void record_jump_cond (enum rtx_code, enum machine_mode, rtx, rtx,
 static void cse_insn (rtx);
 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 cse_extended_basic_block (struct cse_basic_block_data *);
-static void count_reg_usage (rtx, int *, rtx, int);
 static int check_for_label_ref (rtx *, void *);
 extern void dump_class (struct table_elt*);
 static void get_cse_reg_info_1 (unsigned int regno);
@@ -612,9 +618,7 @@ static enum machine_mode cse_cc_succs (basic_block, basic_block, rtx, rtx,
 
 static const struct rtl_hooks cse_rtl_hooks = RTL_HOOKS_INITIALIZER;
 \f
-/* Nonzero if X has the form (PLUS frame-pointer integer).  We check for
-   virtual regs here because the simplify_*_operation routines are called
-   by integrate.c, which is called before virtual register instantiation.  */
+/* Nonzero if X has the form (PLUS frame-pointer integer).  */
 
 static bool
 fixed_base_plus_p (rtx x)
@@ -626,13 +630,10 @@ fixed_base_plus_p (rtx x)
        return true;
       if (x == arg_pointer_rtx && fixed_regs[ARG_POINTER_REGNUM])
        return true;
-      if (REGNO (x) >= FIRST_VIRTUAL_REGISTER
-         && REGNO (x) <= LAST_VIRTUAL_REGISTER)
-       return true;
       return false;
 
     case PLUS:
-      if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+      if (!CONST_INT_P (XEXP (x, 1)))
        return false;
       return fixed_base_plus_p (XEXP (x, 0));
 
@@ -643,7 +644,7 @@ fixed_base_plus_p (rtx x)
 
 /* Dump the expressions in the equivalence class indicated by CLASSP.
    This function is used only for debugging.  */
-void
+DEBUG_FUNCTION void
 dump_class (struct table_elt *classp)
 {
   struct table_elt *elt;
@@ -675,7 +676,7 @@ approx_reg_cost_1 (rtx *xp, void *data)
        {
          if (regno < FIRST_PSEUDO_REGISTER)
            {
-             if (SMALL_REGISTER_CLASSES)
+             if (targetm.small_register_classes_for_mode_p (GET_MODE (x)))
                return 1;
              *cost_p += 2;
            }
@@ -742,7 +743,7 @@ 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)
+notreg_cost (rtx x, enum rtx_code outer, int opno)
 {
   return ((GET_CODE (x) == SUBREG
           && REG_P (SUBREG_REG (x))
@@ -751,10 +752,10 @@ notreg_cost (rtx x, enum rtx_code outer)
           && (GET_MODE_SIZE (GET_MODE (x))
               < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
           && subreg_lowpart_p (x)
-          && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (GET_MODE (x)),
-                                    GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x)))))
+          && TRULY_NOOP_TRUNCATION_MODES_P (GET_MODE (x),
+                                            GET_MODE (SUBREG_REG (x))))
          ? 0
-         : rtx_cost (x, outer, optimize_this_for_speed_p) * 2);
+         : rtx_cost (x, outer, opno, optimize_this_for_speed_p) * 2);
 }
 
 \f
@@ -786,8 +787,7 @@ init_cse_reg_info (unsigned int nregs)
        }
 
       /* Reallocate the table with NEW_SIZE entries.  */
-      if (cse_reg_info_table)
-       free (cse_reg_info_table);
+      free (cse_reg_info_table);
       cse_reg_info_table = XNEWVEC (struct cse_reg_info, new_size);
       cse_reg_info_table_size = new_size;
       cse_reg_info_table_first_uninitialized = 0;
@@ -1209,6 +1209,179 @@ insert_regs (rtx x, struct table_elt *classp, int modified)
     return mention_regs (x);
 }
 \f
+
+/* Compute upper and lower anchors for CST.  Also compute the offset of CST
+   from these anchors/bases such that *_BASE + *_OFFS = CST.  Return false iff
+   CST is equal to an anchor.  */
+
+static bool
+compute_const_anchors (rtx cst,
+                      HOST_WIDE_INT *lower_base, HOST_WIDE_INT *lower_offs,
+                      HOST_WIDE_INT *upper_base, HOST_WIDE_INT *upper_offs)
+{
+  HOST_WIDE_INT n = INTVAL (cst);
+
+  *lower_base = n & ~(targetm.const_anchor - 1);
+  if (*lower_base == n)
+    return false;
+
+  *upper_base =
+    (n + (targetm.const_anchor - 1)) & ~(targetm.const_anchor - 1);
+  *upper_offs = n - *upper_base;
+  *lower_offs = n - *lower_base;
+  return true;
+}
+
+/* Insert the equivalence between ANCHOR and (REG + OFF) in mode MODE.  */
+
+static void
+insert_const_anchor (HOST_WIDE_INT anchor, rtx reg, HOST_WIDE_INT offs,
+                    enum machine_mode mode)
+{
+  struct table_elt *elt;
+  unsigned hash;
+  rtx anchor_exp;
+  rtx exp;
+
+  anchor_exp = GEN_INT (anchor);
+  hash = HASH (anchor_exp, mode);
+  elt = lookup (anchor_exp, hash, mode);
+  if (!elt)
+    elt = insert (anchor_exp, NULL, hash, mode);
+
+  exp = plus_constant (mode, reg, offs);
+  /* REG has just been inserted and the hash codes recomputed.  */
+  mention_regs (exp);
+  hash = HASH (exp, mode);
+
+  /* Use the cost of the register rather than the whole expression.  When
+     looking up constant anchors we will further offset the corresponding
+     expression therefore it does not make sense to prefer REGs over
+     reg-immediate additions.  Prefer instead the oldest expression.  Also
+     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);
+}
+
+/* The constant CST is equivalent to the register REG.  Create
+   equivalences between the two anchors of CST and the corresponding
+   register-offset expressions using REG.  */
+
+static void
+insert_const_anchors (rtx reg, rtx cst, enum machine_mode mode)
+{
+  HOST_WIDE_INT lower_base, lower_offs, upper_base, upper_offs;
+
+  if (!compute_const_anchors (cst, &lower_base, &lower_offs,
+                             &upper_base, &upper_offs))
+      return;
+
+  /* Ignore anchors of value 0.  Constants accessible from zero are
+     simple.  */
+  if (lower_base != 0)
+    insert_const_anchor (lower_base, reg, -lower_offs, mode);
+
+  if (upper_base != 0)
+    insert_const_anchor (upper_base, reg, -upper_offs, mode);
+}
+
+/* We need to express ANCHOR_ELT->exp + OFFS.  Walk the equivalence list of
+   ANCHOR_ELT and see if offsetting any of the entries by OFFS would create a
+   valid expression.  Return the cheapest and oldest of such expressions.  In
+   *OLD, return how old the resulting expression is compared to the other
+   equivalent expressions.  */
+
+static rtx
+find_reg_offset_for_const (struct table_elt *anchor_elt, HOST_WIDE_INT offs,
+                          unsigned *old)
+{
+  struct table_elt *elt;
+  unsigned idx;
+  struct table_elt *match_elt;
+  rtx match;
+
+  /* Find the cheapest and *oldest* expression to maximize the chance of
+     reusing the same pseudo.  */
+
+  match_elt = NULL;
+  match = NULL_RTX;
+  for (elt = anchor_elt->first_same_value, idx = 0;
+       elt;
+       elt = elt->next_same_value, idx++)
+    {
+      if (match_elt && CHEAPER (match_elt, elt))
+       return match;
+
+      if (REG_P (elt->exp)
+         || (GET_CODE (elt->exp) == PLUS
+             && REG_P (XEXP (elt->exp, 0))
+             && GET_CODE (XEXP (elt->exp, 1)) == CONST_INT))
+       {
+         rtx x;
+
+         /* Ignore expressions that are no longer valid.  */
+         if (!REG_P (elt->exp) && !exp_equiv_p (elt->exp, elt->exp, 1, false))
+           continue;
+
+         x = plus_constant (GET_MODE (elt->exp), elt->exp, offs);
+         if (REG_P (x)
+             || (GET_CODE (x) == PLUS
+                 && IN_RANGE (INTVAL (XEXP (x, 1)),
+                              -targetm.const_anchor,
+                              targetm.const_anchor - 1)))
+           {
+             match = x;
+             match_elt = elt;
+             *old = idx;
+           }
+       }
+    }
+
+  return match;
+}
+
+/* Try to express the constant SRC_CONST using a register+offset expression
+   derived from a constant anchor.  Return it if successful or NULL_RTX,
+   otherwise.  */
+
+static rtx
+try_const_anchors (rtx src_const, enum machine_mode mode)
+{
+  struct table_elt *lower_elt, *upper_elt;
+  HOST_WIDE_INT lower_base, lower_offs, upper_base, upper_offs;
+  rtx lower_anchor_rtx, upper_anchor_rtx;
+  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;
+
+  lower_anchor_rtx = GEN_INT (lower_base);
+  upper_anchor_rtx = GEN_INT (upper_base);
+  lower_elt = lookup (lower_anchor_rtx, HASH (lower_anchor_rtx, mode), mode);
+  upper_elt = lookup (upper_anchor_rtx, HASH (upper_anchor_rtx, mode), mode);
+
+  if (lower_elt)
+    lower_exp = find_reg_offset_for_const (lower_elt, lower_offs, &lower_old);
+  if (upper_elt)
+    upper_exp = find_reg_offset_for_const (upper_elt, upper_offs, &upper_old);
+
+  if (!lower_exp)
+    return upper_exp;
+  if (!upper_exp)
+    return lower_exp;
+
+  /* Return the older expression.  */
+  return (upper_old > lower_old ? upper_exp : lower_exp);
+}
+\f
 /* Look in or update the hash table.  */
 
 /* Remove table element ELT from use in the table.
@@ -1376,11 +1549,11 @@ lookup_as_function (rtx x, enum rtx_code code)
   return 0;
 }
 
-/* Insert X in the hash table, assuming HASH is its hash code
-   and CLASSP is an element of the class it should go in
-   (or 0 if a new class should be made).
-   It is inserted at the proper position to keep the class in
-   the order cheapest first.
+/* Insert X in the hash table, assuming HASH is its hash code and
+   CLASSP is an element of the class it should go in (or 0 if a new
+   class should be made).  COST is the code of X and reg_cost is the
+   cost of registers in X.  It is inserted at the proper position to
+   keep the class in the order cheapest first.
 
    MODE is the machine-mode of X, or if X is an integer constant
    with VOIDmode then MODE is the mode with which X will be used.
@@ -1400,11 +1573,9 @@ lookup_as_function (rtx x, enum rtx_code code)
 
    If necessary, update table showing constant values of quantities.  */
 
-#define CHEAPER(X, Y) \
- (preferable ((X)->cost, (X)->regcost, (Y)->cost, (Y)->regcost) < 0)
-
 static struct table_elt *
-insert (rtx x, struct table_elt *classp, unsigned int hash, enum machine_mode mode)
+insert_with_costs (rtx x, struct table_elt *classp, unsigned int hash,
+                  enum machine_mode mode, int cost, int reg_cost)
 {
   struct table_elt *elt;
 
@@ -1426,8 +1597,8 @@ insert (rtx x, struct table_elt *classp, unsigned int hash, enum machine_mode mo
 
   elt->exp = x;
   elt->canon_exp = NULL_RTX;
-  elt->cost = COST (x);
-  elt->regcost = approx_reg_cost (x);
+  elt->cost = cost;
+  elt->regcost = reg_cost;
   elt->next_same_value = 0;
   elt->prev_same_value = 0;
   elt->next_same_hash = table[hash];
@@ -1462,8 +1633,10 @@ insert (rtx x, struct table_elt *classp, unsigned int hash, enum machine_mode mo
          /* Put it after the last element cheaper than X.  */
          struct table_elt *p, *next;
 
-         for (p = classp; (next = p->next_same_value) && CHEAPER (next, elt);
-              p = next);
+         for (p = classp;
+              (next = p->next_same_value) && CHEAPER (next, elt);
+              p = next)
+           ;
 
          /* Put it after P and before NEXT.  */
          elt->next_same_value = next;
@@ -1562,6 +1735,17 @@ insert (rtx x, struct table_elt *classp, unsigned int hash, enum machine_mode mo
 
   return elt;
 }
+
+/* Wrap insert_with_costs by passing the default costs.  */
+
+static struct table_elt *
+insert (rtx x, struct table_elt *classp, unsigned int hash,
+       enum machine_mode mode)
+{
+  return
+    insert_with_costs (x, classp, hash, mode, COST (x), approx_reg_cost (x));
+}
+
 \f
 /* Given two equivalence classes, CLASS1 and CLASS2, put all the entries from
    CLASS2 into CLASS1.  This is done when we have reached an insn which makes
@@ -1645,7 +1829,7 @@ flush_hash_table (void)
       }
 }
 \f
-/* Function called for each rtx to check whether true dependence exist.  */
+/* Function called for each rtx to check whether an anti dependence exist.  */
 struct check_dependence_data
 {
   enum machine_mode mode;
@@ -1658,8 +1842,7 @@ check_dependence (rtx *x, void *data)
 {
   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,
-                                 cse_rtx_varies_p);
+    return canon_anti_dependence (*x, true, d->exp, d->mode, d->addr);
   else
     return 0;
 }
@@ -1916,24 +2099,22 @@ invalidate_for_call (void)
   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
      reg_tick if defined.  Also see if any of these registers is currently
      in the table.  */
-
-  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
-    if (TEST_HARD_REG_BIT (regs_invalidated_by_call, regno))
-      {
-       delete_reg_equiv (regno);
-       if (REG_TICK (regno) >= 0)
-         {
-           REG_TICK (regno)++;
-           SUBREG_TICKED (regno) = -1;
-         }
-
-       in_table |= (TEST_HARD_REG_BIT (hard_regs_in_table, regno) != 0);
-      }
+  EXECUTE_IF_SET_IN_HARD_REG_SET (regs_invalidated_by_call, 0, regno, hrsi)
+    {
+      delete_reg_equiv (regno);
+      if (REG_TICK (regno) >= 0)
+       {
+         REG_TICK (regno)++;
+         SUBREG_TICKED (regno) = -1;
+       }
+      in_table |= (TEST_HARD_REG_BIT (hard_regs_in_table, regno) != 0);
+    }
 
   /* In the case where we have no call-clobbered hard registers in the
      table, we are done.  Otherwise, scan the table and remove any
@@ -2031,7 +2212,7 @@ use_related_value (rtx x, struct table_elt *elt)
 
   offset = (get_integer_term (x) - get_integer_term (p->exp));
   /* Note: OFFSET may be 0 if P->xexp and X are related by commutativity.  */
-  return plus_constant (q->exp, offset);
+  return plus_constant (q->mode, q->exp, offset);
 }
 \f
 
@@ -2049,7 +2230,7 @@ hash_rtx_string (const char *ps)
   return hash;
 }
 
-/* Same as hash_rtx, but call CB on each rtx if it is not NULL.  
+/* Same as hash_rtx, but call CB on each rtx if it is not NULL.
    When the callback returns true, we continue with the new rtx.  */
 
 unsigned
@@ -2072,7 +2253,7 @@ hash_rtx_cb (const_rtx x, enum machine_mode mode,
     return hash;
 
   /* Invoke the callback first.  */
-  if (cb != NULL 
+  if (cb != NULL
       && ((*cb) (x, mode, &newx, &newmode)))
     {
       hash += hash_rtx_cb (newx, newmode, do_not_record_p,
@@ -2099,7 +2280,7 @@ hash_rtx_cb (const_rtx x, enum machine_mode mode,
 
               On all machines, we can't record any global registers.
               Nor should we record any register that is in a small
-              class, as defined by CLASS_LIKELY_SPILLED_P.  */
+              class, as defined by TARGET_CLASS_LIKELY_SPILLED_P.  */
            bool record;
 
            if (regno >= FIRST_PSEUDO_REGISTER)
@@ -2116,9 +2297,9 @@ hash_rtx_cb (const_rtx x, enum machine_mode mode,
              record = true;
            else if (GET_MODE_CLASS (GET_MODE (x)) == MODE_CC)
              record = true;
-           else if (SMALL_REGISTER_CLASSES)
+           else if (targetm.small_register_classes_for_mode_p (GET_MODE (x)))
              record = false;
-           else if (CLASS_LIKELY_SPILLED_P (REGNO_REG_CLASS (regno)))
+           else if (targetm.class_likely_spilled_p (REGNO_REG_CLASS (regno)))
              record = false;
            else
              record = true;
@@ -2182,7 +2363,7 @@ hash_rtx_cb (const_rtx x, enum machine_mode mode,
          {
            elt = CONST_VECTOR_ELT (x, i);
            hash += hash_rtx_cb (elt, GET_MODE (elt),
-                                 do_not_record_p, hash_arg_in_memory_p, 
+                                 do_not_record_p, hash_arg_in_memory_p,
                                  have_reg_qty, cb);
          }
 
@@ -2328,7 +2509,7 @@ hash_rtx_cb (const_rtx x, enum machine_mode mode,
              x = XEXP (x, i);
              goto repeat;
            }
-          
+
          hash += hash_rtx_cb (XEXP (x, i), VOIDmode, do_not_record_p,
                                hash_arg_in_memory_p,
                                have_reg_qty, cb);
@@ -2369,7 +2550,7 @@ hash_rtx_cb (const_rtx x, enum machine_mode mode,
    Store 1 in DO_NOT_RECORD_P if any subexpression is volatile.
 
    If HASH_ARG_IN_MEMORY_P is not NULL, store 1 in it if X contains
-   a MEM rtx which does not have the RTX_UNCHANGING_P bit set.
+   a MEM rtx which does not have the MEM_READONLY_P flag set.
 
    Note that cse_insn knows that the hash code of a MEM expression
    is just (int) MEM plus the hash code of the address.  */
@@ -2385,7 +2566,7 @@ hash_rtx (const_rtx x, enum machine_mode mode, int *do_not_record_p,
 /* Hash an rtx X for cse via hash_rtx.
    Stores 1 in do_not_record if any subexpression is volatile.
    Stores 1 in hash_arg_in_memory if X contains a mem rtx which
-   does not have the RTX_UNCHANGING_P bit set.  */
+   does not have the MEM_READONLY_P flag set.  */
 
 static inline unsigned
 canon_hash (rtx x, enum machine_mode mode)
@@ -2435,13 +2616,15 @@ exp_equiv_p (const_rtx x, const_rtx y, int validate, bool for_gcse)
   if (GET_MODE (x) != GET_MODE (y))
     return 0;
 
+  /* MEMs referring to different address space are not equivalent.  */
+  if (code == MEM && MEM_ADDR_SPACE (x) != MEM_ADDR_SPACE (y))
+    return 0;
+
   switch (code)
     {
     case PC:
     case CC0:
-    case CONST_INT:
-    case CONST_DOUBLE:
-    case CONST_FIXED:
+    CASE_CONST_UNIQUE:
       return x == y;
 
     case LABEL_REF:
@@ -2492,8 +2675,8 @@ exp_equiv_p (const_rtx x, const_rtx y, int validate, bool for_gcse)
             They could e.g. be two different entities allocated into the
             same space on the stack (see e.g. PR25130).  In that case, the
             MEM addresses can be the same, even though the two MEMs are
-            absolutely not equivalent.  
-   
+            absolutely not equivalent.
+
             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.  */
@@ -2602,67 +2785,6 @@ exp_equiv_p (const_rtx x, const_rtx y, int validate, bool for_gcse)
   return 1;
 }
 \f
-/* Return 1 if X has a value that can vary even between two
-   executions of the program.  0 means X can be compared reliably
-   against certain constants or near-constants.  */
-
-static bool
-cse_rtx_varies_p (const_rtx x, bool from_alias)
-{
-  /* We need not check for X and the equivalence class being of the same
-     mode because if X is equivalent to a constant in some mode, it
-     doesn't vary in any mode.  */
-
-  if (REG_P (x)
-      && REGNO_QTY_VALID_P (REGNO (x)))
-    {
-      int x_q = REG_QTY (REGNO (x));
-      struct qty_table_elem *x_ent = &qty_table[x_q];
-
-      if (GET_MODE (x) == x_ent->mode
-         && x_ent->const_rtx != NULL_RTX)
-       return 0;
-    }
-
-  if (GET_CODE (x) == PLUS
-      && GET_CODE (XEXP (x, 1)) == CONST_INT
-      && REG_P (XEXP (x, 0))
-      && REGNO_QTY_VALID_P (REGNO (XEXP (x, 0))))
-    {
-      int x0_q = REG_QTY (REGNO (XEXP (x, 0)));
-      struct qty_table_elem *x0_ent = &qty_table[x0_q];
-
-      if ((GET_MODE (XEXP (x, 0)) == x0_ent->mode)
-         && x0_ent->const_rtx != NULL_RTX)
-       return 0;
-    }
-
-  /* This can happen as the result of virtual register instantiation, if
-     the initial constant is too large to be a valid address.  This gives
-     us a three instruction sequence, load large offset into a register,
-     load fp minus a constant into a register, then a MEM which is the
-     sum of the two `constant' registers.  */
-  if (GET_CODE (x) == PLUS
-      && REG_P (XEXP (x, 0))
-      && REG_P (XEXP (x, 1))
-      && REGNO_QTY_VALID_P (REGNO (XEXP (x, 0)))
-      && REGNO_QTY_VALID_P (REGNO (XEXP (x, 1))))
-    {
-      int x0_q = REG_QTY (REGNO (XEXP (x, 0)));
-      int x1_q = REG_QTY (REGNO (XEXP (x, 1)));
-      struct qty_table_elem *x0_ent = &qty_table[x0_q];
-      struct qty_table_elem *x1_ent = &qty_table[x1_q];
-
-      if ((GET_MODE (XEXP (x, 0)) == x0_ent->mode)
-         && x0_ent->const_rtx != NULL_RTX
-         && (GET_MODE (XEXP (x, 1)) == x1_ent->mode)
-         && x1_ent->const_rtx != NULL_RTX)
-       return 0;
-    }
-
-  return rtx_varies_p (x, from_alias);
-}
-\f
 /* Subroutine of canon_reg.  Pass *XLOC through canon_reg, and validate
    the result if necessary.  INSN is as for canon_reg.  */
 
@@ -2706,10 +2828,7 @@ canon_reg (rtx x, rtx insn)
     case PC:
     case CC0:
     case CONST:
-    case CONST_INT:
-    case CONST_DOUBLE:
-    case CONST_FIXED:
-    case CONST_VECTOR:
+    CASE_CONST_ANY:
     case SYMBOL_REF:
     case LABEL_REF:
     case ADDR_VEC:
@@ -2775,6 +2894,9 @@ find_comparison_args (enum rtx_code code, rtx *parg1, rtx *parg2,
                      enum machine_mode *pmode1, enum machine_mode *pmode2)
 {
   rtx arg1, arg2;
+  struct pointer_set_t *visited = NULL;
+  /* Set nonzero when we find something of interest.  */
+  rtx x = NULL;
 
   arg1 = *parg1, arg2 = *parg2;
 
@@ -2782,11 +2904,18 @@ find_comparison_args (enum rtx_code code, rtx *parg1, rtx *parg2,
 
   while (arg2 == CONST0_RTX (GET_MODE (arg1)))
     {
-      /* Set nonzero when we find something of interest.  */
-      rtx x = 0;
       int reverse_code = 0;
       struct table_elt *p = 0;
 
+      /* Remember state from previous iteration.  */
+      if (x)
+       {
+         if (!visited)
+           visited = pointer_set_create ();
+         pointer_set_insert (visited, 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
@@ -2863,6 +2992,10 @@ find_comparison_args (enum rtx_code code, rtx *parg1, rtx *parg2,
          if (! exp_equiv_p (p->exp, p->exp, 1, false))
            continue;
 
+         /* If it's a comparison we've used before, skip it.  */
+         if (visited && pointer_set_contains (visited, p->exp))
+           continue;
+
          if (GET_CODE (p->exp) == COMPARE
              /* Another possibility is that this machine has a compare insn
                 that includes the comparison code.  In that case, ARG1 would
@@ -2873,12 +3006,8 @@ find_comparison_args (enum rtx_code code, rtx *parg1, rtx *parg2,
                 for STORE_FLAG_VALUE, also look at LT and GE operations.  */
              || ((code == NE
                   || (code == LT
-                      && GET_MODE_CLASS (inner_mode) == MODE_INT
-                      && (GET_MODE_BITSIZE (inner_mode)
-                          <= HOST_BITS_PER_WIDE_INT)
-                      && (STORE_FLAG_VALUE
-                          & ((HOST_WIDE_INT) 1
-                             << (GET_MODE_BITSIZE (inner_mode) - 1))))
+                      && val_signbit_known_set_p (inner_mode,
+                                                  STORE_FLAG_VALUE))
 #ifdef FLOAT_STORE_FLAG_VALUE
                   || (code == LT
                       && SCALAR_FLOAT_MODE_P (inner_mode)
@@ -2893,12 +3022,8 @@ find_comparison_args (enum rtx_code code, rtx *parg1, rtx *parg2,
            }
          else if ((code == EQ
                    || (code == GE
-                       && GET_MODE_CLASS (inner_mode) == MODE_INT
-                       && (GET_MODE_BITSIZE (inner_mode)
-                           <= HOST_BITS_PER_WIDE_INT)
-                       && (STORE_FLAG_VALUE
-                           & ((HOST_WIDE_INT) 1
-                              << (GET_MODE_BITSIZE (inner_mode) - 1))))
+                       && val_signbit_known_set_p (inner_mode,
+                                                   STORE_FLAG_VALUE))
 #ifdef FLOAT_STORE_FLAG_VALUE
                    || (code == GE
                        && SCALAR_FLOAT_MODE_P (inner_mode)
@@ -2949,6 +3074,8 @@ find_comparison_args (enum rtx_code code, rtx *parg1, rtx *parg2,
   *pmode1 = GET_MODE (arg1), *pmode2 = GET_MODE (arg2);
   *parg1 = fold_rtx (arg1, 0), *parg2 = fold_rtx (arg2, 0);
 
+  if (visited)
+    pointer_set_destroy (visited);
   return code;
 }
 \f
@@ -3002,10 +3129,7 @@ fold_rtx (rtx x, rtx insn)
       return x;
 
     case CONST:
-    case CONST_INT:
-    case CONST_DOUBLE:
-    case CONST_FIXED:
-    case CONST_VECTOR:
+    CASE_CONST_ANY:
     case SYMBOL_REF:
     case LABEL_REF:
     case REG:
@@ -3067,12 +3191,9 @@ fold_rtx (rtx x, rtx insn)
            break;
 
          case CONST:
-         case CONST_INT:
+         CASE_CONST_ANY:
          case SYMBOL_REF:
          case LABEL_REF:
-         case CONST_DOUBLE:
-         case CONST_FIXED:
-         case CONST_VECTOR:
            const_arg = folded_arg;
            break;
 
@@ -3112,7 +3233,7 @@ fold_rtx (rtx x, rtx insn)
           argument.  */
        if (const_arg != 0
            && const_arg != folded_arg
-           && COST_IN (const_arg, code) <= COST_IN (folded_arg, code)
+           && COST_IN (const_arg, code, i) <= COST_IN (folded_arg, code, i)
 
            /* It's not safe to substitute the operand of a conversion
               operator with a constant, as the conversion's identity
@@ -3167,8 +3288,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;
 
@@ -3235,7 +3356,7 @@ fold_rtx (rtx x, rtx insn)
                     constant through simplifications.  */
                  p = lookup (folded_arg0, SAFE_HASH (folded_arg0, mode_arg0),
                              mode_arg0);
-                 
+
                  if (p != NULL)
                    {
                      cheapest_simplification = x;
@@ -3337,15 +3458,16 @@ fold_rtx (rtx x, rtx insn)
 
          if (y != 0
              && (inner_const = equiv_constant (XEXP (y, 1))) != 0
-             && GET_CODE (inner_const) == CONST_INT
+             && CONST_INT_P (inner_const)
              && INTVAL (inner_const) != 0)
            folded_arg0 = gen_rtx_IOR (mode_arg0, XEXP (y, 0), inner_const);
        }
 
       {
-       rtx op0 = const_arg0 ? const_arg0 : folded_arg0;
-       rtx op1 = const_arg1 ? const_arg1 : folded_arg1;
-        new_rtx = simplify_relational_operation (code, mode, mode_arg0, op0, op1);
+       rtx op0 = const_arg0 ? const_arg0 : copy_rtx (folded_arg0);
+       rtx op1 = const_arg1 ? const_arg1 : copy_rtx (folded_arg1);
+       new_rtx = simplify_relational_operation (code, mode, mode_arg0,
+                                                op0, op1);
       }
       break;
 
@@ -3407,7 +3529,7 @@ fold_rtx (rtx x, rtx insn)
             the smallest negative number this would overflow: depending
             on the mode, this would either just be the same value (and
             hence not save anything) or be incorrect.  */
-         if (const_arg1 != 0 && GET_CODE (const_arg1) == CONST_INT
+         if (const_arg1 != 0 && CONST_INT_P (const_arg1)
              && INTVAL (const_arg1) < 0
              /* This used to test
 
@@ -3435,11 +3557,11 @@ fold_rtx (rtx x, rtx insn)
        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 && GET_CODE (const_arg1) == CONST_INT)
+         if (const_arg1 != 0 && CONST_INT_P (const_arg1))
            {
              rtx y = lookup_as_function (XEXP (x, 0), PLUS);
-             if (y && GET_CODE (XEXP (y, 1)) == CONST_INT)
-               return fold_rtx (plus_constant (copy_rtx (y),
+             if (y && CONST_INT_P (XEXP (y, 1)))
+               return fold_rtx (plus_constant (mode, copy_rtx (y),
                                                -INTVAL (const_arg1)),
                                 NULL_RTX);
            }
@@ -3459,7 +3581,7 @@ fold_rtx (rtx x, rtx insn)
             if the intermediate operation's result has only one reference.  */
 
          if (REG_P (folded_arg0)
-             && const_arg1 && GET_CODE (const_arg1) == CONST_INT)
+             && const_arg1 && CONST_INT_P (const_arg1))
            {
              int is_shift
                = (code == ASHIFT || code == ASHIFTRT || code == LSHIFTRT);
@@ -3468,7 +3590,7 @@ fold_rtx (rtx x, rtx insn)
              enum rtx_code associate_code;
 
              if (is_shift
-                 && (INTVAL (const_arg1) >= GET_MODE_BITSIZE (mode)
+                 && (INTVAL (const_arg1) >= GET_MODE_PRECISION (mode)
                      || INTVAL (const_arg1) < 0))
                {
                  if (SHIFT_COUNT_TRUNCATED)
@@ -3492,7 +3614,7 @@ fold_rtx (rtx x, rtx insn)
                break;
 
              inner_const = equiv_constant (fold_rtx (XEXP (y, 1), 0));
-             if (!inner_const || GET_CODE (inner_const) != CONST_INT)
+             if (!inner_const || !CONST_INT_P (inner_const))
                break;
 
              /* Don't associate these operations if they are a PLUS with the
@@ -3517,7 +3639,7 @@ fold_rtx (rtx x, rtx insn)
                 break;
 
              if (is_shift
-                 && (INTVAL (inner_const) >= GET_MODE_BITSIZE (mode)
+                 && (INTVAL (inner_const) >= GET_MODE_PRECISION (mode)
                      || INTVAL (inner_const) < 0))
                {
                  if (SHIFT_COUNT_TRUNCATED)
@@ -3546,8 +3668,8 @@ fold_rtx (rtx x, rtx insn)
                 of shifts.  */
 
              if (is_shift
-                 && GET_CODE (new_const) == CONST_INT
-                 && INTVAL (new_const) >= GET_MODE_BITSIZE (mode))
+                 && CONST_INT_P (new_const)
+                 && INTVAL (new_const) >= GET_MODE_PRECISION (mode))
                {
                  /* As an exception, we can turn an ASHIFTRT of this
                     form into a shift of the number of bits - 1.  */
@@ -3658,8 +3780,12 @@ equiv_constant (rtx x)
            }
        }
 
-      /* Otherwise see if we already have a constant for the inner REG.  */
+      /* Otherwise see if we already have a constant for the inner REG,
+        and if that is enough to calculate an equivalent constant for
+        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)
          && (new_rtx = equiv_constant (SUBREG_REG (x))) != 0)
         return simplify_subreg (mode, new_rtx, imode, SUBREG_BYTE (x));
 
@@ -3777,9 +3903,7 @@ record_jump_cond (enum rtx_code code, enum machine_mode mode, rtx op0,
      is not worth testing for with no SUBREG).  */
 
   /* Note that GET_MODE (op0) may not equal MODE.  */
-  if (code == EQ && GET_CODE (op0) == SUBREG
-      && (GET_MODE_SIZE (GET_MODE (op0))
-         > GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0)))))
+  if (code == EQ && paradoxical_subreg_p (op0))
     {
       enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op0));
       rtx tem = record_jump_cond_subreg (inner_mode, op1);
@@ -3788,9 +3912,7 @@ record_jump_cond (enum rtx_code code, enum machine_mode mode, rtx op0,
                          reversed_nonequality);
     }
 
-  if (code == EQ && GET_CODE (op1) == SUBREG
-      && (GET_MODE_SIZE (GET_MODE (op1))
-         > GET_MODE_SIZE (GET_MODE (SUBREG_REG (op1)))))
+  if (code == EQ && paradoxical_subreg_p (op1))
     {
       enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op1));
       rtx tem = record_jump_cond_subreg (inner_mode, op0);
@@ -3966,10 +4088,22 @@ record_jump_cond (enum rtx_code code, enum machine_mode mode, rtx op0,
 }
 \f
 /* CSE processing for one instruction.
-   First simplify sources and addresses of all assignments
-   in the instruction, using previously-computed equivalents values.
-   Then install the new sources and destinations in the table
-   of available values.  */
+
+   Most "true" common subexpressions are mostly optimized away in GIMPLE,
+   but the few that "leak through" are cleaned up by cse_insn, and complex
+   addressing modes are often formed here.
+
+   The main function is cse_insn, and between here and that function
+   a couple of helper functions is defined to keep the size of cse_insn
+   within reasonable proportions.
+   
+   Data is shared between the main and helper functions via STRUCT SET,
+   that contains all data related for every set in the instruction that
+   is being processed.
+   
+   Note that cse_main processes all sets in the instruction.  Most
+   passes in GCC only process simple SET insns or single_set insns, but
+   CSE processes insns with multiple sets as well.  */
 
 /* Data on one SET contained in the instruction.  */
 
@@ -4005,50 +4139,93 @@ struct set
   /* Table entry for the destination address.  */
   struct table_elt *dest_addr_elt;
 };
+\f
+/* Special handling for (set REG0 REG1) where REG0 is the
+   "cheapest", cheaper than REG1.  After cse, REG1 will probably not
+   be used in the sequel, so (if easily done) change this insn to
+   (set REG1 REG0) and replace REG1 with REG0 in the previous insn
+   that computed their value.  Then REG1 will become a dead store
+   and won't cloud the situation for later optimizations.
+
+   Do not make this change if REG1 is a hard register, because it will
+   then be used in the sequel and we may be changing a two-operand insn
+   into a three-operand insn.
+   
+   This is the last transformation that cse_insn will try to do.  */
 
 static void
-cse_insn (rtx insn)
+try_back_substitute_reg (rtx set, rtx insn)
 {
-  rtx x = PATTERN (insn);
-  int i;
-  rtx tem;
-  int n_sets = 0;
+  rtx dest = SET_DEST (set);
+  rtx src = SET_SRC (set);
 
-  rtx src_eqv = 0;
-  struct table_elt *src_eqv_elt = 0;
-  int src_eqv_volatile = 0;
-  int src_eqv_in_memory = 0;
-  unsigned src_eqv_hash = 0;
+  if (REG_P (dest)
+      && REG_P (src) && ! HARD_REGISTER_P (src)
+      && REGNO_QTY_VALID_P (REGNO (src)))
+    {
+      int src_q = REG_QTY (REGNO (src));
+      struct qty_table_elem *src_ent = &qty_table[src_q];
 
-  struct set *sets = (struct set *) 0;
+      if (src_ent->first_reg == REGNO (dest))
+       {
+         /* 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));
+         do
+           {
+             prev = PREV_INSN (prev);
+           }
+         while (prev != bb_head && (NOTE_P (prev) || DEBUG_INSN_P (prev)));
 
-  this_insn = insn;
-#ifdef HAVE_cc0
-  /* Records what this insn does to set CC0.  */
-  this_insn_cc0 = 0;
-  this_insn_cc0_mode = VOIDmode;
-#endif
+         /* Do not swap the registers around if the previous instruction
+            attaches a REG_EQUIV note to REG1.
+
+            ??? It's not entirely clear whether we can transfer a REG_EQUIV
+            from the pseudo that originally shadowed an incoming argument
+            to another register.  Some uses of REG_EQUIV might rely on it
+            being attached to REG1 rather than REG2.
 
-  /* Find all the SETs and CLOBBERs in this instruction.
-     Record all the SETs in the array `set' and count them.
-     Also determine whether there is a CLOBBER that invalidates
-     all memory references, or all references at varying addresses.  */
+            This section previously turned the REG_EQUIV into a REG_EQUAL
+            note.  We cannot do that because REG_EQUIV may provide an
+            uninitialized stack slot when REG_PARM_STACK_SPACE is used.  */
+         if (NONJUMP_INSN_P (prev)
+             && GET_CODE (PATTERN (prev)) == SET
+             && SET_DEST (PATTERN (prev)) == src
+             && ! find_reg_note (prev, REG_EQUIV, NULL_RTX))
+           {
+             rtx note;
 
-  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);
-         XEXP (tem, 0) = canon_reg (XEXP (tem, 0), insn);
+             validate_change (prev, &SET_DEST (PATTERN (prev)), dest, 1);
+             validate_change (insn, &SET_DEST (set), src, 1);
+             validate_change (insn, &SET_SRC (set), dest, 1);
+             apply_change_group ();
+
+             /* If INSN has a REG_EQUAL note, and this note mentions
+                REG0, then we must delete it, because the value in
+                REG0 has changed.  If the note's value is REG1, we must
+                also delete it because that is now this insn's dest.  */
+             note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
+             if (note != 0
+                 && (reg_mentioned_p (dest, XEXP (note, 0))
+                     || rtx_equal_p (src, XEXP (note, 0))))
+               remove_note (insn, note);
+           }
        }
     }
+}
+\f
+/* 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)
+{
+  struct set *sets = *psets;
+  int n_sets = 0;
+  rtx x = PATTERN (insn);
 
   if (GET_CODE (x) == SET)
     {
-      sets = XALLOCA (struct set);
-      sets[0].rtl = x;
-
       /* Ignore SETs that are unconditional jumps.
         They never need cse processing, so this does not hurt.
         The reason is not efficiency but rather
@@ -4059,57 +4236,20 @@ cse_insn (rtx insn)
       if (SET_DEST (x) == pc_rtx
          && GET_CODE (SET_SRC (x)) == LABEL_REF)
        ;
-
       /* Don't count call-insns, (set (reg 0) (call ...)), as a set.
         The hard function value register is used only once, to copy to
-        someplace else, so it isn't worth cse'ing (and on 80386 is unsafe)!
-        Ensure we invalidate the destination register.  On the 80386 no
-        other code would invalidate it since it is a fixed_reg.
-        We need not check the return of apply_change_group; see canon_reg.  */
-
+        someplace else, so it isn't worth cse'ing.  */
       else if (GET_CODE (SET_SRC (x)) == CALL)
-       {
-         canon_reg (SET_SRC (x), insn);
-         apply_change_group ();
-         fold_rtx (SET_SRC (x), insn);
-         invalidate (SET_DEST (x), VOIDmode);
-       }
+       ;
       else
-       n_sets = 1;
+       sets[n_sets++].rtl = x;
     }
   else if (GET_CODE (x) == PARALLEL)
     {
-      int lim = XVECLEN (x, 0);
-
-      sets = XALLOCAVEC (struct set, lim);
-
-      /* Find all regs explicitly clobbered in this insn,
-        and ensure they are not replaced with any other regs
-        elsewhere in this insn.
-        When a reg that is clobbered is also used for input,
-        we should presume that that is for a reason,
-        and we should not substitute some other register
-        which is not supposed to be clobbered.
-        Therefore, this loop cannot be merged into the one below
-        because a CALL may precede a CLOBBER and refer to the
-        value clobbered.  We must not let a canonicalization do
-        anything in that case.  */
-      for (i = 0; i < lim; i++)
-       {
-         rtx y = XVECEXP (x, 0, i);
-         if (GET_CODE (y) == CLOBBER)
-           {
-             rtx clobbered = XEXP (y, 0);
-
-             if (REG_P (clobbered)
-                 || GET_CODE (clobbered) == SUBREG)
-               invalidate (clobbered, VOIDmode);
-             else if (GET_CODE (clobbered) == STRICT_LOW_PART
-                      || GET_CODE (clobbered) == ZERO_EXTRACT)
-               invalidate (XEXP (clobbered, 0), GET_MODE (clobbered));
-           }
-       }
+      int i, lim = XVECLEN (x, 0);
 
+      /* Go over the epressions of the PARALLEL in forward order, to
+        put them in the same order in the SETS array.  */
       for (i = 0; i < lim; i++)
        {
          rtx y = XVECEXP (x, 0, i);
@@ -4117,75 +4257,150 @@ cse_insn (rtx insn)
            {
              /* As above, we ignore unconditional jumps and call-insns and
                 ignore the result of apply_change_group.  */
-             if (GET_CODE (SET_SRC (y)) == CALL)
-               {
-                 canon_reg (SET_SRC (y), insn);
-                 apply_change_group ();
-                 fold_rtx (SET_SRC (y), insn);
-                 invalidate (SET_DEST (y), VOIDmode);
-               }
-             else if (SET_DEST (y) == pc_rtx
-                      && GET_CODE (SET_SRC (y)) == LABEL_REF)
+             if (SET_DEST (y) == pc_rtx
+                 && GET_CODE (SET_SRC (y)) == LABEL_REF)
+               ;
+             else if (GET_CODE (SET_SRC (y)) == CALL)
                ;
              else
                sets[n_sets++].rtl = y;
            }
-         else if (GET_CODE (y) == CLOBBER)
-           {
-             /* If we clobber memory, canon the address.
-                This does nothing when a register is clobbered
-                because we have already invalidated the reg.  */
-             if (MEM_P (XEXP (y, 0)))
-               canon_reg (XEXP (y, 0), insn);
-           }
-         else if (GET_CODE (y) == USE
-                  && ! (REG_P (XEXP (y, 0))
-                        && REGNO (XEXP (y, 0)) < FIRST_PSEUDO_REGISTER))
-           canon_reg (y, insn);
-         else if (GET_CODE (y) == CALL)
-           {
-             /* The result of apply_change_group can be ignored; see
-                canon_reg.  */
-             canon_reg (y, insn);
-             apply_change_group ();
-             fold_rtx (y, insn);
-           }
        }
     }
-  else if (GET_CODE (x) == CLOBBER)
-    {
-      if (MEM_P (XEXP (x, 0)))
-       canon_reg (XEXP (x, 0), insn);
-    }
 
-  /* Canonicalize a USE of a pseudo register or memory location.  */
+  return n_sets;
+}
+\f
+/* Where possible, substitute every register reference in the N_SETS
+   number of SETS in INSN with the 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
+   useful, simple form of CSE, to clean up warts from expanding GIMPLE
+   to RTL.  For instance, a CONST for an address is usually expanded
+   multiple times to loads into different registers, thus creating many
+   subexpressions of the form:
+
+   (set (reg1) (some_const))
+   (set (mem (... reg1 ...) (thing)))
+   (set (reg2) (some_const))
+   (set (mem (... reg2 ...) (thing)))
+
+   After canonicalizing, the code takes the following form:
+
+   (set (reg1) (some_const))
+   (set (mem (... reg1 ...) (thing)))
+   (set (reg2) (some_const))
+   (set (mem (... reg1 ...) (thing)))
+
+   The set to reg2 is now trivially dead, and the memory reference (or
+   address, or whatever) may be a candidate for further CSEing.
+
+   In this function, the result of apply_change_group can be ignored;
+   see canon_reg.  */
+
+static void
+canonicalize_insn (rtx insn, struct set **psets, int n_sets)
+{
+  struct set *sets = *psets;
+  rtx tem;
+  rtx x = PATTERN (insn);
+  int i;
+
+  if (CALL_P (insn))
+    {
+      for (tem = CALL_INSN_FUNCTION_USAGE (insn); tem; tem = XEXP (tem, 1))
+       if (GET_CODE (XEXP (tem, 0)) != SET)
+         XEXP (tem, 0) = canon_reg (XEXP (tem, 0), insn);
+    }
+
+  if (GET_CODE (x) == SET && GET_CODE (SET_SRC (x)) == CALL)
+    {
+      canon_reg (SET_SRC (x), insn);
+      apply_change_group ();
+      fold_rtx (SET_SRC (x), insn);
+    }
+  else if (GET_CODE (x) == CLOBBER)
+    {
+      /* If we clobber memory, canon the address.
+        This does nothing when a register is clobbered
+        because we have already invalidated the reg.  */
+      if (MEM_P (XEXP (x, 0)))
+       canon_reg (XEXP (x, 0), insn);
+    }
   else if (GET_CODE (x) == USE
           && ! (REG_P (XEXP (x, 0))
                 && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER))
-    canon_reg (XEXP (x, 0), insn);
+    /* 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);
+           }
+       }
+    }
   else if (GET_CODE (x) == CALL)
     {
-      /* The result of apply_change_group can be ignored; see canon_reg.  */
       canon_reg (x, insn);
       apply_change_group ();
       fold_rtx (x, insn);
     }
+  else if (DEBUG_INSN_P (insn))
+    canon_reg (PATTERN (insn), insn);
+  else if (GET_CODE (x) == PARALLEL)
+    {
+      for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
+       {
+         rtx y = XVECEXP (x, 0, i);
+         if (GET_CODE (y) == SET && GET_CODE (SET_SRC (y)) == CALL)
+           {
+             canon_reg (SET_SRC (y), insn);
+             apply_change_group ();
+             fold_rtx (SET_SRC (y), insn);
+           }
+         else if (GET_CODE (y) == CLOBBER)
+           {
+             if (MEM_P (XEXP (y, 0)))
+               canon_reg (XEXP (y, 0), insn);
+           }
+         else if (GET_CODE (y) == USE
+                  && ! (REG_P (XEXP (y, 0))
+                        && REGNO (XEXP (y, 0)) < FIRST_PSEUDO_REGISTER))
+           canon_reg (y, insn);
+         else if (GET_CODE (y) == CALL)
+           {
+             canon_reg (y, insn);
+             apply_change_group ();
+             fold_rtx (y, insn);
+           }
+       }
+    }
 
-  /* 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 (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))
+      && (tem = find_reg_note (insn, REG_EQUAL, NULL_RTX)) != 0)
     {
-      /* The result of apply_change_group can be ignored; see canon_reg.  */
-      canon_reg (XEXP (tem, 0), insn);
-      apply_change_group ();
-      src_eqv = fold_rtx (XEXP (tem, 0), insn);
-      XEXP (tem, 0) = copy_rtx (src_eqv);
-      df_notes_rescan (insn);
+      /* We potentially will process this insn many times.  Therefore,
+        drop the REG_EQUAL note if it is equal to the SET_SRC of the
+        unique set in INSN.
+
+        Do not do so if the REG_EQUAL note is for a STRICT_LOW_PART,
+        because cse_insn handles those specially.  */
+      if (GET_CODE (SET_DEST (sets[0].rtl)) != STRICT_LOW_PART
+         && rtx_equal_p (XEXP (tem, 0), SET_SRC (sets[0].rtl)))
+       remove_note (insn, tem);
+      else
+       {
+         canon_reg (XEXP (tem, 0), insn);
+         apply_change_group ();
+         XEXP (tem, 0) = fold_rtx (XEXP (tem, 0), insn);
+         df_notes_rescan (insn);
+       }
     }
 
   /* Canonicalize sources and addresses of destinations.
@@ -4232,6 +4447,62 @@ cse_insn (rtx insn)
      The result of apply_change_group can be ignored; see canon_reg.  */
 
   apply_change_group ();
+}
+\f
+/* Main function of CSE.
+   First simplify sources and addresses of all assignments
+   in the instruction, using previously-computed equivalents values.
+   Then install the new sources and destinations in the table
+   of available values.  */
+
+static void
+cse_insn (rtx insn)
+{
+  rtx x = PATTERN (insn);
+  int i;
+  rtx tem;
+  int n_sets = 0;
+
+  rtx src_eqv = 0;
+  struct table_elt *src_eqv_elt = 0;
+  int src_eqv_volatile = 0;
+  int src_eqv_in_memory = 0;
+  unsigned src_eqv_hash = 0;
+
+  struct set *sets = (struct set *) 0;
+
+  if (GET_CODE (x) == SET)
+    sets = XALLOCA (struct set);
+  else if (GET_CODE (x) == PARALLEL)
+    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
+     elsewhere in this insn.  */
+  invalidate_from_sets_and_clobbers (insn);
+
+  /* Record all the SETs in this instruction.  */
+  n_sets = find_sets_in_insn (insn, &sets);
+
+  /* Substitute the canonical register where possible.  */
+  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 (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));
 
   /* Set sets[i].src_elt to the class each source belongs to.
      Detect assignments from or to volatile things
@@ -4242,6 +4513,7 @@ cse_insn (rtx insn)
 
   for (i = 0; i < n_sets; i++)
     {
+      bool repeat = false;
       rtx src, dest;
       rtx src_folded;
       struct table_elt *elt = 0, *p;
@@ -4249,6 +4521,7 @@ cse_insn (rtx insn)
       rtx src_eqv_here;
       rtx src_const = 0;
       rtx src_related = 0;
+      bool src_related_is_const_anchor = false;
       struct table_elt *src_const_elt = 0;
       int src_cost = MAX_COST;
       int src_eqv_cost = MAX_COST;
@@ -4317,8 +4590,8 @@ cse_insn (rtx insn)
        {
          rtx width = XEXP (SET_DEST (sets[i].rtl), 1);
 
-         if (GET_CODE (src) == CONST_INT
-             && GET_CODE (width) == CONST_INT
+         if (CONST_INT_P (src)
+             && CONST_INT_P (width)
              && INTVAL (width) < HOST_BITS_PER_WIDE_INT
              && (INTVAL (src) & ((HOST_WIDE_INT) (-1) << INTVAL (width))))
            src_folded
@@ -4359,9 +4632,7 @@ cse_insn (rtx insn)
         treat it as volatile.  It may do the work of an SI in one context
         where the extra bits are not being used, but cannot replace an SI
         in general.  */
-      if (GET_CODE (src) == SUBREG
-         && (GET_MODE_SIZE (GET_MODE (src))
-             > GET_MODE_SIZE (GET_MODE (SUBREG_REG (src)))))
+      if (paradoxical_subreg_p (src))
        sets[i].src_volatile = 1;
 #endif
 
@@ -4479,15 +4750,15 @@ cse_insn (rtx insn)
       /* See if we have a CONST_INT that is already in a register in a
         wider mode.  */
 
-      if (src_const && src_related == 0 && GET_CODE (src_const) == CONST_INT
+      if (src_const && src_related == 0 && CONST_INT_P (src_const)
          && GET_MODE_CLASS (mode) == MODE_INT
-         && GET_MODE_BITSIZE (mode) < BITS_PER_WORD)
+         && GET_MODE_PRECISION (mode) < BITS_PER_WORD)
        {
          enum machine_mode wider_mode;
 
          for (wider_mode = GET_MODE_WIDER_MODE (mode);
               wider_mode != VOIDmode
-              && GET_MODE_BITSIZE (wider_mode) <= BITS_PER_WORD
+              && GET_MODE_PRECISION (wider_mode) <= BITS_PER_WORD
               && src_related == 0;
               wider_mode = GET_MODE_WIDER_MODE (wider_mode))
            {
@@ -4514,7 +4785,7 @@ cse_insn (rtx insn)
         value.  */
 
       if (flag_expensive_optimizations && ! src_related
-         && GET_CODE (src) == AND && GET_CODE (XEXP (src, 1)) == CONST_INT
+         && GET_CODE (src) == AND && CONST_INT_P (XEXP (src, 1))
          && GET_MODE_SIZE (mode) < UNITS_PER_WORD)
        {
          enum machine_mode tmode;
@@ -4568,7 +4839,7 @@ cse_insn (rtx insn)
 
          /* 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));
+         memset (memory_extend_rtx, 0, sizeof (*memory_extend_rtx));
          PUT_CODE (memory_extend_rtx, LOAD_EXTEND_OP (mode));
          XEXP (memory_extend_rtx, 0) = src;
 
@@ -4598,6 +4869,19 @@ cse_insn (rtx insn)
        }
 #endif /* LOAD_EXTEND_OP */
 
+      /* Try to express the constant using a register+offset expression
+        derived from a constant anchor.  */
+
+      if (targetm.const_anchor
+         && !src_related
+         && src_const
+         && GET_CODE (src_const) == CONST_INT)
+       {
+         src_related = try_const_anchors (src_const, mode);
+         src_related_is_const_anchor = src_related != NULL_RTX;
+       }
+
+
       if (src == src_folded)
        src_folded = 0;
 
@@ -4626,9 +4910,7 @@ cse_insn (rtx insn)
 
          /* Also skip paradoxical subregs, unless that's what we're
             looking for.  */
-         if (code == SUBREG
-             && (GET_MODE_SIZE (GET_MODE (p->exp))
-                 > GET_MODE_SIZE (GET_MODE (SUBREG_REG (p->exp))))
+         if (paradoxical_subreg_p (p->exp)
              && ! (src != 0
                    && GET_CODE (src) == SUBREG
                    && GET_MODE (src) == GET_MODE (p->exp)
@@ -4702,6 +4984,18 @@ cse_insn (rtx insn)
            {
              src_related_cost = COST (src_related);
              src_related_regcost = approx_reg_cost (src_related);
+
+             /* If a const-anchor is used to synthesize a constant that
+                normally requires multiple instructions then slightly prefer
+                it over the original sequence.  These instructions are likely
+                to become redundant now.  We can't compare against the cost
+                of src_eqv_here because, on MIPS for example, multi-insn
+                constants have zero cost; they are assumed to be hoisted from
+                loops.  */
+             if (src_related_is_const_anchor
+                 && src_related_cost == src_cost
+                 && src_eqv_here)
+               src_related_cost--;
            }
        }
 
@@ -4725,9 +5019,7 @@ cse_insn (rtx insn)
             size, but later may be adjusted so that the upper bits aren't
             what we want.  So reject it.  */
          if (elt != 0
-             && GET_CODE (elt->exp) == SUBREG
-             && (GET_MODE_SIZE (GET_MODE (elt->exp))
-                 > GET_MODE_SIZE (GET_MODE (SUBREG_REG (elt->exp))))
+             && paradoxical_subreg_p (elt->exp)
              /* It is okay, though, if the rtx we're trying to match
                 will ignore any of the bits we can't predict.  */
              && ! (src != 0
@@ -4805,10 +5097,81 @@ cse_insn (rtx insn)
              dest = canon_rtx (SET_DEST (sets[i].rtl));
 
              if (!MEM_P (src) || !MEM_P (dest)
-                 || !nonoverlapping_memrefs_p (src, 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))
+            (set (zero_extract:M2 (reg:M N) (const_int C) (const_int D))
+                 (reg:M2 O)).  */
+         if (GET_CODE (SET_DEST (sets[i].rtl)) == ZERO_EXTRACT
+             && CONST_INT_P (trial)
+             && 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)))
+             && ((unsigned) INTVAL (XEXP (SET_DEST (sets[i].rtl), 1))
+                 + (unsigned) INTVAL (XEXP (SET_DEST (sets[i].rtl), 2))
+                 <= HOST_BITS_PER_WIDE_INT))
+           {
+             rtx dest_reg = XEXP (SET_DEST (sets[i].rtl), 0);
+             rtx width = XEXP (SET_DEST (sets[i].rtl), 1);
+             rtx pos = XEXP (SET_DEST (sets[i].rtl), 2);
+             unsigned int dest_hash = HASH (dest_reg, GET_MODE (dest_reg));
+             struct table_elt *dest_elt
+               = lookup (dest_reg, dest_hash, GET_MODE (dest_reg));
+             rtx dest_cst = NULL;
+
+             if (dest_elt)
+               for (p = dest_elt->first_same_value; p; p = p->next_same_value)
+                 if (p->is_const && CONST_INT_P (p->exp))
+                   {
+                     dest_cst = p->exp;
+                     break;
+                   }
+             if (dest_cst)
+               {
+                 HOST_WIDE_INT val = INTVAL (dest_cst);
+                 HOST_WIDE_INT mask;
+                 unsigned int shift;
+                 if (BITS_BIG_ENDIAN)
+                   shift = GET_MODE_PRECISION (GET_MODE (dest_reg))
+                           - INTVAL (pos) - INTVAL (width);
+                 else
+                   shift = INTVAL (pos);
+                 if (INTVAL (width) == HOST_BITS_PER_WIDE_INT)
+                   mask = ~(HOST_WIDE_INT) 0;
+                 else
+                   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));
+                 validate_unshare_change (insn, &SET_DEST (sets[i].rtl),
+                                          dest_reg, 1);
+                 validate_unshare_change (insn, &SET_SRC (sets[i].rtl),
+                                          GEN_INT (val), 1);
+                 if (apply_change_group ())
+                   {
+                     rtx note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
+                     if (note)
+                       {
+                         remove_note (insn, note);
+                         df_notes_rescan (insn);
+                       }
+                     src_eqv = NULL_RTX;
+                     src_eqv_elt = NULL;
+                     src_eqv_volatile = 0;
+                     src_eqv_in_memory = 0;
+                     src_eqv_hash = 0;
+                     repeat = true;
+                     break;
+                   }
+               }
+           }
+
          /* We don't normally have an insn matching (set (pc) (pc)), so
             check for this separately here.  We will delete such an
             insn below.
@@ -4884,6 +5247,13 @@ cse_insn (rtx insn)
            }
        }
 
+      /* If we changed the insn too much, handle this set from scratch.  */
+      if (repeat)
+       {
+         i--;
+         continue;
+       }
+
       src = SET_SRC (sets[i].rtl);
 
       /* In general, it is good to have a SET with SET_SRC == SET_DEST.
@@ -4946,33 +5316,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.  */
@@ -5012,11 +5382,11 @@ cse_insn (rtx insn)
        {
          rtx width = XEXP (SET_DEST (sets[i].rtl), 1);
 
-         if (src_const != 0 && GET_CODE (src_const) == CONST_INT
-             && GET_CODE (width) == CONST_INT
+         if (src_const != 0 && CONST_INT_P (src_const)
+             && 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.  */
            ;
@@ -5257,7 +5627,7 @@ cse_insn (rtx insn)
        }
     }
 
-  invalidate_from_clobbers (x);
+  invalidate_from_clobbers (insn);
 
   /* Some registers are invalidated by subroutine calls.  Memory is
      invalidated by non-constant calls.  */
@@ -5294,10 +5664,9 @@ cse_insn (rtx insn)
          invalidate (XEXP (dest, 0), GET_MODE (dest));
       }
 
-  /* A volatile ASM invalidates everything.  */
+  /* A volatile ASM or an UNSPEC_VOLATILE invalidates everything.  */
   if (NONJUMP_INSN_P (insn)
-      && GET_CODE (PATTERN (insn)) == ASM_OPERANDS
-      && MEM_VOLATILE_P (PATTERN (insn)))
+      && volatile_insn_p (PATTERN (insn)))
     flush_hash_table ();
 
   /* Don't cse over a call to setjmp; on some machines (eg VAX)
@@ -5410,9 +5779,7 @@ cse_insn (rtx insn)
               some tracking to be wrong.
 
               ??? Think about this more later.  */
-           || (GET_CODE (dest) == SUBREG
-               && (GET_MODE_SIZE (GET_MODE (dest))
-                   > GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest))))
+           || (paradoxical_subreg_p (dest)
                && (GET_CODE (sets[i].src) == SIGN_EXTEND
                    || GET_CODE (sets[i].src) == ZERO_EXTEND)))
          continue;
@@ -5436,6 +5803,14 @@ cse_insn (rtx insn)
        elt = insert (dest, sets[i].src_elt,
                      sets[i].dest_hash, GET_MODE (dest));
 
+       /* If this is a constant, insert the constant anchors with the
+          equivalent register-offset expressions using register DEST.  */
+       if (targetm.const_anchor
+           && REG_P (dest)
+           && SCALAR_INT_MODE_P (GET_MODE (dest))
+           && GET_CODE (sets[i].src_elt->exp) == CONST_INT)
+         insert_const_anchors (dest, sets[i].src_elt->exp, GET_MODE (dest));
+
        elt->in_memory = (MEM_P (sets[i].inner_dest)
                          && !MEM_READONLY_P (sets[i].inner_dest));
 
@@ -5547,64 +5922,8 @@ cse_insn (rtx insn)
 
      Also do not do this if we are operating on a copy of INSN.  */
 
-  if (n_sets == 1 && sets[0].rtl && REG_P (SET_DEST (sets[0].rtl))
-      && NEXT_INSN (PREV_INSN (insn)) == insn
-      && REG_P (SET_SRC (sets[0].rtl))
-      && REGNO (SET_SRC (sets[0].rtl)) >= FIRST_PSEUDO_REGISTER
-      && REGNO_QTY_VALID_P (REGNO (SET_SRC (sets[0].rtl))))
-    {
-      int src_q = REG_QTY (REGNO (SET_SRC (sets[0].rtl)));
-      struct qty_table_elem *src_ent = &qty_table[src_q];
-
-      if (src_ent->first_reg == REGNO (SET_DEST (sets[0].rtl)))
-       {
-         /* 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));
-         do
-           {
-             prev = PREV_INSN (prev);
-           }
-         while (prev != bb_head && NOTE_P (prev));
-
-         /* Do not swap the registers around if the previous instruction
-            attaches a REG_EQUIV note to REG1.
-
-            ??? It's not entirely clear whether we can transfer a REG_EQUIV
-            from the pseudo that originally shadowed an incoming argument
-            to another register.  Some uses of REG_EQUIV might rely on it
-            being attached to REG1 rather than REG2.
-
-            This section previously turned the REG_EQUIV into a REG_EQUAL
-            note.  We cannot do that because REG_EQUIV may provide an
-            uninitialized stack slot when REG_PARM_STACK_SPACE is used.  */
-         if (NONJUMP_INSN_P (prev)
-             && GET_CODE (PATTERN (prev)) == SET
-             && SET_DEST (PATTERN (prev)) == SET_SRC (sets[0].rtl)
-             && ! find_reg_note (prev, REG_EQUIV, NULL_RTX))
-           {
-             rtx dest = SET_DEST (sets[0].rtl);
-             rtx src = SET_SRC (sets[0].rtl);
-             rtx note;
-
-             validate_change (prev, &SET_DEST (PATTERN (prev)), dest, 1);
-             validate_change (insn, &SET_DEST (sets[0].rtl), src, 1);
-             validate_change (insn, &SET_SRC (sets[0].rtl), dest, 1);
-             apply_change_group ();
-
-             /* If INSN has a REG_EQUAL note, and this note mentions
-                REG0, then we must delete it, because the value in
-                REG0 has changed.  If the note's value is REG1, we must
-                also delete it because that is now this insn's dest.  */
-             note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
-             if (note != 0
-                 && (reg_mentioned_p (dest, XEXP (note, 0))
-                     || rtx_equal_p (src, XEXP (note, 0))))
-               remove_note (insn, note);
-           }
-       }
-    }
+  if (n_sets == 1 && sets[0].rtl)
+    try_back_substitute_reg (sets[0].rtl, insn);
 
 done:;
 }
@@ -5626,16 +5945,16 @@ invalidate_memory (void)
       }
 }
 
-/* Perform invalidation on the basis of everything about an insn
+/* Perform invalidation on the basis of everything about INSN,
    except for invalidating the actual places that are SET in it.
    This includes the places CLOBBERed, and anything that might
-   alias with something that is SET or CLOBBERed.
-
-   X is the pattern of the insn.  */
+   alias with something that is SET or CLOBBERed.  */
 
 static void
-invalidate_from_clobbers (rtx x)
+invalidate_from_clobbers (rtx insn)
 {
+  rtx x = PATTERN (insn);
+
   if (GET_CODE (x) == CLOBBER)
     {
       rtx ref = XEXP (x, 0);
@@ -5669,6 +5988,53 @@ invalidate_from_clobbers (rtx x)
     }
 }
 \f
+/* Perform invalidation on the basis of everything about INSN.
+   This includes the places CLOBBERed, and anything that might
+   alias with something that is SET or CLOBBERed.  */
+
+static void
+invalidate_from_sets_and_clobbers (rtx insn)
+{
+  rtx tem;
+  rtx x = PATTERN (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);
+    }
+
+  /* Ensure we invalidate the destination register of a CALL insn.
+     This is necessary for machines where this register is a fixed_reg,
+     because no other code would invalidate it.  */
+  if (GET_CODE (x) == SET && GET_CODE (SET_SRC (x)) == CALL)
+    invalidate (SET_DEST (x), VOIDmode);
+
+  else if (GET_CODE (x) == PARALLEL)
+    {
+      int i;
+
+      for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
+       {
+         rtx y = XVECEXP (x, 0, i);
+         if (GET_CODE (y) == CLOBBER)
+           {
+             rtx clobbered = XEXP (y, 0);
+
+             if (REG_P (clobbered)
+                 || GET_CODE (clobbered) == SUBREG)
+               invalidate (clobbered, VOIDmode);
+             else if (GET_CODE (clobbered) == STRICT_LOW_PART
+                      || GET_CODE (clobbered) == ZERO_EXTRACT)
+               invalidate (XEXP (clobbered, 0), GET_MODE (clobbered));
+           }
+         else if (GET_CODE (y) == SET && GET_CODE (SET_SRC (y)) == CALL)
+           invalidate (SET_DEST (y), VOIDmode);
+       }
+    }
+}
+\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,
@@ -5687,13 +6053,10 @@ cse_process_notes_1 (rtx x, rtx object, bool *changed)
 
   switch (code)
     {
-    case CONST_INT:
     case CONST:
     case SYMBOL_REF:
     case LABEL_REF:
-    case CONST_DOUBLE:
-    case CONST_FIXED:
-    case CONST_VECTOR:
+    CASE_CONST_ANY:
     case PC:
     case CC0:
     case LO_SUM:
@@ -5705,9 +6068,12 @@ cse_process_notes_1 (rtx x, rtx object, bool *changed)
       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);
+      /* Fall through.  */
+
+    case INSN_LIST:
+    case INT_LIST:
       if (XEXP (x, 1))
        XEXP (x, 1) = cse_process_notes (XEXP (x, 1), NULL_RTX, changed);
       return x;
@@ -5773,7 +6139,7 @@ cse_process_notes (rtx x, rtx object, bool *changed)
    describe the path.
    It is filled with a queue of basic blocks, starting with FIRST_BB
    and following a trace through the CFG.
-  
+
    If all paths starting at FIRST_BB have been followed, or no new path
    starting at FIRST_BB can be constructed, this function returns FALSE.
    Otherwise, DATA->path is filled and the function returns TRUE indicating
@@ -5789,8 +6155,8 @@ cse_find_path (basic_block first_bb, struct cse_basic_block_data *data,
   basic_block bb;
   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;
@@ -5834,7 +6200,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
@@ -5847,9 +6213,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;
                }
@@ -5886,14 +6252,16 @@ cse_find_path (basic_block first_bb, struct cse_basic_block_data *data,
          else
            e = NULL;
 
-         if (e && e->dest != EXIT_BLOCK_PTR
+         if (e
+             && !((e->flags & EDGE_ABNORMAL_CALL) && cfun->has_nonlocal_label)
+             && 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;
            }
@@ -5950,7 +6318,7 @@ cse_prescan_path (struct cse_basic_block_data *data)
   int path_entry;
 
   /* Scan to end of each basic block in the path.  */
-  for (path_entry = 0; path_entry < path_size; path_entry++) 
+  for (path_entry = 0; path_entry < path_size; path_entry++)
     {
       basic_block bb;
       rtx insn;
@@ -6010,9 +6378,9 @@ cse_extended_basic_block (struct cse_basic_block_data *ebb_data)
            }
        }
 
+      optimize_this_for_speed_p = optimize_bb_for_speed_p (bb);
       FOR_BB_INSNS (bb, insn)
        {
-         optimize_this_for_speed_p = optimize_bb_for_speed_p (bb);
          /* If we have processed 1,000 insns, flush the hash table to
             avoid extreme quadratic behavior.  We must not include NOTEs
             in the count since there may be more of them when generating
@@ -6022,7 +6390,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 (INSN_P (insn)
+         if (NONDEBUG_INSN_P (insn)
              && num_insns++ > PARAM_VALUE (PARAM_MAX_CSE_INSNS))
            {
              flush_hash_table ();
@@ -6052,29 +6420,31 @@ cse_extended_basic_block (struct cse_basic_block_data *ebb_data)
                recorded_label_ref = true;
 
 #ifdef HAVE_cc0
-             /* If the previous insn set 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_INSN (insn);
-               if (prev_insn && NONJUMP_INSN_P (prev_insn)
-                   && (tem = single_set (prev_insn)) != 0
-                   && 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))
+             if (NONDEBUG_INSN_P (insn))
                {
-                 prev_insn_cc0 = this_insn_cc0;
-                 prev_insn_cc0_mode = this_insn_cc0_mode;
+                 /* 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
            }
@@ -6083,7 +6453,7 @@ cse_extended_basic_block (struct cse_basic_block_data *ebb_data)
       /* With non-call exceptions, we are not always able to update
         the CFG properly inside cse_insn.  So clean up possibly
         redundant EH edges here.  */
-      if (flag_non_call_exceptions && have_eh_succ_edges (bb))
+      if (cfun->can_throw_non_call_exceptions && have_eh_succ_edges (bb))
        cse_cfg_altered |= purge_dead_edges (bb);
 
       /* If we changed a conditional jump, we may have terminated
@@ -6103,7 +6473,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;
                }
@@ -6147,7 +6517,7 @@ cse_extended_basic_block (struct cse_basic_block_data *ebb_data)
    Return 1 if the CFG should be cleaned up because it has been modified.
    Return 0 otherwise.  */
 
-int
+static int
 cse_main (rtx f ATTRIBUTE_UNUSED, int nregs)
 {
   struct cse_basic_block_data ebb_data;
@@ -6156,6 +6526,7 @@ cse_main (rtx f ATTRIBUTE_UNUSED, int nregs)
   int i, n_blocks;
 
   df_set_flags (DF_LR_RUN_DCE);
+  df_note_add_problem ();
   df_analyze ();
   df_set_flags (DF_DEFER_INSN_RESCAN);
 
@@ -6181,7 +6552,7 @@ cse_main (rtx f ATTRIBUTE_UNUSED, int nregs)
 
   /* Set up the table of already visited basic blocks.  */
   cse_visited_basic_blocks = sbitmap_alloc (last_basic_block);
-  sbitmap_zero (cse_visited_basic_blocks);
+  bitmap_clear (cse_visited_basic_blocks);
 
   /* Loop over basic blocks in reverse completion order (RPO),
      excluding the ENTRY and EXIT blocks.  */
@@ -6195,7 +6566,7 @@ cse_main (rtx f ATTRIBUTE_UNUSED, int nregs)
        {
          bb = BASIC_BLOCK (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.  */
@@ -6266,8 +6637,9 @@ check_for_label_ref (rtx *rtl, void *data)
    Don't count a usage of DEST, which is the SET_DEST of a SET which
    contains X in its SET_SRC.  This is because such a SET does not
    modify the liveness of DEST.
-   DEST is set to pc_rtx for a trapping insn, which means that we must count
-   uses of a SET_DEST regardless because the insn can't be deleted here.  */
+   DEST is set to pc_rtx for a trapping insn, or for an insn with side effects.
+   We must then count uses of a SET_DEST regardless, because the insn can't be
+   deleted here.  */
 
 static void
 count_reg_usage (rtx x, int *counts, rtx dest, int incr)
@@ -6290,10 +6662,7 @@ count_reg_usage (rtx x, int *counts, rtx dest, int incr)
     case PC:
     case CC0:
     case CONST:
-    case CONST_INT:
-    case CONST_DOUBLE:
-    case CONST_FIXED:
-    case CONST_VECTOR:
+    CASE_CONST_ANY:
     case SYMBOL_REF:
     case LABEL_REF:
       return;
@@ -6314,12 +6683,17 @@ count_reg_usage (rtx x, int *counts, rtx dest, int incr)
                       incr);
       return;
 
+    case DEBUG_INSN:
+      return;
+
     case CALL_INSN:
     case INSN:
     case JUMP_INSN:
-    /* We expect dest to be NULL_RTX here.  If the insn may trap, mark
-       this fact by setting DEST to pc_rtx.  */
-      if (flag_non_call_exceptions && may_trap_p (PATTERN (x)))
+      /* We expect dest to be NULL_RTX here.  If the insn may throw,
+        or if it cannot be deleted due to side-effects, mark this fact
+        by setting DEST to pc_rtx.  */
+      if ((!cfun->can_delete_dead_exceptions && !insn_nothrow_p (x))
+         || side_effects_p (PATTERN (x)))
        dest = pc_rtx;
       if (code == CALL_INSN)
        count_reg_usage (CALL_INSN_FUNCTION_USAGE (x), counts, dest, incr);
@@ -6359,16 +6733,13 @@ count_reg_usage (rtx x, int *counts, rtx dest, int incr)
       return;
 
     case ASM_OPERANDS:
-      /* If the asm is volatile, then this insn cannot be deleted,
-        and so the inputs *must* be live.  */
-      if (MEM_VOLATILE_P (x))
-       dest = NULL_RTX;
       /* Iterate over just the inputs, not the constraints as well.  */
       for (i = ASM_OPERANDS_INPUT_LENGTH (x) - 1; i >= 0; i--)
        count_reg_usage (ASM_OPERANDS_INPUT (x, i), counts, dest, incr);
       return;
 
     case INSN_LIST:
+    case INT_LIST:
       gcc_unreachable ();
 
     default:
@@ -6386,6 +6757,16 @@ count_reg_usage (rtx x, int *counts, rtx dest, int incr)
     }
 }
 \f
+/* Return true if X is a dead register.  */
+
+static inline int
+is_dead_reg (rtx x, int *counts)
+{
+  return (REG_P (x)
+         && REGNO (x) >= FIRST_PSEUDO_REGISTER
+         && counts[REGNO (x)] == 0);
+}
+
 /* Return true if set is live.  */
 static bool
 set_live_p (rtx set, rtx insn ATTRIBUTE_UNUSED, /* Only used with HAVE_cc0.  */
@@ -6401,14 +6782,12 @@ set_live_p (rtx set, rtx insn ATTRIBUTE_UNUSED, /* Only used with HAVE_cc0.  */
 #ifdef HAVE_cc0
   else if (GET_CODE (SET_DEST (set)) == CC0
           && !side_effects_p (SET_SRC (set))
-          && ((tem = next_nonnote_insn (insn)) == 0
+          && ((tem = next_nonnote_nondebug_insn (insn)) == NULL_RTX
               || !INSN_P (tem)
               || !reg_referenced_p (cc0_rtx, PATTERN (tem))))
     return false;
 #endif
-  else if (!REG_P (SET_DEST (set))
-          || REGNO (SET_DEST (set)) < FIRST_PSEUDO_REGISTER
-          || counts[REGNO (SET_DEST (set))] != 0
+  else if (!is_dead_reg (SET_DEST (set), counts)
           || side_effects_p (SET_SRC (set)))
     return true;
   return false;
@@ -6420,7 +6799,7 @@ static bool
 insn_live_p (rtx insn, int *counts)
 {
   int i;
-  if (flag_non_call_exceptions && may_trap_p (PATTERN (insn)))
+  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);
@@ -6440,10 +6819,80 @@ insn_live_p (rtx insn, int *counts)
        }
       return false;
     }
+  else if (DEBUG_INSN_P (insn))
+    {
+      rtx next;
+
+      for (next = NEXT_INSN (insn); next; next = NEXT_INSN (next))
+       if (NOTE_P (next))
+         continue;
+       else if (!DEBUG_INSN_P (next))
+         return true;
+       else if (INSN_VAR_LOCATION_DECL (insn) == INSN_VAR_LOCATION_DECL (next))
+         return false;
+
+      return true;
+    }
   else
     return true;
 }
 
+/* Count the number of stores into pseudo.  Callback for note_stores.  */
+
+static void
+count_stores (rtx x, const_rtx set ATTRIBUTE_UNUSED, void *data)
+{
+  int *counts = (int *) data;
+  if (REG_P (x) && REGNO (x) >= FIRST_PSEUDO_REGISTER)
+    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.  */
+
+static int
+is_dead_debug_insn (rtx *loc, void *data)
+{
+  rtx x = *loc;
+  struct dead_debug_insn_data *ddid = (struct dead_debug_insn_data *) data;
+
+  if (is_dead_reg (x, ddid->counts))
+    {
+      if (ddid->replacements && ddid->replacements[REGNO (x)] != NULL_RTX)
+       ddid->seen_repl = true;
+      else
+       return 1;
+    }
+  return 0;
+}
+
+/* Replace a dead pseudo in a DEBUG_INSN with replacement DEBUG_EXPR.
+   Callback for simplify_replace_fn_rtx.  */
+
+static rtx
+replace_dead_reg (rtx x, const_rtx old_rtx ATTRIBUTE_UNUSED, void *data)
+{
+  rtx *replacements = (rtx *) data;
+
+  if (REG_P (x)
+      && REGNO (x) >= FIRST_PSEUDO_REGISTER
+      && replacements[REGNO (x)] != NULL_RTX)
+    {
+      if (GET_MODE (x) == GET_MODE (replacements[REGNO (x)]))
+       return replacements[REGNO (x)];
+      return lowpart_subreg (GET_MODE (x), replacements[REGNO (x)],
+                            GET_MODE (replacements[REGNO (x)]));
+    }
+  return NULL_RTX;
+}
+
 /* Scan all the insns and delete any that are dead; i.e., they store a register
    that is never used or they copy a register to itself.
 
@@ -6457,22 +6906,51 @@ delete_trivially_dead_insns (rtx insns, int nreg)
 {
   int *counts;
   rtx insn, prev;
+  rtx *replacements = NULL;
   int ndead = 0;
 
   timevar_push (TV_DELETE_TRIVIALLY_DEAD);
   /* First count the number of times each register is used.  */
-  counts = XCNEWVEC (int, nreg);
-  for (insn = insns; insn; insn = NEXT_INSN (insn))
-    if (INSN_P (insn))
-      count_reg_usage (insn, counts, NULL_RTX, 1);
-
+  if (MAY_HAVE_DEBUG_INSNS)
+    {
+      counts = XCNEWVEC (int, nreg * 3);
+      for (insn = insns; insn; insn = NEXT_INSN (insn))
+       if (DEBUG_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);
+         }
+      /* If there can be debug insns, COUNTS are 3 consecutive arrays.
+        First one counts how many times each pseudo is used outside
+        of debug insns, second counts how many times each pseudo is
+        used in debug insns and third counts how many times a pseudo
+        is stored.  */
+    }
+  else
+    {
+      counts = XCNEWVEC (int, nreg);
+      for (insn = insns; insn; insn = NEXT_INSN (insn))
+       if (INSN_P (insn))
+         count_reg_usage (insn, counts, NULL_RTX, 1);
+      /* If no debug insns can be present, COUNTS is just an array
+        which counts how many times each pseudo is used.  */
+    }
   /* 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.
 
      The first jump optimization pass may leave a real insn as the last
      insn in the function.   We must not skip that insn or we may end
-     up deleting code that is not really dead.  */
+     up deleting code that is not really dead.
+
+     If some otherwise unused register is only used in DEBUG_INSNs,
+     try to create a DEBUG_EXPR temporary and emit a DEBUG_INSN before
+     the setter.  Then go through DEBUG_INSNs and if a DEBUG_EXPR
+     has been created for the unused register, replace it with
+     the DEBUG_EXPR, otherwise reset the DEBUG_INSN.  */
   for (insn = get_last_insn (); insn; insn = prev)
     {
       int live_insn = 0;
@@ -6488,12 +6966,79 @@ delete_trivially_dead_insns (rtx insns, int nreg)
 
       if (! live_insn && dbg_cnt (delete_trivial_dead))
        {
-         count_reg_usage (insn, counts, NULL_RTX, -1);
+         if (DEBUG_INSN_P (insn))
+           count_reg_usage (INSN_VAR_LOCATION_LOC (insn), counts + nreg,
+                            NULL_RTX, -1);
+         else
+           {
+             rtx set;
+             if (MAY_HAVE_DEBUG_INSNS
+                 && (set = single_set (insn)) != NULL_RTX
+                 && is_dead_reg (SET_DEST (set), counts)
+                 /* Used at least once in some DEBUG_INSN.  */
+                 && counts[REGNO (SET_DEST (set)) + nreg] > 0
+                 /* And set exactly once.  */
+                 && counts[REGNO (SET_DEST (set)) + nreg * 2] == 1
+                 && !side_effects_p (SET_SRC (set))
+                 && asm_noperands (PATTERN (insn)) < 0)
+               {
+                 rtx dval, 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);
+                 df_insn_rescan (bind);
+
+                 if (replacements == NULL)
+                   replacements = XCNEWVEC (rtx, nreg);
+                 replacements[REGNO (SET_DEST (set))] = dval;
+               }
+
+             count_reg_usage (insn, counts, NULL_RTX, -1);
+             ndead++;
+           }
          delete_insn_and_edges (insn);
-         ndead++;
        }
     }
 
+  if (MAY_HAVE_DEBUG_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 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))
+             {
+               INSN_VAR_LOCATION_LOC (insn) = gen_rtx_UNKNOWN_VAR_LOC ();
+               df_insn_rescan (insn);
+             }
+           else if (ddid.seen_repl)
+             {
+               INSN_VAR_LOCATION_LOC (insn)
+                 = simplify_replace_fn_rtx (INSN_VAR_LOCATION_LOC (insn),
+                                            NULL_RTX, replace_dead_reg,
+                                            replacements);
+               df_insn_rescan (insn);
+             }
+         }
+      free (replacements);
+    }
+
   if (dump_file && ndead)
     fprintf (dump_file, "Deleted %i trivially dead insns\n",
             ndead);
@@ -6519,7 +7064,7 @@ cse_change_cc_mode (rtx *loc, void *data)
       && GET_MODE (*loc) != GET_MODE (args->newreg))
     {
       validate_change (args->insn, loc, args->newreg, 1);
-      
+
       return -1;
     }
   return 0;
@@ -6539,10 +7084,10 @@ cse_change_cc_mode_insn (rtx insn, rtx newreg)
 
   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);
-  
+
   /* If the following assertion was triggered, there is most probably
      something wrong with the cc_modes_compatible back end function.
      CC modes only can be considered compatible if the insn - with the mode
@@ -6621,7 +7166,7 @@ cse_cc_succs (basic_block bb, basic_block orig_bb, rtx cc_reg, rtx cc_src,
        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;
@@ -6661,7 +7206,7 @@ cse_cc_succs (basic_block bb, basic_block orig_bb, rtx cc_reg, rtx cc_src,
                                       XEXP (SET_SRC (set), 0))
                       && rtx_equal_p (XEXP (cc_src, 1),
                                       XEXP (SET_SRC (set), 1)))
-                          
+
                {
                  comp_mode = targetm.cc_modes_compatible (mode, set_mode);
                  if (comp_mode != VOIDmode
@@ -6904,7 +7449,7 @@ rest_of_handle_cse (void)
     {
       timevar_push (TV_JUMP);
       rebuild_jump_labels (get_insns ());
-      cleanup_cfg (0);
+      cleanup_cfg (CLEANUP_CFG_CHANGED);
       timevar_pop (TV_JUMP);
     }
   else if (tem == 1 || optimize > 1)
@@ -6913,28 +7458,45 @@ rest_of_handle_cse (void)
   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_dump_func |
-  TODO_ggc_collect |
-  TODO_verify_flow,                     /* todo_flags_finish */
- }
+  RTL_PASS, /* type */
+  "cse1", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  true, /* has_gate */
+  true, /* has_execute */
+  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_verify_flow ), /* 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: */
+  bool gate () { return gate_handle_cse (); }
+  unsigned int execute () { return rest_of_handle_cse (); }
+
+}; // class pass_cse
+
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_cse (gcc::context *ctxt)
+{
+  return new pass_cse (ctxt);
+}
+
 
 static bool
 gate_handle_cse2 (void)
@@ -6965,7 +7527,7 @@ rest_of_handle_cse2 (void)
     {
       timevar_push (TV_JUMP);
       rebuild_jump_labels (get_insns ());
-      cleanup_cfg (0);
+      cleanup_cfg (CLEANUP_CFG_CHANGED);
       timevar_pop (TV_JUMP);
     }
   else if (tem == 1)
@@ -6976,28 +7538,45 @@ rest_of_handle_cse2 (void)
 }
 
 
-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_dump_func |
-  TODO_ggc_collect |
-  TODO_verify_flow                      /* todo_flags_finish */
- }
+  RTL_PASS, /* type */
+  "cse2", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  true, /* has_gate */
+  true, /* has_execute */
+  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_verify_flow ), /* todo_flags_finish */
 };
 
+class pass_cse2 : public rtl_opt_pass
+{
+public:
+  pass_cse2 (gcc::context *ctxt)
+    : rtl_opt_pass (pass_data_cse2, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  bool gate () { return gate_handle_cse2 (); }
+  unsigned int execute () { return rest_of_handle_cse2 (); }
+
+}; // class pass_cse2
+
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_cse2 (gcc::context *ctxt)
+{
+  return new pass_cse2 (ctxt);
+}
+
 static bool
 gate_handle_cse_after_global_opts (void)
 {
@@ -7027,7 +7606,7 @@ rest_of_handle_cse_after_global_opts (void)
     {
       timevar_push (TV_JUMP);
       rebuild_jump_labels (get_insns ());
-      cleanup_cfg (0);
+      cleanup_cfg (CLEANUP_CFG_CHANGED);
       timevar_pop (TV_JUMP);
     }
   else if (tem == 1)
@@ -7037,25 +7616,43 @@ rest_of_handle_cse_after_global_opts (void)
   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_dump_func |
-  TODO_ggc_collect |
-  TODO_verify_flow                      /* todo_flags_finish */
- }
+  RTL_PASS, /* type */
+  "cse_local", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  true, /* has_gate */
+  true, /* has_execute */
+  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_verify_flow ), /* 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: */
+  bool gate () { return gate_handle_cse_after_global_opts (); }
+  unsigned int execute () {
+    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);
+}