OSDN Git Service

* cse.c (enum taken): Remove PATH_AROUND.
[pf3gnuchains/gcc-fork.git] / gcc / cse.c
index c7f9000..15cc2d6 100644 (file)
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -560,10 +560,8 @@ struct cse_basic_block_data
     {
       /* The branch insn.  */
       rtx branch;
-      /* Whether it should be taken or not.  AROUND is the same as taken
-        except that it is used when the destination label is not preceded
-       by a BARRIER.  */
-      enum taken {PATH_TAKEN, PATH_NOT_TAKEN, PATH_AROUND} status;
+      /* Whether it should be taken or not.  */
+      enum taken {PATH_TAKEN, PATH_NOT_TAKEN} status;
     } *path;
 };
 
@@ -600,7 +598,6 @@ static inline unsigned safe_hash (rtx, enum machine_mode);
 static unsigned hash_rtx_string (const char *);
 
 static rtx canon_reg (rtx, rtx);
-static void find_best_addr (rtx, rtx *, enum machine_mode);
 static enum rtx_code find_comparison_args (enum rtx_code, rtx *, rtx *,
                                           enum machine_mode *,
                                           enum machine_mode *);
@@ -611,14 +608,11 @@ static void record_jump_cond (enum rtx_code, enum machine_mode, rtx, rtx,
                              int);
 static void cse_insn (rtx, rtx);
 static void cse_end_of_basic_block (rtx, struct cse_basic_block_data *,
-                                   int, int);
-static int addr_affects_sp_p (rtx);
+                                   int);
 static void invalidate_from_clobbers (rtx);
 static rtx cse_process_notes (rtx, rtx);
-static void invalidate_skipped_set (rtx, rtx, void *);
-static void invalidate_skipped_block (rtx);
 static rtx cse_basic_block (rtx, rtx, struct branch_path *);
-static void count_reg_usage (rtx, int *, int);
+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);
@@ -731,57 +725,6 @@ approx_reg_cost (rtx x)
   return cost;
 }
 
-/* Returns a canonical version of X for the address, from the point of view,
-   that all multiplications are represented as MULT instead of the multiply
-   by a power of 2 being represented as ASHIFT.  */
-
-static rtx
-canon_for_address (rtx x)
-{
-  enum rtx_code code;
-  enum machine_mode mode;
-  rtx new = 0;
-  int i;
-  const char *fmt;
-  
-  if (!x)
-    return x;
-  
-  code = GET_CODE (x);
-  mode = GET_MODE (x);
-  
-  switch (code)
-    {
-    case ASHIFT:
-      if (GET_CODE (XEXP (x, 1)) == CONST_INT
-         && INTVAL (XEXP (x, 1)) < GET_MODE_BITSIZE (mode)
-         && INTVAL (XEXP (x, 1)) >= 0)
-        {
-         new = canon_for_address (XEXP (x, 0));
-         new = gen_rtx_MULT (mode, new,
-                             gen_int_mode ((HOST_WIDE_INT) 1
-                                           << INTVAL (XEXP (x, 1)),
-                                           mode));
-       }
-      break;
-    default:
-      break;
-      
-    }
-  if (new)
-    return new;
-  
-  /* Now recursively process each operand of this operation.  */
-  fmt = GET_RTX_FORMAT (code);
-  for (i = 0; i < GET_RTX_LENGTH (code); i++)
-    if (fmt[i] == 'e')
-      {
-       new = canon_for_address (XEXP (x, i));
-       XEXP (x, i) = new;
-      }
-  return x;
-}
-
 /* Return a negative value if an rtx A, whose costs are given by COST_A
    and REGCOST_A, is more desirable than an rtx B.
    Return a positive value if A is less desirable, or 0 if the two are
@@ -867,8 +810,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);
-      cse_reg_info_table = xmalloc (sizeof (struct cse_reg_info)
-                                    * new_size);
+      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;
     }
@@ -1511,7 +1453,7 @@ insert (rtx x, struct table_elt *classp, unsigned int hash, enum machine_mode mo
   if (elt)
     free_element_chain = elt->next_same_hash;
   else
-    elt = xmalloc (sizeof (struct table_elt));
+    elt = XNEW (struct table_elt);
 
   elt->exp = x;
   elt->canon_exp = NULL_RTX;
@@ -1725,7 +1667,7 @@ flush_hash_table (void)
        /* Note that invalidate can remove elements
           after P in the current hash chain.  */
        if (REG_P (p->exp))
-         invalidate (p->exp, p->mode);
+         invalidate (p->exp, VOIDmode);
        else
          remove_from_table (p, i);
       }
@@ -2498,6 +2440,7 @@ exp_equiv_p (rtx x, rtx y, int validate, bool for_gcse)
     case PC:
     case CC0:
     case CONST_INT:
+    case CONST_DOUBLE:
       return x == y;
 
     case LABEL_REF:
@@ -2537,16 +2480,26 @@ exp_equiv_p (rtx x, rtx y, int validate, bool for_gcse)
     case MEM:
       if (for_gcse)
        {
-         /* Can't merge two expressions in different alias sets, since we
-            can decide that the expression is transparent in a block when
-            it isn't, due to it being set with the different alias set.  */
-         if (MEM_ALIAS_SET (x) != MEM_ALIAS_SET (y))
-           return 0;
-
          /* A volatile mem should not be considered equivalent to any
             other.  */
          if (MEM_VOLATILE_P (x) || MEM_VOLATILE_P (y))
            return 0;
+
+         /* Can't merge two expressions in different alias sets, since we
+            can decide that the expression is transparent in a block when
+            it isn't, due to it being set with the different alias set.
+
+            Also, can't merge two expressions with different MEM_ATTRS.
+            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.  
+   
+            But because really all MEM attributes should be the same for
+            equivalent MEMs, we just use the invariant that MEMs that have
+            the same attributes share the same mem_attrs data structure.  */
+         if (MEM_ATTRS (x) != MEM_ATTRS (y))
+           return 0;
        }
       break;
 
@@ -2718,17 +2671,10 @@ static void
 validate_canon_reg (rtx *xloc, rtx insn)
 {
   rtx new = canon_reg (*xloc, insn);
-  int insn_code;
 
   /* If replacing pseudo with hard reg or vice versa, ensure the
      insn remains valid.  Likewise if the insn has MATCH_DUPs.  */
-  if (insn != 0 && new != 0
-      && REG_P (new) && REG_P (*xloc)
-      && (((REGNO (new) < FIRST_PSEUDO_REGISTER)
-          != (REGNO (*xloc) < FIRST_PSEUDO_REGISTER))
-         || GET_MODE (new) != GET_MODE (*xloc)
-         || (insn_code = recog_memoized (insn)) < 0
-         || insn_data[insn_code].n_dups > 0))
+  if (insn != 0 && new != 0)
     validate_change (insn, xloc, new, 1);
   else
     *xloc = new;
@@ -2738,8 +2684,7 @@ validate_canon_reg (rtx *xloc, rtx insn)
    replace each register reference inside it
    with the "oldest" equivalent register.
 
-   If INSN is nonzero and we are replacing a pseudo with a hard register
-   or vice versa, validate_change is used to ensure that INSN remains valid
+   If INSN is nonzero validate_change is used to ensure that INSN remains valid
    after we make our substitution.  The calls are made with IN_GROUP nonzero
    so apply_change_group must be called upon the outermost return from this
    function (unless INSN is zero).  The result of apply_change_group can
@@ -2812,229 +2757,6 @@ canon_reg (rtx x, rtx insn)
   return x;
 }
 \f
-/* LOC is a location within INSN that is an operand address (the contents of
-   a MEM).  Find the best equivalent address to use that is valid for this
-   insn.
-
-   On most CISC machines, complicated address modes are costly, and rtx_cost
-   is a good approximation for that cost.  However, most RISC machines have
-   only a few (usually only one) memory reference formats.  If an address is
-   valid at all, it is often just as cheap as any other address.  Hence, for
-   RISC machines, we use `address_cost' to compare the costs of various
-   addresses.  For two addresses of equal cost, choose the one with the
-   highest `rtx_cost' value as that has the potential of eliminating the
-   most insns.  For equal costs, we choose the first in the equivalence
-   class.  Note that we ignore the fact that pseudo registers are cheaper than
-   hard registers here because we would also prefer the pseudo registers.  */
-
-static void
-find_best_addr (rtx insn, rtx *loc, enum machine_mode mode)
-{
-  struct table_elt *elt;
-  rtx addr = *loc;
-  struct table_elt *p;
-  int found_better = 1;
-  int save_do_not_record = do_not_record;
-  int save_hash_arg_in_memory = hash_arg_in_memory;
-  int addr_volatile;
-  int regno;
-  unsigned hash;
-
-  /* Do not try to replace constant addresses or addresses of local and
-     argument slots.  These MEM expressions are made only once and inserted
-     in many instructions, as well as being used to control symbol table
-     output.  It is not safe to clobber them.
-
-     There are some uncommon cases where the address is already in a register
-     for some reason, but we cannot take advantage of that because we have
-     no easy way to unshare the MEM.  In addition, looking up all stack
-     addresses is costly.  */
-  if ((GET_CODE (addr) == PLUS
-       && REG_P (XEXP (addr, 0))
-       && GET_CODE (XEXP (addr, 1)) == CONST_INT
-       && (regno = REGNO (XEXP (addr, 0)),
-          regno == FRAME_POINTER_REGNUM || regno == HARD_FRAME_POINTER_REGNUM
-          || regno == ARG_POINTER_REGNUM))
-      || (REG_P (addr)
-         && (regno = REGNO (addr), regno == FRAME_POINTER_REGNUM
-             || regno == HARD_FRAME_POINTER_REGNUM
-             || regno == ARG_POINTER_REGNUM))
-      || CONSTANT_ADDRESS_P (addr))
-    return;
-
-  /* If this address is not simply a register, try to fold it.  This will
-     sometimes simplify the expression.  Many simplifications
-     will not be valid, but some, usually applying the associative rule, will
-     be valid and produce better code.  */
-  if (!REG_P (addr))
-    {
-      rtx folded = canon_for_address (fold_rtx (addr, NULL_RTX));
-
-      if (folded != addr)
-       {
-         int addr_folded_cost = address_cost (folded, mode);
-         int addr_cost = address_cost (addr, mode);
-
-         if ((addr_folded_cost < addr_cost
-              || (addr_folded_cost == addr_cost
-                  /* ??? The rtx_cost comparison is left over from an older
-                     version of this code.  It is probably no longer helpful.*/
-                  && (rtx_cost (folded, MEM) > rtx_cost (addr, MEM)
-                      || approx_reg_cost (folded) < approx_reg_cost (addr))))
-             && validate_change (insn, loc, folded, 0))
-           addr = folded;
-       }
-    }
-
-  /* If this address is not in the hash table, we can't look for equivalences
-     of the whole address.  Also, ignore if volatile.  */
-
-  do_not_record = 0;
-  hash = HASH (addr, Pmode);
-  addr_volatile = do_not_record;
-  do_not_record = save_do_not_record;
-  hash_arg_in_memory = save_hash_arg_in_memory;
-
-  if (addr_volatile)
-    return;
-
-  elt = lookup (addr, hash, Pmode);
-
-  if (elt)
-    {
-      /* We need to find the best (under the criteria documented above) entry
-        in the class that is valid.  We use the `flag' field to indicate
-        choices that were invalid and iterate until we can't find a better
-        one that hasn't already been tried.  */
-
-      for (p = elt->first_same_value; p; p = p->next_same_value)
-       p->flag = 0;
-
-      while (found_better)
-       {
-         int best_addr_cost = address_cost (*loc, mode);
-         int best_rtx_cost = (elt->cost + 1) >> 1;
-         int exp_cost;
-         struct table_elt *best_elt = elt;
-
-         found_better = 0;
-         for (p = elt->first_same_value; p; p = p->next_same_value)
-           if (! p->flag)
-             {
-               if ((REG_P (p->exp)
-                    || exp_equiv_p (p->exp, p->exp, 1, false))
-                   && ((exp_cost = address_cost (p->exp, mode)) < best_addr_cost
-                       || (exp_cost == best_addr_cost
-                           && ((p->cost + 1) >> 1) > best_rtx_cost)))
-                 {
-                   found_better = 1;
-                   best_addr_cost = exp_cost;
-                   best_rtx_cost = (p->cost + 1) >> 1;
-                   best_elt = p;
-                 }
-             }
-
-         if (found_better)
-           {
-             if (validate_change (insn, loc,
-                                  canon_reg (copy_rtx (best_elt->exp),
-                                             NULL_RTX), 0))
-               return;
-             else
-               best_elt->flag = 1;
-           }
-       }
-    }
-
-  /* If the address is a binary operation with the first operand a register
-     and the second a constant, do the same as above, but looking for
-     equivalences of the register.  Then try to simplify before checking for
-     the best address to use.  This catches a few cases:  First is when we
-     have REG+const and the register is another REG+const.  We can often merge
-     the constants and eliminate one insn and one register.  It may also be
-     that a machine has a cheap REG+REG+const.  Finally, this improves the
-     code on the Alpha for unaligned byte stores.  */
-
-  if (flag_expensive_optimizations
-      && ARITHMETIC_P (*loc)
-      && REG_P (XEXP (*loc, 0)))
-    {
-      rtx op1 = XEXP (*loc, 1);
-
-      do_not_record = 0;
-      hash = HASH (XEXP (*loc, 0), Pmode);
-      do_not_record = save_do_not_record;
-      hash_arg_in_memory = save_hash_arg_in_memory;
-
-      elt = lookup (XEXP (*loc, 0), hash, Pmode);
-      if (elt == 0)
-       return;
-
-      /* We need to find the best (under the criteria documented above) entry
-        in the class that is valid.  We use the `flag' field to indicate
-        choices that were invalid and iterate until we can't find a better
-        one that hasn't already been tried.  */
-
-      for (p = elt->first_same_value; p; p = p->next_same_value)
-       p->flag = 0;
-
-      while (found_better)
-       {
-         int best_addr_cost = address_cost (*loc, mode);
-         int best_rtx_cost = (COST (*loc) + 1) >> 1;
-         struct table_elt *best_elt = elt;
-         rtx best_rtx = *loc;
-         int count;
-
-         /* This is at worst case an O(n^2) algorithm, so limit our search
-            to the first 32 elements on the list.  This avoids trouble
-            compiling code with very long basic blocks that can easily
-            call simplify_gen_binary so many times that we run out of
-            memory.  */
-
-         found_better = 0;
-         for (p = elt->first_same_value, count = 0;
-              p && count < 32;
-              p = p->next_same_value, count++)
-           if (! p->flag
-               && (REG_P (p->exp)
-                   || exp_equiv_p (p->exp, p->exp, 1, false)))
-             {
-               rtx new = simplify_gen_binary (GET_CODE (*loc), Pmode,
-                                              p->exp, op1);
-               int new_cost;
-               
-               /* Get the canonical version of the address so we can accept
-                  more.  */
-               new = canon_for_address (new);
-               
-               new_cost = address_cost (new, mode);
-
-               if (new_cost < best_addr_cost
-                   || (new_cost == best_addr_cost
-                       && (COST (new) + 1) >> 1 > best_rtx_cost))
-                 {
-                   found_better = 1;
-                   best_addr_cost = new_cost;
-                   best_rtx_cost = (COST (new) + 1) >> 1;
-                   best_elt = p;
-                   best_rtx = new;
-                 }
-             }
-
-         if (found_better)
-           {
-             if (validate_change (insn, loc,
-                                  canon_reg (copy_rtx (best_rtx),
-                                             NULL_RTX), 0))
-               return;
-             else
-               best_elt->flag = 1;
-           }
-       }
-    }
-}
-\f
 /* Given an operation (CODE, *PARG1, *PARG2), where code is a comparison
    operation (EQ, NE, GT, etc.), follow it back through the hash table and
    what values are being compared.
@@ -3085,7 +2807,7 @@ find_comparison_args (enum rtx_code code, rtx *parg1, rtx *parg2,
              || (GET_MODE_CLASS (GET_MODE (arg1)) == MODE_INT
                  && code == LT && STORE_FLAG_VALUE == -1)
 #ifdef FLOAT_STORE_FLAG_VALUE
-             || (GET_MODE_CLASS (GET_MODE (arg1)) == MODE_FLOAT
+             || (SCALAR_FLOAT_MODE_P (GET_MODE (arg1))
                  && (fsfv = FLOAT_STORE_FLAG_VALUE (GET_MODE (arg1)),
                      REAL_VALUE_NEGATIVE (fsfv)))
 #endif
@@ -3095,7 +2817,7 @@ find_comparison_args (enum rtx_code code, rtx *parg1, rtx *parg2,
                   || (GET_MODE_CLASS (GET_MODE (arg1)) == MODE_INT
                       && code == GE && STORE_FLAG_VALUE == -1)
 #ifdef FLOAT_STORE_FLAG_VALUE
-                  || (GET_MODE_CLASS (GET_MODE (arg1)) == MODE_FLOAT
+                  || (SCALAR_FLOAT_MODE_P (GET_MODE (arg1))
                       && (fsfv = FLOAT_STORE_FLAG_VALUE (GET_MODE (arg1)),
                           REAL_VALUE_NEGATIVE (fsfv)))
 #endif
@@ -3158,7 +2880,7 @@ find_comparison_args (enum rtx_code code, rtx *parg1, rtx *parg2,
                              << (GET_MODE_BITSIZE (inner_mode) - 1))))
 #ifdef FLOAT_STORE_FLAG_VALUE
                   || (code == LT
-                      && GET_MODE_CLASS (inner_mode) == MODE_FLOAT
+                      && SCALAR_FLOAT_MODE_P (inner_mode)
                       && (fsfv = FLOAT_STORE_FLAG_VALUE (GET_MODE (arg1)),
                           REAL_VALUE_NEGATIVE (fsfv)))
 #endif
@@ -3178,7 +2900,7 @@ find_comparison_args (enum rtx_code code, rtx *parg1, rtx *parg2,
                               << (GET_MODE_BITSIZE (inner_mode) - 1))))
 #ifdef FLOAT_STORE_FLAG_VALUE
                    || (code == GE
-                       && GET_MODE_CLASS (inner_mode) == MODE_FLOAT
+                       && SCALAR_FLOAT_MODE_P (inner_mode)
                        && (fsfv = FLOAT_STORE_FLAG_VALUE (GET_MODE (arg1)),
                            REAL_VALUE_NEGATIVE (fsfv)))
 #endif
@@ -3229,377 +2951,14 @@ find_comparison_args (enum rtx_code code, rtx *parg1, rtx *parg2,
   return code;
 }
 \f
-/* Fold SUBREG.  */
+/* If X is a nontrivial arithmetic operation on an argument for which
+   a constant value can be determined, return the result of operating
+   on that value, as a constant.  Otherwise, return X, possibly with
+   one or more operands changed to a forward-propagated constant.
 
-static rtx
-fold_rtx_subreg (rtx x, rtx insn)
-{
-  enum machine_mode mode = GET_MODE (x);
-  rtx folded_arg0;
-  rtx const_arg0;
-  rtx new;
-
-  /* See if we previously assigned a constant value to this SUBREG.  */
-  if ((new = lookup_as_function (x, CONST_INT)) != 0
-      || (new = lookup_as_function (x, CONST_DOUBLE)) != 0)
-    return new;
-
-  /* If this is a paradoxical SUBREG, we have no idea what value the
-     extra bits would have.  However, if the operand is equivalent to
-     a SUBREG whose operand is the same as our mode, and all the modes
-     are within a word, we can just use the inner operand because
-     these SUBREGs just say how to treat the register.
-
-     Similarly if we find an integer constant.  */
-
-  if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
-    {
-      enum machine_mode imode = GET_MODE (SUBREG_REG (x));
-      struct table_elt *elt;
-
-      if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD
-         && GET_MODE_SIZE (imode) <= UNITS_PER_WORD
-         && (elt = lookup (SUBREG_REG (x), HASH (SUBREG_REG (x), imode),
-                           imode)) != 0)
-       for (elt = elt->first_same_value; elt; elt = elt->next_same_value)
-         {
-           if (CONSTANT_P (elt->exp)
-               && GET_MODE (elt->exp) == VOIDmode)
-             return elt->exp;
-
-           if (GET_CODE (elt->exp) == SUBREG
-               && GET_MODE (SUBREG_REG (elt->exp)) == mode
-               && exp_equiv_p (elt->exp, elt->exp, 1, false))
-             return copy_rtx (SUBREG_REG (elt->exp));
-         }
-
-      return x;
-    }
-
-  /* Fold SUBREG_REG.  If it changed, see if we can simplify the
-     SUBREG.  We might be able to if the SUBREG is extracting a single
-     word in an integral mode or extracting the low part.  */
-
-  folded_arg0 = fold_rtx (SUBREG_REG (x), insn);
-  const_arg0 = equiv_constant (folded_arg0);
-  if (const_arg0)
-    folded_arg0 = const_arg0;
-
-  if (folded_arg0 != SUBREG_REG (x))
-    {
-      new = simplify_subreg (mode, folded_arg0,
-                            GET_MODE (SUBREG_REG (x)), SUBREG_BYTE (x));
-      if (new)
-       return new;
-    }
-
-  if (REG_P (folded_arg0)
-      && GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (folded_arg0)))
-    {
-      struct table_elt *elt;
-
-      elt = lookup (folded_arg0,
-                   HASH (folded_arg0, GET_MODE (folded_arg0)),
-                   GET_MODE (folded_arg0));
-
-      if (elt)
-       elt = elt->first_same_value;
-
-      if (subreg_lowpart_p (x))
-       /* If this is a narrowing SUBREG and our operand is a REG, see
-          if we can find an equivalence for REG that is an arithmetic
-          operation in a wider mode where both operands are
-          paradoxical SUBREGs from objects of our result mode.  In
-          that case, we couldn-t report an equivalent value for that
-          operation, since we don't know what the extra bits will be.
-          But we can find an equivalence for this SUBREG by folding
-          that operation in the narrow mode.  This allows us to fold
-          arithmetic in narrow modes when the machine only supports
-          word-sized arithmetic.
-
-          Also look for a case where we have a SUBREG whose operand
-          is the same as our result.  If both modes are smaller than
-          a word, we are simply interpreting a register in different
-          modes and we can use the inner value.  */
-
-       for (; elt; elt = elt->next_same_value)
-         {
-           enum rtx_code eltcode = GET_CODE (elt->exp);
-
-           /* Just check for unary and binary operations.  */
-           if (UNARY_P (elt->exp)
-               && eltcode != SIGN_EXTEND
-               && eltcode != ZERO_EXTEND
-               && GET_CODE (XEXP (elt->exp, 0)) == SUBREG
-               && GET_MODE (SUBREG_REG (XEXP (elt->exp, 0))) == mode
-               && (GET_MODE_CLASS (mode)
-                   == GET_MODE_CLASS (GET_MODE (XEXP (elt->exp, 0)))))
-             {
-               rtx op0 = SUBREG_REG (XEXP (elt->exp, 0));
-
-               if (!REG_P (op0) && ! CONSTANT_P (op0))
-                 op0 = fold_rtx (op0, NULL_RTX);
-
-               op0 = equiv_constant (op0);
-               if (op0)
-                 new = simplify_unary_operation (GET_CODE (elt->exp), mode,
-                                                 op0, mode);
-             }
-           else if (ARITHMETIC_P (elt->exp)
-                    && eltcode != DIV && eltcode != MOD
-                    && eltcode != UDIV && eltcode != UMOD
-                    && eltcode != ASHIFTRT && eltcode != LSHIFTRT
-                    && eltcode != ROTATE && eltcode != ROTATERT
-                    && ((GET_CODE (XEXP (elt->exp, 0)) == SUBREG
-                         && (GET_MODE (SUBREG_REG (XEXP (elt->exp, 0)))
-                             == mode))
-                        || CONSTANT_P (XEXP (elt->exp, 0)))
-                    && ((GET_CODE (XEXP (elt->exp, 1)) == SUBREG
-                         && (GET_MODE (SUBREG_REG (XEXP (elt->exp, 1)))
-                             == mode))
-                        || CONSTANT_P (XEXP (elt->exp, 1))))
-             {
-               rtx op0 = gen_lowpart_common (mode, XEXP (elt->exp, 0));
-               rtx op1 = gen_lowpart_common (mode, XEXP (elt->exp, 1));
-
-               if (op0 && !REG_P (op0) && ! CONSTANT_P (op0))
-                 op0 = fold_rtx (op0, NULL_RTX);
-
-               if (op0)
-                 op0 = equiv_constant (op0);
-
-               if (op1 && !REG_P (op1) && ! CONSTANT_P (op1))
-                 op1 = fold_rtx (op1, NULL_RTX);
-
-               if (op1)
-                 op1 = equiv_constant (op1);
-
-               /* If we are looking for the low SImode part of
-                  (ashift:DI c (const_int 32)), it doesn't work to
-                  compute that in SImode, because a 32-bit shift in
-                  SImode is unpredictable.  We know the value is
-                  0.  */
-               if (op0 && op1
-                   && GET_CODE (elt->exp) == ASHIFT
-                   && GET_CODE (op1) == CONST_INT
-                   && INTVAL (op1) >= GET_MODE_BITSIZE (mode))
-                 {
-                   if (INTVAL (op1)
-                       < GET_MODE_BITSIZE (GET_MODE (elt->exp)))
-                     /* If the count fits in the inner mode's width,
-                        but exceeds the outer mode's width, the value
-                        will get truncated to 0 by the subreg.  */
-                     new = CONST0_RTX (mode);
-                   else
-                     /* If the count exceeds even the inner mode's width,
-                        don't fold this expression.  */
-                     new = 0;
-                 }
-               else if (op0 && op1)
-                 new = simplify_binary_operation (GET_CODE (elt->exp),
-                                                  mode, op0, op1);
-             }
-
-           else if (GET_CODE (elt->exp) == SUBREG
-                    && GET_MODE (SUBREG_REG (elt->exp)) == mode
-                    && (GET_MODE_SIZE (GET_MODE (folded_arg0))
-                        <= UNITS_PER_WORD)
-                    && exp_equiv_p (elt->exp, elt->exp, 1, false))
-             new = copy_rtx (SUBREG_REG (elt->exp));
-
-           if (new)
-             return new;
-         }
-      else
-       /* A SUBREG resulting from a zero extension may fold to zero
-          if it extracts higher bits than the ZERO_EXTEND's source
-          bits.  FIXME: if combine tried to, er, combine these
-          instructions, this transformation may be moved to
-          simplify_subreg.  */
-       for (; elt; elt = elt->next_same_value)
-         {
-           if (GET_CODE (elt->exp) == ZERO_EXTEND
-               && subreg_lsb (x)
-               >= GET_MODE_BITSIZE (GET_MODE (XEXP (elt->exp, 0))))
-             return CONST0_RTX (mode);
-         }
-    }
-
-  return x;
-}
-
-/* Fold MEM.  */
-
-static rtx
-fold_rtx_mem (rtx x, rtx insn)
-{
-  enum machine_mode mode = GET_MODE (x);
-  rtx new;
-
-  /* If we are not actually processing an insn, don't try to find the
-     best address.  Not only don't we care, but we could modify the
-     MEM in an invalid way since we have no insn to validate
-     against.  */
-  if (insn != 0)
-    find_best_addr (insn, &XEXP (x, 0), mode);
-
-  {
-    /* Even if we don't fold in the insn itself, we can safely do so
-       here, in hopes of getting a constant.  */
-    rtx addr = fold_rtx (XEXP (x, 0), NULL_RTX);
-    rtx base = 0;
-    HOST_WIDE_INT offset = 0;
-
-    if (REG_P (addr)
-       && REGNO_QTY_VALID_P (REGNO (addr)))
-      {
-       int addr_q = REG_QTY (REGNO (addr));
-       struct qty_table_elem *addr_ent = &qty_table[addr_q];
-
-       if (GET_MODE (addr) == addr_ent->mode
-           && addr_ent->const_rtx != NULL_RTX)
-         addr = addr_ent->const_rtx;
-      }
-
-    /* If address is constant, split it into a base and integer
-       offset.  */
-    if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == LABEL_REF)
-      base = addr;
-    else if (GET_CODE (addr) == CONST && GET_CODE (XEXP (addr, 0)) == PLUS
-            && GET_CODE (XEXP (XEXP (addr, 0), 1)) == CONST_INT)
-      {
-       base = XEXP (XEXP (addr, 0), 0);
-       offset = INTVAL (XEXP (XEXP (addr, 0), 1));
-      }
-    else if (GET_CODE (addr) == LO_SUM
-            && GET_CODE (XEXP (addr, 1)) == SYMBOL_REF)
-      base = XEXP (addr, 1);
-
-    /* If this is a constant pool reference, we can fold it into its
-       constant to allow better value tracking.  */
-    if (base && GET_CODE (base) == SYMBOL_REF
-       && CONSTANT_POOL_ADDRESS_P (base))
-      {
-       rtx constant = get_pool_constant (base);
-       enum machine_mode const_mode = get_pool_mode (base);
-       rtx new;
-
-       if (CONSTANT_P (constant) && GET_CODE (constant) != CONST_INT)
-         {
-           constant_pool_entries_cost = COST (constant);
-           constant_pool_entries_regcost = approx_reg_cost (constant);
-         }
-
-       /* If we are loading the full constant, we have an
-          equivalence.  */
-       if (offset == 0 && mode == const_mode)
-         return constant;
-
-       /* If this actually isn't a constant (weird!), we can't do
-          anything.  Otherwise, handle the two most common cases:
-          extracting a word from a multi-word constant, and
-          extracting the low-order bits.  Other cases don't seem
-          common enough to worry about.  */
-       if (! CONSTANT_P (constant))
-         return x;
-
-       if (GET_MODE_CLASS (mode) == MODE_INT
-           && GET_MODE_SIZE (mode) == UNITS_PER_WORD
-           && offset % UNITS_PER_WORD == 0
-           && (new = operand_subword (constant,
-                                      offset / UNITS_PER_WORD,
-                                      0, const_mode)) != 0)
-         return new;
-
-       if (((BYTES_BIG_ENDIAN
-             && offset == GET_MODE_SIZE (GET_MODE (constant)) - 1)
-            || (! BYTES_BIG_ENDIAN && offset == 0))
-           && (new = gen_lowpart (mode, constant)) != 0)
-         return new;
-      }
-
-    /* If this is a reference to a label at a known position in a jump
-       table, we also know its value.  */
-    if (base && GET_CODE (base) == LABEL_REF)
-      {
-       rtx label = XEXP (base, 0);
-       rtx table_insn = NEXT_INSN (label);
-
-       if (table_insn && JUMP_P (table_insn)
-           && GET_CODE (PATTERN (table_insn)) == ADDR_VEC)
-         {
-           rtx table = PATTERN (table_insn);
-
-           if (offset >= 0
-               && (offset / GET_MODE_SIZE (GET_MODE (table))
-                   < XVECLEN (table, 0)))
-             {
-               rtx label = XVECEXP
-                 (table, 0, offset / GET_MODE_SIZE (GET_MODE (table)));
-               rtx set;
-
-               /* If we have an insn that loads the label from the
-                  jumptable into a reg, we don't want to set the reg
-                  to the label, because this may cause a reference to
-                  the label to remain after the label is removed in
-                  some very obscure cases (PR middle-end/18628).  */
-               if (!insn)
-                 return label;
-
-               set = single_set (insn);
-
-               if (! set || SET_SRC (set) != x)
-                 return x;
-
-               /* If it's a jump, it's safe to reference the label.  */
-               if (SET_DEST (set) == pc_rtx)
-                 return label;
-
-               return x;
-             }
-         }
-       if (table_insn && JUMP_P (table_insn)
-           && GET_CODE (PATTERN (table_insn)) == ADDR_DIFF_VEC)
-         {
-           rtx table = PATTERN (table_insn);
-
-           if (offset >= 0
-               && (offset / GET_MODE_SIZE (GET_MODE (table))
-                   < XVECLEN (table, 1)))
-             {
-               offset /= GET_MODE_SIZE (GET_MODE (table));
-               new = gen_rtx_MINUS (Pmode, XVECEXP (table, 1, offset),
-                                    XEXP (table, 0));
-
-               if (GET_MODE (table) != Pmode)
-                 new = gen_rtx_TRUNCATE (GET_MODE (table), new);
-
-               /* Indicate this is a constant.  This isn't a valid
-                  form of CONST, but it will only be used to fold the
-                  next insns and then discarded, so it should be
-                  safe.
-
-                  Note this expression must be explicitly discarded,
-                  by cse_insn, else it may end up in a REG_EQUAL note
-                  and "escape" to cause problems elsewhere.  */
-               return gen_rtx_CONST (GET_MODE (new), new);
-             }
-         }
-      }
-
-    return x;
-  }
-}
-
-/* If X is a nontrivial arithmetic operation on an argument
-   for which a constant value can be determined, return
-   the result of operating on that value, as a constant.
-   Otherwise, return X, possibly with one or more operands
-   modified by recursive calls to this function.
-
-   If X is a register whose contents are known, we do NOT
-   return those contents here.  equiv_constant is called to
-   perform that task.
+   If X is a register whose contents are known, we do NOT return
+   those contents here; equiv_constant is called to perform that task.
+   For SUBREGs and MEMs, we do that both here and in equiv_constant.
 
    INSN is the insn that we may be modifying.  If it is 0, make a copy
    of X before modifying it.  */
@@ -3612,10 +2971,9 @@ fold_rtx (rtx x, rtx insn)
   const char *fmt;
   int i;
   rtx new = 0;
-  int copied = 0;
-  int must_swap = 0;
+  int changed = 0;
 
-  /* Folded equivalents of first two operands of X.  */
+  /* Operands of X.  */
   rtx folded_arg0;
   rtx folded_arg1;
 
@@ -3632,10 +2990,16 @@ fold_rtx (rtx x, rtx insn)
   if (x == 0)
     return x;
 
-  mode = GET_MODE (x);
+  /* Try to perform some initial simplifications on X.  */
   code = GET_CODE (x);
   switch (code)
     {
+    case MEM:
+    case SUBREG:
+      if ((new = equiv_constant (x)) != NULL_RTX)
+        return new;
+      return x;
+
     case CONST:
     case CONST_INT:
     case CONST_DOUBLE:
@@ -3655,28 +3019,6 @@ fold_rtx (rtx x, rtx insn)
       return prev_insn_cc0;
 #endif
 
-    case SUBREG:
-      return fold_rtx_subreg (x, insn);
-
-    case NOT:
-    case NEG:
-      /* If we have (NOT Y), see if Y is known to be (NOT Z).
-        If so, (NOT Y) simplifies to Z.  Similarly for NEG.  */
-      new = lookup_as_function (XEXP (x, 0), code);
-      if (new)
-       return fold_rtx (copy_rtx (XEXP (new, 0)), insn);
-      break;
-
-    case MEM:
-      return fold_rtx_mem (x, insn);
-
-#ifdef NO_FUNCTION_CSE
-    case CALL:
-      if (CONSTANT_P (XEXP (XEXP (x, 0), 0)))
-       return x;
-      break;
-#endif
-
     case ASM_OPERANDS:
       if (insn)
        {
@@ -3684,12 +3026,21 @@ fold_rtx (rtx x, rtx insn)
            validate_change (insn, &ASM_OPERANDS_INPUT (x, i),
                             fold_rtx (ASM_OPERANDS_INPUT (x, i), insn), 0);
        }
+      return x;
+
+#ifdef NO_FUNCTION_CSE
+    case CALL:
+      if (CONSTANT_P (XEXP (XEXP (x, 0), 0)))
+       return x;
       break;
+#endif
 
+    /* Anything else goes through the loop below.  */
     default:
       break;
     }
 
+  mode = GET_MODE (x);
   const_arg0 = 0;
   const_arg1 = 0;
   const_arg2 = 0;
@@ -3702,55 +3053,13 @@ fold_rtx (rtx x, rtx insn)
   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
     if (fmt[i] == 'e')
       {
-       rtx arg = XEXP (x, i);
-       rtx folded_arg = arg, const_arg = 0;
-       enum machine_mode mode_arg = GET_MODE (arg);
-       rtx cheap_arg, expensive_arg;
-       rtx replacements[2];
-       int j;
-       int old_cost = COST_IN (XEXP (x, i), code);
-
-       /* Most arguments are cheap, so handle them specially.  */
-       switch (GET_CODE (arg))
-         {
-         case REG:
-           /* This is the same as calling equiv_constant; it is duplicated
-              here for speed.  */
-           if (REGNO_QTY_VALID_P (REGNO (arg)))
-             {
-               int arg_q = REG_QTY (REGNO (arg));
-               struct qty_table_elem *arg_ent = &qty_table[arg_q];
-
-               if (arg_ent->const_rtx != NULL_RTX
-                   && !REG_P (arg_ent->const_rtx)
-                   && GET_CODE (arg_ent->const_rtx) != PLUS)
-                 const_arg
-                   = gen_lowpart (GET_MODE (arg),
-                                              arg_ent->const_rtx);
-             }
-           break;
-
-         case CONST:
-         case CONST_INT:
-         case SYMBOL_REF:
-         case LABEL_REF:
-         case CONST_DOUBLE:
-         case CONST_VECTOR:
-           const_arg = arg;
-           break;
-
+       rtx folded_arg = XEXP (x, i), const_arg;
+       enum machine_mode mode_arg = GET_MODE (folded_arg);
 #ifdef HAVE_cc0
-         case CC0:
-           folded_arg = prev_insn_cc0;
-           mode_arg = prev_insn_cc0_mode;
-           const_arg = equiv_constant (folded_arg);
-           break;
+       if (CC0_P (folded_arg))
+         folded_arg = prev_insn_cc0, mode_arg = prev_insn_cc0_mode;
 #endif
-
-         default:
-           folded_arg = fold_rtx (arg, insn);
-           const_arg = equiv_constant (folded_arg);
-         }
+       const_arg = equiv_constant (folded_arg);
 
        /* For the first three operands, see if the operand
           is constant or equivalent to a constant.  */
@@ -3770,120 +3079,50 @@ fold_rtx (rtx x, rtx insn)
            break;
          }
 
-       /* Pick the least expensive of the folded argument and an
-          equivalent constant argument.  */
-       if (const_arg == 0 || const_arg == folded_arg
-           || COST_IN (const_arg, code) > COST_IN (folded_arg, code))
-         cheap_arg = folded_arg, expensive_arg = const_arg;
-       else
-         cheap_arg = const_arg, expensive_arg = folded_arg;
-
-       /* Try to replace the operand with the cheapest of the two
-          possibilities.  If it doesn't work and this is either of the first
-          two operands of a commutative operation, try swapping them.
-          If THAT fails, try the more expensive, provided it is cheaper
-          than what is already there.  */
-
-       if (cheap_arg == XEXP (x, i))
-         continue;
-
-       if (insn == 0 && ! copied)
-         {
-           x = copy_rtx (x);
-           copied = 1;
-         }
-
-       /* Order the replacements from cheapest to most expensive.  */
-       replacements[0] = cheap_arg;
-       replacements[1] = expensive_arg;
-
-       for (j = 0; j < 2 && replacements[j]; j++)
-         {
-           int new_cost = COST_IN (replacements[j], code);
-
-           /* Stop if what existed before was cheaper.  Prefer constants
-              in the case of a tie.  */
-           if (new_cost > old_cost
-               || (new_cost == old_cost && CONSTANT_P (XEXP (x, i))))
-             break;
+       /* Pick the least expensive of the argument and an equivalent constant
+          argument.  */
+       if (const_arg != 0
+           && const_arg != folded_arg
+           && COST_IN (const_arg, code) <= COST_IN (folded_arg, code)
 
            /* It's not safe to substitute the operand of a conversion
               operator with a constant, as the conversion's identity
               depends upon the mode of its operand.  This optimization
               is handled by the call to simplify_unary_operation.  */
-           if (GET_RTX_CLASS (code) == RTX_UNARY
-               && GET_MODE (replacements[j]) != mode_arg0
-               && (code == ZERO_EXTEND
-                   || code == SIGN_EXTEND
-                   || code == TRUNCATE
-                   || code == FLOAT_TRUNCATE
-                   || code == FLOAT_EXTEND
-                   || code == FLOAT
-                   || code == FIX
-                   || code == UNSIGNED_FLOAT
-                   || code == UNSIGNED_FIX))
-             continue;
-
-           if (validate_change (insn, &XEXP (x, i), replacements[j], 0))
-             break;
-
-           if (GET_RTX_CLASS (code) == RTX_COMM_COMPARE
-               || GET_RTX_CLASS (code) == RTX_COMM_ARITH)
-             {
-               validate_change (insn, &XEXP (x, i), XEXP (x, 1 - i), 1);
-               validate_change (insn, &XEXP (x, 1 - i), replacements[j], 1);
-
-               if (apply_change_group ())
-                 {
-                   /* Swap them back to be invalid so that this loop can
-                      continue and flag them to be swapped back later.  */
-                   rtx tem;
-
-                   tem = XEXP (x, 0); XEXP (x, 0) = XEXP (x, 1);
-                                      XEXP (x, 1) = tem;
-                   must_swap = 1;
-                   break;
-                 }
-             }
-         }
-      }
+           && (GET_RTX_CLASS (code) != RTX_UNARY
+               || GET_MODE (const_arg) == mode_arg0
+               || (code != ZERO_EXTEND
+                   && code != SIGN_EXTEND
+                   && code != TRUNCATE
+                   && code != FLOAT_TRUNCATE
+                   && code != FLOAT_EXTEND
+                   && code != FLOAT
+                   && code != FIX
+                   && code != UNSIGNED_FLOAT
+                   && code != UNSIGNED_FIX)))
+         folded_arg = const_arg;
+
+       if (folded_arg == XEXP (x, i))
+         continue;
 
-    else
-      {
-       if (fmt[i] == 'E')
-         /* Don't try to fold inside of a vector of expressions.
-            Doing nothing is harmless.  */
-         {;}
+       if (insn == NULL_RTX && !changed)
+         x = copy_rtx (x);
+       changed = 1;
+       validate_change (insn, &XEXP (x, i), folded_arg, 1);
       }
 
-  /* If a commutative operation, place a constant integer as the second
-     operand unless the first operand is also a constant integer.  Otherwise,
-     place any constant second unless the first operand is also a constant.  */
-
-  if (COMMUTATIVE_P (x))
+  if (changed)
     {
-      if (must_swap
-         || swap_commutative_operands_p (const_arg0 ? const_arg0
-                                                    : XEXP (x, 0),
-                                         const_arg1 ? const_arg1
-                                                    : XEXP (x, 1)))
+      /* Canonicalize X if necessary, and keep const_argN and folded_argN
+        consistent with the order in X.  */
+      if (canonicalize_change_group (insn, x))
        {
-         rtx tem = XEXP (x, 0);
-
-         if (insn == 0 && ! copied)
-           {
-             x = copy_rtx (x);
-             copied = 1;
-           }
-
-         validate_change (insn, &XEXP (x, 0), XEXP (x, 1), 1);
-         validate_change (insn, &XEXP (x, 1), tem, 1);
-         if (apply_change_group ())
-           {
-             tem = const_arg0, const_arg0 = const_arg1, const_arg1 = tem;
-             tem = folded_arg0, folded_arg0 = folded_arg1, folded_arg1 = tem;
-           }
+         rtx tem;
+         tem = const_arg0, const_arg0 = const_arg1, const_arg1 = tem;
+         tem = folded_arg0, folded_arg0 = folded_arg1, folded_arg1 = tem;
        }
+
+      apply_change_group ();
     }
 
   /* If X is an arithmetic operation, see if we can simplify it.  */
@@ -3940,7 +3179,7 @@ fold_rtx (rtx x, rtx insn)
          enum machine_mode mode_arg1;
 
 #ifdef FLOAT_STORE_FLAG_VALUE
-         if (GET_MODE_CLASS (mode) == MODE_FLOAT)
+         if (SCALAR_FLOAT_MODE_P (mode))
            {
              true_rtx = (CONST_DOUBLE_FROM_REAL_VALUE
                          (FLOAT_STORE_FLAG_VALUE (mode), mode));
@@ -3966,6 +3205,57 @@ fold_rtx (rtx x, rtx insn)
             comparison.  */
          if (const_arg0 == 0 || const_arg1 == 0)
            {
+             if (const_arg1 != NULL)
+               {
+                 rtx cheapest_simplification;
+                 int cheapest_cost;
+                 rtx simp_result;
+                 struct table_elt *p;
+
+                 /* See if we can find an equivalent of folded_arg0
+                    that gets us a cheaper expression, possibly a
+                    constant through simplifications.  */
+                 p = lookup (folded_arg0, SAFE_HASH (folded_arg0, mode_arg0),
+                             mode_arg0);
+                 
+                 if (p != NULL)
+                   {
+                     cheapest_simplification = x;
+                     cheapest_cost = COST (x);
+
+                     for (p = p->first_same_value; p != NULL; p = p->next_same_value)
+                       {
+                         int cost;
+
+                         /* If the entry isn't valid, skip it.  */
+                         if (! exp_equiv_p (p->exp, p->exp, 1, false))
+                           continue;
+
+                         /* Try to simplify using this equivalence.  */
+                         simp_result
+                           = simplify_relational_operation (code, mode,
+                                                            mode_arg0,
+                                                            p->exp,
+                                                            const_arg1);
+
+                         if (simp_result == NULL)
+                           continue;
+
+                         cost = COST (simp_result);
+                         if (cost < cheapest_cost)
+                           {
+                             cheapest_cost = cost;
+                             cheapest_simplification = simp_result;
+                           }
+                       }
+
+                     /* If we have a cheaper expression now, use that
+                        and try folding it further, from the top.  */
+                     if (cheapest_simplification != x)
+                       return fold_rtx (cheapest_simplification, insn);
+                   }
+               }
+
              /* Some addresses are known to be nonzero.  We don't know
                 their sign, but equality comparisons are known.  */
              if (const_arg1 == const0_rtx
@@ -4055,7 +3345,7 @@ fold_rtx (rtx x, rtx insn)
              rtx true_rtx = const_true_rtx, false_rtx = const0_rtx;
 
 #ifdef FLOAT_STORE_FLAG_VALUE
-             if (GET_MODE_CLASS (mode) == MODE_FLOAT)
+             if (SCALAR_FLOAT_MODE_P (mode))
                {
                  true_rtx = (CONST_DOUBLE_FROM_REAL_VALUE
                          (FLOAT_STORE_FLAG_VALUE (mode), mode));
@@ -4204,21 +3494,34 @@ fold_rtx (rtx x, rtx insn)
            {
              int is_shift
                = (code == ASHIFT || code == ASHIFTRT || code == LSHIFTRT);
-             rtx y = lookup_as_function (folded_arg0, code);
-             rtx inner_const;
+             rtx y, inner_const, new_const;
              enum rtx_code associate_code;
-             rtx new_const;
-
-             if (y == 0
-                 || 0 == (inner_const
-                          = equiv_constant (fold_rtx (XEXP (y, 1), 0)))
-                 || GET_CODE (inner_const) != CONST_INT
-                 /* If we have compiled a statement like
-                    "if (x == (x & mask1))", and now are looking at
-                    "x & mask2", we will have a case where the first operand
-                    of Y is the same as our first operand.  Unless we detect
-                    this case, an infinite loop will result.  */
-                 || XEXP (y, 0) == folded_arg0)
+
+             if (is_shift
+                 && (INTVAL (const_arg1) >= GET_MODE_BITSIZE (mode)
+                     || INTVAL (const_arg1) < 0))
+               {
+                 if (SHIFT_COUNT_TRUNCATED)
+                   const_arg1 = GEN_INT (INTVAL (const_arg1)
+                                         & (GET_MODE_BITSIZE (mode) - 1));
+                 else
+                   break;
+               }
+
+             y = lookup_as_function (folded_arg0, code);
+             if (y == 0)
+               break;
+
+             /* If we have compiled a statement like
+                "if (x == (x & mask1))", and now are looking at
+                "x & mask2", we will have a case where the first operand
+                of Y is the same as our first operand.  Unless we detect
+                this case, an infinite loop will result.  */
+             if (XEXP (y, 0) == folded_arg0)
+               break;
+
+             inner_const = equiv_constant (fold_rtx (XEXP (y, 1), 0));
+             if (!inner_const || GET_CODE (inner_const) != CONST_INT)
                break;
 
              /* Don't associate these operations if they are a PLUS with the
@@ -4237,6 +3540,17 @@ fold_rtx (rtx x, rtx insn)
                          && exact_log2 (- INTVAL (const_arg1)) >= 0)))
                break;
 
+             if (is_shift
+                 && (INTVAL (inner_const) >= GET_MODE_BITSIZE (mode)
+                     || INTVAL (inner_const) < 0))
+               {
+                 if (SHIFT_COUNT_TRUNCATED)
+                   inner_const = GEN_INT (INTVAL (inner_const)
+                                          & (GET_MODE_BITSIZE (mode) - 1));
+                 else
+                   break;
+               }
+
              /* Compute the code used to compose the constants.  For example,
                 A-C1-C2 is A-(C1 + C2), so if CODE == MINUS, we want PLUS.  */
 
@@ -4254,13 +3568,16 @@ fold_rtx (rtx x, rtx insn)
                 shift on a machine that does a sign-extend as a pair
                 of shifts.  */
 
-             if (is_shift && GET_CODE (new_const) == CONST_INT
+             if (is_shift
+                 && GET_CODE (new_const) == CONST_INT
                  && INTVAL (new_const) >= GET_MODE_BITSIZE (mode))
                {
                  /* As an exception, we can turn an ASHIFTRT of this
                     form into a shift of the number of bits - 1.  */
                  if (code == ASHIFTRT)
                    new_const = GEN_INT (GET_MODE_BITSIZE (mode) - 1);
+                 else if (!side_effects_p (XEXP (y, 0)))
+                   return CONST0_RTX (mode);
                  else
                    break;
                }
@@ -4337,16 +3654,31 @@ equiv_constant (rtx x)
   if (x == 0 || CONSTANT_P (x))
     return x;
 
-  /* If X is a MEM, try to fold it outside the context of any insn to see if
-     it might be equivalent to a constant.  That handles the case where it
-     is a constant-pool reference.  Then try to look it up in the hash table
-     in case it is something whose value we have seen before.  */
+  if (GET_CODE (x) == SUBREG)
+    {
+      rtx new;
+
+      /* See if we previously assigned a constant value to this SUBREG.  */
+      if ((new = lookup_as_function (x, CONST_INT)) != 0
+          || (new = lookup_as_function (x, CONST_DOUBLE)) != 0)
+        return new;
+
+      if (REG_P (SUBREG_REG (x))
+         && (new = equiv_constant (SUBREG_REG (x))) != 0)
+        return simplify_subreg (GET_MODE (x), SUBREG_REG (x),
+                               GET_MODE (SUBREG_REG (x)), SUBREG_BYTE (x));
+
+      return 0;
+    }
+
+  /* If X is a MEM, see if it is a constant-pool reference, or look it up in
+     the hash table in case its value was seen before.  */
 
   if (MEM_P (x))
     {
       struct table_elt *elt;
 
-      x = fold_rtx (x, NULL_RTX);
+      x = avoid_constant_pool_reference (x);
       if (CONSTANT_P (x))
        return x;
 
@@ -4681,6 +4013,8 @@ struct set
   unsigned src_const_hash;
   /* Table entry for constant equivalent for SET_SRC, if any.  */
   struct table_elt *src_const_elt;
+  /* Table entry for the destination address.  */
+  struct table_elt *dest_addr_elt;
 };
 
 static void
@@ -4877,17 +4211,9 @@ cse_insn (rtx insn, rtx libcall_insn)
       rtx dest = SET_DEST (sets[i].rtl);
       rtx src = SET_SRC (sets[i].rtl);
       rtx new = canon_reg (src, insn);
-      int insn_code;
 
       sets[i].orig_src = src;
-      if ((REG_P (new) && REG_P (src)
-          && ((REGNO (new) < FIRST_PSEUDO_REGISTER)
-              != (REGNO (src) < FIRST_PSEUDO_REGISTER)))
-         || (insn_code = recog_memoized (insn)) < 0
-         || insn_data[insn_code].n_dups > 0)
-       validate_change (insn, &SET_SRC (sets[i].rtl), new, 1);
-      else
-       SET_SRC (sets[i].rtl) = new;
+      validate_change (insn, &SET_SRC (sets[i].rtl), new, 1);
 
       if (GET_CODE (dest) == ZERO_EXTRACT)
        {
@@ -5500,6 +4826,22 @@ cse_insn (rtx insn, rtx libcall_insn)
              break;
            }
 
+         /* Reject certain invalid forms of CONST that we create.  */
+         else if (CONSTANT_P (trial)
+                  && GET_CODE (trial) == CONST
+                  /* Reject cases that will cause decode_rtx_const to
+                     die.  On the alpha when simplifying a switch, we
+                     get (const (truncate (minus (label_ref)
+                     (label_ref)))).  */
+                  && (GET_CODE (XEXP (trial, 0)) == TRUNCATE
+                      /* Likewise on IA-64, except without the
+                         truncate.  */
+                      || (GET_CODE (XEXP (trial, 0)) == MINUS
+                          && GET_CODE (XEXP (XEXP (trial, 0), 0)) == LABEL_REF
+                          && GET_CODE (XEXP (XEXP (trial, 0), 1)) == LABEL_REF)))
+           /* Do nothing for this case.  */
+           ;
+
          /* Look for a substitution that makes a valid insn.  */
          else if (validate_change (insn, &SET_SRC (sets[i].rtl), trial, 0))
            {
@@ -5535,17 +4877,6 @@ cse_insn (rtx insn, rtx libcall_insn)
 
          else if (constant_pool_entries_cost
                   && CONSTANT_P (trial)
-                  /* Reject cases that will cause decode_rtx_const to
-                     die.  On the alpha when simplifying a switch, we
-                     get (const (truncate (minus (label_ref)
-                     (label_ref)))).  */
-                  && ! (GET_CODE (trial) == CONST
-                        && GET_CODE (XEXP (trial, 0)) == TRUNCATE)
-                  /* Likewise on IA-64, except without the truncate.  */
-                  && ! (GET_CODE (trial) == CONST
-                        && GET_CODE (XEXP (trial, 0)) == MINUS
-                        && GET_CODE (XEXP (XEXP (trial, 0), 0)) == LABEL_REF
-                        && GET_CODE (XEXP (XEXP (trial, 0), 1)) == LABEL_REF)
                   && (src_folded == 0
                       || (!MEM_P (src_folded)
                           && ! src_folded_force_flag))
@@ -5668,7 +4999,7 @@ cse_insn (rtx insn, rtx libcall_insn)
          rtx addr = XEXP (dest, 0);
          if (GET_RTX_CLASS (GET_CODE (addr)) == RTX_AUTOINC
              && XEXP (addr, 0) == stack_pointer_rtx)
-           invalidate (stack_pointer_rtx, Pmode);
+           invalidate (stack_pointer_rtx, VOIDmode);
 #endif
          dest = fold_rtx (dest, insn);
        }
@@ -5915,6 +5246,40 @@ cse_insn (rtx insn, rtx libcall_insn)
         so that the destination goes into that class.  */
       sets[i].src_elt = src_eqv_elt;
 
+  /* Record destination addresses in the hash table.  This allows us to
+     check if they are invalidated by other sets.  */
+  for (i = 0; i < n_sets; i++)
+    {
+      if (sets[i].rtl)
+       {
+         rtx x = sets[i].inner_dest;
+         struct table_elt *elt;
+         enum machine_mode mode;
+         unsigned hash;
+
+         if (MEM_P (x))
+           {
+             x = XEXP (x, 0);
+             mode = GET_MODE (x);
+             hash = HASH (x, mode);
+             elt = lookup (x, hash, mode);
+             if (!elt)
+               {
+                 if (insert_regs (x, NULL, 0))
+                   {
+                     rehash_using_reg (x);
+                     hash = HASH (x, mode);
+                   }
+                 elt = insert (x, NULL, hash, mode);
+               }
+
+             sets[i].dest_addr_elt = elt;
+           }
+         else
+           sets[i].dest_addr_elt = NULL;
+       }
+    }
+
   invalidate_from_clobbers (x);
 
   /* Some registers are invalidated by subroutine calls.  Memory is
@@ -6007,12 +5372,20 @@ cse_insn (rtx insn, rtx libcall_insn)
     }
 
   /* We may have just removed some of the src_elt's from the hash table.
-     So replace each one with the current head of the same class.  */
+     So replace each one with the current head of the same class.
+     Also check if destination addresses have been removed.  */
 
   for (i = 0; i < n_sets; i++)
     if (sets[i].rtl)
       {
-       if (sets[i].src_elt && sets[i].src_elt->first_same_value == 0)
+       if (sets[i].dest_addr_elt
+           && sets[i].dest_addr_elt->first_same_value == 0)
+         {
+           /* The elt was removed, which means this destination is not
+              valid after this instruction.  */
+           sets[i].rtl = NULL_RTX;
+         }
+       else if (sets[i].src_elt && sets[i].src_elt->first_same_value == 0)
          /* If elt was removed, find current head of same class,
             or 0 if nothing remains of that class.  */
          {
@@ -6301,33 +5674,6 @@ invalidate_memory (void)
       }
 }
 
-/* If ADDR is an address that implicitly affects the stack pointer, return
-   1 and update the register tables to show the effect.  Else, return 0.  */
-
-static int
-addr_affects_sp_p (rtx addr)
-{
-  if (GET_RTX_CLASS (GET_CODE (addr)) == RTX_AUTOINC
-      && REG_P (XEXP (addr, 0))
-      && REGNO (XEXP (addr, 0)) == STACK_POINTER_REGNUM)
-    {
-      if (REG_TICK (STACK_POINTER_REGNUM) >= 0)
-       {
-         REG_TICK (STACK_POINTER_REGNUM)++;
-         /* Is it possible to use a subreg of SP?  */
-         SUBREG_TICKED (STACK_POINTER_REGNUM) = -1;
-       }
-
-      /* This should be *very* rare.  */
-      if (TEST_HARD_REG_BIT (hard_regs_in_table, STACK_POINTER_REGNUM))
-       invalidate (stack_pointer_rtx, VOIDmode);
-
-      return 1;
-    }
-
-  return 0;
-}
-
 /* Perform invalidation on the basis of everything about an insn
    except for invalidating the actual places that are SET in it.
    This includes the places CLOBBERed, and anything that might
@@ -6439,7 +5785,7 @@ cse_process_notes (rtx x, rtx object)
            {
              rtx new = gen_lowpart (GET_MODE (x), ent->const_rtx);
              if (new)
-               return new;
+               return copy_rtx (new);
            }
        }
 
@@ -6458,66 +5804,6 @@ cse_process_notes (rtx x, rtx object)
   return x;
 }
 \f
-/* Process one SET of an insn that was skipped.  We ignore CLOBBERs
-   since they are done elsewhere.  This function is called via note_stores.  */
-
-static void
-invalidate_skipped_set (rtx dest, rtx set, void *data ATTRIBUTE_UNUSED)
-{
-  enum rtx_code code = GET_CODE (dest);
-
-  if (code == MEM
-      && ! addr_affects_sp_p (dest)    /* If this is not a stack push ...  */
-      /* There are times when an address can appear varying and be a PLUS
-        during this scan when it would be a fixed address were we to know
-        the proper equivalences.  So invalidate all memory if there is
-        a BLKmode or nonscalar memory reference or a reference to a
-        variable address.  */
-      && (MEM_IN_STRUCT_P (dest) || GET_MODE (dest) == BLKmode
-         || cse_rtx_varies_p (XEXP (dest, 0), 0)))
-    {
-      invalidate_memory ();
-      return;
-    }
-
-  if (GET_CODE (set) == CLOBBER
-      || CC0_P (dest)
-      || dest == pc_rtx)
-    return;
-
-  if (code == STRICT_LOW_PART || code == ZERO_EXTRACT)
-    invalidate (XEXP (dest, 0), GET_MODE (dest));
-  else if (code == REG || code == SUBREG || code == MEM)
-    invalidate (dest, VOIDmode);
-}
-
-/* Invalidate all insns from START up to the end of the function or the
-   next label.  This called when we wish to CSE around a block that is
-   conditionally executed.  */
-
-static void
-invalidate_skipped_block (rtx start)
-{
-  rtx insn;
-
-  for (insn = start; insn && !LABEL_P (insn);
-       insn = NEXT_INSN (insn))
-    {
-      if (! INSN_P (insn))
-       continue;
-
-      if (CALL_P (insn))
-       {
-         if (! CONST_OR_PURE_CALL_P (insn))
-           invalidate_memory ();
-         invalidate_for_call ();
-       }
-
-      invalidate_from_clobbers (PATTERN (insn));
-      note_stores (PATTERN (insn), invalidate_skipped_set, NULL);
-    }
-}
-\f
 /* Find the end of INSN's basic block and return its range,
    the total number of SETs in all the insns of the block, the last insn of the
    block, and the branch path.
@@ -6525,7 +5811,7 @@ invalidate_skipped_block (rtx start)
    The branch path indicates which branches should be followed.  If a nonzero
    path size is specified, the block should be rescanned and a different set
    of branches will be taken.  The branch path is only used if
-   FLAG_CSE_FOLLOW_JUMPS or FLAG_CSE_SKIP_BLOCKS is nonzero.
+   FLAG_CSE_FOLLOW_JUMPS is nonzero.
 
    DATA is a pointer to a struct cse_basic_block_data, defined below, that is
    used to describe the block.  It is filled in with the information about
@@ -6534,7 +5820,7 @@ invalidate_skipped_block (rtx start)
 
 static void
 cse_end_of_basic_block (rtx insn, struct cse_basic_block_data *data,
-                       int follow_jumps, int skip_blocks)
+                       int follow_jumps)
 {
   rtx p = insn, q;
   int nsets = 0;
@@ -6565,9 +5851,9 @@ cse_end_of_basic_block (rtx insn, struct cse_basic_block_data *data,
      to figure out where to go next.  We want to return the next block
      in the instruction stream, not some branched-to block somewhere
      else.  We accomplish this by pretending our called forbid us to
-     follow jumps, or skip blocks.  */
+     follow jumps.  */
   if (GET_MODE (insn) == QImode)
-    follow_jumps = skip_blocks = 0;
+    follow_jumps = 0;
 
   /* Scan to end of this basic block.  */
   while (p && !LABEL_P (p))
@@ -6608,14 +5894,9 @@ cse_end_of_basic_block (rtx insn, struct cse_basic_block_data *data,
       /* If this is a conditional jump, we can follow it if -fcse-follow-jumps
         was specified, we haven't reached our maximum path length, there are
         insns following the target of the jump, this is the only use of the
-        jump label, and the target label is preceded by a BARRIER.
-
-        Alternatively, we can follow the jump if it branches around a
-        block of code and there are no other branches into the block.
-        In this case invalidate_skipped_block will be called to invalidate any
-        registers set in the block when following the jump.  */
-
-      else if ((follow_jumps || skip_blocks) && path_size < PARAM_VALUE (PARAM_MAX_CSE_PATH_LENGTH) - 1
+        jump label, and the target label is preceded by a BARRIER.  */
+      else if (follow_jumps
+              && path_size < PARAM_VALUE (PARAM_MAX_CSE_PATH_LENGTH) - 1
               && JUMP_P (p)
               && GET_CODE (PATTERN (p)) == SET
               && GET_CODE (SET_SRC (PATTERN (p))) == IF_THEN_ELSE
@@ -6625,7 +5906,6 @@ cse_end_of_basic_block (rtx insn, struct cse_basic_block_data *data,
        {
          for (q = PREV_INSN (JUMP_LABEL (p)); q; q = PREV_INSN (q))
            if ((!NOTE_P (q)
-                || NOTE_LINE_NUMBER (q) == NOTE_INSN_LOOP_END
                 || (PREV_INSN (q) && CALL_P (PREV_INSN (q))
                     && find_reg_note (PREV_INSN (q), REG_SETJMP, NULL)))
                && (!LABEL_P (q) || LABEL_NUSES (q) != 0))
@@ -6664,42 +5944,6 @@ cse_end_of_basic_block (rtx insn, struct cse_basic_block_data *data,
              /* Mark block so we won't scan it again later.  */
              PUT_MODE (NEXT_INSN (p), QImode);
            }
-         /* Detect a branch around a block of code.  */
-         else if (skip_blocks && q != 0 && !LABEL_P (q))
-           {
-             rtx tmp;
-
-             if (next_real_insn (q) == next)
-               {
-                 p = NEXT_INSN (p);
-                 continue;
-               }
-
-             for (i = 0; i < path_entry; i++)
-               if (data->path[i].branch == p)
-                 break;
-
-             if (i != path_entry)
-               break;
-
-             /* This is no_labels_between_p (p, q) with an added check for
-                reaching the end of a function (in case Q precedes P).  */
-             for (tmp = NEXT_INSN (p); tmp && tmp != q; tmp = NEXT_INSN (tmp))
-               if (LABEL_P (tmp))
-                 break;
-
-             if (tmp == q)
-               {
-                 data->path[path_entry].branch = p;
-                 data->path[path_entry++].status = PATH_AROUND;
-
-                 path_size = path_entry;
-
-                 p = JUMP_LABEL (p);
-                 /* Mark block so we won't scan it again later.  */
-                 PUT_MODE (NEXT_INSN (p), QImode);
-               }
-           }
        }
       p = NEXT_INSN (p);
     }
@@ -6732,7 +5976,7 @@ cse_end_of_basic_block (rtx insn, struct cse_basic_block_data *data,
    in conditional jump instructions.  */
 
 int
-cse_main (rtx f, int nregs, FILE *file)
+cse_main (rtx f, int nregs)
 {
   struct cse_basic_block_data val;
   rtx insn = f;
@@ -6740,8 +5984,7 @@ cse_main (rtx f, int nregs, FILE *file)
 
   init_cse_reg_info (nregs);
 
-  val.path = xmalloc (sizeof (struct branch_path)
-                     * PARAM_VALUE (PARAM_MAX_CSE_PATH_LENGTH));
+  val.path = XNEWVEC (struct branch_path, PARAM_VALUE (PARAM_MAX_CSE_PATH_LENGTH));
 
   cse_jumps_altered = 0;
   recorded_label_ref = 0;
@@ -6753,28 +5996,19 @@ cse_main (rtx f, int nregs, FILE *file)
   init_recog ();
   init_alias_analysis ();
 
-  reg_eqv_table = xmalloc (nregs * sizeof (struct reg_eqv_elem));
+  reg_eqv_table = XNEWVEC (struct reg_eqv_elem, nregs);
 
   /* Find the largest uid.  */
 
   max_uid = get_max_uid ();
-  uid_cuid = xcalloc (max_uid + 1, sizeof (int));
+  uid_cuid = XCNEWVEC (int, max_uid + 1);
 
   /* Compute the mapping from uids to cuids.
      CUIDs are numbers assigned to insns, like uids,
-     except that cuids increase monotonically through the code.
-     Don't assign cuids to line-number NOTEs, so that the distance in cuids
-     between two insns is not affected by -g.  */
+     except that cuids increase monotonically through the code.  */
 
   for (insn = f, i = 0; insn; insn = NEXT_INSN (insn))
-    {
-      if (!NOTE_P (insn)
-         || NOTE_LINE_NUMBER (insn) < 0)
-       INSN_CUID (insn) = ++i;
-      else
-       /* Give a line number note the same cuid as preceding insn.  */
-       INSN_CUID (insn) = i;
-    }
+    INSN_CUID (insn) = ++i;
 
   /* Loop over basic blocks.
      Compute the maximum number of qty's needed for each basic block
@@ -6783,8 +6017,7 @@ cse_main (rtx f, int nregs, FILE *file)
   while (insn)
     {
       cse_altered = 0;
-      cse_end_of_basic_block (insn, &val, flag_cse_follow_jumps,
-                             flag_cse_skip_blocks);
+      cse_end_of_basic_block (insn, &val, flag_cse_follow_jumps);
 
       /* If this basic block was already processed or has no sets, skip it.  */
       if (val.nsets == 0 || GET_MODE (insn) == QImode)
@@ -6799,8 +6032,8 @@ cse_main (rtx f, int nregs, FILE *file)
       cse_basic_block_end = val.high_cuid;
       max_qty = val.nsets * 2;
 
-      if (file)
-       fprintf (file, ";; Processing block from %d to %d, %d sets.\n",
+      if (dump_file)
+       fprintf (dump_file, ";; Processing block from %d to %d, %d sets.\n",
                 INSN_UID (insn), val.last ? INSN_UID (val.last) : 0,
                 val.nsets);
 
@@ -6824,8 +6057,7 @@ cse_main (rtx f, int nregs, FILE *file)
             us a new branch path to investigate.  */
          cse_jumps_altered = 0;
          temp = cse_basic_block (insn, val.last, val.path);
-         if (cse_jumps_altered == 0
-             || (flag_cse_follow_jumps == 0 && flag_cse_skip_blocks == 0))
+         if (cse_jumps_altered == 0 || flag_cse_follow_jumps)
            insn = temp;
 
          cse_jumps_altered |= old_cse_jumps_altered;
@@ -6863,7 +6095,7 @@ cse_basic_block (rtx from, rtx to, struct branch_path *next_branch)
   int no_conflict = 0;
 
   /* Allocate the space needed by qty_table.  */
-  qty_table = xmalloc (max_qty * sizeof (struct qty_table_elem));
+  qty_table = XNEWVEC (struct qty_table_elem, max_qty);
 
   new_basic_block ();
 
@@ -6884,7 +6116,7 @@ cse_basic_block (rtx from, rtx to, struct branch_path *next_branch)
 
         ??? This is a real kludge and needs to be done some other way.
         Perhaps for 2.9.  */
-      if (code != NOTE && num_insns++ > 1000)
+      if (code != NOTE && num_insns++ > PARAM_VALUE (PARAM_MAX_CSE_INSNS))
        {
          flush_hash_table ();
          num_insns = 0;
@@ -6897,10 +6129,8 @@ cse_basic_block (rtx from, rtx to, struct branch_path *next_branch)
          enum taken status = next_branch++->status;
          if (status != PATH_NOT_TAKEN)
            {
-             if (status == PATH_TAKEN)
-               record_jump_equiv (insn, 1);
-             else
-               invalidate_skipped_block (NEXT_INSN (insn));
+             gcc_assert (status == PATH_TAKEN);
+             record_jump_equiv (insn, 1);
 
              /* Set the last insn as the jump insn; it doesn't affect cc0.
                 Then follow this branch.  */
@@ -6991,64 +6221,6 @@ cse_basic_block (rtx from, rtx to, struct branch_path *next_branch)
 
          insn = PREV_INSN (to);
        }
-
-      /* See if it is ok to keep on going past the label
-        which used to end our basic block.  Remember that we incremented
-        the count of that label, so we decrement it here.  If we made
-        a jump unconditional, TO_USAGE will be one; in that case, we don't
-        want to count the use in that jump.  */
-
-      if (to != 0 && NEXT_INSN (insn) == to
-         && LABEL_P (to) && --LABEL_NUSES (to) == to_usage)
-       {
-         struct cse_basic_block_data val;
-         rtx prev;
-
-         insn = NEXT_INSN (to);
-
-         /* If TO was the last insn in the function, we are done.  */
-         if (insn == 0)
-           {
-             free (qty_table);
-             return 0;
-           }
-
-         /* If TO was preceded by a BARRIER we are done with this block
-            because it has no continuation.  */
-         prev = prev_nonnote_insn (to);
-         if (prev && BARRIER_P (prev))
-           {
-             free (qty_table);
-             return insn;
-           }
-
-         /* Find the end of the following block.  Note that we won't be
-            following branches in this case.  */
-         to_usage = 0;
-         val.path_size = 0;
-         val.path = xmalloc (sizeof (struct branch_path)
-                             * PARAM_VALUE (PARAM_MAX_CSE_PATH_LENGTH));
-         cse_end_of_basic_block (insn, &val, 0, 0);
-         free (val.path);
-
-         /* If the tables we allocated have enough space left
-            to handle all the SETs in the next basic block,
-            continue through it.  Otherwise, return,
-            and that block will be scanned individually.  */
-         if (val.nsets * 2 + next_qty > max_qty)
-           break;
-
-         cse_basic_block_start = val.low_cuid;
-         cse_basic_block_end = val.high_cuid;
-         to = val.last;
-
-         /* Prevent TO from being deleted if it is a label.  */
-         if (to != 0 && LABEL_P (to))
-           ++LABEL_NUSES (to);
-
-         /* Back up so we process the first insn in the extension.  */
-         insn = PREV_INSN (insn);
-       }
     }
 
   gcc_assert (next_qty <= max_qty);
@@ -7079,10 +6251,16 @@ check_for_label_ref (rtx *rtl, void *data)
 \f
 /* Count the number of times registers are used (not set) in X.
    COUNTS is an array in which we accumulate the count, INCR is how much
-   we count each register usage.  */
+   we count each register usage.
+
+   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.  */
 
 static void
-count_reg_usage (rtx x, int *counts, int incr)
+count_reg_usage (rtx x, int *counts, rtx dest, int incr)
 {
   enum rtx_code code;
   rtx note;
@@ -7095,7 +6273,8 @@ count_reg_usage (rtx x, int *counts, int incr)
   switch (code = GET_CODE (x))
     {
     case REG:
-      counts[REGNO (x)] += incr;
+      if (x != dest)
+       counts[REGNO (x)] += incr;
       return;
 
     case PC:
@@ -7112,23 +6291,28 @@ count_reg_usage (rtx x, int *counts, int incr)
       /* If we are clobbering a MEM, mark any registers inside the address
          as being used.  */
       if (MEM_P (XEXP (x, 0)))
-       count_reg_usage (XEXP (XEXP (x, 0), 0), counts, incr);
+       count_reg_usage (XEXP (XEXP (x, 0), 0), counts, NULL_RTX, incr);
       return;
 
     case SET:
       /* Unless we are setting a REG, count everything in SET_DEST.  */
       if (!REG_P (SET_DEST (x)))
-       count_reg_usage (SET_DEST (x), counts, incr);
-      count_reg_usage (SET_SRC (x), counts, incr);
+       count_reg_usage (SET_DEST (x), counts, NULL_RTX, incr);
+      count_reg_usage (SET_SRC (x), counts,
+                      dest ? dest : SET_DEST (x),
+                      incr);
       return;
 
     case CALL_INSN:
-      count_reg_usage (CALL_INSN_FUNCTION_USAGE (x), counts, incr);
-      /* Fall through.  */
-
     case INSN:
     case JUMP_INSN:
-      count_reg_usage (PATTERN (x), counts, incr);
+    /* 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)))
+       dest = pc_rtx;
+      if (code == CALL_INSN)
+       count_reg_usage (CALL_INSN_FUNCTION_USAGE (x), counts, dest, incr);
+      count_reg_usage (PATTERN (x), counts, dest, incr);
 
       /* Things used in a REG_EQUAL note aren't dead since loop may try to
         use them.  */
@@ -7143,12 +6327,12 @@ count_reg_usage (rtx x, int *counts, int incr)
             Process all the arguments.  */
            do
              {
-               count_reg_usage (XEXP (eqv, 0), counts, incr);
+               count_reg_usage (XEXP (eqv, 0), counts, dest, incr);
                eqv = XEXP (eqv, 1);
              }
            while (eqv && GET_CODE (eqv) == EXPR_LIST);
          else
-           count_reg_usage (eqv, counts, incr);
+           count_reg_usage (eqv, counts, dest, incr);
        }
       return;
 
@@ -7158,15 +6342,19 @@ count_reg_usage (rtx x, int *counts, int incr)
          /* FUNCTION_USAGE expression lists may include (CLOBBER (mem /u)),
             involving registers in the address.  */
          || GET_CODE (XEXP (x, 0)) == CLOBBER)
-       count_reg_usage (XEXP (x, 0), counts, incr);
+       count_reg_usage (XEXP (x, 0), counts, NULL_RTX, incr);
 
-      count_reg_usage (XEXP (x, 1), counts, incr);
+      count_reg_usage (XEXP (x, 1), counts, NULL_RTX, 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, incr);
+       count_reg_usage (ASM_OPERANDS_INPUT (x, i), counts, dest, incr);
       return;
 
     case INSN_LIST:
@@ -7180,10 +6368,10 @@ count_reg_usage (rtx x, int *counts, int incr)
   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
     {
       if (fmt[i] == 'e')
-       count_reg_usage (XEXP (x, i), counts, incr);
+       count_reg_usage (XEXP (x, i), counts, dest, incr);
       else if (fmt[i] == 'E')
        for (j = XVECLEN (x, i) - 1; j >= 0; j--)
-         count_reg_usage (XVECEXP (x, i, j), counts, incr);
+         count_reg_usage (XVECEXP (x, i, j), counts, dest, incr);
     }
 }
 \f
@@ -7270,11 +6458,11 @@ dead_libcall_p (rtx insn, int *counts)
     new = XEXP (note, 0);
 
   /* While changing insn, we must update the counts accordingly.  */
-  count_reg_usage (insn, counts, -1);
+  count_reg_usage (insn, counts, NULL_RTX, -1);
 
   if (validate_change (insn, &SET_SRC (set), new, 0))
     {
-      count_reg_usage (insn, counts, 1);
+      count_reg_usage (insn, counts, NULL_RTX, 1);
       remove_note (insn, find_reg_note (insn, REG_RETVAL, NULL_RTX));
       remove_note (insn, note);
       return true;
@@ -7285,14 +6473,14 @@ dead_libcall_p (rtx insn, int *counts)
       new = force_const_mem (GET_MODE (SET_DEST (set)), new);
       if (new && validate_change (insn, &SET_SRC (set), new, 0))
        {
-         count_reg_usage (insn, counts, 1);
+         count_reg_usage (insn, counts, NULL_RTX, 1);
          remove_note (insn, find_reg_note (insn, REG_RETVAL, NULL_RTX));
          remove_note (insn, note);
          return true;
        }
     }
 
-  count_reg_usage (insn, counts, 1);
+  count_reg_usage (insn, counts, NULL_RTX, 1);
   return false;
 }
 
@@ -7314,10 +6502,10 @@ delete_trivially_dead_insns (rtx insns, int nreg)
 
   timevar_push (TV_DELETE_TRIVIALLY_DEAD);
   /* First count the number of times each register is used.  */
-  counts = xcalloc (nreg, sizeof (int));
+  counts = XCNEWVEC (int, nreg);
   for (insn = insns; insn; insn = NEXT_INSN (insn))
     if (INSN_P (insn))
-      count_reg_usage (insn, counts, 1);
+      count_reg_usage (insn, counts, NULL_RTX, 1);
 
   /* 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
@@ -7355,7 +6543,7 @@ delete_trivially_dead_insns (rtx insns, int nreg)
 
       if (! live_insn)
        {
-         count_reg_usage (insn, counts, -1);
+         count_reg_usage (insn, counts, NULL_RTX, -1);
          delete_insn_and_edges (insn);
          ndead++;
        }
@@ -7639,7 +6827,7 @@ cse_cc_succs (basic_block bb, rtx cc_reg, rtx cc_src, bool can_change_mode)
 /* If we have a fixed condition code register (or two), walk through
    the instructions and try to eliminate duplicate assignments.  */
 
-void
+static void
 cse_condition_code_reg (void)
 {
   unsigned int cc_regno_1;
@@ -7753,17 +6941,17 @@ gate_handle_cse (void)
   return optimize > 0;
 }
 
-static void
+static unsigned int
 rest_of_handle_cse (void)
 {
   int tem;
 
   if (dump_file)
-    dump_flow_info (dump_file);
+    dump_flow_info (dump_file, dump_flags);
 
   reg_scan (get_insns (), max_reg_num ());
 
-  tem = cse_main (get_insns (), max_reg_num (), dump_file);
+  tem = cse_main (get_insns (), max_reg_num ());
   if (tem)
     rebuild_jump_labels (get_insns ());
   if (purge_all_dead_edges ())
@@ -7779,7 +6967,8 @@ rest_of_handle_cse (void)
     delete_dead_jumptables ();
 
   if (tem || optimize > 1)
-    cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_PRE_LOOP);
+    cleanup_cfg (CLEANUP_EXPENSIVE);
+  return 0;
 }
 
 struct tree_opt_pass pass_cse =
@@ -7808,15 +6997,15 @@ gate_handle_cse2 (void)
 }
 
 /* Run second CSE pass after loop optimizations.  */
-static void
+static unsigned int
 rest_of_handle_cse2 (void)
 {
   int tem;
 
   if (dump_file)
-    dump_flow_info (dump_file);
+    dump_flow_info (dump_file, dump_flags);
 
-  tem = cse_main (get_insns (), max_reg_num (), dump_file);
+  tem = cse_main (get_insns (), max_reg_num ());
 
   /* Run a pass to eliminate duplicated assignments to condition code
      registers.  We have to run this after bypass_jumps, because it
@@ -7837,6 +7026,7 @@ rest_of_handle_cse2 (void)
     }
   reg_scan (get_insns (), max_reg_num ());
   cse_not_expected = 1;
+  return 0;
 }