OSDN Git Service

* cp-tree.h (build_lang_field_decl): Remove.
[pf3gnuchains/gcc-fork.git] / gcc / cse.c
index 593d075..f279cd1 100644 (file)
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -1,5 +1,5 @@
 /* Common subexpression elimination for GNU compiler.
-   Copyright (C) 1987, 88, 89, 92-6, 1997 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 89, 92-7, 1998, 1999 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -20,8 +20,9 @@ Boston, MA 02111-1307, USA.  */
 
 
 #include "config.h"
-/* Must precede rtl.h for FFS.  */
-#include <stdio.h>
+/* stdio.h must precede rtl.h for FFS.  */
+#include "system.h"
+#include <setjmp.h>
 
 #include "rtl.h"
 #include "regs.h"
@@ -30,8 +31,11 @@ Boston, MA 02111-1307, USA.  */
 #include "real.h"
 #include "insn-config.h"
 #include "recog.h"
-
-#include <setjmp.h>
+#include "function.h"
+#include "expr.h"
+#include "toplev.h"
+#include "output.h"
+#include "splay-tree.h"
 
 /* The basic idea of common subexpression elimination is to go
    through the code, keeping a record of expressions that would
@@ -192,6 +196,11 @@ Related expressions:
 
 static int max_reg;
 
+/* One plus largest instruction UID used in this function at time of
+   cse_main call.  */
+
+static int max_insn_uid;
+
 /* Length of vectors indexed by quantity number.
    We know in advance we will not need a quantity number this big.  */
 
@@ -267,11 +276,6 @@ static rtx prev_insn;
 
 static rtx this_insn;
 
-/* Index by register number, gives the quantity number
-   of the register's current contents.  */
-
-static int *reg_qty;
-
 /* Index by register number, gives the number of the next (or
    previous) register in the chain of registers sharing the same
    value.
@@ -283,19 +287,36 @@ static int *reg_qty;
 static int *reg_next_eqv;
 static int *reg_prev_eqv;
 
-/* Index by register number, gives the number of times
-   that register has been altered in the current basic block.  */
+struct cse_reg_info {
+  union {
+    /* The number of times the register has been altered in the current
+       basic block.  */
+    int reg_tick;
+    
+    /* The next cse_reg_info structure in the free list.  */
+    struct cse_reg_info* next;
+  } variant;
+
+  /* The REG_TICK value at which rtx's containing this register are
+     valid in the hash table.  If this does not equal the current
+     reg_tick value, such expressions existing in the hash table are
+     invalid.  */
+  int reg_in_table;
+
+  /* The quantity number of the register's current contents.  */
+  int reg_qty;
+};
 
-static int *reg_tick;
+/* A free list of cse_reg_info entries.  */
+static struct cse_reg_info *cse_reg_info_free_list;
 
-/* Index by register number, gives the reg_tick value at which
-   rtx's containing this register are valid in the hash table.
-   If this does not equal the current reg_tick value, such expressions
-   existing in the hash table are invalid.
-   If this is -1, no expressions containing this register have been
-   entered in the table.  */
+/* A mapping from registers to cse_reg_info data structures.  */
+static splay_tree cse_reg_info_tree;
 
-static int *reg_in_table;
+/* The last lookup we did into the cse_reg_info_tree.  This allows us
+   to cache repeated lookups.  */
+static int cached_regno;
+static struct cse_reg_info *cached_cse_reg_info;
 
 /* A HARD_REG_SET containing all the hard registers for which there is 
    currently a REG expression in the hash table.  Note the difference
@@ -309,14 +330,6 @@ static HARD_REG_SET hard_regs_in_table;
 
 static HARD_REG_SET regs_invalidated_by_call;
 
-/* Two vectors of ints:
-   one containing max_reg -1's; the other max_reg + 500 (an approximation
-   for max_qty) elements where element i contains i.
-   These are used to initialize various other vectors fast.  */
-
-static int *all_minus_one;
-static int *consec_ints;
-
 /* CUID of insn that starts the basic block currently being cse-processed.  */
 
 static int cse_basic_block_start;
@@ -440,7 +453,7 @@ struct table_elt
 
 #define HASH(X, M)     \
  (GET_CODE (X) == REG && REGNO (X) >= FIRST_PSEUDO_REGISTER    \
-  ? (((unsigned) REG << 7) + (unsigned) reg_qty[REGNO (X)]) % NBUCKETS \
+  ? (((unsigned) REG << 7) + (unsigned) REG_QTY (REGNO (X))) % NBUCKETS        \
   : canon_hash (X, M) % NBUCKETS)
 
 /* Determine whether register number N is considered a fixed register for CSE.
@@ -485,10 +498,39 @@ struct table_elt
       : 2)                                                             \
    : notreg_cost(X))
 
+/* Get the info associated with register N.  */
+
+#define GET_CSE_REG_INFO(N)                    \
+  (((N) == cached_regno && cached_cse_reg_info)        \
+   ? cached_cse_reg_info : get_cse_reg_info ((N)))
+
+/* Get the number of times this register has been updated in this
+   basic block.  */
+
+#define REG_TICK(N) ((GET_CSE_REG_INFO (N))->variant.reg_tick)
+
+/* Get the point at which REG was recorded in the table.  */
+
+#define REG_IN_TABLE(N) ((GET_CSE_REG_INFO (N))->reg_in_table)
+
+/* Get the quantity number for REG.  */
+
+#define REG_QTY(N) ((GET_CSE_REG_INFO (N))->reg_qty)
+
 /* Determine if the quantity number for register X represents a valid index
    into the `qty_...' variables.  */
 
-#define REGNO_QTY_VALID_P(N) (reg_qty[N] != (N))
+#define REGNO_QTY_VALID_P(N) (REG_QTY (N) != (N))
+
+#ifdef ADDRESS_COST
+/* The ADDRESS_COST macro 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.  */
+#define CSE_ADDRESS_COST(RTX)                                  \
+  ((GET_CODE (RTX) == ADDRESSOF && REG_P (XEXP ((RTX), 0)))    \
+   ? -1 : ADDRESS_COST(RTX))
+#endif 
 
 static struct table_elt *table[NBUCKETS];
 
@@ -609,6 +651,7 @@ static void merge_equiv_classes PROTO((struct table_elt *,
 static void invalidate         PROTO((rtx, enum machine_mode));
 static int cse_rtx_varies_p    PROTO((rtx));
 static void remove_invalid_refs        PROTO((int));
+static void remove_invalid_subreg_refs PROTO((int, int, enum machine_mode));
 static void rehash_using_reg   PROTO((rtx));
 static void invalidate_memory  PROTO((void));
 static void invalidate_for_call        PROTO((void));
@@ -634,7 +677,7 @@ static rtx equiv_constant   PROTO((rtx));
 static void record_jump_equiv  PROTO((rtx, int));
 static void record_jump_cond   PROTO((enum rtx_code, enum machine_mode,
                                       rtx, rtx, int));
-static void cse_insn           PROTO((rtx, int));
+static void cse_insn           PROTO((rtx, rtx));
 static int note_mem_written    PROTO((rtx));
 static void invalidate_from_clobbers PROTO((rtx));
 static rtx cse_process_notes   PROTO((rtx, rtx));
@@ -645,9 +688,33 @@ static void cse_check_loop_start PROTO((rtx, rtx));
 static void cse_set_around_loop        PROTO((rtx, rtx, rtx));
 static rtx cse_basic_block     PROTO((rtx, rtx, struct branch_path *, int));
 static void count_reg_usage    PROTO((rtx, int *, rtx, int));
+extern void dump_class          PROTO((struct table_elt*));
+static void check_fold_consts  PROTO((PTR));
+static struct cse_reg_info* get_cse_reg_info PROTO((int));
+static void free_cse_reg_info   PROTO((splay_tree_value));
+static void flush_hash_table   PROTO((void));
 
 extern int rtx_equal_function_value_matters;
 \f
+/* 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;
+{
+  struct table_elt *elt;
+
+  fprintf (stderr, "Equivalence chain for ");
+  print_rtl (stderr, classp->exp);
+  fprintf (stderr, ": \n");
+  
+  for (elt = classp->first_same_value; elt; elt = elt->next_same_value)
+    {
+      print_rtl (stderr, elt->exp);
+      fprintf (stderr, "\n");
+    }
+}
+
 /* 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.
@@ -684,7 +751,7 @@ notreg_cost (x)
 int
 rtx_cost (x, outer_code)
      rtx x;
-     enum rtx_code outer_code;
+     enum rtx_code outer_code ATTRIBUTE_UNUSED;
 {
   register int i, j;
   register enum rtx_code code;
@@ -744,7 +811,15 @@ rtx_cost (x, outer_code)
 #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
+      break;
     }
 
   /* Sum the costs of the sub-rtx's, plus cost of this operation,
@@ -761,6 +836,57 @@ rtx_cost (x, outer_code)
   return total;
 }
 \f
+static struct cse_reg_info *
+get_cse_reg_info (regno)
+     int regno;
+{
+  struct cse_reg_info *cri;
+  splay_tree_node n;
+
+  /* See if we already have this entry.  */
+  n = splay_tree_lookup (cse_reg_info_tree, 
+                       (splay_tree_key) regno);
+  if (n)
+    cri = (struct cse_reg_info *) (n->value);
+  else 
+    {
+      /* Get a new cse_reg_info structure.  */
+      if (cse_reg_info_free_list) 
+       {
+         cri = cse_reg_info_free_list;
+         cse_reg_info_free_list = cri->variant.next;
+       }
+      else
+       cri = (struct cse_reg_info *) xmalloc (sizeof (struct cse_reg_info));
+
+      /* Initialize it.  */
+      cri->variant.reg_tick = 0;
+      cri->reg_in_table = -1;
+      cri->reg_qty = regno;
+
+      splay_tree_insert (cse_reg_info_tree, 
+                        (splay_tree_key) regno, 
+                        (splay_tree_value) cri);
+    }
+
+  /* Cache this lookup; we tend to be looking up information about the
+     same register several times in a row.  */
+  cached_regno = regno;
+  cached_cse_reg_info = cri;
+
+  return cri;
+}
+
+static void
+free_cse_reg_info (v)
+     splay_tree_value v;
+{
+  struct cse_reg_info *cri = (struct cse_reg_info *) v;
+  
+  cri->variant.next = cse_reg_info_free_list;
+  cse_reg_info_free_list = cri;
+}
+
 /* Clear the hash table and initialize each register with its own quantity,
    for a new basic block.  */
 
@@ -771,11 +897,15 @@ new_basic_block ()
 
   next_qty = max_reg;
 
-  bzero ((char *) reg_tick, max_reg * sizeof (int));
+  if (cse_reg_info_tree) 
+    {
+      splay_tree_delete (cse_reg_info_tree);
+      cached_cse_reg_info = 0;
+    }
+
+  cse_reg_info_tree = splay_tree_new (splay_tree_compare_ints, 0, 
+                                     free_cse_reg_info);
 
-  bcopy ((char *) all_minus_one, (char *) reg_in_table,
-        max_reg * sizeof (int));
-  bcopy ((char *) consec_ints, (char *) reg_qty, max_reg * sizeof (int));
   CLEAR_HARD_REG_SET (hard_regs_in_table);
 
   /* The per-quantity values used to be initialized here, but it is
@@ -812,7 +942,7 @@ make_new_qty (reg)
   if (next_qty >= max_qty)
     abort ();
 
-  q = reg_qty[reg] = next_qty++;
+  q = REG_QTY (reg) = next_qty++;
   qty_first_reg[q] = reg;
   qty_last_reg[q] = reg;
   qty_const[q] = qty_const_insn[q] = 0;
@@ -829,13 +959,13 @@ make_regs_eqv (new, old)
      register int new, old;
 {
   register int lastr, firstr;
-  register int q = reg_qty[old];
+  register int q = REG_QTY (old);
 
   /* Nothing should become eqv until it has a "non-invalid" qty number.  */
   if (! REGNO_QTY_VALID_P (old))
     abort ();
 
-  reg_qty[new] = q;
+  REG_QTY (new) = q;
   firstr = qty_first_reg[q];
   lastr = qty_last_reg[q];
 
@@ -889,7 +1019,7 @@ static void
 delete_reg_equiv (reg)
      register int reg;
 {
-  register int q = reg_qty[reg];
+  register int q = REG_QTY (reg);
   register int p, n;
 
   /* If invalid, do nothing.  */
@@ -908,7 +1038,7 @@ delete_reg_equiv (reg)
   else
     qty_first_reg[q] = n;
 
-  reg_qty[reg] = reg;
+  REG_QTY (reg) = reg;
 }
 
 /* Remove any invalid expressions from the hash table
@@ -946,15 +1076,39 @@ mention_regs (x)
 
       for (i = regno; i < endregno; i++)
        {
-         if (reg_in_table[i] >= 0 && reg_in_table[i] != reg_tick[i])
+         if (REG_IN_TABLE (i) >= 0 && REG_IN_TABLE (i) != REG_TICK (i))
            remove_invalid_refs (i);
 
-         reg_in_table[i] = reg_tick[i];
+         REG_IN_TABLE (i) = REG_TICK (i);
        }
 
       return 0;
     }
 
+  /* If this is a SUBREG, we don't want to discard other SUBREGs of the same
+     pseudo if they don't use overlapping words.  We handle only pseudos
+     here for simplicity.  */
+  if (code == SUBREG && GET_CODE (SUBREG_REG (x)) == REG
+      && REGNO (SUBREG_REG (x)) >= FIRST_PSEUDO_REGISTER)
+    {
+      int i = REGNO (SUBREG_REG (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 entrire 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));
+       }
+
+      REG_IN_TABLE (i) = REG_TICK (i);
+      return 0;
+    }
+
   /* If X is a comparison or a COMPARE and either operand is a register
      that does not have a quantity, give it one.  This is so that a later
      call to record_jump_equiv won't cause X to be assigned a different
@@ -1019,7 +1173,7 @@ insert_regs (x, classp, modified)
         wrong mode for that equivalence, don't do anything here.  */
 
       if (REGNO_QTY_VALID_P (regno)
-         && qty_mode[reg_qty[regno]] != GET_MODE (x))
+         && qty_mode[REG_QTY (regno)] != GET_MODE (x))
        return 0;
 
       if (modified || ! REGNO_QTY_VALID_P (regno))
@@ -1036,7 +1190,7 @@ insert_regs (x, classp, modified)
                }
 
          make_new_qty (regno);
-         qty_mode[reg_qty[regno]] = GET_MODE (x);
+         qty_mode[REG_QTY (regno)] = GET_MODE (x);
          return 1;
        }
 
@@ -1052,8 +1206,19 @@ 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))))
     {
+      int regno = REGNO (SUBREG_REG (x));
+
       insert_regs (SUBREG_REG (x), NULL_PTR, 0);
-      mention_regs (SUBREG_REG (x));
+      /* 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)++;
+      mention_regs (x);
       return 1;
     }
   else
@@ -1229,6 +1394,17 @@ lookup_as_function (x, code)
 {
   register struct table_elt *p = lookup (x, safe_hash (x, VOIDmode) % NBUCKETS,
                                         GET_MODE (x));
+  /* If we are looking for a CONST_INT, the mode doesn't really matter, as
+     long as we are narrowing.  So if we looked in vain for a mode narrower
+     than word_mode before, look for word_mode now.  */
+  if (p == 0 && code == CONST_INT
+      && GET_MODE_SIZE (GET_MODE (x)) < GET_MODE_SIZE (word_mode))
+    {
+      x = copy_rtx (x);
+      PUT_MODE (x, word_mode);
+      p = lookup (x, safe_hash (x, VOIDmode) % NBUCKETS, word_mode);
+    }
+
   if (p == 0)
     return 0;
 
@@ -1376,12 +1552,12 @@ insert (x, classp, hash, mode)
   if (elt->is_const && classp && GET_CODE (classp->exp) == REG
       && GET_CODE (x) != REG)
     {
-      qty_const[reg_qty[REGNO (classp->exp)]]
-       = gen_lowpart_if_possible (qty_mode[reg_qty[REGNO (classp->exp)]], x);
-      qty_const_insn[reg_qty[REGNO (classp->exp)]] = this_insn;
+      qty_const[REG_QTY (REGNO (classp->exp))]
+       = gen_lowpart_if_possible (qty_mode[REG_QTY (REGNO (classp->exp))], x);
+      qty_const_insn[REG_QTY (REGNO (classp->exp))] = this_insn;
     }
 
-  else if (GET_CODE (x) == REG && classp && ! qty_const[reg_qty[REGNO (x)]]
+  else if (GET_CODE (x) == REG && classp && ! qty_const[REG_QTY (REGNO (x))]
           && ! elt->is_const)
     {
       register struct table_elt *p;
@@ -1390,17 +1566,17 @@ insert (x, classp, hash, mode)
        {
          if (p->is_const && GET_CODE (p->exp) != REG)
            {
-             qty_const[reg_qty[REGNO (x)]]
+             qty_const[REG_QTY (REGNO (x))]
                = gen_lowpart_if_possible (GET_MODE (x), p->exp);
-             qty_const_insn[reg_qty[REGNO (x)]] = this_insn;
+             qty_const_insn[REG_QTY (REGNO (x))] = this_insn;
              break;
            }
        }
     }
 
-  else if (GET_CODE (x) == REG && qty_const[reg_qty[REGNO (x)]]
-          && GET_MODE (x) == qty_mode[reg_qty[REGNO (x)]])
-    qty_const_insn[reg_qty[REGNO (x)]] = this_insn;
+  else if (GET_CODE (x) == REG && qty_const[REG_QTY (REGNO (x))]
+          && GET_MODE (x) == qty_mode[REG_QTY (REGNO (x))])
+    qty_const_insn[REG_QTY (REGNO (x))] = this_insn;
 
   /* If this is a constant with symbolic value,
      and it has a term with an explicit integer value,
@@ -1492,6 +1668,28 @@ merge_equiv_classes (class1, class2)
     }
 }
 \f
+
+/* Flush the entire hash table.  */
+
+static void
+flush_hash_table ()
+{
+  int i;
+  struct table_elt *p;
+
+  for (i = 0; i < NBUCKETS; i++)
+    for (p = table[i]; p; p = table[i])
+      {
+       /* Note that invalidate can remove elements
+          after P in the current hash chain.  */
+       if (GET_CODE (p->exp) == REG)
+         invalidate (p->exp, p->mode);
+       else
+         remove_from_table (p, i);
+      }
+}
+
+
 /* Remove from the hash table, or mark as invalid,
    all expressions whose values could be altered by storing in X.
    X is a register, a subreg, or a memory reference with nonvarying address
@@ -1526,7 +1724,7 @@ invalidate (x, full_mode)
       register unsigned hash = HASH (x, GET_MODE (x));
 
       /* Remove REGNO from any quantity list it might be on and indicate
-        that it's value might have changed.  If it is a pseudo, remove its
+        that its value might have changed.  If it is a pseudo, remove its
         entry from the hash table.
 
         For a hard register, we do the first two actions above for any
@@ -1535,7 +1733,7 @@ invalidate (x, full_mode)
         overlap these registers.  */
 
       delete_reg_equiv (regno);
-      reg_tick[regno]++;
+      REG_TICK (regno)++;
 
       if (regno >= FIRST_PSEUDO_REGISTER)
        {
@@ -1544,7 +1742,7 @@ invalidate (x, full_mode)
 
          struct table_elt *elt;
 
-         while (elt = lookup_for_remove (x, hash, GET_MODE (x)))
+         while ((elt = lookup_for_remove (x, hash, GET_MODE (x))))
            remove_from_table (elt, hash);
        }
       else
@@ -1562,7 +1760,7 @@ invalidate (x, full_mode)
              in_table |= TEST_HARD_REG_BIT (hard_regs_in_table, i);
              CLEAR_HARD_REG_BIT (hard_regs_in_table, i);
              delete_reg_equiv (i);
-             reg_tick[i]++;
+             REG_TICK (i)++;
            }
 
          if (in_table)
@@ -1579,7 +1777,7 @@ invalidate (x, full_mode)
                  tendregno
                    = tregno + HARD_REGNO_NREGS (tregno, GET_MODE (p->exp));
                  if (tendregno > regno && tregno < endregno)
-                 remove_from_table (p, hash);
+                   remove_from_table (p, hash);
                }
        }
 
@@ -1594,6 +1792,24 @@ invalidate (x, full_mode)
       return;
     }
 
+  /* If X is a parallel, invalidate all of its elements.  */
+
+  if (GET_CODE (x) == PARALLEL)
+    {
+      for (i = XVECLEN (x, 0) - 1; i >= 0 ; --i)
+       invalidate (XVECEXP (x, 0, i), VOIDmode);
+      return;
+    }
+
+  /* If X is an expr_list, this is part of a disjoint return value;
+     extract the location in question ignoring the offset.  */
+
+  if (GET_CODE (x) == EXPR_LIST)
+    {
+      invalidate (XEXP (x, 0), VOIDmode);
+      return;
+    }
+
   /* X is not a register; it must be a memory reference with
      a nonvarying address.  Remove all hash table elements
      that refer to overlapping pieces of memory.  */
@@ -1641,6 +1857,37 @@ remove_invalid_refs (regno)
          remove_from_table (p, i);
       }
 }
+
+/* Likewise for a subreg with subreg_reg WORD and mode MODE.  */
+static void
+remove_invalid_subreg_refs (regno, word, mode)
+     int regno;
+     int word;
+     enum machine_mode mode;
+{
+  register int i;
+  register struct table_elt *p, *next;
+  int end = word + (GET_MODE_SIZE (mode) - 1) / UNITS_PER_WORD;
+
+  for (i = 0; i < NBUCKETS; i++)
+    for (p = table[i]; p; p = next)
+      {
+       rtx exp;
+       next = p->next_same_hash;
+       
+       exp = p->exp;
+       if (GET_CODE (p->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))
+         remove_from_table (p, i);
+      }
+}
 \f
 /* Recompute the hash codes of any valid entries in the hash table that
    reference X, if X is a register, or SUBREG_REG (X) if X is a SUBREG.
@@ -1651,7 +1898,7 @@ static void
 rehash_using_reg (x)
      rtx x;
 {
-  int i;
+  unsigned int i;
   struct table_elt *p, *next;
   unsigned hash;
 
@@ -1662,8 +1909,8 @@ rehash_using_reg (x)
      valid entries in the table, we have no work to do.  */
 
   if (GET_CODE (x) != REG
-      || reg_in_table[REGNO (x)] < 0
-      || reg_in_table[REGNO (x)] != reg_tick[REGNO (x)])
+      || REG_IN_TABLE (REGNO (x)) < 0
+      || REG_IN_TABLE (REGNO (x)) != REG_TICK (REGNO (x)))
     return;
 
   /* Scan all hash chains looking for valid entries that mention X.
@@ -1716,8 +1963,8 @@ invalidate_for_call ()
     if (TEST_HARD_REG_BIT (regs_invalidated_by_call, regno))
       {
        delete_reg_equiv (regno);
-       if (reg_tick[regno] >= 0)
-         reg_tick[regno]++;
+       if (REG_TICK (regno) >= 0)
+         REG_TICK (regno)++;
 
        in_table |= (TEST_HARD_REG_BIT (hard_regs_in_table, regno) != 0);
       }
@@ -1868,7 +2115,12 @@ canon_hash (x, mode)
 
        /* 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, and sp 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
@@ -1878,15 +2130,30 @@ canon_hash (x, mode)
                    && regno != FRAME_POINTER_REGNUM
                    && regno != HARD_FRAME_POINTER_REGNUM
                    && regno != ARG_POINTER_REGNUM
-                   && regno != STACK_POINTER_REGNUM)))
+                   && regno != STACK_POINTER_REGNUM
+                   && GET_MODE_CLASS (GET_MODE (x)) != MODE_CC)))
          {
            do_not_record = 1;
            return 0;
          }
-       hash += ((unsigned) REG << 7) + (unsigned) reg_qty[regno];
+       hash += ((unsigned) REG << 7) + (unsigned) REG_QTY (regno);
        return hash;
       }
 
+    /* We handle SUBREG of a REG specially because the underlying
+       reg changes its hash value with every value change; we don't
+       want to have to forget unrelated subregs when one subreg changes.  */
+    case SUBREG:
+      {
+       if (GET_CODE (SUBREG_REG (x)) == REG)
+         {
+           hash += (((unsigned) SUBREG << 7)
+                    + REGNO (SUBREG_REG (x)) + SUBREG_WORD (x));
+           return hash;
+         }
+       break;
+      }
+
     case CONST_INT:
       {
        unsigned HOST_WIDE_INT tem = INTVAL (x);
@@ -1912,12 +2179,12 @@ canon_hash (x, mode)
       /* Assume there is only one rtx object for any given label.  */
     case LABEL_REF:
       hash
-       += ((unsigned) LABEL_REF << 7) + (unsigned HOST_WIDE_INT) XEXP (x, 0);
+       += ((unsigned) LABEL_REF << 7) + (unsigned long) XEXP (x, 0);
       return hash;
 
     case SYMBOL_REF:
       hash
-       += ((unsigned) SYMBOL_REF << 7) + (unsigned HOST_WIDE_INT) XSTR (x, 0);
+       += ((unsigned) SYMBOL_REF << 7) + (unsigned long) XSTR (x, 0);
       return hash;
 
     case MEM:
@@ -2032,7 +2299,7 @@ safe_hash (x, mode)
    in all the places that search a hash table chain for an equivalent
    for a given value.  A possible equivalent that has different structure
    has its hash code computed from different data.  Whether the hash code
-   is the same as that of the the given value is pure luck.  */
+   is the same as that of the given value is pure luck.  */
 
 static int
 exp_equiv_p (x, y, validate, equal_values)
@@ -2061,15 +2328,15 @@ exp_equiv_p (x, y, validate, equal_values)
         equivalent.  We only have to validate if Y is a register.  */
       if (CONSTANT_P (x) && GET_CODE (y) == REG
          && REGNO_QTY_VALID_P (REGNO (y))
-         && GET_MODE (y) == qty_mode[reg_qty[REGNO (y)]]
-         && rtx_equal_p (x, qty_const[reg_qty[REGNO (y)]])
-         && (! validate || reg_in_table[REGNO (y)] == reg_tick[REGNO (y)]))
+         && GET_MODE (y) == qty_mode[REG_QTY (REGNO (y))]
+         && rtx_equal_p (x, qty_const[REG_QTY (REGNO (y))])
+         && (! validate || REG_IN_TABLE (REGNO (y)) == REG_TICK (REGNO (y))))
        return 1;
 
       if (CONSTANT_P (y) && code == REG
          && REGNO_QTY_VALID_P (REGNO (x))
-         && GET_MODE (x) == qty_mode[reg_qty[REGNO (x)]]
-         && rtx_equal_p (y, qty_const[reg_qty[REGNO (x)]]))
+         && GET_MODE (x) == qty_mode[REG_QTY (REGNO (x))]
+         && rtx_equal_p (y, qty_const[REG_QTY (REGNO (x))]))
        return 1;
 
       return 0;
@@ -2106,14 +2373,14 @@ exp_equiv_p (x, y, validate, equal_values)
           equivalent.  If there are and we are not to validate, they
           are equivalent.  Otherwise, ensure all regs are up-to-date.  */
 
-       if (reg_qty[REGNO (x)] != reg_qty[regno])
+       if (REG_QTY (REGNO (x)) != REG_QTY (regno))
          return 0;
 
        if (! validate)
          return 1;
 
        for (i = regno; i < endregno; i++)
-         if (reg_in_table[i] != reg_tick[i])
+         if (REG_IN_TABLE (i) != REG_TICK (i))
            return 0;
 
        return 1;
@@ -2263,25 +2530,29 @@ set_nonvarying_address_components (addr, size, pbase, pstart, pend)
   start = 0;
   end = 0;
 
+  if (flag_pic && GET_CODE (base) == PLUS
+      && XEXP (base, 0) == pic_offset_table_rtx)
+    base = XEXP (base, 1);
+
   /* Registers with nonvarying addresses usually have constant equivalents;
      but the frame pointer register is also possible.  */
   if (GET_CODE (base) == REG
       && qty_const != 0
       && REGNO_QTY_VALID_P (REGNO (base))
-      && qty_mode[reg_qty[REGNO (base)]] == GET_MODE (base)
-      && qty_const[reg_qty[REGNO (base)]] != 0)
-    base = qty_const[reg_qty[REGNO (base)]];
+      && qty_mode[REG_QTY (REGNO (base))] == GET_MODE (base)
+      && qty_const[REG_QTY (REGNO (base))] != 0)
+    base = qty_const[REG_QTY (REGNO (base))];
   else if (GET_CODE (base) == PLUS
           && GET_CODE (XEXP (base, 1)) == CONST_INT
           && GET_CODE (XEXP (base, 0)) == REG
           && qty_const != 0
           && REGNO_QTY_VALID_P (REGNO (XEXP (base, 0)))
-          && (qty_mode[reg_qty[REGNO (XEXP (base, 0))]]
+          && (qty_mode[REG_QTY (REGNO (XEXP (base, 0)))]
               == GET_MODE (XEXP (base, 0)))
-          && qty_const[reg_qty[REGNO (XEXP (base, 0))]])
+          && qty_const[REG_QTY (REGNO (XEXP (base, 0)))])
     {
       start = INTVAL (XEXP (base, 1));
-      base = qty_const[reg_qty[REGNO (XEXP (base, 0))]];
+      base = qty_const[REG_QTY (REGNO (XEXP (base, 0)))];
     }
   /* This can happen as the result of virtual register instantiation,
      if the initial offset is too large to be a valid address.  */
@@ -2290,16 +2561,16 @@ set_nonvarying_address_components (addr, size, pbase, pstart, pend)
           && GET_CODE (XEXP (base, 1)) == REG
           && qty_const != 0
           && REGNO_QTY_VALID_P (REGNO (XEXP (base, 0)))
-          && (qty_mode[reg_qty[REGNO (XEXP (base, 0))]]
+          && (qty_mode[REG_QTY (REGNO (XEXP (base, 0)))]
               == GET_MODE (XEXP (base, 0)))
-          && qty_const[reg_qty[REGNO (XEXP (base, 0))]]
+          && qty_const[REG_QTY (REGNO (XEXP (base, 0)))]
           && REGNO_QTY_VALID_P (REGNO (XEXP (base, 1)))
-          && (qty_mode[reg_qty[REGNO (XEXP (base, 1))]]
+          && (qty_mode[REG_QTY (REGNO (XEXP (base, 1)))]
               == GET_MODE (XEXP (base, 1)))
-          && qty_const[reg_qty[REGNO (XEXP (base, 1))]])
+          && qty_const[REG_QTY (REGNO (XEXP (base, 1)))])
     {
-      rtx tem = qty_const[reg_qty[REGNO (XEXP (base, 1))]];
-      base = qty_const[reg_qty[REGNO (XEXP (base, 0))]];
+      rtx tem = qty_const[REG_QTY (REGNO (XEXP (base, 1)))];
+      base = qty_const[REG_QTY (REGNO (XEXP (base, 0)))];
 
       /* One of the two values must be a constant.  */
       if (GET_CODE (base) != CONST_INT)
@@ -2401,8 +2672,8 @@ cse_rtx_varies_p (x)
 
   if (GET_CODE (x) == REG
       && REGNO_QTY_VALID_P (REGNO (x))
-      && GET_MODE (x) == qty_mode[reg_qty[REGNO (x)]]
-      && qty_const[reg_qty[REGNO (x)]] != 0)
+      && GET_MODE (x) == qty_mode[REG_QTY (REGNO (x))]
+      && qty_const[REG_QTY (REGNO (x))] != 0)
     return 0;
 
   if (GET_CODE (x) == PLUS
@@ -2410,8 +2681,8 @@ cse_rtx_varies_p (x)
       && GET_CODE (XEXP (x, 0)) == REG
       && REGNO_QTY_VALID_P (REGNO (XEXP (x, 0)))
       && (GET_MODE (XEXP (x, 0))
-         == qty_mode[reg_qty[REGNO (XEXP (x, 0))]])
-      && qty_const[reg_qty[REGNO (XEXP (x, 0))]])
+         == qty_mode[REG_QTY (REGNO (XEXP (x, 0)))])
+      && qty_const[REG_QTY (REGNO (XEXP (x, 0)))])
     return 0;
 
   /* This can happen as the result of virtual register instantiation, if
@@ -2424,12 +2695,12 @@ cse_rtx_varies_p (x)
       && GET_CODE (XEXP (x, 1)) == REG
       && REGNO_QTY_VALID_P (REGNO (XEXP (x, 0)))
       && (GET_MODE (XEXP (x, 0))
-         == qty_mode[reg_qty[REGNO (XEXP (x, 0))]])
-      && qty_const[reg_qty[REGNO (XEXP (x, 0))]]
+         == qty_mode[REG_QTY (REGNO (XEXP (x, 0)))])
+      && qty_const[REG_QTY (REGNO (XEXP (x, 0)))]
       && REGNO_QTY_VALID_P (REGNO (XEXP (x, 1)))
       && (GET_MODE (XEXP (x, 1))
-         == qty_mode[reg_qty[REGNO (XEXP (x, 1))]])
-      && qty_const[reg_qty[REGNO (XEXP (x, 1))]])
+         == qty_mode[REG_QTY (REGNO (XEXP (x, 1)))])
+      && qty_const[REG_QTY (REGNO (XEXP (x, 1)))])
     return 0;
 
   return rtx_varies_p (x);
@@ -2485,10 +2756,10 @@ canon_reg (x, insn)
            || ! REGNO_QTY_VALID_P (REGNO (x)))
          return x;
 
-       first = qty_first_reg[reg_qty[REGNO (x)]];
+       first = qty_first_reg[REG_QTY (REGNO (x))];
        return (first >= FIRST_PSEUDO_REGISTER ? regno_reg_rtx[first]
                : REGNO_REG_CLASS (first) == NO_REGS ? x
-               : gen_rtx (REG, qty_mode[reg_qty[REGNO (x)]], first));
+               : gen_rtx_REG (qty_mode[REG_QTY (REGNO (x))], first));
       }
       
     default:
@@ -2546,10 +2817,12 @@ find_best_addr (insn, loc)
      rtx insn;
      rtx *loc;
 {
-  struct table_elt *elt, *p;
+  struct table_elt *elt;
   rtx addr = *loc;
-  int our_cost;
+#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 save_hash_arg_in_struct = hash_arg_in_struct;
@@ -2590,8 +2863,8 @@ find_best_addr (insn, loc)
 
       if (1
 #ifdef ADDRESS_COST
-         && (ADDRESS_COST (folded) < ADDRESS_COST (addr)
-             || (ADDRESS_COST (folded) == ADDRESS_COST (addr)
+         && (CSE_ADDRESS_COST (folded) < CSE_ADDRESS_COST (addr)
+             || (CSE_ADDRESS_COST (folded) == CSE_ADDRESS_COST (addr)
                  && rtx_cost (folded, MEM) > rtx_cost (addr, MEM)))
 #else
          && rtx_cost (folded, MEM) < rtx_cost (addr, MEM)
@@ -2618,7 +2891,7 @@ find_best_addr (insn, loc)
 #ifndef ADDRESS_COST
   if (elt)
     {
-      our_cost = elt->cost;
+      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)
@@ -2643,23 +2916,25 @@ find_best_addr (insn, loc)
 
       while (found_better)
        {
-         int best_addr_cost = ADDRESS_COST (*loc);
+         int best_addr_cost = CSE_ADDRESS_COST (*loc);
          int best_rtx_cost = (elt->cost + 1) >> 1;
          struct table_elt *best_elt = elt; 
 
          found_better = 0;
          for (p = elt->first_same_value; p; p = p->next_same_value)
-           if (! p->flag
-               && (GET_CODE (p->exp) == REG
-                   || exp_equiv_p (p->exp, p->exp, 1, 0))
-               && (ADDRESS_COST (p->exp) < best_addr_cost
-                   || (ADDRESS_COST (p->exp) == best_addr_cost
-                       && (p->cost + 1) >> 1 > best_rtx_cost)))
+           if (! p->flag)
              {
-               found_better = 1;
-               best_addr_cost = ADDRESS_COST (p->exp);
-               best_rtx_cost = (p->cost + 1) >> 1;
-               best_elt = p;
+               if ((GET_CODE (p->exp) == REG
+                    || exp_equiv_p (p->exp, p->exp, 1, 0))
+                   && (CSE_ADDRESS_COST (p->exp) < best_addr_cost
+                       || (CSE_ADDRESS_COST (p->exp) == best_addr_cost
+                           && (p->cost + 1) >> 1 > best_rtx_cost)))
+                 {
+                   found_better = 1;
+                   best_addr_cost = CSE_ADDRESS_COST (p->exp);
+                   best_rtx_cost = (p->cost + 1) >> 1;
+                   best_elt = p;
+                 }
              }
 
          if (found_better)
@@ -2711,7 +2986,7 @@ find_best_addr (insn, loc)
 
       while (found_better)
        {
-         int best_addr_cost = ADDRESS_COST (*loc);
+         int best_addr_cost = CSE_ADDRESS_COST (*loc);
          int best_rtx_cost = (COST (*loc) + 1) >> 1;
          struct table_elt *best_elt = elt; 
          rtx best_rtx = *loc;
@@ -2732,12 +3007,12 @@ find_best_addr (insn, loc)
              {
                rtx new = cse_gen_binary (GET_CODE (*loc), Pmode, p->exp, c);
 
-               if ((ADDRESS_COST (new) < best_addr_cost
-                   || (ADDRESS_COST (new) == best_addr_cost
+               if ((CSE_ADDRESS_COST (new) < best_addr_cost
+                   || (CSE_ADDRESS_COST (new) == best_addr_cost
                        && (COST (new) + 1) >> 1 > best_rtx_cost)))
                  {
                    found_better = 1;
-                   best_addr_cost = ADDRESS_COST (new);
+                   best_addr_cost = CSE_ADDRESS_COST (new);
                    best_rtx_cost = (COST (new) + 1) >> 1;
                    best_elt = p;
                    best_rtx = new;
@@ -3090,14 +3365,7 @@ simplify_unary_operation (code, mode, op, op_mode)
          abort ();
        }
 
-      /* Clear the bits that don't belong in our mode,
-        unless they and our sign bit are all one.
-        So we get either a reasonable negative value or a reasonable
-        unsigned value for this mode.  */
-      if (width < HOST_BITS_PER_WIDE_INT
-         && ((val & ((HOST_WIDE_INT) (-1) << (width - 1)))
-             != ((HOST_WIDE_INT) (-1) << (width - 1))))
-       val &= ((HOST_WIDE_INT) 1 << width) - 1;
+      val = trunc_int_for_mode (val, mode);
 
       return GEN_INT (val);
     }
@@ -3269,27 +3537,7 @@ simplify_unary_operation (code, mode, op, op_mode)
 
       set_float_handler (NULL_PTR);
 
-      /* Clear the bits that don't belong in our mode,
-        unless they and our sign bit are all one.
-        So we get either a reasonable negative value or a reasonable
-        unsigned value for this mode.  */
-      if (width < HOST_BITS_PER_WIDE_INT
-         && ((val & ((HOST_WIDE_INT) (-1) << (width - 1)))
-             != ((HOST_WIDE_INT) (-1) << (width - 1))))
-       val &= ((HOST_WIDE_INT) 1 << width) - 1;
-
-      /* If this would be an entire word for the target, but is not for
-        the host, then sign-extend on the host so that the number will look
-        the same way on the host that it would on the target.
-
-        For example, when building a 64 bit alpha hosted 32 bit sparc
-        targeted compiler, then we want the 32 bit unsigned value -1 to be
-        represented as a 64 bit value -1, and not as 0x00000000ffffffff.
-        The later confuses the sparc backend.  */
-
-      if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT && BITS_PER_WORD == width
-         && (val & ((HOST_WIDE_INT) 1 << (width - 1))))
-       val |= ((HOST_WIDE_INT) (-1) << width);
+      val = trunc_int_for_mode (val, mode);
 
       return GEN_INT (val);
     }
@@ -3390,6 +3638,10 @@ simplify_binary_operation (code, mode, op0, op1)
       f1 = real_value_truncate (mode, f1);
 
 #ifdef REAL_ARITHMETIC
+#ifndef REAL_INFINITY
+      if (code == DIV && REAL_VALUES_EQUAL (f1, dconst0))
+       return 0;
+#endif
       REAL_ARITHMETIC (value, rtx_to_tree_code (code), f0, f1);
 #else
       switch (code)
@@ -3686,11 +3938,11 @@ simplify_binary_operation (code, mode, op0, op1)
 
          /* Change subtraction from zero into negation.  */
          if (op0 == CONST0_RTX (mode))
-           return gen_rtx (NEG, mode, op1);
+           return gen_rtx_NEG (mode, op1);
 
          /* (-1 - a) is ~a.  */
          if (op0 == constm1_rtx)
-           return gen_rtx (NOT, mode, op1);
+           return gen_rtx_NOT (mode, op1);
 
          /* Subtracting 0 has no effect.  */
          if (op1 == CONST0_RTX (mode))
@@ -3774,9 +4026,9 @@ simplify_binary_operation (code, mode, op0, op1)
          if (GET_CODE (op1) == AND)
            {
             if (rtx_equal_p (op0, XEXP (op1, 0)))
-              return cse_gen_binary (AND, mode, op0, gen_rtx (NOT, mode, XEXP (op1, 1)));
+              return cse_gen_binary (AND, mode, op0, gen_rtx_NOT (mode, XEXP (op1, 1)));
             if (rtx_equal_p (op0, XEXP (op1, 1)))
-              return cse_gen_binary (AND, mode, op0, gen_rtx (NOT, mode, XEXP (op1, 0)));
+              return cse_gen_binary (AND, mode, op0, gen_rtx_NOT (mode, XEXP (op1, 0)));
           }
          break;
 
@@ -3785,7 +4037,7 @@ simplify_binary_operation (code, mode, op0, op1)
            {
              tem = simplify_unary_operation (NEG, mode, op0, mode);
 
-             return tem ? tem : gen_rtx (NEG, mode, op0);
+             return tem ? tem : gen_rtx_NEG (mode, op0);
            }
 
          /* In IEEE floating point, x*0 is not always 0.  */
@@ -3811,7 +4063,7 @@ simplify_binary_operation (code, mode, op0, op1)
              && (width <= HOST_BITS_PER_WIDE_INT
                  || val != HOST_BITS_PER_WIDE_INT - 1)
              && ! rtx_equal_function_value_matters)
-           return gen_rtx (ASHIFT, mode, op0, GEN_INT (val));
+           return gen_rtx_ASHIFT (mode, op0, GEN_INT (val));
 
          if (GET_CODE (op1) == CONST_DOUBLE
              && GET_MODE_CLASS (GET_MODE (op1)) == MODE_FLOAT)
@@ -3831,10 +4083,10 @@ simplify_binary_operation (code, mode, op0, op1)
 
              /* x*2 is x+x and x*(-1) is -x */
              if (op1is2 && GET_MODE (op0) == mode)
-               return gen_rtx (PLUS, mode, op0, copy_rtx (op0));
+               return gen_rtx_PLUS (mode, op0, copy_rtx (op0));
 
              else if (op1ism1 && GET_MODE (op0) == mode)
-               return gen_rtx (NEG, mode, op0);
+               return gen_rtx_NEG (mode, op0);
            }
          break;
 
@@ -3859,7 +4111,7 @@ simplify_binary_operation (code, mode, op0, op1)
            return op0;
          if (GET_CODE (op1) == CONST_INT
              && (INTVAL (op1) & GET_MODE_MASK (mode)) == GET_MODE_MASK (mode))
-           return gen_rtx (NOT, mode, op0);
+           return gen_rtx_NOT (mode, op0);
          if (op0 == op1 && ! side_effects_p (op0)
              && GET_MODE_CLASS (mode) != MODE_CC)
            return const0_rtx;
@@ -3887,7 +4139,7 @@ simplify_binary_operation (code, mode, op0, op1)
             below).  */
          if (GET_CODE (op1) == CONST_INT
              && (arg1 = exact_log2 (INTVAL (op1))) > 0)
-           return gen_rtx (LSHIFTRT, mode, op0, GEN_INT (arg1));
+           return gen_rtx_LSHIFTRT (mode, op0, GEN_INT (arg1));
 
          /* ... fall through ...  */
 
@@ -3918,11 +4170,11 @@ simplify_binary_operation (code, mode, op0, op1)
                {
 #if defined (REAL_ARITHMETIC)
                  REAL_ARITHMETIC (d, rtx_to_tree_code (DIV), dconst1, d);
-                 return gen_rtx (MULT, mode, op0, 
-                                 CONST_DOUBLE_FROM_REAL_VALUE (d, mode));
+                 return gen_rtx_MULT (mode, op0, 
+                                      CONST_DOUBLE_FROM_REAL_VALUE (d, mode));
 #else
-                 return gen_rtx (MULT, mode, op0, 
-                                 CONST_DOUBLE_FROM_REAL_VALUE (1./d, mode));
+                 return gen_rtx_MULT (mode, op0, 
+                                      CONST_DOUBLE_FROM_REAL_VALUE (1./d, mode));
 #endif
                }
            }
@@ -3933,7 +4185,7 @@ simplify_binary_operation (code, mode, op0, op1)
          /* Handle modulus by power of two (mod with 1 handled below).  */
          if (GET_CODE (op1) == CONST_INT
              && exact_log2 (INTVAL (op1)) > 0)
-           return gen_rtx (AND, mode, op0, GEN_INT (INTVAL (op1) - 1));
+           return gen_rtx_AND (mode, op0, GEN_INT (INTVAL (op1) - 1));
 
          /* ... fall through ...  */
 
@@ -4167,26 +4419,7 @@ simplify_binary_operation (code, mode, op0, op1)
       abort ();
     }
 
-  /* Clear the bits that don't belong in our mode, unless they and our sign
-     bit are all one.  So we get either a reasonable negative value or a
-     reasonable unsigned value for this mode.  */
-  if (width < HOST_BITS_PER_WIDE_INT
-      && ((val & ((HOST_WIDE_INT) (-1) << (width - 1)))
-         != ((HOST_WIDE_INT) (-1) << (width - 1))))
-    val &= ((HOST_WIDE_INT) 1 << width) - 1;
-
-  /* If this would be an entire word for the target, but is not for
-     the host, then sign-extend on the host so that the number will look
-     the same way on the host that it would on the target.
-
-     For example, when building a 64 bit alpha hosted 32 bit sparc
-     targeted compiler, then we want the 32 bit unsigned value -1 to be
-     represented as a 64 bit value -1, and not as 0x00000000ffffffff.
-     The later confuses the sparc backend.  */
-
-  if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT && BITS_PER_WORD == width
-      && (val & ((HOST_WIDE_INT) 1 << (width - 1))))
-    val |= ((HOST_WIDE_INT) (-1) << width);
+  val = trunc_int_for_mode (val, mode);
 
   return GEN_INT (val);
 }
@@ -4365,7 +4598,7 @@ simplify_plus_minus (code, mode, op0, op1)
   for (i = 1; i < n_ops; i++)
     result = cse_gen_binary (negs[i] ? MINUS : PLUS, mode, result, ops[i]);
 
-  return negate ? gen_rtx (NEG, mode, result) : result;
+  return negate ? gen_rtx_NEG (mode, result) : result;
 }
 \f
 /* Make a binary operation by properly ordering the operands and 
@@ -4405,9 +4638,31 @@ cse_gen_binary (code, mode, op0, op1)
           && GET_MODE (op0) != VOIDmode)
     return plus_constant (op0, - INTVAL (op1));
   else
-    return gen_rtx (code, mode, op0, op1);
+    return gen_rtx_fmt_ee (code, mode, op0, op1);
 }
 \f
+struct cfc_args
+{
+  /* Input */
+  rtx op0, op1;
+  /* Output */
+  int equal, op0lt, op1lt;
+};
+
+static void
+check_fold_consts (data)
+  PTR data;
+{
+  struct cfc_args * args = (struct cfc_args *) data;
+  REAL_VALUE_TYPE d0, d1;
+
+  REAL_VALUE_FROM_CONST_DOUBLE (d0, args->op0);
+  REAL_VALUE_FROM_CONST_DOUBLE (d1, args->op1);
+  args->equal = REAL_VALUES_EQUAL (d0, d1);
+  args->op0lt = REAL_VALUES_LESS (d0, d1);
+  args->op1lt = REAL_VALUES_LESS (d1, d0);
+}
+
 /* Like simplify_binary_operation except used for relational operators.
    MODE is the mode of the operands, not that of the result.  If MODE
    is VOIDmode, both operands must also be VOIDmode and we compare the
@@ -4469,19 +4724,20 @@ simplify_relational_operation (code, mode, op0, op1)
   else if (GET_CODE (op0) == CONST_DOUBLE && GET_CODE (op1) == CONST_DOUBLE
           && GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT)
     {
-      REAL_VALUE_TYPE d0, d1;
-      jmp_buf handler;
+      struct cfc_args args;
+
+      /* Setup input for check_fold_consts() */
+      args.op0 = op0;
+      args.op1 = op1;
       
-      if (setjmp (handler))
+      if (do_float_handler(check_fold_consts, (PTR) &args) == 0)
+       /* We got an exception from check_fold_consts() */
        return 0;
 
-      set_float_handler (handler);
-      REAL_VALUE_FROM_CONST_DOUBLE (d0, op0);
-      REAL_VALUE_FROM_CONST_DOUBLE (d1, op1);
-      equal = REAL_VALUES_EQUAL (d0, d1);
-      op0lt = op0ltu = REAL_VALUES_LESS (d0, d1);
-      op1lt = op1ltu = REAL_VALUES_LESS (d1, d0);
-      set_float_handler (NULL_PTR);
+      /* Receive output from check_fold_consts() */
+      equal = args.equal;
+      op0lt = op0ltu = args.op0lt;
+      op1lt = op1ltu = args.op1lt;
     }
 #endif  /* not REAL_IS_NOT_DOUBLE, or REAL_ARITHMETIC */
 
@@ -4703,6 +4959,17 @@ simplify_ternary_operation (code, mode, op0_mode, op0, op1, op2)
          && rtx_equal_p (XEXP (op0, 1), op1)
          && rtx_equal_p (XEXP (op0, 0), op2))
        return op2;
+      else if (GET_RTX_CLASS (GET_CODE (op0)) == '<' && ! side_effects_p (op0))
+       {
+         rtx temp;
+         temp = simplify_relational_operation (GET_CODE (op0), op0_mode,
+                                               XEXP (op0, 0), XEXP (op0, 1));
+         /* See if any simplifications were possible.  */
+         if (temp == const0_rtx)
+           return op2;
+         else if (temp == const1_rtx)
+           return op1;
+       }
       break;
 
     default:
@@ -4769,6 +5036,10 @@ fold_rtx (x, insn)
         since they are used only for lists of args
         in a function call's REG_EQUAL note.  */
     case EXPR_LIST:
+      /* Changing anything inside an ADDRESSOF is incorrect; we don't
+        want to (e.g.,) make (addressof (const_int 0)) just because
+        the location is known to be zero.  */
+    case ADDRESSOF:
       return x;
 
 #ifdef HAVE_cc0
@@ -4789,7 +5060,7 @@ fold_rtx (x, insn)
              && 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);
+           return gen_rtx_LABEL_REF (Pmode, next);
        }
       break;
 
@@ -5002,9 +5273,9 @@ fold_rtx (x, insn)
 
        if (GET_CODE (addr) == REG
            && REGNO_QTY_VALID_P (REGNO (addr))
-           && GET_MODE (addr) == qty_mode[reg_qty[REGNO (addr)]]
-           && qty_const[reg_qty[REGNO (addr)]] != 0)
-         addr = qty_const[reg_qty[REGNO (addr)]];
+           && GET_MODE (addr) == qty_mode[REG_QTY (REGNO (addr))]
+           && qty_const[REG_QTY (REGNO (addr))] != 0)
+         addr = qty_const[REG_QTY (REGNO (addr))];
 
        /* If address is constant, split it into a base and integer offset.  */
        if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == LABEL_REF)
@@ -5019,7 +5290,7 @@ fold_rtx (x, insn)
                 && GET_CODE (XEXP (addr, 1)) == SYMBOL_REF)
          base = XEXP (addr, 1);
        else if (GET_CODE (addr) == ADDRESSOF)
-         XEXP (x, 0) = addr;
+         return change_address (x, VOIDmode, addr);
 
        /* If this is a constant pool reference, we can fold it into its
           constant to allow better value tracking.  */
@@ -5088,17 +5359,21 @@ fold_rtx (x, insn)
                        < XVECLEN (table, 1)))
                  {
                    offset /= GET_MODE_SIZE (GET_MODE (table));
-                   new = gen_rtx (MINUS, Pmode, XVECEXP (table, 1, offset),
-                                  XEXP (table, 0));
+                   new = gen_rtx_MINUS (Pmode, XVECEXP (table, 1, offset),
+                                        XEXP (table, 0));
 
                    if (GET_MODE (table) != Pmode)
-                     new = gen_rtx (TRUNCATE, GET_MODE (table), new);
+                     new = gen_rtx_TRUNCATE (GET_MODE (table), new);
 
                    /* Indicate this is a constant.  This isn't a 
                       valid form of CONST, but it will only be used
                       to fold the next insns and then discarded, so
-                      it should be safe.  */
-                   return gen_rtx (CONST, GET_MODE (new), new);
+                      it should be safe.
+
+                      Note this expression must be explicitly discarded,
+                      by cse_insn, else it may end up in a REG_EQUAL note
+                      and "escape" to cause problems elsewhere.  */
+                   return gen_rtx_CONST (GET_MODE (new), new);
                  }
              }
          }
@@ -5142,12 +5417,12 @@ fold_rtx (x, insn)
            /* This is the same as calling equiv_constant; it is duplicated
               here for speed.  */
            if (REGNO_QTY_VALID_P (REGNO (arg))
-               && qty_const[reg_qty[REGNO (arg)]] != 0
-               && GET_CODE (qty_const[reg_qty[REGNO (arg)]]) != REG
-               && GET_CODE (qty_const[reg_qty[REGNO (arg)]]) != PLUS)
+               && qty_const[REG_QTY (REGNO (arg))] != 0
+               && GET_CODE (qty_const[REG_QTY (REGNO (arg))]) != REG
+               && GET_CODE (qty_const[REG_QTY (REGNO (arg))]) != PLUS)
              const_arg
                = gen_lowpart_if_possible (GET_MODE (arg),
-                                          qty_const[reg_qty[REGNO (arg)]]);
+                                          qty_const[REG_QTY (REGNO (arg))]);
            break;
 
          case CONST:
@@ -5241,10 +5516,13 @@ fold_rtx (x, insn)
          }
       }
 
-    else if (fmt[i] == 'E')
-      /* Don't try to fold inside of a vector of expressions.
-        Doing nothing is harmless.  */
-      ;
+    else
+      {
+       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,
@@ -5298,7 +5576,7 @@ fold_rtx (x, insn)
                                        const_arg0 ? const_arg0 : folded_arg0,
                                        mode_arg0);
        if (new != 0 && is_const)
-         new = gen_rtx (CONST, mode, new);
+         new = gen_rtx_CONST (mode, new);
       }
       break;
       
@@ -5367,8 +5645,8 @@ fold_rtx (x, insn)
                  && (folded_arg0 == folded_arg1
                      || (GET_CODE (folded_arg0) == REG
                          && GET_CODE (folded_arg1) == REG
-                         && (reg_qty[REGNO (folded_arg0)]
-                             == reg_qty[REGNO (folded_arg1)]))
+                         && (REG_QTY (REGNO (folded_arg0))
+                             == REG_QTY (REGNO (folded_arg1))))
                      || ((p0 = lookup (folded_arg0,
                                        (safe_hash (folded_arg0, mode_arg0)
                                         % NBUCKETS), mode_arg0))
@@ -5385,7 +5663,7 @@ fold_rtx (x, insn)
                 (we only check the reverse if not floating-point).  */
              else if (GET_CODE (folded_arg0) == REG)
                {
-                 int qty = reg_qty[REGNO (folded_arg0)];
+                 int qty = REG_QTY (REGNO (folded_arg0));
 
                  if (REGNO_QTY_VALID_P (REGNO (folded_arg0))
                      && (comparison_dominates_p (qty_comparison_code[qty], code)
@@ -5397,7 +5675,7 @@ fold_rtx (x, insn)
                              && rtx_equal_p (qty_comparison_const[qty],
                                              const_arg1))
                          || (GET_CODE (folded_arg1) == REG
-                             && (reg_qty[REGNO (folded_arg1)]
+                             && (REG_QTY (REGNO (folded_arg1))
                                  == qty_comparison_qty[qty]))))
                    return (comparison_dominates_p (qty_comparison_code[qty],
                                                    code)
@@ -5595,14 +5873,14 @@ fold_rtx (x, insn)
                 identical powers of two with post decrement.  */
 
              if (code == PLUS && INTVAL (const_arg1) == INTVAL (inner_const)
-                 && (0
-#if defined(HAVE_PRE_INCREMENT) || defined(HAVE_POST_INCREMENT)
-                     || exact_log2 (INTVAL (const_arg1)) >= 0
-#endif
-#if defined(HAVE_PRE_DECREMENT) || defined(HAVE_POST_DECREMENT)
-                     || exact_log2 (- INTVAL (const_arg1)) >= 0
-#endif
-                 ))
+                 && ((HAVE_PRE_INCREMENT
+                         && exact_log2 (INTVAL (const_arg1)) >= 0)
+                     || (HAVE_POST_INCREMENT
+                         && exact_log2 (INTVAL (const_arg1)) >= 0)
+                     || (HAVE_PRE_DECREMENT
+                         && exact_log2 (- INTVAL (const_arg1)) >= 0)
+                     || (HAVE_POST_DECREMENT
+                         && exact_log2 (- INTVAL (const_arg1)) >= 0)))
                break;
 
              /* Compute the code used to compose the constants.  For example,
@@ -5672,6 +5950,12 @@ fold_rtx (x, insn)
                                        const_arg1 ? const_arg1 : folded_arg1,
                                        const_arg2 ? const_arg2 : XEXP (x, 2));
       break;
+
+    case 'x':
+      /* Always eliminate CONSTANT_P_RTX at this stage. */
+      if (code == CONSTANT_P_RTX)
+       return (const_arg0 ? const1_rtx : const0_rtx);
+      break;
     }
 
   return new ? new : x;
@@ -5686,10 +5970,10 @@ equiv_constant (x)
 {
   if (GET_CODE (x) == REG
       && REGNO_QTY_VALID_P (REGNO (x))
-      && qty_const[reg_qty[REGNO (x)]])
-    x = gen_lowpart_if_possible (GET_MODE (x), qty_const[reg_qty[REGNO (x)]]);
+      && qty_const[REG_QTY (REGNO (x))])
+    x = gen_lowpart_if_possible (GET_MODE (x), qty_const[REG_QTY (REGNO (x))]);
 
-  if (x != 0 && CONSTANT_P (x))
+  if (x == 0 || CONSTANT_P (x))
     return x;
 
   /* If X is a MEM, try to fold it outside the context of any insn to see if
@@ -5749,12 +6033,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 = gen_rtx_MEM (mode, plus_constant (XEXP (x, 0), offset));
       if (! memory_address_p (mode, XEXP (new, 0)))
        return 0;
-      MEM_VOLATILE_P (new) = MEM_VOLATILE_P (x);
       RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (x);
-      MEM_IN_STRUCT_P (new) = MEM_IN_STRUCT_P (x);
+      MEM_COPY_ATTRIBUTES (new, x);
       return new;
     }
   else
@@ -5834,7 +6117,7 @@ record_jump_cond (code, mode, op0, op1, reversed_nonequality)
   /* If OP0 and OP1 are known equal, and either is a paradoxical SUBREG,
      we know that they are also equal in the smaller mode (this is also
      true for all smaller modes whether or not there is a SUBREG, but
-     is not worth testing for with no SUBREG.  */
+     is not worth testing for with no SUBREG).  */
 
   /* Note that GET_MODE (op0) may not equal MODE.  */
   if (code == EQ && GET_CODE (op0) == SUBREG
@@ -5845,7 +6128,7 @@ record_jump_cond (code, mode, op0, op1, reversed_nonequality)
       rtx tem = gen_lowpart_if_possible (inner_mode, op1);
 
       record_jump_cond (code, mode, SUBREG_REG (op0),
-                       tem ? tem : gen_rtx (SUBREG, inner_mode, op1, 0),
+                       tem ? tem : gen_rtx_SUBREG (inner_mode, op1, 0),
                        reversed_nonequality);
     }
 
@@ -5857,7 +6140,7 @@ record_jump_cond (code, mode, op0, op1, reversed_nonequality)
       rtx tem = gen_lowpart_if_possible (inner_mode, op0);
 
       record_jump_cond (code, mode, SUBREG_REG (op1),
-                       tem ? tem : gen_rtx (SUBREG, inner_mode, op0, 0),
+                       tem ? tem : gen_rtx_SUBREG (inner_mode, op0, 0),
                        reversed_nonequality);
     }
 
@@ -5877,7 +6160,7 @@ record_jump_cond (code, mode, op0, op1, reversed_nonequality)
       rtx tem = gen_lowpart_if_possible (inner_mode, op1);
 
       record_jump_cond (code, mode, SUBREG_REG (op0),
-                       tem ? tem : gen_rtx (SUBREG, inner_mode, op1, 0),
+                       tem ? tem : gen_rtx_SUBREG (inner_mode, op1, 0),
                        reversed_nonequality);
     }
 
@@ -5890,7 +6173,7 @@ record_jump_cond (code, mode, op0, op1, reversed_nonequality)
       rtx tem = gen_lowpart_if_possible (inner_mode, op0);
 
       record_jump_cond (code, mode, SUBREG_REG (op1),
-                       tem ? tem : gen_rtx (SUBREG, inner_mode, op0, 0),
+                       tem ? tem : gen_rtx_SUBREG (inner_mode, op0, 0),
                        reversed_nonequality);
     }
 
@@ -5967,7 +6250,7 @@ record_jump_cond (code, mode, op0, op1, reversed_nonequality)
          op0_elt->in_struct = op0_in_struct;
        }
 
-      qty_comparison_code[reg_qty[REGNO (op0)]] = code;
+      qty_comparison_code[REG_QTY (REGNO (op0))] = code;
       if (GET_CODE (op1) == REG)
        {
          /* Look it up again--in case op0 and op1 are the same.  */
@@ -5987,13 +6270,13 @@ record_jump_cond (code, mode, op0, op1, reversed_nonequality)
              op1_elt->in_struct = op1_in_struct;
            }
 
-         qty_comparison_qty[reg_qty[REGNO (op0)]] = reg_qty[REGNO (op1)];
-         qty_comparison_const[reg_qty[REGNO (op0)]] = 0;
+         qty_comparison_qty[REG_QTY (REGNO (op0))] = REG_QTY (REGNO (op1));
+         qty_comparison_const[REG_QTY (REGNO (op0))] = 0;
        }
       else
        {
-         qty_comparison_qty[reg_qty[REGNO (op0)]] = -1;
-         qty_comparison_const[reg_qty[REGNO (op0)]] = op1;
+         qty_comparison_qty[REG_QTY (REGNO (op0))] = -1;
+         qty_comparison_const[REG_QTY (REGNO (op0))] = op1;
        }
 
       return;
@@ -6038,8 +6321,9 @@ record_jump_cond (code, mode, op0, op1, reversed_nonequality)
    Then install the new sources and destinations in the table
    of available values. 
 
-   If IN_LIBCALL_BLOCK is nonzero, don't record any equivalence made in
-   the insn.  */
+   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. */
 
 /* Data on one SET contained in the instruction.  */
 
@@ -6077,18 +6361,20 @@ struct set
 };
 
 static void
-cse_insn (insn, in_libcall_block)
+cse_insn (insn, libcall_insn)
      rtx insn;
-     int in_libcall_block;
+     rtx libcall_insn;
 {
   register rtx x = PATTERN (insn);
   register int i;
   rtx tem;
   register int n_sets = 0;
 
+#ifdef HAVE_cc0
   /* Records what this insn does to set CC0.  */
   rtx this_insn_cc0 = 0;
   enum machine_mode this_insn_cc0_mode = VOIDmode;
+#endif
 
   rtx src_eqv = 0;
   struct table_elt *src_eqv_elt = 0;
@@ -6410,7 +6696,7 @@ cse_insn (insn, in_libcall_block)
         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 refering to SRC, so we don't
+        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.  */
 
@@ -6588,7 +6874,7 @@ cse_insn (insn, in_libcall_block)
          && GET_MODE_SIZE (mode) < UNITS_PER_WORD)
        {
          enum machine_mode tmode;
-         rtx new_and = gen_rtx (AND, VOIDmode, NULL_RTX, XEXP (src, 1));
+         rtx new_and = gen_rtx_AND (VOIDmode, NULL_RTX, XEXP (src, 1));
 
          for (tmode = GET_MODE_WIDER_MODE (mode);
               GET_MODE_SIZE (tmode) <= UNITS_PER_WORD;
@@ -6770,7 +7056,7 @@ cse_insn (insn, in_libcall_block)
          the current contents will be tested and will always be valid.  */
       while (1)
         {
-          rtx trial;
+          rtx trial, old_src;
 
           /* Skip invalid entries.  */
           while (elt && GET_CODE (elt->exp) != REG
@@ -6836,6 +7122,10 @@ cse_insn (insn, in_libcall_block)
             insert the substitution here and we will delete and re-emit
             the insn later.  */
 
+         /* Keep track of the original SET_SRC so that we can fix notes
+            on libcall instructions.  */
+         old_src = SET_SRC (sets[i].rtl);
+
          if (n_sets == 1 && dest == pc_rtx
              && (trial == pc_rtx
                  || (GET_CODE (trial) == LABEL_REF
@@ -6850,7 +7140,7 @@ cse_insn (insn, in_libcall_block)
                  && (GET_CODE (PATTERN (NEXT_INSN (trial))) == ADDR_DIFF_VEC
                      || GET_CODE (PATTERN (NEXT_INSN (trial))) == ADDR_VEC))
 
-               trial = gen_rtx (LABEL_REF, Pmode, get_label_after (trial));
+               trial = gen_rtx_LABEL_REF (Pmode, get_label_after (trial));
 
              SET_SRC (sets[i].rtl) = trial;
              cse_jumps_altered = 1;
@@ -6860,6 +7150,16 @@ cse_insn (insn, in_libcall_block)
          /* Look for a substitution that makes a valid insn.  */
           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
+                to the RETVAL insn.  */
+             if (libcall_insn
+                 && (GET_CODE (old_src) == REG
+                     || GET_CODE (old_src) == SUBREG
+                     ||  GET_CODE (old_src) == MEM))
+               replace_rtx (REG_NOTES (libcall_insn), old_src, 
+                            canon_reg (SET_SRC (sets[i].rtl), insn));
+
              /* The result of apply_change_group can be ignored; see
                 canon_reg.  */
 
@@ -6901,8 +7201,8 @@ cse_insn (insn, in_libcall_block)
         their lifetimes will likely abut instead of overlapping.  */
       if (GET_CODE (dest) == REG
          && REGNO_QTY_VALID_P (REGNO (dest))
-         && qty_mode[reg_qty[REGNO (dest)]] == GET_MODE (dest)
-         && qty_first_reg[reg_qty[REGNO (dest)]] != REGNO (dest)
+         && qty_mode[REG_QTY (REGNO (dest))] == GET_MODE (dest)
+         && qty_first_reg[REG_QTY (REGNO (dest))] != REGNO (dest)
          && GET_CODE (src) == REG && REGNO (src) == REGNO (dest)
          /* Don't do this if the original insn had a hard reg as
             SET_SRC.  */
@@ -6911,18 +7211,25 @@ cse_insn (insn, in_libcall_block)
        /* We can't call canon_reg here because it won't do anything if
           SRC is a hard register.  */
        {
-         int first = qty_first_reg[reg_qty[REGNO (src)]];
-
-         src = SET_SRC (sets[i].rtl)
-           = first >= FIRST_PSEUDO_REGISTER ? regno_reg_rtx[first]
-             : gen_rtx (REG, GET_MODE (src), first);
-
-         /* If we had a constant that is cheaper than what we are now
-            setting SRC to, use that constant.  We ignored it when we
-            thought we could make this into a no-op.  */
-         if (src_const && COST (src_const) < COST (src)
-             && validate_change (insn, &SET_SRC (sets[i].rtl), src_const, 0))
-           src = src_const;
+         int first = qty_first_reg[REG_QTY (REGNO (src))];
+         rtx new_src
+           = (first >= FIRST_PSEUDO_REGISTER
+              ? regno_reg_rtx[first] : gen_rtx_REG (GET_MODE (src), first));
+
+         /* We must use validate-change even for this, because this
+            might be a special no-op instruction, suitable only to
+            tag notes onto.  */
+         if (validate_change (insn, &SET_SRC (sets[i].rtl), new_src, 0))
+           {
+             src = new_src;
+             /* If we had a constant that is cheaper than what we are now
+                setting SRC to, use that constant.  We ignored it when we
+                thought we could make this into a no-op.  */
+             if (src_const && COST (src_const) < COST (src)
+                 && validate_change (insn, &SET_SRC (sets[i].rtl), src_const,
+                                     0))
+               src = src_const;
+           }
        }
 
       /* If we made a change, recompute SRC values.  */
@@ -6943,19 +7250,31 @@ cse_insn (insn, in_libcall_block)
         equivalent constant, we want to add a REG_NOTE.   We don't want
         to write a REG_EQUAL note for a constant pseudo since verifying that
         that pseudo hasn't been eliminated is a pain.  Such a note also
-        won't help anything.  */
+        won't help anything. 
+
+        Avoid a REG_EQUAL note for (CONST (MINUS (LABEL_REF) (LABEL_REF)))
+        which can be created for a reference to a compile time computable
+        entry in a jump table.  */
+
       if (n_sets == 1 && src_const && GET_CODE (dest) == REG
-         && GET_CODE (src_const) != REG)
+         && GET_CODE (src_const) != REG
+         && ! (GET_CODE (src_const) == CONST
+               && GET_CODE (XEXP (src_const, 0)) == MINUS
+               && GET_CODE (XEXP (XEXP (src_const, 0), 0)) == LABEL_REF
+               && GET_CODE (XEXP (XEXP (src_const, 0), 1)) == LABEL_REF))
        {
          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));
+           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,
@@ -6969,11 +7288,11 @@ cse_insn (insn, in_libcall_block)
             the last set for this quantity was for this register.  */
 
          if (REGNO_QTY_VALID_P (REGNO (dest))
-             && qty_const[reg_qty[REGNO (dest)]] == const0_rtx)
+             && qty_const[REG_QTY (REGNO (dest))] == 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 = qty_const_insn[reg_qty[REGNO (dest)]];
+             rtx const_insn = qty_const_insn[REG_QTY (REGNO (dest))];
 
              if ((tem = single_set (const_insn)) != 0
                  && rtx_equal_p (SET_DEST (tem), dest))
@@ -6981,8 +7300,9 @@ cse_insn (insn, in_libcall_block)
                  if (note)
                    XEXP (note, 0) = const_insn;
                  else
-                   REG_NOTES (insn) = gen_rtx (INSN_LIST, REG_WAS_0,
-                                               const_insn, REG_NOTES (insn));
+                   REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_WAS_0,
+                                                         const_insn,
+                                                         REG_NOTES (insn));
                }
            }
        }
@@ -7099,15 +7419,20 @@ cse_insn (insn, in_libcall_block)
             not delete NOTEs except for NOTE_INSN_DELETED since later
             phases assume these notes are retained.  */
 
+         never_reached_warning (insn);
+
          p = insn;
 
          while (NEXT_INSN (p) != 0
                 && GET_CODE (NEXT_INSN (p)) != BARRIER
                 && GET_CODE (NEXT_INSN (p)) != CODE_LABEL)
            {
+             /* Note, we must update P with the return value from
+                delete_insn, otherwise we could get an infinite loop
+                if NEXT_INSN (p) had INSN_DELETED_P set.  */
              if (GET_CODE (NEXT_INSN (p)) != NOTE
                  || NOTE_LINE_NUMBER (NEXT_INSN (p)) == NOTE_INSN_DELETED)
-               delete_insn (NEXT_INSN (p));
+               p = PREV_INSN (delete_insn (NEXT_INSN (p)));
              else
                p = NEXT_INSN (p);
            }
@@ -7160,8 +7485,8 @@ cse_insn (insn, in_libcall_block)
          this_insn_cc0 = src_const && mode != VOIDmode ? src_const : src;
          this_insn_cc0_mode = mode;
          if (FLOAT_MODE_P (mode))
-           this_insn_cc0 = gen_rtx (COMPARE, VOIDmode, this_insn_cc0,
-                                    CONST0_RTX (mode));
+           this_insn_cc0 = gen_rtx_COMPARE (VOIDmode, this_insn_cc0,
+                                            CONST0_RTX (mode));
        }
 #endif
     }
@@ -7229,7 +7554,12 @@ cse_insn (insn, in_libcall_block)
            enum machine_mode mode
              = GET_MODE (src) == VOIDmode ? GET_MODE (dest) : GET_MODE (src);
 
-           if (sets[i].src_elt == 0)
+           /* Don't put a hard register source into the table if this is
+              the last insn of a libcall.  */
+           if (sets[i].src_elt == 0
+               && (GET_CODE (src) != REG
+                   || REGNO (src) >= FIRST_PSEUDO_REGISTER
+                   || ! find_reg_note (insn, REG_RETVAL, NULL_RTX)))
              {
                register struct table_elt *elt;
 
@@ -7296,6 +7626,12 @@ cse_insn (insn, in_libcall_block)
          invalidate (XEXP (dest, 0), GET_MODE (dest));
       }
 
+  /* A volatile ASM invalidates everything.  */
+  if (GET_CODE (insn) == INSN
+      && GET_CODE (PATTERN (insn)) == ASM_OPERANDS
+      && MEM_VOLATILE_P (PATTERN (insn)))
+    flush_hash_table ();
+
   /* Make sure registers mentioned in destinations
      are safe for use in an expression to be inserted.
      This removes from the hash table
@@ -7305,8 +7641,44 @@ cse_insn (insn, in_libcall_block)
      we are going to hash the SET_DEST values unconditionally.  */
 
   for (i = 0; i < n_sets; i++)
-    if (sets[i].rtl && GET_CODE (SET_DEST (sets[i].rtl)) != REG)
-      mention_regs (SET_DEST (sets[i].rtl));
+    {
+      if (sets[i].rtl)
+       {
+         rtx x = SET_DEST (sets[i].rtl);
+
+         if (GET_CODE (x) != REG)
+           mention_regs (x);
+         else
+           {
+             /* We used to rely on all references to a register becoming
+                inaccessible when a register changes to a new quantity,
+                since that changes the hash code.  However, that is not
+                safe, since after NBUCKETS new quantities we get a
+                hash 'collision' of a register with its own invalid
+                entries.  And since SUBREGs have been changed not to
+                change their hash code with the hash code of the register,
+                it wouldn't work any longer at all.  So we have to check
+                for any invalid references lying around now.
+                This code is similar to the REG case in mention_regs,
+                but it knows that reg_tick has been incremented, and
+                it leaves reg_in_table as -1 .  */
+             register int regno = REGNO (x);
+             register int endregno
+               = regno + (regno >= FIRST_PSEUDO_REGISTER ? 1
+                          : HARD_REGNO_NREGS (regno, GET_MODE (x)));
+             int i;
+
+             for (i = regno; i < endregno; i++)
+               {
+                 if (REG_IN_TABLE (i) >= 0)
+                   {
+                     remove_invalid_refs (i);
+                     REG_IN_TABLE (i) = -1;
+                   }
+               }
+           }
+       }
+    }
 
   /* We may have just removed some of the src_elt's from the hash table.
      So replace each one with the current head of the same class.  */
@@ -7335,6 +7707,7 @@ cse_insn (insn, in_libcall_block)
     if (sets[i].rtl)
       {
        register rtx dest = SET_DEST (sets[i].rtl);
+       rtx inner_dest = sets[i].inner_dest;
        register struct table_elt *elt;
 
        /* Don't record value if we are not supposed to risk allocating
@@ -7351,7 +7724,7 @@ cse_insn (insn, in_libcall_block)
               since we might delete the libcall.  Things should have been set
               up so we won't want to reuse such a value, but we play it safe
               here.  */
-           || in_libcall_block
+           || libcall_insn
            /* If we didn't put a REG_EQUAL value or a source into the hash
               table, there is no point is recording DEST.  */
            || sets[i].src_elt == 0
@@ -7383,8 +7756,18 @@ cse_insn (insn, in_libcall_block)
              sets[i].dest_hash = HASH (dest, GET_MODE (dest));
            }
 
-       elt = insert (dest, sets[i].src_elt,
-                     sets[i].dest_hash, GET_MODE (dest));
+       if (GET_CODE (inner_dest) == MEM
+           && GET_CODE (XEXP (inner_dest, 0)) == ADDRESSOF)
+         /* Given (SET (MEM (ADDRESSOF (X))) Y) we don't want to say
+            that (MEM (ADDRESSOF (X))) is equivalent to Y. 
+            Consider the case in which the address of the MEM is
+            passed to a function, which alters the MEM.  Then, if we
+            later use Y instead of the MEM we'll miss the update.  */
+         elt = insert (dest, 0, sets[i].dest_hash, GET_MODE (dest));
+       else
+         elt = insert (dest, sets[i].src_elt,
+                       sets[i].dest_hash, GET_MODE (dest));
+
        elt->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,
@@ -7439,7 +7822,7 @@ cse_insn (insn, in_libcall_block)
 
                new_src = gen_lowpart_if_possible (new_mode, elt->exp);
                if (new_src == 0)
-                 new_src = gen_rtx (SUBREG, new_mode, elt->exp, 0);
+                 new_src = gen_rtx_SUBREG (new_mode, elt->exp, 0);
 
                src_hash = HASH (new_src, new_mode);
                src_elt = lookup (new_src, src_hash, new_mode);
@@ -7484,15 +7867,20 @@ cse_insn (insn, in_libcall_block)
      then be used in the sequel and we may be changing a two-operand insn
      into a three-operand insn.
 
-     Also do not do this if we are operating on a copy of INSN.  */
+     Also do not do this if we are operating on a copy of INSN.
+
+     Also don't do this if INSN ends a libcall; this would cause an unrelated
+     register to be set in the middle of a libcall, and we then get bad code
+     if the libcall is deleted.  */
 
   if (n_sets == 1 && sets[0].rtl && GET_CODE (SET_DEST (sets[0].rtl)) == REG
       && NEXT_INSN (PREV_INSN (insn)) == insn
       && GET_CODE (SET_SRC (sets[0].rtl)) == REG
       && REGNO (SET_SRC (sets[0].rtl)) >= FIRST_PSEUDO_REGISTER
       && REGNO_QTY_VALID_P (REGNO (SET_SRC (sets[0].rtl)))
-      && (qty_first_reg[reg_qty[REGNO (SET_SRC (sets[0].rtl))]]
-         == REGNO (SET_DEST (sets[0].rtl))))
+      && (qty_first_reg[REG_QTY (REGNO (SET_SRC (sets[0].rtl)))]
+         == REGNO (SET_DEST (sets[0].rtl)))
+      && ! find_reg_note (insn, REG_RETVAL, NULL_RTX))
     {
       rtx prev = PREV_INSN (insn);
       while (prev && GET_CODE (prev) == NOTE)
@@ -7566,7 +7954,7 @@ cse_insn (insn, in_libcall_block)
   prev_insn = insn;
 }
 \f
-/* Remove from the ahsh table all expressions that reference memory.  */
+/* Remove from the hash table all expressions that reference memory.  */
 static void
 invalidate_memory ()
 {
@@ -7594,8 +7982,8 @@ note_mem_written (addr)
       && 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]++;
+      if (REG_TICK (STACK_POINTER_REGNUM) >= 0)
+       REG_TICK (STACK_POINTER_REGNUM)++;
 
       /* This should be *very* rare.  */
       if (TEST_HARD_REG_BIT (hard_regs_in_table, STACK_POINTER_REGNUM))
@@ -7704,7 +8092,7 @@ cse_process_notes (x, object)
       }
 
     case REG:
-      i = reg_qty[REGNO (x)];
+      i = REG_QTY (REGNO (x));
 
       /* Return a constant or a constant register.  */
       if (REGNO_QTY_VALID_P (REGNO (x))
@@ -7773,23 +8161,31 @@ cse_around_loop (loop_start)
   if (last_jump_equiv_class)
     for (p = last_jump_equiv_class->first_same_value; p;
         p = p->next_same_value)
-      if (GET_CODE (p->exp) == MEM || GET_CODE (p->exp) == REG
-         || (GET_CODE (p->exp) == SUBREG
-             && GET_CODE (SUBREG_REG (p->exp)) == REG))
-       invalidate (p->exp, VOIDmode);
-      else if (GET_CODE (p->exp) == STRICT_LOW_PART
-              || GET_CODE (p->exp) == ZERO_EXTRACT)
-       invalidate (XEXP (p->exp, 0), GET_MODE (p->exp));
+      {
+        if (GET_CODE (p->exp) == MEM || GET_CODE (p->exp) == REG
+           || (GET_CODE (p->exp) == SUBREG
+               && GET_CODE (SUBREG_REG (p->exp)) == REG))
+         invalidate (p->exp, VOIDmode);
+        else if (GET_CODE (p->exp) == STRICT_LOW_PART
+                || GET_CODE (p->exp) == ZERO_EXTRACT)
+         invalidate (XEXP (p->exp, 0), GET_MODE (p->exp));
+      }
 
   /* Process insns starting after LOOP_START until we hit a CALL_INSN or
      a CODE_LABEL (we could handle a CALL_INSN, but it isn't worth it).
 
      The only thing we do with SET_DEST is invalidate entries, so we
      can safely process each SET in order.  It is slightly less efficient
-     to do so, but we only want to handle the most common cases.  */
+     to do so, but we only want to handle the most common cases.
+
+     The gen_move_insn call in cse_set_around_loop may create new pseudos.
+     These pseudos won't have valid entries in any of the tables indexed
+     by register number, such as reg_qty.  We avoid out-of-range array
+     accesses by not processing any instructions created after cse started.  */
 
   for (insn = NEXT_INSN (loop_start);
        GET_CODE (insn) != CALL_INSN && GET_CODE (insn) != CODE_LABEL
+       && INSN_UID (insn) < max_insn_uid
        && ! (GET_CODE (insn) == NOTE
             && NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END);
        insn = NEXT_INSN (insn))
@@ -7868,6 +8264,7 @@ invalidate_skipped_block (start)
          invalidate_for_call ();
        }
 
+      invalidate_from_clobbers (PATTERN (insn));
       note_stores (PATTERN (insn), invalidate_skipped_set);
     }
 }
@@ -7883,7 +8280,7 @@ static rtx cse_check_loop_start_value;
 static void
 cse_check_loop_start (x, set)
      rtx x;
-     rtx set;
+     rtx set ATTRIBUTE_UNUSED;
 {
   if (cse_check_loop_start_value == 0
       || GET_CODE (x) == CC0 || GET_CODE (x) == PC)
@@ -7968,9 +8365,24 @@ cse_set_around_loop (x, insn, loop_start)
                    if (cse_check_loop_start_value
                        && validate_change (insn, &SET_SRC (x),
                                            src_elt->exp, 0))
-                     emit_insn_after (gen_move_insn (src_elt->exp,
-                                                     SET_DEST (set)),
-                                      p);
+                     {
+                       /* If this creates new pseudos, this is unsafe,
+                          because the regno of new pseudo is unsuitable
+                          to index into reg_qty when cse_insn processes
+                          the new insn.  Therefore, if a new pseudo was
+                          created, discard this optimization.  */
+                       int nregs = max_reg_num ();
+                       rtx move
+                         = gen_move_insn (src_elt->exp, SET_DEST (set));
+                       if (nregs != max_reg_num ())
+                         {
+                           if (! validate_change (insn, &SET_SRC (x),
+                                                  SET_SRC (set), 0))
+                             abort ();
+                         }
+                       else
+                         emit_insn_after (move, p);
+                     }
                    break;
                  }
            }
@@ -8236,26 +8648,16 @@ cse_main (f, nregs, after_loop, file)
 
   max_reg = nregs;
 
-  all_minus_one = (int *) alloca (nregs * sizeof (int));
-  consec_ints = (int *) alloca (nregs * sizeof (int));
-
-  for (i = 0; i < nregs; i++)
-    {
-      all_minus_one[i] = -1;
-      consec_ints[i] = i;
-    }
+  max_insn_uid = get_max_uid ();
 
   reg_next_eqv = (int *) alloca (nregs * sizeof (int));
   reg_prev_eqv = (int *) alloca (nregs * sizeof (int));
-  reg_qty = (int *) alloca (nregs * sizeof (int));
-  reg_in_table = (int *) alloca (nregs * sizeof (int));
-  reg_tick = (int *) alloca (nregs * sizeof (int));
 
 #ifdef LOAD_EXTEND_OP
 
   /* Allocate scratch rtl here.  cse_insn will fill in the memory reference
      and change the code and mode as appropriate.  */
-  memory_extend_rtx = gen_rtx (ZERO_EXTEND, VOIDmode, NULL_RTX);
+  memory_extend_rtx = gen_rtx_ZERO_EXTEND (VOIDmode, NULL_RTX);
 #endif
 
   /* Discard all the free elements of the previous function
@@ -8340,7 +8742,7 @@ cse_main (f, nregs, after_loop, file)
       max_qty = val.nsets * 2;
       
       if (file)
-       fprintf (file, ";; Processing block from %d to %d, %d sets.\n",
+       fnotice (file, ";; Processing block from %d to %d, %d sets.\n",
                 INSN_UID (insn), val.last ? INSN_UID (val.last) : 0,
                 val.nsets);
 
@@ -8403,7 +8805,7 @@ cse_basic_block (from, to, next_branch, around_loop)
 {
   register rtx insn;
   int to_usage = 0;
-  int in_libcall_block = 0;
+  rtx libcall_insn = NULL_RTX;
   int num_insns = 0;
 
   /* Each of these arrays is undefined before max_reg, so only allocate
@@ -8436,28 +8838,20 @@ cse_basic_block (from, to, next_branch, around_loop)
 
   for (insn = from; insn != to; insn = NEXT_INSN (insn))
     {
-      register enum rtx_code code;
-      int i;
-      struct table_elt *p, *next;
+      register enum rtx_code code = GET_CODE (insn);
 
-      /* If we have processed 1,000 insns, flush the hash table to avoid
-        extreme quadratic behavior.
+      /* If we have processed 1,000 insns, flush the hash table to
+        avoid extreme quadratic behavior.  We must not include NOTEs
+        in the count since there may be more or them when generating
+        debugging information.  If we clear the table at different
+        times, code generated with -g -O might be different than code
+        generated with -O but not -g.
 
         ??? This is a real kludge and needs to be done some other way.
         Perhaps for 2.9.  */
-      if (num_insns++ > 1000)
+      if (code != NOTE && num_insns++ > 1000)
        {
-         for (i = 0; i < NBUCKETS; i++)
-           for (p = table[i]; p; p = next)
-             {
-               next = p->next_same_hash;
-
-               if (GET_CODE (p->exp) == REG)
-                 invalidate (p->exp, p->mode);
-               else
-                 remove_from_table (p, i);
-             }
-
+         flush_hash_table ();
          num_insns = 0;
        }
 
@@ -8484,12 +8878,13 @@ cse_basic_block (from, to, next_branch, around_loop)
            }
        }
         
-      code = GET_CODE (insn);
       if (GET_MODE (insn) == QImode)
        PUT_MODE (insn, VOIDmode);
 
       if (GET_RTX_CLASS (code) == 'i')
        {
+         rtx p;
+
          /* Process notes first so we have all notes in canonical forms when
             looking for duplicate operations.  */
 
@@ -8502,12 +8897,12 @@ cse_basic_block (from, to, next_branch, around_loop)
             its destination is the result of the block and hence should be
             recorded.  */
 
-         if (find_reg_note (insn, REG_LIBCALL, NULL_RTX))
-           in_libcall_block = 1;
+         if ((p = find_reg_note (insn, REG_LIBCALL, NULL_RTX)))
+           libcall_insn = XEXP (p, 0);
          else if (find_reg_note (insn, REG_RETVAL, NULL_RTX))
-           in_libcall_block = 0;
+           libcall_insn = NULL_RTX;
 
-         cse_insn (insn, in_libcall_block);
+         cse_insn (insn, libcall_insn);
        }
 
       /* If INSN is now an unconditional jump, skip to the end of our
@@ -8643,7 +9038,13 @@ count_reg_usage (x, counts, dest, incr)
     case CONST_DOUBLE:
     case SYMBOL_REF:
     case LABEL_REF:
-    case CLOBBER:
+      return;
+
+    case CLOBBER:                                                        
+      /* If we are clobbering a MEM, mark any registers inside the address
+         as being used.  */
+      if (GET_CODE (XEXP (x, 0)) == MEM)
+       count_reg_usage (XEXP (XEXP (x, 0), 0), counts, NULL_RTX, incr);
       return;
 
     case SET:
@@ -8679,7 +9080,7 @@ count_reg_usage (x, counts, dest, incr)
     case EXPR_LIST:
     case INSN_LIST:
       if (REG_NOTE_KIND (x) == REG_EQUAL
-         || GET_CODE (XEXP (x,0)) == USE)
+         || (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);
       return;
@@ -8702,21 +9103,23 @@ count_reg_usage (x, counts, dest, incr)
 /* 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.
 
-   This is used to remove insns made obviously dead by cse.  It improves the
-   heuristics in loop since it won't try to move dead invariants out of loops
-   or make givs for dead quantities.  The remaining passes of the compilation
-   are also sped up.  */
+   This is used to remove insns made obviously dead by cse, loop or other
+   optimizations.  It improves the heuristics in loop since it won't try to
+   move dead invariants out of loops or make givs for dead quantities.  The
+   remaining passes of the compilation are also sped up.  */
 
 void
-delete_dead_from_cse (insns, nreg)
+delete_trivially_dead_insns (insns, nreg)
      rtx insns;
      int nreg;
 {
   int *counts = (int *) alloca (nreg * sizeof (int));
   rtx insn, prev;
+#ifdef HAVE_cc0
   rtx tem;
+#endif
   int i;
-  int in_libcall = 0;
+  int in_libcall = 0, dead_libcall = 0;
 
   /* First count the number of times each register is used.  */
   bzero ((char *) counts, sizeof (int) * nreg);
@@ -8729,17 +9132,41 @@ delete_dead_from_cse (insns, nreg)
   for (insn = prev_real_insn (get_last_insn ()); insn; insn = prev)
     {
       int live_insn = 0;
+      rtx note;
 
       prev = prev_real_insn (insn);
 
-      /* Don't delete any insns that are part of a libcall block.
+      /* Don't delete any insns that are part of a libcall block unless
+        we can delete the whole libcall block.
+
         Flow or loop might get confused if we did that.  Remember
         that we are scanning backwards.  */
       if (find_reg_note (insn, REG_RETVAL, NULL_RTX))
-       in_libcall = 1;
+       {
+         in_libcall = 1;
+         live_insn = 1;
+         dead_libcall = 0;
 
-      if (in_libcall)
-       live_insn = 1;
+         /* 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);
+             if (set
+                 && validate_change (insn, &SET_SRC (set), XEXP (note, 0), 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
@@ -8801,6 +9228,9 @@ delete_dead_from_cse (insns, nreg)
        }
 
       if (find_reg_note (insn, REG_LIBCALL, NULL_RTX))
-       in_libcall = 0;
+       {
+         in_libcall = 0;
+         dead_libcall = 0;
+       }
     }
 }