OSDN Git Service

* cppinit.c (cpp_start_read): Free the imacros list as we
[pf3gnuchains/gcc-fork.git] / gcc / cse.c
index f7f5bd4..a870919 100644 (file)
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -1,33 +1,33 @@
 /* Common subexpression elimination for GNU compiler.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998
-   1999, 2000 Free Software Foundation, Inc.
+   1999, 2000, 2001 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 "rtl.h"
 #include "tm_p.h"
 #include "regs.h"
 #include "hard-reg-set.h"
+#include "basic-block.h"
 #include "flags.h"
 #include "real.h"
 #include "insn-config.h"
@@ -345,11 +345,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;
@@ -381,9 +376,8 @@ static int cse_altered;
 
 static int cse_jumps_altered;
 
-/* Nonzero if we put a LABEL_REF into the hash table.  Since we may have put
-   it into an INSN without a REG_LABEL, we have to rerun jump after CSE
-   to put in the note.  */
+/* Nonzero if we put a LABEL_REF into the hash table for an INSN without a
+   REG_LABEL, we have to rerun jump after CSE to put in the note.  */
 static int recorded_label_ref;
 
 /* canon_hash stores 1 in do_not_record
@@ -434,6 +428,8 @@ static int hash_arg_in_memory;
    chain is not useful.
 
    The `cost' field stores the cost of this element's expression.
+   The `regcost' field stores the value returned by approx_reg_cost for
+   this element's expression.
 
    The `is_const' flag is set if the element is a constant (including
    a fixed address).
@@ -456,6 +452,7 @@ struct table_elt
   struct table_elt *first_same_value;
   struct table_elt *related_value;
   int cost;
+  int regcost;
   enum machine_mode mode;
   char in_memory;
   char is_const;
@@ -477,7 +474,8 @@ struct table_elt
   ? (((unsigned) REG << 7) + (unsigned) REG_QTY (REGNO (X)))   \
   : canon_hash (X, M)) & HASH_MASK)
 
-/* Determine whether register number N is considered a fixed register for CSE.
+/* Determine whether register number N is considered a fixed register for the
+   purpose of approximating register costs.
    It is desirable to replace other regs with fixed regs, to reduce need for
    non-fixed hard regs.
    A reg wins if it is either the frame pointer or designated as fixed.  */
@@ -497,19 +495,8 @@ struct table_elt
    || ((N) < FIRST_PSEUDO_REGISTER                                     \
        && FIXED_REGNO_P (N) && REGNO_REG_CLASS (N) != NO_REGS))
 
-/* A register is cheap if it is a user variable assigned to the register
-   or if its register number always corresponds to a cheap register.  */
-
-#define CHEAP_REG(N) \
-  ((REG_USERVAR_P (N) && REGNO (N) < FIRST_PSEUDO_REGISTER)    \
-   || CHEAP_REGNO (REGNO (N)))
-
-#define COST(X)                                                                \
-  (GET_CODE (X) == REG                                                 \
-   ? (CHEAP_REG (X) ? 0                                                        \
-      : REGNO (X) >= FIRST_PSEUDO_REGISTER ? 1                         \
-      : 2)                                                             \
-   : notreg_cost(X))
+#define COST(X) (GET_CODE (X) == REG ? 0 : notreg_cost (X, SET))
+#define COST_IN(X,OUTER) (GET_CODE (X) == REG ? 0 : notreg_cost (X, OUTER))
 
 /* Get the info associated with register N.  */
 
@@ -643,7 +630,10 @@ struct cse_basic_block_data
           || XEXP (X, 0) == virtual_outgoing_args_rtx))        \
    || GET_CODE (X) == ADDRESSOF)
 
-static int notreg_cost         PARAMS ((rtx));
+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));
@@ -659,7 +649,7 @@ static struct table_elt *insert PARAMS ((rtx, struct table_elt *, unsigned,
 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));
+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));
@@ -668,6 +658,7 @@ 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));
@@ -691,11 +682,15 @@ 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));
+static int check_for_label_ref PARAMS ((rtx *, void *));
 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));
+static bool insn_live_p                PARAMS ((rtx, int *));
+static bool set_live_p         PARAMS ((rtx, rtx, int *));
+static bool dead_libcall_p     PARAMS ((rtx));
 \f
 /* Dump the expressions in the equivalence class indicated by CLASSP.
    This function is used only for debugging.  */
@@ -716,12 +711,97 @@ 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;
+{
+  rtx x = *xp;
+  regset set = (regset) data;
+
+  if (x && GET_CODE (x) == REG)
+    SET_REGNO_REG_SET (set, REGNO (x));
+  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
+   0.  If any other hard register reference occurs, return MAX_COST.  */
+
+static int
+approx_reg_cost (x)
+     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++;
+
+          cost += i < FIRST_PSEUDO_REGISTER ? 2 : 1;
+        }
+     });
+
+  CLEAR_REG_SET (&set);
+  return hardregs && SMALL_REGISTER_CLASSES ? MAX_COST : cost;
+}
+
+/* Return a negative value if an rtx A, whose costs are given by COST_A
+   and REGCOST_A, is more desirable than an rtx B.
+   Return a positive value if A is less desirable, or 0 if the two are
+   equally good.  */
+static int
+preferrable (cost_a, regcost_a, cost_b, regcost_b)
+     int cost_a, regcost_a, cost_b, regcost_b;
+{
+  /* First, get rid of a cases involving expressions that are entirely
+     unwanted.  */
+  if (cost_a != cost_b)
+    {
+      if (cost_a == MAX_COST)
+       return 1;
+      if (cost_b == MAX_COST)
+       return -1;
+    }
+
+  /* Avoid extending lifetimes of hardregs.  */
+  if (regcost_a != regcost_b)
+    {
+      if (regcost_a == MAX_COST)
+       return 1;
+      if (regcost_b == MAX_COST)
+       return -1;
+    }
+
+  /* Normal operation costs take precedence.  */
+  if (cost_a != cost_b)
+    return cost_a - cost_b;
+  /* Only if these are identical consider effects on register pressure.  */
+  if (regcost_a != regcost_b)
+    return regcost_a - regcost_b;
+  return 0;
+}
+
 /* Internal function, to compute cost when X is not a register; called
    from COST macro to keep it simple.  */
 
 static int
-notreg_cost (x)
+notreg_cost (x, outer)
      rtx x;
+     enum rtx_code outer;
 {
   return ((GET_CODE (x) == SUBREG
           && GET_CODE (SUBREG_REG (x)) == REG
@@ -732,18 +812,10 @@ notreg_cost (x)
           && subreg_lowpart_p (x)
           && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (GET_MODE (x)),
                                     GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x)))))
-         ? (CHEAP_REG (SUBREG_REG (x)) ? 0
-            : (REGNO (SUBREG_REG (x)) >= FIRST_PSEUDO_REGISTER ? 1
-               : 2))
-         : rtx_cost (x, SET) * 2);
+         ? 0
+         : rtx_cost (x, outer) * 2);
 }
 
-/* Return the right cost to give to an operation
-   to make the cost of the corresponding register-to-register instruction
-   N times that of a fast register-to-register instruction.  */
-
-#define COSTS_N_INSNS(N) ((N) * 4 - 2)
-
 /* Return an estimate of the cost of computing rtx X.
    One use is in cse, to decide which expression to keep in the hash table.
    Another is in rtl generation, to pick the cheapest way to multiply.
@@ -787,20 +859,14 @@ rtx_cost (x, outer_code)
       /* Used in loop.c and combine.c as a marker.  */
       total = 0;
       break;
-    case ASM_OPERANDS:
-      /* We don't want these to be used in substitutions because
-        we have no way of validating the resulting insn.  So assign
-        anything containing an ASM_OPERANDS a very high cost.  */
-      total = 1000;
-      break;
     default:
-      total = 2;
+      total = COSTS_N_INSNS (1);
     }
 
   switch (code)
     {
     case REG:
-      return ! CHEAP_REG (x);
+      return 0;
 
     case SUBREG:
       /* If we can't tie these modes, make this expensive.  The larger
@@ -808,7 +874,8 @@ rtx_cost (x, outer_code)
       if (! MODES_TIEABLE_P (GET_MODE (x), GET_MODE (SUBREG_REG (x))))
        return COSTS_N_INSNS (2
                              + GET_MODE_SIZE (GET_MODE (x)) / UNITS_PER_WORD);
-      return 2;
+      break;
+
 #ifdef RTX_COSTS
       RTX_COSTS (x, code, outer_code);
 #endif
@@ -865,6 +932,7 @@ address_cost (x, mode)
   return rtx_cost (x, MEM);
 #endif
 }
+
 \f
 static struct cse_reg_info *
 get_cse_reg_info (regno)
@@ -923,7 +991,7 @@ new_basic_block ()
 
   /* Clear out hash table state for this pass.  */
 
-  bzero ((char *) reg_hash, sizeof reg_hash);
+  memset ((char *) reg_hash, 0, sizeof reg_hash);
 
   if (cse_reg_info_used_list)
     {
@@ -1147,11 +1215,11 @@ mention_regs (x)
          /* 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 entrire register, including all SUBREG expressions.  */
+            for the entire register, including all SUBREG expressions.  */
          if (REG_IN_TABLE (i) != REG_TICK (i) - 1)
            remove_invalid_refs (i);
          else
-           remove_invalid_subreg_refs (i, SUBREG_WORD (x), GET_MODE (x));
+           remove_invalid_subreg_refs (i, SUBREG_BYTE (x), GET_MODE (x));
        }
 
       REG_IN_TABLE (i) = REG_TICK (i);
@@ -1172,7 +1240,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;
@@ -1180,7 +1248,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;
@@ -1244,6 +1312,19 @@ insert_regs (x, classp, modified)
                  return 1;
                }
 
+         /* Mention_regs for a SUBREG checks if REG_TICK is exactly one larger
+            than REG_IN_TABLE to find out if there was only a single preceding
+            invalidation - for the SUBREG - or another one, which would be
+            for the full register.  However, if we find here that REG_TICK
+            indicates that the register is invalid, it means that it has
+            been invalidated in a separate operation.  The SUBREG might be used
+            now (then this is a recursive call), or we might use the full REG
+            now and a SUBREG of it later.  So bump up REG_TICK so that
+            mention_regs will do the right thing.  */
+         if (! modified
+             && REG_IN_TABLE (regno) >= 0
+             && REG_TICK (regno) == REG_IN_TABLE (regno) + 1)
+           REG_TICK (regno)++;
          make_new_qty (regno, GET_MODE (x));
          return 1;
        }
@@ -1260,18 +1341,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))))
     {
-      unsigned int regno = REGNO (SUBREG_REG (x));
-
-      insert_regs (SUBREG_REG (x), NULL_PTR, 0);
-      /* Mention_regs checks if REG_TICK is exactly one larger than
-        REG_IN_TABLE to find out if there was only a single preceding
-        invalidation - for the SUBREG - or another one, which would be
-        for the full register.  Since we don't invalidate the SUBREG
-        here first, we might have to bump up REG_TICK so that mention_regs
-        will do the right thing.  */
-      if (REG_IN_TABLE (regno) >= 0
-         && REG_TICK (regno) == REG_IN_TABLE (regno) + 1)
-       REG_TICK (regno)++;
+      insert_regs (SUBREG_REG (x), NULL, 0);
       mention_regs (x);
       return 1;
     }
@@ -1477,7 +1547,8 @@ lookup_as_function (x, code)
 
    If necessary, update table showing constant values of quantities.  */
 
-#define CHEAPER(X,Y)   ((X)->cost < (Y)->cost)
+#define CHEAPER(X, Y) \
+ (preferrable ((X)->cost, (X)->regcost, (Y)->cost, (Y)->regcost) < 0)
 
 static struct table_elt *
 insert (x, classp, hash, mode)
@@ -1504,12 +1575,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))
-    recorded_label_ref = 1;
-
   /* Put an element for X into the right hash bucket.  */
 
   elt = free_element_chain;
@@ -1518,12 +1583,13 @@ insert (x, classp, hash, mode)
   else
     {
       n_elements_made++;
-      elt = (struct table_elt *) oballoc (sizeof (struct table_elt));
+      elt = (struct table_elt *) xmalloc (sizeof (struct table_elt));
     }
 
   elt->exp = x;
   elt->canon_exp = NULL_RTX;
   elt->cost = COST (x);
+  elt->regcost = approx_reg_cost (x);
   elt->next_same_value = 0;
   elt->prev_same_value = 0;
   elt->next_same_hash = table[hash];
@@ -1647,7 +1713,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;
@@ -1746,6 +1812,7 @@ struct check_dependence_data
   enum machine_mode mode;
   rtx exp;
 };
+
 static int
 check_dependence (x, data)
      rtx *x;
@@ -1922,38 +1989,37 @@ 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);
       }
 }
 
-/* Likewise for a subreg with subreg_reg WORD and mode MODE.  */
+/* Likewise for a subreg with subreg_reg REGNO, subreg_byte OFFSET,
+   and mode MODE.  */
 static void
-remove_invalid_subreg_refs (regno, word, mode)
+remove_invalid_subreg_refs (regno, offset, mode)
      unsigned int regno;
-     unsigned int word;
+     unsigned int offset;
      enum machine_mode mode;
 {
   unsigned int i;
   struct table_elt *p, *next;
-  unsigned int end = word + (GET_MODE_SIZE (mode) - 1) / UNITS_PER_WORD;
+  unsigned int end = offset + (GET_MODE_SIZE (mode) - 1);
 
   for (i = 0; i < HASH_SIZE; i++)
     for (p = table[i]; p; p = next)
       {
-       rtx exp;
+       rtx exp = p->exp;
        next = p->next_same_hash;
 
-       exp = p->exp;
-       if (GET_CODE (p->exp) != REG
+       if (GET_CODE (exp) != REG
            && (GET_CODE (exp) != SUBREG
                || GET_CODE (SUBREG_REG (exp)) != REG
                || REGNO (SUBREG_REG (exp)) != regno
-               || (((SUBREG_WORD (exp)
-                     + (GET_MODE_SIZE (GET_MODE (exp)) - 1) / UNITS_PER_WORD)
-                    >= word)
-                && SUBREG_WORD (exp) <= end))
-           && refers_to_regno_p (regno, regno + 1, p->exp, NULL_PTR))
+               || (((SUBREG_BYTE (exp)
+                     + (GET_MODE_SIZE (GET_MODE (exp)) - 1)) >= offset)
+                   && SUBREG_BYTE (exp) <= end))
+           && refers_to_regno_p (regno, regno + 1, p->exp, (rtx*)0))
          remove_from_table (p, i);
       }
 }
@@ -2139,6 +2205,21 @@ use_related_value (x, elt)
   return plus_constant (q->exp, offset);
 }
 \f
+/* Hash a string.  Just add its bytes up.  */
+static inline unsigned
+canon_hash_string (ps)
+     const char *ps;
+{
+  unsigned hash = 0;
+  const unsigned char *p = (const unsigned char *)ps;
+  
+  if (p)
+    while (*p)
+      hash += *p++;
+
+  return hash;
+}
+
 /* Hash an rtx.  We are careful to make sure the value is never negative.
    Equivalent registers hash identically.
    MODE is used in hashing for CONST_INTs only;
@@ -2182,10 +2263,13 @@ canon_hash (x, mode)
           failure to do so leads to failure to simplify 0<100 type of
           conditionals.
 
-          On all machines, we can't record any global registers.  */
+          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
            && (global_regs[regno]
+               || CLASS_LIKELY_SPILLED_P (REGNO_REG_CLASS (regno))
                || (SMALL_REGISTER_CLASSES
                    && ! fixed_regs[regno]
                    && regno != FRAME_POINTER_REGNUM
@@ -2210,7 +2294,8 @@ canon_hash (x, mode)
        if (GET_CODE (SUBREG_REG (x)) == REG)
          {
            hash += (((unsigned) SUBREG << 7)
-                    + REGNO (SUBREG_REG (x)) + SUBREG_WORD (x));
+                    + REGNO (SUBREG_REG (x))
+                    + (SUBREG_BYTE (x) / UNITS_PER_WORD));
            return hash;
          }
        break;
@@ -2240,13 +2325,11 @@ canon_hash (x, mode)
 
       /* Assume there is only one rtx object for any given label.  */
     case LABEL_REF:
-      hash
-       += ((unsigned) LABEL_REF << 7) + (unsigned long) XEXP (x, 0);
+      hash += ((unsigned) LABEL_REF << 7) + (unsigned long) XEXP (x, 0);
       return hash;
 
     case SYMBOL_REF:
-      hash
-       += ((unsigned) SYMBOL_REF << 7) + (unsigned long) XSTR (x, 0);
+      hash += ((unsigned) SYMBOL_REF << 7) + (unsigned long) XSTR (x, 0);
       return hash;
 
     case MEM:
@@ -2267,6 +2350,28 @@ canon_hash (x, mode)
       x = XEXP (x, 0);
       goto repeat;
 
+    case USE:
+      /* A USE that mentions non-volatile memory needs special
+        handling since the MEM may be BLKmode which normally
+        prevents an entry from being made.  Pure calls are
+        marked by a USE which mentions BLKmode memory.  */
+      if (GET_CODE (XEXP (x, 0)) == MEM
+         && ! MEM_VOLATILE_P (XEXP (x, 0)))
+       {
+         hash += (unsigned)USE;
+         x = XEXP (x, 0);
+
+         if (! RTX_UNCHANGING_P (x) || FIXED_BASE_PLUS_P (XEXP (x, 0)))
+           hash_arg_in_memory = 1;
+
+         /* Now that we have already found this special case,
+            might as well speed it up as much as possible.  */
+         hash += (unsigned) MEM;
+         x = XEXP (x, 0);
+         goto repeat;
+       }
+      break;
+
     case PRE_DEC:
     case PRE_INC:
     case POST_DEC:
@@ -2286,6 +2391,32 @@ canon_hash (x, mode)
          do_not_record = 1;
          return 0;
        }
+      else
+       {
+         /* We don't want to take the filename and line into account.  */
+         hash += (unsigned) code + (unsigned) GET_MODE (x)
+           + canon_hash_string (ASM_OPERANDS_TEMPLATE (x))
+           + canon_hash_string (ASM_OPERANDS_OUTPUT_CONSTRAINT (x))
+           + (unsigned) ASM_OPERANDS_OUTPUT_IDX (x);
+
+         if (ASM_OPERANDS_INPUT_LENGTH (x))
+           {
+             for (i = 1; i < ASM_OPERANDS_INPUT_LENGTH (x); i++)
+               {
+                 hash += (canon_hash (ASM_OPERANDS_INPUT (x, i),
+                                      GET_MODE (ASM_OPERANDS_INPUT (x, i)))
+                          + canon_hash_string (ASM_OPERANDS_INPUT_CONSTRAINT
+                                               (x, i)));
+               }
+
+             hash += canon_hash_string (ASM_OPERANDS_INPUT_CONSTRAINT (x, 0));
+             x = ASM_OPERANDS_INPUT (x, 0);
+             mode = GET_MODE (x);
+             goto repeat;
+           }
+
+         return hash;
+       }
       break;
 
     default:
@@ -2315,21 +2446,15 @@ canon_hash (x, mode)
        for (j = 0; j < XVECLEN (x, i); j++)
          hash += canon_hash (XVECEXP (x, i, j), 0);
       else if (fmt[i] == 's')
-       {
-         register const unsigned char *p =
-           (const unsigned char *) XSTR (x, i);
-
-         if (p)
-           while (*p)
-             hash += *p++;
-       }
+       hash += canon_hash_string (XSTR (x, i));
       else if (fmt[i] == 'i')
        {
          register unsigned tem = XINT (x, i);
          hash += tem;
        }
       else if (fmt[i] == '0' || fmt[i] == 't')
-       /* unused */;
+       /* Unused.  */
+       ;
       else
        abort ();
     }
@@ -2475,6 +2600,35 @@ exp_equiv_p (x, y, validate, equal_values)
                  && exp_equiv_p (XEXP (x, 1), XEXP (y, 0),
                                  validate, equal_values)));
 
+    case ASM_OPERANDS:
+      /* We don't use the generic code below because we want to
+        disregard filename and line numbers.  */
+
+      /* A volatile asm isn't equivalent to any other.  */
+      if (MEM_VOLATILE_P (x) || MEM_VOLATILE_P (y))
+       return 0;
+
+      if (GET_MODE (x) != GET_MODE (y)
+         || strcmp (ASM_OPERANDS_TEMPLATE (x), ASM_OPERANDS_TEMPLATE (y))
+         || strcmp (ASM_OPERANDS_OUTPUT_CONSTRAINT (x),
+                    ASM_OPERANDS_OUTPUT_CONSTRAINT (y))
+         || ASM_OPERANDS_OUTPUT_IDX (x) != ASM_OPERANDS_OUTPUT_IDX (y)
+         || ASM_OPERANDS_INPUT_LENGTH (x) != ASM_OPERANDS_INPUT_LENGTH (y))
+       return 0;
+
+      if (ASM_OPERANDS_INPUT_LENGTH (x))
+       {
+         for (i = ASM_OPERANDS_INPUT_LENGTH (x) - 1; i >= 0; i--)
+           if (! exp_equiv_p (ASM_OPERANDS_INPUT (x, i),
+                              ASM_OPERANDS_INPUT (y, i),
+                              validate, equal_values)
+               || strcmp (ASM_OPERANDS_INPUT_CONSTRAINT (x, i),
+                          ASM_OPERANDS_INPUT_CONSTRAINT (y, i)))
+             return 0;
+       }
+
+      return 1;
+
     default:
       break;
     }
@@ -2533,8 +2687,9 @@ exp_equiv_p (x, y, validate, equal_values)
    against certain constants or near-constants.  */
 
 static int
-cse_rtx_varies_p (x)
+cse_rtx_varies_p (x, from_alias)
      register 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
@@ -2587,7 +2742,7 @@ cse_rtx_varies_p (x)
        return 0;
     }
 
-  return rtx_varies_p (x);
+  return rtx_varies_p (x, from_alias);
 }
 \f
 /* Canonicalize an expression:
@@ -2716,7 +2871,6 @@ find_best_addr (insn, loc, mode)
   int save_hash_arg_in_memory = hash_arg_in_memory;
   int addr_volatile;
   int regno;
-  int folded_cost, addr_cost;
   unsigned hash;
 
   /* Do not try to replace constant addresses or addresses of local and
@@ -2749,14 +2903,15 @@ find_best_addr (insn, loc, mode)
   if (GET_CODE (addr) != REG)
     {
       rtx folded = fold_rtx (copy_rtx (addr), NULL_RTX);
-
-      folded_cost = address_cost (folded, mode);
-      addr_cost = address_cost (addr, mode);
-
-      if ((folded_cost < addr_cost
-          || (folded_cost == addr_cost
-              && rtx_cost (folded, MEM) > rtx_cost (addr, MEM)))
-         && rtx_cost (folded, MEM) < rtx_cost (addr, MEM)
+      int addr_folded_cost = address_cost (folded, mode);
+      int addr_cost = address_cost (addr, mode);
+
+      if ((addr_folded_cost < addr_cost
+          || (addr_folded_cost == addr_cost
+              /* ??? The rtx_cost comparison is left over from an older
+                 version of this code.  It is probably no longer helpful.  */
+              && (rtx_cost (folded, MEM) > rtx_cost (addr, MEM)
+                  || approx_reg_cost (folded) < approx_reg_cost (addr))))
          && validate_change (insn, loc, folded, 0))
        addr = folded;
     }
@@ -2816,7 +2971,7 @@ find_best_addr (insn, loc, mode)
                     || exp_equiv_p (p->exp, p->exp, 1, 0))
                    && ((exp_cost = address_cost (p->exp, mode)) < best_addr_cost
                        || (exp_cost == best_addr_cost
-                           && (p->cost + 1) >> 1 < best_rtx_cost)))
+                           && ((p->cost + 1) >> 1) > best_rtx_cost)))
                  {
                    found_better = 1;
                    best_addr_cost = exp_cost;
@@ -3002,7 +3157,20 @@ find_comparison_args (code, parg1, parg2, pmode1, pmode2)
        p = lookup (arg1, safe_hash (arg1, GET_MODE (arg1)) & HASH_MASK,
                    GET_MODE (arg1));
       if (p)
-       p = p->first_same_value;
+       {
+         p = p->first_same_value;
+
+         /* If what we compare is already known to be constant, that is as
+            good as it gets.
+            We need to break the loop in this case, because otherwise we
+            can have an infinite loop when looking at a reg that is known
+            to be a constant which is the same as a comparison of a reg
+            against zero which appears later in the insn stream, which in
+            turn is constant and the same as the comparison of the first reg
+            against zero...  */
+         if (p->is_const)
+           break;
+       }
 
       for (; p; p = p->next_same_value)
        {
@@ -3076,12 +3244,19 @@ find_comparison_args (code, parg1, parg2, pmode1, pmode2)
       if (x == 0)
        break;
 
-      arg1 = XEXP (x, 0), arg2 = XEXP (x, 1);
-      if (GET_RTX_CLASS (GET_CODE (x)) == '<')
-       code = GET_CODE (x);
-
+      /* If we need to reverse the comparison, make sure that that is
+        possible -- we can't necessarily infer the value of GE from LT
+        with floating-point operands.  */
       if (reverse_code)
-       code = reverse_condition (code);
+       {
+         enum rtx_code reversed = reversed_comparison_code (x, NULL_RTX);
+         if (reversed == UNKNOWN)
+           break;
+         else code = reversed;
+       }
+      else if (GET_RTX_CLASS (GET_CODE (x)) == '<')
+       code = GET_CODE (x);
+      arg1 = XEXP (x, 0), arg2 = XEXP (x, 1);
     }
 
   /* Return our results.  Return the modes from before fold_rtx
@@ -3163,7 +3338,7 @@ 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.  */
+        lets us fold switch statements on the VAX.  */
       if (insn && GET_CODE (insn) == JUMP_INSN)
        {
          rtx next = next_nonnote_insn (insn);
@@ -3200,8 +3375,7 @@ fold_rtx (x, insn)
              && GET_MODE_SIZE (imode) <= UNITS_PER_WORD
              && (elt = lookup (SUBREG_REG (x), HASH (SUBREG_REG (x), imode),
                                imode)) != 0)
-           for (elt = elt->first_same_value;
-                elt; elt = elt->next_same_value)
+           for (elt = elt->first_same_value; elt; elt = elt->next_same_value)
              {
                if (CONSTANT_P (elt->exp)
                    && GET_MODE (elt->exp) == VOIDmode)
@@ -3227,15 +3401,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_WORD (x), 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;
        }
@@ -3499,10 +3666,17 @@ fold_rtx (x, insn)
        return x;
       }
 
+#ifdef NO_FUNCTION_CSE
+    case CALL:
+      if (CONSTANT_P (XEXP (XEXP (x, 0), 0)))
+       return x;
+      break;
+#endif
+
     case ASM_OPERANDS:
-      for (i = XVECLEN (x, 3) - 1; i >= 0; i--)
-       validate_change (insn, &XVECEXP (x, 3, i),
-                        fold_rtx (XVECEXP (x, 3, i), insn), 0);
+      for (i = ASM_OPERANDS_INPUT_LENGTH (x) - 1; i >= 0; i--)
+       validate_change (insn, &ASM_OPERANDS_INPUT (x, i),
+                        fold_rtx (ASM_OPERANDS_INPUT (x, i), insn), 0);
       break;
 
     default:
@@ -3590,7 +3764,7 @@ fold_rtx (x, insn)
        /* Pick the least expensive of the folded argument and an
           equivalent constant argument.  */
        if (const_arg == 0 || const_arg == folded_arg
-           || COST (const_arg) > COST (folded_arg))
+           || COST_IN (const_arg, code) > COST_IN (folded_arg, code))
          cheap_arg = folded_arg, expensive_arg = const_arg;
        else
          cheap_arg = const_arg, expensive_arg = folded_arg;
@@ -3610,16 +3784,27 @@ fold_rtx (x, insn)
            copied = 1;
          }
 
-       replacements[0] = cheap_arg, replacements[1] = expensive_arg;
-       for (j = 0;
-            j < 2 && replacements[j]
-            && COST (replacements[j]) < COST (XEXP (x, i));
-            j++)
+       /* Order the replacements from cheapest to most expensive.  */
+       replacements[0] = cheap_arg;
+       replacements[1] = expensive_arg;
+
+       for (j = 0; j < 2 && replacements[j];  j++)
          {
+           int 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
+              in the case of a tie.  */
+           if (new_cost > old_cost
+               || (new_cost == old_cost && CONSTANT_P (XEXP (x, i))))
+             break;
+
            if (validate_change (insn, &XEXP (x, i), replacements[j], 0))
              break;
 
-           if (code == NE || code == EQ || GET_RTX_CLASS (code) == 'c')
+           if (code == NE || code == EQ || GET_RTX_CLASS (code) == 'c'
+               || code == LTGT || code == UNEQ || code == ORDERED
+               || code == UNORDERED)
              {
                validate_change (insn, &XEXP (x, i), XEXP (x, 1 - i), 1);
                validate_change (insn, &XEXP (x, 1 - i), replacements[j], 1);
@@ -3644,14 +3829,16 @@ fold_rtx (x, insn)
        if (fmt[i] == 'E')
          /* Don't try to fold inside of a vector of expressions.
             Doing nothing is harmless.  */
-         ;
+         {;}
       }
 
   /* If a commutative operation, place a constant integer as the second
      operand unless the first operand is also a constant integer.  Otherwise,
      place any constant second unless the first operand is also a constant.  */
 
-  if (code == EQ || code == NE || GET_RTX_CLASS (code) == 'c')
+  if (code == EQ || code == NE || GET_RTX_CLASS (code) == 'c'
+      || code == LTGT || code == UNEQ || code == ORDERED
+      || code == UNORDERED)
     {
       if (must_swap || (const_arg0
                        && (const_arg1 == 0
@@ -3712,15 +3899,15 @@ fold_rtx (x, insn)
       if (const_arg0 == 0 || const_arg1 == 0)
        {
          struct table_elt *p0, *p1;
-         rtx true = const_true_rtx, false = const0_rtx;
+         rtx true_rtx = const_true_rtx, false_rtx = const0_rtx;
          enum machine_mode mode_arg1;
 
 #ifdef FLOAT_STORE_FLAG_VALUE
          if (GET_MODE_CLASS (mode) == MODE_FLOAT)
            {
-             true = (CONST_DOUBLE_FROM_REAL_VALUE
+             true_rtx = (CONST_DOUBLE_FROM_REAL_VALUE
                      (FLOAT_STORE_FLAG_VALUE (mode), mode));
-             false = CONST0_RTX (mode);
+             false_rtx = CONST0_RTX (mode);
            }
 #endif
 
@@ -3754,32 +3941,40 @@ fold_rtx (x, insn)
                      || GET_CODE (folded_arg0) == CONST))
                {
                  if (code == EQ)
-                   return false;
+                   return false_rtx;
                  else if (code == NE)
-                   return true;
+                   return true_rtx;
                }
 
-             /* See if the two operands are the same.  We don't do this
-                for IEEE floating-point since we can't assume x == x
-                since x might be a NaN.  */
-
-             if ((TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
-                  || ! FLOAT_MODE_P (mode_arg0) || flag_fast_math)
-                 && (folded_arg0 == folded_arg1
-                     || (GET_CODE (folded_arg0) == REG
-                         && GET_CODE (folded_arg1) == REG
-                         && (REG_QTY (REGNO (folded_arg0))
-                             == REG_QTY (REGNO (folded_arg1))))
-                     || ((p0 = lookup (folded_arg0,
-                                       (safe_hash (folded_arg0, mode_arg0)
-                                        & HASH_MASK), mode_arg0))
-                         && (p1 = lookup (folded_arg1,
-                                          (safe_hash (folded_arg1, mode_arg0)
-                                           & HASH_MASK), mode_arg0))
-                         && p0->first_same_value == p1->first_same_value)))
-               return ((code == EQ || code == LE || code == GE
-                        || code == LEU || code == GEU)
-                       ? true : false);
+             /* See if the two operands are the same.  */
+
+             if (folded_arg0 == folded_arg1
+                 || (GET_CODE (folded_arg0) == REG
+                     && GET_CODE (folded_arg1) == REG
+                     && (REG_QTY (REGNO (folded_arg0))
+                         == REG_QTY (REGNO (folded_arg1))))
+                 || ((p0 = lookup (folded_arg0,
+                                   (safe_hash (folded_arg0, mode_arg0)
+                                    & HASH_MASK), mode_arg0))
+                     && (p1 = lookup (folded_arg1,
+                                      (safe_hash (folded_arg1, mode_arg0)
+                                       & 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;
+               }
 
              /* If FOLDED_ARG0 is a register, see if the comparison we are
                 doing now is either the same as we did before or the reverse
@@ -3803,7 +3998,7 @@ fold_rtx (x, insn)
                              || (GET_CODE (folded_arg1) == REG
                                  && (REG_QTY (REGNO (folded_arg1)) == ent->comparison_qty))))
                        return (comparison_dominates_p (ent->comparison_code, code)
-                               ? true : false);
+                               ? true_rtx : false_rtx);
                    }
                }
            }
@@ -3827,30 +4022,30 @@ fold_rtx (x, insn)
              int has_sign = (HOST_BITS_PER_WIDE_INT >= sign_bitnum
                              && (INTVAL (inner_const)
                                  & ((HOST_WIDE_INT) 1 << sign_bitnum)));
-             rtx true = const_true_rtx, false = const0_rtx;
+             rtx true_rtx = const_true_rtx, false_rtx = const0_rtx;
 
 #ifdef FLOAT_STORE_FLAG_VALUE
              if (GET_MODE_CLASS (mode) == MODE_FLOAT)
                {
-                 true = (CONST_DOUBLE_FROM_REAL_VALUE
+                 true_rtx = (CONST_DOUBLE_FROM_REAL_VALUE
                          (FLOAT_STORE_FLAG_VALUE (mode), mode));
-                 false = CONST0_RTX (mode);
+                 false_rtx = CONST0_RTX (mode);
                }
 #endif
 
              switch (code)
                {
                case EQ:
-                 return false;
+                 return false_rtx;
                case NE:
-                 return true;
+                 return true_rtx;
                case LT:  case LE:
                  if (has_sign)
-                   return true;
+                   return true_rtx;
                  break;
                case GT:  case GE:
                  if (has_sign)
-                   return false;
+                   return false_rtx;
                  break;
                default:
                  break;
@@ -3858,7 +4053,19 @@ fold_rtx (x, insn)
            }
        }
 
-      new = simplify_relational_operation (code, mode_arg0,
+      new = simplify_relational_operation (code,
+                                          (mode_arg0 != VOIDmode
+                                           ? mode_arg0
+                                           : (GET_MODE (const_arg0
+                                                        ? const_arg0
+                                                        : folded_arg0)
+                                              != VOIDmode)
+                                           ? GET_MODE (const_arg0
+                                                       ? const_arg0
+                                                       : folded_arg0)
+                                           : GET_MODE (const_arg1
+                                                       ? const_arg1
+                                                       : folded_arg1)),
                                           const_arg0 ? const_arg0 : folded_arg0,
                                           const_arg1 ? const_arg1 : folded_arg1);
 #ifdef FLOAT_STORE_FLAG_VALUE
@@ -3886,7 +4093,7 @@ fold_rtx (x, insn)
            {
              rtx y
                = GET_CODE (folded_arg0) == MINUS ? folded_arg0
-                 : lookup_as_function (folded_arg0, MINUS);
+               : lookup_as_function (folded_arg0, MINUS);
 
              if (y != 0 && GET_CODE (XEXP (y, 1)) == LABEL_REF
                  && XEXP (XEXP (y, 1), 0) == XEXP (const_arg1, 0))
@@ -3897,7 +4104,7 @@ fold_rtx (x, insn)
                        : lookup_as_function (folded_arg0, CONST))) != 0
                  && GET_CODE (XEXP (y, 0)) == MINUS
                  && GET_CODE (XEXP (XEXP (y, 0), 1)) == LABEL_REF
-                 && XEXP (XEXP (XEXP (y, 0),1), 0) == XEXP (const_arg1, 0))
+                 && XEXP (XEXP (XEXP (y, 0), 1), 0) == XEXP (const_arg1, 0))
                return XEXP (XEXP (y, 0), 0);
            }
 
@@ -3906,7 +4113,7 @@ fold_rtx (x, insn)
            {
              rtx y
                = GET_CODE (folded_arg1) == MINUS ? folded_arg1
-                 : lookup_as_function (folded_arg1, MINUS);
+               : lookup_as_function (folded_arg1, MINUS);
 
              if (y != 0 && GET_CODE (XEXP (y, 1)) == LABEL_REF
                  && XEXP (XEXP (y, 1), 0) == XEXP (const_arg0, 0))
@@ -3917,7 +4124,7 @@ fold_rtx (x, insn)
                        : lookup_as_function (folded_arg1, CONST))) != 0
                  && GET_CODE (XEXP (y, 0)) == MINUS
                  && GET_CODE (XEXP (XEXP (y, 0), 1)) == LABEL_REF
-                 && XEXP (XEXP (XEXP (y, 0),1), 0) == XEXP (const_arg0, 0))
+                 && XEXP (XEXP (XEXP (y, 0), 1), 0) == XEXP (const_arg0, 0))
                return XEXP (XEXP (y, 0), 0);
            }
 
@@ -3935,7 +4142,7 @@ fold_rtx (x, insn)
              && INTVAL (const_arg1) < 0
              /* This used to test
 
-                - INTVAL (const_arg1) >= 0
+                -INTVAL (const_arg1) >= 0
 
                 But The Sun V5.0 compilers mis-compiled that test.  So
                 instead we test for the problematic value in a more direct
@@ -3944,7 +4151,7 @@ fold_rtx (x, insn)
                ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1))
              && GET_CODE (folded_arg1) == REG)
            {
-             rtx new_const = GEN_INT (- INTVAL (const_arg1));
+             rtx new_const = GEN_INT (-INTVAL (const_arg1));
              struct table_elt *p
                = lookup (new_const, safe_hash (new_const, mode) & HASH_MASK,
                          mode);
@@ -3969,7 +4176,7 @@ fold_rtx (x, insn)
                                 NULL_RTX);
            }
 
-         /* ... fall through ...  */
+         /* Fall through.  */
 
        from_plus:
        case SMIN:    case SMAX:      case UMIN:    case UMAX:
@@ -4090,7 +4297,7 @@ fold_rtx (x, insn)
       break;
 
     case 'x':
-      /* Always eliminate CONSTANT_P_RTX at this stage. */
+      /* Always eliminate CONSTANT_P_RTX at this stage.  */
       if (code == CONSTANT_P_RTX)
        return (const_arg0 ? const1_rtx : const0_rtx);
       break;
@@ -4176,10 +4383,11 @@ gen_lowpart_if_possible (mode, x)
           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));
+
+      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
@@ -4230,8 +4438,7 @@ record_jump_equiv (insn, taken)
   code = find_comparison_args (code, &op0, &op1, &mode0, &mode1);
   if (! cond_known_true)
     {
-      reversed_nonequality = (code != EQ && code != NE);
-      code = reverse_condition (code);
+      code = reversed_comparison_code_parts (code, op0, op1, insn);
 
       /* Don't remember if we can't find the inverse.  */
       if (code == UNKNOWN)
@@ -4380,7 +4587,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);
@@ -4392,7 +4599,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;
        }
 
@@ -4408,13 +4615,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;
            }
 
@@ -4435,25 +4642,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;
     }
 
@@ -4469,7 +4676,7 @@ record_jump_cond (code, mode, op0, op1, reversed_nonequality)
 
    If LIBCALL_INSN is nonzero, don't record any equivalence made in
    the insn.  It means that INSN is inside libcall block.  In this
-   case LIBCALL_INSN is the corresponding insn with REG_LIBCALL. */
+   case LIBCALL_INSN is the corresponding insn with REG_LIBCALL.  */
 
 /* Data on one SET contained in the instruction.  */
 
@@ -4526,7 +4733,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;
 
@@ -4538,8 +4745,11 @@ cse_insn (insn, libcall_insn)
   if (GET_CODE (insn) == CALL_INSN)
     {
       for (tem = CALL_INSN_FUNCTION_USAGE (insn); tem; tem = XEXP (tem, 1))
-       if (GET_CODE (XEXP (tem, 0)) == CLOBBER)
-         invalidate (SET_DEST (XEXP (tem, 0)), VOIDmode);
+       {
+         if (GET_CODE (XEXP (tem, 0)) == CLOBBER)
+           invalidate (SET_DEST (XEXP (tem, 0)), VOIDmode);
+         XEXP (tem, 0) = canon_reg (XEXP (tem, 0), insn);
+       }
     }
 
   if (GET_CODE (x) == SET)
@@ -4750,8 +4960,16 @@ cse_insn (insn, libcall_insn)
       rtx src_const = 0;
       rtx src_related = 0;
       struct table_elt *src_const_elt = 0;
-      int src_cost = 10000, src_eqv_cost = 10000, src_folded_cost = 10000;
-      int src_related_cost = 10000, src_elt_cost = 10000;
+      int src_cost = MAX_COST;
+      int src_eqv_cost = MAX_COST;
+      int src_folded_cost = MAX_COST;
+      int src_related_cost = MAX_COST;
+      int src_elt_cost = MAX_COST;
+      int src_regcost = MAX_COST;
+      int src_eqv_regcost = MAX_COST;
+      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
         contents of src_folded before using it.  */
       int src_folded_force_flag = 0;
@@ -4833,18 +5051,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
@@ -5052,7 +5268,7 @@ cse_insn (insn, libcall_insn)
         also have such operations, but this is only likely to be
         beneficial these machines.  */
 
-      if (flag_expensive_optimizations &&  src_related == 0
+      if (flag_expensive_optimizations && src_related == 0
          && (GET_MODE_SIZE (mode) < UNITS_PER_WORD)
          && GET_MODE_CLASS (mode) == MODE_INT
          && GET_CODE (src) == MEM && ! do_not_record
@@ -5158,39 +5374,51 @@ cse_insn (insn, libcall_insn)
       if (src)
        {
          if (rtx_equal_p (src, dest))
-           src_cost = -1;
+           src_cost = src_regcost = -1;
          else
-           src_cost = COST (src);
+           {
+             src_cost = COST (src);
+             src_regcost = approx_reg_cost (src);
+           }
        }
 
       if (src_eqv_here)
        {
          if (rtx_equal_p (src_eqv_here, dest))
-           src_eqv_cost = -1;
+           src_eqv_cost = src_eqv_regcost = -1;
          else
-           src_eqv_cost = COST (src_eqv_here);
+           {
+             src_eqv_cost = COST (src_eqv_here);
+             src_eqv_regcost = approx_reg_cost (src_eqv_here);
+           }
        }
 
       if (src_folded)
        {
          if (rtx_equal_p (src_folded, dest))
-           src_folded_cost = -1;
+           src_folded_cost = src_folded_regcost = -1;
          else
-           src_folded_cost = COST (src_folded);
+           {
+             src_folded_cost = COST (src_folded);
+             src_folded_regcost = approx_reg_cost (src_folded);
+           }
        }
 
       if (src_related)
        {
          if (rtx_equal_p (src_related, dest))
-           src_related_cost = -1;
+           src_related_cost = src_related_regcost = -1;
          else
-           src_related_cost = COST (src_related);
+           {
+             src_related_cost = COST (src_related);
+             src_related_regcost = approx_reg_cost (src_related);
+           }
        }
 
       /* If this was an indirect jump insn, a known label will really be
         cheaper even though it looks more expensive.  */
       if (dest == pc_rtx && src_const && GET_CODE (src_const) == LABEL_REF)
-       src_folded = src_const, src_folded_cost = -1;
+       src_folded = src_const, src_folded_cost = src_folded_regcost = -1;
 
       /* Terminate loop when replacement made.  This must terminate since
          the current contents will be tested and will always be valid.  */
@@ -5222,72 +5450,75 @@ cse_insn (insn, libcall_insn)
              continue;
            }
 
-         if (elt)
-           src_elt_cost = elt->cost;
+          if (elt)
+           {
+             src_elt_cost = elt->cost;
+             src_elt_regcost = elt->regcost;
+           }
 
           /* 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_cost <= src_cost
-             && src_folded_cost <= src_eqv_cost
-             && src_folded_cost <= src_related_cost
-             && src_folded_cost <= src_elt_cost)
+         if (src_folded
+             && preferrable (src_folded_cost, src_folded_regcost,
+                             src_cost, src_regcost) <= 0
+             && preferrable (src_folded_cost, src_folded_regcost,
+                             src_eqv_cost, src_eqv_regcost) <= 0
+             && preferrable (src_folded_cost, src_folded_regcost,
+                             src_related_cost, src_related_regcost) <= 0
+             && preferrable (src_folded_cost, src_folded_regcost,
+                             src_elt_cost, src_elt_regcost) <= 0)
            {
-             trial = src_folded, src_folded_cost = 10000;
+             trial = src_folded, src_folded_cost = MAX_COST;
              if (src_folded_force_flag)
                trial = force_const_mem (mode, trial);
            }
-         else if (src_cost <= src_eqv_cost
-                  && src_cost <= src_related_cost
-                  && src_cost <= src_elt_cost)
-           trial = src, src_cost = 10000;
-         else if (src_eqv_cost <= src_related_cost
-                  && src_eqv_cost <= src_elt_cost)
-           trial = copy_rtx (src_eqv_here), src_eqv_cost = 10000;
-         else if (src_related_cost <= src_elt_cost)
-           trial = copy_rtx (src_related), src_related_cost = 10000;
+         else if (src
+                  && preferrable (src_cost, src_regcost,
+                                  src_eqv_cost, src_eqv_regcost) <= 0
+                  && preferrable (src_cost, src_regcost,
+                                  src_related_cost, src_related_regcost) <= 0
+                  && preferrable (src_cost, src_regcost,
+                                  src_elt_cost, src_elt_regcost) <= 0)
+           trial = src, src_cost = MAX_COST;
+         else if (src_eqv_here
+                  && preferrable (src_eqv_cost, src_eqv_regcost,
+                                  src_related_cost, src_related_regcost) <= 0
+                  && preferrable (src_eqv_cost, src_eqv_regcost,
+                                  src_elt_cost, src_elt_regcost) <= 0)
+           trial = copy_rtx (src_eqv_here), src_eqv_cost = MAX_COST;
+         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;
          else
            {
              trial = copy_rtx (elt->exp);
              elt = elt->next_same_value;
-             src_elt_cost = 10000;
+             src_elt_cost = MAX_COST;
            }
 
          /* We don't normally have an insn matching (set (pc) (pc)), so
             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;
            }
 
          /* Look for a substitution that makes a valid insn.  */
-          else if (validate_change (insn, &SET_SRC (sets[i].rtl), trial, 0))
+         else if (validate_change (insn, &SET_SRC (sets[i].rtl), trial, 0))
            {
              /* If we just made a substitution inside a libcall, then we
                 need to make the same substitution in any notes attached
@@ -5316,8 +5547,16 @@ cse_insn (insn, libcall_insn)
 
          else if (constant_pool_entries_cost
                   && CONSTANT_P (trial)
+                  /* Reject cases that will abort in decode_rtx_const.
+                     On the alpha when simplifying a switch, we get
+                     (const (truncate (minus (label_ref) (label_ref)))).  */
                   && ! (GET_CODE (trial) == CONST
                         && GET_CODE (XEXP (trial, 0)) == TRUNCATE)
+                  /* Likewise on IA-64, except without the truncate.  */
+                  && ! (GET_CODE (trial) == CONST
+                        && GET_CODE (XEXP (trial, 0)) == MINUS
+                        && GET_CODE (XEXP (XEXP (trial, 0), 0)) == LABEL_REF
+                        && GET_CODE (XEXP (XEXP (trial, 0), 1)) == LABEL_REF)
                   && (src_folded == 0
                       || (GET_CODE (src_folded) != MEM
                           && ! src_folded_force_flag))
@@ -5535,13 +5774,17 @@ cse_insn (insn, libcall_insn)
        }
 
       /* 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)
+         /* 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);
              JUMP_LABEL (new) = XEXP (src, 0);
@@ -5549,11 +5792,6 @@ cse_insn (insn, libcall_insn)
              insn = new;
            }
          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);
@@ -5573,9 +5811,15 @@ cse_insn (insn, libcall_insn)
 
       else if (do_not_record)
        {
-         if (GET_CODE (dest) == REG || GET_CODE (dest) == SUBREG
-             || GET_CODE (dest) == MEM)
+         if (GET_CODE (dest) == REG || GET_CODE (dest) == SUBREG)
            invalidate (dest, VOIDmode);
+         else if (GET_CODE (dest) == MEM)
+           {
+             /* Outgoing arguments for a libcall don't
+                affect any recorded expressions.  */
+             if (! libcall_insn || insn == libcall_insn)
+               invalidate (dest, VOIDmode);
+           }
          else if (GET_CODE (dest) == STRICT_LOW_PART
                   || GET_CODE (dest) == ZERO_EXTRACT)
            invalidate (XEXP (dest, 0), GET_MODE (dest));
@@ -5711,7 +5955,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 ();
     }
@@ -5732,9 +5976,15 @@ cse_insn (insn, libcall_insn)
           previous quantity's chain.
           Needed for memory if this is a nonvarying address, unless
           we have just done an invalidate_memory that covers even those.  */
-       if (GET_CODE (dest) == REG || GET_CODE (dest) == SUBREG
-           || GET_CODE (dest) == MEM)
+       if (GET_CODE (dest) == REG || GET_CODE (dest) == SUBREG)
          invalidate (dest, VOIDmode);
+       else if (GET_CODE (dest) == MEM)
+         {
+           /* Outgoing arguments for a libcall don't
+              affect any recorded expressions.  */
+           if (! libcall_insn || insn == libcall_insn)
+             invalidate (dest, VOIDmode);
+         }
        else if (GET_CODE (dest) == STRICT_LOW_PART
                 || GET_CODE (dest) == ZERO_EXTRACT)
          invalidate (XEXP (dest, 0), GET_MODE (dest));
@@ -5990,23 +6240,32 @@ cse_insn (insn, libcall_insn)
        {
          rtx prev = prev_nonnote_insn (insn);
 
+         /* Do not swap the registers around if the previous instruction
+            attaches a REG_EQUIV note to REG1.
+
+            ??? It's not entirely clear whether we can transfer a REG_EQUIV
+            from the pseudo that originally shadowed an incoming argument
+            to another register.  Some uses of REG_EQUIV might rely on it
+            being attached to REG1 rather than REG2.
+
+            This section previously turned the REG_EQUIV into a REG_EQUAL
+            note.  We cannot do that because REG_EQUIV may provide an
+            uninitialised stack slot when REG_PARM_STACK_SPACE is used.  */
+
          if (prev != 0 && GET_CODE (prev) == INSN
              && GET_CODE (PATTERN (prev)) == SET
-             && SET_DEST (PATTERN (prev)) == SET_SRC (sets[0].rtl))
+             && SET_DEST (PATTERN (prev)) == SET_SRC (sets[0].rtl)
+             && ! find_reg_note (prev, REG_EQUIV, NULL_RTX))
            {
              rtx dest = SET_DEST (sets[0].rtl);
              rtx src = SET_SRC (sets[0].rtl);
-             rtx note = find_reg_note (prev, REG_EQUIV, NULL_RTX);
+             rtx note;
 
              validate_change (prev, &SET_DEST (PATTERN (prev)), dest, 1);
              validate_change (insn, &SET_DEST (sets[0].rtl), src, 1);
              validate_change (insn, &SET_SRC (sets[0].rtl), dest, 1);
              apply_change_group ();
 
-             /* If REG1 was equivalent to a constant, REG0 is not.  */
-             if (note)
-               PUT_REG_NOTE_KIND (note, REG_EQUAL);
-
              /* 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);
@@ -6180,7 +6439,8 @@ cse_process_notes (x, object)
       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:
@@ -6306,12 +6566,11 @@ cse_around_loop (loop_start)
             && NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END);
        insn = NEXT_INSN (insn))
     {
-      if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
+      if (INSN_P (insn)
          && (GET_CODE (PATTERN (insn)) == SET
              || GET_CODE (PATTERN (insn)) == CLOBBER))
        cse_set_around_loop (PATTERN (insn), insn, loop_start);
-      else if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
-              && GET_CODE (PATTERN (insn)) == PARALLEL)
+      else if (INSN_P (insn) && GET_CODE (PATTERN (insn)) == PARALLEL)
        for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
          if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == SET
              || GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == CLOBBER)
@@ -6332,14 +6591,14 @@ invalidate_skipped_set (dest, set, data)
   enum rtx_code code = GET_CODE (dest);
 
   if (code == MEM
-      && ! addr_affects_sp_p (dest)    /* If this is not a stack push ... */
+      && ! addr_affects_sp_p (dest)    /* If this is not a stack push ...  */
       /* There are times when an address can appear varying and be a PLUS
         during this scan when it would be a fixed address were we to know
         the proper equivalences.  So invalidate all memory if there is
         a BLKmode or nonscalar memory reference or a reference to a
         variable address.  */
       && (MEM_IN_STRUCT_P (dest) || GET_MODE (dest) == BLKmode
-         || cse_rtx_varies_p (XEXP (dest, 0))))
+         || cse_rtx_varies_p (XEXP (dest, 0), 0)))
     {
       invalidate_memory ();
       return;
@@ -6371,12 +6630,12 @@ invalidate_skipped_block (start)
   for (insn = start; insn && GET_CODE (insn) != CODE_LABEL;
        insn = NEXT_INSN (insn))
     {
-      if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+      if (! INSN_P (insn))
        continue;
 
       if (GET_CODE (insn) == CALL_INSN)
        {
-         if (! CONST_CALL_P (insn))
+         if (! CONST_OR_PURE_CALL_P (insn))
            invalidate_memory ();
          invalidate_for_call ();
        }
@@ -6471,7 +6730,7 @@ cse_set_around_loop (x, insn, loop_start)
                    rtx q;
                    rtx cse_check_loop_start_value = SET_SRC (x);
                    for (q = p; q != loop_start; q = NEXT_INSN (q))
-                     if (GET_RTX_CLASS (GET_CODE (q)) == 'i')
+                     if (INSN_P (q))
                        note_stores (PATTERN (q),
                                     cse_check_loop_start,
                                     &cse_check_loop_start_value);
@@ -6543,8 +6802,7 @@ cse_end_of_basic_block (insn, data, follow_jumps, after_loop, skip_blocks)
   rtx p = insn, q;
   int nsets = 0;
   int low_cuid = INSN_CUID (insn), high_cuid = INSN_CUID (insn);
-  rtx next =
-    GET_RTX_CLASS (GET_CODE (insn)) == 'i' ? insn : next_real_insn (insn);
+  rtx next = INSN_P (insn) ? insn : next_real_insn (insn);
   int path_size = data->path_size;
   int path_entry = 0;
   int i;
@@ -6593,17 +6851,16 @@ 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,
         especially if it is really an ASM_OPERANDS.  */
-      if (GET_RTX_CLASS (GET_CODE (p)) == 'i'
-         && GET_CODE (PATTERN (p)) == PARALLEL)
+      if (INSN_P (p) && GET_CODE (PATTERN (p)) == PARALLEL)
        nsets += XVECLEN (PATTERN (p), 0);
       else if (GET_CODE (p) != NOTE)
        nsets += 1;
@@ -6648,7 +6905,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;
 
@@ -6788,10 +7046,8 @@ cse_main (f, nregs, after_loop, file)
   memory_extend_rtx = gen_rtx_ZERO_EXTEND (VOIDmode, NULL_RTX);
 #endif
 
-  /* Discard all the free elements of the previous function
-     since they are allocated in the temporarily obstack.  */
-  bzero ((char *) table, sizeof table);
-  free_element_chain = 0;
+  /* Reset the counter indicating how many elements have been made
+     thus far.  */
   n_elements_made = 0;
 
   /* Find the largest uid.  */
@@ -6815,39 +7071,7 @@ 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_REGNUM) && !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);
-
-  if (ggc_p)
-    ggc_push_context ();
+  ggc_push_context ();
 
   /* Loop over basic blocks.
      Compute the maximum number of qty's needed for each basic block
@@ -6906,7 +7130,7 @@ cse_main (f, nregs, after_loop, file)
          cse_jumps_altered |= old_cse_jumps_altered;
        }
 
-      if (ggc_p && cse_altered)
+      if (cse_altered)
        ggc_collect ();
 
 #ifdef USE_C_ALLOCA
@@ -6914,8 +7138,7 @@ cse_main (f, nregs, after_loop, file)
 #endif
     }
 
-  if (ggc_p)
-    ggc_pop_context ();
+  ggc_pop_context ();
 
   if (max_elements_made < n_elements_made)
     max_elements_made = n_elements_made;
@@ -7031,6 +7254,13 @@ cse_basic_block (from, to, next_branch, around_loop)
            }
 
          cse_insn (insn, libcall_insn);
+
+         /* 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;
        }
 
       /* If INSN is now an unconditional jump, skip to the end of our
@@ -7124,20 +7354,40 @@ 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_DEAD note.  Return one if so.  DATA is the insn.  */
+
+static int
+check_for_label_ref (rtl, data)
+     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
+         && 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.
@@ -7201,8 +7451,8 @@ count_reg_usage (x, counts, dest, incr)
 
     case CALL_INSN:
       count_reg_usage (CALL_INSN_FUNCTION_USAGE (x), counts, NULL_RTX, incr);
+      /* Fall through.  */
 
-      /* ... falls through ...  */
     case INSN:
     case JUMP_INSN:
       count_reg_usage (PATTERN (x), counts, NULL_RTX, incr);
@@ -7236,6 +7486,101 @@ count_reg_usage (x, counts, dest, incr)
     }
 }
 \f
+/* Return true if set is live.  */
+static bool
+set_live_p (set, insn, counts)
+     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 (insn, counts)
+     rtx insn;
+     int *counts;
+{
+  int i;
+  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 (insn)
+     rtx insn;
+{
+  rtx note;
+  /* 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)
+    {
+      rtx set = single_set (insn);
+      rtx new = simplify_rtx (XEXP (note, 0));
+
+      if (!new)
+       new = XEXP (note, 0);
+
+      if (set && validate_change (insn, &SET_SRC (set), new, 0))
+       {
+         remove_note (insn, find_reg_note (insn, REG_RETVAL, NULL_RTX));
+         return true;
+       }
+    }
+  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.
 
@@ -7245,17 +7590,16 @@ count_reg_usage (x, counts, dest, incr)
    remaining passes of the compilation are also sped up.  */
 
 void
-delete_trivially_dead_insns (insns, nreg)
+delete_trivially_dead_insns (insns, nreg, preserve_basic_blocks)
      rtx insns;
      int nreg;
+     int preserve_basic_blocks;
 {
   int *counts;
   rtx insn, prev;
-#ifdef HAVE_cc0
-  rtx tem;
-#endif
   int i;
   int in_libcall = 0, dead_libcall = 0;
+  basic_block bb;
 
   /* First count the number of times each register is used.  */
   counts = (int *) xcalloc (nreg, sizeof (int));
@@ -7270,136 +7614,90 @@ delete_trivially_dead_insns (insns, nreg)
      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 (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+  if (! INSN_P (insn))
     insn = prev_real_insn (insn);
 
-  for (; insn; insn = prev)
-    {
-      int live_insn = 0;
-      rtx note;
-
-      prev = prev_real_insn (insn);
+  if (!preserve_basic_blocks)
+    for (; insn; insn = prev)
+      {
+       int live_insn = 0;
 
-      /* Don't delete any insns that are part of a libcall block unless
-        we can delete the whole libcall block.
+       prev = 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))
-       {
-         in_libcall = 1;
-         live_insn = 1;
-         dead_libcall = 0;
+       /* Don't delete any insns that are part of a libcall block unless
+          we can delete the whole libcall block.
 
-         /* See if there's a REG_EQUAL note on this insn and try to
-            replace the source with the REG_EQUAL expression.
+          Flow or loop might get confused if we did that.  Remember
+          that we are scanning backwards.  */
+       if (find_reg_note (insn, REG_RETVAL, NULL_RTX))
+         {
+           in_libcall = 1;
+           live_insn = 1;
+           dead_libcall = dead_libcall_p (insn);
+         }
+       else if (in_libcall)
+         live_insn = ! dead_libcall;
+       else
+         live_insn = insn_live_p (insn, counts);
 
-            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 this is a dead insn, delete it and show registers in it aren't
+          being used.  */
 
-             if (!new)
-               new = XEXP (note, 0);
+       if (! live_insn)
+         {
+           count_reg_usage (insn, counts, NULL_RTX, -1);
+           delete_insn (insn);
+         }
 
-             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 (find_reg_note (insn, REG_LIBCALL, NULL_RTX))
+         {
+           in_libcall = 0;
+           dead_libcall = 0;
+         }
+      }
+  else
+    for (i = 0; i < n_basic_blocks; i++)
+      for (bb = BASIC_BLOCK (i), insn = bb->end; insn != bb->head; insn = prev)
        {
-         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))))
-           ;
+         int live_insn = 0;
 
-#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
-                      || GET_RTX_CLASS (GET_CODE (tem)) != 'i'
-                      || ! 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);
+         prev = PREV_INSN (insn);
+         if (!INSN_P (insn))
+           continue;
 
-           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)))
-                 ;
+         /* Don't delete any insns that are part of a libcall block unless
+            we can delete the whole libcall block.
 
-#ifdef HAVE_cc0
-               else if (GET_CODE (SET_DEST (elt)) == CC0
-                        && ! side_effects_p (SET_SRC (elt))
-                        && ((tem = next_nonnote_insn (insn)) == 0
-                            || GET_RTX_CLASS (GET_CODE (tem)) != 'i'
-                            || ! 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);
+           }
+         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, NULL_RTX, -1);
+             if (insn == bb->end)
+               bb->end = PREV_INSN (insn);
+             flow_delete_insn (insn);
+           }
 
-      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;
+           }
        }
-    }
 
   /* Clean up.  */
   free (counts);