cse.c (simplify_ternary_operation): Don't try to simplify IF_THEN_ELSE expressions...
[gcc.git] / gcc / cse.c
index 9bcdcc3675e409a77fe8eef01cf4a5844edae09f..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.  */
 
@@ -561,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.
 
@@ -585,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));
@@ -1871,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;
@@ -1913,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:
@@ -1955,6 +1960,10 @@ canon_hash (x, mode)
          do_not_record = 1;
          return 0;
        }
+      break;
+      
+    default:
+      break;
     }
 
   i = GET_RTX_LENGTH (code) - 1;
@@ -1991,6 +2000,8 @@ canon_hash (x, mode)
          register unsigned tem = XINT (x, i);
          hash += tem;
        }
+      else if (fmt[i] == '0')
+       /* unused */;
       else
        abort ();
     }
@@ -2129,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
@@ -2357,6 +2371,9 @@ set_nonvarying_address_components (addr, size, pbase, pstart, pend)
              base = *pbase;
            }
          break;
+
+       default:
+         break;
        }
 
       break;
@@ -2477,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);
@@ -2562,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;
 
@@ -3322,6 +3343,9 @@ simplify_unary_operation (code, mode, op, op_mode)
            return convert_memory_address (Pmode, op);
          break;
 #endif
+         
+       default:
+         break;
        }
 
       return 0;
@@ -3372,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)
@@ -3668,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))
@@ -3756,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;
 
@@ -3767,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.  */
@@ -3793,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)
@@ -3813,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;
 
@@ -3841,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;
@@ -3869,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 ...  */
 
@@ -3900,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
                }
            }
@@ -3915,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 ...  */
 
@@ -4249,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;
          }
     }
 
@@ -4344,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 
@@ -4384,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.
@@ -4482,14 +4513,7 @@ simplify_relational_operation (code, mode, op0, op1)
       else
        {
          l0u = l0s = INTVAL (op0);
-         h0s = l0s < 0 ? -1 : 0;
-         /* If WIDTH is nonzero and larger than HOST_BITS_PER_WIDE_INT,
-            then the high word is derived from the sign bit of the low
-            word, else the high word is zero.  */
-         if (width != 0 && width > HOST_BITS_PER_WIDE_INT)
-           h0u = l0s < 0 ? -1 : 0;
-         else
-           h0u = 0;
+         h0u = h0s = l0s < 0 ? -1 : 0;
        }
          
       if (GET_CODE (op1) == CONST_DOUBLE)
@@ -4500,14 +4524,7 @@ simplify_relational_operation (code, mode, op0, op1)
       else
        {
          l1u = l1s = INTVAL (op1);
-         h1s = l1s < 0 ? -1 : 0;
-         /* If WIDTH is nonzero and larger than HOST_BITS_PER_WIDE_INT,
-            then the high word is derived from the sign bit of the low
-            word, else the high word is zero.  */
-         if (width != 0 && width > HOST_BITS_PER_WIDE_INT)
-           h1u = l1s < 0 ? -1 : 0;
-         else
-           h1u = 0;
+         h1u = h1s = l1s < 0 ? -1 : 0;
        }
 
       /* If WIDTH is nonzero and smaller than HOST_BITS_PER_WIDE_INT,
@@ -4588,6 +4605,9 @@ simplify_relational_operation (code, mode, op0, op1)
              && INTEGRAL_MODE_P (mode))
            return const0_rtx;
          break;
+         
+       default:
+         break;
        }
 
       return 0;
@@ -4617,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,
@@ -4683,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:
@@ -4749,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
@@ -4769,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;
 
@@ -4998,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.  */
@@ -5066,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);
                  }
              }
          }
@@ -5089,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;
@@ -5273,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;
       
@@ -5424,6 +5474,8 @@ fold_rtx (x, insn)
                  if (has_sign)
                    return false;
                  break;
+               default:
+                 break;
                }
            }
        }
@@ -5619,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,
@@ -5718,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);
@@ -5814,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);
     }
 
@@ -5826,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);
     }
 
@@ -5846,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);
     }
 
@@ -5859,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);
     }
 
@@ -6057,7 +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;
+  enum machine_mode this_insn_cc0_mode = VOIDmode;
 
   rtx src_eqv = 0;
   struct table_elt *src_eqv_elt = 0;
@@ -6379,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.  */
 
@@ -6557,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;
@@ -6819,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;
@@ -6884,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
@@ -6923,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,
@@ -6950,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));
                }
            }
        }
@@ -7031,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;
        }
@@ -7128,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
     }
@@ -7407,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);
@@ -7431,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;
              }
          }
       }
@@ -7682,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++)
@@ -7746,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))
@@ -8061,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)
        {
@@ -8195,6 +8268,8 @@ cse_main (f, nregs, after_loop, file)
 
   max_reg = nregs;
 
+  max_insn_uid = get_max_uid ();
+
   all_minus_one = (int *) alloca (nregs * sizeof (int));
   consec_ints = (int *) alloca (nregs * sizeof (int));
 
@@ -8214,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
@@ -8363,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.  */
@@ -8395,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.  */
@@ -8618,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);