]> gcc.gnu.org Git - gcc.git/blobdiff - gcc/cse.c
(call_insn_operand): New funcion.
[gcc.git] / gcc / cse.c
index e945768f1fdf396ba1fccc031c1dd7c560c5c00d..3d2702fbbe3c3ccc093d3acaead7038a3b5d9261 100644 (file)
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -1,5 +1,5 @@
 /* Common subexpression elimination for GNU compiler.
-   Copyright (C) 1987, 1988, 1989, 1992 Free Software Foundation, Inc.
+   Copyright (C) 1987, 1988, 1989, 1992. 1993 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -326,7 +326,10 @@ static int cse_basic_block_end;
    The cuids are like uids but increase monotonically always.
    We use them to see whether a reg is used outside a given basic block.  */
 
-static short *uid_cuid;
+static int *uid_cuid;
+
+/* Highest UID in UID_CUID.  */
+static int max_uid;
 
 /* Get the cuid of an insn.  */
 
@@ -443,15 +446,21 @@ struct table_elt
 #endif
 
 /* Compute cost of X, as stored in the `cost' field of a table_elt.  Fixed
-   hard registers are the cheapest with a cost of 0.  Next come pseudos
-   with a cost of one and other hard registers with a cost of 2.  Aside
-   from these special cases, call `rtx_cost'.  */
+   hard registers and pointers into the frame are the cheapest with a cost
+   of 0.  Next come pseudos with a cost of one and other hard registers with
+   a cost of 2.  Aside from these special cases, call `rtx_cost'.  */
+
+#define CHEAP_REG(N) \
+  ((N) == FRAME_POINTER_REGNUM || (N) == STACK_POINTER_REGNUM \
+   || (N) == ARG_POINTER_REGNUM                                \
+   || ((N) >= FIRST_VIRTUAL_REGISTER && (N) <= LAST_VIRTUAL_REGISTER) \
+   || ((N) < FIRST_PSEUDO_REGISTER                     \
+       && FIXED_REGNO_P (N) && REGNO_REG_CLASS (N) != NO_REGS))
 
 #define COST(X)                                                \
   (GET_CODE (X) == REG                                 \
-   ? (REGNO (X) >= FIRST_PSEUDO_REGISTER ? 1           \
-      : (FIXED_REGNO_P (REGNO (X))                     \
-        && REGNO_REG_CLASS (REGNO (X)) != NO_REGS) ? 0 \
+   ? (CHEAP_REG (REGNO (X)) ? 0                                \
+      : REGNO (X) >= FIRST_PSEUDO_REGISTER ? 1         \
       : 2)                                             \
    : rtx_cost (X, SET) * 2)
 
@@ -510,6 +519,34 @@ struct write_data
   int all : 1;                 /* Invalidate all memory refs.  */
 };
 
+/* Define maximum length of a branch path.  */
+
+#define PATHLENGTH     10
+
+/* This data describes a block that will be processed by cse_basic_block.  */
+
+struct cse_basic_block_data {
+  /* Lowest CUID value of insns in block.  */
+  int low_cuid;
+  /* Highest CUID value of insns in block.  */
+  int high_cuid;
+  /* Total number of SETs in block.  */
+  int nsets;
+  /* Last insn in the block.  */
+  rtx last;
+  /* Size of current branch path, if any.  */
+  int path_size;
+  /* Current branch path, indicating which branches will be taken.  */
+  struct branch_path {
+    /* The branch insn. */
+    rtx branch;
+    /* Whether it should be taken or not.  AROUND is the same as taken
+       except that it is used when the destination label is not preceded
+       by a BARRIER.  */
+    enum taken {TAKEN, NOT_TAKEN, AROUND} status;
+  } path[PATHLENGTH];
+};
+
 /* Nonzero if X has the form (PLUS frame-pointer integer).  We check for
    virtual regs here because the simplify_*_operation routines are called
    by integrate.c, which is called before virtual register instantiation.  */
@@ -547,26 +584,63 @@ struct write_data
           || XEXP (X, 0) == virtual_stack_dynamic_rtx          \
           || XEXP (X, 0) == virtual_outgoing_args_rtx)))
 
-static struct table_elt *lookup ();
-static void free_element ();
-
-static int insert_regs ();
-static void rehash_using_reg ();
-static void remove_invalid_refs ();
-static int exp_equiv_p ();
-int refers_to_p ();
-int refers_to_mem_p ();
-static void invalidate_from_clobbers ();
-static int safe_hash ();
-static int canon_hash ();
-static rtx fold_rtx ();
-static rtx equiv_constant ();
-static void record_jump_cond ();
-static void note_mem_written ();
-static int cse_rtx_addr_varies_p ();
-static enum rtx_code find_comparison_args ();
-static void cse_insn ();
-static void cse_set_around_loop ();
+static void new_basic_block    PROTO((void));
+static void make_new_qty       PROTO((int));
+static void make_regs_eqv      PROTO((int, int));
+static void delete_reg_equiv   PROTO((int));
+static int mention_regs                PROTO((rtx));
+static int insert_regs         PROTO((rtx, struct table_elt *, int));
+static void free_element       PROTO((struct table_elt *));
+static void remove_from_table  PROTO((struct table_elt *, int));
+static struct table_elt *get_element PROTO((void));
+static struct table_elt *lookup        PROTO((rtx, int, enum machine_mode)),
+       *lookup_for_remove PROTO((rtx, int, enum machine_mode));
+static rtx lookup_as_function  PROTO((rtx, enum rtx_code));
+static struct table_elt *insert PROTO((rtx, struct table_elt *, int,
+                                      enum machine_mode));
+static void merge_equiv_classes PROTO((struct table_elt *,
+                                      struct table_elt *));
+static void invalidate         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_for_call        PROTO((void));
+static rtx use_related_value   PROTO((rtx, struct table_elt *));
+static int canon_hash          PROTO((rtx, enum machine_mode));
+static int safe_hash           PROTO((rtx, enum machine_mode));
+static int exp_equiv_p         PROTO((rtx, rtx, int, int));
+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 *,
+                                                enum machine_mode *,
+                                                enum machine_mode *));
+static rtx cse_gen_binary      PROTO((enum rtx_code, enum machine_mode,
+                                      rtx, rtx));
+static rtx simplify_plus_minus PROTO((enum rtx_code, enum machine_mode,
+                                      rtx, rtx));
+static rtx fold_rtx            PROTO((rtx, rtx));
+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 note_mem_written   PROTO((rtx, struct write_data *));
+static void invalidate_from_clobbers PROTO((struct write_data *, rtx));
+static rtx cse_process_notes   PROTO((rtx, rtx));
+static void cse_around_loop    PROTO((rtx));
+static void invalidate_skipped_set PROTO((rtx, rtx));
+static void invalidate_skipped_block PROTO((rtx));
+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 *, int));
 \f
 /* 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.
@@ -630,7 +704,8 @@ rtx_cost (x, outer_code)
   switch (code)
     {
     case REG:
-      return 1;
+      return ! CHEAP_REG (REGNO (x));
+
     case SUBREG:
       /* If we can't tie these modes, make this expensive.  The larger
         the mode, the more expensive it is.  */
@@ -863,7 +938,7 @@ mention_regs (x)
     {
       if (GET_CODE (XEXP (x, 0)) == REG
          && ! REGNO_QTY_VALID_P (REGNO (XEXP (x, 0))))
-       if (insert_regs (XEXP (x, 0), 0, 0))
+       if (insert_regs (XEXP (x, 0), NULL_PTR, 0))
          {
            rehash_using_reg (XEXP (x, 0));
            changed = 1;
@@ -871,7 +946,7 @@ mention_regs (x)
 
       if (GET_CODE (XEXP (x, 1)) == REG
          && ! REGNO_QTY_VALID_P (REGNO (XEXP (x, 1))))
-       if (insert_regs (XEXP (x, 1), 0, 0))
+       if (insert_regs (XEXP (x, 1), NULL_PTR, 0))
          {
            rehash_using_reg (XEXP (x, 1));
            changed = 1;
@@ -909,9 +984,14 @@ insert_regs (x, classp, modified)
     {
       register int regno = REGNO (x);
 
-      if (modified
-         || ! (REGNO_QTY_VALID_P (regno)
-               && qty_mode[reg_qty[regno]] == GET_MODE (x)))
+      /* If REGNO is in the equivalence table already but is of the
+        wrong mode for that equivalence, don't do anything here.  */
+
+      if (REGNO_QTY_VALID_P (regno)
+         && qty_mode[reg_qty[regno]] != GET_MODE (x))
+       return 0;
+
+      if (modified || ! REGNO_QTY_VALID_P (regno))
        {
          if (classp)
            for (classp = classp->first_same_value;
@@ -939,7 +1019,7 @@ insert_regs (x, classp, modified)
   else if (GET_CODE (x) == SUBREG && GET_CODE (SUBREG_REG (x)) == REG
           && ! REGNO_QTY_VALID_P (REGNO (SUBREG_REG (x))))
     {
-      insert_regs (SUBREG_REG (x), 0, 0);
+      insert_regs (SUBREG_REG (x), NULL_PTR, 0);
       mention_regs (SUBREG_REG (x));
       return 1;
     }
@@ -1297,7 +1377,7 @@ insert (x, classp, hash, mode)
          subhash = safe_hash (subexp, mode) % NBUCKETS;
          subelt = lookup (subexp, subhash, mode);
          if (subelt == 0)
-           subelt = insert (subexp, 0, subhash, mode);
+           subelt = insert (subexp, NULL_PTR, subhash, mode);
          /* Initialize SUBELT's circular chain if it has none.  */
          if (subelt->related_value == 0)
            subelt->related_value = subelt;
@@ -1386,8 +1466,8 @@ invalidate (x)
 {
   register int i;
   register struct table_elt *p;
-  register rtx base;
-  register int start, end;
+  rtx base;
+  HOST_WIDE_INT start, end;
 
   /* If X is a register, dependencies on its contents
      are recorded through the qty number mechanism.
@@ -1416,7 +1496,8 @@ invalidate (x)
        remove_from_table (lookup_for_remove (x, hash, GET_MODE (x)), hash);
       else
        {
-         int in_table = TEST_HARD_REG_BIT (hard_regs_in_table, regno);
+         HOST_WIDE_INT in_table
+           = TEST_HARD_REG_BIT (hard_regs_in_table, regno);
          int endregno = regno + HARD_REGNO_NREGS (regno, GET_MODE (x));
          int tregno, tendregno;
          register struct table_elt *p, *next;
@@ -1466,38 +1547,10 @@ invalidate (x)
 
   if (GET_CODE (x) != MEM)
     abort ();
-  base = XEXP (x, 0);
-  start = 0;
 
-  /* Registers with nonvarying addresses usually have constant equivalents;
-     but the frame pointer register is also possible.  */
-  if (GET_CODE (base) == REG
-      && 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)]];
-  else if (GET_CODE (base) == PLUS
-          && GET_CODE (XEXP (base, 1)) == CONST_INT
-          && GET_CODE (XEXP (base, 0)) == REG
-          && REGNO_QTY_VALID_P (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))]])
-    {
-      start = INTVAL (XEXP (base, 1));
-      base = qty_const[reg_qty[REGNO (XEXP (base, 0))]];
-    }
-
-  if (GET_CODE (base) == CONST)
-    base = XEXP (base, 0);
-  if (GET_CODE (base) == PLUS
-      && GET_CODE (XEXP (base, 1)) == CONST_INT)
-    {
-      start += INTVAL (XEXP (base, 1));
-      base = XEXP (base, 0);
-    }
+  set_nonvarying_address_components (XEXP (x, 0), GET_MODE_SIZE (GET_MODE (x)),
+                                    &base, &start, &end);
 
-  end = start + GET_MODE_SIZE (GET_MODE (x));
   for (i = 0; i < NBUCKETS; i++)
     {
       register struct table_elt *next;
@@ -1527,7 +1580,7 @@ remove_invalid_refs (regno)
       {
        next = p->next_same_hash;
        if (GET_CODE (p->exp) != REG
-           && refers_to_regno_p (regno, regno + 1, p->exp, 0))
+           && refers_to_regno_p (regno, regno + 1, p->exp, NULL_PTR))
          remove_from_table (p, i);
       }
 }
@@ -1675,7 +1728,7 @@ use_related_value (x, elt)
 {
   register struct table_elt *relt = 0;
   register struct table_elt *p, *q;
-  int offset;
+  HOST_WIDE_INT offset;
 
   /* First, is there anything related known?
      If we have a table element, we can tell from that.
@@ -1817,12 +1870,12 @@ canon_hash (x, mode)
       /* Assume there is only one rtx object for any given label.  */
     case LABEL_REF:
       /* Use `and' to ensure a positive number.  */
-      return (hash + ((int) LABEL_REF << 7)
-             + ((int) XEXP (x, 0) & ((1 << HASHBITS) - 1)));
+      return (hash + ((HOST_WIDE_INT) LABEL_REF << 7)
+             + ((HOST_WIDE_INT) XEXP (x, 0) & ((1 << HASHBITS) - 1)));
 
     case SYMBOL_REF:
-      return (hash + ((int) SYMBOL_REF << 7)
-             + ((int) XEXP (x, 0) & ((1 << HASHBITS) - 1)));
+      return (hash + ((HOST_WIDE_INT) SYMBOL_REF << 7)
+             + ((HOST_WIDE_INT) XEXP (x, 0) & ((1 << HASHBITS) - 1)));
 
     case MEM:
       if (MEM_VOLATILE_P (x))
@@ -1952,7 +2005,7 @@ exp_equiv_p (x, y, validate, equal_values)
      int validate;
      int equal_values;
 {
-  register int i;
+  register int i, j;
   register enum rtx_code code;
   register char *fmt;
 
@@ -1998,7 +2051,7 @@ exp_equiv_p (x, y, validate, equal_values)
       return x == y;
 
     case CONST_INT:
-      return XINT (x, 0) == XINT (y, 0);
+      return INTVAL (x) == INTVAL (y);
 
     case LABEL_REF:
     case SYMBOL_REF:
@@ -2052,34 +2105,45 @@ exp_equiv_p (x, y, validate, equal_values)
   fmt = GET_RTX_FORMAT (code);
   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
     {
-      if (fmt[i] == 'e')
+      switch (fmt[i])
        {
+       case 'e':
          if (! exp_equiv_p (XEXP (x, i), XEXP (y, i), validate, equal_values))
            return 0;
-       }
-      else if (fmt[i] == 'E')
-       {
-         int j;
+         break;
+
+       case 'E':
          if (XVECLEN (x, i) != XVECLEN (y, i))
            return 0;
          for (j = 0; j < XVECLEN (x, i); j++)
            if (! exp_equiv_p (XVECEXP (x, i, j), XVECEXP (y, i, j),
                               validate, equal_values))
              return 0;
-       }
-      else if (fmt[i] == 's')
-       {
+         break;
+
+       case 's':
          if (strcmp (XSTR (x, i), XSTR (y, i)))
            return 0;
-       }
-      else if (fmt[i] == 'i')
-       {
+         break;
+
+       case 'i':
          if (XINT (x, i) != XINT (y, i))
            return 0;
+         break;
+
+       case 'w':
+         if (XWINT (x, i) != XWINT (y, i))
+           return 0;
+       break;
+
+       case '0':
+         break;
+
+       default:
+         abort ();
        }
-      else if (fmt[i] != '0')
-       abort ();
-    }
+      }
+
   return 1;
 }
 \f
@@ -2087,7 +2151,7 @@ exp_equiv_p (x, y, validate, equal_values)
    Here we do not require that X or Y be valid (for registers referred to)
    for being in the hash table.  */
 
-int
+static int
 refers_to_p (x, y)
      rtx x, y;
 {
@@ -2136,25 +2200,92 @@ refers_to_p (x, y)
   return 0;
 }
 \f
+/* Given ADDR and SIZE (a memory address, and the size of the memory reference),
+   set PBASE, PSTART, and PEND which correspond to the base of the address,
+   the starting offset, and ending offset respectively.
+
+   ADDR is known to be a nonvarying address. 
+
+   cse_address_varies_p returns zero for nonvarying addresses.  */
+
+static void
+set_nonvarying_address_components (addr, size, pbase, pstart, pend)
+     rtx addr;
+     int size;
+     rtx *pbase;
+     HOST_WIDE_INT *pstart, *pend;
+{
+  rtx base;
+  int start, end;
+
+  base = addr;
+  start = 0;
+  end = 0;
+
+  /* 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)]];
+  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))]]
+              == GET_MODE (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))]];
+    }
+
+  /* By definition, operand1 of a LO_SUM is the associated constant
+     address.  Use the associated constant address as the base instead.  */
+  if (GET_CODE (base) == LO_SUM)
+    base = XEXP (base, 1);
+
+  /* Strip off CONST.  */
+  if (GET_CODE (base) == CONST)
+    base = XEXP (base, 0);
+
+  if (GET_CODE (base) == PLUS
+      && GET_CODE (XEXP (base, 1)) == CONST_INT)
+    {
+      start += INTVAL (XEXP (base, 1));
+      base = XEXP (base, 0);
+    }
+
+  end = start + size;
+
+  /* Set the return values.  */
+  *pbase = base;
+  *pstart = start;
+  *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.
-   This function is not used in such cases.
+   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.  */
 
-int
+static int
 refers_to_mem_p (x, base, start, end)
      rtx x, base;
-     int start, end;
+     HOST_WIDE_INT start, end;
 {
-  register int i;
+  register HOST_WIDE_INT i;
   register enum rtx_code code;
   register char *fmt;
 
@@ -2173,83 +2304,20 @@ refers_to_mem_p (x, base, start, end)
   if (code == MEM)
     {
       register rtx addr = XEXP (x, 0); /* Get the address.  */
-      int myend;
-
-      i = 0;
-      if (GET_CODE (addr) == REG
-         /* qty_const is 0 when outside the cse pass;
-            at such times, this info is not available.  */
-         && qty_const != 0
-         && 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)]];
-      else if (GET_CODE (addr) == PLUS
-              && GET_CODE (XEXP (addr, 1)) == CONST_INT
-              && GET_CODE (XEXP (addr, 0)) == REG
-              && qty_const != 0
-              && REGNO_QTY_VALID_P (REGNO (XEXP (addr, 0)))
-              && (GET_MODE (XEXP (addr, 0))
-                  == qty_mode[reg_qty[REGNO (XEXP (addr, 0))]])
-              && qty_const[reg_qty[REGNO (XEXP (addr, 0))]])
-       {
-         i = INTVAL (XEXP (addr, 1));
-         addr = qty_const[reg_qty[REGNO (XEXP (addr, 0))]];
-       }
+      rtx mybase;
+      HOST_WIDE_INT mystart, myend;
 
-    check_addr:
-      if (GET_CODE (addr) == CONST)
-       addr = XEXP (addr, 0);
-
-      /* If ADDR is BASE, or BASE plus an integer, put
-        the integer in I.  */
-      if (GET_CODE (addr) == PLUS
-         && XEXP (addr, 0) == base
-         && GET_CODE (XEXP (addr, 1)) == CONST_INT)
-       i += INTVAL (XEXP (addr, 1));
-      else if (GET_CODE (addr) == LO_SUM)
-       {
-         if (GET_CODE (base) != LO_SUM)
-           return 1;
-         /* The REG component of the LO_SUM is known by the
-            const value in the XEXP part.  */
-         addr = XEXP (addr, 1);
-         base = XEXP (base, 1);
-         i = 0;
-         if (GET_CODE (base) == CONST)
-           base = XEXP (base, 0);
-         if (GET_CODE (base) == PLUS
-             && GET_CODE (XEXP (base, 1)) == CONST_INT)
-           {
-             int tem = INTVAL (XEXP (base, 1));
-             start += tem;
-             end += tem;
-             base = XEXP (base, 0);
-           }
-         goto check_addr;
-       }
-      else if (GET_CODE (base) == LO_SUM)
-       {
-         base = XEXP (base, 1);
-         if (GET_CODE (base) == CONST)
-           base = XEXP (base, 0);
-         if (GET_CODE (base) == PLUS
-             && GET_CODE (XEXP (base, 1)) == CONST_INT)
-           {
-             int tem = INTVAL (XEXP (base, 1));
-             start += tem;
-             end += tem;
-             base = XEXP (base, 0);
-           }
-         goto check_addr;        
-       }
-      else if (GET_CODE (addr) == CONST_INT && base == const0_rtx)
-       i = INTVAL (addr);
-      else if (addr != base)
+      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;
 
-      myend = i + GET_MODE_SIZE (GET_MODE (x));
-      return myend > start && i < end;
+      return myend > start && mystart < end;
     }
 
   /* X does not match, so try its subexpressions.  */
@@ -2315,8 +2383,11 @@ cse_rtx_addr_varies_p (x)
    with the "oldest" equivalent register.
 
    If INSN is non-zero and we are replacing a pseudo with a hard register
-   or vice versa, verify that INSN remains valid after we make our
-   substitution.  */
+   or vice versa, validate_change is used to ensure that INSN remains valid
+   after we make our substitution.  The calls are made with IN_GROUP non-zero
+   so apply_change_group must be called upon the outermost return from this
+   function (unless INSN is zero).  The result of apply_change_group can
+   generally be discarded since the changes we are making are optional.  */
 
 static rtx
 canon_reg (x, insn)
@@ -2375,10 +2446,11 @@ canon_reg (x, insn)
 
          /* If replacing pseudo with hard reg or vice versa, ensure the
             insn remains valid.  Likewise if the insn has MATCH_DUPs.  */
-         if (new && GET_CODE (new) == REG && GET_CODE (XEXP (x, i)) == REG
+         if (insn != 0 && new != 0
+             && GET_CODE (new) == REG && GET_CODE (XEXP (x, i)) == REG
              && (((REGNO (new) < FIRST_PSEUDO_REGISTER)
                   != (REGNO (XEXP (x, i)) < FIRST_PSEUDO_REGISTER))
-                 || (insn != 0 && insn_n_dups[recog_memoized (insn)] > 0)))
+                 || insn_n_dups[recog_memoized (insn)] > 0))
            validate_change (insn, &XEXP (x, i), new, 1);
          else
            XEXP (x, i) = new;
@@ -2407,7 +2479,7 @@ canon_reg (x, insn)
    than hard registers here because we would also prefer the pseudo registers.
   */
 
-void
+static void
 find_best_addr (insn, loc)
      rtx insn;
      rtx *loc;
@@ -2451,8 +2523,9 @@ find_best_addr (insn, loc)
       && validate_change (insn, loc, fold_rtx (addr, insn), 0))
     addr = *loc;
        
-  /* If this address is not in the hash table, we can't do any better.
-     Also, ignore if volatile.  */
+  /* If this address is not in the hash table, we can't look for equivalences
+     of the whole address.  Also, ignore if volatile.  */
+
   do_not_record = 0;
   hash_code = HASH (addr, Pmode);
   addr_volatile = do_not_record;
@@ -2465,56 +2538,136 @@ find_best_addr (insn, loc)
 
   elt = lookup (addr, hash_code, Pmode);
 
-  if (elt == 0)
-    return;
-
 #ifndef ADDRESS_COST
-  our_cost = elt->cost;
-
-  /* Find the lowest cost below ours that works.  */
-  for (elt = elt->first_same_value; elt; elt = elt->next_same_value)
-    if (elt->cost < our_cost
-       && (GET_CODE (elt->exp) == REG || exp_equiv_p (elt->exp, elt->exp, 1, 0))
-       && validate_change (insn, loc, canon_reg (copy_rtx (elt->exp), 0), 0))
-      return;
+  if (elt)
+    {
+      our_cost = elt->cost;
 
+      /* Find the lowest cost below ours that works.  */
+      for (elt = elt->first_same_value; elt; elt = elt->next_same_value)
+       if (elt->cost < our_cost
+           && (GET_CODE (elt->exp) == REG
+               || exp_equiv_p (elt->exp, elt->exp, 1, 0))
+           && validate_change (insn, loc,
+                               canon_reg (copy_rtx (elt->exp), NULL_RTX), 0))
+         return;
+    }
 #else
 
-  /* We need to find the best (under the criteria documented above) entry in
-     the class that is valid.  We use the `flag' field to indicate choices
-     that were invalid and iterate until we can't find a better one that
-     hasn't already been tried.  */
+  if (elt)
+    {
+      /* We need to find the best (under the criteria documented above) entry
+        in the class that is valid.  We use the `flag' field to indicate
+        choices that were invalid and iterate until we can't find a better
+        one that hasn't already been tried.  */
+
+      for (p = elt->first_same_value; p; p = p->next_same_value)
+       p->flag = 0;
+
+      while (found_better)
+       {
+         int best_addr_cost = 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)))
+             {
+               found_better = 1;
+               best_addr_cost = ADDRESS_COST (p->exp);
+               best_rtx_cost = (p->cost + 1) >> 1;
+               best_elt = p;
+             }
 
-  for (p = elt->first_same_value; p; p = p->next_same_value)
-    p->flag = 0;
+         if (found_better)
+           {
+             if (validate_change (insn, loc,
+                                  canon_reg (copy_rtx (best_elt->exp),
+                                             NULL_RTX), 0))
+               return;
+             else
+               best_elt->flag = 1;
+           }
+       }
+    }
 
-  while (found_better)
+  /* If the address is a binary operation with the first operand a register
+     and the second a constant, do the same as above, but looking for
+     equivalences of the register.  Then try to simplify before checking for
+     the best address to use.  This catches a few cases:  First is when we
+     have REG+const and the register is another REG+const.  We can often merge
+     the constants and eliminate one insn and one register.  It may also be
+     that a machine has a cheap REG+REG+const.  Finally, this improves the
+     code on the Alpha for unaligned byte stores.  */
+
+  if (flag_expensive_optimizations
+      && (GET_RTX_CLASS (GET_CODE (*loc)) == '2'
+         || GET_RTX_CLASS (GET_CODE (*loc)) == 'c')
+      && GET_CODE (XEXP (*loc, 0)) == REG
+      && GET_CODE (XEXP (*loc, 1)) == CONST_INT)
     {
-      int best_addr_cost = ADDRESS_COST (*loc);
-      int best_rtx_cost = (elt->cost + 1) >> 1;
-      struct table_elt *best_elt = elt; 
+      rtx c = XEXP (*loc, 1);
+
+      do_not_record = 0;
+      hash_code = HASH (XEXP (*loc, 0), Pmode);
+      do_not_record = save_do_not_record;
+      hash_arg_in_memory = save_hash_arg_in_memory;
+      hash_arg_in_struct = save_hash_arg_in_struct;
+
+      elt = lookup (XEXP (*loc, 0), hash_code, Pmode);
+      if (elt == 0)
+       return;
+
+      /* We need to find the best (under the criteria documented above) entry
+        in the class that is valid.  We use the `flag' field to indicate
+        choices that were invalid and iterate until we can't find a better
+        one that hasn't already been tried.  */
 
-      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)))
-         {
-           found_better = 1;
-           best_addr_cost = ADDRESS_COST (p->exp);
-           best_rtx_cost = (p->cost + 1) >> 1;
-           best_elt = p;
-         }
+       p->flag = 0;
 
-      if (found_better)
+      while (found_better)
        {
-         if (validate_change (insn, loc,
-                              canon_reg (copy_rtx (best_elt->exp), 0), 0))
-           return;
-         else
-           best_elt->flag = 1;
+         int best_addr_cost = ADDRESS_COST (*loc);
+         int best_rtx_cost = (COST (*loc) + 1) >> 1;
+         struct table_elt *best_elt = elt; 
+         rtx best_rtx = *loc;
+
+         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)))
+             {
+               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
+                       && (COST (new) + 1) >> 1 > best_rtx_cost)))
+                 {
+                   found_better = 1;
+                   best_addr_cost = ADDRESS_COST (new);
+                   best_rtx_cost = (COST (new) + 1) >> 1;
+                   best_elt = p;
+                   best_rtx = new;
+                 }
+             }
+
+         if (found_better)
+           {
+             if (validate_change (insn, loc,
+                                  canon_reg (copy_rtx (best_rtx),
+                                             NULL_RTX), 0))
+               return;
+             else
+               best_elt->flag = 1;
+           }
        }
     }
 #endif
@@ -2533,9 +2686,10 @@ find_best_addr (insn, loc)
    A or the code corresponding to the inverse of the comparison.  */
 
 static enum rtx_code
-find_comparison_args (code, parg1, parg2)
+find_comparison_args (code, parg1, parg2, pmode1, pmode2)
      enum rtx_code code;
      rtx *parg1, *parg2;
+     enum machine_mode *pmode1, *pmode2;
 {
   rtx arg1, arg2;
 
@@ -2543,7 +2697,7 @@ find_comparison_args (code, parg1, parg2)
 
   /* If ARG2 is const0_rtx, see what ARG1 is equivalent to.  */
 
-  while (arg2 == const0_rtx)
+  while (arg2 == CONST0_RTX (GET_MODE (arg1)))
     {
       /* Set non-zero when we find something of interest.  */
       rtx x = 0;
@@ -2615,9 +2769,11 @@ find_comparison_args (code, parg1, parg2)
              || ((code == NE
                   || (code == LT
                       && GET_MODE_CLASS (inner_mode) == MODE_INT
-                      && GET_MODE_BITSIZE (inner_mode) <= HOST_BITS_PER_INT
+                      && (GET_MODE_BITSIZE (inner_mode)
+                          <= HOST_BITS_PER_WIDE_INT)
                       && (STORE_FLAG_VALUE
-                          & (1 << (GET_MODE_BITSIZE (inner_mode) - 1))))
+                          & ((HOST_WIDE_INT) 1
+                             << (GET_MODE_BITSIZE (inner_mode) - 1))))
 #ifdef FLOAT_STORE_FLAG_VALUE
                   || (code == LT
                       && GET_MODE_CLASS (inner_mode) == MODE_FLOAT
@@ -2632,9 +2788,11 @@ find_comparison_args (code, parg1, parg2)
          else if ((code == EQ
                    || (code == GE
                        && GET_MODE_CLASS (inner_mode) == MODE_INT
-                       && GET_MODE_BITSIZE (inner_mode) <= HOST_BITS_PER_INT
+                       && (GET_MODE_BITSIZE (inner_mode)
+                           <= HOST_BITS_PER_WIDE_INT)
                        && (STORE_FLAG_VALUE
-                           & (1 << (GET_MODE_BITSIZE (inner_mode) - 1))))
+                           & ((HOST_WIDE_INT) 1
+                              << (GET_MODE_BITSIZE (inner_mode) - 1))))
 #ifdef FLOAT_STORE_FLAG_VALUE
                    || (code == GE
                        && GET_MODE_CLASS (inner_mode) == MODE_FLOAT
@@ -2670,7 +2828,9 @@ find_comparison_args (code, parg1, parg2)
        code = reverse_condition (code);
     }
 
-  /* Return our results.  */
+  /* Return our results.  Return the modes from before fold_rtx
+     because fold_rtx might produce const_int, and then it's too late.  */
+  *pmode1 = GET_MODE (arg1), *pmode2 = GET_MODE (arg2);
   *parg1 = fold_rtx (arg1, 0), *parg2 = fold_rtx (arg2, 0);
 
   return code;
@@ -2728,17 +2888,17 @@ simplify_unary_operation (code, mode, op, op_mode)
       if (CONST_DOUBLE_HIGH (op) < 0)
        {
          d = (double) (~ CONST_DOUBLE_HIGH (op));
-         d *= ((double) (1 << (HOST_BITS_PER_INT / 2))
-               * (double) (1 << (HOST_BITS_PER_INT / 2)));
-         d += (double) (unsigned) (~ CONST_DOUBLE_LOW (op));
+         d *= ((double) ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2))
+               * (double) ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2)));
+         d += (double) (unsigned HOST_WIDE_INT) (~ CONST_DOUBLE_LOW (op));
          d = (- d - 1.0);
        }
       else
        {
          d = (double) CONST_DOUBLE_HIGH (op);
-         d *= ((double) (1 << (HOST_BITS_PER_INT / 2))
-               * (double) (1 << (HOST_BITS_PER_INT / 2)));
-         d += (double) (unsigned) CONST_DOUBLE_LOW (op);
+         d *= ((double) ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2))
+               * (double) ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2)));
+         d += (double) (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (op);
        }
 #endif  /* REAL_ARITHMETIC */
       return CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
@@ -2753,19 +2913,19 @@ simplify_unary_operation (code, mode, op, op_mode)
                                    CONST_DOUBLE_HIGH (op));
 #else
       d = (double) CONST_DOUBLE_HIGH (op);
-      d *= ((double) (1 << (HOST_BITS_PER_INT / 2))
-           * (double) (1 << (HOST_BITS_PER_INT / 2)));
-      d += (double) (unsigned) CONST_DOUBLE_LOW (op);
+      d *= ((double) ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2))
+           * (double) ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2)));
+      d += (double) (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (op);
 #endif  /* REAL_ARITHMETIC */
       return CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
     }
 #endif
 
-  else if (GET_CODE (op) == CONST_INT
-          && width <= HOST_BITS_PER_INT && width > 0)
+  if (GET_CODE (op) == CONST_INT
+      && width <= HOST_BITS_PER_WIDE_INT && width > 0)
     {
-      register int arg0 = INTVAL (op);
-      register int val;
+      register HOST_WIDE_INT arg0 = INTVAL (op);
+      register HOST_WIDE_INT val;
 
       switch (code)
        {
@@ -2795,10 +2955,17 @@ simplify_unary_operation (code, mode, op, op_mode)
        case ZERO_EXTEND:
          if (op_mode == VOIDmode)
            op_mode = mode;
-         if (GET_MODE_BITSIZE (op_mode) == HOST_BITS_PER_INT)
-           val = arg0;
-         else if (GET_MODE_BITSIZE (op_mode) < HOST_BITS_PER_INT)
-           val = arg0 & ~((-1) << GET_MODE_BITSIZE (op_mode));
+         if (GET_MODE_BITSIZE (op_mode) == HOST_BITS_PER_WIDE_INT)
+           {
+             /* If we were really extending the mode,
+                we would have to distinguish between zero-extension
+                and sign-extension.  */
+             if (width != GET_MODE_BITSIZE (op_mode))
+               abort ();
+             val = arg0;
+           }
+         else if (GET_MODE_BITSIZE (op_mode) < HOST_BITS_PER_WIDE_INT)
+           val = arg0 & ~((HOST_WIDE_INT) (-1) << GET_MODE_BITSIZE (op_mode));
          else
            return 0;
          break;
@@ -2806,13 +2973,22 @@ simplify_unary_operation (code, mode, op, op_mode)
        case SIGN_EXTEND:
          if (op_mode == VOIDmode)
            op_mode = mode;
-         if (GET_MODE_BITSIZE (op_mode) == HOST_BITS_PER_INT)
-           val = arg0;
-         else if (GET_MODE_BITSIZE (op_mode) < HOST_BITS_PER_INT)
+         if (GET_MODE_BITSIZE (op_mode) == HOST_BITS_PER_WIDE_INT)
            {
-             val = arg0 & ~((-1) << GET_MODE_BITSIZE (op_mode));
-             if (val & (1 << (GET_MODE_BITSIZE (op_mode) - 1)))
-               val -= 1 << GET_MODE_BITSIZE (op_mode);
+             /* If we were really extending the mode,
+                we would have to distinguish between zero-extension
+                and sign-extension.  */
+             if (width != GET_MODE_BITSIZE (op_mode))
+               abort ();
+             val = arg0;
+           }
+         else if (GET_MODE_BITSIZE (op_mode) < HOST_BITS_PER_WIDE_INT)
+           {
+             val
+               = arg0 & ~((HOST_WIDE_INT) (-1) << GET_MODE_BITSIZE (op_mode));
+             if (val
+                 & ((HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (op_mode) - 1)))
+               val -= (HOST_WIDE_INT) 1 << GET_MODE_BITSIZE (op_mode);
            }
          else
            return 0;
@@ -2829,11 +3005,12 @@ simplify_unary_operation (code, mode, op, op_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_INT
-         && ((val & ((-1) << (width - 1))) != ((-1) << (width - 1))))
+      if (width < HOST_BITS_PER_WIDE_INT
+         && ((val & ((HOST_WIDE_INT) (-1) << (width - 1)))
+             != ((HOST_WIDE_INT) (-1) << (width - 1))))
        val &= (1 << width) - 1;
 
-      return gen_rtx (CONST_INT, VOIDmode, val);
+      return GEN_INT (val);
     }
 
   /* We can do some operations on integer CONST_DOUBLEs.  Also allow
@@ -2841,7 +3018,7 @@ simplify_unary_operation (code, mode, op, op_mode)
   else if (GET_MODE (op) == VOIDmode
           && (GET_CODE (op) == CONST_DOUBLE || GET_CODE (op) == CONST_INT))
     {
-      int l1, h1, lv, hv;
+      HOST_WIDE_INT l1, h1, lv, hv;
 
       if (GET_CODE (op) == CONST_DOUBLE)
        l1 = CONST_DOUBLE_LOW (op), h1 = CONST_DOUBLE_HIGH (op);
@@ -2869,18 +3046,43 @@ simplify_unary_operation (code, mode, op, op_mode)
        case FFS:
          hv = 0;
          if (l1 == 0)
-           lv = HOST_BITS_PER_INT + exact_log2 (h1 & (-h1)) + 1;
+           lv = HOST_BITS_PER_WIDE_INT + exact_log2 (h1 & (-h1)) + 1;
          else
            lv = exact_log2 (l1 & (-l1)) + 1;
          break;
 
        case TRUNCATE:
-         if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_INT)
-           return gen_rtx (CONST_INT, VOIDmode, l1 & GET_MODE_MASK (mode));
+         if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
+           return GEN_INT (l1 & GET_MODE_MASK (mode));
          else
            return 0;
          break;
 
+       case ZERO_EXTEND:
+         if (op_mode == VOIDmode
+             || GET_MODE_BITSIZE (op_mode) > HOST_BITS_PER_WIDE_INT)
+           return 0;
+
+         hv = 0;
+         lv = l1 & GET_MODE_MASK (op_mode);
+         break;
+
+       case SIGN_EXTEND:
+         if (op_mode == VOIDmode
+             || GET_MODE_BITSIZE (op_mode) > HOST_BITS_PER_WIDE_INT)
+           return 0;
+         else
+           {
+             lv = l1 & GET_MODE_MASK (op_mode);
+             if (GET_MODE_BITSIZE (op_mode) < HOST_BITS_PER_WIDE_INT
+                 && (lv & ((HOST_WIDE_INT) 1
+                           << (GET_MODE_BITSIZE (op_mode) - 1))) != 0)
+               lv -= (HOST_WIDE_INT) 1 << GET_MODE_BITSIZE (op_mode);
+
+             hv = (lv < 0) ? ~ (HOST_WIDE_INT) 0 : 0;
+           }
+         break;
+
        case SQRT:
          return 0;
 
@@ -2921,7 +3123,7 @@ simplify_unary_operation (code, mode, op, op_mode)
          break;
 
        case FLOAT_TRUNCATE:
-         d = (double) REAL_VALUE_TRUNCATE (mode, d);
+         d = real_value_truncate (mode, d);
          break;
 
        case FLOAT_EXTEND:
@@ -2929,11 +3131,11 @@ simplify_unary_operation (code, mode, op, op_mode)
          break;
 
        case FIX:
-         d = (double) REAL_VALUE_FIX_TRUNCATE (d);
+         d = REAL_VALUE_RNDZINT (d);
          break;
 
        case UNSIGNED_FIX:
-         d = (double) REAL_VALUE_UNSIGNED_FIX_TRUNCATE (d);
+         d = REAL_VALUE_UNSIGNED_RNDZINT (d);
          break;
 
        case SQRT:
@@ -2944,16 +3146,16 @@ simplify_unary_operation (code, mode, op, op_mode)
        }
 
       x = immed_real_const_1 (d, mode);
-      set_float_handler (0);
+      set_float_handler (NULL_PTR);
       return x;
     }
   else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE_CLASS (mode) == MODE_INT
-          && width <= HOST_BITS_PER_INT && width > 0)
+          && width <= HOST_BITS_PER_WIDE_INT && width > 0)
     {
       REAL_VALUE_TYPE d;
       jmp_buf handler;
       rtx x;
-      int val;
+      HOST_WIDE_INT val;
 
       if (setjmp (handler))
        return 0;
@@ -2976,17 +3178,18 @@ simplify_unary_operation (code, mode, op, op_mode)
          abort ();
        }
 
-      set_float_handler (0);
+      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_INT
-         && ((val & ((-1) << (width - 1))) != ((-1) << (width - 1))))
-       val &= (1 << width) - 1;
+      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;
 
-      return gen_rtx (CONST_INT, VOIDmode, val);
+      return GEN_INT (val);
     }
 #endif
   /* This was formerly used only for non-IEEE float.
@@ -3034,9 +3237,10 @@ simplify_binary_operation (code, mode, op0, op1)
      enum machine_mode mode;
      rtx op0, op1;
 {
-  register int arg0, arg1, arg0s, arg1s;
-  int val;
+  register HOST_WIDE_INT arg0, arg1, arg0s, arg1s;
+  HOST_WIDE_INT val;
   int width = GET_MODE_BITSIZE (mode);
+  rtx tem;
 
   /* Relational operations don't work here.  We must know the mode
      of the operands in order to do the comparison correctly.
@@ -3061,11 +3265,11 @@ simplify_binary_operation (code, mode, op0, op1)
 
       REAL_VALUE_FROM_CONST_DOUBLE (f0, op0);
       REAL_VALUE_FROM_CONST_DOUBLE (f1, op1);
-      f0 = REAL_VALUE_TRUNCATE (mode, f0);
-      f1 = REAL_VALUE_TRUNCATE (mode, f1);
+      f0 = real_value_truncate (mode, f0);
+      f1 = real_value_truncate (mode, f1);
 
 #ifdef REAL_ARITHMETIC
-      REAL_ARITHMETIC (value, code, f0, f1);
+      REAL_ARITHMETIC (value, rtx_to_tree_code (code), f0, f1);
 #else
       switch (code)
        {
@@ -3081,7 +3285,7 @@ simplify_binary_operation (code, mode, op0, op1)
        case DIV:
 #ifndef REAL_INFINITY
          if (f1 == 0)
-           abort ();
+           return 0;
 #endif
          value = f0 / f1;
          break;
@@ -3096,17 +3300,18 @@ simplify_binary_operation (code, mode, op0, op1)
        }
 #endif
 
-      set_float_handler (0);
-      value = REAL_VALUE_TRUNCATE (mode, value);
+      set_float_handler (NULL_PTR);
+      value = real_value_truncate (mode, value);
       return immed_real_const_1 (value, mode);
     }
+#endif  /* not REAL_IS_NOT_DOUBLE, or REAL_ARITHMETIC */
 
   /* We can fold some multi-word operations.  */
-  else if (GET_MODE_CLASS (mode) == MODE_INT
-          && GET_CODE (op0) == CONST_DOUBLE
-          && (GET_CODE (op1) == CONST_DOUBLE || GET_CODE (op1) == CONST_INT))
+  if (GET_MODE_CLASS (mode) == MODE_INT
+      && GET_CODE (op0) == CONST_DOUBLE
+      && (GET_CODE (op1) == CONST_DOUBLE || GET_CODE (op1) == CONST_INT))
     {
-      int l1, l2, h1, h2, lv, hv;
+      HOST_WIDE_INT l1, l2, h1, h2, lv, hv;
 
       l1 = CONST_DOUBLE_LOW (op0), h1 = CONST_DOUBLE_HIGH (op0);
 
@@ -3150,30 +3355,40 @@ simplify_binary_operation (code, mode, op0, op1)
          break;
 
        case SMIN:
-         if (h1 < h2 || (h1 == h2 && (unsigned) l1 < (unsigned) l2))
+         if (h1 < h2
+             || (h1 == h2
+                 && ((unsigned HOST_WIDE_INT) l1
+                     < (unsigned HOST_WIDE_INT) l2)))
            lv = l1, hv = h1;
          else
            lv = l2, hv = h2;
          break;
 
        case SMAX:
-         if (h1 > h2 || (h1 == h2 && (unsigned) l1 > (unsigned) l2))
+         if (h1 > h2
+             || (h1 == h2
+                 && ((unsigned HOST_WIDE_INT) l1
+                     > (unsigned HOST_WIDE_INT) l2)))
            lv = l1, hv = h1;
          else
            lv = l2, hv = h2;
          break;
 
        case UMIN:
-         if ((unsigned) h1 < (unsigned) h2
-             || (h1 == h2 && (unsigned) l1 < (unsigned) l2))
+         if ((unsigned HOST_WIDE_INT) h1 < (unsigned HOST_WIDE_INT) h2
+             || (h1 == h2
+                 && ((unsigned HOST_WIDE_INT) l1
+                     < (unsigned HOST_WIDE_INT) l2)))
            lv = l1, hv = h1;
          else
            lv = l2, hv = h2;
          break;
 
        case UMAX:
-         if ((unsigned) h1 > (unsigned) h2
-             || (h1 == h2 && (unsigned) l1 > (unsigned) l2))
+         if ((unsigned HOST_WIDE_INT) h1 > (unsigned HOST_WIDE_INT) h2
+             || (h1 == h2
+                 && ((unsigned HOST_WIDE_INT) l1
+                     > (unsigned HOST_WIDE_INT) l2)))
            lv = l1, hv = h1;
          else
            lv = l2, hv = h2;
@@ -3207,10 +3422,9 @@ simplify_binary_operation (code, mode, op0, op1)
 
       return immed_double_const (lv, hv, mode);
     }
-#endif  /* not REAL_IS_NOT_DOUBLE, or REAL_ARITHMETIC */
 
   if (GET_CODE (op0) != CONST_INT || GET_CODE (op1) != CONST_INT
-      || width > HOST_BITS_PER_INT || width == 0)
+      || width > HOST_BITS_PER_WIDE_INT || width == 0)
     {
       /* Even if we can't compute a constant result,
         there are some cases worth simplifying.  */
@@ -3227,79 +3441,33 @@ simplify_binary_operation (code, mode, op0, op1)
          if (op1 == CONST0_RTX (mode))
            return op0;
 
-         /* Strip off any surrounding CONSTs.  They don't matter in any of 
-            the cases below.  */
-         if (GET_CODE (op0) == CONST)
-           op0 = XEXP (op0, 0);
-         if (GET_CODE (op1) == CONST)
-           op1 = XEXP (op1, 0);
-
          /* ((-a) + b) -> (b - a) and similarly for (a + (-b)) */
          if (GET_CODE (op0) == NEG)
-           {
-             rtx tem = simplify_binary_operation (MINUS, mode,
-                                                  op1, XEXP (op0, 0));
-             return tem ? tem : gen_rtx (MINUS, mode, op1, XEXP (op0, 0));
-           }
+           return cse_gen_binary (MINUS, mode, op1, XEXP (op0, 0));
          else if (GET_CODE (op1) == NEG)
-           {
-             rtx tem = simplify_binary_operation (MINUS, mode,
-                                                  op0, XEXP (op1, 0));
-             return tem ? tem : gen_rtx (MINUS, mode, op0, XEXP (op1, 0));
-           }
+           return cse_gen_binary (MINUS, mode, op0, XEXP (op1, 0));
 
-         /* Don't use the associative law for floating point.
-            The inaccuracy makes it nonassociative,
-            and subtle programs can break if operations are associated.  */
-         if (GET_MODE_CLASS (mode) != MODE_INT)
-           break;
+         /* Handle both-operands-constant cases.  We can only add
+            CONST_INTs to constants since the sum of relocatable symbols
+            can't be handled by most assemblers.  */
 
-         /* (a - b) + b -> a, similarly a + (b - a) -> a */
-         if (GET_CODE (op0) == MINUS
-             && rtx_equal_p (XEXP (op0, 1), op1) && ! side_effects_p (op1))
-           return XEXP (op0, 0);
-
-         if (GET_CODE (op1) == MINUS
-             && rtx_equal_p (XEXP (op1, 1), op0) && ! side_effects_p (op0))
-           return XEXP (op1, 0);
-
-         /* (c1 - a) + c2 becomes (c1 + c2) - a.  */
-         if (GET_CODE (op1) == CONST_INT && GET_CODE (op0) == MINUS
-             && GET_CODE (XEXP (op0, 0)) == CONST_INT)
-           {
-             rtx tem = simplify_binary_operation (PLUS, mode, op1,
-                                                  XEXP (op0, 0));
+         if (CONSTANT_P (op0) && GET_CODE (op1) == CONST_INT)
+           return plus_constant (op0, INTVAL (op1));
+         else if (CONSTANT_P (op1) && GET_CODE (op0) == CONST_INT)
+           return plus_constant (op1, INTVAL (op0));
 
-             return tem ? gen_rtx (MINUS, mode, tem, XEXP (op0, 1)) : 0;
-           }
+         /* If one of the operands is a PLUS or a MINUS, see if we can
+            simplify this by the associative law. 
+            Don't use the associative law for floating point.
+            The inaccuracy makes it nonassociative,
+            and subtle programs can break if operations are associated.  */
 
-         /* Handle both-operands-constant cases.  */
-         if (CONSTANT_P (op0) && CONSTANT_P (op1)
-             && GET_CODE (op0) != CONST_DOUBLE
-             && GET_CODE (op1) != CONST_DOUBLE
-             && GET_MODE_CLASS (mode) == MODE_INT)
-           {
-             if (GET_CODE (op1) == CONST_INT)
-               return plus_constant (op0, INTVAL (op1));
-             else if (GET_CODE (op0) == CONST_INT)
-               return plus_constant (op1, INTVAL (op0));
-             else
-               return gen_rtx (CONST, mode,
-                               gen_rtx (PLUS, mode,
-                                        GET_CODE (op0) == CONST
-                                        ? XEXP (op0, 0) : op0,
-                                        GET_CODE (op1) == CONST
-                                        ? XEXP (op1, 0) : op1));
-           }
-         else if (GET_CODE (op1) == CONST_INT
-                  && GET_CODE (op0) == PLUS
-                  && (CONSTANT_P (XEXP (op0, 0))
-                      || CONSTANT_P (XEXP (op0, 1))))
-           /* constant + (variable + constant)
-              can result if an index register is made constant.
-              We simplify this by adding the constants.
-              If we did not, it would become an invalid address.  */
-           return plus_constant (op0, INTVAL (op1));
+         if ((GET_MODE_CLASS (mode) == MODE_INT
+              || GET_MODE_CLASS (mode) == MODE_PARTIAL_INT)
+             && (GET_CODE (op0) == PLUS || GET_CODE (op0) == MINUS
+                 || GET_CODE (op1) == PLUS || GET_CODE (op1) == MINUS)
+             && (tem = simplify_plus_minus (code, mode, op0, op1)) != 0)
+           return tem;
          break;
 
        case COMPARE:
@@ -3323,159 +3491,45 @@ simplify_binary_operation (code, mode, op0, op1)
          /* None of these optimizations can be done for IEEE
             floating point.  */
          if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
-             && GET_MODE_CLASS (mode) != MODE_INT)
+             && GET_MODE_CLASS (mode) != MODE_INT
+             && GET_MODE_CLASS (mode) != MODE_PARTIAL_INT)
            break;
 
          /* We can't assume x-x is 0 even with non-IEEE floating point.  */
          if (rtx_equal_p (op0, op1)
              && ! side_effects_p (op0)
-             && GET_MODE_CLASS (mode) != MODE_FLOAT)
+             && GET_MODE_CLASS (mode) != MODE_FLOAT
+             && GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT)
            return const0_rtx;
 
          /* Change subtraction from zero into negation.  */
          if (op0 == CONST0_RTX (mode))
            return gen_rtx (NEG, mode, op1);
 
+         /* (-1 - a) is ~a.  */
+         if (op0 == constm1_rtx)
+           return gen_rtx (NOT, mode, op1);
+
          /* Subtracting 0 has no effect.  */
          if (op1 == CONST0_RTX (mode))
            return op0;
 
-         /* Strip off any surrounding CONSTs.  They don't matter in any of 
-            the cases below.  */
-         if (GET_CODE (op0) == CONST)
-           op0 = XEXP (op0, 0);
-         if (GET_CODE (op1) == CONST)
-           op1 = XEXP (op1, 0);
-
          /* (a - (-b)) -> (a + b).  */
          if (GET_CODE (op1) == NEG)
-           {
-             rtx tem = simplify_binary_operation (PLUS, mode,
-                                                  op0, XEXP (op1, 0));
-             return tem ? tem : gen_rtx (PLUS, mode, op0, XEXP (op1, 0));
-           }
+           return cse_gen_binary (PLUS, mode, op0, XEXP (op1, 0));
 
-         /* Don't use the associative law for floating point.
+         /* If one of the operands is a PLUS or a MINUS, see if we can
+            simplify this by the associative law. 
+            Don't use the associative law for floating point.
             The inaccuracy makes it nonassociative,
             and subtle programs can break if operations are associated.  */
-         if (GET_MODE_CLASS (mode) != MODE_INT)
-           break;
-
-         /* (a + b) - a -> b, and (b - (a + b))  -> -a  */
-         if (GET_CODE (op0) == PLUS
-             && rtx_equal_p (XEXP (op0, 0), op1)
-             && ! side_effects_p (op1))
-           return XEXP (op0, 1);
-         else if (GET_CODE (op0) == PLUS
-                  && rtx_equal_p (XEXP (op0, 1), op1)
-                  && ! side_effects_p (op1))
-           return XEXP (op0, 0);
-
-         if (GET_CODE (op1) == PLUS
-             && rtx_equal_p (XEXP (op1, 0), op0)
-             && ! side_effects_p (op0))
-           {
-             rtx tem = simplify_unary_operation (NEG, mode, XEXP (op1, 1),
-                                                 mode);
-
-             return tem ? tem : gen_rtx (NEG, mode, XEXP (op1, 1));
-           }
-         else if (GET_CODE (op1) == PLUS
-                  && rtx_equal_p (XEXP (op1, 1), op0)
-                  && ! side_effects_p (op0))
-           {
-             rtx tem = simplify_unary_operation (NEG, mode, XEXP (op1, 0),
-                                                 mode);
 
-             return tem ? tem : gen_rtx (NEG, mode, XEXP (op1, 0));
-           }
-
-         /* a - (a - b) -> b */
-         if (GET_CODE (op1) == MINUS && rtx_equal_p (op0, XEXP (op1, 0))
-             && ! side_effects_p (op0))
-           return XEXP (op1, 1);
-
-         /* (a +/- b) - (a +/- c) can be simplified.  Do variants of
-            this involving commutativity.  The most common case is
-            (a + C1) - (a + C2), but it's not hard to do all the cases.  */
-         if ((GET_CODE (op0) == PLUS || GET_CODE (op0) == MINUS)
-             && (GET_CODE (op1) == PLUS || GET_CODE (op1) == MINUS))
-           {
-             rtx lhs0 = XEXP (op0, 0), lhs1 = XEXP (op0, 1);
-             rtx rhs0 = XEXP (op1, 0), rhs1 = XEXP (op1, 1);
-             int lhs_neg = GET_CODE (op0) == MINUS;
-             int rhs_neg = GET_CODE (op1) == MINUS;
-             rtx lhs = 0, rhs = 0;
-
-             /* Set LHS and RHS to the two different terms.  */
-             if (rtx_equal_p (lhs0, rhs0) && ! side_effects_p (lhs0))
-               lhs = lhs1, rhs = rhs1;
-             else if (! rhs_neg && rtx_equal_p (lhs0, rhs1)
-                      && ! side_effects_p (lhs0))
-               lhs = lhs1, rhs = rhs0;
-             else if (! lhs_neg && rtx_equal_p (lhs1, rhs0)
-                      && ! side_effects_p (lhs1))
-               lhs = lhs0, rhs = rhs1;
-             else if (! lhs_neg && ! rhs_neg && rtx_equal_p (lhs1, rhs1)
-                      && ! side_effects_p (lhs1))
-               lhs = lhs0, rhs = rhs0;
-
-             /* The RHS is the operand of a MINUS, so its negation
-                status should be complemented.  */
-             rhs_neg = ! rhs_neg;
-
-             /* If we found two values equal, form the sum or difference
-                of the remaining two terms.   */
-             if (lhs)
-               {
-                 rtx tem = simplify_binary_operation (lhs_neg == rhs_neg
-                                                      ? PLUS : MINUS,
-                                                      mode,
-                                                      lhs_neg ? rhs : lhs,
-                                                      lhs_neg ? lhs : rhs);
-                 if (tem == 0)
-                   tem = gen_rtx (lhs_neg == rhs_neg
-                                  ? PLUS : MINUS,
-                                  mode, lhs_neg ? rhs : lhs,
-                                  lhs_neg ? lhs : rhs);
-
-                 /* If both sides negated, negate result.  */
-                 if (lhs_neg && rhs_neg)
-                   {
-                     rtx tem1
-                       = simplify_unary_operation (NEG, mode, tem, mode);
-                     if (tem1 == 0)
-                       tem1 = gen_rtx (NEG, mode, tem);
-                     tem = tem1;
-                   }
-
-                 return tem;
-               }
-
-             return 0;
-           }
-
-         /* c1 - (a + c2) becomes (c1 - c2) - a.  */
-         if (GET_CODE (op0) == CONST_INT && GET_CODE (op1) == PLUS
-             && GET_CODE (XEXP (op1, 1)) == CONST_INT)
-           {
-             rtx tem = simplify_binary_operation (MINUS, mode, op0,
-                                                  XEXP (op1, 1));
-
-             return tem ? gen_rtx (MINUS, mode, tem, XEXP (op1, 0)) : 0;
-           }
-
-         /* c1 - (c2 - a) becomes (c1 - c2) + a.  */
-         if (GET_CODE (op0) == CONST_INT && GET_CODE (op1) == MINUS
-             && GET_CODE (XEXP (op1, 0)) == CONST_INT)
-           {
-             rtx tem = simplify_binary_operation (MINUS, mode, op0,
-                                                  XEXP (op1, 0));
-
-             return (tem && GET_CODE (tem) == CONST_INT
-                     ? plus_constant (XEXP (op1, 1), INTVAL (tem))
-                     : 0);
-           }
+         if ((GET_MODE_CLASS (mode) == MODE_INT
+              || GET_MODE_CLASS (mode) == MODE_PARTIAL_INT)
+             && (GET_CODE (op0) == PLUS || GET_CODE (op0) == MINUS
+                 || GET_CODE (op1) == PLUS || GET_CODE (op1) == MINUS)
+             && (tem = simplify_plus_minus (code, mode, op0, op1)) != 0)
+           return tem;
 
          /* Don't let a relocatable value get a negative coeff.  */
          if (GET_CODE (op1) == CONST_INT)
@@ -3485,7 +3539,7 @@ simplify_binary_operation (code, mode, op0, op1)
        case MULT:
          if (op1 == constm1_rtx)
            {
-             rtx tem = simplify_unary_operation (NEG, mode, op0, mode);
+             tem = simplify_unary_operation (NEG, mode, op0, mode);
 
              return tem ? tem : gen_rtx (NEG, mode, op0);
            }
@@ -3506,22 +3560,29 @@ simplify_binary_operation (code, mode, op0, op1)
          /* Convert multiply by constant power of two into shift.  */
          if (GET_CODE (op1) == CONST_INT
              && (val = exact_log2 (INTVAL (op1))) >= 0)
-           return gen_rtx (ASHIFT, mode, op0,
-                           gen_rtx (CONST_INT, VOIDmode, val));
+           return gen_rtx (ASHIFT, mode, op0, GEN_INT (val));
 
          if (GET_CODE (op1) == CONST_DOUBLE
              && GET_MODE_CLASS (GET_MODE (op1)) == MODE_FLOAT)
            {
              REAL_VALUE_TYPE d;
+             jmp_buf handler;
+             int op1is2, op1ism1;
+
+             if (setjmp (handler))
+               return 0;
+
+             set_float_handler (handler);
              REAL_VALUE_FROM_CONST_DOUBLE (d, op1);
+             op1is2 = REAL_VALUES_EQUAL (d, dconst2);
+             op1ism1 = REAL_VALUES_EQUAL (d, dconstm1);
+             set_float_handler (NULL_PTR);
 
              /* x*2 is x+x and x*(-1) is -x */
-             if (REAL_VALUES_EQUAL (d, dconst2)
-                 && GET_MODE (op0) == mode)
+             if (op1is2 && GET_MODE (op0) == mode)
                return gen_rtx (PLUS, mode, op0, copy_rtx (op0));
 
-             else if (REAL_VALUES_EQUAL (d, dconstm1)
-                      && GET_MODE (op0) == mode)
+             else if (op1ism1 && GET_MODE (op0) == mode)
                return gen_rtx (NEG, mode, op0);
            }
          break;
@@ -3537,7 +3598,8 @@ simplify_binary_operation (code, mode, op0, op1)
          /* A | (~A) -> -1 */
          if (((GET_CODE (op0) == NOT && rtx_equal_p (XEXP (op0, 0), op1))
               || (GET_CODE (op1) == NOT && rtx_equal_p (XEXP (op1, 0), op0)))
-             && ! side_effects_p (op0))
+             && ! side_effects_p (op0)
+             && GET_MODE_CLASS (mode) != MODE_CC)
            return constm1_rtx;
          break;
 
@@ -3547,7 +3609,8 @@ simplify_binary_operation (code, mode, op0, op1)
          if (GET_CODE (op1) == CONST_INT
              && (INTVAL (op1) & GET_MODE_MASK (mode)) == GET_MODE_MASK (mode))
            return gen_rtx (NOT, mode, op0);
-         if (op0 == op1 && ! side_effects_p (op0))
+         if (op0 == op1 && ! side_effects_p (op0)
+             && GET_MODE_CLASS (mode) != MODE_CC)
            return const0_rtx;
          break;
 
@@ -3557,12 +3620,14 @@ simplify_binary_operation (code, mode, op0, op1)
          if (GET_CODE (op1) == CONST_INT
              && (INTVAL (op1) & GET_MODE_MASK (mode)) == GET_MODE_MASK (mode))
            return op0;
-         if (op0 == op1 && ! side_effects_p (op0))
+         if (op0 == op1 && ! side_effects_p (op0)
+             && GET_MODE_CLASS (mode) != MODE_CC)
            return op0;
          /* A & (~A) -> 0 */
          if (((GET_CODE (op0) == NOT && rtx_equal_p (XEXP (op0, 0), op1))
               || (GET_CODE (op1) == NOT && rtx_equal_p (XEXP (op1, 0), op0)))
-             && ! side_effects_p (op0))
+             && ! side_effects_p (op0)
+             && GET_MODE_CLASS (mode) != MODE_CC)
            return const0_rtx;
          break;
 
@@ -3571,17 +3636,21 @@ 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_rtx (CONST_INT, VOIDmode, arg1));
+           return gen_rtx (LSHIFTRT, mode, op0, GEN_INT (arg1));
 
          /* ... fall through ... */
 
        case DIV:
          if (op1 == CONST1_RTX (mode))
            return op0;
-         else if (op0 == CONST0_RTX (mode)
-                  && ! side_effects_p (op1))
+
+         /* In IEEE floating point, 0/x is not always 0.  */
+         if ((TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
+              || GET_MODE_CLASS (mode) == MODE_INT)
+             && op0 == CONST0_RTX (mode)
+             && ! side_effects_p (op1))
            return op0;
+
 #if 0 /* Turned off till an expert says this is a safe thing to do.  */
 #if ! defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC)
          /* Change division by a constant into multiplication.  */
@@ -3594,7 +3663,7 @@ simplify_binary_operation (code, mode, op0, op1)
              if (REAL_VALUES_EQUAL (d, dconst0))
                abort();
 #if defined (REAL_ARITHMETIC)
-             REAL_ARITHMETIC (d, RDIV_EXPR, dconst1, d);
+             REAL_ARITHMETIC (d, (int) RDIV_EXPR, dconst1, d);
              return gen_rtx (MULT, mode, op0, 
                              CONST_DOUBLE_FROM_REAL_VALUE (d, mode));
 #else
@@ -3610,8 +3679,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_rtx (CONST_INT, VOIDmode, INTVAL (op1) - 1));
+           return gen_rtx (AND, mode, op0, GEN_INT (INTVAL (op1) - 1));
 
          /* ... fall through ... */
 
@@ -3624,7 +3692,7 @@ simplify_binary_operation (code, mode, op0, op1)
        case ROTATERT:
        case ROTATE:
          /* Rotating ~0 always results in ~0.  */
-         if (GET_CODE (op0) == CONST_INT && width <= HOST_BITS_PER_INT
+         if (GET_CODE (op0) == CONST_INT && width <= HOST_BITS_PER_WIDE_INT
              && INTVAL (op0) == GET_MODE_MASK (mode)
              && ! side_effects_p (op1))
            return op0;
@@ -3642,8 +3710,8 @@ simplify_binary_operation (code, mode, op0, op1)
          break;
 
        case SMIN:
-         if (width <= HOST_BITS_PER_INT && GET_CODE (op1) == CONST_INT 
-             && INTVAL (op1) == 1 << (width -1)
+         if (width <= HOST_BITS_PER_WIDE_INT && GET_CODE (op1) == CONST_INT 
+             && INTVAL (op1) == (HOST_WIDE_INT) 1 << (width -1)
              && ! side_effects_p (op0))
            return op1;
          else if (rtx_equal_p (op0, op1) && ! side_effects_p (op0))
@@ -3651,8 +3719,9 @@ simplify_binary_operation (code, mode, op0, op1)
          break;
           
        case SMAX:
-         if (width <= HOST_BITS_PER_INT && GET_CODE (op1) == CONST_INT
-             && INTVAL (op1) == GET_MODE_MASK (mode) >> 1
+         if (width <= HOST_BITS_PER_WIDE_INT && GET_CODE (op1) == CONST_INT
+             && (INTVAL (op1)
+                 == (unsigned HOST_WIDE_INT) GET_MODE_MASK (mode) >> 1)
              && ! side_effects_p (op0))
            return op1;
          else if (rtx_equal_p (op0, op1) && ! side_effects_p (op0))
@@ -3686,18 +3755,18 @@ simplify_binary_operation (code, mode, op0, op1)
   arg0 = INTVAL (op0);
   arg1 = INTVAL (op1);
 
-  if (width < HOST_BITS_PER_INT)
+  if (width < HOST_BITS_PER_WIDE_INT)
     {
-      arg0 &= (1 << width) - 1;
-      arg1 &= (1 << width) - 1;
+      arg0 &= ((HOST_WIDE_INT) 1 << width) - 1;
+      arg1 &= ((HOST_WIDE_INT) 1 << width) - 1;
 
       arg0s = arg0;
-      if (arg0s & (1 << (width - 1)))
-       arg0s |= ((-1) << width);
+      if (arg0s & ((HOST_WIDE_INT) 1 << (width - 1)))
+       arg0s |= ((HOST_WIDE_INT) (-1) << width);
 
       arg1s = arg1;
-      if (arg1s & (1 << (width - 1)))
-       arg1s |= ((-1) << width);
+      if (arg1s & ((HOST_WIDE_INT) 1 << (width - 1)))
+       arg1s |= ((HOST_WIDE_INT) (-1) << width);
     }
   else
     {
@@ -3736,13 +3805,13 @@ simplify_binary_operation (code, mode, op0, op1)
     case UDIV:
       if (arg1 == 0)
        return 0;
-      val = (unsigned) arg0 / arg1;
+      val = (unsigned HOST_WIDE_INT) arg0 / arg1;
       break;
 
     case UMOD:
       if (arg1 == 0)
        return 0;
-      val = (unsigned) arg0 % arg1;
+      val = (unsigned HOST_WIDE_INT) arg0 % arg1;
       break;
 
     case AND:
@@ -3770,7 +3839,7 @@ simplify_binary_operation (code, mode, op0, op1)
       if (arg1 >= width)
        return 0;
 
-      val = ((unsigned) arg0) >> arg1;
+      val = ((unsigned HOST_WIDE_INT) arg0) >> arg1;
       break;
 
     case ASHIFT:
@@ -3785,7 +3854,7 @@ simplify_binary_operation (code, mode, op0, op1)
       if (arg1 >= width)
        return 0;
 
-      val = ((unsigned) arg0) << arg1;
+      val = ((unsigned HOST_WIDE_INT) arg0) << arg1;
       break;
 
     case ASHIFTRT:
@@ -3800,6 +3869,12 @@ simplify_binary_operation (code, mode, op0, op1)
        return 0;
 
       val = arg0s >> arg1;
+
+      /* Bootstrap compiler may not have sign extended the right shift.
+        Manually extend the sign to insure bootstrap cc matches gcc.  */
+      if (arg0s < 0 && arg1 > 0)
+       val |= ((HOST_WIDE_INT) -1) << (HOST_BITS_PER_WIDE_INT - arg1);
+
       break;
 
     case ROTATERT:
@@ -3807,8 +3882,8 @@ simplify_binary_operation (code, mode, op0, op1)
        return 0;
 
       arg1 %= width;
-      val = ((((unsigned) arg0) << (width - arg1))
-            | (((unsigned) arg0) >> arg1));
+      val = ((((unsigned HOST_WIDE_INT) arg0) << (width - arg1))
+            | (((unsigned HOST_WIDE_INT) arg0) >> arg1));
       break;
 
     case ROTATE:
@@ -3816,8 +3891,8 @@ simplify_binary_operation (code, mode, op0, op1)
        return 0;
 
       arg1 %= width;
-      val = ((((unsigned) arg0) << arg1)
-            | (((unsigned) arg0) >> (width - arg1)));
+      val = ((((unsigned HOST_WIDE_INT) arg0) << arg1)
+            | (((unsigned HOST_WIDE_INT) arg0) >> (width - arg1)));
       break;
 
     case COMPARE:
@@ -3829,7 +3904,8 @@ simplify_binary_operation (code, mode, op0, op1)
       break;
 
     case UMIN:
-      val = (unsigned int)arg0 <= (unsigned int)arg1 ? arg0 : arg1;
+      val = ((unsigned HOST_WIDE_INT) arg0
+            <= (unsigned HOST_WIDE_INT) arg1 ? arg0 : arg1);
       break;
 
     case SMAX:
@@ -3837,7 +3913,8 @@ simplify_binary_operation (code, mode, op0, op1)
       break;
 
     case UMAX:
-      val = (unsigned int)arg0 > (unsigned int)arg1 ? arg0 : arg1;
+      val = ((unsigned HOST_WIDE_INT) arg0
+            > (unsigned HOST_WIDE_INT) arg1 ? arg0 : arg1);
       break;
 
     default:
@@ -3847,11 +3924,226 @@ simplify_binary_operation (code, mode, op0, op1)
   /* 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_INT
-      && ((val & ((-1) << (width - 1))) != ((-1) << (width - 1))))
-    val &= (1 << width) - 1;
+  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;
+
+  return GEN_INT (val);
+}
+\f
+/* Simplify a PLUS or MINUS, at least one of whose operands may be another
+   PLUS or MINUS.
+
+   Rather than test for specific case, we do this by a brute-force method
+   and do all possible simplifications until no more changes occur.  Then
+   we rebuild the operation.  */
+
+static rtx
+simplify_plus_minus (code, mode, op0, op1)
+     enum rtx_code code;
+     enum machine_mode mode;
+     rtx op0, op1;
+{
+  rtx ops[8];
+  int negs[8];
+  rtx result, tem;
+  int n_ops = 2, input_ops = 2, input_consts = 0, n_consts = 0;
+  int first = 1, negate = 0, changed;
+  int i, j;
+
+  bzero (ops, sizeof ops);
   
-  return gen_rtx (CONST_INT, VOIDmode, val);
+  /* Set up the two operands and then expand them until nothing has been
+     changed.  If we run out of room in our array, give up; this should
+     almost never happen.  */
+
+  ops[0] = op0, ops[1] = op1, negs[0] = 0, negs[1] = (code == MINUS);
+
+  changed = 1;
+  while (changed)
+    {
+      changed = 0;
+
+      for (i = 0; i < n_ops; i++)
+       switch (GET_CODE (ops[i]))
+         {
+         case PLUS:
+         case MINUS:
+           if (n_ops == 7)
+             return 0;
+
+           ops[n_ops] = XEXP (ops[i], 1);
+           negs[n_ops++] = GET_CODE (ops[i]) == MINUS ? !negs[i] : negs[i];
+           ops[i] = XEXP (ops[i], 0);
+           input_ops++;
+           changed = 1;
+           break;
+
+         case NEG:
+           ops[i] = XEXP (ops[i], 0);
+           negs[i] = ! negs[i];
+           changed = 1;
+           break;
+
+         case CONST:
+           ops[i] = XEXP (ops[i], 0);
+           input_consts++;
+           changed = 1;
+           break;
+
+         case NOT:
+           /* ~a -> (-a - 1) */
+           if (n_ops != 7)
+             {
+               ops[n_ops] = constm1_rtx;
+               negs[n_ops++] = negs[i];
+               ops[i] = XEXP (ops[i], 0);
+               negs[i] = ! negs[i];
+               changed = 1;
+             }
+           break;
+
+         case CONST_INT:
+           if (negs[i])
+             ops[i] = GEN_INT (- INTVAL (ops[i])), negs[i] = 0, changed = 1;
+           break;
+         }
+    }
+
+  /* If we only have two operands, we can't do anything.  */
+  if (n_ops <= 2)
+    return 0;
+
+  /* Now simplify each pair of operands until nothing changes.  The first
+     time through just simplify constants against each other.  */
+
+  changed = 1;
+  while (changed)
+    {
+      changed = first;
+
+      for (i = 0; i < n_ops - 1; i++)
+       for (j = i + 1; j < n_ops; j++)
+         if (ops[i] != 0 && ops[j] != 0
+             && (! first || (CONSTANT_P (ops[i]) && CONSTANT_P (ops[j]))))
+           {
+             rtx lhs = ops[i], rhs = ops[j];
+             enum rtx_code ncode = PLUS;
+
+             if (negs[i] && ! negs[j])
+               lhs = ops[j], rhs = ops[i], ncode = MINUS;
+             else if (! negs[i] && negs[j])
+               ncode = MINUS;
+
+             tem = simplify_binary_operation (ncode, mode, lhs, rhs);
+             if (tem)
+               {
+                 ops[i] = tem, ops[j] = 0;
+                 negs[i] = negs[i] && negs[j];
+                 if (GET_CODE (tem) == NEG)
+                   ops[i] = XEXP (tem, 0), negs[i] = ! negs[i];
+
+                 if (GET_CODE (ops[i]) == CONST_INT && negs[i])
+                   ops[i] = GEN_INT (- INTVAL (ops[i])), negs[i] = 0;
+                 changed = 1;
+               }
+           }
+
+      first = 0;
+    }
+
+  /* Pack all the operands to the lower-numbered entries and give up if
+     we didn't reduce the number of operands we had.  Make sure we
+     count a CONST as two operands.  If we have the same number of
+     operands, but have made more CONSTs than we had, this is also
+     an improvement, so accept it.  */
+
+  for (i = 0, j = 0; j < n_ops; j++)
+    if (ops[j] != 0)
+      {
+       ops[i] = ops[j], negs[i++] = negs[j];
+       if (GET_CODE (ops[j]) == CONST)
+         n_consts++;
+      }
+
+  if (i + n_consts > input_ops
+      || (i + n_consts == input_ops && n_consts <= input_consts))
+    return 0;
+
+  n_ops = i;
+
+  /* If we have a CONST_INT, put it last.  */
+  for (i = 0; i < n_ops - 1; i++)
+    if (GET_CODE (ops[i]) == CONST_INT)
+      {
+       tem = ops[n_ops - 1], ops[n_ops - 1] = ops[i] , ops[i] = tem;
+       j = negs[n_ops - 1], negs[n_ops - 1] = negs[i], negs[i] = j;
+      }
+
+  /* Put a non-negated operand first.  If there aren't any, make all
+     operands positive and negate the whole thing later.  */
+  for (i = 0; i < n_ops && negs[i]; i++)
+    ;
+
+  if (i == n_ops)
+    {
+      for (i = 0; i < n_ops; i++)
+       negs[i] = 0;
+      negate = 1;
+    }
+  else if (i != 0)
+    {
+      tem = ops[0], ops[0] = ops[i], ops[i] = tem;
+      j = negs[0], negs[0] = negs[i], negs[i] = j;
+    }
+
+  /* Now make the result by performing the requested operations.  */
+  result = ops[0];
+  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;
+}
+\f
+/* Make a binary operation by properly ordering the operands and 
+   seeing if the expression folds.  */
+
+static rtx
+cse_gen_binary (code, mode, op0, op1)
+     enum rtx_code code;
+     enum machine_mode mode;
+     rtx op0, op1;
+{
+  rtx tem;
+
+  /* Put complex operands first and constants second if commutative.  */
+  if (GET_RTX_CLASS (code) == 'c'
+      && ((CONSTANT_P (op0) && GET_CODE (op1) != CONST_INT)
+         || (GET_RTX_CLASS (GET_CODE (op0)) == 'o'
+             && GET_RTX_CLASS (GET_CODE (op1)) != 'o')
+         || (GET_CODE (op0) == SUBREG
+             && GET_RTX_CLASS (GET_CODE (SUBREG_REG (op0))) == 'o'
+             && GET_RTX_CLASS (GET_CODE (op1)) != 'o')))
+    tem = op0, op0 = op1, op1 = tem;
+
+  /* If this simplifies, do it.  */
+  tem = simplify_binary_operation (code, mode, op0, op1);
+
+  if (tem)
+    return tem;
+
+  /* Handle addition and subtraction of CONST_INT specially.  Otherwise,
+     just form the operation.  */
+
+  if (code == PLUS && GET_CODE (op1) == CONST_INT
+      && GET_MODE (op0) != VOIDmode)
+    return plus_constant (op0, INTVAL (op1));
+  else if (code == MINUS && GET_CODE (op1) == CONST_INT
+          && GET_MODE (op0) != VOIDmode)
+    return plus_constant (op0, - INTVAL (op1));
+  else
+    return gen_rtx (code, mode, op0, op1);
 }
 \f
 /* Like simplify_binary_operation except used for relational operators.
@@ -3863,16 +4155,25 @@ simplify_relational_operation (code, mode, op0, op1)
      enum machine_mode mode;
      rtx op0, op1;
 {
-  register int arg0, arg1, arg0s, arg1s;
-  int val;
+  register HOST_WIDE_INT arg0, arg1, arg0s, arg1s;
+  HOST_WIDE_INT val;
   int width = GET_MODE_BITSIZE (mode);
 
   /* If op0 is a compare, extract the comparison arguments from it.  */
   if (GET_CODE (op0) == COMPARE && op1 == const0_rtx)
     op1 = XEXP (op0, 1), op0 = XEXP (op0, 0);
 
-  if (GET_CODE (op0) != CONST_INT || GET_CODE (op1) != CONST_INT
-      || width > HOST_BITS_PER_INT || width == 0)
+  /* What to do with MODE_CC isn't clear yet.
+     Let's make sure nothing erroneous is done.  */
+  if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_CC)
+    return 0;
+
+  /* Unlike the arithmetic operations, we can do the comparison whether
+     or not WIDTH is larger than HOST_BITS_PER_WIDE_INT because the
+     CONST_INTs are to be understood as being infinite precision as
+     is the comparison.  So there is no question of overflow.  */
+
+  if (GET_CODE (op0) != CONST_INT || GET_CODE (op1) != CONST_INT || width == 0)
     {
       /* Even if we can't compute a constant result,
         there are some cases worth simplifying.  */
@@ -3884,12 +4185,13 @@ simplify_relational_operation (code, mode, op0, op1)
              || GET_MODE_CLASS (GET_MODE (op0)) != MODE_FLOAT))
        return (code == EQ || code == GE || code == LE || code == LEU
                || code == GEU) ? const_true_rtx : const0_rtx;
+
+#if ! defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC)
       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;
-         int value;
          jmp_buf handler;
          int op0lt, op1lt, equal;
 
@@ -3902,7 +4204,7 @@ simplify_relational_operation (code, mode, op0, op1)
          equal = REAL_VALUES_EQUAL (d0, d1);
          op0lt = REAL_VALUES_LESS (d0, d1);
          op1lt = REAL_VALUES_LESS (d1, d0);
-         set_float_handler (0);
+         set_float_handler (NULL_PTR);
 
          switch (code)
            {
@@ -3920,7 +4222,60 @@ simplify_relational_operation (code, mode, op0, op1)
              return op1lt ? const_true_rtx : const0_rtx;
            }
        }
-      
+#endif  /* not REAL_IS_NOT_DOUBLE, or REAL_ARITHMETIC */
+
+      else if (GET_MODE_CLASS (mode) == MODE_INT
+              && width > HOST_BITS_PER_WIDE_INT
+              && (GET_CODE (op0) == CONST_DOUBLE
+                  || GET_CODE (op0) == CONST_INT)
+              && (GET_CODE (op1) == CONST_DOUBLE
+                  || GET_CODE (op1) == CONST_INT))
+       {
+         HOST_WIDE_INT h0, l0, h1, l1;
+         unsigned HOST_WIDE_INT uh0, ul0, uh1, ul1;
+         int op0lt, op0ltu, equal;
+
+         if (GET_CODE (op0) == CONST_DOUBLE)
+           l0 = CONST_DOUBLE_LOW (op0), h0 = CONST_DOUBLE_HIGH (op0);
+         else
+           l0 = INTVAL (op0), h0 = l0 < 0 ? -1 : 0;
+         
+         if (GET_CODE (op1) == CONST_DOUBLE)
+           l1 = CONST_DOUBLE_LOW (op1), h1 = CONST_DOUBLE_HIGH (op1);
+         else
+           l1 = INTVAL (op1), h1 = l1 < 0 ? -1 : 0;
+
+         uh0 = h0, ul0 = l0, uh1 = h1, ul1 = l1;
+
+         equal = (h0 == h1 && l0 == l1);
+         op0lt = (h0 < h1 || (h0 == h1 && l0 < l1));
+         op0ltu = (uh0 < uh1 || (uh0 == uh1 && ul0 < ul1));
+
+         switch (code)
+           {
+           case EQ:
+             return equal ? const_true_rtx : const0_rtx;
+           case NE:
+             return !equal ? const_true_rtx : const0_rtx;
+           case LE:
+             return equal || op0lt ? const_true_rtx : const0_rtx;
+           case LT:
+             return op0lt ? const_true_rtx : const0_rtx;
+           case GE:
+             return !op0lt ? const_true_rtx : const0_rtx;
+           case GT:
+             return !equal && !op0lt ? const_true_rtx : const0_rtx;
+           case LEU:
+             return equal || op0ltu ? const_true_rtx : const0_rtx;
+           case LTU:
+             return op0ltu ? const_true_rtx : const0_rtx;
+           case GEU:
+             return !op0ltu ? const_true_rtx : const0_rtx;
+           case GTU:
+             return !equal && !op0ltu ? const_true_rtx : const0_rtx;
+           }
+       }
+
       switch (code)
        {
        case EQ:
@@ -3989,18 +4344,18 @@ simplify_relational_operation (code, mode, op0, op1)
   arg0 = INTVAL (op0);
   arg1 = INTVAL (op1);
 
-  if (width < HOST_BITS_PER_INT)
+  if (width < HOST_BITS_PER_WIDE_INT)
     {
-      arg0 &= (1 << width) - 1;
-      arg1 &= (1 << width) - 1;
+      arg0 &= ((HOST_WIDE_INT) 1 << width) - 1;
+      arg1 &= ((HOST_WIDE_INT) 1 << width) - 1;
 
       arg0s = arg0;
-      if (arg0s & (1 << (width - 1)))
-       arg0s |= ((-1) << width);
+      if (arg0s & ((HOST_WIDE_INT) 1 << (width - 1)))
+       arg0s |= ((HOST_WIDE_INT) (-1) << width);
 
       arg1s = arg1;
-      if (arg1s & (1 << (width - 1)))
-       arg1s |= ((-1) << width);
+      if (arg1s & ((HOST_WIDE_INT) 1 << (width - 1)))
+       arg1s |= ((HOST_WIDE_INT) (-1) << width);
     }
   else
     {
@@ -4037,19 +4392,23 @@ simplify_relational_operation (code, mode, op0, op1)
       break;
 
     case LEU:
-      val = ((unsigned) arg0) <= ((unsigned) arg1) ? STORE_FLAG_VALUE : 0;
+      val = (((unsigned HOST_WIDE_INT) arg0)
+            <= ((unsigned HOST_WIDE_INT) arg1) ? STORE_FLAG_VALUE : 0);
       break;
 
     case LTU:
-      val = ((unsigned) arg0) < ((unsigned) arg1) ? STORE_FLAG_VALUE : 0;
+      val = (((unsigned HOST_WIDE_INT) arg0)
+            < ((unsigned HOST_WIDE_INT) arg1) ? STORE_FLAG_VALUE : 0);
       break;
 
     case GEU:
-      val = ((unsigned) arg0) >= ((unsigned) arg1) ? STORE_FLAG_VALUE : 0;
+      val = (((unsigned HOST_WIDE_INT) arg0)
+            >= ((unsigned HOST_WIDE_INT) arg1) ? STORE_FLAG_VALUE : 0);
       break;
 
     case GTU:
-      val = ((unsigned) arg0) > ((unsigned) arg1) ? STORE_FLAG_VALUE : 0;
+      val = (((unsigned HOST_WIDE_INT) arg0)
+            > ((unsigned HOST_WIDE_INT) arg1) ? STORE_FLAG_VALUE : 0);
       break;
 
     default:
@@ -4059,11 +4418,12 @@ simplify_relational_operation (code, mode, op0, op1)
   /* 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_INT
-      && ((val & ((-1) << (width - 1))) != ((-1) << (width - 1))))
-    val &= (1 << width) - 1;
+  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;
   
-  return gen_rtx (CONST_INT, VOIDmode, val);
+  return GEN_INT (val);
 }
 \f
 /* Simplify CODE, an operation with result mode MODE and three operands,
@@ -4080,7 +4440,7 @@ simplify_ternary_operation (code, mode, op0_mode, op0, op1, op2)
 
   /* VOIDmode means "infinite" precision.  */
   if (width == 0)
-    width = HOST_BITS_PER_INT;
+    width = HOST_BITS_PER_WIDE_INT;
 
   switch (code)
     {
@@ -4090,34 +4450,36 @@ simplify_ternary_operation (code, mode, op0_mode, op0, op1, op2)
          && GET_CODE (op1) == CONST_INT
          && GET_CODE (op2) == CONST_INT
          && INTVAL (op1) + INTVAL (op2) <= GET_MODE_BITSIZE (op0_mode)
-         && width <= HOST_BITS_PER_INT)
+         && width <= HOST_BITS_PER_WIDE_INT)
        {
          /* Extracting a bit-field from a constant */
-         int val = INTVAL (op0);
+         HOST_WIDE_INT val = INTVAL (op0);
 
 #if BITS_BIG_ENDIAN
          val >>= (GET_MODE_BITSIZE (op0_mode) - INTVAL (op2) - INTVAL (op1));
 #else
          val >>= INTVAL (op2);
 #endif
-         if (HOST_BITS_PER_INT != INTVAL (op1))
+         if (HOST_BITS_PER_WIDE_INT != INTVAL (op1))
            {
              /* First zero-extend.  */
-             val &= (1 << INTVAL (op1)) - 1;
+             val &= ((HOST_WIDE_INT) 1 << INTVAL (op1)) - 1;
              /* If desired, propagate sign bit.  */
-             if (code == SIGN_EXTRACT && (val & (1 << (INTVAL (op1) - 1))))
-               val |= ~ ((1 << INTVAL (op1)) - 1);
+             if (code == SIGN_EXTRACT
+                 && (val & ((HOST_WIDE_INT) 1 << (INTVAL (op1) - 1))))
+               val |= ~ (((HOST_WIDE_INT) 1 << INTVAL (op1)) - 1);
            }
 
          /* 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_INT
-             && ((val & ((-1) << (width - 1))) != ((-1) << (width - 1))))
-           val &= (1 << width) - 1;
+         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;
 
-         return gen_rtx (CONST_INT, VOIDmode, val);
+         return GEN_INT (val);
        }
       break;
 
@@ -4140,8 +4502,8 @@ simplify_ternary_operation (code, mode, op0_mode, op0, op1, op2)
    modified by recursive calls to this function.
 
    If X is a register whose contents are known, we do NOT
-   return those contents.  This is because an instruction that
-   uses a register is usually faster than one that uses a constant.
+   return those contents here.  equiv_constant is called to
+   perform that task.
 
    INSN is the insn that we may be modifying.  If it is 0, make a copy
    of X before modifying it.  */
@@ -4154,7 +4516,7 @@ fold_rtx (x, insn)
   register enum rtx_code code;
   register enum machine_mode mode;
   register char *fmt;
-  register int i, val;
+  register int i;
   rtx new = 0;
   int copied = 0;
   int must_swap = 0;
@@ -4220,10 +4582,32 @@ fold_rtx (x, insn)
          || (new = lookup_as_function (x, CONST_DOUBLE)) != 0)
        return new;
 
-      /* If this is a paradoxical SUBREG, we can't do anything with
-        it because we have no idea what value the extra bits would have.  */
+      /* If this is a paradoxical SUBREG, we have no idea what value the
+        extra bits would have.  However, if the operand is equivalent
+        to a SUBREG whose operand is the same as our mode, and all the
+        modes are within a word, we can just use the inner operand
+        because these SUBREGs just say how to treat the register.  */
+
       if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
-       return x;
+       {
+         enum machine_mode imode = GET_MODE (SUBREG_REG (x));
+         struct table_elt *elt;
+
+         if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD
+             && GET_MODE_SIZE (imode) <= UNITS_PER_WORD
+             && (elt = lookup (SUBREG_REG (x), HASH (SUBREG_REG (x), imode),
+                               imode)) != 0)
+           {
+             for (elt = elt->first_same_value;
+                  elt; elt = elt->next_same_value)
+               if (GET_CODE (elt->exp) == SUBREG
+                   && GET_MODE (SUBREG_REG (elt->exp)) == mode
+                   && exp_equiv_p (elt->exp, elt->exp, 1, 0))
+                 return copy_rtx (SUBREG_REG (elt->exp));
+           }
+
+         return x;
+       }
 
       /* Fold SUBREG_REG.  If it changed, see if we can simplify the SUBREG.
         We might be able to if the SUBREG is extracting a single word in an
@@ -4250,17 +4634,23 @@ fold_rtx (x, insn)
        }
 
       /* If this is a narrowing SUBREG and our operand is a REG, see if
-        we can find an equivalence for REG that is a arithmetic operation
+        we can find an equivalence for REG that is an arithmetic operation
         in a wider mode where both operands are paradoxical SUBREGs
         from objects of our result mode.  In that case, we couldn't report
         an equivalent value for that operation, since we don't know what the
         extra bits will be.  But we can find an equivalence for this SUBREG
         by folding that operation is the narrow mode.  This allows us to
         fold arithmetic in narrow modes when the machine only supports
-        word-sized arithmetic.  */
+        word-sized arithmetic.  
+
+        Also look for a case where we have a SUBREG whose operand is the
+        same as our result.  If both modes are smaller than a word, we
+        are simply interpreting a register in different modes and we
+        can use the inner value.  */
 
       if (GET_CODE (folded_arg0) == REG
-         && GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (folded_arg0)))
+         && GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (folded_arg0))
+         && subreg_lowpart_p (x))
        {
          struct table_elt *elt;
 
@@ -4275,6 +4665,8 @@ fold_rtx (x, insn)
 
          for (; elt; elt = elt->next_same_value)
            {
+             enum rtx_code eltcode = GET_CODE (elt->exp);
+
              /* Just check for unary and binary operations.  */
              if (GET_RTX_CLASS (GET_CODE (elt->exp)) == '1'
                  && GET_CODE (elt->exp) != SIGN_EXTEND
@@ -4285,7 +4677,7 @@ fold_rtx (x, insn)
                  rtx op0 = SUBREG_REG (XEXP (elt->exp, 0));
 
                  if (GET_CODE (op0) != REG && ! CONSTANT_P (op0))
-                   op0 = fold_rtx (op0, 0);
+                   op0 = fold_rtx (op0, NULL_RTX);
 
                  op0 = equiv_constant (op0);
                  if (op0)
@@ -4294,6 +4686,10 @@ fold_rtx (x, insn)
                }
              else if ((GET_RTX_CLASS (GET_CODE (elt->exp)) == '2'
                        || GET_RTX_CLASS (GET_CODE (elt->exp)) == 'c')
+                      && eltcode != DIV && eltcode != MOD
+                      && eltcode != UDIV && eltcode != UMOD
+                      && eltcode != ASHIFTRT && eltcode != LSHIFTRT
+                      && eltcode != ROTATE && eltcode != ROTATERT
                       && ((GET_CODE (XEXP (elt->exp, 0)) == SUBREG
                            && (GET_MODE (SUBREG_REG (XEXP (elt->exp, 0)))
                                == mode))
@@ -4307,13 +4703,13 @@ fold_rtx (x, insn)
                  rtx op1 = gen_lowpart_common (mode, XEXP (elt->exp, 1));
 
                  if (op0 && GET_CODE (op0) != REG && ! CONSTANT_P (op0))
-                   op0 = fold_rtx (op0, 0);
+                   op0 = fold_rtx (op0, NULL_RTX);
 
                  if (op0)
                    op0 = equiv_constant (op0);
 
                  if (op1 && GET_CODE (op1) != REG && ! CONSTANT_P (op1))
-                   op1 = fold_rtx (op1, 0);
+                   op1 = fold_rtx (op1, NULL_RTX);
 
                  if (op1)
                    op1 = equiv_constant (op1);
@@ -4323,6 +4719,13 @@ fold_rtx (x, insn)
                                                     op0, op1);
                }
 
+             else if (GET_CODE (elt->exp) == SUBREG
+                      && GET_MODE (SUBREG_REG (elt->exp)) == mode
+                      && (GET_MODE_SIZE (GET_MODE (folded_arg0))
+                          <= UNITS_PER_WORD)
+                      && exp_equiv_p (elt->exp, elt->exp, 1, 0))
+               new = copy_rtx (SUBREG_REG (elt->exp));
+
              if (new)
                return new;
            }
@@ -4338,7 +4741,7 @@ fold_rtx (x, insn)
       if (new)
        return fold_rtx (copy_rtx (XEXP (new, 0)), insn);
       break;
-      
+
     case MEM:
       /* If we are not actually processing an insn, don't try to find the
         best address.  Not only don't we care, but we could modify the
@@ -4349,9 +4752,9 @@ fold_rtx (x, insn)
       {
        /* Even if we don't fold in the insn itself,
           we can safely do so here, in hopes of getting a constant.  */
-       rtx addr = fold_rtx (XEXP (x, 0), 0);
+       rtx addr = fold_rtx (XEXP (x, 0), NULL_RTX);
        rtx base = 0;
-       int offset = 0;
+       HOST_WIDE_INT offset = 0;
 
        if (GET_CODE (addr) == REG
            && REGNO_QTY_VALID_P (REGNO (addr))
@@ -4637,32 +5040,24 @@ fold_rtx (x, insn)
        {
          struct table_elt *p0, *p1;
          rtx true = const_true_rtx, false = const0_rtx;
+         enum machine_mode mode_arg1;
 
 #ifdef FLOAT_STORE_FLAG_VALUE
-         if (GET_MODE_CLASS (mode))
+         if (GET_MODE_CLASS (mode) == MODE_FLOAT)
            {
              true = immed_real_const_1 (FLOAT_STORE_FLAG_VALUE, mode);
              false = CONST0_RTX (mode);
            }
 #endif
 
-         code = find_comparison_args (code, &folded_arg0, &folded_arg1);
+         code = find_comparison_args (code, &folded_arg0, &folded_arg1,
+                                      &mode_arg0, &mode_arg1);
          const_arg0 = equiv_constant (folded_arg0);
          const_arg1 = equiv_constant (folded_arg1);
 
-         /* Get a mode from the values actually being compared, or from the
-            old value of MODE_ARG0 if both are constants.  If the resulting
-            mode is VOIDmode or a MODE_CC mode, we don't know what kinds
-            of things are being compared, so we can't do anything with this
-            comparison.  */
-
-         if (GET_MODE (folded_arg0) != VOIDmode
-             && GET_MODE_CLASS (GET_MODE (folded_arg0)) != MODE_CC)
-           mode_arg0 = GET_MODE (folded_arg0);
-
-         else if (GET_MODE (folded_arg1) != VOIDmode
-                  && GET_MODE_CLASS (GET_MODE (folded_arg1)) != MODE_CC)
-           mode_arg0 = GET_MODE (folded_arg1);
+         /* If the mode is VOIDmode or a MODE_CC mode, we don't know
+            what kinds of things are being compared, so we can't do
+            anything with this comparison.  */
 
          if (mode_arg0 == VOIDmode || GET_MODE_CLASS (mode_arg0) == MODE_CC)
            break;
@@ -4751,12 +5146,13 @@ fold_rtx (x, insn)
              && INTVAL (inner_const) != 0)
            {
              int sign_bitnum = GET_MODE_BITSIZE (mode_arg0) - 1;
-             int has_sign = (HOST_BITS_PER_INT >= sign_bitnum
-                             && (INTVAL (inner_const) & (1 << sign_bitnum)));
+             int has_sign = (HOST_BITS_PER_WIDE_INT >= sign_bitnum
+                             && (INTVAL (inner_const)
+                                 & ((HOST_WIDE_INT) 1 << sign_bitnum)));
              rtx true = const_true_rtx, false = const0_rtx;
 
 #ifdef FLOAT_STORE_FLAG_VALUE
-             if (GET_MODE_CLASS (mode))
+             if (GET_MODE_CLASS (mode) == MODE_FLOAT)
                {
                  true = immed_real_const_1 (FLOAT_STORE_FLAG_VALUE, mode);
                  false = CONST0_RTX (mode);
@@ -4808,10 +5204,22 @@ fold_rtx (x, insn)
                  && XEXP (XEXP (y, 1), 0) == XEXP (const_arg1, 0))
                return XEXP (y, 0);
            }
+         goto from_plus;
+
+       case MINUS:
+         /* If we have (MINUS Y C), see if Y is known to be (PLUS Z C2).
+            If so, produce (PLUS Z C2-C).  */
+         if (const_arg1 != 0 && GET_CODE (const_arg1) == CONST_INT)
+           {
+             rtx y = lookup_as_function (XEXP (x, 0), PLUS);
+             if (y && GET_CODE (XEXP (y, 1)) == CONST_INT)
+               return fold_rtx (plus_constant (y, -INTVAL (const_arg1)),
+                                NULL_RTX);
+           }
 
          /* ... fall through ... */
 
-       case MINUS:
+       from_plus:
        case SMIN:    case SMAX:      case UMIN:    case UMAX:
        case IOR:     case AND:       case XOR:
        case MULT:    case DIV:       case UDIV:
@@ -4892,11 +5300,7 @@ fold_rtx (x, insn)
              if (! reg_mentioned_p (folded_arg0, y))
                y = fold_rtx (y, insn);
 
-             new = simplify_binary_operation (code, mode, y, new_const);
-             if (new)
-               return new;
-
-             return gen_rtx (code, mode, y, new_const);
+             return cse_gen_binary (code, mode, y, new_const);
            }
        }
 
@@ -4949,7 +5353,7 @@ equiv_constant (x)
     {
       struct table_elt *elt;
 
-      x = fold_rtx (x, 0);
+      x = fold_rtx (x, NULL_RTX);
       if (CONSTANT_P (x))
        return x;
 
@@ -5029,7 +5433,7 @@ record_jump_equiv (insn, taken)
 {
   int cond_known_true;
   rtx op0, op1;
-  enum machine_mode mode;
+  enum machine_mode mode, mode0, mode1;
   int reversed_nonequality = 0;
   enum rtx_code code;
 
@@ -5050,7 +5454,7 @@ record_jump_equiv (insn, taken)
   op0 = fold_rtx (XEXP (XEXP (SET_SRC (PATTERN (insn)), 0), 0), insn);
   op1 = fold_rtx (XEXP (XEXP (SET_SRC (PATTERN (insn)), 0), 1), insn);
 
-  code = find_comparison_args (code, &op0, &op1);
+  code = find_comparison_args (code, &op0, &op1, &mode0, &mode1);
   if (! cond_known_true)
     {
       reversed_nonequality = (code != EQ && code != NE);
@@ -5058,8 +5462,9 @@ record_jump_equiv (insn, taken)
     }
 
   /* The mode is the mode of the non-constant.  */
-  mode = GET_MODE (op0);
-  if (mode == VOIDmode) mode = GET_MODE (op1);
+  mode = mode0;
+  if (mode1 != VOIDmode)
+    mode = mode1;
 
   record_jump_cond (code, mode, op0, op1, reversed_nonequality);
 }
@@ -5085,8 +5490,10 @@ record_jump_cond (code, mode, op0, op1, reversed_nonequality)
      true for all smaller modes whether or not there is a SUBREG, but
      is not worth testing for with no SUBREG.  */
 
+  /* Note that GET_MODE (op0) may not equal MODE.  */
   if (code == EQ && GET_CODE (op0) == SUBREG
-      && GET_MODE_SIZE (mode) > GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0))))
+      && (GET_MODE_SIZE (GET_MODE (op0))
+         > GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0)))))
     {
       enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op0));
       rtx tem = gen_lowpart_if_possible (inner_mode, op1);
@@ -5097,7 +5504,8 @@ record_jump_cond (code, mode, op0, op1, reversed_nonequality)
     }
 
   if (code == EQ && GET_CODE (op1) == SUBREG
-      && GET_MODE_SIZE (mode) > GET_MODE_SIZE (GET_MODE (SUBREG_REG (op1))))
+      && (GET_MODE_SIZE (GET_MODE (op1))
+         > GET_MODE_SIZE (GET_MODE (SUBREG_REG (op1)))))
     {
       enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op1));
       rtx tem = gen_lowpart_if_possible (inner_mode, op0);
@@ -5110,9 +5518,14 @@ record_jump_cond (code, mode, op0, op1, reversed_nonequality)
   /* Similarly, if this is an NE comparison, and either is a SUBREG 
      making a smaller mode, we know the whole thing is also NE.  */
 
+  /* Note that GET_MODE (op0) may not equal MODE;
+     if we test MODE instead, we can get an infinite recursion
+     alternating between two modes each wider than MODE.  */
+
   if (code == NE && GET_CODE (op0) == SUBREG
       && subreg_lowpart_p (op0)
-      && GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0))))
+      && (GET_MODE_SIZE (GET_MODE (op0))
+         < GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0)))))
     {
       enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op0));
       rtx tem = gen_lowpart_if_possible (inner_mode, op1);
@@ -5124,7 +5537,8 @@ record_jump_cond (code, mode, op0, op1, reversed_nonequality)
 
   if (code == NE && GET_CODE (op1) == SUBREG
       && subreg_lowpart_p (op1)
-      && GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (SUBREG_REG (op1))))
+      && (GET_MODE_SIZE (GET_MODE (op1))
+         < GET_MODE_SIZE (GET_MODE (SUBREG_REG (op1)))))
     {
       enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op1));
       rtx tem = gen_lowpart_if_possible (inner_mode, op0);
@@ -5161,8 +5575,12 @@ record_jump_cond (code, mode, op0, op1, reversed_nonequality)
   op1_elt = lookup (op1, op1_hash_code, mode);
 
   /* If we aren't setting two things equal all we can do is save this
-     comparison.  */
-  if (code != EQ)
+     comparison.   Similarly if this is floating-point.  In the latter
+     case, OP1 might be zero and both -0.0 and 0.0 are equal to it.
+     If we record the equality, we might inadvertently delete code
+     whose intent was to change -0 to +0.  */
+
+  if (code != EQ || GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT)
     {
       /* If we reversed a floating-point comparison, if OP0 is not a
         register, or if OP1 is neither a register or constant, we can't
@@ -5179,13 +5597,13 @@ record_jump_cond (code, mode, op0, op1, reversed_nonequality)
         new quantity number.  */
       if (op0_elt == 0)
        {
-         if (insert_regs (op0, 0, 0))
+         if (insert_regs (op0, NULL_PTR, 0))
            {
              rehash_using_reg (op0);
              op0_hash_code = HASH (op0, mode);
            }
 
-         op0_elt = insert (op0, 0, op0_hash_code, mode);
+         op0_elt = insert (op0, NULL_PTR, op0_hash_code, mode);
          op0_elt->in_memory = op0_in_memory;
          op0_elt->in_struct = op0_in_struct;
        }
@@ -5196,13 +5614,13 @@ record_jump_cond (code, mode, op0, op1, reversed_nonequality)
          /* Put OP1 in the hash table so it gets a new quantity number.  */
          if (op1_elt == 0)
            {
-             if (insert_regs (op1, 0, 0))
+             if (insert_regs (op1, NULL_PTR, 0))
                {
                  rehash_using_reg (op1);
                  op1_hash_code = HASH (op1, mode);
                }
 
-             op1_elt = insert (op1, 0, op1_hash_code, mode);
+             op1_elt = insert (op1, NULL_PTR, op1_hash_code, mode);
              op1_elt->in_memory = op1_in_memory;
              op1_elt->in_struct = op1_in_struct;
            }
@@ -5354,7 +5772,8 @@ cse_insn (insn, in_libcall_block)
         The hard function value register is used only once, to copy to
         someplace else, so it isn't worth cse'ing (and on 80386 is unsafe)!
         Ensure we invalidate the destination register.  On the 80386 no
-        other code would invalidate it since it is a fixed_reg.  */
+        other code would invalidate it since it is a fixed_reg.
+        We need not check the return of apply_change_group; see canon_reg. */
 
       else if (GET_CODE (SET_SRC (x)) == CALL)
        {
@@ -5397,7 +5816,8 @@ cse_insn (insn, in_libcall_block)
          register rtx y = XVECEXP (x, 0, i);
          if (GET_CODE (y) == SET)
            {
-             /* As above, we ignore unconditional jumps and call-insns. */
+             /* As above, we ignore unconditional jumps and call-insns and
+                ignore the result of apply_change_group.  */
              if (GET_CODE (SET_SRC (y)) == CALL)
                {
                  canon_reg (SET_SRC (y), insn);
@@ -5419,16 +5839,18 @@ cse_insn (insn, in_libcall_block)
                 because we have already invalidated the reg.  */
              if (GET_CODE (XEXP (y, 0)) == MEM)
                {
-                 canon_reg (XEXP (y, 0), 0);
+                 canon_reg (XEXP (y, 0), NULL_RTX);
                  note_mem_written (XEXP (y, 0), &writes_memory);
                }
            }
          else if (GET_CODE (y) == USE
                   && ! (GET_CODE (XEXP (y, 0)) == REG
                         && REGNO (XEXP (y, 0)) < FIRST_PSEUDO_REGISTER))
-           canon_reg (y, 0);
+           canon_reg (y, NULL_RTX);
          else if (GET_CODE (y) == CALL)
            {
+             /* The result of apply_change_group can be ignored; see
+                canon_reg.  */
              canon_reg (y, insn);
              apply_change_group ();
              fold_rtx (y, insn);
@@ -5439,7 +5861,7 @@ cse_insn (insn, in_libcall_block)
     {
       if (GET_CODE (XEXP (x, 0)) == MEM)
        {
-         canon_reg (XEXP (x, 0), 0);
+         canon_reg (XEXP (x, 0), NULL_RTX);
          note_mem_written (XEXP (x, 0), &writes_memory);
        }
     }
@@ -5448,9 +5870,10 @@ cse_insn (insn, in_libcall_block)
   else if (GET_CODE (x) == USE
           && ! (GET_CODE (XEXP (x, 0)) == REG
                 && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER))
-    canon_reg (XEXP (x, 0), 0);
+    canon_reg (XEXP (x, 0), NULL_RTX);
   else if (GET_CODE (x) == CALL)
     {
+      /* The result of apply_change_group can be ignored; see canon_reg.  */
       canon_reg (x, insn);
       apply_change_group ();
       fold_rtx (x, insn);
@@ -5459,10 +5882,10 @@ cse_insn (insn, in_libcall_block)
   if (n_sets == 1 && REG_NOTES (insn) != 0)
     {
       /* Store the equivalent value in SRC_EQV, if different.  */
-      rtx tem = find_reg_note (insn, REG_EQUAL, 0);
+      rtx tem = find_reg_note (insn, REG_EQUAL, NULL_RTX);
 
       if (tem && ! rtx_equal_p (XEXP (tem, 0), SET_SRC (sets[0].rtl)))
-        src_eqv = canon_reg (XEXP (tem, 0), 0);
+        src_eqv = canon_reg (XEXP (tem, 0), NULL_RTX);
     }
 
   /* Canonicalize sources and addresses of destinations.
@@ -5510,7 +5933,9 @@ cse_insn (insn, in_libcall_block)
      group and see if they all work.  Note that this will cause some
      canonicalizations that would have worked individually not to be applied
      because some other canonicalization didn't work, but this should not
-     occur often.  */
+     occur often. 
+
+     The result of apply_change_group can be ignored; see canon_reg.  */
 
   apply_change_group ();
 
@@ -5589,10 +6014,11 @@ cse_insn (insn, in_libcall_block)
 
          if (GET_CODE (src) == CONST_INT
              && GET_CODE (width) == CONST_INT
-             && INTVAL (width) < HOST_BITS_PER_INT
-             && (INTVAL (src) & ((-1) << INTVAL (width))))
-           src_folded = gen_rtx (CONST_INT, VOIDmode,
-                                 INTVAL (src) & ((1 << INTVAL (width)) - 1));
+             && INTVAL (width) < HOST_BITS_PER_WIDE_INT
+             && (INTVAL (src) & ((HOST_WIDE_INT) (-1) << INTVAL (width))))
+           src_folded
+             = GEN_INT (INTVAL (src) & (((HOST_WIDE_INT) 1
+                                         << INTVAL (width)) - 1));
        }
 
       /* Compute SRC's hash code, and also notice if it
@@ -5608,6 +6034,10 @@ cse_insn (insn, in_libcall_block)
       sets[i].src_in_memory = hash_arg_in_memory;
       sets[i].src_in_struct = hash_arg_in_struct;
 
+#if 0
+      /* It is no longer clear why we used to do this, but it doesn't
+        appear to still be needed.  So let's try without it since this
+        code hurts cse'ing widened ops.  */
       /* If source is a perverse subreg (such as QI treated as an SI),
         treat it as volatile.  It may do the work of an SI in one context
         where the extra bits are not being used, but cannot replace an SI
@@ -5616,6 +6046,7 @@ cse_insn (insn, in_libcall_block)
          && (GET_MODE_SIZE (GET_MODE (src))
              > GET_MODE_SIZE (GET_MODE (SUBREG_REG (src)))))
        sets[i].src_volatile = 1;
+#endif
 
       /* Locate all possible equivalent forms for SRC.  Try to replace
          SRC in the insn with each cheaper equivalent.
@@ -5729,6 +6160,37 @@ cse_insn (insn, in_libcall_block)
            }
         }
 
+      /* See if we have a CONST_INT that is already in a register in a
+        wider mode.  */
+
+      if (src_const && src_related == 0 && GET_CODE (src_const) == CONST_INT
+         && GET_MODE_CLASS (mode) == MODE_INT
+         && GET_MODE_BITSIZE (mode) < BITS_PER_WORD)
+       {
+         enum machine_mode wider_mode;
+
+         for (wider_mode = GET_MODE_WIDER_MODE (mode);
+              GET_MODE_BITSIZE (wider_mode) <= BITS_PER_WORD
+              && src_related == 0;
+              wider_mode = GET_MODE_WIDER_MODE (wider_mode))
+           {
+             struct table_elt *const_elt
+               = lookup (src_const, HASH (src_const, wider_mode), wider_mode);
+
+             if (const_elt == 0)
+               continue;
+
+             for (const_elt = const_elt->first_same_value;
+                  const_elt; const_elt = const_elt->next_same_value)
+               if (GET_CODE (const_elt->exp) == REG)
+                 {
+                   src_related = gen_lowpart_if_possible (mode,
+                                                          const_elt->exp);
+                   break;
+                 }
+           }
+       }
+
       /* Another possibility is that we have an AND with a constant in
         a mode narrower than a word.  If so, it might have been generated
         as part of an "if" which would narrow the AND.  If we already
@@ -5740,7 +6202,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, 0, 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;
@@ -5934,7 +6396,13 @@ 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))
            {
-             SET_SRC (sets[i].rtl) = canon_reg (SET_SRC (sets[i].rtl), insn);
+             /* The result of apply_change_group can be ignored; see
+                canon_reg.  */
+
+             validate_change (insn, &SET_SRC (sets[i].rtl),
+                              canon_reg (SET_SRC (sets[i].rtl), insn),
+                              1);
+             apply_change_group ();
              break;
            }
 
@@ -6010,7 +6478,7 @@ cse_insn (insn, in_libcall_block)
       if (n_sets == 1 && src_const && GET_CODE (dest) == REG
          && GET_CODE (src_const) != REG)
        {
-         rtx tem = find_reg_note (insn, REG_EQUAL, 0);
+         rtx tem = find_reg_note (insn, REG_EQUAL, NULL_RTX);
          
          /* Record the actual constant value in a REG_EQUAL note, making
             a new one if one does not already exist.  */
@@ -6035,7 +6503,7 @@ cse_insn (insn, in_libcall_block)
              && 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, 0);
+             rtx note = find_reg_note (insn, REG_WAS_0, NULL_RTX);
              rtx const_insn = qty_const_insn[reg_qty[REGNO (dest)]];
 
              if ((tem = single_set (const_insn)) != 0
@@ -6095,8 +6563,9 @@ cse_insn (insn, in_libcall_block)
 
          if (src_const != 0 && GET_CODE (src_const) == CONST_INT
              && GET_CODE (width) == CONST_INT
-             && INTVAL (width) < HOST_BITS_PER_INT
-             && ! (INTVAL (src_const) & ((-1) << INTVAL (width))))
+             && INTVAL (width) < HOST_BITS_PER_WIDE_INT
+             && ! (INTVAL (src_const)
+                   & ((HOST_WIDE_INT) (-1) << INTVAL (width))))
            /* Exception: if the value is constant,
               and it won't be truncated, record it.  */
            ;
@@ -6144,6 +6613,13 @@ cse_insn (insn, in_libcall_block)
              delete_insn (insn);
              insn = new;
            }
+         else
+           /* Otherwise, force rerecognition, since it probably had
+              a different pattern before.
+              This shouldn't really be necessary, since whatever
+              changed the source value above should have done this.
+              Until the right place is found, might as well do this here.  */
+           INSN_CODE (insn) = -1;
 
          /* Now that we've converted this jump to an unconditional jump,
             there is dead code after it.  Delete the dead code until we
@@ -6504,7 +6980,7 @@ cse_insn (insn, in_libcall_block)
          && SET_DEST (PATTERN (prev)) == SET_SRC (sets[0].rtl))
        {
          rtx dest = SET_DEST (sets[0].rtl);
-         rtx note = find_reg_note (prev, REG_EQUIV, 0);
+         rtx note = find_reg_note (prev, REG_EQUIV, NULL_RTX);
 
          validate_change (prev, & SET_DEST (PATTERN (prev)), dest, 1);
          validate_change (insn, & SET_DEST (sets[0].rtl),
@@ -6518,11 +6994,11 @@ cse_insn (insn, in_libcall_block)
 
          /* If there was a REG_WAS_0 note on PREV, remove it.  Move
             any REG_WAS_0 note on INSN to PREV.  */
-         note = find_reg_note (prev, REG_WAS_0, 0);
+         note = find_reg_note (prev, REG_WAS_0, NULL_RTX);
          if (note)
            remove_note (prev, note);
 
-         note = find_reg_note (insn, REG_WAS_0, 0);
+         note = find_reg_note (insn, REG_WAS_0, NULL_RTX);
          if (note)
            {
              remove_note (insn, note);
@@ -6593,9 +7069,12 @@ note_mem_written (written, writes_ptr)
        {
          /* 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.  */
-         if (!(MEM_IN_STRUCT_P (written)
-               || GET_CODE (XEXP (written, 0)) == PLUS))
+            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.  */
+         if (! ((MEM_IN_STRUCT_P (written)
+                 || GET_CODE (XEXP (written, 0)) == PLUS)
+                && GET_MODE (written) != QImode))
            writes_ptr->all = 1;
          writes_ptr->nonscalar = 1;
        }
@@ -6697,9 +7176,9 @@ cse_process_notes (x, object)
     case EXPR_LIST:
     case INSN_LIST:
       if (REG_NOTE_KIND (x) == REG_EQUAL)
-       XEXP (x, 0) = cse_process_notes (XEXP (x, 0), 0);
+       XEXP (x, 0) = cse_process_notes (XEXP (x, 0), NULL_RTX);
       if (XEXP (x, 1))
-       XEXP (x, 1) = cse_process_notes (XEXP (x, 1), 0);
+       XEXP (x, 1) = cse_process_notes (XEXP (x, 1), NULL_RTX);
       return x;
 
     case SIGN_EXTEND:
@@ -6728,7 +7207,7 @@ cse_process_notes (x, object)
        }
 
       /* Otherwise, canonicalize this register.  */
-      return canon_reg (x, 0);
+      return canon_reg (x, NULL_RTX);
     }
 
   for (i = 0; i < GET_RTX_LENGTH (code); i++)
@@ -6775,7 +7254,7 @@ cse_around_loop (loop_start)
 
   /* If the last insn of the loop (the end test) was an NE comparison,
      we will interpret it as an EQ comparison, since we fell through
-     the loop.  Any equivalances resulting from that comparison are
+     the loop.  Any equivalences resulting from that comparison are
      therefore not valid and must be invalidated.  */
   if (last_jump_equiv_class)
     for (p = last_jump_equiv_class->first_same_value; p;
@@ -7006,32 +7485,6 @@ cse_set_around_loop (x, insn, loop_start)
    the current block.  The incoming structure's branch path, if any, is used
    to construct the output branch path.  */
 
-/* Define maximum length of a branch path.  */
-
-#define PATHLENGTH     20
-
-struct cse_basic_block_data {
-  /* Lowest CUID value of insns in block.  */
-  int low_cuid;
-  /* Highest CUID value of insns in block.  */
-  int high_cuid;
-  /* Total number of SETs in block.  */
-  int nsets;
-  /* Last insn in the block.  */
-  rtx last;
-  /* Size of current branch path, if any.  */
-  int path_size;
-  /* Current branch path, indicating which branches will be taken.  */
-  struct branch_path {
-    /* The branch insn. */
-    rtx branch;
-    /* Whether it should be taken or not.  AROUND is the same as taken
-       except that it is used when the destination label is not preceded
-       by a BARRIER.  */
-    enum taken {TAKEN, NOT_TAKEN, AROUND} status;
-  } path[PATHLENGTH];
-};
-
 void
 cse_end_of_basic_block (insn, data, follow_jumps, after_loop, skip_blocks)
      rtx insn;
@@ -7098,10 +7551,13 @@ cse_end_of_basic_block (insn, data, follow_jumps, after_loop, skip_blocks)
       else if (GET_CODE (p) != NOTE)
        nsets += 1;
        
-      if (INSN_CUID (p) > high_cuid)
+      /* Ignore insns made by CSE; they cannot affect the boundaries of
+        the basic block.  */
+
+      if (INSN_UID (p) <= max_uid && INSN_CUID (p) > high_cuid)
        high_cuid = INSN_CUID (p);
-      if (INSN_CUID (p) < low_cuid)
-       low_cuid = INSN_CUID(p);
+      if (INSN_UID (p) <= max_uid && INSN_CUID (p) < low_cuid)
+       low_cuid = INSN_CUID (p);
 
       /* See if this insn is in our branch path.  If it is and we are to
         take it, do so.  */
@@ -7231,8 +7687,6 @@ cse_end_of_basic_block (insn, data, follow_jumps, after_loop, skip_blocks)
   data->path[path_size].branch = 0;
 }
 \f
-static rtx cse_basic_block ();
-
 /* Perform cse on the instructions of a function.
    F is the first instruction.
    NREGS is one plus the highest pseudo-reg number used in the instruction.
@@ -7285,9 +7739,9 @@ cse_main (f, nregs, after_loop, file)
 
   /* Find the largest uid.  */
 
-  i = get_max_uid ();
-  uid_cuid = (short *) alloca ((i + 1) * sizeof (short));
-  bzero (uid_cuid, (i + 1) * sizeof (short));
+  max_uid = get_max_uid ();
+  uid_cuid = (int *) alloca ((max_uid + 1) * sizeof (int));
+  bzero (uid_cuid, (max_uid + 1) * sizeof (int));
 
   /* Compute the mapping from uids to cuids.
      CUIDs are numbers assigned to insns, like uids,
@@ -7486,7 +7940,7 @@ cse_basic_block (from, to, next_branch, around_loop)
             looking for duplicate operations.  */
 
          if (REG_NOTES (insn))
-           REG_NOTES (insn) = cse_process_notes (REG_NOTES (insn), 0);
+           REG_NOTES (insn) = cse_process_notes (REG_NOTES (insn), NULL_RTX);
 
          /* Track when we are inside in LIBCALL block.  Inside such a block,
             we do not want to record destinations.  The last insn of a
@@ -7494,9 +7948,9 @@ 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, 0))
+         if (find_reg_note (insn, REG_LIBCALL, NULL_RTX))
            in_libcall_block = 1;
-         else if (find_reg_note (insn, REG_RETVAL, 0))
+         else if (find_reg_note (insn, REG_RETVAL, NULL_RTX))
            in_libcall_block = 0;
 
          cse_insn (insn, in_libcall_block);
@@ -7701,7 +8155,7 @@ delete_dead_from_cse (insns, nreg)
       /* Don't delete any insns that are part of a 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, 0))
+      if (find_reg_note (insn, REG_RETVAL, NULL_RTX))
        in_libcall = 1;
 
       if (in_libcall)
@@ -7766,7 +8220,7 @@ delete_dead_from_cse (insns, nreg)
          delete_insn (insn);
        }
 
-      if (find_reg_note (insn, REG_LIBCALL, 0))
+      if (find_reg_note (insn, REG_LIBCALL, NULL_RTX))
        in_libcall = 0;
     }
 }
This page took 0.117213 seconds and 5 git commands to generate.