cse.c (simplify_ternary_operation): Don't try to simplify IF_THEN_ELSE expressions...
[gcc.git] / gcc / cse.c
index df64afae27a852b0dc9218054b6c95443053cdc0..22d6b8b0976cd93e82337c69c97f0793969b6deb 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 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -30,6 +30,7 @@ Boston, MA 02111-1307, USA.  */
 #include "real.h"
 #include "insn-config.h"
 #include "recog.h"
+#include "expr.h"
 
 #include <setjmp.h>
 
@@ -192,6 +193,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.  */
 
@@ -202,7 +208,7 @@ static int max_qty;
 
 static int next_qty;
 
-/* Indexed by quantity number, gives the first (or last) (pseudo) register 
+/* Indexed by quantity number, gives the first (or last) register 
    in the chain of registers that currently contain this quantity.  */
 
 static int *qty_first_reg;
@@ -267,13 +273,13 @@ static rtx prev_insn;
 
 static rtx this_insn;
 
-/* Index by (pseudo) register number, gives the quantity number
+/* Index by register number, gives the quantity number
    of the register's current contents.  */
 
 static int *reg_qty;
 
-/* Index by (pseudo) register number, gives the number of the next (or
-   previous) (pseudo) register in the chain of registers sharing the same
+/* Index by register number, gives the number of the next (or
+   previous) register in the chain of registers sharing the same
    value.
 
    Or -1 if this register is at the end of the chain.
@@ -283,12 +289,12 @@ static int *reg_qty;
 static int *reg_next_eqv;
 static int *reg_prev_eqv;
 
-/* Index by (pseudo) register number, gives the number of times
+/* Index by register number, gives the number of times
    that register has been altered in the current basic block.  */
 
 static int *reg_tick;
 
-/* Index by (pseudo) register number, gives the reg_tick value at which
+/* 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.
@@ -519,27 +525,6 @@ static struct table_elt *last_jump_equiv_class;
 
 static int constant_pool_entries_cost;
 
-/* Bits describing what kind of values in memory must be invalidated
-   for a particular instruction.  If all three bits are zero,
-   no memory refs need to be invalidated.  Each bit is more powerful
-   than the preceding ones, and if a bit is set then the preceding
-   bits are also set.
-
-   Here is how the bits are set:
-   Pushing onto the stack invalidates only the stack pointer,
-   writing at a fixed address invalidates only variable addresses,
-   writing in a structure element at variable address
-     invalidates all but scalar variables,
-   and writing in anything else at variable address invalidates everything.  */
-
-struct write_data
-{
-  int sp : 1;                  /* Invalidate stack pointer.  */
-  int var : 1;                 /* Invalidate variable addresses.  */
-  int nonscalar : 1;           /* Invalidate all but scalar variables.  */
-  int all : 1;                 /* Invalidate all memory refs.  */
-};
-
 /* Define maximum length of a branch path.  */
 
 #define PATHLENGTH     10
@@ -582,7 +567,8 @@ struct cse_basic_block_data {
           || XEXP (X, 0) == hard_frame_pointer_rtx             \
           || XEXP (X, 0) == arg_pointer_rtx                    \
           || XEXP (X, 0) == virtual_stack_vars_rtx             \
-          || XEXP (X, 0) == virtual_incoming_args_rtx)))
+          || XEXP (X, 0) == virtual_incoming_args_rtx))        \
+   || GET_CODE (X) == ADDRESSOF)
 
 /* Similar, but also allows reference to the stack pointer.
 
@@ -606,7 +592,8 @@ struct cse_basic_block_data {
    || (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == CONST_INT \
        && (XEXP (X, 0) == stack_pointer_rtx                    \
           || XEXP (X, 0) == virtual_stack_dynamic_rtx          \
-          || XEXP (X, 0) == virtual_outgoing_args_rtx)))
+          || XEXP (X, 0) == virtual_outgoing_args_rtx))        \
+   || GET_CODE (X) == ADDRESSOF)
 
 static int notreg_cost         PROTO((rtx));
 static void new_basic_block    PROTO((void));
@@ -626,9 +613,10 @@ static struct table_elt *insert PROTO((rtx, struct table_elt *, unsigned,
 static void merge_equiv_classes PROTO((struct table_elt *,
                                       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 rehash_using_reg   PROTO((rtx));
-static void invalidate_memory  PROTO((struct write_data *));
+static void invalidate_memory  PROTO((void));
 static void invalidate_for_call        PROTO((void));
 static rtx use_related_value   PROTO((rtx, struct table_elt *));
 static unsigned canon_hash     PROTO((rtx, enum machine_mode));
@@ -638,9 +626,6 @@ static void set_nonvarying_address_components PROTO((rtx, int, rtx *,
                                                     HOST_WIDE_INT *,
                                                     HOST_WIDE_INT *));
 static int refers_to_p         PROTO((rtx, rtx));
-static int refers_to_mem_p     PROTO((rtx, rtx, HOST_WIDE_INT,
-                                      HOST_WIDE_INT));
-static int cse_rtx_addr_varies_p PROTO((rtx));
 static rtx canon_reg           PROTO((rtx, rtx));
 static void find_best_addr     PROTO((rtx, rtx *));
 static enum rtx_code find_comparison_args PROTO((enum rtx_code, rtx *, rtx *,
@@ -656,8 +641,8 @@ 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 note_mem_written   PROTO((rtx, struct write_data *));
-static void invalidate_from_clobbers PROTO((struct write_data *, rtx));
+static int note_mem_written    PROTO((rtx));
+static void invalidate_from_clobbers PROTO((rtx));
 static rtx cse_process_notes   PROTO((rtx, rtx));
 static void cse_around_loop    PROTO((rtx));
 static void invalidate_skipped_set PROTO((rtx, rtx));
@@ -873,11 +858,11 @@ make_regs_eqv (new, old)
       && ((new < FIRST_PSEUDO_REGISTER && FIXED_REGNO_P (new))
          || (new >= FIRST_PSEUDO_REGISTER
              && (firstr < FIRST_PSEUDO_REGISTER
-                 || ((uid_cuid[regno_last_uid[new]] > cse_basic_block_end
-                      || (uid_cuid[regno_first_uid[new]]
+                 || ((uid_cuid[REGNO_LAST_UID (new)] > cse_basic_block_end
+                      || (uid_cuid[REGNO_FIRST_UID (new)]
                           < cse_basic_block_start))
-                     && (uid_cuid[regno_last_uid[new]]
-                         > uid_cuid[regno_last_uid[firstr]]))))))
+                     && (uid_cuid[REGNO_LAST_UID (new)]
+                         > uid_cuid[REGNO_LAST_UID (firstr)]))))))
     {
       reg_prev_eqv[firstr] = new;
       reg_next_eqv[new] = firstr;
@@ -1534,8 +1519,6 @@ invalidate (x, full_mode)
 {
   register int i;
   register struct table_elt *p;
-  rtx base;
-  HOST_WIDE_INT start, end;
 
   /* If X is a register, dependencies on its contents
      are recorded through the qty number mechanism.
@@ -1627,16 +1610,17 @@ invalidate (x, full_mode)
   if (full_mode == VOIDmode)
     full_mode = GET_MODE (x);
 
-  set_nonvarying_address_components (XEXP (x, 0), GET_MODE_SIZE (full_mode),
-                                    &base, &start, &end);
-
   for (i = 0; i < NBUCKETS; i++)
     {
       register struct table_elt *next;
       for (p = table[i]; p; p = next)
        {
          next = p->next_same_hash;
-         if (refers_to_mem_p (p->exp, base, start, end))
+         /* Invalidate ASM_OPERANDS which reference memory (this is easier
+            than checking all the aliases).  */
+         if (p->in_memory
+             && (GET_CODE (p->exp) != MEM
+                 || true_dependence (x, full_mode, p->exp, cse_rtx_varies_p)))
            remove_from_table (p, i);
        }
     }
@@ -1717,30 +1701,6 @@ rehash_using_reg (x)
       }
 }
 \f
-/* Remove from the hash table all expressions that reference memory,
-   or some of them as specified by *WRITES.  */
-
-static void
-invalidate_memory (writes)
-     struct write_data *writes;
-{
-  register int i;
-  register struct table_elt *p, *next;
-  int all = writes->all;
-  int nonscalar = writes->nonscalar;
-
-  for (i = 0; i < NBUCKETS; i++)
-    for (p = table[i]; p; p = next)
-      {
-       next = p->next_same_hash;
-       if (p->in_memory
-           && (all
-               || (nonscalar && p->in_struct)
-               || cse_rtx_addr_varies_p (p->exp)))
-         remove_from_table (p, i);
-      }
-}
-\f
 /* Remove from the hash table any expression that is a call-clobbered
    register.  Also update their TICK values.  */
 
@@ -1778,6 +1738,12 @@ invalidate_for_call ()
        {
          next = p->next_same_hash;
 
+         if (p->in_memory)
+           {
+             remove_from_table (p, hash);
+             continue;
+           }
+
          if (GET_CODE (p->exp) != REG
              || REGNO (p->exp) >= FIRST_PSEUDO_REGISTER)
            continue;
@@ -1913,15 +1879,12 @@ canon_hash (x, mode)
 
        if (regno < FIRST_PSEUDO_REGISTER
            && (global_regs[regno]
-#ifdef SMALL_REGISTER_CLASSES
                || (SMALL_REGISTER_CLASSES
                    && ! fixed_regs[regno]
                    && regno != FRAME_POINTER_REGNUM
                    && regno != HARD_FRAME_POINTER_REGNUM
                    && regno != ARG_POINTER_REGNUM
-                   && regno != STACK_POINTER_REGNUM)
-#endif
-               ))
+                   && regno != STACK_POINTER_REGNUM)))
          {
            do_not_record = 1;
            return 0;
@@ -1955,12 +1918,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:
@@ -1997,6 +1960,10 @@ canon_hash (x, mode)
          do_not_record = 1;
          return 0;
        }
+      break;
+      
+    default:
+      break;
     }
 
   i = GET_RTX_LENGTH (code) - 1;
@@ -2033,6 +2000,8 @@ canon_hash (x, mode)
          register unsigned tem = XINT (x, i);
          hash += tem;
        }
+      else if (fmt[i] == '0')
+       /* unused */;
       else
        abort ();
     }
@@ -2171,6 +2140,9 @@ exp_equiv_p (x, y, validate, equal_values)
                               validate, equal_values)
                  && exp_equiv_p (XEXP (x, 1), XEXP (y, 0),
                                  validate, equal_values)));
+      
+    default:
+      break;
     }
 
   /* Compare the elements.  If any pair of corresponding elements
@@ -2399,6 +2371,9 @@ set_nonvarying_address_components (addr, size, pbase, pstart, pend)
              base = *pbase;
            }
          break;
+
+       default:
+         break;
        }
 
       break;
@@ -2418,105 +2393,31 @@ set_nonvarying_address_components (addr, size, pbase, pstart, pend)
   *pend = end;
 }
 
-/* Return 1 iff any subexpression of X refers to memory
-   at an address of BASE plus some offset
-   such that any of the bytes' offsets fall between START (inclusive)
-   and END (exclusive).
-
-   The value is undefined if X is a varying address (as determined by
-   cse_rtx_addr_varies_p).  This function is not used in such cases.
-
-   When used in the cse pass, `qty_const' is nonzero, and it is used
-   to treat an address that is a register with a known constant value
-   as if it were that constant value.
-   In the loop pass, `qty_const' is zero, so this is not done.  */
+/* Return 1 if X has a value that can vary even between two
+   executions of the program.  0 means X can be compared reliably
+   against certain constants or near-constants.  */
 
 static int
-refers_to_mem_p (x, base, start, end)
-     rtx x, base;
-     HOST_WIDE_INT start, end;
-{
-  register HOST_WIDE_INT i;
-  register enum rtx_code code;
-  register char *fmt;
-
- repeat:
-  if (x == 0)
-    return 0;
-
-  code = GET_CODE (x);
-  if (code == MEM)
-    {
-      register rtx addr = XEXP (x, 0); /* Get the address.  */
-      rtx mybase;
-      HOST_WIDE_INT mystart, myend;
-
-      set_nonvarying_address_components (addr, GET_MODE_SIZE (GET_MODE (x)),
-                                        &mybase, &mystart, &myend);
-
-
-      /* refers_to_mem_p is never called with varying addresses. 
-        If the base addresses are not equal, there is no chance
-        of the memory addresses conflicting.  */
-      if (! rtx_equal_p (mybase, base))
-       return 0;
-
-      return myend > start && mystart < end;
-    }
-
-  /* X does not match, so try its subexpressions.  */
-
-  fmt = GET_RTX_FORMAT (code);
-  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
-    if (fmt[i] == 'e')
-      {
-       if (i == 0)
-         {
-           x = XEXP (x, 0);
-           goto repeat;
-         }
-       else
-         if (refers_to_mem_p (XEXP (x, i), base, start, end))
-           return 1;
-      }
-    else if (fmt[i] == 'E')
-      {
-       int j;
-       for (j = 0; j < XVECLEN (x, i); j++)
-         if (refers_to_mem_p (XVECEXP (x, i, j), base, start, end))
-           return 1;
-      }
-
-  return 0;
-}
-
-/* Nonzero if X refers to memory at a varying address;
-   except that a register which has at the moment a known constant value
-   isn't considered variable.  */
-
-static int
-cse_rtx_addr_varies_p (x)
-     rtx x;
+cse_rtx_varies_p (x)
+     register rtx x;
 {
   /* 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
      doesn't vary in any mode.  */
 
-  if (GET_CODE (x) == MEM
-      && 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))]] != 0)
+  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)
     return 0;
 
-  if (GET_CODE (x) == MEM
-      && GET_CODE (XEXP (x, 0)) == PLUS
-      && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
-      && GET_CODE (XEXP (XEXP (x, 0), 0)) == REG
-      && REGNO_QTY_VALID_P (REGNO (XEXP (XEXP (x, 0), 0)))
-      && (GET_MODE (XEXP (XEXP (x, 0), 0))
-         == qty_mode[reg_qty[REGNO (XEXP (XEXP (x, 0), 0))]])
-      && qty_const[reg_qty[REGNO (XEXP (XEXP (x, 0), 0))]])
+  if (GET_CODE (x) == PLUS
+      && GET_CODE (XEXP (x, 1)) == CONST_INT
+      && 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))]])
     return 0;
 
   /* This can happen as the result of virtual register instantiation, if
@@ -2524,21 +2425,20 @@ cse_rtx_addr_varies_p (x)
      us a three instruction sequence, load large offset into a register,
      load fp minus a constant into a register, then a MEM which is the
      sum of the two `constant' registers.  */
-  if (GET_CODE (x) == MEM
-      && GET_CODE (XEXP (x, 0)) == PLUS
-      && GET_CODE (XEXP (XEXP (x, 0), 0)) == REG
-      && GET_CODE (XEXP (XEXP (x, 0), 1)) == REG
-      && REGNO_QTY_VALID_P (REGNO (XEXP (XEXP (x, 0), 0)))
-      && (GET_MODE (XEXP (XEXP (x, 0), 0))
-         == qty_mode[reg_qty[REGNO (XEXP (XEXP (x, 0), 0))]])
-      && qty_const[reg_qty[REGNO (XEXP (XEXP (x, 0), 0))]]
-      && REGNO_QTY_VALID_P (REGNO (XEXP (XEXP (x, 0), 1)))
-      && (GET_MODE (XEXP (XEXP (x, 0), 1))
-         == qty_mode[reg_qty[REGNO (XEXP (XEXP (x, 0), 1))]])
-      && qty_const[reg_qty[REGNO (XEXP (XEXP (x, 0), 1))]])
+  if (GET_CODE (x) == PLUS
+      && GET_CODE (XEXP (x, 0)) == REG
+      && 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))]]
+      && 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))]])
     return 0;
 
-  return rtx_addr_varies_p (x);
+  return rtx_varies_p (x);
 }
 \f
 /* Canonicalize an expression:
@@ -2594,8 +2494,11 @@ canon_reg (x, insn)
        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:
+      break;
     }
 
   fmt = GET_RTX_FORMAT (code);
@@ -2679,6 +2582,7 @@ find_best_addr (insn, loc)
          && (regno = REGNO (addr), regno == FRAME_POINTER_REGNUM
              || regno == HARD_FRAME_POINTER_REGNUM
              || regno == ARG_POINTER_REGNUM))
+      || GET_CODE (addr) == ADDRESSOF
       || CONSTANT_ADDRESS_P (addr))
     return;
 
@@ -2694,9 +2598,9 @@ find_best_addr (insn, loc)
 #ifdef ADDRESS_COST
          && (ADDRESS_COST (folded) < ADDRESS_COST (addr)
              || (ADDRESS_COST (folded) == ADDRESS_COST (addr)
-                 && rtx_cost (folded) > rtx_cost (addr)))
+                 && rtx_cost (folded, MEM) > rtx_cost (addr, MEM)))
 #else
-         && rtx_cost (folded) < rtx_cost (addr)
+         && rtx_cost (folded, MEM) < rtx_cost (addr, MEM)
 #endif
          && validate_change (insn, loc, folded, 0))
        addr = folded;
@@ -3439,6 +3343,9 @@ simplify_unary_operation (code, mode, op, op_mode)
            return convert_memory_address (Pmode, op);
          break;
 #endif
+         
+       default:
+         break;
        }
 
       return 0;
@@ -3489,6 +3396,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)
@@ -3785,11 +3696,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))
@@ -3873,9 +3784,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;
 
@@ -3884,7 +3795,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.  */
@@ -3910,7 +3821,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)
@@ -3930,10 +3841,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;
 
@@ -3958,7 +3869,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;
@@ -3986,7 +3897,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 ...  */
 
@@ -4017,11 +3928,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
                }
            }
@@ -4032,7 +3943,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 ...  */
 
@@ -4366,6 +4277,9 @@ simplify_plus_minus (code, mode, op0, op1)
            if (negs[i])
              ops[i] = GEN_INT (- INTVAL (ops[i])), negs[i] = 0, changed = 1;
            break;
+
+         default:
+           break;
          }
     }
 
@@ -4461,7 +4375,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 
@@ -4501,7 +4415,7 @@ 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
 /* Like simplify_binary_operation except used for relational operators.
@@ -4599,7 +4513,7 @@ simplify_relational_operation (code, mode, op0, op1)
       else
        {
          l0u = l0s = INTVAL (op0);
-         h0u = 0, h0s = l0s < 0 ? -1 : 0;
+         h0u = h0s = l0s < 0 ? -1 : 0;
        }
          
       if (GET_CODE (op1) == CONST_DOUBLE)
@@ -4610,7 +4524,7 @@ simplify_relational_operation (code, mode, op0, op1)
       else
        {
          l1u = l1s = INTVAL (op1);
-         h1u = 0, h1s = l1s < 0 ? -1 : 0;
+         h1u = h1s = l1s < 0 ? -1 : 0;
        }
 
       /* If WIDTH is nonzero and smaller than HOST_BITS_PER_WIDE_INT,
@@ -4691,6 +4605,9 @@ simplify_relational_operation (code, mode, op0, op1)
              && INTEGRAL_MODE_P (mode))
            return const0_rtx;
          break;
+         
+       default:
+         break;
        }
 
       return 0;
@@ -4720,9 +4637,9 @@ simplify_relational_operation (code, mode, op0, op1)
       return equal || op0ltu ? const_true_rtx : const0_rtx;
     case GEU:
       return equal || op1ltu ? const_true_rtx : const0_rtx;
+    default:
+      abort ();
     }
-
-  abort ();
 }
 \f
 /* Simplify CODE, an operation with result mode MODE and three operands,
@@ -4786,6 +4703,27 @@ simplify_ternary_operation (code, mode, op0_mode, op0, op1, op2)
     case IF_THEN_ELSE:
       if (GET_CODE (op0) == CONST_INT)
        return op0 != const0_rtx ? op1 : op2;
+
+      /* Convert a == b ? b : a to "a".  */
+      if (GET_CODE (op0) == NE && ! side_effects_p (op0)
+         && rtx_equal_p (XEXP (op0, 0), op1)
+         && rtx_equal_p (XEXP (op0, 1), op2))
+       return op1;
+      else if (GET_CODE (op0) == EQ && ! side_effects_p (op0)
+         && 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:
@@ -4852,6 +4790,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
@@ -4872,7 +4814,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;
 
@@ -5101,6 +5043,8 @@ fold_rtx (x, insn)
        else if (GET_CODE (addr) == LO_SUM
                 && GET_CODE (XEXP (addr, 1)) == SYMBOL_REF)
          base = XEXP (addr, 1);
+       else if (GET_CODE (addr) == ADDRESSOF)
+         return change_address (x, VOIDmode, addr);
 
        /* If this is a constant pool reference, we can fold it into its
           constant to allow better value tracking.  */
@@ -5169,17 +5113,17 @@ 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);
+                   return gen_rtx_CONST (GET_MODE (new), new);
                  }
              }
          }
@@ -5192,6 +5136,9 @@ fold_rtx (x, insn)
        validate_change (insn, &XVECEXP (x, 3, i),
                         fold_rtx (XVECEXP (x, 3, i), insn), 0);
       break;
+      
+    default:
+      break;
     }
 
   const_arg0 = 0;
@@ -5376,7 +5323,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;
       
@@ -5527,6 +5474,8 @@ fold_rtx (x, insn)
                  if (has_sign)
                    return false;
                  break;
+               default:
+                 break;
                }
            }
        }
@@ -5722,6 +5671,10 @@ fold_rtx (x, insn)
 
              return cse_gen_binary (code, mode, y, new_const);
            }
+         break;
+
+       default:
+         break;
        }
 
       new = simplify_binary_operation (code, mode,
@@ -5821,7 +5774,7 @@ 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);
@@ -5917,7 +5870,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);
     }
 
@@ -5929,7 +5882,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);
     }
 
@@ -5949,7 +5902,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);
     }
 
@@ -5962,7 +5915,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);
     }
 
@@ -6160,9 +6113,7 @@ cse_insn (insn, in_libcall_block)
 
   /* Records what this insn does to set CC0.  */
   rtx this_insn_cc0 = 0;
-  enum machine_mode this_insn_cc0_mode;
-  struct write_data writes_memory;
-  static struct write_data init = {0, 0, 0, 0};
+  enum machine_mode this_insn_cc0_mode = VOIDmode;
 
   rtx src_eqv = 0;
   struct table_elt *src_eqv_elt = 0;
@@ -6174,7 +6125,6 @@ cse_insn (insn, in_libcall_block)
   struct set *sets;
 
   this_insn = insn;
-  writes_memory = init;
 
   /* Find all the SETs and CLOBBERs in this instruction.
      Record all the SETs in the array `set' and count them.
@@ -6276,15 +6226,11 @@ cse_insn (insn, in_libcall_block)
            }
          else if (GET_CODE (y) == CLOBBER)
            {
-             /* If we clobber memory, take note of that,
-                and canon the address.
+             /* If we clobber memory, canon the address.
                 This does nothing when a register is clobbered
                 because we have already invalidated the reg.  */
              if (GET_CODE (XEXP (y, 0)) == MEM)
-               {
-                 canon_reg (XEXP (y, 0), NULL_RTX);
-                 note_mem_written (XEXP (y, 0), &writes_memory);
-               }
+               canon_reg (XEXP (y, 0), NULL_RTX);
            }
          else if (GET_CODE (y) == USE
                   && ! (GET_CODE (XEXP (y, 0)) == REG
@@ -6303,10 +6249,7 @@ cse_insn (insn, in_libcall_block)
   else if (GET_CODE (x) == CLOBBER)
     {
       if (GET_CODE (XEXP (x, 0)) == MEM)
-       {
-         canon_reg (XEXP (x, 0), NULL_RTX);
-         note_mem_written (XEXP (x, 0), &writes_memory);
-       }
+       canon_reg (XEXP (x, 0), NULL_RTX);
     }
 
   /* Canonicalize a USE of a pseudo register or memory location.  */
@@ -6492,7 +6435,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.  */
 
@@ -6500,7 +6443,7 @@ cse_insn (insn, in_libcall_block)
          && find_reg_note (insn, REG_EQUIV, src) != 0
          && GET_CODE (dest) == REG
          && REGNO (dest) >= FIRST_PSEUDO_REGISTER
-         && reg_n_sets[REGNO (dest)] != 1)
+         && REG_N_SETS (REGNO (dest)) != 1)
        sets[i].src_volatile = 1;
 
 #if 0
@@ -6670,7 +6613,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;
@@ -6773,6 +6716,18 @@ cse_insn (insn, in_libcall_block)
          if (code != REG && ! exp_equiv_p (p->exp, p->exp, 1, 0))
            continue;
 
+         /* Also skip paradoxical subregs, unless that's what we're
+            looking for.  */
+         if (code == SUBREG
+             && (GET_MODE_SIZE (GET_MODE (p->exp))
+                 > GET_MODE_SIZE (GET_MODE (SUBREG_REG (p->exp))))
+             && ! (src != 0
+                   && GET_CODE (src) == SUBREG
+                   && GET_MODE (src) == GET_MODE (p->exp)
+                   && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (src)))
+                       < GET_MODE_SIZE (GET_MODE (SUBREG_REG (p->exp))))))
+           continue;
+
           if (src && GET_CODE (src) == code && rtx_equal_p (src, p->exp))
            src = 0;
           else if (src_folded && GET_CODE (src_folded) == code
@@ -6846,6 +6801,25 @@ cse_insn (insn, in_libcall_block)
           while (elt && GET_CODE (elt->exp) != REG
                 && ! exp_equiv_p (elt->exp, elt->exp, 1, 0))
            elt = elt->next_same_value;      
+
+         /* A paradoxical subreg would be bad here: it'll be the right
+            size, but later may be adjusted so that the upper bits aren't
+            what we want.  So reject it.  */
+         if (elt != 0
+             && GET_CODE (elt->exp) == SUBREG
+             && (GET_MODE_SIZE (GET_MODE (elt->exp))
+                 > GET_MODE_SIZE (GET_MODE (SUBREG_REG (elt->exp))))
+             /* It is okay, though, if the rtx we're trying to match
+                will ignore any of the bits we can't predict.  */
+             && ! (src != 0
+                   && GET_CODE (src) == SUBREG
+                   && GET_MODE (src) == GET_MODE (elt->exp)
+                   && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (src)))
+                       < GET_MODE_SIZE (GET_MODE (SUBREG_REG (elt->exp))))))
+           {
+             elt = elt->next_same_value;
+             continue;
+           }
              
           if (elt) src_elt_cost = elt->cost;
 
@@ -6901,7 +6875,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;
@@ -6933,7 +6907,8 @@ cse_insn (insn, in_libcall_block)
                   && (src_folded == 0
                       || (GET_CODE (src_folded) != MEM
                           && ! src_folded_force_flag))
-                  && GET_MODE_CLASS (mode) != MODE_CC)
+                  && GET_MODE_CLASS (mode) != MODE_CC
+                  && mode != VOIDmode)
            {
              src_folded_force_flag = 1;
              src_folded = trial;
@@ -6965,7 +6940,7 @@ cse_insn (insn, in_libcall_block)
 
          src = SET_SRC (sets[i].rtl)
            = first >= FIRST_PSEUDO_REGISTER ? regno_reg_rtx[first]
-             : gen_rtx (REG, GET_MODE (src), 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
@@ -7004,8 +6979,8 @@ cse_insn (insn, in_libcall_block)
          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,
@@ -7031,8 +7006,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));
                }
            }
        }
@@ -7056,13 +7032,15 @@ cse_insn (insn, in_libcall_block)
 
       if (GET_CODE (dest) == MEM)
        {
+#ifdef PUSH_ROUNDING
+         /* Stack pushes invalidate the stack pointer.  */
+         rtx addr = XEXP (dest, 0);
+         if ((GET_CODE (addr) == PRE_DEC || GET_CODE (addr) == PRE_INC
+              || GET_CODE (addr) == POST_DEC || GET_CODE (addr) == POST_INC)
+             && XEXP (addr, 0) == stack_pointer_rtx)
+           invalidate (stack_pointer_rtx, Pmode);
+#endif
          dest = fold_rtx (dest, insn);
-
-         /* Decide whether we invalidate everything in memory,
-            or just things at non-fixed places.
-            Writing a large aggregate must invalidate everything
-            because we don't know how long it is.  */
-         note_mem_written (dest, &writes_memory);
        }
 
       /* Compute the hash code of the destination now,
@@ -7110,7 +7088,8 @@ cse_insn (insn, in_libcall_block)
          NOTE_SOURCE_FILE (insn) = 0;
          cse_jumps_altered = 1;
          /* One less use of the label this insn used to jump to.  */
-         --LABEL_NUSES (JUMP_LABEL (insn));
+         if (JUMP_LABEL (insn) != 0)
+           --LABEL_NUSES (JUMP_LABEL (insn));
          /* No more processing for this set.  */
          sets[i].rtl = 0;
        }
@@ -7207,8 +7186,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
     }
@@ -7307,17 +7286,15 @@ cse_insn (insn, in_libcall_block)
         so that the destination goes into that class.  */
       sets[i].src_elt = src_eqv_elt;
 
-  invalidate_from_clobbers (&writes_memory, x);
+  invalidate_from_clobbers (x);
 
   /* Some registers are invalidated by subroutine calls.  Memory is 
      invalidated by non-constant calls.  */
 
   if (GET_CODE (insn) == CALL_INSN)
     {
-      static struct write_data everything = {0, 1, 1, 1};
-
       if (! CONST_CALL_P (insn))
-       invalidate_memory (&everything);
+       invalidate_memory ();
       invalidate_for_call ();
     }
 
@@ -7338,8 +7315,7 @@ cse_insn (insn, in_libcall_block)
           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 && ! writes_memory.all
-               && ! cse_rtx_addr_varies_p (dest)))
+           || GET_CODE (dest) == MEM)
          invalidate (dest, VOIDmode);
        else if (GET_CODE (dest) == STRICT_LOW_PART
                 || GET_CODE (dest) == ZERO_EXTRACT)
@@ -7393,6 +7369,10 @@ cse_insn (insn, in_libcall_block)
        if ((flag_float_store
             && GET_CODE (dest) == MEM
             && FLOAT_MODE_P (GET_MODE (dest)))
+           /* Don't record BLKmode values, because we don't know the
+              size of it, and can't be sure that other BLKmode values
+              have the same or smaller size.  */
+           || GET_MODE (dest) == BLKmode
            /* Don't record values of destinations set inside a 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
@@ -7485,7 +7465,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);
@@ -7509,6 +7489,11 @@ cse_insn (insn, in_libcall_block)
                  merge_equiv_classes (src_elt, classp);
 
                classp = src_elt->first_same_value;
+               /* Ignore invalid entries.  */
+               while (classp
+                      && GET_CODE (classp->exp) != REG
+                      && ! exp_equiv_p (classp->exp, classp->exp, 1, 0))
+                 classp = classp->next_same_value;
              }
          }
       }
@@ -7607,53 +7592,43 @@ cse_insn (insn, in_libcall_block)
   prev_insn = insn;
 }
 \f
-/* Store 1 in *WRITES_PTR for those categories of memory ref
-   that must be invalidated when the expression WRITTEN is stored in.
-   If WRITTEN is null, say everything must be invalidated.  */
-
+/* Remove from the ahsh table all expressions that reference memory.  */
 static void
-note_mem_written (written, writes_ptr)
-     rtx written;
-     struct write_data *writes_ptr;
+invalidate_memory ()
 {
-  static struct write_data everything = {0, 1, 1, 1};
+  register int i;
+  register struct table_elt *p, *next;
+
+  for (i = 0; i < NBUCKETS; i++)
+    for (p = table[i]; p; p = next)
+      {
+       next = p->next_same_hash;
+       if (p->in_memory)
+         remove_from_table (p, i);
+      }
+}
 
-  if (written == 0)
-    *writes_ptr = everything;
-  else if (GET_CODE (written) == MEM)
+/* XXX ??? The name of this function bears little resemblance to
+   what this function actually does.  FIXME.  */
+static int
+note_mem_written (addr)
+     register rtx addr;
+{
+  /* Pushing or popping the stack invalidates just the stack pointer.  */
+  if ((GET_CODE (addr) == PRE_DEC || GET_CODE (addr) == PRE_INC
+       || GET_CODE (addr) == POST_DEC || GET_CODE (addr) == POST_INC)
+      && GET_CODE (XEXP (addr, 0)) == REG
+      && REGNO (XEXP (addr, 0)) == STACK_POINTER_REGNUM)
     {
-      /* Pushing or popping the stack invalidates just the stack pointer.  */
-      rtx addr = XEXP (written, 0);
-      if ((GET_CODE (addr) == PRE_DEC || GET_CODE (addr) == PRE_INC
-          || GET_CODE (addr) == POST_DEC || GET_CODE (addr) == POST_INC)
-         && GET_CODE (XEXP (addr, 0)) == REG
-         && REGNO (XEXP (addr, 0)) == STACK_POINTER_REGNUM)
-       {
-         writes_ptr->sp = 1;
-         return;
-       }
-      else if (GET_MODE (written) == BLKmode)
-       *writes_ptr = everything;
-      else if (cse_rtx_addr_varies_p (written))
-       {
-         /* A varying address that is a sum indicates an array element,
-            and that's just as good as a structure element
-            in implying that we need not invalidate scalar variables.
-            However, we must allow QImode aliasing of scalars, because the
-            ANSI C standard allows character pointers to alias anything.
-            We must also allow AND addresses, because they may generate
-            accesses outside the object being referenced.  This is used to
-            generate aligned addresses from unaligned addresses, for instance,
-            the alpha storeqi_unaligned pattern.  */
-         if (! ((MEM_IN_STRUCT_P (written)
-                 || GET_CODE (XEXP (written, 0)) == PLUS)
-                && GET_MODE (written) != QImode
-                && GET_CODE (XEXP (written, 0)) != AND))
-           writes_ptr->all = 1;
-         writes_ptr->nonscalar = 1;
-       }
-      writes_ptr->var = 1;
+      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))
+       invalidate (stack_pointer_rtx, VOIDmode);
+      return 1;
     }
+  return 0;
 }
 
 /* Perform invalidation on the basis of everything about an insn
@@ -7661,41 +7636,24 @@ note_mem_written (written, writes_ptr)
    This includes the places CLOBBERed, and anything that might
    alias with something that is SET or CLOBBERed.
 
-   W points to the writes_memory for this insn, a struct write_data
-   saying which kinds of memory references must be invalidated.
    X is the pattern of the insn.  */
 
 static void
-invalidate_from_clobbers (w, x)
-     struct write_data *w;
+invalidate_from_clobbers (x)
      rtx x;
 {
-  /* If W->var is not set, W specifies no action.
-     If W->all is set, this step gets all memory refs
-     so they can be ignored in the rest of this function.  */
-  if (w->var)
-    invalidate_memory (w);
-
-  if (w->sp)
-    {
-      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))
-       invalidate (stack_pointer_rtx, VOIDmode);
-    }
-
   if (GET_CODE (x) == CLOBBER)
     {
       rtx ref = XEXP (x, 0);
-
-      if (GET_CODE (ref) == REG || GET_CODE (ref) == SUBREG
-         || (GET_CODE (ref) == MEM && ! w->all))
-       invalidate (ref, VOIDmode);
-      else if (GET_CODE (ref) == STRICT_LOW_PART
-              || GET_CODE (ref) == ZERO_EXTRACT)
-       invalidate (XEXP (ref, 0), GET_MODE (ref));
+      if (ref)
+       {
+         if (GET_CODE (ref) == REG || GET_CODE (ref) == SUBREG
+             || GET_CODE (ref) == MEM)
+           invalidate (ref, VOIDmode);
+         else if (GET_CODE (ref) == STRICT_LOW_PART
+                  || GET_CODE (ref) == ZERO_EXTRACT)
+           invalidate (XEXP (ref, 0), GET_MODE (ref));
+       }
     }
   else if (GET_CODE (x) == PARALLEL)
     {
@@ -7706,15 +7664,12 @@ invalidate_from_clobbers (w, x)
          if (GET_CODE (y) == CLOBBER)
            {
              rtx ref = XEXP (y, 0);
-             if (ref)
-               {
-                 if (GET_CODE (ref) == REG || GET_CODE (ref) == SUBREG
-                     || (GET_CODE (ref) == MEM && !w->all))
-                   invalidate (ref, VOIDmode);
-                 else if (GET_CODE (ref) == STRICT_LOW_PART
-                          || GET_CODE (ref) == ZERO_EXTRACT)
-                   invalidate (XEXP (ref, 0), GET_MODE (ref));
-               }
+             if (GET_CODE (ref) == REG || GET_CODE (ref) == SUBREG
+                 || GET_CODE (ref) == MEM)
+               invalidate (ref, VOIDmode);
+             else if (GET_CODE (ref) == STRICT_LOW_PART
+                      || GET_CODE (ref) == ZERO_EXTRACT)
+               invalidate (XEXP (ref, 0), GET_MODE (ref));
            }
        }
     }
@@ -7790,6 +7745,9 @@ cse_process_notes (x, object)
 
       /* Otherwise, canonicalize this register.  */
       return canon_reg (x, NULL_RTX);
+      
+    default:
+      break;
     }
 
   for (i = 0; i < GET_RTX_LENGTH (code); i++)
@@ -7854,10 +7812,16 @@ cse_around_loop (loop_start)
 
      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))
@@ -7876,10 +7840,6 @@ cse_around_loop (loop_start)
     }
 }
 \f
-/* Variable used for communications between the next two routines.  */
-
-static struct write_data skipped_writes_memory;
-
 /* Process one SET of an insn that was skipped.  We ignore CLOBBERs
    since they are done elsewhere.  This function is called via note_stores.  */
 
@@ -7888,14 +7848,21 @@ invalidate_skipped_set (dest, set)
      rtx set;
      rtx dest;
 {
-  if (GET_CODE (dest) == MEM)
-    note_mem_written (dest, &skipped_writes_memory);
-
-  /* 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 promote "nonscalar" to be "all".  */
-  if (skipped_writes_memory.nonscalar)
-    skipped_writes_memory.all = 1;
+  enum rtx_code code = GET_CODE (dest);
+
+  if (code == MEM
+      && ! note_mem_written (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))))
+    {
+      invalidate_memory ();
+      return;
+    }
 
   if (GET_CODE (set) == CLOBBER
 #ifdef HAVE_cc0
@@ -7904,12 +7871,10 @@ invalidate_skipped_set (dest, set)
       || dest == pc_rtx)
     return;
 
-  if (GET_CODE (dest) == REG || GET_CODE (dest) == SUBREG
-      || (! skipped_writes_memory.all && ! cse_rtx_addr_varies_p (dest)))
-    invalidate (dest, VOIDmode);
-  else if (GET_CODE (dest) == STRICT_LOW_PART
-          || GET_CODE (dest) == ZERO_EXTRACT)
+  if (code == STRICT_LOW_PART || code == ZERO_EXTRACT)
     invalidate (XEXP (dest, 0), GET_MODE (dest));
+  else if (code == REG || code == SUBREG || code == MEM)
+    invalidate (dest, VOIDmode);
 }
 
 /* Invalidate all insns from START up to the end of the function or the
@@ -7921,8 +7886,6 @@ invalidate_skipped_block (start)
      rtx start;
 {
   rtx insn;
-  static struct write_data init = {0, 0, 0, 0};
-  static struct write_data everything = {0, 1, 1, 1};
 
   for (insn = start; insn && GET_CODE (insn) != CODE_LABEL;
        insn = NEXT_INSN (insn))
@@ -7930,16 +7893,14 @@ invalidate_skipped_block (start)
       if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
        continue;
 
-      skipped_writes_memory = init;
-
       if (GET_CODE (insn) == CALL_INSN)
        {
+         if (! CONST_CALL_P (insn))
+           invalidate_memory ();
          invalidate_for_call ();
-         skipped_writes_memory = everything;
        }
 
       note_stores (PATTERN (insn), invalidate_skipped_set);
-      invalidate_from_clobbers (&skipped_writes_memory, PATTERN (insn));
     }
 }
 \f
@@ -7989,10 +7950,6 @@ cse_set_around_loop (x, insn, loop_start)
      rtx loop_start;
 {
   struct table_elt *src_elt;
-  static struct write_data init = {0, 0, 0, 0};
-  struct write_data writes_memory;
-
-  writes_memory = init;
 
   /* If this is a SET, see if we can replace SET_SRC, but ignore SETs that
      are setting PC or CC0 or whose SET_SRC is already a register.  */
@@ -8052,16 +8009,11 @@ cse_set_around_loop (x, insn, loop_start)
     }
 
   /* Now invalidate anything modified by X.  */
-  note_mem_written (SET_DEST (x), &writes_memory);
-
-  if (writes_memory.var)
-    invalidate_memory (&writes_memory);
+  note_mem_written (SET_DEST (x));
 
-  /* See comment on similar code in cse_insn for explanation of these
-     tests.  */
+  /* See comment on similar code in cse_insn for explanation of these tests.  */
   if (GET_CODE (SET_DEST (x)) == REG || GET_CODE (SET_DEST (x)) == SUBREG
-      || (GET_CODE (SET_DEST (x)) == MEM && ! writes_memory.all
-         && ! cse_rtx_addr_varies_p (SET_DEST (x))))
+      || GET_CODE (SET_DEST (x)) == MEM)
     invalidate (SET_DEST (x), VOIDmode);
   else if (GET_CODE (SET_DEST (x)) == STRICT_LOW_PART
           || GET_CODE (SET_DEST (x)) == ZERO_EXTRACT)
@@ -8181,6 +8133,7 @@ cse_end_of_basic_block (insn, data, follow_jumps, after_loop, skip_blocks)
               && GET_CODE (p) == JUMP_INSN
               && GET_CODE (PATTERN (p)) == SET
               && GET_CODE (SET_SRC (PATTERN (p))) == IF_THEN_ELSE
+              && JUMP_LABEL (p) != 0
               && LABEL_NUSES (JUMP_LABEL (p)) == 1
               && NEXT_INSN (JUMP_LABEL (p)) != 0)
        {
@@ -8311,9 +8264,12 @@ cse_main (f, nregs, after_loop, file)
   val.path_size = 0;
 
   init_recog ();
+  init_alias_analysis ();
 
   max_reg = nregs;
 
+  max_insn_uid = get_max_uid ();
+
   all_minus_one = (int *) alloca (nregs * sizeof (int));
   consec_ints = (int *) alloca (nregs * sizeof (int));
 
@@ -8333,7 +8289,7 @@ cse_main (f, nregs, after_loop, file)
 
   /* 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, 0);
+  memory_extend_rtx = gen_rtx_ZERO_EXTEND (VOIDmode, NULL_RTX);
 #endif
 
   /* Discard all the free elements of the previous function
@@ -8482,6 +8438,7 @@ cse_basic_block (from, to, next_branch, around_loop)
   register rtx insn;
   int to_usage = 0;
   int in_libcall_block = 0;
+  int num_insns = 0;
 
   /* Each of these arrays is undefined before max_reg, so only allocate
      the space actually needed and adjust the start below.  */
@@ -8514,6 +8471,29 @@ 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;
+
+      /* If we have processed 1,000 insns, flush the hash table to avoid
+        extreme quadratic behavior.
+
+        ??? This is a real kludge and needs to be done some other way.
+        Perhaps for 2.9.  */
+      if (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);
+             }
+
+         num_insns = 0;
+       }
 
       /* See if this is a branch that is part of the path.  If so, and it is
         to be taken, do so.  */
@@ -8737,6 +8717,9 @@ count_reg_usage (x, counts, dest, incr)
        count_reg_usage (XEXP (x, 0), counts, NULL_RTX, incr);
       count_reg_usage (XEXP (x, 1), counts, NULL_RTX, incr);
       return;
+      
+    default:
+      break;
     }
 
   fmt = GET_RTX_FORMAT (code);