]> gcc.gnu.org Git - gcc.git/blobdiff - gcc/cse.c
(call_insn_operand): New funcion.
[gcc.git] / gcc / cse.c
index 7f1ff1c7b88f740f55266912ff5f309caf22bdb9..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.
 
@@ -328,6 +328,9 @@ static int cse_basic_block_end;
 
 static int *uid_cuid;
 
+/* Highest UID in UID_CUID.  */
+static int max_uid;
+
 /* Get the cuid of an insn.  */
 
 #define INSN_CUID(INSN) (uid_cuid[INSN_UID (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.  */
@@ -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;
@@ -1386,8 +1466,8 @@ invalidate (x)
 {
   register int i;
   register struct table_elt *p;
-  register rtx base;
-  register HOST_WIDE_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;
@@ -2098,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;
 {
@@ -2147,20 +2200,87 @@ 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;
      HOST_WIDE_INT start, end;
@@ -2184,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)
-           {
-             HOST_WIDE_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)
-           {
-             HOST_WIDE_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.  */
@@ -2326,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)
@@ -2386,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;
@@ -2418,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;
@@ -2584,11 +2645,7 @@ find_best_addr (insn, loc)
                && (GET_CODE (p->exp) == REG
                    || exp_equiv_p (p->exp, p->exp, 1, 0)))
              {
-               rtx new = simplify_binary_operation (GET_CODE (*loc), Pmode,
-                                                    p->exp, c);
-
-               if (new == 0)
-                 new = gen_rtx (GET_CODE (*loc), Pmode, p->exp, c);
+               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
@@ -3066,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:
@@ -3074,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:
@@ -3183,6 +3240,7 @@ simplify_binary_operation (code, mode, op0, op1)
   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.
@@ -3211,7 +3269,7 @@ simplify_binary_operation (code, mode, op0, op1)
       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)
        {
@@ -3246,11 +3304,12 @@ simplify_binary_operation (code, mode, op0, op1)
       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))
     {
       HOST_WIDE_INT l1, l2, h1, h2, lv, hv;
 
@@ -3363,7 +3422,6 @@ 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_WIDE_INT || width == 0)
@@ -3383,85 +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;
-
-         /* (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);
+         /* 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.  */
 
-         /* (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
-               break;
-#if 0 /* No good, because this can produce the sum of two relocatable
-        symbols, in an assembler instruction.  Most UNIX assemblers can't
-        handle that.  */
-             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));
-#endif
-           }
-         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:
@@ -3485,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)
@@ -3647,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);
            }
@@ -3674,15 +3566,23 @@ simplify_binary_operation (code, mode, op0, op1)
              && 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;
@@ -3698,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;
 
@@ -3708,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;
 
@@ -3718,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;
 
@@ -3759,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
@@ -3816,7 +3720,8 @@ simplify_binary_operation (code, mode, op0, op1)
           
        case SMAX:
          if (width <= HOST_BITS_PER_WIDE_INT && GET_CODE (op1) == CONST_INT
-             && INTVAL (op1) == GET_MODE_MASK (mode) >> 1
+             && (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))
@@ -3964,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:
@@ -4021,6 +3932,220 @@ simplify_binary_operation (code, mode, op0, op1)
   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);
+  
+  /* 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.
    MODE is the mode of the operands, not that of the result.  */
 
@@ -4038,8 +4163,17 @@ simplify_relational_operation (code, mode, op0, op1)
   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_WIDE_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.  */
@@ -4051,6 +4185,8 @@ 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)
@@ -4086,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:
@@ -4313,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.  */
@@ -5024,7 +5213,8 @@ fold_rtx (x, insn)
            {
              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)));
+               return fold_rtx (plus_constant (y, -INTVAL (const_arg1)),
+                                NULL_RTX);
            }
 
          /* ... fall through ... */
@@ -5110,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);
            }
        }
 
@@ -5304,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);
@@ -5316,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);
@@ -5329,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);
@@ -5343,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);
@@ -5577,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)
        {
@@ -5620,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);
@@ -5652,6 +5849,8 @@ cse_insn (insn, in_libcall_block)
            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);
@@ -5674,6 +5873,7 @@ cse_insn (insn, in_libcall_block)
     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);
@@ -5733,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 ();
 
@@ -6194,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;
            }
 
@@ -6405,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
@@ -6854,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;
        }
@@ -6995,7 +7213,7 @@ cse_process_notes (x, object)
   for (i = 0; i < GET_RTX_LENGTH (code); i++)
     if (fmt[i] == 'e')
       validate_change (object, &XEXP (x, i),
-                      cse_process_notes (XEXP (x, i), object), NULL_RTX);
+                      cse_process_notes (XEXP (x, i), object), 0);
 
   return x;
 }
@@ -7267,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;
@@ -7359,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.  */
@@ -7492,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.
@@ -7546,9 +7739,9 @@ cse_main (f, nregs, after_loop, file)
 
   /* Find the largest uid.  */
 
-  i = get_max_uid ();
-  uid_cuid = (int *) alloca ((i + 1) * sizeof (int));
-  bzero (uid_cuid, (i + 1) * sizeof (int));
+  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,
This page took 0.066385 seconds and 5 git commands to generate.