OSDN Git Service

2006-02-15 Paolo Bonzini <bonzini@gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / cse.c
index e155db9..7d6f46b 100644 (file)
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -1,6 +1,6 @@
 /* Common subexpression elimination for GNU compiler.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998
-   1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -16,19 +16,18 @@ for more details.
 
 You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.  */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.  */
 
 #include "config.h"
 /* stdio.h must precede rtl.h for FFS.  */
 #include "system.h"
 #include "coretypes.h"
 #include "tm.h"
-
 #include "rtl.h"
 #include "tm_p.h"
-#include "regs.h"
 #include "hard-reg-set.h"
+#include "regs.h"
 #include "basic-block.h"
 #include "flags.h"
 #include "real.h"
@@ -43,6 +42,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "except.h"
 #include "target.h"
 #include "params.h"
+#include "rtlhooks-def.h"
+#include "tree-pass.h"
 
 /* The basic idea of common subexpression elimination is to go
    through the code, keeping a record of expressions that would
@@ -80,14 +81,15 @@ Registers and "quantity numbers":
    copies one register into another, we copy the quantity number.
    When a register is loaded in any other way, we allocate a new
    quantity number to describe the value generated by this operation.
-   `reg_qty' records what quantity a register is currently thought
+   `REG_QTY (N)' records what quantity register N is currently thought
    of as containing.
 
-   All real quantity numbers are greater than or equal to `max_reg'.
-   If register N has not been assigned a quantity, reg_qty[N] will equal N.
+   All real quantity numbers are greater than or equal to zero.
+   If register N has not been assigned a quantity, `REG_QTY (N)' will
+   equal -N - 1, which is always negative.
 
-   Quantity numbers below `max_reg' do not exist and none of the `qty_table'
-   entries should be referenced with an index below `max_reg'.
+   Quantity numbers below zero do not exist and none of the `qty_table'
+   entries should be referenced with a negative index.
 
    We also maintain a bidirectional chain of registers for each
    quantity number.  The `qty_table` members `first_reg' and `last_reg',
@@ -171,18 +173,20 @@ Other expressions:
    the register's new value.  This sequence of circumstances is rare
    within any one basic block.
 
-   The vectors `reg_tick' and `reg_in_table' are used to detect this case.
-   reg_tick[i] is incremented whenever a value is stored in register i.
-   reg_in_table[i] holds -1 if no references to register i have been
-   entered in the table; otherwise, it contains the value reg_tick[i] had
-   when the references were entered.  If we want to enter a reference
-   and reg_in_table[i] != reg_tick[i], we must scan and remove old references.
-   Until we want to enter a new entry, the mere fact that the two vectors
-   don't match makes the entries be ignored if anyone tries to match them.
+   `REG_TICK' and `REG_IN_TABLE', accessors for members of
+   cse_reg_info, are used to detect this case.  REG_TICK (i) is
+   incremented whenever a value is stored in register i.
+   REG_IN_TABLE (i) holds -1 if no references to register i have been
+   entered in the table; otherwise, it contains the value REG_TICK (i)
+   had when the references were entered.  If we want to enter a
+   reference and REG_IN_TABLE (i) != REG_TICK (i), we must scan and
+   remove old references.  Until we want to enter a new entry, the
+   mere fact that the two vectors don't match makes the entries be
+   ignored if anyone tries to match them.
 
    Registers themselves are entered in the hash table as well as in
-   the equivalent-register chains.  However, the vectors `reg_tick'
-   and `reg_in_table' do not apply to expressions which are simple
+   the equivalent-register chains.  However, `REG_TICK' and
+   `REG_IN_TABLE' do not apply to expressions which are simple
    register references.  These expressions are removed from the table
    immediately when they become invalid, and this can be done even if
    we do not immediately search for all the expressions that refer to
@@ -201,15 +205,6 @@ Related expressions:
    so that it is possible to find out if there exists any
    register equivalent to an expression related to a given expression.  */
 
-/* One plus largest register number used in this function.  */
-
-static int max_reg;
-
-/* One plus largest instruction UID used in this function at time of
-   cse_main call.  */
-
-static int max_insn_uid;
-
 /* Length of qty_table vector.  We know in advance we will not need
    a quantity number this big.  */
 
@@ -261,6 +256,14 @@ struct qty_table_elem
 /* The table of all qtys, indexed by qty number.  */
 static struct qty_table_elem *qty_table;
 
+/* Structure used to pass arguments via for_each_rtx to function
+   cse_change_cc_mode.  */
+struct change_cc_mode_args
+{
+  rtx insn;
+  rtx newreg;
+};
+
 #ifdef HAVE_cc0
 /* For machines that have a CC0, we do not record its value in the hash
    table since its use is guaranteed to be the insn immediately following
@@ -289,7 +292,7 @@ static rtx this_insn;
 
    Or -1 if this register is at the end of the chain.
 
-   If reg_qty[N] == N, reg_eqv_table[N].next is undefined.  */
+   If REG_QTY (N) == -N - 1, reg_eqv_table[N].next is undefined.  */
 
 /* Per-register equivalence chain.  */
 struct reg_eqv_elem
@@ -302,14 +305,8 @@ static struct reg_eqv_elem *reg_eqv_table;
 
 struct cse_reg_info
 {
-  /* Next in hash chain.  */
-  struct cse_reg_info *hash_next;
-
-  /* The next cse_reg_info structure in the free or used list.  */
-  struct cse_reg_info *next;
-
-  /* Search key */
-  unsigned int regno;
+  /* The timestamp at which this register is initialized.  */
+  unsigned int timestamp;
 
   /* The quantity number of the register's current contents.  */
   int reg_qty;
@@ -329,26 +326,22 @@ struct cse_reg_info
   unsigned int subreg_ticked;
 };
 
-/* A free list of cse_reg_info entries.  */
-static struct cse_reg_info *cse_reg_info_free_list;
-
-/* A used list of cse_reg_info entries.  */
-static struct cse_reg_info *cse_reg_info_used_list;
-static struct cse_reg_info *cse_reg_info_used_list_end;
+/* A table of cse_reg_info indexed by register numbers.  */
+static struct cse_reg_info *cse_reg_info_table;
 
-/* A mapping from registers to cse_reg_info data structures.  */
-#define REGHASH_SHIFT  7
-#define REGHASH_SIZE   (1 << REGHASH_SHIFT)
-#define REGHASH_MASK   (REGHASH_SIZE - 1)
-static struct cse_reg_info *reg_hash[REGHASH_SIZE];
+/* The size of the above table.  */
+static unsigned int cse_reg_info_table_size;
 
-#define REGHASH_FN(REGNO)      \
-       (((REGNO) ^ ((REGNO) >> REGHASH_SHIFT)) & REGHASH_MASK)
+/* The index of the first entry that has not been initialized.  */
+static unsigned int cse_reg_info_table_first_uninitialized;
 
-/* The last lookup we did into the cse_reg_info_tree.  This allows us
-   to cache repeated lookups.  */
-static unsigned int cached_regno;
-static struct cse_reg_info *cached_cse_reg_info;
+/* The timestamp at the beginning of the current run of
+   cse_basic_block.  We increment this variable at the beginning of
+   the current run of cse_basic_block.  The timestamp field of a
+   cse_reg_info entry matches the value of this variable if and only
+   if the entry has been initialized during the current run of
+   cse_basic_block.  */
+static unsigned int cse_reg_info_timestamp;
 
 /* A HARD_REG_SET containing all the hard registers for which there is
    currently a REG expression in the hash table.  Note the difference
@@ -398,12 +391,6 @@ static int recorded_label_ref;
 
 static int do_not_record;
 
-#ifdef LOAD_EXTEND_OP
-
-/* Scratch rtl used when looking for load-extended copy of a MEM.  */
-static rtx memory_extend_rtx;
-#endif
-
 /* canon_hash stores 1 in hash_arg_in_memory
    if it notices a reference to memory within the expression being hashed.  */
 
@@ -484,10 +471,16 @@ struct table_elt
    register (hard registers may require `do_not_record' to be set).  */
 
 #define HASH(X, M)     \
- ((GET_CODE (X) == REG && REGNO (X) >= FIRST_PSEUDO_REGISTER   \
+ ((REG_P (X) && REGNO (X) >= FIRST_PSEUDO_REGISTER     \
   ? (((unsigned) REG << 7) + (unsigned) REG_QTY (REGNO (X)))   \
   : canon_hash (X, M)) & HASH_MASK)
 
+/* Like HASH, but without side-effects.  */
+#define SAFE_HASH(X, M)        \
+ ((REG_P (X) && REGNO (X) >= FIRST_PSEUDO_REGISTER     \
+  ? (((unsigned) REG << 7) + (unsigned) REG_QTY (REGNO (X)))   \
+  : safe_hash (X, M)) & HASH_MASK)
+
 /* Determine whether register number N is considered a fixed register for the
    purpose of approximating register costs.
    It is desirable to replace other regs with fixed regs, to reduce need for
@@ -502,44 +495,36 @@ struct table_elt
    of 0.  Next come pseudos with a cost of one and other hard registers with
    a cost of 2.  Aside from these special cases, call `rtx_cost'.  */
 
-#define CHEAP_REGNO(N) \
-  ((N) == FRAME_POINTER_REGNUM || (N) == HARD_FRAME_POINTER_REGNUM     \
-   || (N) == STACK_POINTER_REGNUM || (N) == ARG_POINTER_REGNUM         \
-   || ((N) >= FIRST_VIRTUAL_REGISTER && (N) <= LAST_VIRTUAL_REGISTER)  \
-   || ((N) < FIRST_PSEUDO_REGISTER                                     \
+#define CHEAP_REGNO(N)                                                 \
+  (REGNO_PTR_FRAME_P(N)                                                        \
+   || (HARD_REGISTER_NUM_P (N)                                         \
        && FIXED_REGNO_P (N) && REGNO_REG_CLASS (N) != NO_REGS))
 
-#define COST(X) (GET_CODE (X) == REG ? 0 : notreg_cost (X, SET))
-#define COST_IN(X,OUTER) (GET_CODE (X) == REG ? 0 : notreg_cost (X, OUTER))
-
-/* Get the info associated with register N.  */
-
-#define GET_CSE_REG_INFO(N)                    \
-  (((N) == cached_regno && cached_cse_reg_info)        \
-   ? cached_cse_reg_info : get_cse_reg_info ((N)))
+#define COST(X) (REG_P (X) ? 0 : notreg_cost (X, SET))
+#define COST_IN(X,OUTER) (REG_P (X) ? 0 : notreg_cost (X, OUTER))
 
 /* Get the number of times this register has been updated in this
    basic block.  */
 
-#define REG_TICK(N) ((GET_CSE_REG_INFO (N))->reg_tick)
+#define REG_TICK(N) (get_cse_reg_info (N)->reg_tick)
 
 /* Get the point at which REG was recorded in the table.  */
 
-#define REG_IN_TABLE(N) ((GET_CSE_REG_INFO (N))->reg_in_table)
+#define REG_IN_TABLE(N) (get_cse_reg_info (N)->reg_in_table)
 
 /* Get the SUBREG set at the last increment to REG_TICK (-1 if not a
    SUBREG).  */
 
-#define SUBREG_TICKED(N) ((GET_CSE_REG_INFO (N))->subreg_ticked)
+#define SUBREG_TICKED(N) (get_cse_reg_info (N)->subreg_ticked)
 
 /* Get the quantity number for REG.  */
 
-#define REG_QTY(N) ((GET_CSE_REG_INFO (N))->reg_qty)
+#define REG_QTY(N) (get_cse_reg_info (N)->reg_qty)
 
 /* Determine if the quantity number for register X represents a valid index
    into the qty_table.  */
 
-#define REGNO_QTY_VALID_P(N) (REG_QTY (N) != (int) (N))
+#define REGNO_QTY_VALID_P(N) (REG_QTY (N) >= 0)
 
 static struct table_elt *table[HASH_SIZE];
 
@@ -548,21 +533,6 @@ static struct table_elt *table[HASH_SIZE];
 
 static struct table_elt *free_element_chain;
 
-/* Number of `struct table_elt' structures made so far for this function.  */
-
-static int n_elements_made;
-
-/* Maximum value `n_elements_made' has had so far in this compilation
-   for functions previously processed.  */
-
-static int max_elements_made;
-
-/* Surviving equivalence class when two equivalence classes are merged
-   by recording the effects of a jump in the last insn.  Zero if the
-   last insn was not a conditional jump.  */
-
-static struct table_elt *last_jump_equiv_class;
-
 /* Set to the cost of a constant pool reference if one was found for a
    symbolic constant.  If this was found, it means we should try to
    convert constants into constant pool entries if they don't fit in
@@ -593,7 +563,7 @@ struct cse_basic_block_data
       /* 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 {TAKEN, NOT_TAKEN, AROUND} status;
+      enum taken {PATH_TAKEN, PATH_NOT_TAKEN, PATH_AROUND} status;
     } *path;
 };
 
@@ -624,10 +594,11 @@ static void rehash_using_reg (rtx);
 static void invalidate_memory (void);
 static void invalidate_for_call (void);
 static rtx use_related_value (rtx, struct table_elt *);
-static unsigned canon_hash (rtx, enum machine_mode);
-static unsigned canon_hash_string (const char *);
-static unsigned safe_hash (rtx, enum machine_mode);
-static int exp_equiv_p (rtx, rtx, int, int);
+
+static inline unsigned canon_hash (rtx, enum machine_mode);
+static inline unsigned safe_hash (rtx, enum machine_mode);
+static unsigned hash_rtx_string (const char *);
+
 static 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 *,
@@ -640,20 +611,18 @@ 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, int);
+                                   int, int);
 static int addr_affects_sp_p (rtx);
 static void invalidate_from_clobbers (rtx);
 static rtx cse_process_notes (rtx, rtx);
-static void cse_around_loop (rtx);
 static void invalidate_skipped_set (rtx, rtx, void *);
 static void invalidate_skipped_block (rtx);
-static void cse_check_loop_start (rtx, rtx, void *);
-static void cse_set_around_loop (rtx, rtx, rtx);
-static rtx cse_basic_block (rtx, rtx, struct branch_path *, int);
-static void count_reg_usage (rtx, int *, int);
+static rtx cse_basic_block (rtx, rtx, struct branch_path *);
+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 struct cse_reg_info * get_cse_reg_info (unsigned int);
+static void get_cse_reg_info_1 (unsigned int regno);
+static struct cse_reg_info * get_cse_reg_info (unsigned int regno);
 static int check_dependence (rtx *, void *);
 
 static void flush_hash_table (void);
@@ -661,9 +630,16 @@ static bool insn_live_p (rtx, int *);
 static bool set_live_p (rtx, rtx, int *);
 static bool dead_libcall_p (rtx, int *);
 static int cse_change_cc_mode (rtx *, void *);
+static void cse_change_cc_mode_insn (rtx, rtx);
 static void cse_change_cc_mode_insns (rtx, rtx, rtx);
 static enum machine_mode cse_cc_succs (basic_block, rtx, rtx, bool);
 \f
+
+#undef RTL_HOOKS_GEN_LOWPART
+#define RTL_HOOKS_GEN_LOWPART          gen_lowpart_if_possible
+
+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.  */
@@ -688,9 +664,6 @@ fixed_base_plus_p (rtx x)
        return false;
       return fixed_base_plus_p (XEXP (x, 0));
 
-    case ADDRESSOF:
-      return true;
-
     default:
       return false;
     }
@@ -722,7 +695,7 @@ approx_reg_cost_1 (rtx *xp, void *data)
   rtx x = *xp;
   int *cost_p = data;
 
-  if (x && GET_CODE (x) == REG)
+  if (x && REG_P (x))
     {
       unsigned int regno = REGNO (x);
 
@@ -758,6 +731,57 @@ 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
@@ -800,7 +824,7 @@ static int
 notreg_cost (rtx x, enum rtx_code outer)
 {
   return ((GET_CODE (x) == SUBREG
-          && GET_CODE (SUBREG_REG (x)) == REG
+          && REG_P (SUBREG_REG (x))
           && GET_MODE_CLASS (GET_MODE (x)) == MODE_INT
           && GET_MODE_CLASS (GET_MODE (SUBREG_REG (x))) == MODE_INT
           && (GET_MODE_SIZE (GET_MODE (x))
@@ -813,47 +837,85 @@ notreg_cost (rtx x, enum rtx_code outer)
 }
 
 \f
-static struct cse_reg_info *
-get_cse_reg_info (unsigned int regno)
-{
-  struct cse_reg_info **hash_head = &reg_hash[REGHASH_FN (regno)];
-  struct cse_reg_info *p;
+/* Initialize CSE_REG_INFO_TABLE.  */
 
-  for (p = *hash_head; p != NULL; p = p->hash_next)
-    if (p->regno == regno)
-      break;
-
-  if (p == NULL)
+static void
+init_cse_reg_info (unsigned int nregs)
+{
+  /* Do we need to grow the table?  */
+  if (nregs > cse_reg_info_table_size)
     {
-      /* Get a new cse_reg_info structure.  */
-      if (cse_reg_info_free_list)
+      unsigned int new_size;
+
+      if (cse_reg_info_table_size < 2048)
        {
-         p = cse_reg_info_free_list;
-         cse_reg_info_free_list = p->next;
+         /* Compute a new size that is a power of 2 and no smaller
+            than the large of NREGS and 64.  */
+         new_size = (cse_reg_info_table_size
+                     ? cse_reg_info_table_size : 64);
+
+         while (new_size < nregs)
+           new_size *= 2;
        }
       else
-       p = xmalloc (sizeof (struct cse_reg_info));
-
-      /* Insert into hash table.  */
-      p->hash_next = *hash_head;
-      *hash_head = p;
-
-      /* Initialize it.  */
-      p->reg_tick = 1;
-      p->reg_in_table = -1;
-      p->subreg_ticked = -1;
-      p->reg_qty = regno;
-      p->regno = regno;
-      p->next = cse_reg_info_used_list;
-      cse_reg_info_used_list = p;
-      if (!cse_reg_info_used_list_end)
-       cse_reg_info_used_list_end = p;
+       {
+         /* If we need a big table, allocate just enough to hold
+            NREGS registers.  */
+         new_size = nregs;
+       }
+
+      /* Reallocate the table with NEW_SIZE entries.  */
+      if (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;
+    }
+
+  /* Do we have all of the first NREGS entries initialized?  */
+  if (cse_reg_info_table_first_uninitialized < nregs)
+    {
+      unsigned int old_timestamp = cse_reg_info_timestamp - 1;
+      unsigned int i;
+
+      /* Put the old timestamp on newly allocated entries so that they
+        will all be considered out of date.  We do not touch those
+        entries beyond the first NREGS entries to be nice to the
+        virtual memory.  */
+      for (i = cse_reg_info_table_first_uninitialized; i < nregs; i++)
+       cse_reg_info_table[i].timestamp = old_timestamp;
+
+      cse_reg_info_table_first_uninitialized = nregs;
     }
+}
 
-  /* Cache this lookup; we tend to be looking up information about the
-     same register several times in a row.  */
-  cached_regno = regno;
-  cached_cse_reg_info = p;
+/* Given REGNO, initialize the cse_reg_info entry for REGNO.  */
+
+static void
+get_cse_reg_info_1 (unsigned int regno)
+{
+  /* Set TIMESTAMP field to CSE_REG_INFO_TIMESTAMP so that this
+     entry will be considered to have been initialized.  */
+  cse_reg_info_table[regno].timestamp = cse_reg_info_timestamp;
+
+  /* Initialize the rest of the entry.  */
+  cse_reg_info_table[regno].reg_tick = 1;
+  cse_reg_info_table[regno].reg_in_table = -1;
+  cse_reg_info_table[regno].subreg_ticked = -1;
+  cse_reg_info_table[regno].reg_qty = -regno - 1;
+}
+
+/* Find a cse_reg_info entry for REGNO.  */
+
+static inline struct cse_reg_info *
+get_cse_reg_info (unsigned int regno)
+{
+  struct cse_reg_info *p = &cse_reg_info_table[regno];
+
+  /* If this entry has not been initialized, go ahead and initialize
+     it.  */
+  if (p->timestamp != cse_reg_info_timestamp)
+    get_cse_reg_info_1 (regno);
 
   return p;
 }
@@ -866,20 +928,12 @@ new_basic_block (void)
 {
   int i;
 
-  next_qty = max_reg;
-
-  /* Clear out hash table state for this pass.  */
+  next_qty = 0;
 
-  memset (reg_hash, 0, sizeof reg_hash);
-
-  if (cse_reg_info_used_list)
-    {
-      cse_reg_info_used_list_end->next = cse_reg_info_free_list;
-      cse_reg_info_free_list = cse_reg_info_used_list;
-      cse_reg_info_used_list = cse_reg_info_used_list_end = 0;
-    }
-  cached_cse_reg_info = 0;
+  /* Invalidate cse_reg_info_table.  */
+  cse_reg_info_timestamp++;
 
+  /* Clear out hash table state for this pass.  */
   CLEAR_HARD_REG_SET (hard_regs_in_table);
 
   /* The per-quantity values used to be initialized here, but it is
@@ -923,8 +977,7 @@ make_new_qty (unsigned int reg, enum machine_mode mode)
   struct qty_table_elem *ent;
   struct reg_eqv_elem *eqv;
 
-  if (next_qty >= max_qty)
-    abort ();
+  gcc_assert (next_qty < max_qty);
 
   q = REG_QTY (reg) = next_qty++;
   ent = &qty_table[q];
@@ -951,8 +1004,7 @@ make_regs_eqv (unsigned int new, unsigned int old)
   ent = &qty_table[q];
 
   /* Nothing should become eqv until it has a "non-invalid" qty number.  */
-  if (! REGNO_QTY_VALID_P (old))
-    abort ();
+  gcc_assert (REGNO_QTY_VALID_P (old));
 
   REG_QTY (new) = q;
   firstr = ent->first_reg;
@@ -1012,7 +1064,7 @@ delete_reg_equiv (unsigned int reg)
   int p, n;
 
   /* If invalid, do nothing.  */
-  if (q == (int) reg)
+  if (! REGNO_QTY_VALID_P (reg))
     return;
 
   ent = &qty_table[q];
@@ -1029,7 +1081,7 @@ delete_reg_equiv (unsigned int reg)
   else
     ent->first_reg = n;
 
-  REG_QTY (reg) = reg;
+  REG_QTY (reg) = -reg - 1;
 }
 
 /* Remove any invalid expressions from the hash table
@@ -1079,7 +1131,7 @@ mention_regs (rtx x)
   /* If this is a SUBREG, we don't want to discard other SUBREGs of the same
      pseudo if they don't use overlapping words.  We handle only pseudos
      here for simplicity.  */
-  if (code == SUBREG && GET_CODE (SUBREG_REG (x)) == REG
+  if (code == SUBREG && REG_P (SUBREG_REG (x))
       && REGNO (SUBREG_REG (x)) >= FIRST_PSEUDO_REGISTER)
     {
       unsigned int i = REGNO (SUBREG_REG (x));
@@ -1115,7 +1167,7 @@ mention_regs (rtx x)
 
   if (code == COMPARE || COMPARISON_P (x))
     {
-      if (GET_CODE (XEXP (x, 0)) == REG
+      if (REG_P (XEXP (x, 0))
          && ! REGNO_QTY_VALID_P (REGNO (XEXP (x, 0))))
        if (insert_regs (XEXP (x, 0), NULL, 0))
          {
@@ -1123,7 +1175,7 @@ mention_regs (rtx x)
            changed = 1;
          }
 
-      if (GET_CODE (XEXP (x, 1)) == REG
+      if (REG_P (XEXP (x, 1))
          && ! REGNO_QTY_VALID_P (REGNO (XEXP (x, 1))))
        if (insert_regs (XEXP (x, 1), NULL, 0))
          {
@@ -1156,7 +1208,7 @@ mention_regs (rtx x)
 static int
 insert_regs (rtx x, struct table_elt *classp, int modified)
 {
-  if (GET_CODE (x) == REG)
+  if (REG_P (x))
     {
       unsigned int regno = REGNO (x);
       int qty_valid;
@@ -1179,10 +1231,27 @@ insert_regs (rtx x, struct table_elt *classp, int modified)
            for (classp = classp->first_same_value;
                 classp != 0;
                 classp = classp->next_same_value)
-             if (GET_CODE (classp->exp) == REG
+             if (REG_P (classp->exp)
                  && GET_MODE (classp->exp) == GET_MODE (x))
                {
-                 make_regs_eqv (regno, REGNO (classp->exp));
+                 unsigned c_regno = REGNO (classp->exp);
+
+                 gcc_assert (REGNO_QTY_VALID_P (c_regno));
+
+                 /* Suppose that 5 is hard reg and 100 and 101 are
+                    pseudos.  Consider
+
+                    (set (reg:si 100) (reg:si 5))
+                    (set (reg:si 5) (reg:si 100))
+                    (set (reg:di 101) (reg:di 5))
+
+                    We would now set REG_QTY (101) = REG_QTY (5), but the
+                    entry for 5 is in SImode.  When we use this later in
+                    copy propagation, we get the register in wrong mode.  */
+                 if (qty_table[REG_QTY (c_regno)].mode != GET_MODE (x))
+                   continue;
+
+                 make_regs_eqv (regno, c_regno);
                  return 1;
                }
 
@@ -1212,7 +1281,7 @@ insert_regs (rtx x, struct table_elt *classp, int modified)
      not be accessible because its hash code will have changed.  So assign
      a quantity number now.  */
 
-  else if (GET_CODE (x) == SUBREG && GET_CODE (SUBREG_REG (x)) == REG
+  else if (GET_CODE (x) == SUBREG && REG_P (SUBREG_REG (x))
           && ! REGNO_QTY_VALID_P (REGNO (SUBREG_REG (x))))
     {
       insert_regs (SUBREG_REG (x), NULL, 0);
@@ -1319,8 +1388,8 @@ lookup (rtx x, unsigned int hash, enum machine_mode mode)
   struct table_elt *p;
 
   for (p = table[hash]; p; p = p->next_same_hash)
-    if (mode == p->mode && ((x == p->exp && GET_CODE (x) == REG)
-                           || exp_equiv_p (x, p->exp, GET_CODE (x) != REG, 0)))
+    if (mode == p->mode && ((x == p->exp && REG_P (x))
+                           || exp_equiv_p (x, p->exp, !REG_P (x), false)))
       return p;
 
   return 0;
@@ -1334,21 +1403,22 @@ lookup_for_remove (rtx x, unsigned int hash, enum machine_mode mode)
 {
   struct table_elt *p;
 
-  if (GET_CODE (x) == REG)
+  if (REG_P (x))
     {
       unsigned int regno = REGNO (x);
 
       /* Don't check the machine mode when comparing registers;
         invalidating (REG:SI 0) also invalidates (REG:DF 0).  */
       for (p = table[hash]; p; p = p->next_same_hash)
-       if (GET_CODE (p->exp) == REG
+       if (REG_P (p->exp)
            && REGNO (p->exp) == regno)
          return p;
     }
   else
     {
       for (p = table[hash]; p; p = p->next_same_hash)
-       if (mode == p->mode && (x == p->exp || exp_equiv_p (x, p->exp, 0, 0)))
+       if (mode == p->mode
+           && (x == p->exp || exp_equiv_p (x, p->exp, 0, false)))
          return p;
     }
 
@@ -1362,7 +1432,7 @@ static rtx
 lookup_as_function (rtx x, enum rtx_code code)
 {
   struct table_elt *p
-    = lookup (x, safe_hash (x, VOIDmode) & HASH_MASK, GET_MODE (x));
+    = lookup (x, SAFE_HASH (x, VOIDmode), GET_MODE (x));
 
   /* If we are looking for a CONST_INT, the mode doesn't really matter, as
      long as we are narrowing.  So if we looked in vain for a mode narrower
@@ -1372,7 +1442,7 @@ lookup_as_function (rtx x, enum rtx_code code)
     {
       x = copy_rtx (x);
       PUT_MODE (x, word_mode);
-      p = lookup (x, safe_hash (x, VOIDmode) & HASH_MASK, word_mode);
+      p = lookup (x, SAFE_HASH (x, VOIDmode), word_mode);
     }
 
   if (p == 0)
@@ -1381,7 +1451,7 @@ lookup_as_function (rtx x, enum rtx_code code)
   for (p = p->first_same_value; p; p = p->next_same_value)
     if (GET_CODE (p->exp) == code
        /* Make sure this is a valid entry in the table.  */
-       && exp_equiv_p (p->exp, p->exp, 1, 0))
+       && exp_equiv_p (p->exp, p->exp, 1, false))
       return p->exp;
 
   return 0;
@@ -1421,11 +1491,10 @@ insert (rtx x, struct table_elt *classp, unsigned int hash, enum machine_mode mo
 
   /* If X is a register and we haven't made a quantity for it,
      something is wrong.  */
-  if (GET_CODE (x) == REG && ! REGNO_QTY_VALID_P (REGNO (x)))
-    abort ();
+  gcc_assert (!REG_P (x) || REGNO_QTY_VALID_P (REGNO (x)));
 
   /* If X is a hard register, show it is being put in the table.  */
-  if (GET_CODE (x) == REG && REGNO (x) < FIRST_PSEUDO_REGISTER)
+  if (REG_P (x) && REGNO (x) < FIRST_PSEUDO_REGISTER)
     {
       unsigned int regno = REGNO (x);
       unsigned int endregno = regno + hard_regno_nregs[regno][GET_MODE (x)];
@@ -1441,10 +1510,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
-    {
-      n_elements_made++;
-      elt = xmalloc (sizeof (struct table_elt));
-    }
+    elt = XNEW (struct table_elt);
 
   elt->exp = x;
   elt->canon_exp = NULL_RTX;
@@ -1457,13 +1523,7 @@ insert (rtx x, struct table_elt *classp, unsigned int hash, enum machine_mode mo
   elt->related_value = 0;
   elt->in_memory = 0;
   elt->mode = mode;
-  elt->is_const = (CONSTANT_P (x)
-                  /* GNU C++ takes advantage of this for `this'
-                     (and other const values).  */
-                  || (GET_CODE (x) == REG
-                      && RTX_UNCHANGING_P (x)
-                      && REGNO (x) >= FIRST_PSEUDO_REGISTER)
-                  || fixed_base_plus_p (x));
+  elt->is_const = (CONSTANT_P (x) || fixed_base_plus_p (x));
 
   if (table[hash])
     table[hash]->prev_same_hash = elt;
@@ -1521,8 +1581,8 @@ insert (rtx x, struct table_elt *classp, unsigned int hash, enum machine_mode mo
      update the qtys `const_insn' to show that `this_insn' is the latest
      insn making that quantity equivalent to the constant.  */
 
-  if (elt->is_const && classp && GET_CODE (classp->exp) == REG
-      && GET_CODE (x) != REG)
+  if (elt->is_const && classp && REG_P (classp->exp)
+      && !REG_P (x))
     {
       int exp_q = REG_QTY (REGNO (classp->exp));
       struct qty_table_elem *exp_ent = &qty_table[exp_q];
@@ -1531,7 +1591,7 @@ insert (rtx x, struct table_elt *classp, unsigned int hash, enum machine_mode mo
       exp_ent->const_insn = this_insn;
     }
 
-  else if (GET_CODE (x) == REG
+  else if (REG_P (x)
           && classp
           && ! qty_table[REG_QTY (REGNO (x))].const_rtx
           && ! elt->is_const)
@@ -1540,7 +1600,7 @@ insert (rtx x, struct table_elt *classp, unsigned int hash, enum machine_mode mo
 
       for (p = classp; p != 0; p = p->next_same_value)
        {
-         if (p->is_const && GET_CODE (p->exp) != REG)
+         if (p->is_const && !REG_P (p->exp))
            {
              int x_q = REG_QTY (REGNO (x));
              struct qty_table_elem *x_ent = &qty_table[x_q];
@@ -1553,7 +1613,7 @@ insert (rtx x, struct table_elt *classp, unsigned int hash, enum machine_mode mo
        }
     }
 
-  else if (GET_CODE (x) == REG
+  else if (REG_P (x)
           && qty_table[REG_QTY (REGNO (x))].const_rtx
           && GET_MODE (x) == qty_table[REG_QTY (REGNO (x))].mode)
     qty_table[REG_QTY (REGNO (x))].const_insn = this_insn;
@@ -1570,7 +1630,7 @@ insert (rtx x, struct table_elt *classp, unsigned int hash, enum machine_mode mo
       if (subexp != 0)
        {
          /* Get the integer-free subexpression in the hash table.  */
-         subhash = safe_hash (subexp, mode) & HASH_MASK;
+         subhash = SAFE_HASH (subexp, mode);
          subelt = lookup (subexp, subhash, mode);
          if (subelt == 0)
            subelt = insert (subexp, NULL, subhash, mode);
@@ -1624,17 +1684,22 @@ merge_equiv_classes (struct table_elt *class1, struct table_elt *class2)
       /* Remove old entry, make a new one in CLASS1's class.
         Don't do this for invalid entries as we cannot find their
         hash code (it also isn't necessary).  */
-      if (GET_CODE (exp) == REG || exp_equiv_p (exp, exp, 1, 0))
+      if (REG_P (exp) || exp_equiv_p (exp, exp, 1, false))
        {
+         bool need_rehash = false;
+
          hash_arg_in_memory = 0;
          hash = HASH (exp, mode);
 
-         if (GET_CODE (exp) == REG)
-           delete_reg_equiv (REGNO (exp));
+         if (REG_P (exp))
+           {
+             need_rehash = REGNO_QTY_VALID_P (REGNO (exp));
+             delete_reg_equiv (REGNO (exp));
+           }
 
          remove_from_table (elt, hash);
 
-         if (insert_regs (exp, class1, 0))
+         if (insert_regs (exp, class1, 0) || need_rehash)
            {
              rehash_using_reg (exp);
              hash = HASH (exp, mode);
@@ -1658,7 +1723,7 @@ flush_hash_table (void)
       {
        /* Note that invalidate can remove elements
           after P in the current hash chain.  */
-       if (GET_CODE (p->exp) == REG)
+       if (REG_P (p->exp))
          invalidate (p->exp, p->mode);
        else
          remove_from_table (p, i);
@@ -1677,7 +1742,7 @@ static int
 check_dependence (rtx *x, void *data)
 {
   struct check_dependence_data *d = (struct check_dependence_data *) data;
-  if (*x && GET_CODE (*x) == MEM)
+  if (*x && MEM_P (*x))
     return canon_true_dependence (d->exp, d->mode, d->addr, *x,
                                  cse_rtx_varies_p);
   else
@@ -1762,7 +1827,7 @@ invalidate (rtx x, enum machine_mode full_mode)
                  {
                    next = p->next_same_hash;
 
-                   if (GET_CODE (p->exp) != REG
+                   if (!REG_P (p->exp)
                        || REGNO (p->exp) >= FIRST_PSEUDO_REGISTER)
                      continue;
 
@@ -1830,7 +1895,7 @@ invalidate (rtx x, enum machine_mode full_mode)
       return;
 
     default:
-      abort ();
+      gcc_unreachable ();
     }
 }
 \f
@@ -1849,7 +1914,7 @@ remove_invalid_refs (unsigned int regno)
     for (p = table[i]; p; p = next)
       {
        next = p->next_same_hash;
-       if (GET_CODE (p->exp) != REG
+       if (!REG_P (p->exp)
            && refers_to_regno_p (regno, regno + 1, p->exp, (rtx *) 0))
          remove_from_table (p, i);
       }
@@ -1871,9 +1936,9 @@ remove_invalid_subreg_refs (unsigned int regno, unsigned int offset,
        rtx exp = p->exp;
        next = p->next_same_hash;
 
-       if (GET_CODE (exp) != REG
+       if (!REG_P (exp)
            && (GET_CODE (exp) != SUBREG
-               || GET_CODE (SUBREG_REG (exp)) != REG
+               || !REG_P (SUBREG_REG (exp))
                || REGNO (SUBREG_REG (exp)) != regno
                || (((SUBREG_BYTE (exp)
                      + (GET_MODE_SIZE (GET_MODE (exp)) - 1)) >= offset)
@@ -1901,22 +1966,21 @@ rehash_using_reg (rtx x)
   /* If X is not a register or if the register is known not to be in any
      valid entries in the table, we have no work to do.  */
 
-  if (GET_CODE (x) != REG
+  if (!REG_P (x)
       || REG_IN_TABLE (REGNO (x)) < 0
       || REG_IN_TABLE (REGNO (x)) != REG_TICK (REGNO (x)))
     return;
 
   /* Scan all hash chains looking for valid entries that mention X.
-     If we find one and it is in the wrong hash chain, move it.  We can skip
-     objects that are registers, since they are handled specially.  */
+     If we find one and it is in the wrong hash chain, move it.  */
 
   for (i = 0; i < HASH_SIZE; i++)
     for (p = table[i]; p; p = next)
       {
        next = p->next_same_hash;
-       if (GET_CODE (p->exp) != REG && reg_mentioned_p (x, p->exp)
-           && exp_equiv_p (p->exp, p->exp, 1, 0)
-           && i != (hash = safe_hash (p->exp, p->mode) & HASH_MASK))
+       if (reg_mentioned_p (x, p->exp)
+           && exp_equiv_p (p->exp, p->exp, 1, false)
+           && i != (hash = SAFE_HASH (p->exp, p->mode)))
          {
            if (p->next_same_hash)
              p->next_same_hash->prev_same_hash = p->prev_same_hash;
@@ -1975,7 +2039,7 @@ invalidate_for_call (void)
        {
          next = p->next_same_hash;
 
-         if (GET_CODE (p->exp) != REG
+         if (!REG_P (p->exp)
              || REGNO (p->exp) >= FIRST_PSEUDO_REGISTER)
            continue;
 
@@ -2015,7 +2079,7 @@ use_related_value (rtx x, struct table_elt *elt)
       rtx subexp = get_related_value (x);
       if (subexp != 0)
        relt = lookup (subexp,
-                      safe_hash (subexp, GET_MODE (subexp)) & HASH_MASK,
+                      SAFE_HASH (subexp, GET_MODE (subexp)),
                       GET_MODE (subexp));
     }
 
@@ -2041,7 +2105,7 @@ use_related_value (rtx x, struct table_elt *elt)
        q = 0;
       else
        for (q = p->first_same_value; q; q = q->next_same_value)
-         if (GET_CODE (q->exp) == REG)
+         if (REG_P (q->exp))
            break;
 
       if (q)
@@ -2066,7 +2130,7 @@ use_related_value (rtx x, struct table_elt *elt)
 \f
 /* Hash a string.  Just add its bytes up.  */
 static inline unsigned
-canon_hash_string (const char *ps)
+hash_rtx_string (const char *ps)
 {
   unsigned hash = 0;
   const unsigned char *p = (const unsigned char *) ps;
@@ -2083,23 +2147,26 @@ canon_hash_string (const char *ps)
    MODE is used in hashing for CONST_INTs only;
    otherwise the mode of X is used.
 
-   Store 1 in do_not_record if any subexpression is volatile.
+   Store 1 in DO_NOT_RECORD_P if any subexpression is volatile.
 
-   Store 1 in hash_arg_in_memory if X contains a MEM rtx
-   which does not have the RTX_UNCHANGING_P bit set.
+   If HASH_ARG_IN_MEMORY_P is not NULL, store 1 in it if X contains
+   a MEM rtx which does not have the RTX_UNCHANGING_P bit set.
 
    Note that cse_insn knows that the hash code of a MEM expression
    is just (int) MEM plus the hash code of the address.  */
 
-static unsigned
-canon_hash (rtx x, enum machine_mode mode)
+unsigned
+hash_rtx (rtx x, enum machine_mode mode, int *do_not_record_p,
+         int *hash_arg_in_memory_p, bool have_reg_qty)
 {
   int i, j;
   unsigned hash = 0;
   enum rtx_code code;
   const char *fmt;
 
-  /* repeat is used to turn tail-recursion into iteration.  */
+  /* Used to turn recursion into iteration.  We can't rely on GCC's
+     tail-recursion elimination since we need to keep accumulating values
+     in HASH.  */
  repeat:
   if (x == 0)
     return hash;
@@ -2110,48 +2177,52 @@ canon_hash (rtx x, enum machine_mode mode)
     case REG:
       {
        unsigned int regno = REGNO (x);
-       bool record;
-
-       /* On some machines, we can't record any non-fixed hard register,
-          because extending its life will cause reload problems.  We
-          consider ap, fp, sp, gp to be fixed for this purpose.
 
-          We also consider CCmode registers to be fixed for this purpose;
-          failure to do so leads to failure to simplify 0<100 type of
-          conditionals.
-
-          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.  */
-
-       if (regno >= FIRST_PSEUDO_REGISTER)
-         record = true;
-       else if (x == frame_pointer_rtx
-                || x == hard_frame_pointer_rtx
-                || x == arg_pointer_rtx
-                || x == stack_pointer_rtx
-                || x == pic_offset_table_rtx)
-         record = true;
-       else if (global_regs[regno])
-         record = false;
-       else if (fixed_regs[regno])
-         record = true;
-       else if (GET_MODE_CLASS (GET_MODE (x)) == MODE_CC)
-         record = true;
-       else if (SMALL_REGISTER_CLASSES)
-         record = false;
-       else if (CLASS_LIKELY_SPILLED_P (REGNO_REG_CLASS (regno)))
-         record = false;
-       else
-         record = true;
-
-       if (!record)
+       if (!reload_completed)
          {
-           do_not_record = 1;
-           return 0;
+           /* On some machines, we can't record any non-fixed hard register,
+              because extending its life will cause reload problems.  We
+              consider ap, fp, sp, gp to be fixed for this purpose.
+
+              We also consider CCmode registers to be fixed for this purpose;
+              failure to do so leads to failure to simplify 0<100 type of
+              conditionals.
+
+              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.  */
+           bool record;
+
+           if (regno >= FIRST_PSEUDO_REGISTER)
+             record = true;
+           else if (x == frame_pointer_rtx
+                    || x == hard_frame_pointer_rtx
+                    || x == arg_pointer_rtx
+                    || x == stack_pointer_rtx
+                    || x == pic_offset_table_rtx)
+             record = true;
+           else if (global_regs[regno])
+             record = false;
+           else if (fixed_regs[regno])
+             record = true;
+           else if (GET_MODE_CLASS (GET_MODE (x)) == MODE_CC)
+             record = true;
+           else if (SMALL_REGISTER_CLASSES)
+             record = false;
+           else if (CLASS_LIKELY_SPILLED_P (REGNO_REG_CLASS (regno)))
+             record = false;
+           else
+             record = true;
+
+           if (!record)
+             {
+               *do_not_record_p = 1;
+               return 0;
+             }
          }
 
-       hash += ((unsigned) REG << 7) + (unsigned) REG_QTY (regno);
+       hash += ((unsigned int) REG << 7);
+        hash += (have_reg_qty ? (unsigned) REG_QTY (regno) : regno);
        return hash;
       }
 
@@ -2160,9 +2231,9 @@ canon_hash (rtx x, enum machine_mode mode)
        want to have to forget unrelated subregs when one subreg changes.  */
     case SUBREG:
       {
-       if (GET_CODE (SUBREG_REG (x)) == REG)
+       if (REG_P (SUBREG_REG (x)))
          {
-           hash += (((unsigned) SUBREG << 7)
+           hash += (((unsigned int) SUBREG << 7)
                     + REGNO (SUBREG_REG (x))
                     + (SUBREG_BYTE (x) / UNITS_PER_WORD));
            return hash;
@@ -2171,21 +2242,19 @@ canon_hash (rtx x, enum machine_mode mode)
       }
 
     case CONST_INT:
-      {
-       unsigned HOST_WIDE_INT tem = INTVAL (x);
-       hash += ((unsigned) CONST_INT << 7) + (unsigned) mode + tem;
-       return hash;
-      }
+      hash += (((unsigned int) CONST_INT << 7) + (unsigned int) mode
+               + (unsigned int) INTVAL (x));
+      return hash;
 
     case CONST_DOUBLE:
       /* This is like the general case, except that it only counts
         the integers representing the constant.  */
-      hash += (unsigned) code + (unsigned) GET_MODE (x);
+      hash += (unsigned int) code + (unsigned int) GET_MODE (x);
       if (GET_MODE (x) != VOIDmode)
        hash += real_hash (CONST_DOUBLE_REAL_VALUE (x));
       else
-       hash += ((unsigned) CONST_DOUBLE_LOW (x)
-                + (unsigned) CONST_DOUBLE_HIGH (x));
+       hash += ((unsigned int) CONST_DOUBLE_LOW (x)
+                + (unsigned int) CONST_DOUBLE_HIGH (x));
       return hash;
 
     case CONST_VECTOR:
@@ -2198,7 +2267,8 @@ canon_hash (rtx x, enum machine_mode mode)
        for (i = 0; i < units; ++i)
          {
            elt = CONST_VECTOR_ELT (x, i);
-           hash += canon_hash (elt, GET_MODE (elt));
+           hash += hash_rtx (elt, GET_MODE (elt), do_not_record_p,
+                             hash_arg_in_memory_p, have_reg_qty);
          }
 
        return hash;
@@ -2206,23 +2276,39 @@ canon_hash (rtx x, enum machine_mode mode)
 
       /* Assume there is only one rtx object for any given label.  */
     case LABEL_REF:
-      hash += ((unsigned) LABEL_REF << 7) + (unsigned long) XEXP (x, 0);
+      /* We don't hash on the address of the CODE_LABEL to avoid bootstrap
+        differences and differences between each stage's debugging dumps.  */
+        hash += (((unsigned int) LABEL_REF << 7)
+                 + CODE_LABEL_NUMBER (XEXP (x, 0)));
       return hash;
 
     case SYMBOL_REF:
-      hash += ((unsigned) SYMBOL_REF << 7) + (unsigned long) XSTR (x, 0);
-      return hash;
+      {
+       /* Don't hash on the symbol's address to avoid bootstrap differences.
+          Different hash values may cause expressions to be recorded in
+          different orders and thus different registers to be used in the
+          final assembler.  This also avoids differences in the dump files
+          between various stages.  */
+       unsigned int h = 0;
+       const unsigned char *p = (const unsigned char *) XSTR (x, 0);
+
+       while (*p)
+         h += (h << 7) + *p++; /* ??? revisit */
+
+       hash += ((unsigned int) SYMBOL_REF << 7) + h;
+       return hash;
+      }
 
     case MEM:
       /* We don't record if marked volatile or if BLKmode since we don't
         know the size of the move.  */
       if (MEM_VOLATILE_P (x) || GET_MODE (x) == BLKmode)
        {
-         do_not_record = 1;
+         *do_not_record_p = 1;
          return 0;
        }
-      if (! RTX_UNCHANGING_P (x) || fixed_base_plus_p (XEXP (x, 0)))
-       hash_arg_in_memory = 1;
+      if (hash_arg_in_memory_p && !MEM_READONLY_P (x))
+       *hash_arg_in_memory_p = 1;
 
       /* Now that we have already found this special case,
         might as well speed it up as much as possible.  */
@@ -2234,15 +2320,16 @@ canon_hash (rtx x, enum machine_mode mode)
       /* A USE that mentions non-volatile memory needs special
         handling since the MEM may be BLKmode which normally
         prevents an entry from being made.  Pure calls are
-        marked by a USE which mentions BLKmode memory.  */
-      if (GET_CODE (XEXP (x, 0)) == MEM
+        marked by a USE which mentions BLKmode memory.
+        See calls.c:emit_call_1.  */
+      if (MEM_P (XEXP (x, 0))
          && ! MEM_VOLATILE_P (XEXP (x, 0)))
        {
          hash += (unsigned) USE;
          x = XEXP (x, 0);
 
-         if (! RTX_UNCHANGING_P (x) || fixed_base_plus_p (XEXP (x, 0)))
-           hash_arg_in_memory = 1;
+         if (hash_arg_in_memory_p && !MEM_READONLY_P (x))
+           *hash_arg_in_memory_p = 1;
 
          /* Now that we have already found this special case,
             might as well speed it up as much as possible.  */
@@ -2262,34 +2349,36 @@ canon_hash (rtx x, enum machine_mode mode)
     case CC0:
     case CALL:
     case UNSPEC_VOLATILE:
-      do_not_record = 1;
+      *do_not_record_p = 1;
       return 0;
 
     case ASM_OPERANDS:
       if (MEM_VOLATILE_P (x))
        {
-         do_not_record = 1;
+         *do_not_record_p = 1;
          return 0;
        }
       else
        {
          /* We don't want to take the filename and line into account.  */
          hash += (unsigned) code + (unsigned) GET_MODE (x)
-           + canon_hash_string (ASM_OPERANDS_TEMPLATE (x))
-           + canon_hash_string (ASM_OPERANDS_OUTPUT_CONSTRAINT (x))
+           + hash_rtx_string (ASM_OPERANDS_TEMPLATE (x))
+           + hash_rtx_string (ASM_OPERANDS_OUTPUT_CONSTRAINT (x))
            + (unsigned) ASM_OPERANDS_OUTPUT_IDX (x);
 
          if (ASM_OPERANDS_INPUT_LENGTH (x))
            {
              for (i = 1; i < ASM_OPERANDS_INPUT_LENGTH (x); i++)
                {
-                 hash += (canon_hash (ASM_OPERANDS_INPUT (x, i),
-                                      GET_MODE (ASM_OPERANDS_INPUT (x, i)))
-                          + canon_hash_string (ASM_OPERANDS_INPUT_CONSTRAINT
-                                               (x, i)));
+                 hash += (hash_rtx (ASM_OPERANDS_INPUT (x, i),
+                                    GET_MODE (ASM_OPERANDS_INPUT (x, i)),
+                                    do_not_record_p, hash_arg_in_memory_p,
+                                    have_reg_qty)
+                          + hash_rtx_string
+                               (ASM_OPERANDS_INPUT_CONSTRAINT (x, i)));
                }
 
-             hash += canon_hash_string (ASM_OPERANDS_INPUT_CONSTRAINT (x, 0));
+             hash += hash_rtx_string (ASM_OPERANDS_INPUT_CONSTRAINT (x, 0));
              x = ASM_OPERANDS_INPUT (x, 0);
              mode = GET_MODE (x);
              goto repeat;
@@ -2308,50 +2397,67 @@ canon_hash (rtx x, enum machine_mode mode)
   fmt = GET_RTX_FORMAT (code);
   for (; i >= 0; i--)
     {
-      if (fmt[i] == 'e')
+      switch (fmt[i])
        {
-         rtx tem = XEXP (x, i);
-
+       case 'e':
          /* If we are about to do the last recursive call
             needed at this level, change it into iteration.
             This function  is called enough to be worth it.  */
          if (i == 0)
            {
-             x = tem;
+             x = XEXP (x, i);
              goto repeat;
            }
-         hash += canon_hash (tem, 0);
-       }
-      else if (fmt[i] == 'E')
-       for (j = 0; j < XVECLEN (x, i); j++)
-         hash += canon_hash (XVECEXP (x, i, j), 0);
-      else if (fmt[i] == 's')
-       hash += canon_hash_string (XSTR (x, i));
-      else if (fmt[i] == 'i')
-       {
-         unsigned tem = XINT (x, i);
-         hash += tem;
+
+         hash += hash_rtx (XEXP (x, i), 0, do_not_record_p,
+                           hash_arg_in_memory_p, have_reg_qty);
+         break;
+
+       case 'E':
+         for (j = 0; j < XVECLEN (x, i); j++)
+           hash += hash_rtx (XVECEXP (x, i, j), 0, do_not_record_p,
+                             hash_arg_in_memory_p, have_reg_qty);
+         break;
+
+       case 's':
+         hash += hash_rtx_string (XSTR (x, i));
+         break;
+
+       case 'i':
+         hash += (unsigned int) XINT (x, i);
+         break;
+
+       case '0': case 't':
+         /* Unused.  */
+         break;
+
+       default:
+         gcc_unreachable ();
        }
-      else if (fmt[i] == '0' || fmt[i] == 't')
-       /* Unused.  */
-       ;
-      else
-       abort ();
     }
+
   return hash;
 }
 
-/* Like canon_hash but with no side effects.  */
+/* 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.  */
 
-static unsigned
+static inline unsigned
+canon_hash (rtx x, enum machine_mode mode)
+{
+  return hash_rtx (x, mode, &do_not_record, &hash_arg_in_memory, true);
+}
+
+/* Like canon_hash but with no side effects, i.e. do_not_record
+   and hash_arg_in_memory are not changed.  */
+
+static inline unsigned
 safe_hash (rtx x, enum machine_mode mode)
 {
-  int save_do_not_record = do_not_record;
-  int save_hash_arg_in_memory = hash_arg_in_memory;
-  unsigned hash = canon_hash (x, mode);
-  hash_arg_in_memory = save_hash_arg_in_memory;
-  do_not_record = save_do_not_record;
-  return hash;
+  int dummy_do_not_record;
+  return hash_rtx (x, mode, &dummy_do_not_record, NULL, true);
 }
 \f
 /* Return 1 iff X and Y would canonicalize into the same thing,
@@ -2361,16 +2467,10 @@ safe_hash (rtx x, enum machine_mode mode)
    and Y was found in the hash table.  We check register refs
    in Y for being marked as valid.
 
-   If EQUAL_VALUES is nonzero, we allow a register to match a constant value
-   that is known to be in the register.  Ordinarily, we don't allow them
-   to match, because letting them match would cause unpredictable results
-   in all the places that search a hash table chain for an equivalent
-   for a given value.  A possible equivalent that has different structure
-   has its hash code computed from different data.  Whether the hash code
-   is the same as that of the given value is pure luck.  */
+   If FOR_GCSE is true, we compare X and Y for equivalence for GCSE.  */
 
-static int
-exp_equiv_p (rtx x, rtx y, int validate, int equal_values)
+int
+exp_equiv_p (rtx x, rtx y, int validate, bool for_gcse)
 {
   int i, j;
   enum rtx_code code;
@@ -2380,42 +2480,13 @@ exp_equiv_p (rtx x, rtx y, int validate, int equal_values)
      if VALIDATE is nonzero.  */
   if (x == y && !validate)
     return 1;
+
   if (x == 0 || y == 0)
     return x == y;
 
   code = GET_CODE (x);
   if (code != GET_CODE (y))
-    {
-      if (!equal_values)
-       return 0;
-
-      /* If X is a constant and Y is a register or vice versa, they may be
-        equivalent.  We only have to validate if Y is a register.  */
-      if (CONSTANT_P (x) && GET_CODE (y) == REG
-         && REGNO_QTY_VALID_P (REGNO (y)))
-       {
-         int y_q = REG_QTY (REGNO (y));
-         struct qty_table_elem *y_ent = &qty_table[y_q];
-
-         if (GET_MODE (y) == y_ent->mode
-             && rtx_equal_p (x, y_ent->const_rtx)
-             && (! validate || REG_IN_TABLE (REGNO (y)) == REG_TICK (REGNO (y))))
-           return 1;
-       }
-
-      if (CONSTANT_P (y) && code == REG
-         && 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
-             && rtx_equal_p (y, x_ent->const_rtx))
-           return 1;
-       }
-
-      return 0;
-    }
+    return 0;
 
   /* (MULT:SI x y) and (MULT:HI x y) are NOT equivalent.  */
   if (GET_MODE (x) != GET_MODE (y))
@@ -2426,6 +2497,7 @@ exp_equiv_p (rtx x, rtx y, int validate, int equal_values)
     case PC:
     case CC0:
     case CONST_INT:
+    case CONST_DOUBLE:
       return x == y;
 
     case LABEL_REF:
@@ -2435,29 +2507,58 @@ exp_equiv_p (rtx x, rtx y, int validate, int equal_values)
       return XSTR (x, 0) == XSTR (y, 0);
 
     case REG:
-      {
-       unsigned int regno = REGNO (y);
-       unsigned int endregno
-         = regno + (regno >= FIRST_PSEUDO_REGISTER ? 1
-                    : hard_regno_nregs[regno][GET_MODE (y)]);
-       unsigned int i;
+      if (for_gcse)
+       return REGNO (x) == REGNO (y);
+      else
+       {
+         unsigned int regno = REGNO (y);
+         unsigned int i;
+         unsigned int endregno
+           = regno + (regno >= FIRST_PSEUDO_REGISTER ? 1
+                      : hard_regno_nregs[regno][GET_MODE (y)]);
 
-       /* If the quantities are not the same, the expressions are not
-          equivalent.  If there are and we are not to validate, they
-          are equivalent.  Otherwise, ensure all regs are up-to-date.  */
+         /* If the quantities are not the same, the expressions are not
+            equivalent.  If there are and we are not to validate, they
+            are equivalent.  Otherwise, ensure all regs are up-to-date.  */
 
-       if (REG_QTY (REGNO (x)) != REG_QTY (regno))
-         return 0;
+         if (REG_QTY (REGNO (x)) != REG_QTY (regno))
+           return 0;
+
+         if (! validate)
+           return 1;
+
+         for (i = regno; i < endregno; i++)
+           if (REG_IN_TABLE (i) != REG_TICK (i))
+             return 0;
 
-       if (! validate)
          return 1;
+       }
 
-       for (i = regno; i < endregno; i++)
-         if (REG_IN_TABLE (i) != REG_TICK (i))
+    case MEM:
+      if (for_gcse)
+       {
+         /* A volatile mem should not be considered equivalent to any
+            other.  */
+         if (MEM_VOLATILE_P (x) || MEM_VOLATILE_P (y))
            return 0;
 
-       return 1;
-      }
+         /* 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;
 
     /*  For commutative operations, check both orders.  */
     case PLUS:
@@ -2467,13 +2568,14 @@ exp_equiv_p (rtx x, rtx y, int validate, int equal_values)
     case XOR:
     case NE:
     case EQ:
-      return ((exp_equiv_p (XEXP (x, 0), XEXP (y, 0), validate, equal_values)
+      return ((exp_equiv_p (XEXP (x, 0), XEXP (y, 0),
+                            validate, for_gcse)
               && exp_equiv_p (XEXP (x, 1), XEXP (y, 1),
-                              validate, equal_values))
+                               validate, for_gcse))
              || (exp_equiv_p (XEXP (x, 0), XEXP (y, 1),
-                              validate, equal_values)
+                               validate, for_gcse)
                  && exp_equiv_p (XEXP (x, 1), XEXP (y, 0),
-                                 validate, equal_values)));
+                                  validate, for_gcse)));
 
     case ASM_OPERANDS:
       /* We don't use the generic code below because we want to
@@ -2496,7 +2598,7 @@ exp_equiv_p (rtx x, rtx y, int validate, int equal_values)
          for (i = ASM_OPERANDS_INPUT_LENGTH (x) - 1; i >= 0; i--)
            if (! exp_equiv_p (ASM_OPERANDS_INPUT (x, i),
                               ASM_OPERANDS_INPUT (y, i),
-                              validate, equal_values)
+                              validate, for_gcse)
                || strcmp (ASM_OPERANDS_INPUT_CONSTRAINT (x, i),
                           ASM_OPERANDS_INPUT_CONSTRAINT (y, i)))
              return 0;
@@ -2509,7 +2611,7 @@ exp_equiv_p (rtx x, rtx y, int validate, int equal_values)
     }
 
   /* Compare the elements.  If any pair of corresponding elements
-     fail to match, return 0 for the whole things.  */
+     fail to match, return 0 for the whole thing.  */
 
   fmt = GET_RTX_FORMAT (code);
   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
@@ -2517,7 +2619,8 @@ exp_equiv_p (rtx x, rtx y, int validate, int equal_values)
       switch (fmt[i])
        {
        case 'e':
-         if (! exp_equiv_p (XEXP (x, i), XEXP (y, i), validate, equal_values))
+         if (! exp_equiv_p (XEXP (x, i), XEXP (y, i),
+                             validate, for_gcse))
            return 0;
          break;
 
@@ -2526,7 +2629,7 @@ exp_equiv_p (rtx x, rtx y, int validate, int equal_values)
            return 0;
          for (j = 0; j < XVECLEN (x, i); j++)
            if (! exp_equiv_p (XVECEXP (x, i, j), XVECEXP (y, i, j),
-                              validate, equal_values))
+                               validate, for_gcse))
              return 0;
          break;
 
@@ -2550,7 +2653,7 @@ exp_equiv_p (rtx x, rtx y, int validate, int equal_values)
          break;
 
        default:
-         abort ();
+         gcc_unreachable ();
        }
     }
 
@@ -2568,7 +2671,7 @@ cse_rtx_varies_p (rtx x, int from_alias)
      mode because if X is equivalent to a constant in some mode, it
      doesn't vary in any mode.  */
 
-  if (GET_CODE (x) == REG
+  if (REG_P (x)
       && REGNO_QTY_VALID_P (REGNO (x)))
     {
       int x_q = REG_QTY (REGNO (x));
@@ -2581,7 +2684,7 @@ cse_rtx_varies_p (rtx x, int from_alias)
 
   if (GET_CODE (x) == PLUS
       && GET_CODE (XEXP (x, 1)) == CONST_INT
-      && GET_CODE (XEXP (x, 0)) == REG
+      && REG_P (XEXP (x, 0))
       && REGNO_QTY_VALID_P (REGNO (XEXP (x, 0))))
     {
       int x0_q = REG_QTY (REGNO (XEXP (x, 0)));
@@ -2598,8 +2701,8 @@ cse_rtx_varies_p (rtx x, int from_alias)
      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
-      && GET_CODE (XEXP (x, 0)) == REG
-      && GET_CODE (XEXP (x, 1)) == REG
+      && 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))))
     {
@@ -2618,6 +2721,29 @@ cse_rtx_varies_p (rtx x, int from_alias)
   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.  */
+
+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))
+    validate_change (insn, xloc, new, 1);
+  else
+    *xloc = new;
+}
+
 /* Canonicalize an expression:
    replace each register reference inside it
    with the "oldest" equivalent register.
@@ -2687,25 +2813,10 @@ canon_reg (rtx x, rtx insn)
       int j;
 
       if (fmt[i] == 'e')
-       {
-         rtx new = canon_reg (XEXP (x, i), 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
-             && GET_CODE (new) == REG && GET_CODE (XEXP (x, i)) == REG
-             && (((REGNO (new) < FIRST_PSEUDO_REGISTER)
-                  != (REGNO (XEXP (x, i)) < FIRST_PSEUDO_REGISTER))
-                 || (insn_code = recog_memoized (insn)) < 0
-                 || insn_data[insn_code].n_dups > 0))
-           validate_change (insn, &XEXP (x, i), new, 1);
-         else
-           XEXP (x, i) = new;
-       }
+       validate_canon_reg (&XEXP (x, i), insn);
       else if (fmt[i] == 'E')
        for (j = 0; j < XVECLEN (x, i); j++)
-         XVECEXP (x, i, j) = canon_reg (XVECEXP (x, i, j), insn);
+         validate_canon_reg (&XVECEXP (x, i, j), insn);
     }
 
   return x;
@@ -2749,16 +2860,15 @@ find_best_addr (rtx insn, rtx *loc, enum machine_mode mode)
      no easy way to unshare the MEM.  In addition, looking up all stack
      addresses is costly.  */
   if ((GET_CODE (addr) == PLUS
-       && GET_CODE (XEXP (addr, 0)) == REG
+       && 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))
-      || (GET_CODE (addr) == REG
+      || (REG_P (addr)
          && (regno = REGNO (addr), regno == FRAME_POINTER_REGNUM
              || regno == HARD_FRAME_POINTER_REGNUM
              || regno == ARG_POINTER_REGNUM))
-      || GET_CODE (addr) == ADDRESSOF
       || CONSTANT_ADDRESS_P (addr))
     return;
 
@@ -2766,20 +2876,24 @@ find_best_addr (rtx insn, rtx *loc, enum machine_mode mode)
      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 (GET_CODE (addr) != REG)
+  if (!REG_P (addr))
     {
-      rtx folded = fold_rtx (copy_rtx (addr), NULL_RTX);
-      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;
+      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
@@ -2817,8 +2931,8 @@ find_best_addr (rtx insn, rtx *loc, enum machine_mode mode)
          for (p = elt->first_same_value; p; p = p->next_same_value)
            if (! p->flag)
              {
-               if ((GET_CODE (p->exp) == REG
-                    || exp_equiv_p (p->exp, p->exp, 1, 0))
+               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)))
@@ -2853,7 +2967,7 @@ find_best_addr (rtx insn, rtx *loc, enum machine_mode mode)
 
   if (flag_expensive_optimizations
       && ARITHMETIC_P (*loc)
-      && GET_CODE (XEXP (*loc, 0)) == REG)
+      && REG_P (XEXP (*loc, 0)))
     {
       rtx op1 = XEXP (*loc, 1);
 
@@ -2893,12 +3007,19 @@ find_best_addr (rtx insn, rtx *loc, enum machine_mode mode)
               p && count < 32;
               p = p->next_same_value, count++)
            if (! p->flag
-               && (GET_CODE (p->exp) == REG
-                   || exp_equiv_p (p->exp, p->exp, 1, 0)))
+               && (REG_P (p->exp)
+                   || (GET_CODE (p->exp) != EXPR_LIST
+                       && 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
@@ -2976,7 +3097,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
@@ -2986,7 +3107,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
@@ -3003,8 +3124,7 @@ find_comparison_args (enum rtx_code code, rtx *parg1, rtx *parg2,
       if (x == 0)
        /* Look up ARG1 in the hash table and see if it has an equivalence
           that lets us see what is being compared.  */
-       p = lookup (arg1, safe_hash (arg1, GET_MODE (arg1)) & HASH_MASK,
-                   GET_MODE (arg1));
+       p = lookup (arg1, SAFE_HASH (arg1, GET_MODE (arg1)), GET_MODE (arg1));
       if (p)
        {
          p = p->first_same_value;
@@ -3029,7 +3149,7 @@ find_comparison_args (enum rtx_code code, rtx *parg1, rtx *parg2,
 #endif
 
          /* If the entry isn't valid, skip it.  */
-         if (! exp_equiv_p (p->exp, p->exp, 1, 0))
+         if (! exp_equiv_p (p->exp, p->exp, 1, false))
            continue;
 
          if (GET_CODE (p->exp) == COMPARE
@@ -3050,7 +3170,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
@@ -3070,7 +3190,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
@@ -3121,6 +3241,371 @@ find_comparison_args (enum rtx_code code, rtx *parg1, rtx *parg2,
   return code;
 }
 \f
+/* Fold SUBREG.  */
+
+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;
+      }
+
+    /* Call target hook to avoid the effects of -fpic etc....  */
+    addr = targetm.delegitimize_address (addr);
+
+    /* 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.
@@ -3170,222 +3655,23 @@ fold_rtx (rtx x, rtx insn)
     case CONST_INT:
     case CONST_DOUBLE:
     case CONST_VECTOR:
-    case SYMBOL_REF:
-    case LABEL_REF:
-    case REG:
-      /* No use simplifying an EXPR_LIST
-        since they are used only for lists of args
-        in a function call's REG_EQUAL note.  */
-    case EXPR_LIST:
-      /* Changing anything inside an ADDRESSOF is incorrect; we don't
-        want to (e.g.,) make (addressof (const_int 0)) just because
-        the location is known to be zero.  */
-    case ADDRESSOF:
-      return x;
-
-#ifdef HAVE_cc0
-    case CC0:
-      return prev_insn_cc0;
-#endif
-
-    case PC:
-      /* If the next insn is a CODE_LABEL followed by a jump table,
-        PC's value is a LABEL_REF pointing to that label.  That
-        lets us fold switch statements on the VAX.  */
-      {
-       rtx next;
-       if (insn && tablejump_p (insn, &next, NULL))
-         return gen_rtx_LABEL_REF (Pmode, next);
-      }
-      break;
-
-    case SUBREG:
-      /* 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, 0))
-                 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 (GET_CODE (folded_arg0) == REG
-         && GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (folded_arg0)))
-       {
-         struct table_elt *elt;
-
-         /* We can use HASH here since we know that canon_hash won't be
-            called.  */
-         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 (GET_CODE (op0) != REG && ! 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 && GET_CODE (op0) != REG && ! CONSTANT_P (op0))
-                     op0 = fold_rtx (op0, NULL_RTX);
-
-                   if (op0)
-                     op0 = equiv_constant (op0);
-
-                   if (op1 && GET_CODE (op1) != REG && ! 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, 0))
-                 new = copy_rtx (SUBREG_REG (elt->exp));
+    case SYMBOL_REF:
+    case LABEL_REF:
+    case REG:
+    case PC:
+      /* No use simplifying an EXPR_LIST
+        since they are used only for lists of args
+        in a function call's REG_EQUAL note.  */
+    case EXPR_LIST:
+      return x;
 
-               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);
-             }
-       }
+#ifdef HAVE_cc0
+    case CC0:
+      return prev_insn_cc0;
+#endif
 
-      return x;
+    case SUBREG:
+      return fold_rtx_subreg (x, insn);
 
     case NOT:
     case NEG:
@@ -3397,136 +3683,7 @@ fold_rtx (rtx x, rtx insn)
       break;
 
     case MEM:
-      /* 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), GET_MODE (x));
-
-      {
-       /* 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 (GET_CODE (addr) == REG
-           && 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);
-       else if (GET_CODE (addr) == ADDRESSOF)
-         return change_address (x, VOIDmode, addr);
-
-       /* 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 && GET_CODE (table_insn) == JUMP_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)))
-                 return XVECEXP (table, 0,
-                                 offset / GET_MODE_SIZE (GET_MODE (table)));
-             }
-           if (table_insn && GET_CODE (table_insn) == JUMP_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;
-      }
+      return fold_rtx_mem (x, insn);
 
 #ifdef NO_FUNCTION_CSE
     case CALL:
@@ -3536,9 +3693,12 @@ fold_rtx (rtx x, rtx insn)
 #endif
 
     case ASM_OPERANDS:
-      for (i = ASM_OPERANDS_INPUT_LENGTH (x) - 1; i >= 0; i--)
-       validate_change (insn, &ASM_OPERANDS_INPUT (x, i),
-                        fold_rtx (ASM_OPERANDS_INPUT (x, i), insn), 0);
+      if (insn)
+       {
+         for (i = ASM_OPERANDS_INPUT_LENGTH (x) - 1; i >= 0; i--)
+           validate_change (insn, &ASM_OPERANDS_INPUT (x, i),
+                            fold_rtx (ASM_OPERANDS_INPUT (x, i), insn), 0);
+       }
       break;
 
     default:
@@ -3577,7 +3737,7 @@ fold_rtx (rtx x, rtx insn)
                struct qty_table_elem *arg_ent = &qty_table[arg_q];
 
                if (arg_ent->const_rtx != NULL_RTX
-                   && GET_CODE (arg_ent->const_rtx) != REG
+                   && !REG_P (arg_ent->const_rtx)
                    && GET_CODE (arg_ent->const_rtx) != PLUS)
                  const_arg
                    = gen_lowpart (GET_MODE (arg),
@@ -3664,7 +3824,7 @@ fold_rtx (rtx x, rtx insn)
 
            /* 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 it's operand.  This optimization
+              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
@@ -3763,7 +3923,16 @@ fold_rtx (rtx x, rtx insn)
        new = simplify_unary_operation (code, mode,
                                        const_arg0 ? const_arg0 : folded_arg0,
                                        mode_arg0);
-       if (new != 0 && is_const)
+       /* NEG of PLUS could be converted into MINUS, but that causes
+          expressions of the form
+          (CONST (MINUS (CONST_INT) (SYMBOL_REF)))
+          which many ports mistakenly treat as LEGITIMATE_CONSTANT_P.
+          FIXME: those ports should be fixed.  */
+       if (new != 0 && is_const
+           && GET_CODE (new) == PLUS
+           && (GET_CODE (XEXP (new, 0)) == SYMBOL_REF
+               || GET_CODE (XEXP (new, 0)) == LABEL_REF)
+           && GET_CODE (XEXP (new, 1)) == CONST_INT)
          new = gen_rtx_CONST (mode, new);
       }
       break;
@@ -3775,6 +3944,10 @@ fold_rtx (rtx x, rtx insn)
         constant, set CONST_ARG0 and CONST_ARG1 appropriately.  We needn't
         do anything if both operands are already known to be constant.  */
 
+      /* ??? Vector mode comparisons are not supported yet.  */
+      if (VECTOR_MODE_P (mode))
+       break;
+
       if (const_arg0 == 0 || const_arg1 == 0)
        {
          struct table_elt *p0, *p1;
@@ -3782,7 +3955,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));
@@ -3792,8 +3965,6 @@ fold_rtx (rtx x, rtx insn)
 
          code = find_comparison_args (code, &folded_arg0, &folded_arg1,
                                       &mode_arg0, &mode_arg1);
-         const_arg0 = equiv_constant (folded_arg0);
-         const_arg1 = equiv_constant (folded_arg1);
 
          /* If the mode is VOIDmode or a MODE_CC mode, we don't know
             what kinds of things are being compared, so we can't do
@@ -3802,11 +3973,65 @@ fold_rtx (rtx x, rtx insn)
          if (mode_arg0 == VOIDmode || GET_MODE_CLASS (mode_arg0) == MODE_CC)
            break;
 
+         const_arg0 = equiv_constant (folded_arg0);
+         const_arg1 = equiv_constant (folded_arg1);
+
          /* If we do not now have two constants being compared, see
             if we can nevertheless deduce some things about the
             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
@@ -3821,16 +4046,16 @@ fold_rtx (rtx x, rtx insn)
              /* See if the two operands are the same.  */
 
              if (folded_arg0 == folded_arg1
-                 || (GET_CODE (folded_arg0) == REG
-                     && GET_CODE (folded_arg1) == REG
+                 || (REG_P (folded_arg0)
+                     && REG_P (folded_arg1)
                      && (REG_QTY (REGNO (folded_arg0))
                          == REG_QTY (REGNO (folded_arg1))))
                  || ((p0 = lookup (folded_arg0,
-                                   (safe_hash (folded_arg0, mode_arg0)
-                                    & HASH_MASK), mode_arg0))
+                                   SAFE_HASH (folded_arg0, mode_arg0),
+                                   mode_arg0))
                      && (p1 = lookup (folded_arg1,
-                                      (safe_hash (folded_arg1, mode_arg0)
-                                       & HASH_MASK), mode_arg0))
+                                      SAFE_HASH (folded_arg1, mode_arg0),
+                                      mode_arg0))
                      && p0->first_same_value == p1->first_same_value))
                {
                  /* Sadly two equal NaNs are not equivalent.  */
@@ -3850,7 +4075,7 @@ fold_rtx (rtx x, rtx insn)
              /* If FOLDED_ARG0 is a register, see if the comparison we are
                 doing now is either the same as we did before or the reverse
                 (we only check the reverse if not floating-point).  */
-             else if (GET_CODE (folded_arg0) == REG)
+             else if (REG_P (folded_arg0))
                {
                  int qty = REG_QTY (REGNO (folded_arg0));
 
@@ -3866,7 +4091,7 @@ fold_rtx (rtx x, rtx insn)
                              || (const_arg1
                                  && rtx_equal_p (ent->comparison_const,
                                                  const_arg1))
-                             || (GET_CODE (folded_arg1) == REG
+                             || (REG_P (folded_arg1)
                                  && (REG_QTY (REGNO (folded_arg1)) == ent->comparison_qty))))
                        return (comparison_dominates_p (ent->comparison_code, code)
                                ? true_rtx : false_rtx);
@@ -3896,7 +4121,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));
@@ -4000,16 +4225,15 @@ fold_rtx (rtx x, rtx insn)
                 manner and hope the Sun compilers get it correct.  */
              && INTVAL (const_arg1) !=
                ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1))
-             && GET_CODE (folded_arg1) == REG)
+             && REG_P (folded_arg1))
            {
              rtx new_const = GEN_INT (-INTVAL (const_arg1));
              struct table_elt *p
-               = lookup (new_const, safe_hash (new_const, mode) & HASH_MASK,
-                         mode);
+               = lookup (new_const, SAFE_HASH (new_const, mode), mode);
 
              if (p)
                for (p = p->first_same_value; p; p = p->next_same_value)
-                 if (GET_CODE (p->exp) == REG)
+                 if (REG_P (p->exp))
                    return simplify_gen_binary (MINUS, mode, folded_arg0,
                                                canon_reg (p->exp, NULL_RTX));
            }
@@ -4041,7 +4265,7 @@ fold_rtx (rtx x, rtx insn)
             Note that the similar optimization done by combine.c only works
             if the intermediate operation's result has only one reference.  */
 
-         if (GET_CODE (folded_arg0) == REG
+         if (REG_P (folded_arg0)
              && const_arg1 && GET_CODE (const_arg1) == CONST_INT)
            {
              int is_shift
@@ -4153,17 +4377,6 @@ fold_rtx (rtx x, rtx insn)
                                        const_arg2 ? const_arg2 : XEXP (x, 2));
       break;
 
-    case RTX_EXTRA:
-      /* Eliminate CONSTANT_P_RTX if its constant.  */
-      if (code == CONSTANT_P_RTX)
-       {
-         if (const_arg0)
-           return const1_rtx;
-         if (optimize == 0 || !flag_gcse)
-           return const0_rtx;
-       }
-      break;
-
     default:
       break;
     }
@@ -4177,7 +4390,7 @@ fold_rtx (rtx x, rtx insn)
 static rtx
 equiv_constant (rtx x)
 {
-  if (GET_CODE (x) == REG
+  if (REG_P (x)
       && REGNO_QTY_VALID_P (REGNO (x)))
     {
       int x_q = REG_QTY (REGNO (x));
@@ -4195,7 +4408,7 @@ equiv_constant (rtx x)
      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) == MEM)
+  if (MEM_P (x))
     {
       struct table_elt *elt;
 
@@ -4203,7 +4416,7 @@ equiv_constant (rtx x)
       if (CONSTANT_P (x))
        return x;
 
-      elt = lookup (x, safe_hash (x, GET_MODE (x)) & HASH_MASK, GET_MODE (x));
+      elt = lookup (x, SAFE_HASH (x, GET_MODE (x)), GET_MODE (x));
       if (elt == 0)
        return 0;
 
@@ -4215,48 +4428,7 @@ equiv_constant (rtx x)
   return 0;
 }
 \f
-/* Assuming that X is an rtx (e.g., MEM, REG or SUBREG) for a fixed-point
-   number, return an rtx (MEM, SUBREG, or CONST_INT) that refers to the
-   least-significant part of X.
-   MODE specifies how big a part of X to return.
-
-   If the requested operation cannot be done, 0 is returned.
-
-   This is similar to gen_lowpart_general in emit-rtl.c.  */
-
-rtx
-gen_lowpart_if_possible (enum machine_mode mode, rtx x)
-{
-  rtx result = gen_lowpart_common (mode, x);
-
-  if (result)
-    return result;
-  else if (GET_CODE (x) == MEM)
-    {
-      /* This is the only other case we handle.  */
-      int offset = 0;
-      rtx new;
-
-      if (WORDS_BIG_ENDIAN)
-       offset = (MAX (GET_MODE_SIZE (GET_MODE (x)), UNITS_PER_WORD)
-                 - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD));
-      if (BYTES_BIG_ENDIAN)
-       /* Adjust the address so that the address-after-the-data is
-          unchanged.  */
-       offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode))
-                  - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x))));
-
-      new = adjust_address_nv (x, mode, offset);
-      if (! memory_address_p (mode, XEXP (new, 0)))
-       return 0;
-
-      return new;
-    }
-  else
-    return 0;
-}
-\f
-/* Given INSN, a jump insn, TAKEN indicates if we are following the "taken"
+/* Given INSN, a jump insn, PATH_TAKEN indicates if we are following the "taken"
    branch.  It will be zero if not.
 
    In certain cases, this can cause us to add an equivalence.  For example,
@@ -4313,6 +4485,18 @@ record_jump_equiv (rtx insn, int taken)
   record_jump_cond (code, mode, op0, op1, reversed_nonequality);
 }
 
+/* Yet another form of subreg creation.  In this case, we want something in
+   MODE, and we should assume OP has MODE iff it is naturally modeless.  */
+
+static rtx
+record_jump_cond_subreg (enum machine_mode mode, rtx op)
+{
+  enum machine_mode op_mode = GET_MODE (op);
+  if (op_mode == mode || op_mode == VOIDmode)
+    return op;
+  return lowpart_subreg (mode, op, op_mode);
+}
+
 /* We know that comparison CODE applied to OP0 and OP1 in MODE is true.
    REVERSED_NONEQUALITY is nonzero if CODE had to be swapped.
    Make any useful entries we can with that information.  Called from
@@ -4337,11 +4521,10 @@ record_jump_cond (enum rtx_code code, enum machine_mode mode, rtx op0,
          > GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0)))))
     {
       enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op0));
-      rtx tem = gen_lowpart (inner_mode, op1);
-
-      record_jump_cond (code, mode, SUBREG_REG (op0),
-                       tem ? tem : gen_rtx_SUBREG (inner_mode, op1, 0),
-                       reversed_nonequality);
+      rtx tem = record_jump_cond_subreg (inner_mode, op1);
+      if (tem)
+       record_jump_cond (code, mode, SUBREG_REG (op0), tem,
+                         reversed_nonequality);
     }
 
   if (code == EQ && GET_CODE (op1) == SUBREG
@@ -4349,11 +4532,10 @@ record_jump_cond (enum rtx_code code, enum machine_mode mode, rtx op0,
          > GET_MODE_SIZE (GET_MODE (SUBREG_REG (op1)))))
     {
       enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op1));
-      rtx tem = gen_lowpart (inner_mode, op0);
-
-      record_jump_cond (code, mode, SUBREG_REG (op1),
-                       tem ? tem : gen_rtx_SUBREG (inner_mode, op0, 0),
-                       reversed_nonequality);
+      rtx tem = record_jump_cond_subreg (inner_mode, op0);
+      if (tem)
+       record_jump_cond (code, mode, SUBREG_REG (op1), tem,
+                         reversed_nonequality);
     }
 
   /* Similarly, if this is an NE comparison, and either is a SUBREG
@@ -4369,11 +4551,10 @@ record_jump_cond (enum rtx_code code, enum machine_mode mode, rtx op0,
          < GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0)))))
     {
       enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op0));
-      rtx tem = gen_lowpart (inner_mode, op1);
-
-      record_jump_cond (code, mode, SUBREG_REG (op0),
-                       tem ? tem : gen_rtx_SUBREG (inner_mode, op1, 0),
-                       reversed_nonequality);
+      rtx tem = record_jump_cond_subreg (inner_mode, op1);
+      if (tem)
+       record_jump_cond (code, mode, SUBREG_REG (op0), tem,
+                         reversed_nonequality);
     }
 
   if (code == NE && GET_CODE (op1) == SUBREG
@@ -4382,11 +4563,10 @@ record_jump_cond (enum rtx_code code, enum machine_mode mode, rtx op0,
          < GET_MODE_SIZE (GET_MODE (SUBREG_REG (op1)))))
     {
       enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op1));
-      rtx tem = gen_lowpart (inner_mode, op0);
-
-      record_jump_cond (code, mode, SUBREG_REG (op1),
-                       tem ? tem : gen_rtx_SUBREG (inner_mode, op0, 0),
-                       reversed_nonequality);
+      rtx tem = record_jump_cond_subreg (inner_mode, op0);
+      if (tem)
+       record_jump_cond (code, mode, SUBREG_REG (op1), tem,
+                         reversed_nonequality);
     }
 
   /* Hash both operands.  */
@@ -4433,11 +4613,11 @@ record_jump_cond (enum rtx_code code, enum machine_mode mode, rtx op0,
         register, or if OP1 is neither a register or constant, we can't
         do anything.  */
 
-      if (GET_CODE (op1) != REG)
+      if (!REG_P (op1))
        op1 = equiv_constant (op1);
 
       if ((reversed_nonequality && FLOAT_MODE_P (mode))
-         || GET_CODE (op0) != REG || op1 == 0)
+         || !REG_P (op0) || op1 == 0)
        return;
 
       /* Put OP0 in the hash table if it isn't already.  This gives it a
@@ -4464,7 +4644,7 @@ record_jump_cond (enum rtx_code code, enum machine_mode mode, rtx op0,
       ent = &qty_table[qty];
 
       ent->comparison_code = code;
-      if (GET_CODE (op1) == REG)
+      if (REG_P (op1))
        {
          /* Look it up again--in case op0 and op1 are the same.  */
          op1_elt = lookup (op1, op1_hash, mode);
@@ -4522,7 +4702,6 @@ record_jump_cond (enum rtx_code code, enum machine_mode mode, rtx op0,
     }
 
   merge_equiv_classes (op0_elt, op1_elt);
-  last_jump_equiv_class = op0_elt;
 }
 \f
 /* CSE processing for one instruction.
@@ -4599,7 +4778,7 @@ cse_insn (rtx insn, rtx libcall_insn)
      Also determine whether there is a CLOBBER that invalidates
      all memory references, or all references at varying addresses.  */
 
-  if (GET_CODE (insn) == CALL_INSN)
+  if (CALL_P (insn))
     {
       for (tem = CALL_INSN_FUNCTION_USAGE (insn); tem; tem = XEXP (tem, 1))
        {
@@ -4666,7 +4845,7 @@ cse_insn (rtx insn, rtx libcall_insn)
            {
              rtx clobbered = XEXP (y, 0);
 
-             if (GET_CODE (clobbered) == REG
+             if (REG_P (clobbered)
                  || GET_CODE (clobbered) == SUBREG)
                invalidate (clobbered, VOIDmode);
              else if (GET_CODE (clobbered) == STRICT_LOW_PART
@@ -4700,11 +4879,11 @@ cse_insn (rtx insn, rtx libcall_insn)
              /* If we clobber memory, canon the address.
                 This does nothing when a register is clobbered
                 because we have already invalidated the reg.  */
-             if (GET_CODE (XEXP (y, 0)) == MEM)
+             if (MEM_P (XEXP (y, 0)))
                canon_reg (XEXP (y, 0), NULL_RTX);
            }
          else if (GET_CODE (y) == USE
-                  && ! (GET_CODE (XEXP (y, 0)) == REG
+                  && ! (REG_P (XEXP (y, 0))
                         && REGNO (XEXP (y, 0)) < FIRST_PSEUDO_REGISTER))
            canon_reg (y, NULL_RTX);
          else if (GET_CODE (y) == CALL)
@@ -4719,13 +4898,13 @@ cse_insn (rtx insn, rtx libcall_insn)
     }
   else if (GET_CODE (x) == CLOBBER)
     {
-      if (GET_CODE (XEXP (x, 0)) == MEM)
+      if (MEM_P (XEXP (x, 0)))
        canon_reg (XEXP (x, 0), NULL_RTX);
     }
 
   /* Canonicalize a USE of a pseudo register or memory location.  */
   else if (GET_CODE (x) == USE
-          && ! (GET_CODE (XEXP (x, 0)) == REG
+          && ! (REG_P (XEXP (x, 0))
                 && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER))
     canon_reg (XEXP (x, 0), NULL_RTX);
   else if (GET_CODE (x) == CALL)
@@ -4767,7 +4946,7 @@ cse_insn (rtx insn, rtx libcall_insn)
       int insn_code;
 
       sets[i].orig_src = src;
-      if ((GET_CODE (new) == REG && GET_CODE (src) == REG
+      if ((REG_P (new) && REG_P (src)
           && ((REGNO (new) < FIRST_PSEUDO_REGISTER)
               != (REGNO (src) < FIRST_PSEUDO_REGISTER)))
          || (insn_code = recog_memoized (insn)) < 0
@@ -4776,7 +4955,7 @@ cse_insn (rtx insn, rtx libcall_insn)
       else
        SET_SRC (sets[i].rtl) = new;
 
-      if (GET_CODE (dest) == ZERO_EXTRACT || GET_CODE (dest) == SIGN_EXTRACT)
+      if (GET_CODE (dest) == ZERO_EXTRACT)
        {
          validate_change (insn, &XEXP (dest, 1),
                           canon_reg (XEXP (dest, 1), insn), 1);
@@ -4784,12 +4963,12 @@ cse_insn (rtx insn, rtx libcall_insn)
                           canon_reg (XEXP (dest, 2), insn), 1);
        }
 
-      while (GET_CODE (dest) == SUBREG || GET_CODE (dest) == STRICT_LOW_PART
+      while (GET_CODE (dest) == SUBREG
             || GET_CODE (dest) == ZERO_EXTRACT
-            || GET_CODE (dest) == SIGN_EXTRACT)
+            || GET_CODE (dest) == STRICT_LOW_PART)
        dest = XEXP (dest, 0);
 
-      if (GET_CODE (dest) == MEM)
+      if (MEM_P (dest))
        canon_reg (dest, insn);
     }
 
@@ -4883,8 +5062,7 @@ cse_insn (rtx insn, rtx libcall_insn)
         causes later instructions to be mis-optimized.  */
       /* If storing a constant in a bitfield, pre-truncate the constant
         so we will be able to record it later.  */
-      if (GET_CODE (SET_DEST (sets[i].rtl)) == ZERO_EXTRACT
-         || GET_CODE (SET_DEST (sets[i].rtl)) == SIGN_EXTRACT)
+      if (GET_CODE (SET_DEST (sets[i].rtl)) == ZERO_EXTRACT)
        {
          rtx width = XEXP (SET_DEST (sets[i].rtl), 1);
 
@@ -4916,9 +5094,9 @@ cse_insn (rtx insn, rtx libcall_insn)
         RTL would be referring to SRC, so we don't lose any optimization
         opportunities by not having SRC in the hash table.  */
 
-      if (GET_CODE (src) == MEM
+      if (MEM_P (src)
          && find_reg_note (insn, REG_EQUIV, NULL_RTX) != 0
-         && GET_CODE (dest) == REG
+         && REG_P (dest)
          && REGNO (dest) >= FIRST_PSEUDO_REGISTER)
        sets[i].src_volatile = 1;
 
@@ -5069,7 +5247,7 @@ cse_insn (rtx insn, rtx libcall_insn)
 
              for (const_elt = const_elt->first_same_value;
                   const_elt; const_elt = const_elt->next_same_value)
-               if (GET_CODE (const_elt->exp) == REG)
+               if (REG_P (const_elt->exp))
                  {
                    src_related = gen_lowpart (mode,
                                                           const_elt->exp);
@@ -5108,7 +5286,7 @@ cse_insn (rtx insn, rtx libcall_insn)
 
                  for (larger_elt = larger_elt->first_same_value;
                       larger_elt; larger_elt = larger_elt->next_same_value)
-                   if (GET_CODE (larger_elt->exp) == REG)
+                   if (REG_P (larger_elt->exp))
                      {
                        src_related
                          = gen_lowpart (mode, larger_elt->exp);
@@ -5130,13 +5308,16 @@ cse_insn (rtx insn, rtx libcall_insn)
       if (flag_expensive_optimizations && src_related == 0
          && (GET_MODE_SIZE (mode) < UNITS_PER_WORD)
          && GET_MODE_CLASS (mode) == MODE_INT
-         && GET_CODE (src) == MEM && ! do_not_record
-         && LOAD_EXTEND_OP (mode) != NIL)
+         && MEM_P (src) && ! do_not_record
+         && LOAD_EXTEND_OP (mode) != UNKNOWN)
        {
+         struct rtx_def memory_extend_buf;
+         rtx memory_extend_rtx = &memory_extend_buf;
          enum machine_mode tmode;
 
          /* Set what we are trying to extend and the operation it might
             have been extended with.  */
+         memset (memory_extend_rtx, 0, sizeof(*memory_extend_rtx));
          PUT_CODE (memory_extend_rtx, LOAD_EXTEND_OP (mode));
          XEXP (memory_extend_rtx, 0) = src;
 
@@ -5154,7 +5335,7 @@ cse_insn (rtx insn, rtx libcall_insn)
 
              for (larger_elt = larger_elt->first_same_value;
                   larger_elt; larger_elt = larger_elt->next_same_value)
-               if (GET_CODE (larger_elt->exp) == REG)
+               if (REG_P (larger_elt->exp))
                  {
                    src_related = gen_lowpart (mode,
                                                           larger_elt->exp);
@@ -5190,7 +5371,7 @@ cse_insn (rtx insn, rtx libcall_insn)
          /* If the expression is not valid, ignore it.  Then we do not
             have to check for validity below.  In most cases, we can use
             `rtx_equal_p', since canonicalization has already been done.  */
-         if (code != REG && ! exp_equiv_p (p->exp, p->exp, 1, 0))
+         if (code != REG && ! exp_equiv_p (p->exp, p->exp, 1, false))
            continue;
 
          /* Also skip paradoxical subregs, unless that's what we're
@@ -5286,8 +5467,8 @@ cse_insn (rtx insn, rtx libcall_insn)
          rtx trial;
 
          /* Skip invalid entries.  */
-         while (elt && GET_CODE (elt->exp) != REG
-                && ! exp_equiv_p (elt->exp, elt->exp, 1, 0))
+         while (elt && !REG_P (elt->exp)
+                && ! exp_equiv_p (elt->exp, elt->exp, 1, false))
            elt = elt->next_same_value;
 
          /* A paradoxical subreg would be bad here: it'll be the right
@@ -5375,11 +5556,32 @@ cse_insn (rtx insn, rtx libcall_insn)
                  || (GET_CODE (trial) == LABEL_REF
                      && ! condjump_p (insn))))
            {
+             /* Don't substitute non-local labels, this confuses CFG.  */
+             if (GET_CODE (trial) == LABEL_REF
+                 && LABEL_REF_NONLOCAL_P (trial))
+               continue;
+
              SET_SRC (sets[i].rtl) = trial;
              cse_jumps_altered = 1;
              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))
            {
@@ -5389,9 +5591,9 @@ cse_insn (rtx insn, rtx libcall_insn)
                 need to make the same substitution in any notes attached
                 to the RETVAL insn.  */
              if (libcall_insn
-                 && (GET_CODE (sets[i].orig_src) == REG
+                 && (REG_P (sets[i].orig_src)
                      || GET_CODE (sets[i].orig_src) == SUBREG
-                     || GET_CODE (sets[i].orig_src) == MEM))
+                     || MEM_P (sets[i].orig_src)))
                {
                  rtx note = find_reg_equal_equiv_note (libcall_insn);
                  if (note != 0)
@@ -5415,18 +5617,8 @@ cse_insn (rtx insn, rtx libcall_insn)
 
          else if (constant_pool_entries_cost
                   && CONSTANT_P (trial)
-                  /* Reject cases that will abort in decode_rtx_const.
-                     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
-                      || (GET_CODE (src_folded) != MEM
+                      || (!MEM_P (src_folded)
                           && ! src_folded_force_flag))
                   && GET_MODE_CLASS (mode) != MODE_CC
                   && mode != VOIDmode)
@@ -5446,7 +5638,7 @@ cse_insn (rtx insn, rtx libcall_insn)
         with the head of the class.  If we do not do this, we will have
         both registers live over a portion of the basic block.  This way,
         their lifetimes will likely abut instead of overlapping.  */
-      if (GET_CODE (dest) == REG
+      if (REG_P (dest)
          && REGNO_QTY_VALID_P (REGNO (dest)))
        {
          int dest_q = REG_QTY (REGNO (dest));
@@ -5454,12 +5646,12 @@ cse_insn (rtx insn, rtx libcall_insn)
 
          if (dest_ent->mode == GET_MODE (dest)
              && dest_ent->first_reg != REGNO (dest)
-             && GET_CODE (src) == REG && REGNO (src) == REGNO (dest)
+             && REG_P (src) && REGNO (src) == REGNO (dest)
              /* Don't do this if the original insn had a hard reg as
                 SET_SRC or SET_DEST.  */
-             && (GET_CODE (sets[i].src) != REG
+             && (!REG_P (sets[i].src)
                  || REGNO (sets[i].src) >= FIRST_PSEUDO_REGISTER)
-             && (GET_CODE (dest) != REG || REGNO (dest) >= FIRST_PSEUDO_REGISTER))
+             && (!REG_P (dest) || REGNO (dest) >= FIRST_PSEUDO_REGISTER))
            /* We can't call canon_reg here because it won't do anything if
               SRC is a hard register.  */
            {
@@ -5510,8 +5702,8 @@ cse_insn (rtx insn, rtx libcall_insn)
         which can be created for a reference to a compile time computable
         entry in a jump table.  */
 
-      if (n_sets == 1 && src_const && GET_CODE (dest) == REG
-         && GET_CODE (src_const) != REG
+      if (n_sets == 1 && src_const && REG_P (dest)
+         && !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
@@ -5532,17 +5724,15 @@ cse_insn (rtx insn, rtx libcall_insn)
       /* Now deal with the destination.  */
       do_not_record = 0;
 
-      /* Look within any SIGN_EXTRACT or ZERO_EXTRACT
-        to the MEM or REG within it.  */
-      while (GET_CODE (dest) == SIGN_EXTRACT
+      /* Look within any ZERO_EXTRACT to the MEM or REG within it.  */
+      while (GET_CODE (dest) == SUBREG
             || GET_CODE (dest) == ZERO_EXTRACT
-            || GET_CODE (dest) == SUBREG
             || GET_CODE (dest) == STRICT_LOW_PART)
        dest = XEXP (dest, 0);
 
       sets[i].inner_dest = dest;
 
-      if (GET_CODE (dest) == MEM)
+      if (MEM_P (dest))
        {
 #ifdef PUSH_ROUNDING
          /* Stack pushes invalidate the stack pointer.  */
@@ -5564,8 +5754,7 @@ cse_insn (rtx insn, rtx libcall_insn)
         because the value in it after the store
         may not equal what was stored, due to truncation.  */
 
-      if (GET_CODE (SET_DEST (sets[i].rtl)) == ZERO_EXTRACT
-         || GET_CODE (SET_DEST (sets[i].rtl)) == SIGN_EXTRACT)
+      if (GET_CODE (SET_DEST (sets[i].rtl)) == ZERO_EXTRACT)
        {
          rtx width = XEXP (SET_DEST (sets[i].rtl), 1);
 
@@ -5603,11 +5792,12 @@ cse_insn (rtx insn, rtx libcall_insn)
 
       /* If this SET is now setting PC to a label, we know it used to
         be a conditional or computed branch.  */
-      else if (dest == pc_rtx && GET_CODE (src) == LABEL_REF)
+      else if (dest == pc_rtx && GET_CODE (src) == LABEL_REF
+              && !LABEL_REF_NONLOCAL_P (src))
        {
          /* Now emit a BARRIER after the unconditional jump.  */
          if (NEXT_INSN (insn) == 0
-             || GET_CODE (NEXT_INSN (insn)) != BARRIER)
+             || !BARRIER_P (NEXT_INSN (insn)))
            emit_barrier_after (insn);
 
          /* We reemit the jump in as many cases as possible just in
@@ -5638,14 +5828,12 @@ cse_insn (rtx insn, rtx libcall_insn)
 
              /* Now emit a BARRIER after the unconditional jump.  */
              if (NEXT_INSN (insn) == 0
-                 || GET_CODE (NEXT_INSN (insn)) != BARRIER)
+                 || !BARRIER_P (NEXT_INSN (insn)))
                emit_barrier_after (insn);
            }
          else
            INSN_CODE (insn) = -1;
 
-         never_reached_warning (insn, NULL);
-
          /* Do not bother deleting any unreachable code,
             let jump/flow do that.  */
 
@@ -5658,15 +5846,10 @@ cse_insn (rtx insn, rtx libcall_insn)
 
       else if (do_not_record)
        {
-         if (GET_CODE (dest) == REG || GET_CODE (dest) == SUBREG)
+         if (REG_P (dest) || GET_CODE (dest) == SUBREG)
+           invalidate (dest, VOIDmode);
+         else if (MEM_P (dest))
            invalidate (dest, VOIDmode);
-         else if (GET_CODE (dest) == MEM)
-           {
-             /* Outgoing arguments for a libcall don't
-                affect any recorded expressions.  */
-             if (! libcall_insn || insn == libcall_insn)
-               invalidate (dest, VOIDmode);
-           }
          else if (GET_CODE (dest) == STRICT_LOW_PART
                   || GET_CODE (dest) == ZERO_EXTRACT)
            invalidate (XEXP (dest, 0), GET_MODE (dest));
@@ -5808,7 +5991,7 @@ cse_insn (rtx insn, rtx libcall_insn)
   /* Some registers are invalidated by subroutine calls.  Memory is
      invalidated by non-constant calls.  */
 
-  if (GET_CODE (insn) == CALL_INSN)
+  if (CALL_P (insn))
     {
       if (! CONST_OR_PURE_CALL_P (insn))
        invalidate_memory ();
@@ -5831,22 +6014,17 @@ cse_insn (rtx insn, rtx libcall_insn)
           previous quantity's chain.
           Needed for memory if this is a nonvarying address, unless
           we have just done an invalidate_memory that covers even those.  */
-       if (GET_CODE (dest) == REG || GET_CODE (dest) == SUBREG)
+       if (REG_P (dest) || GET_CODE (dest) == SUBREG)
+         invalidate (dest, VOIDmode);
+       else if (MEM_P (dest))
          invalidate (dest, VOIDmode);
-       else if (GET_CODE (dest) == MEM)
-         {
-           /* Outgoing arguments for a libcall don't
-              affect any recorded expressions.  */
-           if (! libcall_insn || insn == libcall_insn)
-             invalidate (dest, VOIDmode);
-         }
        else if (GET_CODE (dest) == STRICT_LOW_PART
                 || GET_CODE (dest) == ZERO_EXTRACT)
          invalidate (XEXP (dest, 0), GET_MODE (dest));
       }
 
   /* A volatile ASM invalidates everything.  */
-  if (GET_CODE (insn) == INSN
+  if (NONJUMP_INSN_P (insn)
       && GET_CODE (PATTERN (insn)) == ASM_OPERANDS
       && MEM_VOLATILE_P (PATTERN (insn)))
     flush_hash_table ();
@@ -5865,7 +6043,7 @@ cse_insn (rtx insn, rtx libcall_insn)
        {
          rtx x = SET_DEST (sets[i].rtl);
 
-         if (GET_CODE (x) != REG)
+         if (!REG_P (x))
            mention_regs (x);
          else
            {
@@ -5926,14 +6104,13 @@ cse_insn (rtx insn, rtx libcall_insn)
     if (sets[i].rtl)
       {
        rtx dest = SET_DEST (sets[i].rtl);
-       rtx inner_dest = sets[i].inner_dest;
        struct table_elt *elt;
 
        /* Don't record value if we are not supposed to risk allocating
           floating-point values in registers that might be wider than
           memory.  */
        if ((flag_float_store
-            && GET_CODE (dest) == MEM
+            && MEM_P (dest)
             && FLOAT_MODE_P (GET_MODE (dest)))
            /* Don't record BLKmode values, because we don't know the
               size of it, and can't be sure that other BLKmode values
@@ -5965,7 +6142,7 @@ cse_insn (rtx insn, rtx libcall_insn)
        if (GET_CODE (dest) == STRICT_LOW_PART)
          dest = SUBREG_REG (XEXP (dest, 0));
 
-       if (GET_CODE (dest) == REG || GET_CODE (dest) == SUBREG)
+       if (REG_P (dest) || GET_CODE (dest) == SUBREG)
          /* Registers must also be inserted into chains for quantities.  */
          if (insert_regs (dest, sets[i].src_elt, 1))
            {
@@ -5975,22 +6152,11 @@ cse_insn (rtx insn, rtx libcall_insn)
              sets[i].dest_hash = HASH (dest, GET_MODE (dest));
            }
 
-       if (GET_CODE (inner_dest) == MEM
-           && GET_CODE (XEXP (inner_dest, 0)) == ADDRESSOF)
-         /* Given (SET (MEM (ADDRESSOF (X))) Y) we don't want to say
-            that (MEM (ADDRESSOF (X))) is equivalent to Y.
-            Consider the case in which the address of the MEM is
-            passed to a function, which alters the MEM.  Then, if we
-            later use Y instead of the MEM we'll miss the update.  */
-         elt = insert (dest, 0, sets[i].dest_hash, GET_MODE (dest));
-       else
-         elt = insert (dest, sets[i].src_elt,
-                       sets[i].dest_hash, GET_MODE (dest));
+       elt = insert (dest, sets[i].src_elt,
+                     sets[i].dest_hash, GET_MODE (dest));
 
-       elt->in_memory = (GET_CODE (sets[i].inner_dest) == MEM
-                         && (! RTX_UNCHANGING_P (sets[i].inner_dest)
-                             || fixed_base_plus_p (XEXP (sets[i].inner_dest,
-                                                         0))));
+       elt->in_memory = (MEM_P (sets[i].inner_dest)
+                         && !MEM_READONLY_P (sets[i].inner_dest));
 
        /* If we have (set (subreg:m1 (reg:m2 foo) 0) (bar:m1)), M1 is no
           narrower than M2, and both M1 and M2 are the same number of words,
@@ -6027,8 +6193,8 @@ cse_insn (rtx insn, rtx libcall_insn)
                int byte = 0;
 
                /* Ignore invalid entries.  */
-               if (GET_CODE (elt->exp) != REG
-                   && ! exp_equiv_p (elt->exp, elt->exp, 1, 0))
+               if (!REG_P (elt->exp)
+                   && ! exp_equiv_p (elt->exp, elt->exp, 1, false))
                  continue;
 
                /* We may have already been playing subreg games.  If the
@@ -6080,8 +6246,8 @@ cse_insn (rtx insn, rtx libcall_insn)
                classp = src_elt->first_same_value;
                /* Ignore invalid entries.  */
                while (classp
-                      && GET_CODE (classp->exp) != REG
-                      && ! exp_equiv_p (classp->exp, classp->exp, 1, 0))
+                      && !REG_P (classp->exp)
+                      && ! exp_equiv_p (classp->exp, classp->exp, 1, false))
                  classp = classp->next_same_value;
              }
          }
@@ -6104,9 +6270,9 @@ cse_insn (rtx insn, rtx libcall_insn)
      register to be set in the middle of a libcall, and we then get bad code
      if the libcall is deleted.  */
 
-  if (n_sets == 1 && sets[0].rtl && GET_CODE (SET_DEST (sets[0].rtl)) == REG
+  if (n_sets == 1 && sets[0].rtl && REG_P (SET_DEST (sets[0].rtl))
       && NEXT_INSN (PREV_INSN (insn)) == insn
-      && GET_CODE (SET_SRC (sets[0].rtl)) == REG
+      && 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))))
     {
@@ -6123,7 +6289,7 @@ cse_insn (rtx insn, rtx libcall_insn)
            {
              prev = PREV_INSN (prev);
            }
-         while (prev && GET_CODE (prev) == NOTE
+         while (prev && NOTE_P (prev)
                 && NOTE_LINE_NUMBER (prev) != NOTE_INSN_BASIC_BLOCK);
 
          /* Do not swap the registers around if the previous instruction
@@ -6138,7 +6304,7 @@ cse_insn (rtx insn, rtx libcall_insn)
             note.  We cannot do that because REG_EQUIV may provide an
             uninitialized stack slot when REG_PARM_STACK_SPACE is used.  */
 
-         if (prev != 0 && GET_CODE (prev) == INSN
+         if (prev != 0 && 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))
@@ -6168,8 +6334,7 @@ cse_insn (rtx insn, rtx libcall_insn)
   /* If this is a conditional jump insn, record any known equivalences due to
      the condition being tested.  */
 
-  last_jump_equiv_class = 0;
-  if (GET_CODE (insn) == JUMP_INSN
+  if (JUMP_P (insn)
       && n_sets == 1 && GET_CODE (x) == SET
       && GET_CODE (SET_SRC (x)) == IF_THEN_ELSE)
     record_jump_equiv (insn, 0);
@@ -6178,7 +6343,7 @@ cse_insn (rtx insn, rtx libcall_insn)
   /* If the previous insn set CC0 and this insn no longer references CC0,
      delete the previous insn.  Here we use the fact that nothing expects CC0
      to be valid over an insn, which is true until the final pass.  */
-  if (prev_insn && GET_CODE (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, x))
@@ -6214,7 +6379,7 @@ static int
 addr_affects_sp_p (rtx addr)
 {
   if (GET_RTX_CLASS (GET_CODE (addr)) == RTX_AUTOINC
-      && GET_CODE (XEXP (addr, 0)) == REG
+      && REG_P (XEXP (addr, 0))
       && REGNO (XEXP (addr, 0)) == STACK_POINTER_REGNUM)
     {
       if (REG_TICK (STACK_POINTER_REGNUM) >= 0)
@@ -6249,8 +6414,8 @@ invalidate_from_clobbers (rtx x)
       rtx ref = XEXP (x, 0);
       if (ref)
        {
-         if (GET_CODE (ref) == REG || GET_CODE (ref) == SUBREG
-             || GET_CODE (ref) == MEM)
+         if (REG_P (ref) || GET_CODE (ref) == SUBREG
+             || MEM_P (ref))
            invalidate (ref, VOIDmode);
          else if (GET_CODE (ref) == STRICT_LOW_PART
                   || GET_CODE (ref) == ZERO_EXTRACT)
@@ -6266,8 +6431,8 @@ invalidate_from_clobbers (rtx x)
          if (GET_CODE (y) == CLOBBER)
            {
              rtx ref = XEXP (y, 0);
-             if (GET_CODE (ref) == REG || GET_CODE (ref) == SUBREG
-                 || GET_CODE (ref) == MEM)
+             if (REG_P (ref) || GET_CODE (ref) == SUBREG
+                 || MEM_P (ref))
                invalidate (ref, VOIDmode);
              else if (GET_CODE (ref) == STRICT_LOW_PART
                       || GET_CODE (ref) == ZERO_EXTRACT)
@@ -6341,7 +6506,7 @@ cse_process_notes (rtx x, rtx object)
 
          if (ent->const_rtx != NULL_RTX
              && (CONSTANT_P (ent->const_rtx)
-                 || GET_CODE (ent->const_rtx) == REG))
+                 || REG_P (ent->const_rtx)))
            {
              rtx new = gen_lowpart (GET_MODE (x), ent->const_rtx);
              if (new)
@@ -6364,88 +6529,6 @@ cse_process_notes (rtx x, rtx object)
   return x;
 }
 \f
-/* Find common subexpressions between the end test of a loop and the beginning
-   of the loop.  LOOP_START is the CODE_LABEL at the start of a loop.
-
-   Often we have a loop where an expression in the exit test is used
-   in the body of the loop.  For example "while (*p) *q++ = *p++;".
-   Because of the way we duplicate the loop exit test in front of the loop,
-   however, we don't detect that common subexpression.  This will be caught
-   when global cse is implemented, but this is a quite common case.
-
-   This function handles the most common cases of these common expressions.
-   It is called after we have processed the basic block ending with the
-   NOTE_INSN_LOOP_END note that ends a loop and the previous JUMP_INSN
-   jumps to a label used only once.  */
-
-static void
-cse_around_loop (rtx loop_start)
-{
-  rtx insn;
-  int i;
-  struct table_elt *p;
-
-  /* If the jump at the end of the loop doesn't go to the start, we don't
-     do anything.  */
-  for (insn = PREV_INSN (loop_start);
-       insn && (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) >= 0);
-       insn = PREV_INSN (insn))
-    ;
-
-  if (insn == 0
-      || GET_CODE (insn) != NOTE
-      || NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_BEG)
-    return;
-
-  /* If the last insn of the loop (the end test) was an NE comparison,
-     we will interpret it as an EQ comparison, since we fell through
-     the loop.  Any equivalences resulting from that comparison are
-     therefore not valid and must be invalidated.  */
-  if (last_jump_equiv_class)
-    for (p = last_jump_equiv_class->first_same_value; p;
-        p = p->next_same_value)
-      {
-       if (GET_CODE (p->exp) == MEM || GET_CODE (p->exp) == REG
-           || (GET_CODE (p->exp) == SUBREG
-               && GET_CODE (SUBREG_REG (p->exp)) == REG))
-         invalidate (p->exp, VOIDmode);
-       else if (GET_CODE (p->exp) == STRICT_LOW_PART
-                || GET_CODE (p->exp) == ZERO_EXTRACT)
-         invalidate (XEXP (p->exp, 0), GET_MODE (p->exp));
-      }
-
-  /* Process insns starting after LOOP_START until we hit a CALL_INSN or
-     a CODE_LABEL (we could handle a CALL_INSN, but it isn't worth it).
-
-     The only thing we do with SET_DEST is invalidate entries, so we
-     can safely process each SET in order.  It is slightly less efficient
-     to do so, but we only want to handle the most common cases.
-
-     The gen_move_insn call in cse_set_around_loop may create new pseudos.
-     These pseudos won't have valid entries in any of the tables indexed
-     by register number, such as reg_qty.  We avoid out-of-range array
-     accesses by not processing any instructions created after cse started.  */
-
-  for (insn = NEXT_INSN (loop_start);
-       GET_CODE (insn) != CALL_INSN && GET_CODE (insn) != CODE_LABEL
-       && INSN_UID (insn) < max_insn_uid
-       && ! (GET_CODE (insn) == NOTE
-            && NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END);
-       insn = NEXT_INSN (insn))
-    {
-      if (INSN_P (insn)
-         && (GET_CODE (PATTERN (insn)) == SET
-             || GET_CODE (PATTERN (insn)) == CLOBBER))
-       cse_set_around_loop (PATTERN (insn), insn, loop_start);
-      else if (INSN_P (insn) && GET_CODE (PATTERN (insn)) == PARALLEL)
-       for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
-         if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == SET
-             || GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == CLOBBER)
-           cse_set_around_loop (XVECEXP (PATTERN (insn), 0, i), insn,
-                                loop_start);
-    }
-}
-\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.  */
 
@@ -6488,13 +6571,13 @@ invalidate_skipped_block (rtx start)
 {
   rtx insn;
 
-  for (insn = start; insn && GET_CODE (insn) != CODE_LABEL;
+  for (insn = start; insn && !LABEL_P (insn);
        insn = NEXT_INSN (insn))
     {
       if (! INSN_P (insn))
        continue;
 
-      if (GET_CODE (insn) == CALL_INSN)
+      if (CALL_P (insn))
        {
          if (! CONST_OR_PURE_CALL_P (insn))
            invalidate_memory ();
@@ -6506,146 +6589,6 @@ invalidate_skipped_block (rtx start)
     }
 }
 \f
-/* If modifying X will modify the value in *DATA (which is really an
-   `rtx *'), indicate that fact by setting the pointed to value to
-   NULL_RTX.  */
-
-static void
-cse_check_loop_start (rtx x, rtx set ATTRIBUTE_UNUSED, void *data)
-{
-  rtx *cse_check_loop_start_value = (rtx *) data;
-
-  if (*cse_check_loop_start_value == NULL_RTX
-      || GET_CODE (x) == CC0 || GET_CODE (x) == PC)
-    return;
-
-  if ((GET_CODE (x) == MEM && GET_CODE (*cse_check_loop_start_value) == MEM)
-      || reg_overlap_mentioned_p (x, *cse_check_loop_start_value))
-    *cse_check_loop_start_value = NULL_RTX;
-}
-
-/* X is a SET or CLOBBER contained in INSN that was found near the start of
-   a loop that starts with the label at LOOP_START.
-
-   If X is a SET, we see if its SET_SRC is currently in our hash table.
-   If so, we see if it has a value equal to some register used only in the
-   loop exit code (as marked by jump.c).
-
-   If those two conditions are true, we search backwards from the start of
-   the loop to see if that same value was loaded into a register that still
-   retains its value at the start of the loop.
-
-   If so, we insert an insn after the load to copy the destination of that
-   load into the equivalent register and (try to) replace our SET_SRC with that
-   register.
-
-   In any event, we invalidate whatever this SET or CLOBBER modifies.  */
-
-static void
-cse_set_around_loop (rtx x, rtx insn, rtx loop_start)
-{
-  struct table_elt *src_elt;
-
-  /* If this is a SET, see if we can replace SET_SRC, but ignore SETs that
-     are setting PC or CC0 or whose SET_SRC is already a register.  */
-  if (GET_CODE (x) == SET
-      && GET_CODE (SET_DEST (x)) != PC && GET_CODE (SET_DEST (x)) != CC0
-      && GET_CODE (SET_SRC (x)) != REG)
-    {
-      src_elt = lookup (SET_SRC (x),
-                       HASH (SET_SRC (x), GET_MODE (SET_DEST (x))),
-                       GET_MODE (SET_DEST (x)));
-
-      if (src_elt)
-       for (src_elt = src_elt->first_same_value; src_elt;
-            src_elt = src_elt->next_same_value)
-         if (GET_CODE (src_elt->exp) == REG && REG_LOOP_TEST_P (src_elt->exp)
-             && COST (src_elt->exp) < COST (SET_SRC (x)))
-           {
-             rtx p, set;
-
-             /* Look for an insn in front of LOOP_START that sets
-                something in the desired mode to SET_SRC (x) before we hit
-                a label or CALL_INSN.  */
-
-             for (p = prev_nonnote_insn (loop_start);
-                  p && GET_CODE (p) != CALL_INSN
-                  && GET_CODE (p) != CODE_LABEL;
-                  p = prev_nonnote_insn  (p))
-               if ((set = single_set (p)) != 0
-                   && GET_CODE (SET_DEST (set)) == REG
-                   && GET_MODE (SET_DEST (set)) == src_elt->mode
-                   && rtx_equal_p (SET_SRC (set), SET_SRC (x)))
-                 {
-                   /* We now have to ensure that nothing between P
-                      and LOOP_START modified anything referenced in
-                      SET_SRC (x).  We know that nothing within the loop
-                      can modify it, or we would have invalidated it in
-                      the hash table.  */
-                   rtx q;
-                   rtx cse_check_loop_start_value = SET_SRC (x);
-                   for (q = p; q != loop_start; q = NEXT_INSN (q))
-                     if (INSN_P (q))
-                       note_stores (PATTERN (q),
-                                    cse_check_loop_start,
-                                    &cse_check_loop_start_value);
-
-                   /* If nothing was changed and we can replace our
-                      SET_SRC, add an insn after P to copy its destination
-                      to what we will be replacing SET_SRC with.  */
-                   if (cse_check_loop_start_value
-                       && single_set (p)
-                       && !can_throw_internal (insn)
-                       && validate_change (insn, &SET_SRC (x),
-                                           src_elt->exp, 0))
-                     {
-                       /* If this creates new pseudos, this is unsafe,
-                          because the regno of new pseudo is unsuitable
-                          to index into reg_qty when cse_insn processes
-                          the new insn.  Therefore, if a new pseudo was
-                          created, discard this optimization.  */
-                       int nregs = max_reg_num ();
-                       rtx move
-                         = gen_move_insn (src_elt->exp, SET_DEST (set));
-                       if (nregs != max_reg_num ())
-                         {
-                           if (! validate_change (insn, &SET_SRC (x),
-                                                  SET_SRC (set), 0))
-                             abort ();
-                         }
-                       else
-                         {
-                           if (CONSTANT_P (SET_SRC (set))
-                               && ! find_reg_equal_equiv_note (insn))
-                             set_unique_reg_note (insn, REG_EQUAL,
-                                                  SET_SRC (set));
-                           if (control_flow_insn_p (p))
-                             /* p can cause a control flow transfer so it
-                                is the last insn of a basic block.  We can't
-                                therefore use emit_insn_after.  */
-                             emit_insn_before (move, next_nonnote_insn (p));
-                           else
-                             emit_insn_after (move, p);
-                         }
-                     }
-                   break;
-                 }
-           }
-    }
-
-  /* Deal with the destination of X affecting the stack pointer.  */
-  addr_affects_sp_p (SET_DEST (x));
-
-  /* See comment on similar code in cse_insn for explanation of these
-     tests.  */
-  if (GET_CODE (SET_DEST (x)) == REG || GET_CODE (SET_DEST (x)) == SUBREG
-      || GET_CODE (SET_DEST (x)) == MEM)
-    invalidate (SET_DEST (x), VOIDmode);
-  else if (GET_CODE (SET_DEST (x)) == STRICT_LOW_PART
-          || GET_CODE (SET_DEST (x)) == ZERO_EXTRACT)
-    invalidate (XEXP (SET_DEST (x), 0), GET_MODE (SET_DEST (x)));
-}
-\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.
@@ -6662,7 +6605,7 @@ cse_set_around_loop (rtx x, rtx insn, rtx loop_start)
 
 static void
 cse_end_of_basic_block (rtx insn, struct cse_basic_block_data *data,
-                       int follow_jumps, int after_loop, int skip_blocks)
+                       int follow_jumps, int skip_blocks)
 {
   rtx p = insn, q;
   int nsets = 0;
@@ -6673,14 +6616,15 @@ cse_end_of_basic_block (rtx insn, struct cse_basic_block_data *data,
   int i;
 
   /* Update the previous branch path, if any.  If the last branch was
-     previously TAKEN, mark it NOT_TAKEN.  If it was previously NOT_TAKEN,
+     previously PATH_TAKEN, mark it PATH_NOT_TAKEN.
+     If it was previously PATH_NOT_TAKEN,
      shorten the path by one and look at the previous branch.  We know that
      at least one branch must have been taken if PATH_SIZE is nonzero.  */
   while (path_size > 0)
     {
-      if (data->path[path_size - 1].status != NOT_TAKEN)
+      if (data->path[path_size - 1].status != PATH_NOT_TAKEN)
        {
-         data->path[path_size - 1].status = NOT_TAKEN;
+         data->path[path_size - 1].status = PATH_NOT_TAKEN;
          break;
        }
       else
@@ -6697,29 +6641,12 @@ cse_end_of_basic_block (rtx insn, struct cse_basic_block_data *data,
     follow_jumps = skip_blocks = 0;
 
   /* Scan to end of this basic block.  */
-  while (p && GET_CODE (p) != CODE_LABEL)
+  while (p && !LABEL_P (p))
     {
-      /* Don't cse out the end of a loop.  This makes a difference
-        only for the unusual loops that always execute at least once;
-        all other loops have labels there so we will stop in any case.
-        Cse'ing out the end of the loop is dangerous because it
-        might cause an invariant expression inside the loop
-        to be reused after the end of the loop.  This would make it
-        hard to move the expression out of the loop in loop.c,
-        especially if it is one of several equivalent expressions
-        and loop.c would like to eliminate it.
-
-        If we are running after loop.c has finished, we can ignore
-        the NOTE_INSN_LOOP_END.  */
-
-      if (! after_loop && GET_CODE (p) == NOTE
-         && NOTE_LINE_NUMBER (p) == NOTE_INSN_LOOP_END)
-       break;
-
       /* Don't cse over a call to setjmp; on some machines (eg VAX)
         the regs restored by the longjmp come from
         a later time than the setjmp.  */
-      if (PREV_INSN (p) && GET_CODE (PREV_INSN (p)) == CALL_INSN
+      if (PREV_INSN (p) && CALL_P (PREV_INSN (p))
          && find_reg_note (PREV_INSN (p), REG_SETJMP, NULL))
        break;
 
@@ -6727,7 +6654,7 @@ cse_end_of_basic_block (rtx insn, struct cse_basic_block_data *data,
         especially if it is really an ASM_OPERANDS.  */
       if (INSN_P (p) && GET_CODE (PATTERN (p)) == PARALLEL)
        nsets += XVECLEN (PATTERN (p), 0);
-      else if (GET_CODE (p) != NOTE)
+      else if (!NOTE_P (p))
        nsets += 1;
 
       /* Ignore insns made by CSE; they cannot affect the boundaries of
@@ -6742,7 +6669,7 @@ cse_end_of_basic_block (rtx insn, struct cse_basic_block_data *data,
         take it, do so.  */
       if (path_entry < path_size && data->path[path_entry].branch == p)
        {
-         if (data->path[path_entry].status != NOT_TAKEN)
+         if (data->path[path_entry].status != PATH_NOT_TAKEN)
            p = JUMP_LABEL (p);
 
          /* Point to next entry in path, if any.  */
@@ -6760,7 +6687,7 @@ cse_end_of_basic_block (rtx insn, struct cse_basic_block_data *data,
         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
-              && GET_CODE (p) == JUMP_INSN
+              && JUMP_P (p)
               && GET_CODE (PATTERN (p)) == SET
               && GET_CODE (SET_SRC (PATTERN (p))) == IF_THEN_ELSE
               && JUMP_LABEL (p) != 0
@@ -6768,16 +6695,16 @@ cse_end_of_basic_block (rtx insn, struct cse_basic_block_data *data,
               && NEXT_INSN (JUMP_LABEL (p)) != 0)
        {
          for (q = PREV_INSN (JUMP_LABEL (p)); q; q = PREV_INSN (q))
-           if ((GET_CODE (q) != NOTE
+           if ((!NOTE_P (q)
                 || NOTE_LINE_NUMBER (q) == NOTE_INSN_LOOP_END
-                || (PREV_INSN (q) && GET_CODE (PREV_INSN (q)) == CALL_INSN
+                || (PREV_INSN (q) && CALL_P (PREV_INSN (q))
                     && find_reg_note (PREV_INSN (q), REG_SETJMP, NULL)))
-               && (GET_CODE (q) != CODE_LABEL || LABEL_NUSES (q) != 0))
+               && (!LABEL_P (q) || LABEL_NUSES (q) != 0))
              break;
 
          /* If we ran into a BARRIER, this code is an extension of the
             basic block when the branch is taken.  */
-         if (follow_jumps && q != 0 && GET_CODE (q) == BARRIER)
+         if (follow_jumps && q != 0 && BARRIER_P (q))
            {
              /* Don't allow ourself to keep walking around an
                 always-executed loop.  */
@@ -6796,7 +6723,7 @@ cse_end_of_basic_block (rtx insn, struct cse_basic_block_data *data,
                break;
 
              data->path[path_entry].branch = p;
-             data->path[path_entry++].status = TAKEN;
+             data->path[path_entry++].status = PATH_TAKEN;
 
              /* This branch now ends our path.  It was possible that we
                 didn't see this branch the last time around (when the
@@ -6809,7 +6736,7 @@ cse_end_of_basic_block (rtx insn, struct cse_basic_block_data *data,
              PUT_MODE (NEXT_INSN (p), QImode);
            }
          /* Detect a branch around a block of code.  */
-         else if (skip_blocks && q != 0 && GET_CODE (q) != CODE_LABEL)
+         else if (skip_blocks && q != 0 && !LABEL_P (q))
            {
              rtx tmp;
 
@@ -6829,13 +6756,13 @@ cse_end_of_basic_block (rtx insn, struct cse_basic_block_data *data,
              /* 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 (GET_CODE (tmp) == CODE_LABEL)
+               if (LABEL_P (tmp))
                  break;
 
              if (tmp == q)
                {
                  data->path[path_entry].branch = p;
-                 data->path[path_entry++].status = AROUND;
+                 data->path[path_entry++].status = PATH_AROUND;
 
                  path_size = path_entry;
 
@@ -6856,7 +6783,7 @@ cse_end_of_basic_block (rtx insn, struct cse_basic_block_data *data,
   /* If all jumps in the path are not taken, set our path length to zero
      so a rescan won't be done.  */
   for (i = path_size - 1; i >= 0; i--)
-    if (data->path[i].status != NOT_TAKEN)
+    if (data->path[i].status != PATH_NOT_TAKEN)
       break;
 
   if (i == -1)
@@ -6872,53 +6799,36 @@ cse_end_of_basic_block (rtx insn, struct cse_basic_block_data *data,
    F is the first instruction.
    NREGS is one plus the highest pseudo-reg number used in the instruction.
 
-   AFTER_LOOP is 1 if this is the cse call done after loop optimization
-   (only if -frerun-cse-after-loop).
-
    Returns 1 if jump_optimize should be redone due to simplifications
    in conditional jump instructions.  */
 
 int
-cse_main (rtx f, int nregs, int after_loop, FILE *file)
+cse_main (rtx f, int nregs)
 {
   struct cse_basic_block_data val;
   rtx insn = f;
   int i;
 
-  val.path = xmalloc (sizeof (struct branch_path)
-                     * PARAM_VALUE (PARAM_MAX_CSE_PATH_LENGTH));
+  init_cse_reg_info (nregs);
+
+  val.path = XNEWVEC (struct branch_path, PARAM_VALUE (PARAM_MAX_CSE_PATH_LENGTH));
 
   cse_jumps_altered = 0;
   recorded_label_ref = 0;
   constant_pool_entries_cost = 0;
   constant_pool_entries_regcost = 0;
   val.path_size = 0;
-  gen_lowpart = gen_lowpart_if_possible;
+  rtl_hooks = cse_rtl_hooks;
 
   init_recog ();
   init_alias_analysis ();
 
-  max_reg = nregs;
-
-  max_insn_uid = get_max_uid ();
-
-  reg_eqv_table = xmalloc (nregs * sizeof (struct reg_eqv_elem));
-
-#ifdef LOAD_EXTEND_OP
-
-  /* Allocate scratch rtl here.  cse_insn will fill in the memory reference
-     and change the code and mode as appropriate.  */
-  memory_extend_rtx = gen_rtx_ZERO_EXTEND (VOIDmode, NULL_RTX);
-#endif
-
-  /* Reset the counter indicating how many elements have been made
-     thus far.  */
-  n_elements_made = 0;
+  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,
@@ -6928,7 +6838,7 @@ cse_main (rtx f, int nregs, int after_loop, FILE *file)
 
   for (insn = f, i = 0; insn; insn = NEXT_INSN (insn))
     {
-      if (GET_CODE (insn) != NOTE
+      if (!NOTE_P (insn)
          || NOTE_LINE_NUMBER (insn) < 0)
        INSN_CUID (insn) = ++i;
       else
@@ -6936,8 +6846,6 @@ cse_main (rtx f, int nregs, int after_loop, FILE *file)
        INSN_CUID (insn) = i;
     }
 
-  ggc_push_context ();
-
   /* Loop over basic blocks.
      Compute the maximum number of qty's needed for each basic block
      (which is 2 for each SET).  */
@@ -6945,7 +6853,7 @@ cse_main (rtx f, int nregs, int after_loop, FILE *file)
   while (insn)
     {
       cse_altered = 0;
-      cse_end_of_basic_block (insn, &val, flag_cse_follow_jumps, after_loop,
+      cse_end_of_basic_block (insn, &val, flag_cse_follow_jumps,
                              flag_cse_skip_blocks);
 
       /* If this basic block was already processed or has no sets, skip it.  */
@@ -6961,8 +6869,8 @@ cse_main (rtx f, int nregs, int after_loop, FILE *file)
       cse_basic_block_end = val.high_cuid;
       max_qty = val.nsets * 2;
 
-      if (file)
-       fnotice (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);
 
@@ -6971,13 +6879,11 @@ cse_main (rtx f, int nregs, int after_loop, FILE *file)
       if (max_qty < 500)
        max_qty = 500;
 
-      max_qty += max_reg;
-
       /* If this basic block is being extended by following certain jumps,
          (see `cse_end_of_basic_block'), we reprocess the code from the start.
          Otherwise, we start after this basic block.  */
       if (val.path_size > 0)
-       cse_basic_block (insn, val.last, val.path, 0);
+       cse_basic_block (insn, val.last, val.path);
       else
        {
          int old_cse_jumps_altered = cse_jumps_altered;
@@ -6987,7 +6893,7 @@ cse_main (rtx f, int nregs, int after_loop, FILE *file)
             jump, we want to reprocess the block, since it will give
             us a new branch path to investigate.  */
          cse_jumps_altered = 0;
-         temp = cse_basic_block (insn, val.last, val.path, ! after_loop);
+         temp = cse_basic_block (insn, val.last, val.path);
          if (cse_jumps_altered == 0
              || (flag_cse_follow_jumps == 0 && flag_cse_skip_blocks == 0))
            insn = temp;
@@ -7003,32 +6909,22 @@ cse_main (rtx f, int nregs, int after_loop, FILE *file)
 #endif
     }
 
-  ggc_pop_context ();
-
-  if (max_elements_made < n_elements_made)
-    max_elements_made = n_elements_made;
-
   /* Clean up.  */
   end_alias_analysis ();
   free (uid_cuid);
   free (reg_eqv_table);
   free (val.path);
-  gen_lowpart = gen_lowpart_general;
+  rtl_hooks = general_rtl_hooks;
 
   return cse_jumps_altered || recorded_label_ref;
 }
 
 /* Process a single basic block.  FROM and TO and the limits of the basic
    block.  NEXT_BRANCH points to the branch path when following jumps or
-   a null path when not following jumps.
-
-   AROUND_LOOP is nonzero if we are to try to cse around to the start of a
-   loop.  This is true when we are being called for the last time on a
-   block and this CSE pass is before loop.c.  */
+   a null path when not following jumps.  */
 
 static rtx
-cse_basic_block (rtx from, rtx to, struct branch_path *next_branch,
-                int around_loop)
+cse_basic_block (rtx from, rtx to, struct branch_path *next_branch)
 {
   rtx insn;
   int to_usage = 0;
@@ -7036,16 +6932,13 @@ cse_basic_block (rtx from, rtx to, struct branch_path *next_branch,
   int num_insns = 0;
   int no_conflict = 0;
 
-  /* This array is undefined before max_reg, so only allocate
-     the space actually needed and adjust the start.  */
-
-  qty_table = xmalloc ((max_qty - max_reg) * sizeof (struct qty_table_elem));
-  qty_table -= max_reg;
+  /* Allocate the space needed by qty_table.  */
+  qty_table = XNEWVEC (struct qty_table_elem, max_qty);
 
   new_basic_block ();
 
   /* TO might be a label.  If so, protect it from being deleted.  */
-  if (to != 0 && GET_CODE (to) == CODE_LABEL)
+  if (to != 0 && LABEL_P (to))
     ++LABEL_NUSES (to);
 
   for (insn = from; insn != to; insn = NEXT_INSN (insn))
@@ -7061,7 +6954,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;
@@ -7072,9 +6965,9 @@ cse_basic_block (rtx from, rtx to, struct branch_path *next_branch,
       if (next_branch->branch == insn)
        {
          enum taken status = next_branch++->status;
-         if (status != NOT_TAKEN)
+         if (status != PATH_NOT_TAKEN)
            {
-             if (status == TAKEN)
+             if (status == PATH_TAKEN)
                record_jump_equiv (insn, 1);
              else
                invalidate_skipped_block (NEXT_INSN (insn));
@@ -7136,7 +7029,7 @@ cse_basic_block (rtx from, rtx to, struct branch_path *next_branch,
            
          /* If we haven't already found an insn where we added a LABEL_REF,
             check this one.  */
-         if (GET_CODE (insn) == INSN && ! recorded_label_ref
+         if (NONJUMP_INSN_P (insn) && ! recorded_label_ref
              && for_each_rtx (&PATTERN (insn), check_for_label_ref,
                               (void *) insn))
            recorded_label_ref = 1;
@@ -7151,7 +7044,7 @@ cse_basic_block (rtx from, rtx to, struct branch_path *next_branch,
        {
          if (to == 0)
            {
-             free (qty_table + max_reg);
+             free (qty_table);
              return 0;
            }
 
@@ -7176,7 +7069,7 @@ cse_basic_block (rtx from, rtx to, struct branch_path *next_branch,
         want to count the use in that jump.  */
 
       if (to != 0 && NEXT_INSN (insn) == to
-         && GET_CODE (to) == CODE_LABEL && --LABEL_NUSES (to) == to_usage)
+         && LABEL_P (to) && --LABEL_NUSES (to) == to_usage)
        {
          struct cse_basic_block_data val;
          rtx prev;
@@ -7186,16 +7079,16 @@ cse_basic_block (rtx from, rtx to, struct branch_path *next_branch,
          /* If TO was the last insn in the function, we are done.  */
          if (insn == 0)
            {
-             free (qty_table + max_reg);
+             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 && GET_CODE (prev) == BARRIER)
+         if (prev && BARRIER_P (prev))
            {
-             free (qty_table + max_reg);
+             free (qty_table);
              return insn;
            }
 
@@ -7203,9 +7096,8 @@ cse_basic_block (rtx from, rtx to, struct branch_path *next_branch,
             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, 0);
+         val.path = XNEWVEC (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
@@ -7220,7 +7112,7 @@ cse_basic_block (rtx from, rtx to, struct branch_path *next_branch,
          to = val.last;
 
          /* Prevent TO from being deleted if it is a label.  */
-         if (to != 0 && GET_CODE (to) == CODE_LABEL)
+         if (to != 0 && LABEL_P (to))
            ++LABEL_NUSES (to);
 
          /* Back up so we process the first insn in the extension.  */
@@ -7228,25 +7120,9 @@ cse_basic_block (rtx from, rtx to, struct branch_path *next_branch,
        }
     }
 
-  if (next_qty > max_qty)
-    abort ();
-
-  /* If we are running before loop.c, we stopped on a NOTE_INSN_LOOP_END, and
-     the previous insn is the only insn that branches to the head of a loop,
-     we can cse into the loop.  Don't do this if we changed the jump
-     structure of a loop unless we aren't going to be following jumps.  */
+  gcc_assert (next_qty <= max_qty);
 
-  insn = prev_nonnote_insn (to);
-  if ((cse_jumps_altered == 0
-       || (flag_cse_follow_jumps == 0 && flag_cse_skip_blocks == 0))
-      && around_loop && to != 0
-      && GET_CODE (to) == NOTE && NOTE_LINE_NUMBER (to) == NOTE_INSN_LOOP_END
-      && GET_CODE (insn) == JUMP_INSN
-      && JUMP_LABEL (insn) != 0
-      && LABEL_NUSES (JUMP_LABEL (insn)) == 1)
-    cse_around_loop (JUMP_LABEL (insn));
-
-  free (qty_table + max_reg);
+  free (qty_table);
 
   return to ? NEXT_INSN (to) : 0;
 }
@@ -7272,10 +7148,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;
@@ -7288,7 +7170,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:
@@ -7304,24 +7187,29 @@ count_reg_usage (rtx x, int *counts, int incr)
     case CLOBBER:
       /* If we are clobbering a MEM, mark any registers inside the address
          as being used.  */
-      if (GET_CODE (XEXP (x, 0)) == MEM)
-       count_reg_usage (XEXP (XEXP (x, 0), 0), counts, incr);
+      if (MEM_P (XEXP (x, 0)))
+       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 (GET_CODE (SET_DEST (x)) != REG)
-       count_reg_usage (SET_DEST (x), counts, incr);
-      count_reg_usage (SET_SRC (x), counts, incr);
+      if (!REG_P (SET_DEST (x)))
+       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.  */
@@ -7336,12 +7224,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;
 
@@ -7351,19 +7239,23 @@ 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:
-      abort ();
+      gcc_unreachable ();
 
     default:
       break;
@@ -7373,10 +7265,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
@@ -7400,15 +7292,10 @@ set_live_p (rtx set, rtx insn ATTRIBUTE_UNUSED, /* Only used with HAVE_cc0.  */
               || !reg_referenced_p (cc0_rtx, PATTERN (tem))))
     return false;
 #endif
-  else if (GET_CODE (SET_DEST (set)) != REG
+  else if (!REG_P (SET_DEST (set))
           || REGNO (SET_DEST (set)) < FIRST_PSEUDO_REGISTER
           || counts[REGNO (SET_DEST (set))] != 0
-          || side_effects_p (SET_SRC (set))
-          /* An ADDRESSOF expression can turn into a use of the
-             internal arg pointer, so always consider the
-             internal arg pointer live.  If it is truly dead,
-             flow will delete the initializing insn.  */
-          || (SET_DEST (set) == current_function_internal_arg_pointer))
+          || side_effects_p (SET_SRC (set)))
     return true;
   return false;
 }
@@ -7468,11 +7355,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;
@@ -7483,14 +7370,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;
 }
 
@@ -7508,73 +7395,66 @@ delete_trivially_dead_insns (rtx insns, int nreg)
   int *counts;
   rtx insn, prev;
   int in_libcall = 0, dead_libcall = 0;
-  int ndead = 0, nlastdead, niterations = 0;
+  int ndead = 0;
 
   timevar_push (TV_DELETE_TRIVIALLY_DEAD);
   /* First count the number of times each register is used.  */
-  counts = xcalloc (nreg, sizeof (int));
-  for (insn = next_real_insn (insns); insn; insn = next_real_insn (insn))
-    count_reg_usage (insn, counts, 1);
-
-  do
+  counts = XCNEWVEC (int, nreg);
+  for (insn = insns; insn; insn = NEXT_INSN (insn))
+    if (INSN_P (insn))
+      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
+     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.  */
+  for (insn = get_last_insn (); insn; insn = prev)
     {
-      nlastdead = ndead;
-      niterations++;
-      /* 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.  */
-      insn = get_last_insn ();
-      if (! INSN_P (insn))
-       insn = prev_real_insn (insn);
+      int live_insn = 0;
 
-      for (; insn; insn = prev)
-       {
-         int live_insn = 0;
-
-         prev = prev_real_insn (insn);
+      prev = PREV_INSN (insn);
+      if (!INSN_P (insn))
+       continue;
 
-         /* Don't delete any insns that are part of a libcall block unless
-            we can delete the whole libcall block.
+      /* Don't delete any insns that are part of a libcall block unless
+        we can delete the whole libcall block.
 
-            Flow or loop might get confused if we did that.  Remember
-            that we are scanning backwards.  */
-         if (find_reg_note (insn, REG_RETVAL, NULL_RTX))
-           {
-             in_libcall = 1;
-             live_insn = 1;
-             dead_libcall = dead_libcall_p (insn, counts);
-           }
-         else if (in_libcall)
-           live_insn = ! dead_libcall;
-         else
-           live_insn = insn_live_p (insn, counts);
+        Flow or loop might get confused if we did that.  Remember
+        that we are scanning backwards.  */
+      if (find_reg_note (insn, REG_RETVAL, NULL_RTX))
+       {
+         in_libcall = 1;
+         live_insn = 1;
+         dead_libcall = dead_libcall_p (insn, counts);
+       }
+      else if (in_libcall)
+       live_insn = ! dead_libcall;
+      else
+       live_insn = insn_live_p (insn, counts);
 
-         /* If this is a dead insn, delete it and show registers in it aren't
-            being used.  */
+      /* If this is a dead insn, delete it and show registers in it aren't
+        being used.  */
 
-         if (! live_insn)
-           {
-             count_reg_usage (insn, counts, -1);
-             delete_insn_and_edges (insn);
-             ndead++;
-           }
+      if (! live_insn)
+       {
+         count_reg_usage (insn, counts, NULL_RTX, -1);
+         delete_insn_and_edges (insn);
+         ndead++;
+       }
 
-         if (find_reg_note (insn, REG_LIBCALL, NULL_RTX))
-           {
-             in_libcall = 0;
-             dead_libcall = 0;
-           }
+      if (in_libcall && find_reg_note (insn, REG_LIBCALL, NULL_RTX))
+       {
+         in_libcall = 0;
+         dead_libcall = 0;
        }
     }
-  while (ndead != nlastdead);
 
   if (dump_file && ndead)
-    fprintf (dump_file, "Deleted %i trivially dead insns; %i iterations\n",
-            ndead, niterations);
+    fprintf (dump_file, "Deleted %i trivially dead insns\n",
+            ndead);
   /* Clean up.  */
   free (counts);
   timevar_pop (TV_DELETE_TRIVIALLY_DEAD);
@@ -7589,20 +7469,47 @@ delete_trivially_dead_insns (rtx insns, int nreg)
 static int
 cse_change_cc_mode (rtx *loc, void *data)
 {
-  rtx newreg = (rtx) data;
+  struct change_cc_mode_args* args = (struct change_cc_mode_args*)data;
 
   if (*loc
-      && GET_CODE (*loc) == REG
-      && REGNO (*loc) == REGNO (newreg)
-      && GET_MODE (*loc) != GET_MODE (newreg))
+      && REG_P (*loc)
+      && REGNO (*loc) == REGNO (args->newreg)
+      && GET_MODE (*loc) != GET_MODE (args->newreg))
     {
-      *loc = newreg;
+      validate_change (args->insn, loc, args->newreg, 1);
+      
       return -1;
     }
   return 0;
 }
 
 /* Change the mode of any reference to the register REGNO (NEWREG) to
+   GET_MODE (NEWREG) in INSN.  */
+
+static void
+cse_change_cc_mode_insn (rtx insn, rtx newreg)
+{
+  struct change_cc_mode_args args;
+  int success;
+
+  if (!INSN_P (insn))
+    return;
+
+  args.insn = insn;
+  args.newreg = newreg;
+  
+  for_each_rtx (&PATTERN (insn), cse_change_cc_mode, &args);
+  for_each_rtx (&REG_NOTES (insn), cse_change_cc_mode, &args);
+  
+  /* 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
+     replaced by any of the compatible modes - can still be recognized.  */
+  success = apply_change_group ();
+  gcc_assert (success);
+}
+
+/* Change the mode of any reference to the register REGNO (NEWREG) to
    GET_MODE (NEWREG), starting at START.  Stop before END.  Stop at
    any instruction which modifies NEWREG.  */
 
@@ -7619,8 +7526,7 @@ cse_change_cc_mode_insns (rtx start, rtx end, rtx newreg)
       if (reg_set_p (newreg, insn))
        return;
 
-      for_each_rtx (&PATTERN (insn), cse_change_cc_mode, newreg);
-      for_each_rtx (&REG_NOTES (insn), cse_change_cc_mode, newreg);
+      cse_change_cc_mode_insn (insn, newreg);
     }
 }
 
@@ -7649,6 +7555,7 @@ cse_cc_succs (basic_block bb, rtx cc_reg, rtx cc_src, bool can_change_mode)
   rtx last_insns[2];
   unsigned int i;
   rtx newreg;
+  edge_iterator ei;
 
   /* We expect to have two successors.  Look at both before picking
      the final mode for the comparison.  If we have more successors
@@ -7659,7 +7566,7 @@ cse_cc_succs (basic_block bb, rtx cc_reg, rtx cc_src, bool can_change_mode)
   found_equiv = false;
   mode = GET_MODE (cc_src);
   insn_count = 0;
-  for (e = bb->succ; e; e = e->succ_next)
+  FOR_EACH_EDGE (e, ei, bb->succs)
     {
       rtx insn;
       rtx end;
@@ -7667,8 +7574,7 @@ cse_cc_succs (basic_block bb, rtx cc_reg, rtx cc_src, bool can_change_mode)
       if (e->flags & EDGE_COMPLEX)
        continue;
 
-      if (! e->dest->pred
-         || e->dest->pred->pred_next
+      if (EDGE_COUNT (e->dest->preds) != 1
          || e->dest == EXIT_BLOCK_PTR)
        continue;
 
@@ -7688,7 +7594,7 @@ cse_cc_succs (basic_block bb, rtx cc_reg, rtx cc_src, bool can_change_mode)
          /* Check whether INSN sets CC_REG to CC_SRC.  */
          set = single_set (insn);
          if (set
-             && GET_CODE (SET_DEST (set)) == REG
+             && REG_P (SET_DEST (set))
              && REGNO (SET_DEST (set)) == REGNO (cc_reg))
            {
              bool found;
@@ -7727,9 +7633,10 @@ cse_cc_succs (basic_block bb, rtx cc_reg, rtx cc_src, bool can_change_mode)
 
                      if (mode != comp_mode)
                        {
-                         if (! can_change_mode)
-                           abort ();
+                         gcc_assert (can_change_mode);
                          mode = comp_mode;
+
+                         /* The modified insn will be re-recognized later.  */
                          PUT_MODE (cc_src, mode);
                        }
                    }
@@ -7776,8 +7683,7 @@ cse_cc_succs (basic_block bb, rtx cc_reg, rtx cc_src, bool can_change_mode)
          submode = cse_cc_succs (e->dest, cc_reg, cc_src, false);
          if (submode != VOIDmode)
            {
-             if (submode != mode)
-               abort ();
+             gcc_assert (submode == mode);
              found_equiv = true;
              can_change_mode = false;
            }
@@ -7818,7 +7724,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;
@@ -7856,7 +7762,7 @@ cse_condition_code_reg (void)
         to optimize.  */
 
       last_insn = BB_END (bb);
-      if (GET_CODE (last_insn) != JUMP_INSN)
+      if (!JUMP_P (last_insn))
        continue;
 
       if (reg_referenced_p (cc_reg_1, PATTERN (last_insn)))
@@ -7878,7 +7784,7 @@ cse_condition_code_reg (void)
            continue;
          set = single_set (insn);
          if (set
-             && GET_CODE (SET_DEST (set)) == REG
+             && REG_P (SET_DEST (set))
              && REGNO (SET_DEST (set)) == REGNO (cc_reg))
            {
              cc_src_insn = insn;
@@ -7905,18 +7811,12 @@ cse_condition_code_reg (void)
       mode = cse_cc_succs (bb, cc_reg, cc_src, true);
       if (mode != VOIDmode)
        {
-         if (mode != GET_MODE (cc_src))
-           abort ();
+         gcc_assert (mode == GET_MODE (cc_src));
          if (mode != orig_mode)
            {
              rtx newreg = gen_rtx_REG (mode, REGNO (cc_reg));
 
-             /* Change the mode of CC_REG in CC_SRC_INSN to
-                GET_MODE (NEWREG).  */
-             for_each_rtx (&PATTERN (cc_src_insn), cse_change_cc_mode,
-                           newreg);
-             for_each_rtx (&REG_NOTES (cc_src_insn), cse_change_cc_mode,
-                           newreg);
+             cse_change_cc_mode_insn (cc_src_insn, newreg);
 
              /* Do the same in the following insns that use the
                 current value of CC_REG within BB.  */
@@ -7927,3 +7827,119 @@ cse_condition_code_reg (void)
        }
     }
 }
+\f
+
+/* Perform common subexpression elimination.  Nonzero value from
+   `cse_main' means that jumps were simplified and some code may now
+   be unreachable, so do jump optimization again.  */
+static bool
+gate_handle_cse (void)
+{
+  return optimize > 0;
+}
+
+static void
+rest_of_handle_cse (void)
+{
+  int tem;
+
+  if (dump_file)
+    dump_flow_info (dump_file, dump_flags);
+
+  reg_scan (get_insns (), max_reg_num ());
+
+  tem = cse_main (get_insns (), max_reg_num ());
+  if (tem)
+    rebuild_jump_labels (get_insns ());
+  if (purge_all_dead_edges ())
+    delete_unreachable_blocks ();
+
+  delete_trivially_dead_insns (get_insns (), max_reg_num ());
+
+  /* If we are not running more CSE passes, then we are no longer
+     expecting CSE to be run.  But always rerun it in a cheap mode.  */
+  cse_not_expected = !flag_rerun_cse_after_loop && !flag_gcse;
+
+  if (tem)
+    delete_dead_jumptables ();
+
+  if (tem || optimize > 1)
+    cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_PRE_LOOP);
+}
+
+struct tree_opt_pass pass_cse =
+{
+  "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_dump_func |
+  TODO_ggc_collect,                     /* todo_flags_finish */
+  's'                                   /* letter */
+};
+
+
+static bool
+gate_handle_cse2 (void)
+{
+  return optimize > 0 && flag_rerun_cse_after_loop;
+}
+
+/* Run second CSE pass after loop optimizations.  */
+static void
+rest_of_handle_cse2 (void)
+{
+  int tem;
+
+  if (dump_file)
+    dump_flow_info (dump_file, dump_flags);
+
+  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
+     makes it harder for that pass to determine whether a jump can be
+     bypassed safely.  */
+  cse_condition_code_reg ();
+
+  purge_all_dead_edges ();
+  delete_trivially_dead_insns (get_insns (), max_reg_num ());
+
+  if (tem)
+    {
+      timevar_push (TV_JUMP);
+      rebuild_jump_labels (get_insns ());
+      delete_dead_jumptables ();
+      cleanup_cfg (CLEANUP_EXPENSIVE);
+      timevar_pop (TV_JUMP);
+    }
+  reg_scan (get_insns (), max_reg_num ());
+  cse_not_expected = 1;
+}
+
+
+struct tree_opt_pass pass_cse2 =
+{
+  "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_dump_func |
+  TODO_ggc_collect,                     /* todo_flags_finish */
+  't'                                   /* letter */
+};
+