OSDN Git Service

* config.gcc (m68020-*-elf*, m68k-*-elf*, m68010-*-netbsdelf*,
[pf3gnuchains/gcc-fork.git] / gcc / cse.c
index 2b48751..faaf187 100644 (file)
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -1,28 +1,29 @@
 /* Common subexpression elimination for GNU compiler.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998
-   1999, 2000, 2001 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
 
-This file is part of GNU CC.
+This file is part of GCC.
 
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
 
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
 
 You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+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.  */
 
 #include "config.h"
 /* stdio.h must precede rtl.h for FFS.  */
 #include "system.h"
-#include <setjmp.h>
+#include "coretypes.h"
+#include "tm.h"
 
 #include "rtl.h"
 #include "tm_p.h"
@@ -38,6 +39,10 @@ Boston, MA 02111-1307, USA.  */
 #include "toplev.h"
 #include "output.h"
 #include "ggc.h"
+#include "timevar.h"
+#include "except.h"
+#include "target.h"
+#include "params.h"
 
 /* The basic idea of common subexpression elimination is to go
    through the code, keeping a record of expressions that would
@@ -247,8 +252,10 @@ struct qty_table_elem
   rtx comparison_const;
   int comparison_qty;
   unsigned int first_reg, last_reg;
-  enum machine_mode mode;
-  enum rtx_code comparison_code;
+  /* The sizes of these fields should match the sizes of the
+     code and mode fields of struct rtx_def (see rtl.h).  */
+  ENUM_BITFIELD(rtx_code) comparison_code : 16;
+  ENUM_BITFIELD(machine_mode) mode : 8;
 };
 
 /* The table of all qtys, indexed by qty number.  */
@@ -266,11 +273,11 @@ static struct qty_table_elem *qty_table;
 
 static rtx prev_insn_cc0;
 static enum machine_mode prev_insn_cc0_mode;
-#endif
 
 /* Previous actual insn.  0 if at first insn of basic block.  */
 
 static rtx prev_insn;
+#endif
 
 /* Insn being scanned.  */
 
@@ -316,6 +323,10 @@ struct cse_reg_info
      reg_tick value, such expressions existing in the hash table are
      invalid.  */
   int reg_in_table;
+
+  /* The SUBREG that was set when REG_TICK was last incremented.  Set
+     to -1 if the last store was to the whole register, not a subreg.  */
+  unsigned int subreg_ticked;
 };
 
 /* A free list of cse_reg_info entries.  */
@@ -346,11 +357,6 @@ static struct cse_reg_info *cached_cse_reg_info;
 
 static HARD_REG_SET hard_regs_in_table;
 
-/* A HARD_REG_SET containing all the hard registers that are invalidated
-   by a CALL_INSN.  */
-
-static HARD_REG_SET regs_invalidated_by_call;
-
 /* CUID of insn that starts the basic block currently being cse-processed.  */
 
 static int cse_basic_block_start;
@@ -386,10 +392,6 @@ static int cse_jumps_altered;
    REG_LABEL, we have to rerun jump after CSE to put in the note.  */
 static int recorded_label_ref;
 
-/* Says which LABEL_REF was put in the hash table.  Used to see if we need
-   to set the above flag.  */
-static rtx new_label_ref;
-
 /* canon_hash stores 1 in do_not_record
    if it notices a reference to CC0, PC, or some other volatile
    subexpression.  */
@@ -463,7 +465,9 @@ struct table_elt
   struct table_elt *related_value;
   int cost;
   int regcost;
-  enum machine_mode mode;
+  /* The size of this field should match the size
+     of the mode field of struct rtx_def (see rtl.h).  */
+  ENUM_BITFIELD(machine_mode) mode : 8;
   char in_memory;
   char is_const;
   char flag;
@@ -499,9 +503,9 @@ struct table_elt
    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) == 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                                     \
        && FIXED_REGNO_P (N) && REGNO_REG_CLASS (N) != NO_REGS))
 
@@ -510,7 +514,7 @@ struct table_elt
 
 /* Get the info associated with register N.  */
 
-#define GET_CSE_REG_INFO(N)                    \
+#define GET_CSE_REG_INFO(N)                    \
   (((N) == cached_regno && cached_cse_reg_info)        \
    ? cached_cse_reg_info : get_cse_reg_info ((N)))
 
@@ -523,6 +527,11 @@ struct table_elt
 
 #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)
+
 /* Get the quantity number for REG.  */
 
 #define REG_QTY(N) ((GET_CSE_REG_INFO (N))->reg_qty)
@@ -560,10 +569,7 @@ static struct table_elt *last_jump_equiv_class;
    the insn.  */
 
 static int constant_pool_entries_cost;
-
-/* Define maximum length of a branch path.  */
-
-#define PATHLENGTH     10
+static int constant_pool_entries_regcost;
 
 /* This data describes a block that will be processed by cse_basic_block.  */
 
@@ -588,121 +594,107 @@ struct cse_basic_block_data
         except that it is used when the destination label is not preceded
        by a BARRIER.  */
       enum taken {TAKEN, NOT_TAKEN, AROUND} status;
-    } path[PATHLENGTH];
+    } *path;
 };
 
+static bool fixed_base_plus_p (rtx x);
+static int notreg_cost (rtx, enum rtx_code);
+static int approx_reg_cost_1 (rtx *, void *);
+static int approx_reg_cost (rtx);
+static int preferrable (int, int, int, int);
+static void new_basic_block (void);
+static void make_new_qty (unsigned int, enum machine_mode);
+static void make_regs_eqv (unsigned int, unsigned int);
+static void delete_reg_equiv (unsigned int);
+static int mention_regs (rtx);
+static int insert_regs (rtx, struct table_elt *, int);
+static void remove_from_table (struct table_elt *, unsigned);
+static struct table_elt *lookup        (rtx, unsigned, enum machine_mode);
+static struct table_elt *lookup_for_remove (rtx, unsigned, enum machine_mode);
+static rtx lookup_as_function (rtx, enum rtx_code);
+static struct table_elt *insert (rtx, struct table_elt *, unsigned,
+                                enum machine_mode);
+static void merge_equiv_classes (struct table_elt *, struct table_elt *);
+static void invalidate (rtx, enum machine_mode);
+static int cse_rtx_varies_p (rtx, int);
+static void remove_invalid_refs (unsigned int);
+static void remove_invalid_subreg_refs (unsigned int, unsigned int,
+                                       enum machine_mode);
+static void rehash_using_reg (rtx);
+static void invalidate_memory (void);
+static void invalidate_for_call (void);
+static rtx use_related_value (rtx, struct table_elt *);
+static 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 rtx canon_reg (rtx, rtx);
+static void find_best_addr (rtx, rtx *, enum machine_mode);
+static enum rtx_code find_comparison_args (enum rtx_code, rtx *, rtx *,
+                                          enum machine_mode *,
+                                          enum machine_mode *);
+static rtx fold_rtx (rtx, rtx);
+static rtx equiv_constant (rtx);
+static void record_jump_equiv (rtx, int);
+static void record_jump_cond (enum rtx_code, enum machine_mode, rtx, rtx,
+                             int);
+static void cse_insn (rtx, rtx);
+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 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 int check_dependence (rtx *, void *);
+
+static void flush_hash_table (void);
+static bool insn_live_p (rtx, int *);
+static bool set_live_p (rtx, rtx, int *);
+static bool dead_libcall_p (rtx, int *);
+\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.
-
-   ?!? FIXED_BASE_PLUS_P and NONZERO_BASE_PLUS_P need to move into
-   a header file so that their definitions can be shared with the
-   simplification routines in simplify-rtx.c.  Until then, do not
-   change these macros without also changing the copy in simplify-rtx.c.  */
-
-#define FIXED_BASE_PLUS_P(X)                                   \
-  ((X) == frame_pointer_rtx || (X) == hard_frame_pointer_rtx   \
-   || ((X) == arg_pointer_rtx && fixed_regs[ARG_POINTER_REGNUM])\
-   || (X) == virtual_stack_vars_rtx                            \
-   || (X) == virtual_incoming_args_rtx                         \
-   || (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == CONST_INT \
-       && (XEXP (X, 0) == frame_pointer_rtx                    \
-          || XEXP (X, 0) == hard_frame_pointer_rtx             \
-          || ((X) == arg_pointer_rtx                           \
-              && fixed_regs[ARG_POINTER_REGNUM])               \
-          || XEXP (X, 0) == virtual_stack_vars_rtx             \
-          || XEXP (X, 0) == virtual_incoming_args_rtx))        \
-   || GET_CODE (X) == ADDRESSOF)
-
-/* Similar, but also allows reference to the stack pointer.
-
-   This used to include FIXED_BASE_PLUS_P, however, we can't assume that
-   arg_pointer_rtx by itself is nonzero, because on at least one machine,
-   the i960, the arg pointer is zero when it is unused.  */
-
-#define NONZERO_BASE_PLUS_P(X)                                 \
-  ((X) == frame_pointer_rtx || (X) == hard_frame_pointer_rtx   \
-   || (X) == virtual_stack_vars_rtx                            \
-   || (X) == virtual_incoming_args_rtx                         \
-   || (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == CONST_INT \
-       && (XEXP (X, 0) == frame_pointer_rtx                    \
-          || XEXP (X, 0) == hard_frame_pointer_rtx             \
-          || ((X) == arg_pointer_rtx                           \
-              && fixed_regs[ARG_POINTER_REGNUM])               \
-          || XEXP (X, 0) == virtual_stack_vars_rtx             \
-          || XEXP (X, 0) == virtual_incoming_args_rtx))        \
-   || (X) == stack_pointer_rtx                                 \
-   || (X) == virtual_stack_dynamic_rtx                         \
-   || (X) == virtual_outgoing_args_rtx                         \
-   || (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == CONST_INT \
-       && (XEXP (X, 0) == stack_pointer_rtx                    \
-          || XEXP (X, 0) == virtual_stack_dynamic_rtx          \
-          || XEXP (X, 0) == virtual_outgoing_args_rtx))        \
-   || GET_CODE (X) == ADDRESSOF)
-
-static int notreg_cost         PARAMS ((rtx, enum rtx_code));
-static int approx_reg_cost_1   PARAMS ((rtx *, void *));
-static int approx_reg_cost     PARAMS ((rtx));
-static int preferrable         PARAMS ((int, int, int, int));
-static void new_basic_block    PARAMS ((void));
-static void make_new_qty       PARAMS ((unsigned int, enum machine_mode));
-static void make_regs_eqv      PARAMS ((unsigned int, unsigned int));
-static void delete_reg_equiv   PARAMS ((unsigned int));
-static int mention_regs                PARAMS ((rtx));
-static int insert_regs         PARAMS ((rtx, struct table_elt *, int));
-static void remove_from_table  PARAMS ((struct table_elt *, unsigned));
-static struct table_elt *lookup        PARAMS ((rtx, unsigned, enum machine_mode)),
-       *lookup_for_remove PARAMS ((rtx, unsigned, enum machine_mode));
-static rtx lookup_as_function  PARAMS ((rtx, enum rtx_code));
-static struct table_elt *insert PARAMS ((rtx, struct table_elt *, unsigned,
-                                        enum machine_mode));
-static void merge_equiv_classes PARAMS ((struct table_elt *,
-                                        struct table_elt *));
-static void invalidate         PARAMS ((rtx, enum machine_mode));
-static int cse_rtx_varies_p    PARAMS ((rtx, int));
-static void remove_invalid_refs        PARAMS ((unsigned int));
-static void remove_invalid_subreg_refs PARAMS ((unsigned int, unsigned int,
-                                                enum machine_mode));
-static void rehash_using_reg   PARAMS ((rtx));
-static void invalidate_memory  PARAMS ((void));
-static void invalidate_for_call        PARAMS ((void));
-static rtx use_related_value   PARAMS ((rtx, struct table_elt *));
-static unsigned canon_hash     PARAMS ((rtx, enum machine_mode));
-static unsigned canon_hash_string PARAMS ((const char *));
-static unsigned safe_hash      PARAMS ((rtx, enum machine_mode));
-static int exp_equiv_p         PARAMS ((rtx, rtx, int, int));
-static rtx canon_reg           PARAMS ((rtx, rtx));
-static void find_best_addr     PARAMS ((rtx, rtx *, enum machine_mode));
-static enum rtx_code find_comparison_args PARAMS ((enum rtx_code, rtx *, rtx *,
-                                                  enum machine_mode *,
-                                                  enum machine_mode *));
-static rtx fold_rtx            PARAMS ((rtx, rtx));
-static rtx equiv_constant      PARAMS ((rtx));
-static void record_jump_equiv  PARAMS ((rtx, int));
-static void record_jump_cond   PARAMS ((enum rtx_code, enum machine_mode,
-                                        rtx, rtx, int));
-static void cse_insn           PARAMS ((rtx, rtx));
-static int addr_affects_sp_p   PARAMS ((rtx));
-static void invalidate_from_clobbers PARAMS ((rtx));
-static rtx cse_process_notes   PARAMS ((rtx, rtx));
-static void cse_around_loop    PARAMS ((rtx));
-static void invalidate_skipped_set PARAMS ((rtx, rtx, void *));
-static void invalidate_skipped_block PARAMS ((rtx));
-static void cse_check_loop_start PARAMS ((rtx, rtx, void *));
-static void cse_set_around_loop        PARAMS ((rtx, rtx, rtx));
-static rtx cse_basic_block     PARAMS ((rtx, rtx, struct branch_path *, int));
-static void count_reg_usage    PARAMS ((rtx, int *, rtx, int));
-extern void dump_class          PARAMS ((struct table_elt*));
-static struct cse_reg_info * get_cse_reg_info PARAMS ((unsigned int));
-static int check_dependence    PARAMS ((rtx *, void *));
-
-static void flush_hash_table   PARAMS ((void));
-\f
+   by integrate.c, which is called before virtual register instantiation.  */
+
+static bool
+fixed_base_plus_p (rtx x)
+{
+  switch (GET_CODE (x))
+    {
+    case REG:
+      if (x == frame_pointer_rtx || x == hard_frame_pointer_rtx)
+       return true;
+      if (x == arg_pointer_rtx && fixed_regs[ARG_POINTER_REGNUM])
+       return true;
+      if (REGNO (x) >= FIRST_VIRTUAL_REGISTER
+         && REGNO (x) <= LAST_VIRTUAL_REGISTER)
+       return true;
+      return false;
+
+    case PLUS:
+      if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+       return false;
+      return fixed_base_plus_p (XEXP (x, 0));
+
+    case ADDRESSOF:
+      return true;
+
+    default:
+      return false;
+    }
+}
+
 /* Dump the expressions in the equivalence class indicated by CLASSP.
    This function is used only for debugging.  */
 void
-dump_class (classp)
-     struct table_elt *classp;
+dump_class (struct table_elt *classp)
 {
   struct table_elt *elt;
 
@@ -718,50 +710,47 @@ dump_class (classp)
 }
 
 /* Subroutine of approx_reg_cost; called through for_each_rtx.  */
+
 static int
-approx_reg_cost_1 (xp, data)
-     rtx *xp;
-     void *data;
+approx_reg_cost_1 (rtx *xp, void *data)
 {
   rtx x = *xp;
-  regset set = (regset) data;
+  int *cost_p = data;
 
   if (x && GET_CODE (x) == REG)
-    SET_REGNO_REG_SET (set, REGNO (x));
+    {
+      unsigned int regno = REGNO (x);
+
+      if (! CHEAP_REGNO (regno))
+       {
+         if (regno < FIRST_PSEUDO_REGISTER)
+           {
+             if (SMALL_REGISTER_CLASSES)
+               return 1;
+             *cost_p += 2;
+           }
+         else
+           *cost_p += 1;
+       }
+    }
+
   return 0;
 }
 
 /* Return an estimate of the cost of the registers used in an rtx.
    This is mostly the number of different REG expressions in the rtx;
-   however for some excecptions like fixed registers we use a cost of
+   however for some exceptions like fixed registers we use a cost of
    0.  If any other hard register reference occurs, return MAX_COST.  */
 
 static int
-approx_reg_cost (x)
-     rtx x;
+approx_reg_cost (rtx x)
 {
-  regset_head set;
-  int i;
   int cost = 0;
-  int hardregs = 0;
-
-  INIT_REG_SET (&set);
-  for_each_rtx (&x, approx_reg_cost_1, (void *)&set);
 
-  EXECUTE_IF_SET_IN_REG_SET
-    (&set, 0, i,
-     {
-       if (! CHEAP_REGNO (i))
-        {
-          if (i < FIRST_PSEUDO_REGISTER)
-            hardregs++;
+  if (for_each_rtx (&x, approx_reg_cost_1, (void *) &cost))
+    return MAX_COST;
 
-          cost += i < FIRST_PSEUDO_REGISTER ? 2 : 1;
-        }
-     });
-
-  CLEAR_REG_SET (&set);
-  return hardregs && SMALL_REGISTER_CLASSES ? MAX_COST : cost;
+  return cost;
 }
 
 /* Return a negative value if an rtx A, whose costs are given by COST_A
@@ -769,10 +758,9 @@ approx_reg_cost (x)
    Return a positive value if A is less desirable, or 0 if the two are
    equally good.  */
 static int
-preferrable (cost_a, regcost_a, cost_b, regcost_b)
-     int cost_a, regcost_a, cost_b, regcost_b;
+preferrable (int cost_a, int regcost_a, int cost_b, int regcost_b)
 {
-  /* First, get rid of cases involving expressions that are entirely
+  /* First, get rid of cases involving expressions that are entirely
      unwanted.  */
   if (cost_a != cost_b)
     {
@@ -804,9 +792,7 @@ preferrable (cost_a, regcost_a, cost_b, regcost_b)
    from COST macro to keep it simple.  */
 
 static int
-notreg_cost (x, outer)
-     rtx x;
-     enum rtx_code outer;
+notreg_cost (rtx x, enum rtx_code outer)
 {
   return ((GET_CODE (x) == SUBREG
           && GET_CODE (SUBREG_REG (x)) == REG
@@ -827,32 +813,24 @@ notreg_cost (x, outer)
    Other uses like the latter are expected in the future.  */
 
 int
-rtx_cost (x, outer_code)
-     rtx x;
-     enum rtx_code outer_code ATTRIBUTE_UNUSED;
+rtx_cost (rtx x, enum rtx_code outer_code ATTRIBUTE_UNUSED)
 {
-  register int i, j;
-  register enum rtx_code code;
-  register const char *fmt;
-  register int total;
+  int i, j;
+  enum rtx_code code;
+  const char *fmt;
+  int total;
 
   if (x == 0)
     return 0;
 
   /* Compute the default costs of certain things.
-     Note that RTX_COSTS can override the defaults.  */
+     Note that targetm.rtx_costs can override the defaults.  */
 
   code = GET_CODE (x);
   switch (code)
     {
     case MULT:
-      /* Count multiplication by 2**n as a shift,
-        because if we are considering it, we would output it as a shift.  */
-      if (GET_CODE (XEXP (x, 1)) == CONST_INT
-         && exact_log2 (INTVAL (XEXP (x, 1))) >= 0)
-       total = 2;
-      else
-       total = COSTS_N_INSNS (5);
+      total = COSTS_N_INSNS (5);
       break;
     case DIV:
     case UDIV:
@@ -881,17 +859,9 @@ rtx_cost (x, outer_code)
                              + GET_MODE_SIZE (GET_MODE (x)) / UNITS_PER_WORD);
       break;
 
-#ifdef RTX_COSTS
-      RTX_COSTS (x, code, outer_code);
-#endif
-#ifdef CONST_COSTS
-      CONST_COSTS (x, code, outer_code);
-#endif
-
     default:
-#ifdef DEFAULT_RTX_COSTS
-      DEFAULT_RTX_COSTS (x, code, outer_code);
-#endif
+      if ((*targetm.rtx_costs) (x, code, outer_code, &total))
+       return total;
       break;
     }
 
@@ -910,14 +880,12 @@ rtx_cost (x, outer_code)
 }
 \f
 /* Return cost of address expression X.
-   Expect that X is propertly formed address reference.  */
+   Expect that X is properly formed address reference.  */
 
 int
-address_cost (x, mode)
-     rtx x;
-     enum machine_mode mode;
+address_cost (rtx x, enum machine_mode mode)
 {
-  /* The ADDRESS_COST macro does not deal with ADDRESSOF nodes.  But,
+  /* The address_cost target hook does not deal with ADDRESSOF nodes.  But,
      during CSE, such nodes are present.  Using an ADDRESSOF node which
      refers to the address of a REG is a good thing because we can then
      turn (MEM (ADDRESSSOF (REG))) into just plain REG.  */
@@ -927,21 +895,24 @@ address_cost (x, mode)
 
   /* We may be asked for cost of various unusual addresses, such as operands
      of push instruction.  It is not worthwhile to complicate writing
-     of ADDRESS_COST macro by such cases.  */
+     of the target hook by such cases.  */
 
   if (!memory_address_p (mode, x))
     return 1000;
-#ifdef ADDRESS_COST
-  return ADDRESS_COST (x);
-#else
-  return rtx_cost (x, MEM);
-#endif
+
+  return (*targetm.address_cost) (x);
 }
 
+/* If the target doesn't override, compute the cost as with arithmetic.  */
+
+int
+default_address_cost (rtx x)
+{
+  return rtx_cost (x, MEM);
+}
 \f
 static struct cse_reg_info *
-get_cse_reg_info (regno)
-     unsigned int regno;
+get_cse_reg_info (unsigned int regno)
 {
   struct cse_reg_info **hash_head = &reg_hash[REGHASH_FN (regno)];
   struct cse_reg_info *p;
@@ -959,7 +930,7 @@ get_cse_reg_info (regno)
          cse_reg_info_free_list = p->next;
        }
       else
-       p = (struct cse_reg_info *) xmalloc (sizeof (struct cse_reg_info));
+       p = xmalloc (sizeof (struct cse_reg_info));
 
       /* Insert into hash table.  */
       p->hash_next = *hash_head;
@@ -968,6 +939,7 @@ get_cse_reg_info (regno)
       /* 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;
@@ -988,15 +960,15 @@ get_cse_reg_info (regno)
    for a new basic block.  */
 
 static void
-new_basic_block ()
+new_basic_block (void)
 {
-  register int i;
+  int i;
 
   next_qty = max_reg;
 
   /* Clear out hash table state for this pass.  */
 
-  memset ((char *) reg_hash, 0, sizeof reg_hash);
+  memset (reg_hash, 0, sizeof reg_hash);
 
   if (cse_reg_info_used_list)
     {
@@ -1033,9 +1005,8 @@ new_basic_block ()
        }
     }
 
-  prev_insn = 0;
-
 #ifdef HAVE_cc0
+  prev_insn = 0;
   prev_insn_cc0 = 0;
 #endif
 }
@@ -1044,13 +1015,11 @@ new_basic_block ()
    register before and initialize that quantity.  */
 
 static void
-make_new_qty (reg, mode)
-     unsigned int reg;
-     enum machine_mode mode;
+make_new_qty (unsigned int reg, enum machine_mode mode)
 {
-  register int q;
-  register struct qty_table_elem *ent;
-  register struct reg_eqv_elem *eqv;
+  int q;
+  struct qty_table_elem *ent;
+  struct reg_eqv_elem *eqv;
 
   if (next_qty >= max_qty)
     abort ();
@@ -1071,8 +1040,7 @@ make_new_qty (reg, mode)
    OLD is not changing; NEW is.  */
 
 static void
-make_regs_eqv (new, old)
-     unsigned int new, old;
+make_regs_eqv (unsigned int new, unsigned int old)
 {
   unsigned int lastr, firstr;
   int q = REG_QTY (old);
@@ -1135,12 +1103,11 @@ make_regs_eqv (new, old)
 /* Remove REG from its equivalence class.  */
 
 static void
-delete_reg_equiv (reg)
-     unsigned int reg;
+delete_reg_equiv (unsigned int reg)
 {
-  register struct qty_table_elem *ent;
-  register int q = REG_QTY (reg);
-  register int p, n;
+  struct qty_table_elem *ent;
+  int q = REG_QTY (reg);
+  int p, n;
 
   /* If invalid, do nothing.  */
   if (q == (int) reg)
@@ -1176,13 +1143,12 @@ delete_reg_equiv (reg)
    of X.  */
 
 static int
-mention_regs (x)
-     rtx x;
+mention_regs (rtx x)
 {
-  register enum rtx_code code;
-  register int i, j;
-  register const char *fmt;
-  register int changed = 0;
+  enum rtx_code code;
+  int i, j;
+  const char *fmt;
+  int changed = 0;
 
   if (x == 0)
     return 0;
@@ -1202,6 +1168,7 @@ mention_regs (x)
            remove_invalid_refs (i);
 
          REG_IN_TABLE (i) = REG_TICK (i);
+         SUBREG_TICKED (i) = -1;
        }
 
       return 0;
@@ -1217,17 +1184,20 @@ mention_regs (x)
 
       if (REG_IN_TABLE (i) >= 0 && REG_IN_TABLE (i) != REG_TICK (i))
        {
-         /* If reg_tick has been incremented more than once since
-            reg_in_table was last set, that means that the entire
-            register has been set before, so discard anything memorized
-            for the entire register, including all SUBREG expressions.  */
-         if (REG_IN_TABLE (i) != REG_TICK (i) - 1)
+         /* If REG_IN_TABLE (i) differs from REG_TICK (i) by one, and
+            the last store to this register really stored into this
+            subreg, then remove the memory of this subreg.
+            Otherwise, remove any memory of the entire register and
+            all its subregs from the table.  */
+         if (REG_TICK (i) - REG_IN_TABLE (i) > 1
+             || SUBREG_TICKED (i) != REGNO (SUBREG_REG (x)))
            remove_invalid_refs (i);
          else
            remove_invalid_subreg_refs (i, SUBREG_BYTE (x), GET_MODE (x));
        }
 
       REG_IN_TABLE (i) = REG_TICK (i);
+      SUBREG_TICKED (i) = REGNO (SUBREG_REG (x));
       return 0;
     }
 
@@ -1245,7 +1215,7 @@ mention_regs (x)
     {
       if (GET_CODE (XEXP (x, 0)) == REG
          && ! REGNO_QTY_VALID_P (REGNO (XEXP (x, 0))))
-       if (insert_regs (XEXP (x, 0), NULL_PTR, 0))
+       if (insert_regs (XEXP (x, 0), NULL, 0))
          {
            rehash_using_reg (XEXP (x, 0));
            changed = 1;
@@ -1253,7 +1223,7 @@ mention_regs (x)
 
       if (GET_CODE (XEXP (x, 1)) == REG
          && ! REGNO_QTY_VALID_P (REGNO (XEXP (x, 1))))
-       if (insert_regs (XEXP (x, 1), NULL_PTR, 0))
+       if (insert_regs (XEXP (x, 1), NULL, 0))
          {
            rehash_using_reg (XEXP (x, 1));
            changed = 1;
@@ -1282,10 +1252,7 @@ mention_regs (x)
    so X's hash code may be different.  */
 
 static int
-insert_regs (x, classp, modified)
-     rtx x;
-     struct table_elt *classp;
-     int modified;
+insert_regs (rtx x, struct table_elt *classp, int modified)
 {
   if (GET_CODE (x) == REG)
     {
@@ -1346,7 +1313,7 @@ insert_regs (x, classp, modified)
   else if (GET_CODE (x) == SUBREG && GET_CODE (SUBREG_REG (x)) == REG
           && ! REGNO_QTY_VALID_P (REGNO (SUBREG_REG (x))))
     {
-      insert_regs (SUBREG_REG (x), NULL_PTR, 0);
+      insert_regs (SUBREG_REG (x), NULL, 0);
       mention_regs (x);
       return 1;
     }
@@ -1362,9 +1329,7 @@ insert_regs (x, classp, modified)
    and we save much time not recomputing it.  */
 
 static void
-remove_from_table (elt, hash)
-     register struct table_elt *elt;
-     unsigned hash;
+remove_from_table (struct table_elt *elt, unsigned int hash)
 {
   if (elt == 0)
     return;
@@ -1375,8 +1340,8 @@ remove_from_table (elt, hash)
   /* Remove the table element from its equivalence class.  */
 
   {
-    register struct table_elt *prev = elt->prev_same_value;
-    register struct table_elt *next = elt->next_same_value;
+    struct table_elt *prev = elt->prev_same_value;
+    struct table_elt *next = elt->next_same_value;
 
     if (next)
       next->prev_same_value = prev;
@@ -1385,7 +1350,7 @@ remove_from_table (elt, hash)
       prev->next_same_value = next;
     else
       {
-       register struct table_elt *newfirst = next;
+       struct table_elt *newfirst = next;
        while (next)
          {
            next->first_same_value = newfirst;
@@ -1397,8 +1362,8 @@ remove_from_table (elt, hash)
   /* Remove the table element from its hash bucket.  */
 
   {
-    register struct table_elt *prev = elt->prev_same_hash;
-    register struct table_elt *next = elt->next_same_hash;
+    struct table_elt *prev = elt->prev_same_hash;
+    struct table_elt *next = elt->next_same_hash;
 
     if (next)
       next->prev_same_hash = prev;
@@ -1423,7 +1388,7 @@ remove_from_table (elt, hash)
 
   if (elt->related_value != 0 && elt->related_value != elt)
     {
-      register struct table_elt *p = elt->related_value;
+      struct table_elt *p = elt->related_value;
 
       while (p->related_value != elt)
        p = p->related_value;
@@ -1447,12 +1412,9 @@ remove_from_table (elt, hash)
    looks like X.  */
 
 static struct table_elt *
-lookup (x, hash, mode)
-     rtx x;
-     unsigned hash;
-     enum machine_mode mode;
+lookup (rtx x, unsigned int hash, enum machine_mode mode)
 {
-  register struct table_elt *p;
+  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)
@@ -1466,12 +1428,9 @@ lookup (x, hash, mode)
    Also ignore discrepancies in the machine mode of a register.  */
 
 static struct table_elt *
-lookup_for_remove (x, hash, mode)
-     rtx x;
-     unsigned hash;
-     enum machine_mode mode;
+lookup_for_remove (rtx x, unsigned int hash, enum machine_mode mode)
 {
-  register struct table_elt *p;
+  struct table_elt *p;
 
   if (GET_CODE (x) == REG)
     {
@@ -1498,11 +1457,9 @@ lookup_for_remove (x, hash, mode)
    If one is found, return that expression.  */
 
 static rtx
-lookup_as_function (x, code)
-     rtx x;
-     enum rtx_code code;
+lookup_as_function (rtx x, enum rtx_code code)
 {
-  register struct table_elt *p
+  struct table_elt *p
     = lookup (x, safe_hash (x, VOIDmode) & HASH_MASK, GET_MODE (x));
 
   /* If we are looking for a CONST_INT, the mode doesn't really matter, as
@@ -1556,13 +1513,9 @@ lookup_as_function (x, code)
  (preferrable ((X)->cost, (X)->regcost, (Y)->cost, (Y)->regcost) < 0)
 
 static struct table_elt *
-insert (x, classp, hash, mode)
-     register rtx x;
-     register struct table_elt *classp;
-     unsigned hash;
-     enum machine_mode mode;
+insert (rtx x, struct table_elt *classp, unsigned int hash, enum machine_mode mode)
 {
-  register struct table_elt *elt;
+  struct table_elt *elt;
 
   /* If X is a register and we haven't made a quantity for it,
      something is wrong.  */
@@ -1580,12 +1533,6 @@ insert (x, classp, hash, mode)
        SET_HARD_REG_BIT (hard_regs_in_table, i);
     }
 
-  /* If X is a label, show we recorded it.  */
-  if (GET_CODE (x) == LABEL_REF
-      || (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS
-         && GET_CODE (XEXP (XEXP (x, 0), 0)) == LABEL_REF))
-    new_label_ref = x;
-
   /* Put an element for X into the right hash bucket.  */
 
   elt = free_element_chain;
@@ -1594,7 +1541,7 @@ insert (x, classp, hash, mode)
   else
     {
       n_elements_made++;
-      elt = (struct table_elt *) xmalloc (sizeof (struct table_elt));
+      elt = xmalloc (sizeof (struct table_elt));
     }
 
   elt->exp = x;
@@ -1611,10 +1558,10 @@ insert (x, classp, hash, mode)
   elt->is_const = (CONSTANT_P (x)
                   /* GNU C++ takes advantage of this for `this'
                      (and other const values).  */
-                  || (RTX_UNCHANGING_P (x)
-                      && GET_CODE (x) == REG
+                  || (GET_CODE (x) == REG
+                      && RTX_UNCHANGING_P (x)
                       && REGNO (x) >= FIRST_PSEUDO_REGISTER)
-                  || FIXED_BASE_PLUS_P (x));
+                  || fixed_base_plus_p (x));
 
   if (table[hash])
     table[hash]->prev_same_hash = elt;
@@ -1625,9 +1572,9 @@ insert (x, classp, hash, mode)
     {
       classp = classp->first_same_value;
       if (CHEAPER (elt, classp))
-       /* Insert at the head of the class */
+       /* Insert at the head of the class */
        {
-         register struct table_elt *p;
+         struct table_elt *p;
          elt->next_same_value = classp;
          classp->prev_same_value = elt;
          elt->first_same_value = elt;
@@ -1639,7 +1586,7 @@ insert (x, classp, hash, mode)
        {
          /* Insert not at head of the class.  */
          /* Put it after the last element cheaper than X.  */
-         register struct table_elt *p, *next;
+         struct table_elt *p, *next;
 
          for (p = classp; (next = p->next_same_value) && CHEAPER (next, elt);
               p = next);
@@ -1687,7 +1634,7 @@ insert (x, classp, hash, mode)
           && ! qty_table[REG_QTY (REGNO (x))].const_rtx
           && ! elt->is_const)
     {
-      register struct table_elt *p;
+      struct table_elt *p;
 
       for (p = classp; p != 0; p = p->next_same_value)
        {
@@ -1724,7 +1671,7 @@ insert (x, classp, hash, mode)
          subhash = safe_hash (subexp, mode) & HASH_MASK;
          subelt = lookup (subexp, subhash, mode);
          if (subelt == 0)
-           subelt = insert (subexp, NULL_PTR, subhash, mode);
+           subelt = insert (subexp, NULL, subhash, mode);
          /* Initialize SUBELT's circular chain if it has none.  */
          if (subelt->related_value == 0)
            subelt->related_value = subelt;
@@ -1752,8 +1699,7 @@ insert (x, classp, hash, mode)
    Any invalid entries in CLASS2 will not be copied.  */
 
 static void
-merge_equiv_classes (class1, class2)
-     struct table_elt *class1, *class2;
+merge_equiv_classes (struct table_elt *class1, struct table_elt *class2)
 {
   struct table_elt *elt, *next, *new;
 
@@ -1800,7 +1746,7 @@ merge_equiv_classes (class1, class2)
 /* Flush the entire hash table.  */
 
 static void
-flush_hash_table ()
+flush_hash_table (void)
 {
   int i;
   struct table_elt *p;
@@ -1823,10 +1769,9 @@ struct check_dependence_data
   enum machine_mode mode;
   rtx exp;
 };
+
 static int
-check_dependence (x, data)
-     rtx *x;
-     void *data;
+check_dependence (rtx *x, void *data)
 {
   struct check_dependence_data *d = (struct check_dependence_data *) data;
   if (*x && GET_CODE (*x) == MEM)
@@ -1848,12 +1793,10 @@ check_dependence (x, data)
    or it may be either of those plus a numeric offset.  */
 
 static void
-invalidate (x, full_mode)
-     rtx x;
-     enum machine_mode full_mode;
+invalidate (rtx x, enum machine_mode full_mode)
 {
-  register int i;
-  register struct table_elt *p;
+  int i;
+  struct table_elt *p;
 
   switch (GET_CODE (x))
     {
@@ -1877,6 +1820,7 @@ invalidate (x, full_mode)
 
        delete_reg_equiv (regno);
        REG_TICK (regno)++;
+       SUBREG_TICKED (regno) = -1;
 
        if (regno >= FIRST_PSEUDO_REGISTER)
          {
@@ -1894,7 +1838,7 @@ invalidate (x, full_mode)
            unsigned int endregno
              = regno + HARD_REGNO_NREGS (regno, GET_MODE (x));
            unsigned int tregno, tendregno, rn;
-           register struct table_elt *p, *next;
+           struct table_elt *p, *next;
 
            CLEAR_HARD_REG_BIT (hard_regs_in_table, regno);
 
@@ -1904,6 +1848,7 @@ invalidate (x, full_mode)
                CLEAR_HARD_REG_BIT (hard_regs_in_table, rn);
                delete_reg_equiv (rn);
                REG_TICK (rn)++;
+               SUBREG_TICKED (rn) = -1;
              }
 
            if (in_table)
@@ -1953,7 +1898,7 @@ invalidate (x, full_mode)
 
       for (i = 0; i < HASH_SIZE; i++)
        {
-         register struct table_elt *next;
+         struct table_elt *next;
 
          for (p = table[i]; p; p = next)
            {
@@ -1988,8 +1933,7 @@ invalidate (x, full_mode)
    expressions to reappear as valid.  */
 
 static void
-remove_invalid_refs (regno)
-     unsigned int regno;
+remove_invalid_refs (unsigned int regno)
 {
   unsigned int i;
   struct table_elt *p, *next;
@@ -1999,7 +1943,7 @@ remove_invalid_refs (regno)
       {
        next = p->next_same_hash;
        if (GET_CODE (p->exp) != REG
-           && refers_to_regno_p (regno, regno + 1, p->exp, NULL_PTR))
+           && refers_to_regno_p (regno, regno + 1, p->exp, (rtx *) 0))
          remove_from_table (p, i);
       }
 }
@@ -2007,10 +1951,8 @@ remove_invalid_refs (regno)
 /* Likewise for a subreg with subreg_reg REGNO, subreg_byte OFFSET,
    and mode MODE.  */
 static void
-remove_invalid_subreg_refs (regno, offset, mode)
-     unsigned int regno;
-     unsigned int offset;
-     enum machine_mode mode;
+remove_invalid_subreg_refs (unsigned int regno, unsigned int offset,
+                           enum machine_mode mode)
 {
   unsigned int i;
   struct table_elt *p, *next;
@@ -2029,7 +1971,7 @@ remove_invalid_subreg_refs (regno, offset, mode)
                || (((SUBREG_BYTE (exp)
                      + (GET_MODE_SIZE (GET_MODE (exp)) - 1)) >= offset)
                    && SUBREG_BYTE (exp) <= end))
-           && refers_to_regno_p (regno, regno + 1, p->exp, NULL_PTR))
+           && refers_to_regno_p (regno, regno + 1, p->exp, (rtx *) 0))
          remove_from_table (p, i);
       }
 }
@@ -2040,8 +1982,7 @@ remove_invalid_subreg_refs (regno, offset, mode)
    This is called when we make a jump equivalence.  */
 
 static void
-rehash_using_reg (x)
-     rtx x;
+rehash_using_reg (rtx x)
 {
   unsigned int i;
   struct table_elt *p, *next;
@@ -2091,7 +2032,7 @@ rehash_using_reg (x)
    register.  Also update their TICK values.  */
 
 static void
-invalidate_for_call ()
+invalidate_for_call (void)
 {
   unsigned int regno, endregno;
   unsigned int i;
@@ -2109,7 +2050,10 @@ invalidate_for_call ()
       {
        delete_reg_equiv (regno);
        if (REG_TICK (regno) >= 0)
-         REG_TICK (regno)++;
+         {
+           REG_TICK (regno)++;
+           SUBREG_TICKED (regno) = -1;
+         }
 
        in_table |= (TEST_HARD_REG_BIT (hard_regs_in_table, regno) != 0);
       }
@@ -2147,12 +2091,10 @@ invalidate_for_call ()
    If none can be found, return 0.  */
 
 static rtx
-use_related_value (x, elt)
-     rtx x;
-     struct table_elt *elt;
+use_related_value (rtx x, struct table_elt *elt)
 {
-  register struct table_elt *relt = 0;
-  register struct table_elt *p, *q;
+  struct table_elt *relt = 0;
+  struct table_elt *p, *q;
   HOST_WIDE_INT offset;
 
   /* First, is there anything related known?
@@ -2217,12 +2159,11 @@ use_related_value (x, elt)
 \f
 /* Hash a string.  Just add its bytes up.  */
 static inline unsigned
-canon_hash_string (ps)
-     const char *ps;
+canon_hash_string (const char *ps)
 {
   unsigned hash = 0;
-  const unsigned char *p = (const unsigned char *)ps;
-  
+  const unsigned char *p = (const unsigned char *) ps;
+
   if (p)
     while (*p)
       hash += *p++;
@@ -2244,14 +2185,12 @@ canon_hash_string (ps)
    is just (int) MEM plus the hash code of the address.  */
 
 static unsigned
-canon_hash (x, mode)
-     rtx x;
-     enum machine_mode mode;
+canon_hash (rtx x, enum machine_mode mode)
 {
-  register int i, j;
-  register unsigned hash = 0;
-  register enum rtx_code code;
-  register const char *fmt;
+  int i, j;
+  unsigned hash = 0;
+  enum rtx_code code;
+  const char *fmt;
 
   /* repeat is used to turn tail-recursion into iteration.  */
  repeat:
@@ -2264,26 +2203,42 @@ canon_hash (x, 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, and sp to be fixed for this purpose.
+          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.  */
-
-       if (regno < FIRST_PSEUDO_REGISTER
-           && (global_regs[regno]
-               || (SMALL_REGISTER_CLASSES
-                   && ! fixed_regs[regno]
-                   && regno != FRAME_POINTER_REGNUM
-                   && regno != HARD_FRAME_POINTER_REGNUM
-                   && regno != ARG_POINTER_REGNUM
-                   && regno != STACK_POINTER_REGNUM
-                   && GET_MODE_CLASS (GET_MODE (x)) != MODE_CC)))
+          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)
          {
            do_not_record = 1;
            return 0;
@@ -2320,16 +2275,28 @@ canon_hash (x, mode)
         the integers representing the constant.  */
       hash += (unsigned) code + (unsigned) GET_MODE (x);
       if (GET_MODE (x) != VOIDmode)
-       for (i = 2; i < GET_RTX_LENGTH (CONST_DOUBLE); i++)
-         {
-           unsigned HOST_WIDE_INT tem = XWINT (x, i);
-           hash += tem;
-         }
+       hash += real_hash (CONST_DOUBLE_REAL_VALUE (x));
       else
        hash += ((unsigned) CONST_DOUBLE_LOW (x)
                 + (unsigned) CONST_DOUBLE_HIGH (x));
       return hash;
 
+    case CONST_VECTOR:
+      {
+       int units;
+       rtx elt;
+
+       units = CONST_VECTOR_NUNITS (x);
+
+       for (i = 0; i < units; ++i)
+         {
+           elt = CONST_VECTOR_ELT (x, i);
+           hash += canon_hash (elt, GET_MODE (elt));
+         }
+
+       return hash;
+      }
+
       /* Assume there is only one rtx object for any given label.  */
     case LABEL_REF:
       hash += ((unsigned) LABEL_REF << 7) + (unsigned long) XEXP (x, 0);
@@ -2347,10 +2314,9 @@ canon_hash (x, mode)
          do_not_record = 1;
          return 0;
        }
-      if (! RTX_UNCHANGING_P (x) || FIXED_BASE_PLUS_P (XEXP (x, 0)))
-       {
-         hash_arg_in_memory = 1;
-       }
+      if (! RTX_UNCHANGING_P (x) || fixed_base_plus_p (XEXP (x, 0)))
+       hash_arg_in_memory = 1;
+
       /* Now that we have already found this special case,
         might as well speed it up as much as possible.  */
       hash += (unsigned) MEM;
@@ -2365,10 +2331,10 @@ canon_hash (x, mode)
       if (GET_CODE (XEXP (x, 0)) == MEM
          && ! MEM_VOLATILE_P (XEXP (x, 0)))
        {
-         hash += (unsigned)USE;
+         hash += (unsigned) USE;
          x = XEXP (x, 0);
 
-         if (! RTX_UNCHANGING_P (x) || FIXED_BASE_PLUS_P (XEXP (x, 0)))
+         if (! RTX_UNCHANGING_P (x) || fixed_base_plus_p (XEXP (x, 0)))
            hash_arg_in_memory = 1;
 
          /* Now that we have already found this special case,
@@ -2456,7 +2422,7 @@ canon_hash (x, mode)
        hash += canon_hash_string (XSTR (x, i));
       else if (fmt[i] == 'i')
        {
-         register unsigned tem = XINT (x, i);
+         unsigned tem = XINT (x, i);
          hash += tem;
        }
       else if (fmt[i] == '0' || fmt[i] == 't')
@@ -2471,9 +2437,7 @@ canon_hash (x, mode)
 /* Like canon_hash but with no side effects.  */
 
 static unsigned
-safe_hash (x, mode)
-     rtx x;
-     enum machine_mode mode;
+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;
@@ -2499,14 +2463,11 @@ safe_hash (x, mode)
    is the same as that of the given value is pure luck.  */
 
 static int
-exp_equiv_p (x, y, validate, equal_values)
-     rtx x, y;
-     int validate;
-     int equal_values;
+exp_equiv_p (rtx x, rtx y, int validate, int equal_values)
 {
-  register int i, j;
-  register enum rtx_code code;
-  register const char *fmt;
+  int i, j;
+  enum rtx_code code;
+  const char *fmt;
 
   /* Note: it is incorrect to assume an expression is equivalent to itself
      if VALIDATE is nonzero.  */
@@ -2694,9 +2655,7 @@ exp_equiv_p (x, y, validate, equal_values)
    against certain constants or near-constants.  */
 
 static int
-cse_rtx_varies_p (x, from_alias)
-     register rtx x;
-     int from_alias;
+cse_rtx_varies_p (rtx x, int from_alias)
 {
   /* We need not check for X and the equivalence class being of the same
      mode because if X is equivalent to a constant in some mode, it
@@ -2756,21 +2715,19 @@ cse_rtx_varies_p (x, from_alias)
    replace each register reference inside it
    with the "oldest" equivalent register.
 
-   If INSN is non-zero and we are replacing a pseudo with a hard register
+   If INSN is nonzero and we are replacing a pseudo with a hard register
    or vice versa, validate_change is used to ensure that INSN remains valid
-   after we make our substitution.  The calls are made with IN_GROUP non-zero
+   after we make our substitution.  The calls are made with IN_GROUP nonzero
    so apply_change_group must be called upon the outermost return from this
    function (unless INSN is zero).  The result of apply_change_group can
    generally be discarded since the changes we are making are optional.  */
 
 static rtx
-canon_reg (x, insn)
-     rtx x;
-     rtx insn;
+canon_reg (rtx x, rtx insn)
 {
-  register int i;
-  register enum rtx_code code;
-  register const char *fmt;
+  int i;
+  enum rtx_code code;
+  const char *fmt;
 
   if (x == 0)
     return x;
@@ -2783,6 +2740,7 @@ canon_reg (x, insn)
     case CONST:
     case CONST_INT:
     case CONST_DOUBLE:
+    case CONST_VECTOR:
     case SYMBOL_REF:
     case LABEL_REF:
     case ADDR_VEC:
@@ -2791,9 +2749,9 @@ canon_reg (x, insn)
 
     case REG:
       {
-       register int first;
-       register int q;
-       register struct qty_table_elem *ent;
+       int first;
+       int q;
+       struct qty_table_elem *ent;
 
        /* Never replace a hard reg, because hard regs can appear
           in more than one machine mode, and we must preserve the mode
@@ -2819,7 +2777,7 @@ canon_reg (x, insn)
   fmt = GET_RTX_FORMAT (code);
   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
     {
-      register int j;
+      int j;
 
       if (fmt[i] == 'e')
        {
@@ -2854,26 +2812,20 @@ canon_reg (x, insn)
    is a good approximation for that cost.  However, most RISC machines have
    only a few (usually only one) memory reference formats.  If an address is
    valid at all, it is often just as cheap as any other address.  Hence, for
-   RISC machines, we use the configuration macro `ADDRESS_COST' to compare the
-   costs of various addresses.  For two addresses of equal cost, choose the one
-   with the highest `rtx_cost' value as that has the potential of eliminating
-   the most insns.  For equal costs, we choose the first in the equivalence
-   class.  Note that we ignore the fact that pseudo registers are cheaper
-   than hard registers here because we would also prefer the pseudo registers.
-  */
+   RISC machines, we use `address_cost' to compare the costs of various
+   addresses.  For two addresses of equal cost, choose the one with the
+   highest `rtx_cost' value as that has the potential of eliminating the
+   most insns.  For equal costs, we choose the first in the equivalence
+   class.  Note that we ignore the fact that pseudo registers are cheaper than
+   hard registers here because we would also prefer the pseudo registers.  */
 
 static void
-find_best_addr (insn, loc, mode)
-     rtx insn;
-     rtx *loc;
-     enum machine_mode mode;
+find_best_addr (rtx insn, rtx *loc, enum machine_mode mode)
 {
   struct table_elt *elt;
   rtx addr = *loc;
-#ifdef ADDRESS_COST
   struct table_elt *p;
   int found_better = 1;
-#endif
   int save_do_not_record = do_not_record;
   int save_hash_arg_in_memory = hash_arg_in_memory;
   int addr_volatile;
@@ -2937,22 +2889,6 @@ find_best_addr (insn, loc, mode)
 
   elt = lookup (addr, hash, Pmode);
 
-#ifndef ADDRESS_COST
-  if (elt)
-    {
-      int our_cost = elt->cost;
-
-      /* Find the lowest cost below ours that works.  */
-      for (elt = elt->first_same_value; elt; elt = elt->next_same_value)
-       if (elt->cost < our_cost
-           && (GET_CODE (elt->exp) == REG
-               || exp_equiv_p (elt->exp, elt->exp, 1, 0))
-           && validate_change (insn, loc,
-                               canon_reg (copy_rtx (elt->exp), NULL_RTX), 0))
-         return;
-    }
-#else
-
   if (elt)
     {
       /* We need to find the best (under the criteria documented above) entry
@@ -3011,10 +2947,9 @@ find_best_addr (insn, loc, mode)
   if (flag_expensive_optimizations
       && (GET_RTX_CLASS (GET_CODE (*loc)) == '2'
          || GET_RTX_CLASS (GET_CODE (*loc)) == 'c')
-      && GET_CODE (XEXP (*loc, 0)) == REG
-      && GET_CODE (XEXP (*loc, 1)) == CONST_INT)
+      && GET_CODE (XEXP (*loc, 0)) == REG)
     {
-      rtx c = XEXP (*loc, 1);
+      rtx op1 = XEXP (*loc, 1);
 
       do_not_record = 0;
       hash = HASH (XEXP (*loc, 0), Pmode);
@@ -3056,7 +2991,7 @@ find_best_addr (insn, loc, mode)
                    || exp_equiv_p (p->exp, p->exp, 1, 0)))
              {
                rtx new = simplify_gen_binary (GET_CODE (*loc), Pmode,
-                                              p->exp, c);
+                                              p->exp, op1);
                int new_cost;
                new_cost = address_cost (new, mode);
 
@@ -3083,7 +3018,6 @@ find_best_addr (insn, loc, mode)
            }
        }
     }
-#endif
 }
 \f
 /* Given an operation (CODE, *PARG1, *PARG2), where code is a comparison
@@ -3099,10 +3033,8 @@ find_best_addr (insn, loc, mode)
    A or the code corresponding to the inverse of the comparison.  */
 
 static enum rtx_code
-find_comparison_args (code, parg1, parg2, pmode1, pmode2)
-     enum rtx_code code;
-     rtx *parg1, *parg2;
-     enum machine_mode *pmode1, *pmode2;
+find_comparison_args (enum rtx_code code, rtx *parg1, rtx *parg2,
+                     enum machine_mode *pmode1, enum machine_mode *pmode2)
 {
   rtx arg1, arg2;
 
@@ -3112,7 +3044,7 @@ find_comparison_args (code, parg1, parg2, pmode1, pmode2)
 
   while (arg2 == CONST0_RTX (GET_MODE (arg1)))
     {
-      /* Set non-zero when we find something of interest.  */
+      /* Set nonzero when we find something of interest.  */
       rtx x = 0;
       int reverse_code = 0;
       struct table_elt *p = 0;
@@ -3130,13 +3062,17 @@ find_comparison_args (code, parg1, parg2, pmode1, pmode2)
 
       else if (GET_RTX_CLASS (GET_CODE (arg1)) == '<')
        {
+#ifdef FLOAT_STORE_FLAG_VALUE
+         REAL_VALUE_TYPE fsfv;
+#endif
+
          if (code == NE
              || (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
-                 && (REAL_VALUE_NEGATIVE
-                     (FLOAT_STORE_FLAG_VALUE (GET_MODE (arg1)))))
+                 && (fsfv = FLOAT_STORE_FLAG_VALUE (GET_MODE (arg1)),
+                     REAL_VALUE_NEGATIVE (fsfv)))
 #endif
              )
            x = arg1;
@@ -3145,8 +3081,8 @@ find_comparison_args (code, parg1, parg2, pmode1, pmode2)
                       && code == GE && STORE_FLAG_VALUE == -1)
 #ifdef FLOAT_STORE_FLAG_VALUE
                   || (GET_MODE_CLASS (GET_MODE (arg1)) == MODE_FLOAT
-                      && (REAL_VALUE_NEGATIVE
-                          (FLOAT_STORE_FLAG_VALUE (GET_MODE (arg1)))))
+                      && (fsfv = FLOAT_STORE_FLAG_VALUE (GET_MODE (arg1)),
+                          REAL_VALUE_NEGATIVE (fsfv)))
 #endif
                   )
            x = arg1, reverse_code = 1;
@@ -3182,6 +3118,9 @@ find_comparison_args (code, parg1, parg2, pmode1, pmode2)
       for (; p; p = p->next_same_value)
        {
          enum machine_mode inner_mode = GET_MODE (p->exp);
+#ifdef FLOAT_STORE_FLAG_VALUE
+         REAL_VALUE_TYPE fsfv;
+#endif
 
          /* If the entry isn't valid, skip it.  */
          if (! exp_equiv_p (p->exp, p->exp, 1, 0))
@@ -3206,8 +3145,8 @@ find_comparison_args (code, parg1, parg2, pmode1, pmode2)
 #ifdef FLOAT_STORE_FLAG_VALUE
                   || (code == LT
                       && GET_MODE_CLASS (inner_mode) == MODE_FLOAT
-                      && (REAL_VALUE_NEGATIVE
-                          (FLOAT_STORE_FLAG_VALUE (GET_MODE (arg1)))))
+                      && (fsfv = FLOAT_STORE_FLAG_VALUE (GET_MODE (arg1)),
+                          REAL_VALUE_NEGATIVE (fsfv)))
 #endif
                   )
                  && GET_RTX_CLASS (GET_CODE (p->exp)) == '<'))
@@ -3226,8 +3165,8 @@ find_comparison_args (code, parg1, parg2, pmode1, pmode2)
 #ifdef FLOAT_STORE_FLAG_VALUE
                    || (code == GE
                        && GET_MODE_CLASS (inner_mode) == MODE_FLOAT
-                       && (REAL_VALUE_NEGATIVE
-                           (FLOAT_STORE_FLAG_VALUE (GET_MODE (arg1)))))
+                       && (fsfv = FLOAT_STORE_FLAG_VALUE (GET_MODE (arg1)),
+                           REAL_VALUE_NEGATIVE (fsfv)))
 #endif
                    )
                   && GET_RTX_CLASS (GET_CODE (p->exp)) == '<')
@@ -3237,9 +3176,10 @@ find_comparison_args (code, parg1, parg2, pmode1, pmode2)
              break;
            }
 
-         /* If this is fp + constant, the equivalent is a better operand since
-            it may let us predict the value of the comparison.  */
-         else if (NONZERO_BASE_PLUS_P (p->exp))
+         /* If this non-trapping address, e.g. fp + constant, the
+            equivalent is a better operand since it may let us predict
+            the value of the comparison.  */
+         else if (!rtx_addr_can_trap_p (p->exp))
            {
              arg1 = p->exp;
              continue;
@@ -3259,7 +3199,8 @@ find_comparison_args (code, parg1, parg2, pmode1, pmode2)
          enum rtx_code reversed = reversed_comparison_code (x, NULL_RTX);
          if (reversed == UNKNOWN)
            break;
-         else code = reversed;
+         else
+           code = reversed;
        }
       else if (GET_RTX_CLASS (GET_CODE (x)) == '<')
        code = GET_CODE (x);
@@ -3288,14 +3229,12 @@ find_comparison_args (code, parg1, parg2, pmode1, pmode2)
    of X before modifying it.  */
 
 static rtx
-fold_rtx (x, insn)
-     rtx x;
-     rtx insn;
+fold_rtx (rtx x, rtx insn)
 {
-  register enum rtx_code code;
-  register enum machine_mode mode;
-  register const char *fmt;
-  register int i;
+  enum rtx_code code;
+  enum machine_mode mode;
+  const char *fmt;
+  int i;
   rtx new = 0;
   int copied = 0;
   int must_swap = 0;
@@ -3324,6 +3263,7 @@ fold_rtx (x, insn)
     case CONST:
     case CONST_INT:
     case CONST_DOUBLE:
+    case CONST_VECTOR:
     case SYMBOL_REF:
     case LABEL_REF:
     case REG:
@@ -3345,18 +3285,12 @@ fold_rtx (x, insn)
     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.  */
-      if (insn && GET_CODE (insn) == JUMP_INSN)
-       {
-         rtx next = next_nonnote_insn (insn);
-
-         if (next && GET_CODE (next) == CODE_LABEL
-             && NEXT_INSN (next) != 0
-             && GET_CODE (NEXT_INSN (next)) == JUMP_INSN
-             && (GET_CODE (PATTERN (NEXT_INSN (next))) == ADDR_VEC
-                 || GET_CODE (PATTERN (NEXT_INSN (next))) == ADDR_DIFF_VEC))
-           return gen_rtx_LABEL_REF (Pmode, next);
-       }
+        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:
@@ -3408,16 +3342,8 @@ fold_rtx (x, insn)
 
       if (folded_arg0 != SUBREG_REG (x))
        {
-         new = 0;
-
-         if (GET_MODE_CLASS (mode) == MODE_INT
-             && GET_MODE_SIZE (mode) == UNITS_PER_WORD
-             && GET_MODE (SUBREG_REG (x)) != VOIDmode)
-           new = operand_subword (folded_arg0,
-                                  (SUBREG_BYTE (x) / UNITS_PER_WORD), 0,
-                                  GET_MODE (SUBREG_REG (x)));
-         if (new == 0 && subreg_lowpart_p (x))
-           new = gen_lowpart_if_possible (mode, folded_arg0);
+         new = simplify_subreg (mode, folded_arg0,
+                                GET_MODE (SUBREG_REG (x)), SUBREG_BYTE (x));
          if (new)
            return new;
        }
@@ -3461,7 +3387,9 @@ fold_rtx (x, insn)
                  && GET_CODE (elt->exp) != SIGN_EXTEND
                  && GET_CODE (elt->exp) != ZERO_EXTEND
                  && GET_CODE (XEXP (elt->exp, 0)) == SUBREG
-                 && GET_MODE (SUBREG_REG (XEXP (elt->exp, 0))) == mode)
+                 && 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));
 
@@ -3602,7 +3530,10 @@ fold_rtx (x, insn)
            rtx new;
 
            if (CONSTANT_P (constant) && GET_CODE (constant) != CONST_INT)
-             constant_pool_entries_cost = COST (constant);
+             {
+               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)
@@ -3716,6 +3647,7 @@ fold_rtx (x, insn)
        rtx cheap_arg, expensive_arg;
        rtx replacements[2];
        int j;
+       int old_cost = COST_IN (XEXP (x, i), code);
 
        /* Most arguments are cheap, so handle them specially.  */
        switch (GET_CODE (arg))
@@ -3742,6 +3674,7 @@ fold_rtx (x, insn)
          case SYMBOL_REF:
          case LABEL_REF:
          case CONST_DOUBLE:
+         case CONST_VECTOR:
            const_arg = arg;
            break;
 
@@ -3803,9 +3736,8 @@ fold_rtx (x, insn)
        replacements[0] = cheap_arg;
        replacements[1] = expensive_arg;
 
-       for (j = 0; j < 2 && replacements[j];  j++)
+       for (j = 0; j < 2 && replacements[j]; j++)
          {
-           int old_cost = COST_IN (XEXP (x, i), code);
            int new_cost = COST_IN (replacements[j], code);
 
            /* Stop if what existed before was cheaper.  Prefer constants
@@ -3855,12 +3787,13 @@ fold_rtx (x, insn)
       || code == LTGT || code == UNEQ || code == ORDERED
       || code == UNORDERED)
     {
-      if (must_swap || (const_arg0
-                       && (const_arg1 == 0
-                           || (GET_CODE (const_arg0) == CONST_INT
-                               && GET_CODE (const_arg1) != CONST_INT))))
+      if (must_swap
+         || swap_commutative_operands_p (const_arg0 ? const_arg0
+                                                    : XEXP (x, 0),
+                                         const_arg1 ? const_arg1
+                                                    : XEXP (x, 1)))
        {
-         register rtx tem = XEXP (x, 0);
+         rtx tem = XEXP (x, 0);
 
          if (insn == 0 && ! copied)
            {
@@ -3921,7 +3854,7 @@ fold_rtx (x, insn)
          if (GET_MODE_CLASS (mode) == MODE_FLOAT)
            {
              true_rtx = (CONST_DOUBLE_FROM_REAL_VALUE
-                     (FLOAT_STORE_FLAG_VALUE (mode), mode));
+                         (FLOAT_STORE_FLAG_VALUE (mode), mode));
              false_rtx = CONST0_RTX (mode);
            }
 #endif
@@ -3943,17 +3876,10 @@ fold_rtx (x, insn)
             comparison.  */
          if (const_arg0 == 0 || const_arg1 == 0)
            {
-             /* Is FOLDED_ARG0 frame-pointer plus a constant?  Or
-                non-explicit constant?  These aren't zero, but we
-                don't know their sign.  */
+             /* Some addresses are known to be nonzero.  We don't know
+                their sign, but equality comparisons are known.  */
              if (const_arg1 == const0_rtx
-                 && (NONZERO_BASE_PLUS_P (folded_arg0)
-#if 0  /* Sad to say, on sysvr4, #pragma weak can make a symbol address
-         come out as 0.  */
-                     || GET_CODE (folded_arg0) == SYMBOL_REF
-#endif
-                     || GET_CODE (folded_arg0) == LABEL_REF
-                     || GET_CODE (folded_arg0) == CONST))
+                 && nonzero_address_p (folded_arg0))
                {
                  if (code == EQ)
                    return false_rtx;
@@ -3976,19 +3902,18 @@ fold_rtx (x, insn)
                                        & HASH_MASK), mode_arg0))
                      && p0->first_same_value == p1->first_same_value))
                {
-                  /* Sadly two equal NaNs are not equivalent.  */
-                  if (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
-                      || ! FLOAT_MODE_P (mode_arg0) 
-                      || flag_unsafe_math_optimizations)
-                     return ((code == EQ || code == LE || code == GE
-                              || code == LEU || code == GEU || code == UNEQ
-                              || code == UNLE || code == UNGE || code == ORDERED)
-                             ? true_rtx : false_rtx);
-                  /* Take care for the FP compares we can resolve.  */
-                  if (code == UNEQ || code == UNLE || code == UNGE)
-                    return true_rtx;
-                  if (code == LTGT || code == LT || code == GT)
-                    return false_rtx;
+                 /* Sadly two equal NaNs are not equivalent.  */
+                 if (!HONOR_NANS (mode_arg0))
+                   return ((code == EQ || code == LE || code == GE
+                            || code == LEU || code == GEU || code == UNEQ
+                            || code == UNLE || code == UNGE
+                            || code == ORDERED)
+                           ? true_rtx : false_rtx);
+                 /* Take care for the FP compares we can resolve.  */
+                 if (code == UNEQ || code == UNLE || code == UNGE)
+                   return true_rtx;
+                 if (code == LTGT || code == LT || code == GT)
+                   return false_rtx;
                }
 
              /* If FOLDED_ARG0 is a register, see if the comparison we are
@@ -4147,7 +4072,7 @@ fold_rtx (x, insn)
             CONST_INT, see if we can find a register equivalent to the
             positive constant.  Make a MINUS if so.  Don't do this for
             a non-negative constant since we might then alternate between
-            chosing positive and negative constants.  Having the positive
+            choosing positive and negative constants.  Having the positive
             constant previously-used is the more common case.  Be sure
             the resulting constant is non-negative; if const_arg1 were
             the smallest negative number this would overflow: depending
@@ -4196,7 +4121,7 @@ fold_rtx (x, insn)
        from_plus:
        case SMIN:    case SMAX:      case UMIN:    case UMAX:
        case IOR:     case AND:       case XOR:
-       case MULT:    case DIV:       case UDIV:
+       case MULT:
        case ASHIFT:  case LSHIFTRT:  case ASHIFTRT:
          /* If we have (<op> <reg> <const_int>) for an associative OP and REG
             is known to be of similar form, we may be able to replace the
@@ -4232,7 +4157,7 @@ fold_rtx (x, insn)
                 with a pre- or post-increment.  Similarly for two subtracts of
                 identical powers of two with post decrement.  */
 
-             if (code == PLUS && INTVAL (const_arg1) == INTVAL (inner_const)
+             if (code == PLUS && const_arg1 == inner_const
                  && ((HAVE_PRE_INCREMENT
                          && exact_log2 (INTVAL (const_arg1)) >= 0)
                      || (HAVE_POST_INCREMENT
@@ -4244,11 +4169,9 @@ fold_rtx (x, insn)
                break;
 
              /* Compute the code used to compose the constants.  For example,
-                A/C1/C2 is A/(C1 * C2), so if CODE == DIV, we want MULT.  */
+                A-C1-C2 is A-(C1 + C2), so if CODE == MINUS, we want PLUS.  */
 
-             associate_code
-               = (code == MULT || code == DIV || code == UDIV ? MULT
-                  : is_shift || code == PLUS || code == MINUS ? PLUS : code);
+             associate_code = (is_shift || code == MINUS ? PLUS : code);
 
              new_const = simplify_binary_operation (associate_code, mode,
                                                     const_arg1, inner_const);
@@ -4286,6 +4209,14 @@ fold_rtx (x, insn)
            }
          break;
 
+       case DIV:       case UDIV:
+         /* ??? The associative optimization performed immediately above is
+            also possible for DIV and UDIV using associate_code of MULT.
+            However, we would need extra code to verify that the
+            multiplication does not overflow, that is, there is no overflow
+            in the calculation of new_const.  */
+         break;
+
        default:
          break;
        }
@@ -4312,9 +4243,14 @@ fold_rtx (x, insn)
       break;
 
     case 'x':
-      /* Always eliminate CONSTANT_P_RTX at this stage.  */
+      /* Eliminate CONSTANT_P_RTX if its constant.  */
       if (code == CONSTANT_P_RTX)
-       return (const_arg0 ? const1_rtx : const0_rtx);
+       {
+         if (const_arg0)
+           return const1_rtx;
+         if (optimize == 0 || !flag_gcse)
+           return const0_rtx;
+       }
       break;
     }
 
@@ -4325,8 +4261,7 @@ fold_rtx (x, insn)
    Return 0 if we don't know one.  */
 
 static rtx
-equiv_constant (x)
-     rtx x;
+equiv_constant (rtx x)
 {
   if (GET_CODE (x) == REG
       && REGNO_QTY_VALID_P (REGNO (x)))
@@ -4376,9 +4311,7 @@ equiv_constant (x)
    This is similar to gen_lowpart in emit-rtl.c.  */
 
 rtx
-gen_lowpart_if_possible (mode, x)
-     enum machine_mode mode;
-     register rtx x;
+gen_lowpart_if_possible (enum machine_mode mode, rtx x)
 {
   rtx result = gen_lowpart_common (mode, x);
 
@@ -4387,23 +4320,22 @@ gen_lowpart_if_possible (mode, x)
   else if (GET_CODE (x) == MEM)
     {
       /* This is the only other case we handle.  */
-      register int offset = 0;
+      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 = gen_rtx_MEM (mode, plus_constant (XEXP (x, 0), offset));
+       /* 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;
-      MEM_COPY_ATTRIBUTES (new, x);
+
       return new;
     }
   else
@@ -4415,16 +4347,14 @@ gen_lowpart_if_possible (mode, x)
 
    In certain cases, this can cause us to add an equivalence.  For example,
    if we are following the taken case of
-       if (i == 2)
+       if (i == 2)
    we can add the fact that `i' and '2' are now equivalent.
 
    In any case, we can record that this comparison was passed.  If the same
    comparison is seen later, we will know its value.  */
 
 static void
-record_jump_equiv (insn, taken)
-     rtx insn;
-     int taken;
+record_jump_equiv (rtx insn, int taken)
 {
   int cond_known_true;
   rtx op0, op1;
@@ -4475,11 +4405,8 @@ record_jump_equiv (insn, taken)
    above function and called recursively.  */
 
 static void
-record_jump_cond (code, mode, op0, op1, reversed_nonequality)
-     enum rtx_code code;
-     enum machine_mode mode;
-     rtx op0, op1;
-     int reversed_nonequality;
+record_jump_cond (enum rtx_code code, enum machine_mode mode, rtx op0,
+                 rtx op1, int reversed_nonequality)
 {
   unsigned op0_hash, op1_hash;
   int op0_in_memory, op1_in_memory;
@@ -4603,7 +4530,7 @@ record_jump_cond (code, mode, op0, op1, reversed_nonequality)
         new quantity number.  */
       if (op0_elt == 0)
        {
-         if (insert_regs (op0, NULL_PTR, 0))
+         if (insert_regs (op0, NULL, 0))
            {
              rehash_using_reg (op0);
              op0_hash = HASH (op0, mode);
@@ -4615,7 +4542,7 @@ record_jump_cond (code, mode, op0, op1, reversed_nonequality)
                op1_hash = HASH (op1,mode);
            }
 
-         op0_elt = insert (op0, NULL_PTR, op0_hash, mode);
+         op0_elt = insert (op0, NULL, op0_hash, mode);
          op0_elt->in_memory = op0_in_memory;
        }
 
@@ -4631,13 +4558,13 @@ record_jump_cond (code, mode, op0, op1, reversed_nonequality)
          /* Put OP1 in the hash table so it gets a new quantity number.  */
          if (op1_elt == 0)
            {
-             if (insert_regs (op1, NULL_PTR, 0))
+             if (insert_regs (op1, NULL, 0))
                {
                  rehash_using_reg (op1);
                  op1_hash = HASH (op1, mode);
                }
 
-             op1_elt = insert (op1, NULL_PTR, op1_hash, mode);
+             op1_elt = insert (op1, NULL, op1_hash, mode);
              op1_elt->in_memory = op1_in_memory;
            }
 
@@ -4658,25 +4585,25 @@ record_jump_cond (code, mode, op0, op1, reversed_nonequality)
 
   if (op0_elt == 0)
     {
-      if (insert_regs (op0, NULL_PTR, 0))
+      if (insert_regs (op0, NULL, 0))
        {
          rehash_using_reg (op0);
          op0_hash = HASH (op0, mode);
        }
 
-      op0_elt = insert (op0, NULL_PTR, op0_hash, mode);
+      op0_elt = insert (op0, NULL, op0_hash, mode);
       op0_elt->in_memory = op0_in_memory;
     }
 
   if (op1_elt == 0)
     {
-      if (insert_regs (op1, NULL_PTR, 0))
+      if (insert_regs (op1, NULL, 0))
        {
          rehash_using_reg (op1);
          op1_hash = HASH (op1, mode);
        }
 
-      op1_elt = insert (op1, NULL_PTR, op1_hash, mode);
+      op1_elt = insert (op1, NULL, op1_hash, mode);
       op1_elt->in_memory = op1_in_memory;
     }
 
@@ -4715,8 +4642,10 @@ struct set
   /* Nonzero if the SET_SRC contains something
      whose value cannot be predicted and understood.  */
   char src_volatile;
-  /* Original machine mode, in case it becomes a CONST_INT.  */
-  enum machine_mode mode;
+  /* Original machine mode, in case it becomes a CONST_INT.
+     The size of this field should match the size of the mode
+     field of struct rtx_def (see rtl.h).  */
+  ENUM_BITFIELD(machine_mode) mode : 8;
   /* A constant equivalent for SET_SRC, if any.  */
   rtx src_const;
   /* Original SET_SRC value used for libcall notes.  */
@@ -4728,14 +4657,12 @@ struct set
 };
 
 static void
-cse_insn (insn, libcall_insn)
-     rtx insn;
-     rtx libcall_insn;
+cse_insn (rtx insn, rtx libcall_insn)
 {
-  register rtx x = PATTERN (insn);
-  register int i;
+  rtx x = PATTERN (insn);
+  int i;
   rtx tem;
-  register int n_sets = 0;
+  int n_sets = 0;
 
 #ifdef HAVE_cc0
   /* Records what this insn does to set CC0.  */
@@ -4749,7 +4676,7 @@ cse_insn (insn, libcall_insn)
   int src_eqv_in_memory = 0;
   unsigned src_eqv_hash = 0;
 
-  struct set *sets = (struct set *) NULL_PTR;
+  struct set *sets = (struct set *) 0;
 
   this_insn = insn;
 
@@ -4770,7 +4697,7 @@ cse_insn (insn, libcall_insn)
 
   if (GET_CODE (x) == SET)
     {
-      sets = (struct set *) alloca (sizeof (struct set));
+      sets = alloca (sizeof (struct set));
       sets[0].rtl = x;
 
       /* Ignore SETs that are unconditional jumps.
@@ -4803,9 +4730,9 @@ cse_insn (insn, libcall_insn)
     }
   else if (GET_CODE (x) == PARALLEL)
     {
-      register int lim = XVECLEN (x, 0);
+      int lim = XVECLEN (x, 0);
 
-      sets = (struct set *) alloca (lim * sizeof (struct set));
+      sets = alloca (lim * sizeof (struct set));
 
       /* Find all regs explicitly clobbered in this insn,
         and ensure they are not replaced with any other regs
@@ -4820,7 +4747,7 @@ cse_insn (insn, libcall_insn)
         anything in that case.  */
       for (i = 0; i < lim; i++)
        {
-         register rtx y = XVECEXP (x, 0, i);
+         rtx y = XVECEXP (x, 0, i);
          if (GET_CODE (y) == CLOBBER)
            {
              rtx clobbered = XEXP (y, 0);
@@ -4836,7 +4763,7 @@ cse_insn (insn, libcall_insn)
 
       for (i = 0; i < lim; i++)
        {
-         register rtx y = XVECEXP (x, 0, i);
+         rtx y = XVECEXP (x, 0, i);
          if (GET_CODE (y) == SET)
            {
              /* As above, we ignore unconditional jumps and call-insns and
@@ -4903,7 +4830,10 @@ cse_insn (insn, libcall_insn)
       && (tem = find_reg_note (insn, REG_EQUAL, NULL_RTX)) != 0
       && (! rtx_equal_p (XEXP (tem, 0), SET_SRC (sets[0].rtl))
          || GET_CODE (SET_DEST (sets[0].rtl)) == STRICT_LOW_PART))
-    src_eqv = canon_reg (XEXP (tem, 0), NULL_RTX);
+    {
+      src_eqv = fold_rtx (canon_reg (XEXP (tem, 0), NULL_RTX), insn);
+      XEXP (tem, 0) = src_eqv;
+    }
 
   /* Canonicalize sources and addresses of destinations.
      We do this in a separate pass to avoid problems when a MATCH_DUP is
@@ -4968,9 +4898,9 @@ cse_insn (insn, libcall_insn)
 
   for (i = 0; i < n_sets; i++)
     {
-      register rtx src, dest;
-      register rtx src_folded;
-      register struct table_elt *elt = 0, *p;
+      rtx src, dest;
+      rtx src_folded;
+      struct table_elt *elt = 0, *p;
       enum machine_mode mode;
       rtx src_eqv_here;
       rtx src_const = 0;
@@ -4986,7 +4916,7 @@ cse_insn (insn, libcall_insn)
       int src_folded_regcost = MAX_COST;
       int src_related_regcost = MAX_COST;
       int src_elt_regcost = MAX_COST;
-      /* Set non-zero if we need to call force_const_mem on with the
+      /* Set nonzero if we need to call force_const_mem on with the
         contents of src_folded before using it.  */
       int src_folded_force_flag = 0;
 
@@ -5007,7 +4937,6 @@ cse_insn (insn, libcall_insn)
            eqvmode = GET_MODE (SUBREG_REG (XEXP (dest, 0)));
          do_not_record = 0;
          hash_arg_in_memory = 0;
-         src_eqv = fold_rtx (src_eqv, insn);
          src_eqv_hash = HASH (src_eqv, eqvmode);
 
          /* Find the equivalence class for the equivalent expression.  */
@@ -5067,18 +4996,16 @@ cse_insn (insn, libcall_insn)
       sets[i].src_in_memory = hash_arg_in_memory;
 
       /* If SRC is a MEM, there is a REG_EQUIV note for SRC, and DEST is
-        a pseudo that is set more than once, do not record SRC.  Using
-        SRC as a replacement for anything else will be incorrect in that
-        situation.  Note that this usually occurs only for stack slots,
-        in which case all the RTL would be referring to SRC, so we don't
-        lose any optimization opportunities by not having SRC in the
-        hash table.  */
+        a pseudo, do not record SRC.  Using SRC as a replacement for
+        anything else will be incorrect in that situation.  Note that
+        this usually occurs only for stack slots, in which case all the
+        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
-         && find_reg_note (insn, REG_EQUIV, src) != 0
+         && find_reg_note (insn, REG_EQUIV, NULL_RTX) != 0
          && GET_CODE (dest) == REG
-         && REGNO (dest) >= FIRST_PSEUDO_REGISTER
-         && REG_N_SETS (REGNO (dest)) != 1)
+         && REGNO (dest) >= FIRST_PSEUDO_REGISTER)
        sets[i].src_volatile = 1;
 
 #if 0
@@ -5329,9 +5256,9 @@ cse_insn (insn, libcall_insn)
       if (src == src_folded)
        src_folded = 0;
 
-      /* At this point, ELT, if non-zero, points to a class of expressions
+      /* At this point, ELT, if nonzero, points to a class of expressions
          equivalent to the source of this SET and SRC, SRC_EQV, SRC_FOLDED,
-        and SRC_RELATED, if non-zero, each contain additional equivalent
+        and SRC_RELATED, if nonzero, each contain additional equivalent
         expressions.  Prune these latter expressions by deleting expressions
         already in the equivalence class.
 
@@ -5468,13 +5395,13 @@ cse_insn (insn, libcall_insn)
              continue;
            }
 
-          if (elt)
+         if (elt)
            {
              src_elt_cost = elt->cost;
              src_elt_regcost = elt->regcost;
            }
 
-          /* Find cheapest and skip it for the next time.   For items
+         /* Find cheapest and skip it for the next time.   For items
             of equal cost, use this order:
             src_folded, src, src_eqv, src_related and hash table entry.  */
          if (src_folded
@@ -5489,7 +5416,11 @@ cse_insn (insn, libcall_insn)
            {
              trial = src_folded, src_folded_cost = MAX_COST;
              if (src_folded_force_flag)
-               trial = force_const_mem (mode, trial);
+               {
+                 rtx forced = force_const_mem (mode, trial);
+                 if (forced)
+                   trial = forced;
+               }
            }
          else if (src
                   && preferrable (src_cost, src_regcost,
@@ -5508,7 +5439,7 @@ cse_insn (insn, libcall_insn)
          else if (src_related
                   && preferrable (src_related_cost, src_related_regcost,
                                   src_elt_cost, src_elt_regcost) <= 0)
-           trial = copy_rtx (src_related), src_related_cost = MAX_COST;
+           trial = copy_rtx (src_related), src_related_cost = MAX_COST;
          else
            {
              trial = copy_rtx (elt->exp);
@@ -5520,31 +5451,17 @@ cse_insn (insn, libcall_insn)
             check for this separately here.  We will delete such an
             insn below.
 
-            Tablejump insns contain a USE of the table, so simply replacing
-            the operand with the constant won't match.  This is simply an
-            unconditional branch, however, and is therefore valid.  Just
-            insert the substitution here and we will delete and re-emit
-            the insn later.  */
-
+            For other cases such as a table jump or conditional jump
+            where we know the ultimate target, go ahead and replace the
+            operand.  While that may not make a valid insn, we will
+            reemit the jump below (and also insert any necessary
+            barriers).  */
          if (n_sets == 1 && dest == pc_rtx
              && (trial == pc_rtx
                  || (GET_CODE (trial) == LABEL_REF
                      && ! condjump_p (insn))))
            {
-             if (trial == pc_rtx)
-               {
-                 SET_SRC (sets[i].rtl) = trial;
-                 cse_jumps_altered = 1;
-                 break;
-               }
-
-             PATTERN (insn) = gen_jump (XEXP (trial, 0));
-             INSN_CODE (insn) = -1;
-
-             if (NEXT_INSN (insn) != 0
-                 && GET_CODE (NEXT_INSN (insn)) != BARRIER)
-               emit_barrier_after (insn);
-
+             SET_SRC (sets[i].rtl) = trial;
              cse_jumps_altered = 1;
              break;
            }
@@ -5552,6 +5469,8 @@ cse_insn (insn, libcall_insn)
          /* Look for a substitution that makes a valid insn.  */
          else if (validate_change (insn, &SET_SRC (sets[i].rtl), trial, 0))
            {
+             rtx new = canon_reg (SET_SRC (sets[i].rtl), insn);
+
              /* If we just made a substitution inside a libcall, then we
                 need to make the same substitution in any notes attached
                 to the RETVAL insn.  */
@@ -5559,15 +5478,13 @@ cse_insn (insn, libcall_insn)
                  && (GET_CODE (sets[i].orig_src) == REG
                      || GET_CODE (sets[i].orig_src) == SUBREG
                      || GET_CODE (sets[i].orig_src) == MEM))
-               replace_rtx (REG_NOTES (libcall_insn), sets[i].orig_src,
-                            canon_reg (SET_SRC (sets[i].rtl), insn));
+               simplify_replace_rtx (REG_NOTES (libcall_insn),
+                                     sets[i].orig_src, copy_rtx (new));
 
              /* The result of apply_change_group can be ignored; see
                 canon_reg.  */
 
-             validate_change (insn, &SET_SRC (sets[i].rtl),
-                              canon_reg (SET_SRC (sets[i].rtl), insn),
-                              1);
+             validate_change (insn, &SET_SRC (sets[i].rtl), new, 1);
              apply_change_group ();
              break;
            }
@@ -5598,6 +5515,7 @@ cse_insn (insn, libcall_insn)
              src_folded_force_flag = 1;
              src_folded = trial;
              src_folded_cost = constant_pool_entries_cost;
+             src_folded_regcost = constant_pool_entries_regcost;
            }
        }
 
@@ -5680,52 +5598,15 @@ cse_insn (insn, libcall_insn)
                && GET_CODE (XEXP (XEXP (src_const, 0), 0)) == LABEL_REF
                && GET_CODE (XEXP (XEXP (src_const, 0), 1)) == LABEL_REF))
        {
-         tem = find_reg_note (insn, REG_EQUAL, NULL_RTX);
-
-         /* Make sure that the rtx is not shared with any other insn.  */
-         src_const = copy_rtx (src_const);
-
-         /* Record the actual constant value in a REG_EQUAL note, making
-            a new one if one does not already exist.  */
-         if (tem)
-           XEXP (tem, 0) = src_const;
-         else
-           REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL,
-                                                 src_const, REG_NOTES (insn));
-
-          /* If storing a constant value in a register that
-            previously held the constant value 0,
-            record this fact with a REG_WAS_0 note on this insn.
-
-            Note that the *register* is required to have previously held 0,
-            not just any register in the quantity and we must point to the
-            insn that set that register to zero.
-
-            Rather than track each register individually, we just see if
-            the last set for this quantity was for this register.  */
-
-         if (REGNO_QTY_VALID_P (REGNO (dest)))
+         /* We only want a REG_EQUAL note if src_const != src.  */
+         if (! rtx_equal_p (src, src_const))
            {
-             int dest_q = REG_QTY (REGNO (dest));
-             struct qty_table_elem *dest_ent = &qty_table[dest_q];
-
-             if (dest_ent->const_rtx == const0_rtx)
-               {
-                 /* See if we previously had a REG_WAS_0 note.  */
-                 rtx note = find_reg_note (insn, REG_WAS_0, NULL_RTX);
-                 rtx const_insn = dest_ent->const_insn;
+             /* Make sure that the rtx is not shared.  */
+             src_const = copy_rtx (src_const);
 
-                 if ((tem = single_set (const_insn)) != 0
-                     && rtx_equal_p (SET_DEST (tem), dest))
-                   {
-                     if (note)
-                       XEXP (note, 0) = const_insn;
-                     else
-                       REG_NOTES (insn)
-                         = gen_rtx_INSN_LIST (REG_WAS_0, const_insn,
-                                              REG_NOTES (insn));
-                   }
-               }
+             /* Record the actual constant value in a REG_EQUAL note,
+                making a new one if one does not already exist.  */
+             set_unique_reg_note (insn, REG_EQUAL, src_const);
            }
        }
 
@@ -5795,45 +5676,49 @@ cse_insn (insn, libcall_insn)
       else if (n_sets == 1 && dest == pc_rtx && src == pc_rtx)
        {
          /* One less use of the label this insn used to jump to.  */
-         if (JUMP_LABEL (insn) != 0)
-           --LABEL_NUSES (JUMP_LABEL (insn));
-         PUT_CODE (insn, NOTE);
-         NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
-         NOTE_SOURCE_FILE (insn) = 0;
+         delete_insn (insn);
          cse_jumps_altered = 1;
          /* No more processing for this set.  */
          sets[i].rtl = 0;
        }
 
       /* If this SET is now setting PC to a label, we know it used to
-        be a conditional or computed branch.  So we see if we can follow
-        it.  If it was a computed branch, delete it and re-emit.  */
+        be a conditional or computed branch.  */
       else if (dest == pc_rtx && GET_CODE (src) == LABEL_REF)
        {
-         /* If this is not in the format for a simple branch and
-            we are the only SET in it, re-emit it.  */
-         if (! simplejump_p (insn) && n_sets == 1)
+         /* Now emit a BARRIER after the unconditional jump.  */
+         if (NEXT_INSN (insn) == 0
+             || GET_CODE (NEXT_INSN (insn)) != BARRIER)
+           emit_barrier_after (insn);
+
+         /* We reemit the jump in as many cases as possible just in
+            case the form of an unconditional jump is significantly
+            different than a computed jump or conditional jump.
+
+            If this insn has multiple sets, then reemitting the
+            jump is nontrivial.  So instead we just force rerecognition
+            and hope for the best.  */
+         if (n_sets == 1)
            {
-             rtx new = emit_jump_insn_before (gen_jump (XEXP (src, 0)), insn);
+             rtx new = emit_jump_insn_after (gen_jump (XEXP (src, 0)), insn);
+
              JUMP_LABEL (new) = XEXP (src, 0);
              LABEL_NUSES (XEXP (src, 0))++;
+             delete_insn (insn);
              insn = new;
+
+             /* Now emit a BARRIER after the unconditional jump.  */
+             if (NEXT_INSN (insn) == 0
+                 || GET_CODE (NEXT_INSN (insn)) != BARRIER)
+               emit_barrier_after (insn);
            }
          else
-           /* Otherwise, force rerecognition, since it probably had
-              a different pattern before.
-              This shouldn't really be necessary, since whatever
-              changed the source value above should have done this.
-              Until the right place is found, might as well do this here.  */
            INSN_CODE (insn) = -1;
 
-         never_reached_warning (insn);
+         never_reached_warning (insn, NULL);
 
-         /* Now emit a BARRIER after the unconditional jump.  Do not bother
-            deleting any unreachable code, let jump/flow do that.  */
-         if (NEXT_INSN (insn) != 0
-             && GET_CODE (NEXT_INSN (insn)) != BARRIER)
-           emit_barrier_after (insn);
+         /* Do not bother deleting any unreachable code,
+            let jump/flow do that.  */
 
          cse_jumps_altered = 1;
          sets[i].rtl = 0;
@@ -5890,8 +5775,8 @@ cse_insn (insn, libcall_insn)
   if (src_eqv && src_eqv_elt == 0 && sets[0].rtl != 0 && ! src_eqv_volatile
       && ! rtx_equal_p (src_eqv, SET_DEST (sets[0].rtl)))
     {
-      register struct table_elt *elt;
-      register struct table_elt *classp = sets[0].src_elt;
+      struct table_elt *elt;
+      struct table_elt *classp = sets[0].src_elt;
       rtx dest = SET_DEST (sets[0].rtl);
       enum machine_mode eqvmode = GET_MODE (dest);
 
@@ -5936,9 +5821,9 @@ cse_insn (insn, libcall_insn)
          {
            /* Insert source and constant equivalent into hash table, if not
               already present.  */
-           register struct table_elt *classp = src_eqv_elt;
-           register rtx src = sets[i].src;
-           register rtx dest = SET_DEST (sets[i].rtl);
+           struct table_elt *classp = src_eqv_elt;
+           rtx src = sets[i].src;
+           rtx dest = SET_DEST (sets[i].rtl);
            enum machine_mode mode
              = GET_MODE (src) == VOIDmode ? GET_MODE (dest) : GET_MODE (src);
 
@@ -5947,11 +5832,9 @@ cse_insn (insn, libcall_insn)
                /* Don't put a hard register source into the table if this is
                   the last insn of a libcall.  In this case, we only need
                   to put src_eqv_elt in src_elt.  */
-               if (GET_CODE (src) != REG
-                   || REGNO (src) >= FIRST_PSEUDO_REGISTER
-                   || ! find_reg_note (insn, REG_RETVAL, NULL_RTX))
+               if (! find_reg_note (insn, REG_RETVAL, NULL_RTX))
                  {
-                   register struct table_elt *elt;
+                   struct table_elt *elt;
 
                    /* Note that these insert_regs calls cannot remove
                       any of the src_elt's, because they would have failed to
@@ -5988,7 +5871,7 @@ cse_insn (insn, libcall_insn)
 
   if (GET_CODE (insn) == CALL_INSN)
     {
-      if (! CONST_CALL_P (insn))
+      if (! CONST_OR_PURE_CALL_P (insn))
        invalidate_memory ();
       invalidate_for_call ();
     }
@@ -6003,7 +5886,7 @@ cse_insn (insn, libcall_insn)
       {
        /* We can't use the inner dest, because the mode associated with
           a ZERO_EXTRACT is significant.  */
-       register rtx dest = SET_DEST (sets[i].rtl);
+       rtx dest = SET_DEST (sets[i].rtl);
 
        /* Needed for registers to remove the register from its
           previous quantity's chain.
@@ -6087,7 +5970,7 @@ cse_insn (insn, libcall_insn)
          /* If elt was removed, find current head of same class,
             or 0 if nothing remains of that class.  */
          {
-           register struct table_elt *elt = sets[i].src_elt;
+           struct table_elt *elt = sets[i].src_elt;
 
            while (elt && elt->prev_same_value)
              elt = elt->prev_same_value;
@@ -6103,9 +5986,9 @@ cse_insn (insn, libcall_insn)
   for (i = 0; i < n_sets; i++)
     if (sets[i].rtl)
       {
-       register rtx dest = SET_DEST (sets[i].rtl);
+       rtx dest = SET_DEST (sets[i].rtl);
        rtx inner_dest = sets[i].inner_dest;
-       register struct table_elt *elt;
+       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
@@ -6167,7 +6050,7 @@ cse_insn (insn, libcall_insn)
 
        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,
+                             || fixed_base_plus_p (XEXP (sets[i].inner_dest,
                                                          0))));
 
        /* If we have (set (subreg:m1 (reg:m2 foo) 0) (bar:m1)), M1 is no
@@ -6202,15 +6085,38 @@ cse_insn (insn, libcall_insn)
                rtx new_src = 0;
                unsigned src_hash;
                struct table_elt *src_elt;
+               int byte = 0;
 
                /* Ignore invalid entries.  */
                if (GET_CODE (elt->exp) != REG
                    && ! exp_equiv_p (elt->exp, elt->exp, 1, 0))
                  continue;
 
-               new_src = gen_lowpart_if_possible (new_mode, elt->exp);
-               if (new_src == 0)
-                 new_src = gen_rtx_SUBREG (new_mode, elt->exp, 0);
+               /* We may have already been playing subreg games.  If the
+                  mode is already correct for the destination, use it.  */
+               if (GET_MODE (elt->exp) == new_mode)
+                 new_src = elt->exp;
+               else
+                 {
+                   /* Calculate big endian correction for the SUBREG_BYTE.
+                      We have already checked that M1 (GET_MODE (dest))
+                      is not narrower than M2 (new_mode).  */
+                   if (BYTES_BIG_ENDIAN)
+                     byte = (GET_MODE_SIZE (GET_MODE (dest))
+                             - GET_MODE_SIZE (new_mode));
+
+                   new_src = simplify_gen_subreg (new_mode, elt->exp,
+                                                  GET_MODE (dest), byte);
+                 }
+
+               /* The call to simplify_gen_subreg fails if the value
+                  is VOIDmode, yet we can't do any simplification, e.g.
+                  for EXPR_LISTs denoting function call results.
+                  It is invalid to construct a SUBREG with a VOIDmode
+                  SUBREG_REG, hence a zero new_src means we can't do
+                  this substitution.  */
+               if (! new_src)
+                 continue;
 
                src_hash = HASH (new_src, new_mode);
                src_elt = lookup (new_src, src_hash, new_mode);
@@ -6271,7 +6177,15 @@ cse_insn (insn, libcall_insn)
       if ((src_ent->first_reg == REGNO (SET_DEST (sets[0].rtl)))
          && ! find_reg_note (insn, REG_RETVAL, NULL_RTX))
        {
-         rtx prev = prev_nonnote_insn (insn);
+         rtx prev = insn;
+         /* Scan for the previous nonnote insn, but stop at a basic
+            block boundary.  */
+         do
+           {
+             prev = PREV_INSN (prev);
+           }
+         while (prev && GET_CODE (prev) == NOTE
+                && NOTE_LINE_NUMBER (prev) != NOTE_INSN_BASIC_BLOCK);
 
          /* Do not swap the registers around if the previous instruction
             attaches a REG_EQUIV note to REG1.
@@ -6283,7 +6197,7 @@ cse_insn (insn, libcall_insn)
 
             This section previously turned the REG_EQUIV into a REG_EQUAL
             note.  We cannot do that because REG_EQUIV may provide an
-            uninitialised stack slot when REG_PARM_STACK_SPACE is used. */
+            uninitialized stack slot when REG_PARM_STACK_SPACE is used.  */
 
          if (prev != 0 && GET_CODE (prev) == INSN
              && GET_CODE (PATTERN (prev)) == SET
@@ -6299,20 +6213,6 @@ cse_insn (insn, libcall_insn)
              validate_change (insn, &SET_SRC (sets[0].rtl), dest, 1);
              apply_change_group ();
 
-             /* If there was a REG_WAS_0 note on PREV, remove it.  Move
-                any REG_WAS_0 note on INSN to PREV.  */
-             note = find_reg_note (prev, REG_WAS_0, NULL_RTX);
-             if (note)
-               remove_note (prev, note);
-
-             note = find_reg_note (insn, REG_WAS_0, NULL_RTX);
-             if (note)
-               {
-                 remove_note (insn, note);
-                 XEXP (note, 1) = REG_NOTES (prev);
-                 REG_NOTES (prev) = note;
-               }
-
              /* If INSN has a REG_EQUAL note, and this note mentions
                 REG0, then we must delete it, because the value in
                 REG0 has changed.  If the note's value is REG1, we must
@@ -6343,26 +6243,21 @@ cse_insn (insn, libcall_insn)
       && (tem = single_set (prev_insn)) != 0
       && SET_DEST (tem) == cc0_rtx
       && ! reg_mentioned_p (cc0_rtx, x))
-    {
-      PUT_CODE (prev_insn, NOTE);
-      NOTE_LINE_NUMBER (prev_insn) = NOTE_INSN_DELETED;
-      NOTE_SOURCE_FILE (prev_insn) = 0;
-    }
+    delete_insn (prev_insn);
 
   prev_insn_cc0 = this_insn_cc0;
   prev_insn_cc0_mode = this_insn_cc0_mode;
-#endif
-
   prev_insn = insn;
+#endif
 }
 \f
 /* Remove from the hash table all expressions that reference memory.  */
 
 static void
-invalidate_memory ()
+invalidate_memory (void)
 {
-  register int i;
-  register struct table_elt *p, *next;
+  int i;
+  struct table_elt *p, *next;
 
   for (i = 0; i < HASH_SIZE; i++)
     for (p = table[i]; p; p = next)
@@ -6377,15 +6272,18 @@ invalidate_memory ()
    1 and update the register tables to show the effect.  Else, return 0.  */
 
 static int
-addr_affects_sp_p (addr)
-     register rtx addr;
+addr_affects_sp_p (rtx addr)
 {
   if (GET_RTX_CLASS (GET_CODE (addr)) == 'a'
       && GET_CODE (XEXP (addr, 0)) == REG
       && REGNO (XEXP (addr, 0)) == STACK_POINTER_REGNUM)
     {
       if (REG_TICK (STACK_POINTER_REGNUM) >= 0)
-       REG_TICK (STACK_POINTER_REGNUM)++;
+       {
+         REG_TICK (STACK_POINTER_REGNUM)++;
+         /* Is it possible to use a subreg of SP?  */
+         SUBREG_TICKED (STACK_POINTER_REGNUM) = -1;
+       }
 
       /* This should be *very* rare.  */
       if (TEST_HARD_REG_BIT (hard_regs_in_table, STACK_POINTER_REGNUM))
@@ -6405,8 +6303,7 @@ addr_affects_sp_p (addr)
    X is the pattern of the insn.  */
 
 static void
-invalidate_from_clobbers (x)
-     rtx x;
+invalidate_from_clobbers (rtx x)
 {
   if (GET_CODE (x) == CLOBBER)
     {
@@ -6423,10 +6320,10 @@ invalidate_from_clobbers (x)
     }
   else if (GET_CODE (x) == PARALLEL)
     {
-      register int i;
+      int i;
       for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
        {
-         register rtx y = XVECEXP (x, 0, i);
+         rtx y = XVECEXP (x, 0, i);
          if (GET_CODE (y) == CLOBBER)
            {
              rtx ref = XEXP (y, 0);
@@ -6451,9 +6348,7 @@ invalidate_from_clobbers (x)
    Return the replacement for X.  */
 
 static rtx
-cse_process_notes (x, object)
-     rtx x;
-     rtx object;
+cse_process_notes (rtx x, rtx object)
 {
   enum rtx_code code = GET_CODE (x);
   const char *fmt = GET_RTX_FORMAT (code);
@@ -6466,13 +6361,15 @@ cse_process_notes (x, object)
     case SYMBOL_REF:
     case LABEL_REF:
     case CONST_DOUBLE:
+    case CONST_VECTOR:
     case PC:
     case CC0:
     case LO_SUM:
       return x;
 
     case MEM:
-      XEXP (x, 0) = cse_process_notes (XEXP (x, 0), x);
+      validate_change (x, &XEXP (x, 0),
+                      cse_process_notes (XEXP (x, 0), x), 0);
       return x;
 
     case EXPR_LIST:
@@ -6543,8 +6440,7 @@ cse_process_notes (x, object)
    jumps to a label used only once.  */
 
 static void
-cse_around_loop (loop_start)
-     rtx loop_start;
+cse_around_loop (rtx loop_start)
 {
   rtx insn;
   int i;
@@ -6615,10 +6511,7 @@ cse_around_loop (loop_start)
    since they are done elsewhere.  This function is called via note_stores.  */
 
 static void
-invalidate_skipped_set (dest, set, data)
-     rtx set;
-     rtx dest;
-     void *data ATTRIBUTE_UNUSED;
+invalidate_skipped_set (rtx dest, rtx set, void *data ATTRIBUTE_UNUSED)
 {
   enum rtx_code code = GET_CODE (dest);
 
@@ -6637,9 +6530,7 @@ invalidate_skipped_set (dest, set, data)
     }
 
   if (GET_CODE (set) == CLOBBER
-#ifdef HAVE_cc0
-      || dest == cc0_rtx
-#endif
+      || CC0_P (dest)
       || dest == pc_rtx)
     return;
 
@@ -6654,8 +6545,7 @@ invalidate_skipped_set (dest, set, data)
    conditionally executed.  */
 
 static void
-invalidate_skipped_block (start)
-     rtx start;
+invalidate_skipped_block (rtx start)
 {
   rtx insn;
 
@@ -6667,7 +6557,7 @@ invalidate_skipped_block (start)
 
       if (GET_CODE (insn) == CALL_INSN)
        {
-         if (! CONST_CALL_P (insn))
+         if (! CONST_OR_PURE_CALL_P (insn))
            invalidate_memory ();
          invalidate_for_call ();
        }
@@ -6682,10 +6572,7 @@ invalidate_skipped_block (start)
    NULL_RTX.  */
 
 static void
-cse_check_loop_start (x, set, data)
-     rtx x;
-     rtx set ATTRIBUTE_UNUSED;
-     void *data;
+cse_check_loop_start (rtx x, rtx set ATTRIBUTE_UNUSED, void *data)
 {
   rtx *cse_check_loop_start_value = (rtx *) data;
 
@@ -6716,10 +6603,7 @@ cse_check_loop_start (x, set, data)
    In any event, we invalidate whatever this SET or CLOBBER modifies.  */
 
 static void
-cse_set_around_loop (x, insn, loop_start)
-     rtx x;
-     rtx insn;
-     rtx loop_start;
+cse_set_around_loop (rtx x, rtx insn, rtx loop_start)
 {
   struct table_elt *src_elt;
 
@@ -6771,6 +6655,8 @@ cse_set_around_loop (x, insn, loop_start)
                       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))
                      {
@@ -6789,7 +6675,19 @@ cse_set_around_loop (x, insn, loop_start)
                              abort ();
                          }
                        else
-                         emit_insn_after (move, p);
+                         {
+                           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;
                  }
@@ -6813,10 +6711,10 @@ cse_set_around_loop (x, insn, loop_start)
    the total number of SETs in all the insns of the block, the last insn of the
    block, and the branch path.
 
-   The branch path indicates which branches should be followed.  If a non-zero
+   The branch path indicates which branches should be followed.  If a nonzero
    path size is specified, the block should be rescanned and a different set
    of branches will be taken.  The branch path is only used if
-   FLAG_CSE_FOLLOW_JUMPS or FLAG_CSE_SKIP_BLOCKS is non-zero.
+   FLAG_CSE_FOLLOW_JUMPS or FLAG_CSE_SKIP_BLOCKS is nonzero.
 
    DATA is a pointer to a struct cse_basic_block_data, defined below, that is
    used to describe the block.  It is filled in with the information about
@@ -6824,12 +6722,8 @@ cse_set_around_loop (x, insn, loop_start)
    to construct the output branch path.  */
 
 void
-cse_end_of_basic_block (insn, data, follow_jumps, after_loop, skip_blocks)
-     rtx insn;
-     struct cse_basic_block_data *data;
-     int follow_jumps;
-     int after_loop;
-     int skip_blocks;
+cse_end_of_basic_block (rtx insn, struct cse_basic_block_data *data,
+                       int follow_jumps, int after_loop, int skip_blocks)
 {
   rtx p = insn, q;
   int nsets = 0;
@@ -6842,7 +6736,7 @@ cse_end_of_basic_block (insn, data, follow_jumps, after_loop, skip_blocks)
   /* Update the previous branch path, if any.  If the last branch was
      previously TAKEN, mark it NOT_TAKEN.  If it was previously 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 non-zero.  */
+     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)
@@ -6883,11 +6777,11 @@ cse_end_of_basic_block (insn, data, follow_jumps, after_loop, skip_blocks)
          && NOTE_LINE_NUMBER (p) == NOTE_INSN_LOOP_END)
        break;
 
-      /* Don't cse over a call to setjmp; on some machines (eg vax)
+      /* 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 (GET_CODE (p) == NOTE
-         && NOTE_LINE_NUMBER (p) == NOTE_INSN_SETJMP)
+      if (PREV_INSN (p) && GET_CODE (PREV_INSN (p)) == CALL_INSN
+         && find_reg_note (PREV_INSN (p), REG_SETJMP, NULL))
        break;
 
       /* A PARALLEL can have lots of SETs in it,
@@ -6926,7 +6820,7 @@ cse_end_of_basic_block (insn, data, follow_jumps, after_loop, skip_blocks)
         In this case invalidate_skipped_block will be called to invalidate any
         registers set in the block when following the jump.  */
 
-      else if ((follow_jumps || skip_blocks) && path_size < PATHLENGTH - 1
+      else if ((follow_jumps || skip_blocks) && path_size < PARAM_VALUE (PARAM_MAX_CSE_PATH_LENGTH) - 1
               && GET_CODE (p) == JUMP_INSN
               && GET_CODE (PATTERN (p)) == SET
               && GET_CODE (SET_SRC (PATTERN (p))) == IF_THEN_ELSE
@@ -6937,7 +6831,8 @@ cse_end_of_basic_block (insn, data, follow_jumps, after_loop, skip_blocks)
          for (q = PREV_INSN (JUMP_LABEL (p)); q; q = PREV_INSN (q))
            if ((GET_CODE (q) != NOTE
                 || NOTE_LINE_NUMBER (q) == NOTE_INSN_LOOP_END
-                || NOTE_LINE_NUMBER (q) == NOTE_INSN_SETJMP)
+                || (PREV_INSN (q) && GET_CODE (PREV_INSN (q)) == CALL_INSN
+                    && find_reg_note (PREV_INSN (q), REG_SETJMP, NULL)))
                && (GET_CODE (q) != CODE_LABEL || LABEL_NUSES (q) != 0))
              break;
 
@@ -6977,7 +6872,7 @@ cse_end_of_basic_block (insn, data, follow_jumps, after_loop, skip_blocks)
          /* Detect a branch around a block of code.  */
          else if (skip_blocks && q != 0 && GET_CODE (q) != CODE_LABEL)
            {
-             register rtx tmp;
+             rtx tmp;
 
              if (next_real_insn (q) == next)
                {
@@ -7045,19 +6940,19 @@ cse_end_of_basic_block (insn, data, follow_jumps, after_loop, skip_blocks)
    in conditional jump instructions.  */
 
 int
-cse_main (f, nregs, after_loop, file)
-     rtx f;
-     int nregs;
-     int after_loop;
-     FILE *file;
+cse_main (rtx f, int nregs, int after_loop, FILE *file)
 {
   struct cse_basic_block_data val;
-  register rtx insn = f;
-  register int i;
+  rtx insn = f;
+  int i;
+
+  val.path = xmalloc (sizeof (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;
 
   init_recog ();
@@ -7067,8 +6962,7 @@ cse_main (f, nregs, after_loop, file)
 
   max_insn_uid = get_max_uid ();
 
-  reg_eqv_table = (struct reg_eqv_elem *)
-    xmalloc (nregs * sizeof (struct reg_eqv_elem));
+  reg_eqv_table = xmalloc (nregs * sizeof (struct reg_eqv_elem));
 
 #ifdef LOAD_EXTEND_OP
 
@@ -7084,7 +6978,7 @@ cse_main (f, nregs, after_loop, file)
   /* Find the largest uid.  */
 
   max_uid = get_max_uid ();
-  uid_cuid = (int *) xcalloc (max_uid + 1, sizeof (int));
+  uid_cuid = xcalloc (max_uid + 1, sizeof (int));
 
   /* Compute the mapping from uids to cuids.
      CUIDs are numbers assigned to insns, like uids,
@@ -7102,37 +6996,6 @@ cse_main (f, nregs, after_loop, file)
        INSN_CUID (insn) = i;
     }
 
-  /* Initialize which registers are clobbered by calls.  */
-
-  CLEAR_HARD_REG_SET (regs_invalidated_by_call);
-
-  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-    if ((call_used_regs[i]
-        /* Used to check !fixed_regs[i] here, but that isn't safe;
-           fixed regs are still call-clobbered, and sched can get
-           confused if they can "live across calls".
-
-           The frame pointer is always preserved across calls.  The arg
-           pointer is if it is fixed.  The stack pointer usually is, unless
-           RETURN_POPS_ARGS, in which case an explicit CLOBBER
-           will be present.  If we are generating PIC code, the PIC offset
-           table register is preserved across calls.  */
-
-        && i != STACK_POINTER_REGNUM
-        && i != FRAME_POINTER_REGNUM
-#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
-        && i != HARD_FRAME_POINTER_REGNUM
-#endif
-#if ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
-        && ! (i == ARG_POINTER_REGNUM && fixed_regs[i])
-#endif
-#if !defined (PIC_OFFSET_TABLE_REG_CALL_CLOBBERED)
-        && ! (i == PIC_OFFSET_TABLE_REGNUM && flag_pic)
-#endif
-        )
-       || global_regs[i])
-      SET_HARD_REG_BIT (regs_invalidated_by_call, i);
-
   ggc_push_context ();
 
   /* Loop over basic blocks.
@@ -7209,6 +7072,7 @@ cse_main (f, nregs, after_loop, file)
   end_alias_analysis ();
   free (uid_cuid);
   free (reg_eqv_table);
+  free (val.path);
 
   return cse_jumps_altered || recorded_label_ref;
 }
@@ -7217,17 +7081,15 @@ cse_main (f, nregs, after_loop, file)
    block.  NEXT_BRANCH points to the branch path when following jumps or
    a null path when not following jumps.
 
-   AROUND_LOOP is non-zero if we are to try to cse around to the start of a
+   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.  */
 
 static rtx
-cse_basic_block (from, to, next_branch, around_loop)
-     register rtx from, to;
-     struct branch_path *next_branch;
-     int around_loop;
+cse_basic_block (rtx from, rtx to, struct branch_path *next_branch,
+                int around_loop)
 {
-  register rtx insn;
+  rtx insn;
   int to_usage = 0;
   rtx libcall_insn = NULL_RTX;
   int num_insns = 0;
@@ -7235,9 +7097,7 @@ cse_basic_block (from, to, next_branch, around_loop)
   /* This array is undefined before max_reg, so only allocate
      the space actually needed and adjust the start.  */
 
-  qty_table
-    = (struct qty_table_elem *) xmalloc ((max_qty - max_reg)
-                                        * sizeof (struct qty_table_elem));
+  qty_table = xmalloc ((max_qty - max_reg) * sizeof (struct qty_table_elem));
   qty_table -= max_reg;
 
   new_basic_block ();
@@ -7248,7 +7108,7 @@ cse_basic_block (from, to, next_branch, around_loop)
 
   for (insn = from; insn != to; insn = NEXT_INSN (insn))
     {
-      register enum rtx_code code = GET_CODE (insn);
+      enum rtx_code code = GET_CODE (insn);
 
       /* If we have processed 1,000 insns, flush the hash table to
         avoid extreme quadratic behavior.  We must not include NOTEs
@@ -7281,8 +7141,8 @@ cse_basic_block (from, to, next_branch, around_loop)
                 Then follow this branch.  */
 #ifdef HAVE_cc0
              prev_insn_cc0 = 0;
-#endif
              prev_insn = insn;
+#endif
              insn = JUMP_LABEL (insn);
              continue;
            }
@@ -7315,16 +7175,13 @@ cse_basic_block (from, to, next_branch, around_loop)
                libcall_insn = 0;
            }
 
-         new_label_ref = 0;
          cse_insn (insn, libcall_insn);
 
-         /* If this insn uses a LABEL_REF and there isn't a REG_LABEL
-            note for it, we must rerun jump since it needs to place the
-            note.  If this is a LABEL_REF for a CODE_LABEL that isn't in
-            the insn chain, don't do this since no REG_LABEL will be added. */
-         if (new_label_ref != 0 && INSN_UID (XEXP (new_label_ref, 0)) != 0
-             && reg_mentioned_p (new_label_ref, PATTERN (insn))
-             && ! find_reg_note (insn, REG_LABEL, XEXP (new_label_ref, 0)))
+         /* 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
+             && for_each_rtx (&PATTERN (insn), check_for_label_ref,
+                              (void *) insn))
            recorded_label_ref = 1;
        }
 
@@ -7389,7 +7246,10 @@ cse_basic_block (from, to, next_branch, around_loop)
             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);
+         free (val.path);
 
          /* If the tables we allocated have enough space left
             to handle all the SETs in the next basic block,
@@ -7419,36 +7279,49 @@ cse_basic_block (from, to, next_branch, around_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.  */
 
+  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 (PREV_INSN (to)) == JUMP_INSN
-      && JUMP_LABEL (PREV_INSN (to)) != 0
-      && LABEL_NUSES (JUMP_LABEL (PREV_INSN (to))) == 1)
-    cse_around_loop (JUMP_LABEL (PREV_INSN (to)));
+      && 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);
 
   return to ? NEXT_INSN (to) : 0;
 }
 \f
+/* Called via for_each_rtx to see if an insn is using a LABEL_REF for which
+   there isn't a REG_LABEL note.  Return one if so.  DATA is the insn.  */
+
+static int
+check_for_label_ref (rtx *rtl, void *data)
+{
+  rtx insn = (rtx) data;
+
+  /* If this insn uses a LABEL_REF and there isn't a REG_LABEL note for it,
+     we must rerun jump since it needs to place the note.  If this is a
+     LABEL_REF for a CODE_LABEL that isn't in the insn chain, don't do this
+     since no REG_LABEL will be added.  */
+  return (GET_CODE (*rtl) == LABEL_REF
+         && ! LABEL_REF_NONLOCAL_P (*rtl)
+         && LABEL_P (XEXP (*rtl, 0))
+         && INSN_UID (XEXP (*rtl, 0)) != 0
+         && ! find_reg_note (insn, REG_LABEL, XEXP (*rtl, 0)));
+}
+\f
 /* Count the number of times registers are used (not set) in X.
    COUNTS is an array in which we accumulate the count, INCR is how much
-   we count each register usage.
-
-   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.  */
+   we count each register usage.  */
 
 static void
-count_reg_usage (x, counts, dest, incr)
-     rtx x;
-     int *counts;
-     rtx dest;
-     int incr;
+count_reg_usage (rtx x, int *counts, int incr)
 {
   enum rtx_code code;
+  rtx note;
   const char *fmt;
   int i, j;
 
@@ -7458,8 +7331,7 @@ count_reg_usage (x, counts, dest, incr)
   switch (code = GET_CODE (x))
     {
     case REG:
-      if (x != dest)
-       counts[REGNO (x)] += incr;
+      counts[REGNO (x)] += incr;
       return;
 
     case PC:
@@ -7467,6 +7339,7 @@ count_reg_usage (x, counts, dest, incr)
     case CONST:
     case CONST_INT:
     case CONST_DOUBLE:
+    case CONST_VECTOR:
     case SYMBOL_REF:
     case LABEL_REF:
       return;
@@ -7475,47 +7348,66 @@ count_reg_usage (x, counts, dest, incr)
       /* 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, NULL_RTX, incr);
+       count_reg_usage (XEXP (XEXP (x, 0), 0), counts, 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, NULL_RTX, incr);
-
-      /* If SRC has side-effects, then we can't delete this insn, so the
-        usage of SET_DEST inside SRC counts.
-
-        ??? Strictly-speaking, we might be preserving this insn
-        because some other SET has side-effects, but that's hard
-        to do and can't happen now.  */
-      count_reg_usage (SET_SRC (x), counts,
-                      side_effects_p (SET_SRC (x)) ? NULL_RTX : SET_DEST (x),
-                      incr);
+       count_reg_usage (SET_DEST (x), counts, incr);
+      count_reg_usage (SET_SRC (x), counts, incr);
       return;
 
     case CALL_INSN:
-      count_reg_usage (CALL_INSN_FUNCTION_USAGE (x), counts, NULL_RTX, incr);
+      count_reg_usage (CALL_INSN_FUNCTION_USAGE (x), counts, incr);
       /* Fall through.  */
 
     case INSN:
     case JUMP_INSN:
-      count_reg_usage (PATTERN (x), counts, NULL_RTX, incr);
+      count_reg_usage (PATTERN (x), counts, incr);
 
       /* Things used in a REG_EQUAL note aren't dead since loop may try to
         use them.  */
 
-      count_reg_usage (REG_NOTES (x), counts, NULL_RTX, incr);
+      note = find_reg_equal_equiv_note (x);
+      if (note)
+       {
+         rtx eqv = XEXP (note, 0);
+
+         if (GET_CODE (eqv) == EXPR_LIST)
+         /* This REG_EQUAL note describes the result of a function call.
+            Process all the arguments.  */
+           do
+             {
+               count_reg_usage (XEXP (eqv, 0), counts, incr);
+               eqv = XEXP (eqv, 1);
+             }
+           while (eqv && GET_CODE (eqv) == EXPR_LIST);
+         else
+           count_reg_usage (eqv, counts, incr);
+       }
       return;
 
     case EXPR_LIST:
-    case INSN_LIST:
       if (REG_NOTE_KIND (x) == REG_EQUAL
-         || (REG_NOTE_KIND (x) != REG_NONNEG && GET_CODE (XEXP (x,0)) == USE))
-       count_reg_usage (XEXP (x, 0), counts, NULL_RTX, incr);
-      count_reg_usage (XEXP (x, 1), counts, NULL_RTX, incr);
+         || (REG_NOTE_KIND (x) != REG_NONNEG && GET_CODE (XEXP (x,0)) == USE)
+         /* 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, 1), counts, incr);
+      return;
+
+    case ASM_OPERANDS:
+      /* 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);
       return;
 
+    case INSN_LIST:
+      abort ();
+
     default:
       break;
     }
@@ -7524,13 +7416,127 @@ count_reg_usage (x, counts, dest, incr)
   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
     {
       if (fmt[i] == 'e')
-       count_reg_usage (XEXP (x, i), counts, dest, incr);
+       count_reg_usage (XEXP (x, i), counts, incr);
       else if (fmt[i] == 'E')
        for (j = XVECLEN (x, i) - 1; j >= 0; j--)
-         count_reg_usage (XVECEXP (x, i, j), counts, dest, incr);
+         count_reg_usage (XVECEXP (x, i, j), counts, incr);
     }
 }
 \f
+/* Return true if set is live.  */
+static bool
+set_live_p (rtx set, rtx insn ATTRIBUTE_UNUSED, /* Only used with HAVE_cc0.  */
+           int *counts)
+{
+#ifdef HAVE_cc0
+  rtx tem;
+#endif
+
+  if (set_noop_p (set))
+    ;
+
+#ifdef HAVE_cc0
+  else if (GET_CODE (SET_DEST (set)) == CC0
+          && !side_effects_p (SET_SRC (set))
+          && ((tem = next_nonnote_insn (insn)) == 0
+              || !INSN_P (tem)
+              || !reg_referenced_p (cc0_rtx, PATTERN (tem))))
+    return false;
+#endif
+  else if (GET_CODE (SET_DEST (set)) != REG
+          || 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))
+    return true;
+  return false;
+}
+
+/* Return true if insn is live.  */
+
+static bool
+insn_live_p (rtx insn, int *counts)
+{
+  int i;
+  if (flag_non_call_exceptions && may_trap_p (PATTERN (insn)))
+    return true;
+  else if (GET_CODE (PATTERN (insn)) == SET)
+    return set_live_p (PATTERN (insn), insn, counts);
+  else if (GET_CODE (PATTERN (insn)) == PARALLEL)
+    {
+      for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
+       {
+         rtx elt = XVECEXP (PATTERN (insn), 0, i);
+
+         if (GET_CODE (elt) == SET)
+           {
+             if (set_live_p (elt, insn, counts))
+               return true;
+           }
+         else if (GET_CODE (elt) != CLOBBER && GET_CODE (elt) != USE)
+           return true;
+       }
+      return false;
+    }
+  else
+    return true;
+}
+
+/* Return true if libcall is dead as a whole.  */
+
+static bool
+dead_libcall_p (rtx insn, int *counts)
+{
+  rtx note, set, new;
+
+  /* See if there's a REG_EQUAL note on this insn and try to
+     replace the source with the REG_EQUAL expression.
+
+     We assume that insns with REG_RETVALs can only be reg->reg
+     copies at this point.  */
+  note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
+  if (!note)
+    return false;
+
+  set = single_set (insn);
+  if (!set)
+    return false;
+
+  new = simplify_rtx (XEXP (note, 0));
+  if (!new)
+    new = XEXP (note, 0);
+
+  /* While changing insn, we must update the counts accordingly.  */
+  count_reg_usage (insn, counts, -1);
+
+  if (validate_change (insn, &SET_SRC (set), new, 0))
+    {
+      count_reg_usage (insn, counts, 1);
+      remove_note (insn, find_reg_note (insn, REG_RETVAL, NULL_RTX));
+      remove_note (insn, note);
+      return true;
+    }
+
+  if (CONSTANT_P (new))
+    {
+      new = force_const_mem (GET_MODE (SET_DEST (set)), new);
+      if (new && validate_change (insn, &SET_SRC (set), new, 0))
+       {
+         count_reg_usage (insn, counts, 1);
+         remove_note (insn, find_reg_note (insn, REG_RETVAL, NULL_RTX));
+         remove_note (insn, note);
+         return true;
+       }
+    }
+
+  count_reg_usage (insn, counts, 1);
+  return false;
+}
+
 /* Scan all the insns and delete any that are dead; i.e., they store a register
    that is never used or they copy a register to itself.
 
@@ -7539,163 +7545,81 @@ count_reg_usage (x, counts, dest, incr)
    move dead invariants out of loops or make givs for dead quantities.  The
    remaining passes of the compilation are also sped up.  */
 
-void
-delete_trivially_dead_insns (insns, nreg)
-     rtx insns;
-     int nreg;
+int
+delete_trivially_dead_insns (rtx insns, int nreg)
 {
   int *counts;
   rtx insn, prev;
-#ifdef HAVE_cc0
-  rtx tem;
-#endif
-  int i;
   int in_libcall = 0, dead_libcall = 0;
+  int ndead = 0, nlastdead, niterations = 0;
 
+  timevar_push (TV_DELETE_TRIVIALLY_DEAD);
   /* First count the number of times each register is used.  */
-  counts = (int *) xcalloc (nreg, sizeof (int));
+  counts = xcalloc (nreg, sizeof (int));
   for (insn = next_real_insn (insns); insn; insn = next_real_insn (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.   */
-  insn = get_last_insn ();
-  if (! INSN_P (insn))
-    insn = prev_real_insn (insn);
+    count_reg_usage (insn, counts, 1);
 
-  for (; insn; insn = prev)
+  do
     {
-      int live_insn = 0;
-      rtx note;
-
-      prev = prev_real_insn (insn);
-
-      /* Don't delete any insns that are part of a libcall block unless
-        we can delete the whole libcall block.
+      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);
 
-        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))
+      for (; insn; insn = prev)
        {
-         in_libcall = 1;
-         live_insn = 1;
-         dead_libcall = 0;
+         int live_insn = 0;
 
-         /* See if there's a REG_EQUAL note on this insn and try to
-            replace the source with the REG_EQUAL expression.
+         prev = prev_real_insn (insn);
 
-            We assume that insns with REG_RETVALs can only be reg->reg
-            copies at this point.  */
-         note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
-         if (note)
-           {
-             rtx set = single_set (insn);
-             rtx new = simplify_rtx (XEXP (note, 0));
-
-             if (!new)
-               new = XEXP (note, 0);
+         /* Don't delete any insns that are part of a libcall block unless
+            we can delete the whole libcall block.
 
-             if (set && validate_change (insn, &SET_SRC (set), new, 0))
-               {
-                 remove_note (insn,
-                              find_reg_note (insn, REG_RETVAL, NULL_RTX));
-                 dead_libcall = 1;
-               }
-           }
-       }
-      else if (in_libcall)
-       live_insn = ! dead_libcall;
-      else if (GET_CODE (PATTERN (insn)) == SET)
-       {
-         if ((GET_CODE (SET_DEST (PATTERN (insn))) == REG
-              || GET_CODE (SET_DEST (PATTERN (insn))) == SUBREG)
-             && rtx_equal_p (SET_DEST (PATTERN (insn)),
-                             SET_SRC (PATTERN (insn))))
-           ;
-         else if (GET_CODE (SET_DEST (PATTERN (insn))) == STRICT_LOW_PART
-                  && rtx_equal_p (XEXP (SET_DEST (PATTERN (insn)), 0),
-                                  SET_SRC (PATTERN (insn))))
-           ;
-
-#ifdef HAVE_cc0
-         else if (GET_CODE (SET_DEST (PATTERN (insn))) == CC0
-                  && ! side_effects_p (SET_SRC (PATTERN (insn)))
-                  && ((tem = next_nonnote_insn (insn)) == 0
-                      || ! INSN_P (tem)
-                      || ! reg_referenced_p (cc0_rtx, PATTERN (tem))))
-           ;
-#endif
-         else if (GET_CODE (SET_DEST (PATTERN (insn))) != REG
-                  || REGNO (SET_DEST (PATTERN (insn))) < FIRST_PSEUDO_REGISTER
-                  || counts[REGNO (SET_DEST (PATTERN (insn)))] != 0
-                  || side_effects_p (SET_SRC (PATTERN (insn)))
-                  /* 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 (PATTERN (insn))
-                      == current_function_internal_arg_pointer))
-           live_insn = 1;
-       }
-      else if (GET_CODE (PATTERN (insn)) == PARALLEL)
-       for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
-         {
-           rtx elt = XVECEXP (PATTERN (insn), 0, i);
-
-           if (GET_CODE (elt) == SET)
-             {
-               if ((GET_CODE (SET_DEST (elt)) == REG
-                    || GET_CODE (SET_DEST (elt)) == SUBREG)
-                   && rtx_equal_p (SET_DEST (elt), SET_SRC (elt)))
-                 ;
-
-#ifdef HAVE_cc0
-               else if (GET_CODE (SET_DEST (elt)) == CC0
-                        && ! side_effects_p (SET_SRC (elt))
-                        && ((tem = next_nonnote_insn (insn)) == 0
-                            || ! INSN_P (tem)
-                            || ! reg_referenced_p (cc0_rtx, PATTERN (tem))))
-                 ;
-#endif
-               else if (GET_CODE (SET_DEST (elt)) != REG
-                        || REGNO (SET_DEST (elt)) < FIRST_PSEUDO_REGISTER
-                        || counts[REGNO (SET_DEST (elt))] != 0
-                        || side_effects_p (SET_SRC (elt))
-                        /* 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 (elt)
-                            == current_function_internal_arg_pointer))
-                 live_insn = 1;
-             }
-           else if (GET_CODE (elt) != CLOBBER && GET_CODE (elt) != USE)
+            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;
-         }
-      else
-       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, NULL_RTX, -1);
-         delete_insn (insn);
-       }
+         if (! live_insn)
+           {
+             count_reg_usage (insn, counts, -1);
+             delete_insn_and_edges (insn);
+             ndead++;
+           }
 
-      if (find_reg_note (insn, REG_LIBCALL, NULL_RTX))
-       {
-         in_libcall = 0;
-         dead_libcall = 0;
+         if (find_reg_note (insn, REG_LIBCALL, NULL_RTX))
+           {
+             in_libcall = 0;
+             dead_libcall = 0;
+           }
        }
     }
+  while (ndead != nlastdead);
 
+  if (rtl_dump_file && ndead)
+    fprintf (rtl_dump_file, "Deleted %i trivially dead insns; %i iterations\n",
+            ndead, niterations);
   /* Clean up.  */
   free (counts);
+  timevar_pop (TV_DELETE_TRIVIALLY_DEAD);
+  return ndead;
 }