]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
simplify-rtx.c: New file.
authorJeffrey A Law <law@cygnus.com>
Mon, 1 Nov 1999 00:18:23 +0000 (00:18 +0000)
committerJeff Law <law@gcc.gnu.org>
Mon, 1 Nov 1999 00:18:23 +0000 (17:18 -0700)
        * simplify-rtx.c: New file.
        * Makefile.in (OBJS): Add simplify-rtx.o
        (simplify-rtx.o): Add dependencies.
        * rtl.h (simplify_gen_binary, simplify_rtx): Add prototypes.
        * cse.c: Use simplify_gen_binary intead of cse_gen_binary.
        (cse_gen_binary, simplify_unary_operation): Delete.
        (simplify_binary_operation, simplify_plus_minus): Likewise.
        (check_fold_consts, simplify_relation_operation): Likewise.
        (simplify_ternary_operation): Likewise.
        (delete_trivially_dead_insns): Simplify the contents of the
        REG_EQUAL note before trying to substitute it into the source
        of the reg-reg copy at the end of a libcall sequence.

From-SVN: r30295

gcc/ChangeLog
gcc/Makefile.in
gcc/cse.c
gcc/rtl.h
gcc/simplify-rtx.c [new file with mode: 0644]

index cc4971b173b1508f3b64c309d1440f8f47ac14c8..1df4e23fd9dd22c0f796d9b997ea7305524698c8 100644 (file)
@@ -7,6 +7,19 @@ Sun Oct 31 13:32:15 CET 1999  Marc Lehmann <pcg@goof.com>
 
 Sun Oct 31 01:53:30 1999  Jeffrey A Law  (law@cygnus.com)
 
+       * simplify-rtx.c: New file.
+       * Makefile.in (OBJS): Add simplify-rtx.o
+       (simplify-rtx.o): Add dependencies.
+       * rtl.h (simplify_gen_binary, simplify_rtx): Add prototypes.
+       * cse.c: Use simplify_gen_binary intead of cse_gen_binary.
+       (cse_gen_binary, simplify_unary_operation): Delete.
+       (simplify_binary_operation, simplify_plus_minus): Likewise.
+       (check_fold_consts, simplify_relation_operation): Likewise.
+       (simplify_ternary_operation): Likewise.
+       (delete_trivially_dead_insns): Simplify the contents of the
+       REG_EQUAL note before trying to substitute it into the source
+       of the reg-reg copy at the end of a libcall sequence.
+
        * combine.c (combine_simplify_rtx): Renamed from simplify_rtx.  All
        references/callers changed.
 
index fd9847e5653cebf5cbac6652522c9beb3b8eb28a..3773f9b53a044ea56a7dd8e4e033b6eb3028bf55 100644 (file)
@@ -667,7 +667,7 @@ OBJS = toplev.o version.o tree.o print-tree.o stor-layout.o fold-const.o \
  insn-opinit.o insn-recog.o insn-extract.o insn-output.o insn-emit.o lcm.o \
  profile.o insn-attrtab.o $(out_object_file) $(EXTRA_OBJS) convert.o \
  mbchar.o dyn-string.o splay-tree.o graph.o sbitmap.o resource.o hash.o \
- lists.o ggc-common.o $(GGC)
+ lists.o ggc-common.o $(GGC) simplify-rtx.o
 
 # GEN files are listed separately, so they can be built before doing parallel
 #  makes for cc1 or cc1plus.  Otherwise sequent parallel make attempts to load
@@ -1532,6 +1532,9 @@ jump.o : jump.c $(CONFIG_H) system.h $(RTL_H) flags.h hard-reg-set.h $(REGS_H) \
 stupid.o : stupid.c $(CONFIG_H) system.h $(RTL_H) $(REGS_H) hard-reg-set.h \
    $(BASIC_BLOCK_H) insn-config.h reload.h flags.h function.h toplev.h
 
+simplify-rtx.o : simplify-rtx.c $(CONFIG_H) system.h $(RTL_H) $(REGS_H) \
+   hard-reg-set.h flags.h real.h insn-config.h $(RECOG_H) $(EXPR_H) toplev.h \
+   output.h function.h 
 cse.o : cse.c $(CONFIG_H) system.h $(RTL_H) $(REGS_H) hard-reg-set.h flags.h \
    real.h insn-config.h $(RECOG_H) $(EXPR_H) toplev.h output.h function.h \
    $(srcdir)/../include/hashtab.h ggc.h
index bc7bd659ba08b6d134108982966dc3be897436a8..1478556aa3822c5751688a046ca4e4c22813b343 100644 (file)
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -600,7 +600,12 @@ struct cse_basic_block_data {
 
 /* 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.  */
+   by integrate.c, which is called before virtual register instantiation. 
+
+   ?!? FIXED_BASE_PLUS_P and NONZERO_BASE_PLUS_P need to move into
+   a header file so that their definitions can be shared with the
+   simplification routines in simplify-rtx.c.  Until then, do not
+   change these macros without also changing the copy in simplify-rtx.c.  */
 
 #define FIXED_BASE_PLUS_P(X)                                   \
   ((X) == frame_pointer_rtx || (X) == hard_frame_pointer_rtx   \
@@ -679,8 +684,6 @@ 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));
@@ -3020,1991 +3023,207 @@ find_best_addr (insn, loc)
          /* This is at worst case an O(n^2) algorithm, so limit our search
             to the first 32 elements on the list.  This avoids trouble
             compiling code with very long basic blocks that can easily
-            call cse_gen_binary so many times that we run out of memory.  */
-
-         found_better = 0;
-         for (p = elt->first_same_value, count = 0;
-              p && count < 32;
-              p = p->next_same_value, count++)
-           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 ((CSE_ADDRESS_COST (new) < best_addr_cost
-                   || (CSE_ADDRESS_COST (new) == best_addr_cost
-                       && (COST (new) + 1) >> 1 > best_rtx_cost)))
-                 {
-                   found_better = 1;
-                   best_addr_cost = CSE_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
-}
-\f
-/* Given an operation (CODE, *PARG1, *PARG2), where code is a comparison
-   operation (EQ, NE, GT, etc.), follow it back through the hash table and
-   what values are being compared.
-
-   *PARG1 and *PARG2 are updated to contain the rtx representing the values
-   actually being compared.  For example, if *PARG1 was (cc0) and *PARG2
-   was (const_int 0), *PARG1 and *PARG2 will be set to the objects that were
-   compared to produce cc0.
-
-   The return value is the comparison operator and is either the code of
-   A or the code corresponding to the inverse of the comparison.  */
-
-static enum rtx_code
-find_comparison_args (code, parg1, parg2, pmode1, pmode2)
-     enum rtx_code code;
-     rtx *parg1, *parg2;
-     enum machine_mode *pmode1, *pmode2;
-{
-  rtx arg1, arg2;
-
-  arg1 = *parg1, arg2 = *parg2;
-
-  /* If ARG2 is const0_rtx, see what ARG1 is equivalent to.  */
-
-  while (arg2 == CONST0_RTX (GET_MODE (arg1)))
-    {
-      /* Set non-zero when we find something of interest.  */
-      rtx x = 0;
-      int reverse_code = 0;
-      struct table_elt *p = 0;
-
-      /* If arg1 is a COMPARE, extract the comparison arguments from it.
-        On machines with CC0, this is the only case that can occur, since
-        fold_rtx will return the COMPARE or item being compared with zero
-        when given CC0.  */
-
-      if (GET_CODE (arg1) == COMPARE && arg2 == const0_rtx)
-       x = arg1;
-
-      /* If ARG1 is a comparison operator and CODE is testing for
-        STORE_FLAG_VALUE, get the inner arguments.  */
-
-      else if (GET_RTX_CLASS (GET_CODE (arg1)) == '<')
-       {
-         if (code == NE
-             || (GET_MODE_CLASS (GET_MODE (arg1)) == MODE_INT
-                 && code == LT && STORE_FLAG_VALUE == -1)
-#ifdef FLOAT_STORE_FLAG_VALUE
-             || (GET_MODE_CLASS (GET_MODE (arg1)) == MODE_FLOAT
-                 && FLOAT_STORE_FLAG_VALUE < 0)
-#endif
-             )
-           x = arg1;
-         else if (code == EQ
-                  || (GET_MODE_CLASS (GET_MODE (arg1)) == MODE_INT
-                      && code == GE && STORE_FLAG_VALUE == -1)
-#ifdef FLOAT_STORE_FLAG_VALUE
-                  || (GET_MODE_CLASS (GET_MODE (arg1)) == MODE_FLOAT
-                      && FLOAT_STORE_FLAG_VALUE < 0)
-#endif
-                  )
-           x = arg1, reverse_code = 1;
-       }
-
-      /* ??? We could also check for
-
-        (ne (and (eq (...) (const_int 1))) (const_int 0))
-
-        and related forms, but let's wait until we see them occurring.  */
-
-      if (x == 0)
-       /* Look up ARG1 in the hash table and see if it has an equivalence
-          that lets us see what is being compared.  */
-       p = lookup (arg1, safe_hash (arg1, GET_MODE (arg1)) % NBUCKETS,
-                   GET_MODE (arg1));
-      if (p) p = p->first_same_value;
-
-      for (; p; p = p->next_same_value)
-       {
-         enum machine_mode inner_mode = GET_MODE (p->exp);
-
-         /* If the entry isn't valid, skip it.  */
-         if (! exp_equiv_p (p->exp, p->exp, 1, 0))
-           continue;
-
-         if (GET_CODE (p->exp) == COMPARE
-             /* Another possibility is that this machine has a compare insn
-                that includes the comparison code.  In that case, ARG1 would
-                be equivalent to a comparison operation that would set ARG1 to
-                either STORE_FLAG_VALUE or zero.  If this is an NE operation,
-                ORIG_CODE is the actual comparison being done; if it is an EQ,
-                we must reverse ORIG_CODE.  On machine with a negative value
-                for STORE_FLAG_VALUE, also look at LT and GE operations.  */
-             || ((code == NE
-                  || (code == LT
-                      && GET_MODE_CLASS (inner_mode) == MODE_INT
-                      && (GET_MODE_BITSIZE (inner_mode)
-                          <= HOST_BITS_PER_WIDE_INT)
-                      && (STORE_FLAG_VALUE
-                          & ((HOST_WIDE_INT) 1
-                             << (GET_MODE_BITSIZE (inner_mode) - 1))))
-#ifdef FLOAT_STORE_FLAG_VALUE
-                  || (code == LT
-                      && GET_MODE_CLASS (inner_mode) == MODE_FLOAT
-                      && FLOAT_STORE_FLAG_VALUE < 0)
-#endif
-                  )
-                 && GET_RTX_CLASS (GET_CODE (p->exp)) == '<'))
-           {
-             x = p->exp;
-             break;
-           }
-         else if ((code == EQ
-                   || (code == GE
-                       && GET_MODE_CLASS (inner_mode) == MODE_INT
-                       && (GET_MODE_BITSIZE (inner_mode)
-                           <= HOST_BITS_PER_WIDE_INT)
-                       && (STORE_FLAG_VALUE
-                           & ((HOST_WIDE_INT) 1
-                              << (GET_MODE_BITSIZE (inner_mode) - 1))))
-#ifdef FLOAT_STORE_FLAG_VALUE
-                   || (code == GE
-                       && GET_MODE_CLASS (inner_mode) == MODE_FLOAT
-                       && FLOAT_STORE_FLAG_VALUE < 0)
-#endif
-                   )
-                  && GET_RTX_CLASS (GET_CODE (p->exp)) == '<')
-           {
-             reverse_code = 1;
-             x = p->exp;
-             break;
-           }
-
-         /* If this is fp + constant, the equivalent is a better operand since
-            it may let us predict the value of the comparison.  */
-         else if (NONZERO_BASE_PLUS_P (p->exp))
-           {
-             arg1 = p->exp;
-             continue;
-           }
-       }
-
-      /* If we didn't find a useful equivalence for ARG1, we are done.
-        Otherwise, set up for the next iteration.  */
-      if (x == 0)
-       break;
-
-      arg1 = XEXP (x, 0),  arg2 = XEXP (x, 1);
-      if (GET_RTX_CLASS (GET_CODE (x)) == '<')
-       code = GET_CODE (x);
-
-      if (reverse_code)
-       code = reverse_condition (code);
-    }
-
-  /* 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;
-}
-\f
-/* Try to simplify a unary operation CODE whose output mode is to be
-   MODE with input operand OP whose mode was originally OP_MODE.
-   Return zero if no simplification can be made.  */
-
-rtx
-simplify_unary_operation (code, mode, op, op_mode)
-     enum rtx_code code;
-     enum machine_mode mode;
-     rtx op;
-     enum machine_mode op_mode;
-{
-  register int width = GET_MODE_BITSIZE (mode);
-
-  /* The order of these tests is critical so that, for example, we don't
-     check the wrong mode (input vs. output) for a conversion operation,
-     such as FIX.  At some point, this should be simplified.  */
-
-#if !defined(REAL_IS_NOT_DOUBLE) || defined(REAL_ARITHMETIC)
-
-  if (code == FLOAT && GET_MODE (op) == VOIDmode
-      && (GET_CODE (op) == CONST_DOUBLE || GET_CODE (op) == CONST_INT))
-    {
-      HOST_WIDE_INT hv, lv;
-      REAL_VALUE_TYPE d;
-
-      if (GET_CODE (op) == CONST_INT)
-       lv = INTVAL (op), hv = INTVAL (op) < 0 ? -1 : 0;
-      else
-       lv = CONST_DOUBLE_LOW (op),  hv = CONST_DOUBLE_HIGH (op);
-
-#ifdef REAL_ARITHMETIC
-      REAL_VALUE_FROM_INT (d, lv, hv, mode);
-#else
-      if (hv < 0)
-       {
-         d = (double) (~ hv);
-         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) (~ lv);
-         d = (- d - 1.0);
-       }
-      else
-       {
-         d = (double) hv;
-         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) lv;
-       }
-#endif  /* REAL_ARITHMETIC */
-      d = real_value_truncate (mode, d);
-      return CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
-    }
-  else if (code == UNSIGNED_FLOAT && GET_MODE (op) == VOIDmode
-          && (GET_CODE (op) == CONST_DOUBLE || GET_CODE (op) == CONST_INT))
-    {
-      HOST_WIDE_INT hv, lv;
-      REAL_VALUE_TYPE d;
-
-      if (GET_CODE (op) == CONST_INT)
-       lv = INTVAL (op), hv = INTVAL (op) < 0 ? -1 : 0;
-      else
-       lv = CONST_DOUBLE_LOW (op),  hv = CONST_DOUBLE_HIGH (op);
-
-      if (op_mode == VOIDmode)
-       {
-         /* We don't know how to interpret negative-looking numbers in
-            this case, so don't try to fold those.  */
-         if (hv < 0)
-           return 0;
-       }
-      else if (GET_MODE_BITSIZE (op_mode) >= HOST_BITS_PER_WIDE_INT * 2)
-       ;
-      else
-       hv = 0, lv &= GET_MODE_MASK (op_mode);
-
-#ifdef REAL_ARITHMETIC
-      REAL_VALUE_FROM_UNSIGNED_INT (d, lv, hv, mode);
-#else
-
-      d = (double) (unsigned HOST_WIDE_INT) hv;
-      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) lv;
-#endif  /* REAL_ARITHMETIC */
-      d = real_value_truncate (mode, d);
-      return CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
-    }
-#endif
-
-  if (GET_CODE (op) == CONST_INT
-      && width <= HOST_BITS_PER_WIDE_INT && width > 0)
-    {
-      register HOST_WIDE_INT arg0 = INTVAL (op);
-      register HOST_WIDE_INT val;
-
-      switch (code)
-       {
-       case NOT:
-         val = ~ arg0;
-         break;
-
-       case NEG:
-         val = - arg0;
-         break;
-
-       case ABS:
-         val = (arg0 >= 0 ? arg0 : - arg0);
-         break;
-
-       case FFS:
-         /* Don't use ffs here.  Instead, get low order bit and then its
-            number.  If arg0 is zero, this will return 0, as desired.  */
-         arg0 &= GET_MODE_MASK (mode);
-         val = exact_log2 (arg0 & (- arg0)) + 1;
-         break;
-
-       case TRUNCATE:
-         val = arg0;
-         break;
-
-       case ZERO_EXTEND:
-         if (op_mode == VOIDmode)
-           op_mode = 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;
-
-       case SIGN_EXTEND:
-         if (op_mode == VOIDmode)
-           op_mode = 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));
-             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;
-         break;
-
-       case SQRT:
-         return 0;
-
-       default:
-         abort ();
-       }
-
-      val = trunc_int_for_mode (val, mode);
-
-      return GEN_INT (val);
-    }
-
-  /* We can do some operations on integer CONST_DOUBLEs.  Also allow
-     for a DImode operation on a CONST_INT.  */
-  else if (GET_MODE (op) == VOIDmode && width <= HOST_BITS_PER_INT * 2
-          && (GET_CODE (op) == CONST_DOUBLE || GET_CODE (op) == CONST_INT))
-    {
-      HOST_WIDE_INT l1, h1, lv, hv;
-
-      if (GET_CODE (op) == CONST_DOUBLE)
-       l1 = CONST_DOUBLE_LOW (op), h1 = CONST_DOUBLE_HIGH (op);
-      else
-       l1 = INTVAL (op), h1 = l1 < 0 ? -1 : 0;
-
-      switch (code)
-       {
-       case NOT:
-         lv = ~ l1;
-         hv = ~ h1;
-         break;
-
-       case NEG:
-         neg_double (l1, h1, &lv, &hv);
-         break;
-
-       case ABS:
-         if (h1 < 0)
-           neg_double (l1, h1, &lv, &hv);
-         else
-           lv = l1, hv = h1;
-         break;
-
-       case FFS:
-         hv = 0;
-         if (l1 == 0)
-           lv = HOST_BITS_PER_WIDE_INT + exact_log2 (h1 & (-h1)) + 1;
-         else
-           lv = exact_log2 (l1 & (-l1)) + 1;
-         break;
-
-       case TRUNCATE:
-         /* This is just a change-of-mode, so do nothing.  */
-         lv = l1, hv = h1;
-         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;
-
-       default:
-         return 0;
-       }
-
-      return immed_double_const (lv, hv, mode);
-    }
-
-#if ! defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC)
-  else if (GET_CODE (op) == CONST_DOUBLE
-          && GET_MODE_CLASS (mode) == MODE_FLOAT)
-    {
-      REAL_VALUE_TYPE d;
-      jmp_buf handler;
-      rtx x;
-
-      if (setjmp (handler))
-       /* There used to be a warning here, but that is inadvisable.
-          People may want to cause traps, and the natural way
-          to do it should not get a warning.  */
-       return 0;
-
-      set_float_handler (handler);
-
-      REAL_VALUE_FROM_CONST_DOUBLE (d, op);
-
-      switch (code)
-       {
-       case NEG:
-         d = REAL_VALUE_NEGATE (d);
-         break;
-
-       case ABS:
-         if (REAL_VALUE_NEGATIVE (d))
-           d = REAL_VALUE_NEGATE (d);
-         break;
-
-       case FLOAT_TRUNCATE:
-         d = real_value_truncate (mode, d);
-         break;
-
-       case FLOAT_EXTEND:
-         /* All this does is change the mode.  */
-         break;
-
-       case FIX:
-         d = REAL_VALUE_RNDZINT (d);
-         break;
-
-       case UNSIGNED_FIX:
-         d = REAL_VALUE_UNSIGNED_RNDZINT (d);
-         break;
-
-       case SQRT:
-         return 0;
-
-       default:
-         abort ();
-       }
-
-      x = CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
-      set_float_handler (NULL_PTR);
-      return x;
-    }
-
-  else if (GET_CODE (op) == CONST_DOUBLE
-          && GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT
-          && GET_MODE_CLASS (mode) == MODE_INT
-          && width <= HOST_BITS_PER_WIDE_INT && width > 0)
-    {
-      REAL_VALUE_TYPE d;
-      jmp_buf handler;
-      HOST_WIDE_INT val;
-
-      if (setjmp (handler))
-       return 0;
-
-      set_float_handler (handler);
-
-      REAL_VALUE_FROM_CONST_DOUBLE (d, op);
-
-      switch (code)
-       {
-       case FIX:
-         val = REAL_VALUE_FIX (d);
-         break;
-
-       case UNSIGNED_FIX:
-         val = REAL_VALUE_UNSIGNED_FIX (d);
-         break;
-
-       default:
-         abort ();
-       }
-
-      set_float_handler (NULL_PTR);
-
-      val = trunc_int_for_mode (val, mode);
-
-      return GEN_INT (val);
-    }
-#endif
-  /* This was formerly used only for non-IEEE float.
-     eggert@twinsun.com says it is safe for IEEE also.  */
-  else
-    {
-      /* There are some simplifications we can do even if the operands
-        aren't constant.  */
-      switch (code)
-       {
-       case NEG:
-       case NOT:
-         /* (not (not X)) == X, similarly for NEG.  */
-         if (GET_CODE (op) == code)
-           return XEXP (op, 0);
-         break;
-
-       case SIGN_EXTEND:
-         /* (sign_extend (truncate (minus (label_ref L1) (label_ref L2))))
-            becomes just the MINUS if its mode is MODE.  This allows
-            folding switch statements on machines using casesi (such as
-            the Vax).  */
-         if (GET_CODE (op) == TRUNCATE
-             && GET_MODE (XEXP (op, 0)) == mode
-             && GET_CODE (XEXP (op, 0)) == MINUS
-             && GET_CODE (XEXP (XEXP (op, 0), 0)) == LABEL_REF
-             && GET_CODE (XEXP (XEXP (op, 0), 1)) == LABEL_REF)
-           return XEXP (op, 0);
-
-#ifdef POINTERS_EXTEND_UNSIGNED
-         if (! POINTERS_EXTEND_UNSIGNED
-             && mode == Pmode && GET_MODE (op) == ptr_mode
-             && CONSTANT_P (op))
-           return convert_memory_address (Pmode, op);
-#endif
-         break;
-
-#ifdef POINTERS_EXTEND_UNSIGNED
-       case ZERO_EXTEND:
-         if (POINTERS_EXTEND_UNSIGNED
-             && mode == Pmode && GET_MODE (op) == ptr_mode
-             && CONSTANT_P (op))
-           return convert_memory_address (Pmode, op);
-         break;
-#endif
-         
-       default:
-         break;
-       }
-
-      return 0;
-    }
-}
-\f
-/* Simplify a binary operation CODE with result mode MODE, operating on OP0
-   and OP1.  Return 0 if no simplification is possible.
-
-   Don't use this for relational operations such as EQ or LT.
-   Use simplify_relational_operation instead.  */
-
-rtx
-simplify_binary_operation (code, mode, op0, op1)
-     enum rtx_code code;
-     enum machine_mode mode;
-     rtx 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.
-     Assuming a full word can give incorrect results.
-     Consider comparing 128 with -128 in QImode.  */
-
-  if (GET_RTX_CLASS (code) == '<')
-    abort ();
-
-#if ! defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC)
-  if (GET_MODE_CLASS (mode) == MODE_FLOAT
-      && GET_CODE (op0) == CONST_DOUBLE && GET_CODE (op1) == CONST_DOUBLE
-      && mode == GET_MODE (op0) && mode == GET_MODE (op1))
-    {
-      REAL_VALUE_TYPE f0, f1, value;
-      jmp_buf handler;
-
-      if (setjmp (handler))
-       return 0;
-
-      set_float_handler (handler);
-
-      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);
-
-#ifdef REAL_ARITHMETIC
-#ifndef REAL_INFINITY
-      if (code == DIV && REAL_VALUES_EQUAL (f1, dconst0))
-       return 0;
-#endif
-      REAL_ARITHMETIC (value, rtx_to_tree_code (code), f0, f1);
-#else
-      switch (code)
-       {
-       case PLUS:
-         value = f0 + f1;
-         break;
-       case MINUS:
-         value = f0 - f1;
-         break;
-       case MULT:
-         value = f0 * f1;
-         break;
-       case DIV:
-#ifndef REAL_INFINITY
-         if (f1 == 0)
-           return 0;
-#endif
-         value = f0 / f1;
-         break;
-       case SMIN:
-         value = MIN (f0, f1);
-         break;
-       case SMAX:
-         value = MAX (f0, f1);
-         break;
-       default:
-         abort ();
-       }
-#endif
-
-      value = real_value_truncate (mode, value);
-      set_float_handler (NULL_PTR);
-      return CONST_DOUBLE_FROM_REAL_VALUE (value, mode);
-    }
-#endif  /* not REAL_IS_NOT_DOUBLE, or REAL_ARITHMETIC */
-
-  /* We can fold some multi-word operations.  */
-  if (GET_MODE_CLASS (mode) == MODE_INT
-      && width == HOST_BITS_PER_WIDE_INT * 2
-      && (GET_CODE (op0) == CONST_DOUBLE || GET_CODE (op0) == CONST_INT)
-      && (GET_CODE (op1) == CONST_DOUBLE || GET_CODE (op1) == CONST_INT))
-    {
-      HOST_WIDE_INT l1, l2, h1, h2, lv, hv;
-
-      if (GET_CODE (op0) == CONST_DOUBLE)
-       l1 = CONST_DOUBLE_LOW (op0), h1 = CONST_DOUBLE_HIGH (op0);
-      else
-       l1 = INTVAL (op0), h1 = l1 < 0 ? -1 : 0;
-
-      if (GET_CODE (op1) == CONST_DOUBLE)
-       l2 = CONST_DOUBLE_LOW (op1), h2 = CONST_DOUBLE_HIGH (op1);
-      else
-       l2 = INTVAL (op1), h2 = l2 < 0 ? -1 : 0;
-
-      switch (code)
-       {
-       case MINUS:
-         /* A - B == A + (-B).  */
-         neg_double (l2, h2, &lv, &hv);
-         l2 = lv, h2 = hv;
-
-         /* .. fall through ...  */
-
-       case PLUS:
-         add_double (l1, h1, l2, h2, &lv, &hv);
-         break;
-
-       case MULT:
-         mul_double (l1, h1, l2, h2, &lv, &hv);
-         break;
-
-       case DIV:  case MOD:   case UDIV:  case UMOD:
-         /* We'd need to include tree.h to do this and it doesn't seem worth
-            it.  */
-         return 0;
-
-       case AND:
-         lv = l1 & l2, hv = h1 & h2;
-         break;
-
-       case IOR:
-         lv = l1 | l2, hv = h1 | h2;
-         break;
-
-       case XOR:
-         lv = l1 ^ l2, hv = h1 ^ h2;
-         break;
-
-       case SMIN:
-         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 HOST_WIDE_INT) l1
-                     > (unsigned HOST_WIDE_INT) l2)))
-           lv = l1, hv = h1;
-         else
-           lv = l2, hv = h2;
-         break;
-
-       case UMIN:
-         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 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 LSHIFTRT:   case ASHIFTRT:
-       case ASHIFT:
-       case ROTATE:     case ROTATERT:
-#ifdef SHIFT_COUNT_TRUNCATED
-         if (SHIFT_COUNT_TRUNCATED)
-           l2 &= (GET_MODE_BITSIZE (mode) - 1), h2 = 0;
-#endif
-
-         if (h2 != 0 || l2 < 0 || l2 >= GET_MODE_BITSIZE (mode))
-           return 0;
-
-         if (code == LSHIFTRT || code == ASHIFTRT)
-           rshift_double (l1, h1, l2, GET_MODE_BITSIZE (mode), &lv, &hv,
-                          code == ASHIFTRT);
-         else if (code == ASHIFT)
-           lshift_double (l1, h1, l2, GET_MODE_BITSIZE (mode), &lv, &hv, 1);
-         else if (code == ROTATE)
-           lrotate_double (l1, h1, l2, GET_MODE_BITSIZE (mode), &lv, &hv);
-         else /* code == ROTATERT */
-           rrotate_double (l1, h1, l2, GET_MODE_BITSIZE (mode), &lv, &hv);
-         break;
-
-       default:
-         return 0;
-       }
-
-      return immed_double_const (lv, hv, mode);
-    }
-
-  if (GET_CODE (op0) != CONST_INT || GET_CODE (op1) != CONST_INT
-      || width > HOST_BITS_PER_WIDE_INT || width == 0)
-    {
-      /* Even if we can't compute a constant result,
-        there are some cases worth simplifying.  */
-
-      switch (code)
-       {
-       case PLUS:
-         /* In IEEE floating point, x+0 is not the same as x.  Similarly
-            for the other optimizations below.  */
-         if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
-             && FLOAT_MODE_P (mode) && ! flag_fast_math)
-           break;
-
-         if (op1 == CONST0_RTX (mode))
-           return op0;
-
-         /* ((-a) + b) -> (b - a) and similarly for (a + (-b)) */
-         if (GET_CODE (op0) == NEG)
-           return cse_gen_binary (MINUS, mode, op1, XEXP (op0, 0));
-         else if (GET_CODE (op1) == NEG)
-           return cse_gen_binary (MINUS, mode, op0, 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.  Don't add CONST_INT
-            to CONST_INT since overflow won't be computed properly if wider
-            than HOST_BITS_PER_WIDE_INT.  */
-
-         if (CONSTANT_P (op0) && GET_MODE (op0) != VOIDmode
-             && GET_CODE (op1) == CONST_INT)
-           return plus_constant (op0, INTVAL (op1));
-         else if (CONSTANT_P (op1) && GET_MODE (op1) != VOIDmode
-                  && GET_CODE (op0) == CONST_INT)
-           return plus_constant (op1, INTVAL (op0));
-
-         /* See if this is something like X * C - X or vice versa or
-            if the multiplication is written as a shift.  If so, we can
-            distribute and make a new multiply, shift, or maybe just
-            have X (if C is 2 in the example above).  But don't make
-            real multiply if we didn't have one before.  */
-
-         if (! FLOAT_MODE_P (mode))
-           {
-             HOST_WIDE_INT coeff0 = 1, coeff1 = 1;
-             rtx lhs = op0, rhs = op1;
-             int had_mult = 0;
-
-             if (GET_CODE (lhs) == NEG)
-               coeff0 = -1, lhs = XEXP (lhs, 0);
-             else if (GET_CODE (lhs) == MULT
-                      && GET_CODE (XEXP (lhs, 1)) == CONST_INT)
-               {
-                 coeff0 = INTVAL (XEXP (lhs, 1)), lhs = XEXP (lhs, 0);
-                 had_mult = 1;
-               }
-             else if (GET_CODE (lhs) == ASHIFT
-                      && GET_CODE (XEXP (lhs, 1)) == CONST_INT
-                      && INTVAL (XEXP (lhs, 1)) >= 0
-                      && INTVAL (XEXP (lhs, 1)) < HOST_BITS_PER_WIDE_INT)
-               {
-                 coeff0 = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (lhs, 1));
-                 lhs = XEXP (lhs, 0);
-               }
-
-             if (GET_CODE (rhs) == NEG)
-               coeff1 = -1, rhs = XEXP (rhs, 0);
-             else if (GET_CODE (rhs) == MULT
-                      && GET_CODE (XEXP (rhs, 1)) == CONST_INT)
-               {
-                 coeff1 = INTVAL (XEXP (rhs, 1)), rhs = XEXP (rhs, 0);
-                 had_mult = 1;
-               }
-             else if (GET_CODE (rhs) == ASHIFT
-                      && GET_CODE (XEXP (rhs, 1)) == CONST_INT
-                      && INTVAL (XEXP (rhs, 1)) >= 0
-                      && INTVAL (XEXP (rhs, 1)) < HOST_BITS_PER_WIDE_INT)
-               {
-                 coeff1 = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (rhs, 1));
-                 rhs = XEXP (rhs, 0);
-               }
-
-             if (rtx_equal_p (lhs, rhs))
-               {
-                 tem = cse_gen_binary (MULT, mode, lhs,
-                                       GEN_INT (coeff0 + coeff1));
-                 return (GET_CODE (tem) == MULT && ! had_mult) ? 0 : tem;
-               }
-           }
-
-         /* 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 (INTEGRAL_MODE_P (mode)
-             && (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:
-#ifdef HAVE_cc0
-         /* Convert (compare FOO (const_int 0)) to FOO unless we aren't
-            using cc0, in which case we want to leave it as a COMPARE
-            so we can distinguish it from a register-register-copy.
-
-            In IEEE floating point, x-0 is not the same as x.  */
-
-         if ((TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
-              || ! FLOAT_MODE_P (mode) || flag_fast_math)
-             && op1 == CONST0_RTX (mode))
-           return op0;
-#else
-         /* Do nothing here.  */
-#endif
-         break;
-             
-       case MINUS:
-         /* None of these optimizations can be done for IEEE
-            floating point.  */
-         if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
-             && FLOAT_MODE_P (mode) && ! flag_fast_math)
-           break;
-
-         /* We can't assume x-x is 0 even with non-IEEE floating point,
-            but since it is zero except in very strange circumstances, we
-            will treat it as zero with -ffast-math.  */
-         if (rtx_equal_p (op0, op1)
-             && ! side_effects_p (op0)
-             && (! FLOAT_MODE_P (mode) || flag_fast_math))
-           return CONST0_RTX (mode);
-
-         /* 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;
-
-         /* See if this is something like X * C - X or vice versa or
-            if the multiplication is written as a shift.  If so, we can
-            distribute and make a new multiply, shift, or maybe just
-            have X (if C is 2 in the example above).  But don't make
-            real multiply if we didn't have one before.  */
-
-         if (! FLOAT_MODE_P (mode))
-           {
-             HOST_WIDE_INT coeff0 = 1, coeff1 = 1;
-             rtx lhs = op0, rhs = op1;
-             int had_mult = 0;
-
-             if (GET_CODE (lhs) == NEG)
-               coeff0 = -1, lhs = XEXP (lhs, 0);
-             else if (GET_CODE (lhs) == MULT
-                      && GET_CODE (XEXP (lhs, 1)) == CONST_INT)
-               {
-                 coeff0 = INTVAL (XEXP (lhs, 1)), lhs = XEXP (lhs, 0);
-                 had_mult = 1;
-               }
-             else if (GET_CODE (lhs) == ASHIFT
-                      && GET_CODE (XEXP (lhs, 1)) == CONST_INT
-                      && INTVAL (XEXP (lhs, 1)) >= 0
-                      && INTVAL (XEXP (lhs, 1)) < HOST_BITS_PER_WIDE_INT)
-               {
-                 coeff0 = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (lhs, 1));
-                 lhs = XEXP (lhs, 0);
-               }
-
-             if (GET_CODE (rhs) == NEG)
-               coeff1 = - 1, rhs = XEXP (rhs, 0);
-             else if (GET_CODE (rhs) == MULT
-                      && GET_CODE (XEXP (rhs, 1)) == CONST_INT)
-               {
-                 coeff1 = INTVAL (XEXP (rhs, 1)), rhs = XEXP (rhs, 0);
-                 had_mult = 1;
-               }
-             else if (GET_CODE (rhs) == ASHIFT
-                      && GET_CODE (XEXP (rhs, 1)) == CONST_INT
-                      && INTVAL (XEXP (rhs, 1)) >= 0
-                      && INTVAL (XEXP (rhs, 1)) < HOST_BITS_PER_WIDE_INT)
-               {
-                 coeff1 = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (rhs, 1));
-                 rhs = XEXP (rhs, 0);
-               }
-
-             if (rtx_equal_p (lhs, rhs))
-               {
-                 tem = cse_gen_binary (MULT, mode, lhs,
-                                       GEN_INT (coeff0 - coeff1));
-                 return (GET_CODE (tem) == MULT && ! had_mult) ? 0 : tem;
-               }
-           }
-
-         /* (a - (-b)) -> (a + b).  */
-         if (GET_CODE (op1) == NEG)
-           return cse_gen_binary (PLUS, mode, op0, XEXP (op1, 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.  */
-
-         if (INTEGRAL_MODE_P (mode)
-             && (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 && GET_MODE (op0) != VOIDmode)
-           return plus_constant (op0, - INTVAL (op1));
-
-         /* (x - (x & y)) -> (x & ~y) */
-         if (GET_CODE (op1) == AND)
-           {
-            if (rtx_equal_p (op0, XEXP (op1, 0)))
-              return cse_gen_binary (AND, mode, op0,
-                                     gen_rtx_NOT (mode, XEXP (op1, 1)));
-            if (rtx_equal_p (op0, XEXP (op1, 1)))
-              return cse_gen_binary (AND, mode, op0,
-                                     gen_rtx_NOT (mode, XEXP (op1, 0)));
-          }
-         break;
-
-       case MULT:
-         if (op1 == constm1_rtx)
-           {
-             tem = simplify_unary_operation (NEG, mode, op0, mode);
-
-             return tem ? tem : gen_rtx_NEG (mode, op0);
-           }
-
-         /* In IEEE floating point, x*0 is not always 0.  */
-         if ((TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
-              || ! FLOAT_MODE_P (mode) || flag_fast_math)
-             && op1 == CONST0_RTX (mode)
-             && ! side_effects_p (op0))
-           return op1;
-
-         /* In IEEE floating point, x*1 is not equivalent to x for nans.
-            However, ANSI says we can drop signals,
-            so we can do this anyway.  */
-         if (op1 == CONST1_RTX (mode))
-           return op0;
-
-         /* Convert multiply by constant power of two into shift unless
-            we are still generating RTL.  This test is a kludge.  */
-         if (GET_CODE (op1) == CONST_INT
-             && (val = exact_log2 (INTVAL (op1))) >= 0
-             /* If the mode is larger than the host word size, and the
-                uppermost bit is set, then this isn't a power of two due
-                to implicit sign extension.  */
-             && (width <= HOST_BITS_PER_WIDE_INT
-                 || val != HOST_BITS_PER_WIDE_INT - 1)
-             && ! rtx_equal_function_value_matters)
-           return gen_rtx_ASHIFT (mode, op0, GEN_INT (val));
-
-         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 (op1is2 && GET_MODE (op0) == mode)
-               return gen_rtx_PLUS (mode, op0, copy_rtx (op0));
-
-             else if (op1ism1 && GET_MODE (op0) == mode)
-               return gen_rtx_NEG (mode, op0);
-           }
-         break;
-
-       case IOR:
-         if (op1 == const0_rtx)
-           return op0;
-         if (GET_CODE (op1) == CONST_INT
-             && (INTVAL (op1) & GET_MODE_MASK (mode)) == GET_MODE_MASK (mode))
-           return op1;
-         if (rtx_equal_p (op0, op1) && ! side_effects_p (op0))
-           return op0;
-         /* 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)
-             && GET_MODE_CLASS (mode) != MODE_CC)
-           return constm1_rtx;
-         break;
-
-       case XOR:
-         if (op1 == const0_rtx)
-           return op0;
-         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)
-             && GET_MODE_CLASS (mode) != MODE_CC)
-           return const0_rtx;
-         break;
-
-       case AND:
-         if (op1 == const0_rtx && ! side_effects_p (op0))
-           return const0_rtx;
-         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)
-             && 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)
-             && GET_MODE_CLASS (mode) != MODE_CC)
-           return const0_rtx;
-         break;
-
-       case UDIV:
-         /* Convert divide by power of two into shift (divide by 1 handled
-            below).  */
-         if (GET_CODE (op1) == CONST_INT
-             && (arg1 = exact_log2 (INTVAL (op1))) > 0)
-           return gen_rtx_LSHIFTRT (mode, op0, GEN_INT (arg1));
-
-         /* ... fall through ...  */
-
-       case DIV:
-         if (op1 == CONST1_RTX (mode))
-           return op0;
-
-         /* In IEEE floating point, 0/x is not always 0.  */
-         if ((TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
-              || ! FLOAT_MODE_P (mode) || flag_fast_math)
-             && op0 == CONST0_RTX (mode)
-             && ! side_effects_p (op1))
-           return op0;
-
-#if ! defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC)
-         /* Change division by a constant into multiplication.  Only do
-            this with -ffast-math until an expert says it is safe in
-            general.  */
-         else if (GET_CODE (op1) == CONST_DOUBLE
-                  && GET_MODE_CLASS (GET_MODE (op1)) == MODE_FLOAT
-                  && op1 != CONST0_RTX (mode)
-                  && flag_fast_math)
-           {
-             REAL_VALUE_TYPE d;
-             REAL_VALUE_FROM_CONST_DOUBLE (d, op1);
-
-             if (! REAL_VALUES_EQUAL (d, dconst0))
-               {
-#if defined (REAL_ARITHMETIC)
-                 REAL_ARITHMETIC (d, rtx_to_tree_code (DIV), dconst1, d);
-                 return gen_rtx_MULT (mode, op0, 
-                                      CONST_DOUBLE_FROM_REAL_VALUE (d, mode));
-#else
-                 return
-                   gen_rtx_MULT (mode, op0, 
-                                 CONST_DOUBLE_FROM_REAL_VALUE (1./d, mode));
-#endif
-               }
-           }
-#endif
-         break;
-
-       case UMOD:
-         /* Handle modulus by power of two (mod with 1 handled below).  */
-         if (GET_CODE (op1) == CONST_INT
-             && exact_log2 (INTVAL (op1)) > 0)
-           return gen_rtx_AND (mode, op0, GEN_INT (INTVAL (op1) - 1));
-
-         /* ... fall through ...  */
-
-       case MOD:
-         if ((op0 == const0_rtx || op1 == const1_rtx)
-             && ! side_effects_p (op0) && ! side_effects_p (op1))
-           return const0_rtx;
-         break;
-
-       case ROTATERT:
-       case ROTATE:
-         /* Rotating ~0 always results in ~0.  */
-         if (GET_CODE (op0) == CONST_INT && width <= HOST_BITS_PER_WIDE_INT
-             && (unsigned HOST_WIDE_INT) INTVAL (op0) == GET_MODE_MASK (mode)
-             && ! side_effects_p (op1))
-           return op0;
-
-         /* ... fall through ...  */
-
-       case ASHIFT:
-       case ASHIFTRT:
-       case LSHIFTRT:
-         if (op1 == const0_rtx)
-           return op0;
-         if (op0 == const0_rtx && ! side_effects_p (op1))
-           return op0;
-         break;
-
-       case SMIN:
-         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))
-           return op0;
-         break;
-          
-       case SMAX:
-         if (width <= HOST_BITS_PER_WIDE_INT && GET_CODE (op1) == CONST_INT
-             && ((unsigned HOST_WIDE_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))
-           return op0;
-         break;
-
-       case UMIN:
-         if (op1 == const0_rtx && ! side_effects_p (op0))
-           return op1;
-         else if (rtx_equal_p (op0, op1) && ! side_effects_p (op0))
-           return op0;
-         break;
-           
-       case UMAX:
-         if (op1 == constm1_rtx && ! side_effects_p (op0))
-           return op1;
-         else if (rtx_equal_p (op0, op1) && ! side_effects_p (op0))
-           return op0;
-         break;
-
-       default:
-         abort ();
-       }
-      
-      return 0;
-    }
-
-  /* Get the integer argument values in two forms:
-     zero-extended in ARG0, ARG1 and sign-extended in ARG0S, ARG1S.  */
-
-  arg0 = INTVAL (op0);
-  arg1 = INTVAL (op1);
-
-  if (width < HOST_BITS_PER_WIDE_INT)
-    {
-      arg0 &= ((HOST_WIDE_INT) 1 << width) - 1;
-      arg1 &= ((HOST_WIDE_INT) 1 << width) - 1;
-
-      arg0s = arg0;
-      if (arg0s & ((HOST_WIDE_INT) 1 << (width - 1)))
-       arg0s |= ((HOST_WIDE_INT) (-1) << width);
-
-      arg1s = arg1;
-      if (arg1s & ((HOST_WIDE_INT) 1 << (width - 1)))
-       arg1s |= ((HOST_WIDE_INT) (-1) << width);
-    }
-  else
-    {
-      arg0s = arg0;
-      arg1s = arg1;
-    }
-
-  /* Compute the value of the arithmetic.  */
-
-  switch (code)
-    {
-    case PLUS:
-      val = arg0s + arg1s;
-      break;
-
-    case MINUS:
-      val = arg0s - arg1s;
-      break;
-
-    case MULT:
-      val = arg0s * arg1s;
-      break;
-
-    case DIV:
-      if (arg1s == 0)
-       return 0;
-      val = arg0s / arg1s;
-      break;
-
-    case MOD:
-      if (arg1s == 0)
-       return 0;
-      val = arg0s % arg1s;
-      break;
-
-    case UDIV:
-      if (arg1 == 0)
-       return 0;
-      val = (unsigned HOST_WIDE_INT) arg0 / arg1;
-      break;
-
-    case UMOD:
-      if (arg1 == 0)
-       return 0;
-      val = (unsigned HOST_WIDE_INT) arg0 % arg1;
-      break;
-
-    case AND:
-      val = arg0 & arg1;
-      break;
-
-    case IOR:
-      val = arg0 | arg1;
-      break;
-
-    case XOR:
-      val = arg0 ^ arg1;
-      break;
-
-    case LSHIFTRT:
-      /* If shift count is undefined, don't fold it; let the machine do
-        what it wants.  But truncate it if the machine will do that.  */
-      if (arg1 < 0)
-       return 0;
-
-#ifdef SHIFT_COUNT_TRUNCATED
-      if (SHIFT_COUNT_TRUNCATED)
-       arg1 %= width;
-#endif
-
-      val = ((unsigned HOST_WIDE_INT) arg0) >> arg1;
-      break;
-
-    case ASHIFT:
-      if (arg1 < 0)
-       return 0;
-
-#ifdef SHIFT_COUNT_TRUNCATED
-      if (SHIFT_COUNT_TRUNCATED)
-       arg1 %= width;
-#endif
-
-      val = ((unsigned HOST_WIDE_INT) arg0) << arg1;
-      break;
-
-    case ASHIFTRT:
-      if (arg1 < 0)
-       return 0;
-
-#ifdef SHIFT_COUNT_TRUNCATED
-      if (SHIFT_COUNT_TRUNCATED)
-       arg1 %= width;
-#endif
-
-      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:
-      if (arg1 < 0)
-       return 0;
-
-      arg1 %= width;
-      val = ((((unsigned HOST_WIDE_INT) arg0) << (width - arg1))
-            | (((unsigned HOST_WIDE_INT) arg0) >> arg1));
-      break;
-
-    case ROTATE:
-      if (arg1 < 0)
-       return 0;
-
-      arg1 %= width;
-      val = ((((unsigned HOST_WIDE_INT) arg0) << arg1)
-            | (((unsigned HOST_WIDE_INT) arg0) >> (width - arg1)));
-      break;
-
-    case COMPARE:
-      /* Do nothing here.  */
-      return 0;
-
-    case SMIN:
-      val = arg0s <= arg1s ? arg0s : arg1s;
-      break;
-
-    case UMIN:
-      val = ((unsigned HOST_WIDE_INT) arg0
-            <= (unsigned HOST_WIDE_INT) arg1 ? arg0 : arg1);
-      break;
-
-    case SMAX:
-      val = arg0s > arg1s ? arg0s : arg1s;
-      break;
-
-    case UMAX:
-      val = ((unsigned HOST_WIDE_INT) arg0
-            > (unsigned HOST_WIDE_INT) arg1 ? arg0 : arg1);
-      break;
-
-    default:
-      abort ();
-    }
-
-  val = trunc_int_for_mode (val, mode);
-
-  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 ((char *) 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;
-
-         default:
-           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]);
+            call simplify_gen_binary so many times that we run out of
+            memory.  */
 
-  return negate ? gen_rtx_NEG (mode, result) : result;
-}
-\f
-/* Make a binary operation by properly ordering the operands and 
-   seeing if the expression folds.  */
+         found_better = 0;
+         for (p = elt->first_same_value, count = 0;
+              p && count < 32;
+              p = p->next_same_value, count++)
+           if (! p->flag
+               && (GET_CODE (p->exp) == REG
+                   || exp_equiv_p (p->exp, p->exp, 1, 0)))
+             {
+               rtx new = simplify_gen_binary (GET_CODE (*loc), Pmode,
+                                              p->exp, c);
 
-static rtx
-cse_gen_binary (code, mode, op0, op1)
-     enum rtx_code code;
-     enum machine_mode mode;
-     rtx op0, op1;
-{
-  rtx tem;
+               if ((CSE_ADDRESS_COST (new) < best_addr_cost
+                   || (CSE_ADDRESS_COST (new) == best_addr_cost
+                       && (COST (new) + 1) >> 1 > best_rtx_cost)))
+                 {
+                   found_better = 1;
+                   best_addr_cost = CSE_ADDRESS_COST (new);
+                   best_rtx_cost = (COST (new) + 1) >> 1;
+                   best_elt = p;
+                   best_rtx = new;
+                 }
+             }
 
-  /* 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_fmt_ee (code, mode, op0, op1);
+         if (found_better)
+           {
+             if (validate_change (insn, loc,
+                                  canon_reg (copy_rtx (best_rtx),
+                                             NULL_RTX), 0))
+               return;
+             else
+               best_elt->flag = 1;
+           }
+       }
+    }
+#endif
 }
 \f
-struct cfc_args
-{
-  /* Input */
-  rtx op0, op1;
-  /* Output */
-  int equal, op0lt, op1lt;
-};
-
-static void
-check_fold_consts (data)
-  PTR data;
-{
-  struct cfc_args * args = (struct cfc_args *) data;
-  REAL_VALUE_TYPE d0, d1;
-
-  REAL_VALUE_FROM_CONST_DOUBLE (d0, args->op0);
-  REAL_VALUE_FROM_CONST_DOUBLE (d1, args->op1);
-  args->equal = REAL_VALUES_EQUAL (d0, d1);
-  args->op0lt = REAL_VALUES_LESS (d0, d1);
-  args->op1lt = REAL_VALUES_LESS (d1, d0);
-}
+/* Given an operation (CODE, *PARG1, *PARG2), where code is a comparison
+   operation (EQ, NE, GT, etc.), follow it back through the hash table and
+   what values are being compared.
 
-/* Like simplify_binary_operation except used for relational operators.
-   MODE is the mode of the operands, not that of the result.  If MODE
-   is VOIDmode, both operands must also be VOIDmode and we compare the
-   operands in "infinite precision".
+   *PARG1 and *PARG2 are updated to contain the rtx representing the values
+   actually being compared.  For example, if *PARG1 was (cc0) and *PARG2
+   was (const_int 0), *PARG1 and *PARG2 will be set to the objects that were
+   compared to produce cc0.
 
-   If no simplification is possible, this function returns zero.  Otherwise,
-   it returns either const_true_rtx or const0_rtx.  */
+   The return value is the comparison operator and is either the code of
+   A or the code corresponding to the inverse of the comparison.  */
 
-rtx
-simplify_relational_operation (code, mode, op0, op1)
+static enum rtx_code
+find_comparison_args (code, parg1, parg2, pmode1, pmode2)
      enum rtx_code code;
-     enum machine_mode mode;
-     rtx op0, op1;
+     rtx *parg1, *parg2;
+     enum machine_mode *pmode1, *pmode2;
 {
-  int equal, op0lt, op0ltu, op1lt, op1ltu;
-  rtx tem;
-
-  /* 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);
-
-  /* We can't simplify MODE_CC values since we don't know what the
-     actual comparison is.  */
-  if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_CC
-#ifdef HAVE_cc0
-      || op0 == cc0_rtx
-#endif
-      )
-    return 0;
-
-  /* For integer comparisons of A and B maybe we can simplify A - B and can
-     then simplify a comparison of that with zero.  If A and B are both either
-     a register or a CONST_INT, this can't help; testing for these cases will
-     prevent infinite recursion here and speed things up.
-
-     If CODE is an unsigned comparison, then we can never do this optimization,
-     because it gives an incorrect result if the subtraction wraps around zero.
-     ANSI C defines unsigned operations such that they never overflow, and
-     thus such cases can not be ignored.  */
-
-  if (INTEGRAL_MODE_P (mode) && op1 != const0_rtx
-      && ! ((GET_CODE (op0) == REG || GET_CODE (op0) == CONST_INT)
-           && (GET_CODE (op1) == REG || GET_CODE (op1) == CONST_INT))
-      && 0 != (tem = simplify_binary_operation (MINUS, mode, op0, op1))
-      && code != GTU && code != GEU && code != LTU && code != LEU)
-    return simplify_relational_operation (signed_condition (code),
-                                         mode, tem, const0_rtx);
-
-  /* For non-IEEE floating-point, if the two operands are equal, we know the
-     result.  */
-  if (rtx_equal_p (op0, op1)
-      && (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
-         || ! FLOAT_MODE_P (GET_MODE (op0)) || flag_fast_math))
-    equal = 1, op0lt = 0, op0ltu = 0, op1lt = 0, op1ltu = 0;
-
-  /* If the operands are floating-point constants, see if we can fold
-     the result.  */
-#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)
-    {
-      struct cfc_args args;
+  rtx arg1, arg2;
 
-      /* Setup input for check_fold_consts() */
-      args.op0 = op0;
-      args.op1 = op1;
-      
-      if (do_float_handler(check_fold_consts, (PTR) &args) == 0)
-       /* We got an exception from check_fold_consts() */
-       return 0;
+  arg1 = *parg1, arg2 = *parg2;
 
-      /* Receive output from check_fold_consts() */
-      equal = args.equal;
-      op0lt = op0ltu = args.op0lt;
-      op1lt = op1ltu = args.op1lt;
-    }
-#endif  /* not REAL_IS_NOT_DOUBLE, or REAL_ARITHMETIC */
+  /* If ARG2 is const0_rtx, see what ARG1 is equivalent to.  */
 
-  /* Otherwise, see if the operands are both integers.  */
-  else if ((GET_MODE_CLASS (mode) == MODE_INT || mode == VOIDmode)
-          && (GET_CODE (op0) == CONST_DOUBLE || GET_CODE (op0) == CONST_INT)
-          && (GET_CODE (op1) == CONST_DOUBLE || GET_CODE (op1) == CONST_INT))
+  while (arg2 == CONST0_RTX (GET_MODE (arg1)))
     {
-      int width = GET_MODE_BITSIZE (mode);
-      HOST_WIDE_INT l0s, h0s, l1s, h1s;
-      unsigned HOST_WIDE_INT l0u, h0u, l1u, h1u;
-
-      /* Get the two words comprising each integer constant.  */
-      if (GET_CODE (op0) == CONST_DOUBLE)
-       {
-         l0u = l0s = CONST_DOUBLE_LOW (op0);
-         h0u = h0s = CONST_DOUBLE_HIGH (op0);
-       }
-      else
-       {
-         l0u = l0s = INTVAL (op0);
-         h0u = h0s = l0s < 0 ? -1 : 0;
-       }
-         
-      if (GET_CODE (op1) == CONST_DOUBLE)
-       {
-         l1u = l1s = CONST_DOUBLE_LOW (op1);
-         h1u = h1s = CONST_DOUBLE_HIGH (op1);
-       }
-      else
-       {
-         l1u = l1s = INTVAL (op1);
-         h1u = h1s = l1s < 0 ? -1 : 0;
-       }
-
-      /* If WIDTH is nonzero and smaller than HOST_BITS_PER_WIDE_INT,
-        we have to sign or zero-extend the values.  */
-      if (width != 0 && width <= HOST_BITS_PER_WIDE_INT)
-       h0u = h1u = 0, h0s = l0s < 0 ? -1 : 0, h1s = l1s < 0 ? -1 : 0;
-
-      if (width != 0 && width < HOST_BITS_PER_WIDE_INT)
-       {
-         l0u &= ((HOST_WIDE_INT) 1 << width) - 1;
-         l1u &= ((HOST_WIDE_INT) 1 << width) - 1;
+      /* Set non-zero when we find something of interest.  */
+      rtx x = 0;
+      int reverse_code = 0;
+      struct table_elt *p = 0;
 
-         if (l0s & ((HOST_WIDE_INT) 1 << (width - 1)))
-           l0s |= ((HOST_WIDE_INT) (-1) << width);
+      /* If arg1 is a COMPARE, extract the comparison arguments from it.
+        On machines with CC0, this is the only case that can occur, since
+        fold_rtx will return the COMPARE or item being compared with zero
+        when given CC0.  */
 
-         if (l1s & ((HOST_WIDE_INT) 1 << (width - 1)))
-           l1s |= ((HOST_WIDE_INT) (-1) << width);
-       }
+      if (GET_CODE (arg1) == COMPARE && arg2 == const0_rtx)
+       x = arg1;
 
-      equal = (h0u == h1u && l0u == l1u);
-      op0lt = (h0s < h1s || (h0s == h1s && l0s < l1s));
-      op1lt = (h1s < h0s || (h1s == h0s && l1s < l0s));
-      op0ltu = (h0u < h1u || (h0u == h1u && l0u < l1u));
-      op1ltu = (h1u < h0u || (h1u == h0u && l1u < l0u));
-    }
+      /* If ARG1 is a comparison operator and CODE is testing for
+        STORE_FLAG_VALUE, get the inner arguments.  */
 
-  /* Otherwise, there are some code-specific tests we can make.  */
-  else
-    {
-      switch (code)
+      else if (GET_RTX_CLASS (GET_CODE (arg1)) == '<')
        {
-       case EQ:
-         /* References to the frame plus a constant or labels cannot
-            be zero, but a SYMBOL_REF can due to #pragma weak.  */
-         if (((NONZERO_BASE_PLUS_P (op0) && op1 == const0_rtx)
-              || GET_CODE (op0) == LABEL_REF)
-#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
-             /* On some machines, the ap reg can be 0 sometimes.  */
-             && op0 != arg_pointer_rtx
-#endif
-               )
-           return const0_rtx;
-         break;
-
-       case NE:
-         if (((NONZERO_BASE_PLUS_P (op0) && op1 == const0_rtx)
-              || GET_CODE (op0) == LABEL_REF)
-#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
-             && op0 != arg_pointer_rtx
+         if (code == NE
+             || (GET_MODE_CLASS (GET_MODE (arg1)) == MODE_INT
+                 && code == LT && STORE_FLAG_VALUE == -1)
+#ifdef FLOAT_STORE_FLAG_VALUE
+             || (GET_MODE_CLASS (GET_MODE (arg1)) == MODE_FLOAT
+                 && FLOAT_STORE_FLAG_VALUE < 0)
 #endif
              )
-           return const_true_rtx;
-         break;
-
-       case GEU:
-         /* Unsigned values are never negative.  */
-         if (op1 == const0_rtx)
-           return const_true_rtx;
-         break;
-
-       case LTU:
-         if (op1 == const0_rtx)
-           return const0_rtx;
-         break;
-
-       case LEU:
-         /* Unsigned values are never greater than the largest
-            unsigned value.  */
-         if (GET_CODE (op1) == CONST_INT
-             && (unsigned HOST_WIDE_INT) INTVAL (op1) == GET_MODE_MASK (mode)
-           && INTEGRAL_MODE_P (mode))
-         return const_true_rtx;
-         break;
-
-       case GTU:
-         if (GET_CODE (op1) == CONST_INT
-             && (unsigned HOST_WIDE_INT) INTVAL (op1) == GET_MODE_MASK (mode)
-             && INTEGRAL_MODE_P (mode))
-           return const0_rtx;
-         break;
-         
-       default:
-         break;
+           x = arg1;
+         else if (code == EQ
+                  || (GET_MODE_CLASS (GET_MODE (arg1)) == MODE_INT
+                      && code == GE && STORE_FLAG_VALUE == -1)
+#ifdef FLOAT_STORE_FLAG_VALUE
+                  || (GET_MODE_CLASS (GET_MODE (arg1)) == MODE_FLOAT
+                      && FLOAT_STORE_FLAG_VALUE < 0)
+#endif
+                  )
+           x = arg1, reverse_code = 1;
        }
 
-      return 0;
-    }
+      /* ??? We could also check for
 
-  /* If we reach here, EQUAL, OP0LT, OP0LTU, OP1LT, and OP1LTU are set
-     as appropriate.  */
-  switch (code)
-    {
-    case EQ:
-      return equal ? const_true_rtx : const0_rtx;
-    case NE:
-      return ! equal ? const_true_rtx : const0_rtx;
-    case LT:
-      return op0lt ? const_true_rtx : const0_rtx;
-    case GT:
-      return op1lt ? const_true_rtx : const0_rtx;
-    case LTU:
-      return op0ltu ? const_true_rtx : const0_rtx;
-    case GTU:
-      return op1ltu ? const_true_rtx : const0_rtx;
-    case LE:
-      return equal || op0lt ? const_true_rtx : const0_rtx;
-    case GE:
-      return equal || op1lt ? const_true_rtx : const0_rtx;
-    case LEU:
-      return equal || op0ltu ? const_true_rtx : const0_rtx;
-    case GEU:
-      return equal || op1ltu ? const_true_rtx : const0_rtx;
-    default:
-      abort ();
-    }
-}
-\f
-/* Simplify CODE, an operation with result mode MODE and three operands,
-   OP0, OP1, and OP2.  OP0_MODE was the mode of OP0 before it became
-   a constant.  Return 0 if no simplifications is possible.  */
+        (ne (and (eq (...) (const_int 1))) (const_int 0))
 
-rtx
-simplify_ternary_operation (code, mode, op0_mode, op0, op1, op2)
-     enum rtx_code code;
-     enum machine_mode mode, op0_mode;
-     rtx op0, op1, op2;
-{
-  int width = GET_MODE_BITSIZE (mode);
+        and related forms, but let's wait until we see them occurring.  */
 
-  /* VOIDmode means "infinite" precision.  */
-  if (width == 0)
-    width = HOST_BITS_PER_WIDE_INT;
+      if (x == 0)
+       /* Look up ARG1 in the hash table and see if it has an equivalence
+          that lets us see what is being compared.  */
+       p = lookup (arg1, safe_hash (arg1, GET_MODE (arg1)) % NBUCKETS,
+                   GET_MODE (arg1));
+      if (p) p = p->first_same_value;
 
-  switch (code)
-    {
-    case SIGN_EXTRACT:
-    case ZERO_EXTRACT:
-      if (GET_CODE (op0) == CONST_INT
-         && GET_CODE (op1) == CONST_INT
-         && GET_CODE (op2) == CONST_INT
-         && INTVAL (op1) + INTVAL (op2) <= GET_MODE_BITSIZE (op0_mode)
-         && width <= HOST_BITS_PER_WIDE_INT)
+      for (; p; p = p->next_same_value)
        {
-         /* Extracting a bit-field from a constant */
-         HOST_WIDE_INT val = INTVAL (op0);
+         enum machine_mode inner_mode = GET_MODE (p->exp);
 
-         if (BITS_BIG_ENDIAN)
-           val >>= (GET_MODE_BITSIZE (op0_mode)
-                    - INTVAL (op2) - INTVAL (op1));
-         else
-           val >>= INTVAL (op2);
+         /* If the entry isn't valid, skip it.  */
+         if (! exp_equiv_p (p->exp, p->exp, 1, 0))
+           continue;
 
-         if (HOST_BITS_PER_WIDE_INT != INTVAL (op1))
+         if (GET_CODE (p->exp) == COMPARE
+             /* Another possibility is that this machine has a compare insn
+                that includes the comparison code.  In that case, ARG1 would
+                be equivalent to a comparison operation that would set ARG1 to
+                either STORE_FLAG_VALUE or zero.  If this is an NE operation,
+                ORIG_CODE is the actual comparison being done; if it is an EQ,
+                we must reverse ORIG_CODE.  On machine with a negative value
+                for STORE_FLAG_VALUE, also look at LT and GE operations.  */
+             || ((code == NE
+                  || (code == LT
+                      && GET_MODE_CLASS (inner_mode) == MODE_INT
+                      && (GET_MODE_BITSIZE (inner_mode)
+                          <= HOST_BITS_PER_WIDE_INT)
+                      && (STORE_FLAG_VALUE
+                          & ((HOST_WIDE_INT) 1
+                             << (GET_MODE_BITSIZE (inner_mode) - 1))))
+#ifdef FLOAT_STORE_FLAG_VALUE
+                  || (code == LT
+                      && GET_MODE_CLASS (inner_mode) == MODE_FLOAT
+                      && FLOAT_STORE_FLAG_VALUE < 0)
+#endif
+                  )
+                 && GET_RTX_CLASS (GET_CODE (p->exp)) == '<'))
            {
-             /* First zero-extend.  */
-             val &= ((HOST_WIDE_INT) 1 << INTVAL (op1)) - 1;
-             /* If desired, propagate sign bit.  */
-             if (code == SIGN_EXTRACT
-                 && (val & ((HOST_WIDE_INT) 1 << (INTVAL (op1) - 1))))
-               val |= ~ (((HOST_WIDE_INT) 1 << INTVAL (op1)) - 1);
+             x = p->exp;
+             break;
+           }
+         else if ((code == EQ
+                   || (code == GE
+                       && GET_MODE_CLASS (inner_mode) == MODE_INT
+                       && (GET_MODE_BITSIZE (inner_mode)
+                           <= HOST_BITS_PER_WIDE_INT)
+                       && (STORE_FLAG_VALUE
+                           & ((HOST_WIDE_INT) 1
+                              << (GET_MODE_BITSIZE (inner_mode) - 1))))
+#ifdef FLOAT_STORE_FLAG_VALUE
+                   || (code == GE
+                       && GET_MODE_CLASS (inner_mode) == MODE_FLOAT
+                       && FLOAT_STORE_FLAG_VALUE < 0)
+#endif
+                   )
+                  && GET_RTX_CLASS (GET_CODE (p->exp)) == '<')
+           {
+             reverse_code = 1;
+             x = p->exp;
+             break;
            }
 
-         /* Clear the bits that don't belong in our mode,
-            unless they and our sign bit are all one.
-            So we get either a reasonable negative value or a reasonable
-            unsigned value for this mode.  */
-         if (width < HOST_BITS_PER_WIDE_INT
-             && ((val & ((HOST_WIDE_INT) (-1) << (width - 1)))
-                 != ((HOST_WIDE_INT) (-1) << (width - 1))))
-           val &= ((HOST_WIDE_INT) 1 << width) - 1;
-
-         return GEN_INT (val);
+         /* If this is fp + constant, the equivalent is a better operand since
+            it may let us predict the value of the comparison.  */
+         else if (NONZERO_BASE_PLUS_P (p->exp))
+           {
+             arg1 = p->exp;
+             continue;
+           }
        }
-      break;
 
-    case IF_THEN_ELSE:
-      if (GET_CODE (op0) == CONST_INT)
-       return op0 != const0_rtx ? op1 : op2;
-
-      /* Convert a == b ? b : a to "a".  */
-      if (GET_CODE (op0) == NE && ! side_effects_p (op0)
-         && rtx_equal_p (XEXP (op0, 0), op1)
-         && rtx_equal_p (XEXP (op0, 1), op2))
-       return op1;
-      else if (GET_CODE (op0) == EQ && ! side_effects_p (op0)
-         && rtx_equal_p (XEXP (op0, 1), op1)
-         && rtx_equal_p (XEXP (op0, 0), op2))
-       return op2;
-      else if (GET_RTX_CLASS (GET_CODE (op0)) == '<' && ! side_effects_p (op0))
-       {
-         rtx temp;
-         temp = simplify_relational_operation (GET_CODE (op0), op0_mode,
-                                               XEXP (op0, 0), XEXP (op0, 1));
-         /* See if any simplifications were possible.  */
-         if (temp == const0_rtx)
-           return op2;
-         else if (temp == const1_rtx)
-           return op1;
-       }
-      break;
+      /* If we didn't find a useful equivalence for ARG1, we are done.
+        Otherwise, set up for the next iteration.  */
+      if (x == 0)
+       break;
 
-    default:
-      abort ();
+      arg1 = XEXP (x, 0),  arg2 = XEXP (x, 1);
+      if (GET_RTX_CLASS (GET_CODE (x)) == '<')
+       code = GET_CODE (x);
+
+      if (reverse_code)
+       code = reverse_condition (code);
     }
 
-  return 0;
+  /* 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;
 }
 \f
 /* If X is a nontrivial arithmetic operation on an argument
@@ -5850,8 +4069,8 @@ fold_rtx (x, insn)
              if (p)
                for (p = p->first_same_value; p; p = p->next_same_value)
                  if (GET_CODE (p->exp) == REG)
-                   return cse_gen_binary (MINUS, mode, folded_arg0,
-                                          canon_reg (p->exp, NULL_RTX));
+                   return simplify_gen_binary (MINUS, mode, folded_arg0,
+                                               canon_reg (p->exp, NULL_RTX));
            }
          goto from_plus;
 
@@ -5958,7 +4177,7 @@ fold_rtx (x, insn)
              if (! reg_mentioned_p (folded_arg0, y))
                y = fold_rtx (y, insn);
 
-             return cse_gen_binary (code, mode, y, new_const);
+             return simplify_gen_binary (code, mode, y, new_const);
            }
          break;
 
@@ -7298,11 +5517,32 @@ cse_insn (insn, libcall_insn)
                && GET_CODE (XEXP (XEXP (src_const, 0), 0)) == LABEL_REF
                && GET_CODE (XEXP (XEXP (src_const, 0), 1)) == LABEL_REF))
        {
+         rtx simplified_src_const;
          tem = find_reg_note (insn, REG_EQUAL, NULL_RTX);
          
          /* Make sure that the rtx is not shared with any other insn.  */
          src_const = copy_rtx (src_const);
 
+         /* Try to simplify SRC_CONST.
+
+            The primary purpose behind simplifying the note is to allow
+            for easier removal of library call sequences later.  Consider
+            a udiv libcall where we can determine the second argument is
+            a constant.  SRC_CONST would look like:
+
+               (udiv (reg) (const_int 2**n))
+
+            That RTL expression will simplify into:
+
+               (lshiftrt (reg) (const_int n))
+
+            A target using library calls for division is more likely to
+            have a lshiftrt insn.  Thus, it is more likely that the libcall
+            can be deleted in delete_trivially_dead_insns if we simplify
+            the note.  */
+         simplified_src_const = simplify_rtx (src_const);
+         src_const = simplified_src_const ? simplified_src_const : src_const;
+         
          /* Record the actual constant value in a REG_EQUAL note, making
             a new one if one does not already exist.  */
          if (tem)
@@ -9181,8 +7421,12 @@ delete_trivially_dead_insns (insns, nreg)
          if (note)
            {
              rtx set = single_set (insn);
-             if (set
-                 && validate_change (insn, &SET_SRC (set), XEXP (note, 0), 0))
+             rtx new = simplify_rtx (XEXP (note, 0));
+
+             if (!new)
+               new = XEXP (note, 0);
+
+             if (set && validate_change (insn, &SET_SRC (set), new, 0))
                {
                  remove_note (insn,
                               find_reg_note (insn, REG_RETVAL, NULL_RTX));
index e1e1b66f0b27830ab723b9b2d27fbf7c833d2a0b..b96ab3839b2aa6936ca28c0799f165d9615f4fc4 100644 (file)
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -1069,6 +1069,9 @@ extern rtx simplify_unary_operation       PROTO((enum rtx_code, enum machine_mode, rtx
 extern rtx simplify_binary_operation   PROTO((enum rtx_code, enum machine_mode, rtx, rtx));
 extern rtx simplify_ternary_operation  PROTO((enum rtx_code, enum machine_mode, enum machine_mode, rtx, rtx, rtx));
 extern rtx simplify_relational_operation PROTO((enum rtx_code, enum machine_mode, rtx, rtx));
+extern rtx simplify_gen_binary         PROTO((enum rtx_code, enum machine_mode,
+                                              rtx, rtx));
+extern rtx simplify_rtx                        PROTO((rtx));
 extern rtx gen_move_insn               PROTO((rtx, rtx));
 extern rtx gen_jump                    PROTO((rtx));
 extern rtx gen_beq                     PROTO((rtx));
diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c
new file mode 100644 (file)
index 0000000..60c80c0
--- /dev/null
@@ -0,0 +1,1953 @@
+/* Common subexpression elimination for GNU compiler.
+   Copyright (C) 1987, 88, 89, 92-7, 1998, 1999 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+
+#include "config.h"
+/* stdio.h must precede rtl.h for FFS.  */
+#include "system.h"
+#include <setjmp.h>
+
+#include "rtl.h"
+#include "tm_p.h"
+#include "regs.h"
+#include "hard-reg-set.h"
+#include "flags.h"
+#include "real.h"
+#include "insn-config.h"
+#include "recog.h"
+#include "function.h"
+#include "expr.h"
+#include "toplev.h"
+#include "output.h"
+
+/* Simplification and canonicalization of RTL.  */
+
+/* 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.
+
+   ?!? FIXED_BASE_PLUS_P and NONZERO_BASE_PLUS_P need to move into 
+   a header file so that their definitions can be shared with the
+   simplification routines in simplify-rtx.c.  Until then, do not
+   change these macros without also changing the copy in simplify-rtx.c.  */
+
+#define FIXED_BASE_PLUS_P(X)                                   \
+  ((X) == frame_pointer_rtx || (X) == hard_frame_pointer_rtx   \
+   || ((X) == arg_pointer_rtx && fixed_regs[ARG_POINTER_REGNUM])\
+   || (X) == virtual_stack_vars_rtx                            \
+   || (X) == virtual_incoming_args_rtx                         \
+   || (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == CONST_INT \
+       && (XEXP (X, 0) == frame_pointer_rtx                    \
+          || XEXP (X, 0) == hard_frame_pointer_rtx             \
+          || ((X) == arg_pointer_rtx                           \
+              && fixed_regs[ARG_POINTER_REGNUM])               \
+          || XEXP (X, 0) == virtual_stack_vars_rtx             \
+          || XEXP (X, 0) == virtual_incoming_args_rtx))        \
+   || GET_CODE (X) == ADDRESSOF)
+
+/* Similar, but also allows reference to the stack pointer.
+
+   This used to include FIXED_BASE_PLUS_P, however, we can't assume that
+   arg_pointer_rtx by itself is nonzero, because on at least one machine,
+   the i960, the arg pointer is zero when it is unused.  */
+
+#define NONZERO_BASE_PLUS_P(X)                                 \
+  ((X) == frame_pointer_rtx || (X) == hard_frame_pointer_rtx   \
+   || (X) == virtual_stack_vars_rtx                            \
+   || (X) == virtual_incoming_args_rtx                         \
+   || (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == CONST_INT \
+       && (XEXP (X, 0) == frame_pointer_rtx                    \
+          || XEXP (X, 0) == hard_frame_pointer_rtx             \
+          || ((X) == arg_pointer_rtx                           \
+              && fixed_regs[ARG_POINTER_REGNUM])               \
+          || XEXP (X, 0) == virtual_stack_vars_rtx             \
+          || XEXP (X, 0) == virtual_incoming_args_rtx))        \
+   || (X) == stack_pointer_rtx                                 \
+   || (X) == virtual_stack_dynamic_rtx                         \
+   || (X) == virtual_outgoing_args_rtx                         \
+   || (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == CONST_INT \
+       && (XEXP (X, 0) == stack_pointer_rtx                    \
+          || XEXP (X, 0) == virtual_stack_dynamic_rtx          \
+          || XEXP (X, 0) == virtual_outgoing_args_rtx))        \
+   || GET_CODE (X) == ADDRESSOF)
+
+
+static rtx simplify_plus_minus PROTO((enum rtx_code, enum machine_mode,
+                                      rtx, rtx));
+static void check_fold_consts  PROTO((PTR));
+
+/* Make a binary operation by properly ordering the operands and 
+   seeing if the expression folds.  */
+
+rtx
+simplify_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_fmt_ee (code, mode, op0, op1);
+}
+\f
+/* Try to simplify a unary operation CODE whose output mode is to be
+   MODE with input operand OP whose mode was originally OP_MODE.
+   Return zero if no simplification can be made.  */
+
+rtx
+simplify_unary_operation (code, mode, op, op_mode)
+     enum rtx_code code;
+     enum machine_mode mode;
+     rtx op;
+     enum machine_mode op_mode;
+{
+  register int width = GET_MODE_BITSIZE (mode);
+
+  /* The order of these tests is critical so that, for example, we don't
+     check the wrong mode (input vs. output) for a conversion operation,
+     such as FIX.  At some point, this should be simplified.  */
+
+#if !defined(REAL_IS_NOT_DOUBLE) || defined(REAL_ARITHMETIC)
+
+  if (code == FLOAT && GET_MODE (op) == VOIDmode
+      && (GET_CODE (op) == CONST_DOUBLE || GET_CODE (op) == CONST_INT))
+    {
+      HOST_WIDE_INT hv, lv;
+      REAL_VALUE_TYPE d;
+
+      if (GET_CODE (op) == CONST_INT)
+       lv = INTVAL (op), hv = INTVAL (op) < 0 ? -1 : 0;
+      else
+       lv = CONST_DOUBLE_LOW (op),  hv = CONST_DOUBLE_HIGH (op);
+
+#ifdef REAL_ARITHMETIC
+      REAL_VALUE_FROM_INT (d, lv, hv, mode);
+#else
+      if (hv < 0)
+       {
+         d = (double) (~ hv);
+         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) (~ lv);
+         d = (- d - 1.0);
+       }
+      else
+       {
+         d = (double) hv;
+         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) lv;
+       }
+#endif  /* REAL_ARITHMETIC */
+      d = real_value_truncate (mode, d);
+      return CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
+    }
+  else if (code == UNSIGNED_FLOAT && GET_MODE (op) == VOIDmode
+          && (GET_CODE (op) == CONST_DOUBLE || GET_CODE (op) == CONST_INT))
+    {
+      HOST_WIDE_INT hv, lv;
+      REAL_VALUE_TYPE d;
+
+      if (GET_CODE (op) == CONST_INT)
+       lv = INTVAL (op), hv = INTVAL (op) < 0 ? -1 : 0;
+      else
+       lv = CONST_DOUBLE_LOW (op),  hv = CONST_DOUBLE_HIGH (op);
+
+      if (op_mode == VOIDmode)
+       {
+         /* We don't know how to interpret negative-looking numbers in
+            this case, so don't try to fold those.  */
+         if (hv < 0)
+           return 0;
+       }
+      else if (GET_MODE_BITSIZE (op_mode) >= HOST_BITS_PER_WIDE_INT * 2)
+       ;
+      else
+       hv = 0, lv &= GET_MODE_MASK (op_mode);
+
+#ifdef REAL_ARITHMETIC
+      REAL_VALUE_FROM_UNSIGNED_INT (d, lv, hv, mode);
+#else
+
+      d = (double) (unsigned HOST_WIDE_INT) hv;
+      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) lv;
+#endif  /* REAL_ARITHMETIC */
+      d = real_value_truncate (mode, d);
+      return CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
+    }
+#endif
+
+  if (GET_CODE (op) == CONST_INT
+      && width <= HOST_BITS_PER_WIDE_INT && width > 0)
+    {
+      register HOST_WIDE_INT arg0 = INTVAL (op);
+      register HOST_WIDE_INT val;
+
+      switch (code)
+       {
+       case NOT:
+         val = ~ arg0;
+         break;
+
+       case NEG:
+         val = - arg0;
+         break;
+
+       case ABS:
+         val = (arg0 >= 0 ? arg0 : - arg0);
+         break;
+
+       case FFS:
+         /* Don't use ffs here.  Instead, get low order bit and then its
+            number.  If arg0 is zero, this will return 0, as desired.  */
+         arg0 &= GET_MODE_MASK (mode);
+         val = exact_log2 (arg0 & (- arg0)) + 1;
+         break;
+
+       case TRUNCATE:
+         val = arg0;
+         break;
+
+       case ZERO_EXTEND:
+         if (op_mode == VOIDmode)
+           op_mode = 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;
+
+       case SIGN_EXTEND:
+         if (op_mode == VOIDmode)
+           op_mode = 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));
+             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;
+         break;
+
+       case SQRT:
+         return 0;
+
+       default:
+         abort ();
+       }
+
+      val = trunc_int_for_mode (val, mode);
+
+      return GEN_INT (val);
+    }
+
+  /* We can do some operations on integer CONST_DOUBLEs.  Also allow
+     for a DImode operation on a CONST_INT.  */
+  else if (GET_MODE (op) == VOIDmode && width <= HOST_BITS_PER_INT * 2
+          && (GET_CODE (op) == CONST_DOUBLE || GET_CODE (op) == CONST_INT))
+    {
+      HOST_WIDE_INT l1, h1, lv, hv;
+
+      if (GET_CODE (op) == CONST_DOUBLE)
+       l1 = CONST_DOUBLE_LOW (op), h1 = CONST_DOUBLE_HIGH (op);
+      else
+       l1 = INTVAL (op), h1 = l1 < 0 ? -1 : 0;
+
+      switch (code)
+       {
+       case NOT:
+         lv = ~ l1;
+         hv = ~ h1;
+         break;
+
+       case NEG:
+         neg_double (l1, h1, &lv, &hv);
+         break;
+
+       case ABS:
+         if (h1 < 0)
+           neg_double (l1, h1, &lv, &hv);
+         else
+           lv = l1, hv = h1;
+         break;
+
+       case FFS:
+         hv = 0;
+         if (l1 == 0)
+           lv = HOST_BITS_PER_WIDE_INT + exact_log2 (h1 & (-h1)) + 1;
+         else
+           lv = exact_log2 (l1 & (-l1)) + 1;
+         break;
+
+       case TRUNCATE:
+         /* This is just a change-of-mode, so do nothing.  */
+         lv = l1, hv = h1;
+         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;
+
+       default:
+         return 0;
+       }
+
+      return immed_double_const (lv, hv, mode);
+    }
+
+#if ! defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC)
+  else if (GET_CODE (op) == CONST_DOUBLE
+          && GET_MODE_CLASS (mode) == MODE_FLOAT)
+    {
+      REAL_VALUE_TYPE d;
+      jmp_buf handler;
+      rtx x;
+
+      if (setjmp (handler))
+       /* There used to be a warning here, but that is inadvisable.
+          People may want to cause traps, and the natural way
+          to do it should not get a warning.  */
+       return 0;
+
+      set_float_handler (handler);
+
+      REAL_VALUE_FROM_CONST_DOUBLE (d, op);
+
+      switch (code)
+       {
+       case NEG:
+         d = REAL_VALUE_NEGATE (d);
+         break;
+
+       case ABS:
+         if (REAL_VALUE_NEGATIVE (d))
+           d = REAL_VALUE_NEGATE (d);
+         break;
+
+       case FLOAT_TRUNCATE:
+         d = real_value_truncate (mode, d);
+         break;
+
+       case FLOAT_EXTEND:
+         /* All this does is change the mode.  */
+         break;
+
+       case FIX:
+         d = REAL_VALUE_RNDZINT (d);
+         break;
+
+       case UNSIGNED_FIX:
+         d = REAL_VALUE_UNSIGNED_RNDZINT (d);
+         break;
+
+       case SQRT:
+         return 0;
+
+       default:
+         abort ();
+       }
+
+      x = CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
+      set_float_handler (NULL_PTR);
+      return x;
+    }
+
+  else if (GET_CODE (op) == CONST_DOUBLE
+          && GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT
+          && GET_MODE_CLASS (mode) == MODE_INT
+          && width <= HOST_BITS_PER_WIDE_INT && width > 0)
+    {
+      REAL_VALUE_TYPE d;
+      jmp_buf handler;
+      HOST_WIDE_INT val;
+
+      if (setjmp (handler))
+       return 0;
+
+      set_float_handler (handler);
+
+      REAL_VALUE_FROM_CONST_DOUBLE (d, op);
+
+      switch (code)
+       {
+       case FIX:
+         val = REAL_VALUE_FIX (d);
+         break;
+
+       case UNSIGNED_FIX:
+         val = REAL_VALUE_UNSIGNED_FIX (d);
+         break;
+
+       default:
+         abort ();
+       }
+
+      set_float_handler (NULL_PTR);
+
+      val = trunc_int_for_mode (val, mode);
+
+      return GEN_INT (val);
+    }
+#endif
+  /* This was formerly used only for non-IEEE float.
+     eggert@twinsun.com says it is safe for IEEE also.  */
+  else
+    {
+      /* There are some simplifications we can do even if the operands
+        aren't constant.  */
+      switch (code)
+       {
+       case NEG:
+       case NOT:
+         /* (not (not X)) == X, similarly for NEG.  */
+         if (GET_CODE (op) == code)
+           return XEXP (op, 0);
+         break;
+
+       case SIGN_EXTEND:
+         /* (sign_extend (truncate (minus (label_ref L1) (label_ref L2))))
+            becomes just the MINUS if its mode is MODE.  This allows
+            folding switch statements on machines using casesi (such as
+            the Vax).  */
+         if (GET_CODE (op) == TRUNCATE
+             && GET_MODE (XEXP (op, 0)) == mode
+             && GET_CODE (XEXP (op, 0)) == MINUS
+             && GET_CODE (XEXP (XEXP (op, 0), 0)) == LABEL_REF
+             && GET_CODE (XEXP (XEXP (op, 0), 1)) == LABEL_REF)
+           return XEXP (op, 0);
+
+#ifdef POINTERS_EXTEND_UNSIGNED
+         if (! POINTERS_EXTEND_UNSIGNED
+             && mode == Pmode && GET_MODE (op) == ptr_mode
+             && CONSTANT_P (op))
+           return convert_memory_address (Pmode, op);
+#endif
+         break;
+
+#ifdef POINTERS_EXTEND_UNSIGNED
+       case ZERO_EXTEND:
+         if (POINTERS_EXTEND_UNSIGNED
+             && mode == Pmode && GET_MODE (op) == ptr_mode
+             && CONSTANT_P (op))
+           return convert_memory_address (Pmode, op);
+         break;
+#endif
+         
+       default:
+         break;
+       }
+
+      return 0;
+    }
+}
+\f
+/* Simplify a binary operation CODE with result mode MODE, operating on OP0
+   and OP1.  Return 0 if no simplification is possible.
+
+   Don't use this for relational operations such as EQ or LT.
+   Use simplify_relational_operation instead.  */
+
+rtx
+simplify_binary_operation (code, mode, op0, op1)
+     enum rtx_code code;
+     enum machine_mode mode;
+     rtx 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.
+     Assuming a full word can give incorrect results.
+     Consider comparing 128 with -128 in QImode.  */
+
+  if (GET_RTX_CLASS (code) == '<')
+    abort ();
+
+#if ! defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC)
+  if (GET_MODE_CLASS (mode) == MODE_FLOAT
+      && GET_CODE (op0) == CONST_DOUBLE && GET_CODE (op1) == CONST_DOUBLE
+      && mode == GET_MODE (op0) && mode == GET_MODE (op1))
+    {
+      REAL_VALUE_TYPE f0, f1, value;
+      jmp_buf handler;
+
+      if (setjmp (handler))
+       return 0;
+
+      set_float_handler (handler);
+
+      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);
+
+#ifdef REAL_ARITHMETIC
+#ifndef REAL_INFINITY
+      if (code == DIV && REAL_VALUES_EQUAL (f1, dconst0))
+       return 0;
+#endif
+      REAL_ARITHMETIC (value, rtx_to_tree_code (code), f0, f1);
+#else
+      switch (code)
+       {
+       case PLUS:
+         value = f0 + f1;
+         break;
+       case MINUS:
+         value = f0 - f1;
+         break;
+       case MULT:
+         value = f0 * f1;
+         break;
+       case DIV:
+#ifndef REAL_INFINITY
+         if (f1 == 0)
+           return 0;
+#endif
+         value = f0 / f1;
+         break;
+       case SMIN:
+         value = MIN (f0, f1);
+         break;
+       case SMAX:
+         value = MAX (f0, f1);
+         break;
+       default:
+         abort ();
+       }
+#endif
+
+      value = real_value_truncate (mode, value);
+      set_float_handler (NULL_PTR);
+      return CONST_DOUBLE_FROM_REAL_VALUE (value, mode);
+    }
+#endif  /* not REAL_IS_NOT_DOUBLE, or REAL_ARITHMETIC */
+
+  /* We can fold some multi-word operations.  */
+  if (GET_MODE_CLASS (mode) == MODE_INT
+      && width == HOST_BITS_PER_WIDE_INT * 2
+      && (GET_CODE (op0) == CONST_DOUBLE || GET_CODE (op0) == CONST_INT)
+      && (GET_CODE (op1) == CONST_DOUBLE || GET_CODE (op1) == CONST_INT))
+    {
+      HOST_WIDE_INT l1, l2, h1, h2, lv, hv;
+
+      if (GET_CODE (op0) == CONST_DOUBLE)
+       l1 = CONST_DOUBLE_LOW (op0), h1 = CONST_DOUBLE_HIGH (op0);
+      else
+       l1 = INTVAL (op0), h1 = l1 < 0 ? -1 : 0;
+
+      if (GET_CODE (op1) == CONST_DOUBLE)
+       l2 = CONST_DOUBLE_LOW (op1), h2 = CONST_DOUBLE_HIGH (op1);
+      else
+       l2 = INTVAL (op1), h2 = l2 < 0 ? -1 : 0;
+
+      switch (code)
+       {
+       case MINUS:
+         /* A - B == A + (-B).  */
+         neg_double (l2, h2, &lv, &hv);
+         l2 = lv, h2 = hv;
+
+         /* .. fall through ...  */
+
+       case PLUS:
+         add_double (l1, h1, l2, h2, &lv, &hv);
+         break;
+
+       case MULT:
+         mul_double (l1, h1, l2, h2, &lv, &hv);
+         break;
+
+       case DIV:  case MOD:   case UDIV:  case UMOD:
+         /* We'd need to include tree.h to do this and it doesn't seem worth
+            it.  */
+         return 0;
+
+       case AND:
+         lv = l1 & l2, hv = h1 & h2;
+         break;
+
+       case IOR:
+         lv = l1 | l2, hv = h1 | h2;
+         break;
+
+       case XOR:
+         lv = l1 ^ l2, hv = h1 ^ h2;
+         break;
+
+       case SMIN:
+         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 HOST_WIDE_INT) l1
+                     > (unsigned HOST_WIDE_INT) l2)))
+           lv = l1, hv = h1;
+         else
+           lv = l2, hv = h2;
+         break;
+
+       case UMIN:
+         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 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 LSHIFTRT:   case ASHIFTRT:
+       case ASHIFT:
+       case ROTATE:     case ROTATERT:
+#ifdef SHIFT_COUNT_TRUNCATED
+         if (SHIFT_COUNT_TRUNCATED)
+           l2 &= (GET_MODE_BITSIZE (mode) - 1), h2 = 0;
+#endif
+
+         if (h2 != 0 || l2 < 0 || l2 >= GET_MODE_BITSIZE (mode))
+           return 0;
+
+         if (code == LSHIFTRT || code == ASHIFTRT)
+           rshift_double (l1, h1, l2, GET_MODE_BITSIZE (mode), &lv, &hv,
+                          code == ASHIFTRT);
+         else if (code == ASHIFT)
+           lshift_double (l1, h1, l2, GET_MODE_BITSIZE (mode), &lv, &hv, 1);
+         else if (code == ROTATE)
+           lrotate_double (l1, h1, l2, GET_MODE_BITSIZE (mode), &lv, &hv);
+         else /* code == ROTATERT */
+           rrotate_double (l1, h1, l2, GET_MODE_BITSIZE (mode), &lv, &hv);
+         break;
+
+       default:
+         return 0;
+       }
+
+      return immed_double_const (lv, hv, mode);
+    }
+
+  if (GET_CODE (op0) != CONST_INT || GET_CODE (op1) != CONST_INT
+      || width > HOST_BITS_PER_WIDE_INT || width == 0)
+    {
+      /* Even if we can't compute a constant result,
+        there are some cases worth simplifying.  */
+
+      switch (code)
+       {
+       case PLUS:
+         /* In IEEE floating point, x+0 is not the same as x.  Similarly
+            for the other optimizations below.  */
+         if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
+             && FLOAT_MODE_P (mode) && ! flag_fast_math)
+           break;
+
+         if (op1 == CONST0_RTX (mode))
+           return op0;
+
+         /* ((-a) + b) -> (b - a) and similarly for (a + (-b)) */
+         if (GET_CODE (op0) == NEG)
+           return simplify_gen_binary (MINUS, mode, op1, XEXP (op0, 0));
+         else if (GET_CODE (op1) == NEG)
+           return simplify_gen_binary (MINUS, mode, op0, 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.  Don't add CONST_INT
+            to CONST_INT since overflow won't be computed properly if wider
+            than HOST_BITS_PER_WIDE_INT.  */
+
+         if (CONSTANT_P (op0) && GET_MODE (op0) != VOIDmode
+             && GET_CODE (op1) == CONST_INT)
+           return plus_constant (op0, INTVAL (op1));
+         else if (CONSTANT_P (op1) && GET_MODE (op1) != VOIDmode
+                  && GET_CODE (op0) == CONST_INT)
+           return plus_constant (op1, INTVAL (op0));
+
+         /* See if this is something like X * C - X or vice versa or
+            if the multiplication is written as a shift.  If so, we can
+            distribute and make a new multiply, shift, or maybe just
+            have X (if C is 2 in the example above).  But don't make
+            real multiply if we didn't have one before.  */
+
+         if (! FLOAT_MODE_P (mode))
+           {
+             HOST_WIDE_INT coeff0 = 1, coeff1 = 1;
+             rtx lhs = op0, rhs = op1;
+             int had_mult = 0;
+
+             if (GET_CODE (lhs) == NEG)
+               coeff0 = -1, lhs = XEXP (lhs, 0);
+             else if (GET_CODE (lhs) == MULT
+                      && GET_CODE (XEXP (lhs, 1)) == CONST_INT)
+               {
+                 coeff0 = INTVAL (XEXP (lhs, 1)), lhs = XEXP (lhs, 0);
+                 had_mult = 1;
+               }
+             else if (GET_CODE (lhs) == ASHIFT
+                      && GET_CODE (XEXP (lhs, 1)) == CONST_INT
+                      && INTVAL (XEXP (lhs, 1)) >= 0
+                      && INTVAL (XEXP (lhs, 1)) < HOST_BITS_PER_WIDE_INT)
+               {
+                 coeff0 = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (lhs, 1));
+                 lhs = XEXP (lhs, 0);
+               }
+
+             if (GET_CODE (rhs) == NEG)
+               coeff1 = -1, rhs = XEXP (rhs, 0);
+             else if (GET_CODE (rhs) == MULT
+                      && GET_CODE (XEXP (rhs, 1)) == CONST_INT)
+               {
+                 coeff1 = INTVAL (XEXP (rhs, 1)), rhs = XEXP (rhs, 0);
+                 had_mult = 1;
+               }
+             else if (GET_CODE (rhs) == ASHIFT
+                      && GET_CODE (XEXP (rhs, 1)) == CONST_INT
+                      && INTVAL (XEXP (rhs, 1)) >= 0
+                      && INTVAL (XEXP (rhs, 1)) < HOST_BITS_PER_WIDE_INT)
+               {
+                 coeff1 = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (rhs, 1));
+                 rhs = XEXP (rhs, 0);
+               }
+
+             if (rtx_equal_p (lhs, rhs))
+               {
+                 tem = simplify_gen_binary (MULT, mode, lhs,
+                                       GEN_INT (coeff0 + coeff1));
+                 return (GET_CODE (tem) == MULT && ! had_mult) ? 0 : tem;
+               }
+           }
+
+         /* 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 (INTEGRAL_MODE_P (mode)
+             && (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:
+#ifdef HAVE_cc0
+         /* Convert (compare FOO (const_int 0)) to FOO unless we aren't
+            using cc0, in which case we want to leave it as a COMPARE
+            so we can distinguish it from a register-register-copy.
+
+            In IEEE floating point, x-0 is not the same as x.  */
+
+         if ((TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
+              || ! FLOAT_MODE_P (mode) || flag_fast_math)
+             && op1 == CONST0_RTX (mode))
+           return op0;
+#else
+         /* Do nothing here.  */
+#endif
+         break;
+             
+       case MINUS:
+         /* None of these optimizations can be done for IEEE
+            floating point.  */
+         if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
+             && FLOAT_MODE_P (mode) && ! flag_fast_math)
+           break;
+
+         /* We can't assume x-x is 0 even with non-IEEE floating point,
+            but since it is zero except in very strange circumstances, we
+            will treat it as zero with -ffast-math.  */
+         if (rtx_equal_p (op0, op1)
+             && ! side_effects_p (op0)
+             && (! FLOAT_MODE_P (mode) || flag_fast_math))
+           return CONST0_RTX (mode);
+
+         /* 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;
+
+         /* See if this is something like X * C - X or vice versa or
+            if the multiplication is written as a shift.  If so, we can
+            distribute and make a new multiply, shift, or maybe just
+            have X (if C is 2 in the example above).  But don't make
+            real multiply if we didn't have one before.  */
+
+         if (! FLOAT_MODE_P (mode))
+           {
+             HOST_WIDE_INT coeff0 = 1, coeff1 = 1;
+             rtx lhs = op0, rhs = op1;
+             int had_mult = 0;
+
+             if (GET_CODE (lhs) == NEG)
+               coeff0 = -1, lhs = XEXP (lhs, 0);
+             else if (GET_CODE (lhs) == MULT
+                      && GET_CODE (XEXP (lhs, 1)) == CONST_INT)
+               {
+                 coeff0 = INTVAL (XEXP (lhs, 1)), lhs = XEXP (lhs, 0);
+                 had_mult = 1;
+               }
+             else if (GET_CODE (lhs) == ASHIFT
+                      && GET_CODE (XEXP (lhs, 1)) == CONST_INT
+                      && INTVAL (XEXP (lhs, 1)) >= 0
+                      && INTVAL (XEXP (lhs, 1)) < HOST_BITS_PER_WIDE_INT)
+               {
+                 coeff0 = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (lhs, 1));
+                 lhs = XEXP (lhs, 0);
+               }
+
+             if (GET_CODE (rhs) == NEG)
+               coeff1 = - 1, rhs = XEXP (rhs, 0);
+             else if (GET_CODE (rhs) == MULT
+                      && GET_CODE (XEXP (rhs, 1)) == CONST_INT)
+               {
+                 coeff1 = INTVAL (XEXP (rhs, 1)), rhs = XEXP (rhs, 0);
+                 had_mult = 1;
+               }
+             else if (GET_CODE (rhs) == ASHIFT
+                      && GET_CODE (XEXP (rhs, 1)) == CONST_INT
+                      && INTVAL (XEXP (rhs, 1)) >= 0
+                      && INTVAL (XEXP (rhs, 1)) < HOST_BITS_PER_WIDE_INT)
+               {
+                 coeff1 = ((HOST_WIDE_INT) 1) << INTVAL (XEXP (rhs, 1));
+                 rhs = XEXP (rhs, 0);
+               }
+
+             if (rtx_equal_p (lhs, rhs))
+               {
+                 tem = simplify_gen_binary (MULT, mode, lhs,
+                                            GEN_INT (coeff0 - coeff1));
+                 return (GET_CODE (tem) == MULT && ! had_mult) ? 0 : tem;
+               }
+           }
+
+         /* (a - (-b)) -> (a + b).  */
+         if (GET_CODE (op1) == NEG)
+           return simplify_gen_binary (PLUS, mode, op0, XEXP (op1, 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.  */
+
+         if (INTEGRAL_MODE_P (mode)
+             && (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 && GET_MODE (op0) != VOIDmode)
+           return plus_constant (op0, - INTVAL (op1));
+
+         /* (x - (x & y)) -> (x & ~y) */
+         if (GET_CODE (op1) == AND)
+           {
+            if (rtx_equal_p (op0, XEXP (op1, 0)))
+              return simplify_gen_binary (AND, mode, op0,
+                                          gen_rtx_NOT (mode, XEXP (op1, 1)));
+            if (rtx_equal_p (op0, XEXP (op1, 1)))
+              return simplify_gen_binary (AND, mode, op0,
+                                          gen_rtx_NOT (mode, XEXP (op1, 0)));
+          }
+         break;
+
+       case MULT:
+         if (op1 == constm1_rtx)
+           {
+             tem = simplify_unary_operation (NEG, mode, op0, mode);
+
+             return tem ? tem : gen_rtx_NEG (mode, op0);
+           }
+
+         /* In IEEE floating point, x*0 is not always 0.  */
+         if ((TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
+              || ! FLOAT_MODE_P (mode) || flag_fast_math)
+             && op1 == CONST0_RTX (mode)
+             && ! side_effects_p (op0))
+           return op1;
+
+         /* In IEEE floating point, x*1 is not equivalent to x for nans.
+            However, ANSI says we can drop signals,
+            so we can do this anyway.  */
+         if (op1 == CONST1_RTX (mode))
+           return op0;
+
+         /* Convert multiply by constant power of two into shift unless
+            we are still generating RTL.  This test is a kludge.  */
+         if (GET_CODE (op1) == CONST_INT
+             && (val = exact_log2 (INTVAL (op1))) >= 0
+             /* If the mode is larger than the host word size, and the
+                uppermost bit is set, then this isn't a power of two due
+                to implicit sign extension.  */
+             && (width <= HOST_BITS_PER_WIDE_INT
+                 || val != HOST_BITS_PER_WIDE_INT - 1)
+             && ! rtx_equal_function_value_matters)
+           return gen_rtx_ASHIFT (mode, op0, GEN_INT (val));
+
+         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 (op1is2 && GET_MODE (op0) == mode)
+               return gen_rtx_PLUS (mode, op0, copy_rtx (op0));
+
+             else if (op1ism1 && GET_MODE (op0) == mode)
+               return gen_rtx_NEG (mode, op0);
+           }
+         break;
+
+       case IOR:
+         if (op1 == const0_rtx)
+           return op0;
+         if (GET_CODE (op1) == CONST_INT
+             && (INTVAL (op1) & GET_MODE_MASK (mode)) == GET_MODE_MASK (mode))
+           return op1;
+         if (rtx_equal_p (op0, op1) && ! side_effects_p (op0))
+           return op0;
+         /* 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)
+             && GET_MODE_CLASS (mode) != MODE_CC)
+           return constm1_rtx;
+         break;
+
+       case XOR:
+         if (op1 == const0_rtx)
+           return op0;
+         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)
+             && GET_MODE_CLASS (mode) != MODE_CC)
+           return const0_rtx;
+         break;
+
+       case AND:
+         if (op1 == const0_rtx && ! side_effects_p (op0))
+           return const0_rtx;
+         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)
+             && 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)
+             && GET_MODE_CLASS (mode) != MODE_CC)
+           return const0_rtx;
+         break;
+
+       case UDIV:
+         /* Convert divide by power of two into shift (divide by 1 handled
+            below).  */
+         if (GET_CODE (op1) == CONST_INT
+             && (arg1 = exact_log2 (INTVAL (op1))) > 0)
+           return gen_rtx_LSHIFTRT (mode, op0, GEN_INT (arg1));
+
+         /* ... fall through ...  */
+
+       case DIV:
+         if (op1 == CONST1_RTX (mode))
+           return op0;
+
+         /* In IEEE floating point, 0/x is not always 0.  */
+         if ((TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
+              || ! FLOAT_MODE_P (mode) || flag_fast_math)
+             && op0 == CONST0_RTX (mode)
+             && ! side_effects_p (op1))
+           return op0;
+
+#if ! defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC)
+         /* Change division by a constant into multiplication.  Only do
+            this with -ffast-math until an expert says it is safe in
+            general.  */
+         else if (GET_CODE (op1) == CONST_DOUBLE
+                  && GET_MODE_CLASS (GET_MODE (op1)) == MODE_FLOAT
+                  && op1 != CONST0_RTX (mode)
+                  && flag_fast_math)
+           {
+             REAL_VALUE_TYPE d;
+             REAL_VALUE_FROM_CONST_DOUBLE (d, op1);
+
+             if (! REAL_VALUES_EQUAL (d, dconst0))
+               {
+#if defined (REAL_ARITHMETIC)
+                 REAL_ARITHMETIC (d, rtx_to_tree_code (DIV), dconst1, d);
+                 return gen_rtx_MULT (mode, op0, 
+                                      CONST_DOUBLE_FROM_REAL_VALUE (d, mode));
+#else
+                 return
+                   gen_rtx_MULT (mode, op0, 
+                                 CONST_DOUBLE_FROM_REAL_VALUE (1./d, mode));
+#endif
+               }
+           }
+#endif
+         break;
+
+       case UMOD:
+         /* Handle modulus by power of two (mod with 1 handled below).  */
+         if (GET_CODE (op1) == CONST_INT
+             && exact_log2 (INTVAL (op1)) > 0)
+           return gen_rtx_AND (mode, op0, GEN_INT (INTVAL (op1) - 1));
+
+         /* ... fall through ...  */
+
+       case MOD:
+         if ((op0 == const0_rtx || op1 == const1_rtx)
+             && ! side_effects_p (op0) && ! side_effects_p (op1))
+           return const0_rtx;
+         break;
+
+       case ROTATERT:
+       case ROTATE:
+         /* Rotating ~0 always results in ~0.  */
+         if (GET_CODE (op0) == CONST_INT && width <= HOST_BITS_PER_WIDE_INT
+             && (unsigned HOST_WIDE_INT) INTVAL (op0) == GET_MODE_MASK (mode)
+             && ! side_effects_p (op1))
+           return op0;
+
+         /* ... fall through ...  */
+
+       case ASHIFT:
+       case ASHIFTRT:
+       case LSHIFTRT:
+         if (op1 == const0_rtx)
+           return op0;
+         if (op0 == const0_rtx && ! side_effects_p (op1))
+           return op0;
+         break;
+
+       case SMIN:
+         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))
+           return op0;
+         break;
+          
+       case SMAX:
+         if (width <= HOST_BITS_PER_WIDE_INT && GET_CODE (op1) == CONST_INT
+             && ((unsigned HOST_WIDE_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))
+           return op0;
+         break;
+
+       case UMIN:
+         if (op1 == const0_rtx && ! side_effects_p (op0))
+           return op1;
+         else if (rtx_equal_p (op0, op1) && ! side_effects_p (op0))
+           return op0;
+         break;
+           
+       case UMAX:
+         if (op1 == constm1_rtx && ! side_effects_p (op0))
+           return op1;
+         else if (rtx_equal_p (op0, op1) && ! side_effects_p (op0))
+           return op0;
+         break;
+
+       default:
+         abort ();
+       }
+      
+      return 0;
+    }
+
+  /* Get the integer argument values in two forms:
+     zero-extended in ARG0, ARG1 and sign-extended in ARG0S, ARG1S.  */
+
+  arg0 = INTVAL (op0);
+  arg1 = INTVAL (op1);
+
+  if (width < HOST_BITS_PER_WIDE_INT)
+    {
+      arg0 &= ((HOST_WIDE_INT) 1 << width) - 1;
+      arg1 &= ((HOST_WIDE_INT) 1 << width) - 1;
+
+      arg0s = arg0;
+      if (arg0s & ((HOST_WIDE_INT) 1 << (width - 1)))
+       arg0s |= ((HOST_WIDE_INT) (-1) << width);
+
+      arg1s = arg1;
+      if (arg1s & ((HOST_WIDE_INT) 1 << (width - 1)))
+       arg1s |= ((HOST_WIDE_INT) (-1) << width);
+    }
+  else
+    {
+      arg0s = arg0;
+      arg1s = arg1;
+    }
+
+  /* Compute the value of the arithmetic.  */
+
+  switch (code)
+    {
+    case PLUS:
+      val = arg0s + arg1s;
+      break;
+
+    case MINUS:
+      val = arg0s - arg1s;
+      break;
+
+    case MULT:
+      val = arg0s * arg1s;
+      break;
+
+    case DIV:
+      if (arg1s == 0)
+       return 0;
+      val = arg0s / arg1s;
+      break;
+
+    case MOD:
+      if (arg1s == 0)
+       return 0;
+      val = arg0s % arg1s;
+      break;
+
+    case UDIV:
+      if (arg1 == 0)
+       return 0;
+      val = (unsigned HOST_WIDE_INT) arg0 / arg1;
+      break;
+
+    case UMOD:
+      if (arg1 == 0)
+       return 0;
+      val = (unsigned HOST_WIDE_INT) arg0 % arg1;
+      break;
+
+    case AND:
+      val = arg0 & arg1;
+      break;
+
+    case IOR:
+      val = arg0 | arg1;
+      break;
+
+    case XOR:
+      val = arg0 ^ arg1;
+      break;
+
+    case LSHIFTRT:
+      /* If shift count is undefined, don't fold it; let the machine do
+        what it wants.  But truncate it if the machine will do that.  */
+      if (arg1 < 0)
+       return 0;
+
+#ifdef SHIFT_COUNT_TRUNCATED
+      if (SHIFT_COUNT_TRUNCATED)
+       arg1 %= width;
+#endif
+
+      val = ((unsigned HOST_WIDE_INT) arg0) >> arg1;
+      break;
+
+    case ASHIFT:
+      if (arg1 < 0)
+       return 0;
+
+#ifdef SHIFT_COUNT_TRUNCATED
+      if (SHIFT_COUNT_TRUNCATED)
+       arg1 %= width;
+#endif
+
+      val = ((unsigned HOST_WIDE_INT) arg0) << arg1;
+      break;
+
+    case ASHIFTRT:
+      if (arg1 < 0)
+       return 0;
+
+#ifdef SHIFT_COUNT_TRUNCATED
+      if (SHIFT_COUNT_TRUNCATED)
+       arg1 %= width;
+#endif
+
+      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:
+      if (arg1 < 0)
+       return 0;
+
+      arg1 %= width;
+      val = ((((unsigned HOST_WIDE_INT) arg0) << (width - arg1))
+            | (((unsigned HOST_WIDE_INT) arg0) >> arg1));
+      break;
+
+    case ROTATE:
+      if (arg1 < 0)
+       return 0;
+
+      arg1 %= width;
+      val = ((((unsigned HOST_WIDE_INT) arg0) << arg1)
+            | (((unsigned HOST_WIDE_INT) arg0) >> (width - arg1)));
+      break;
+
+    case COMPARE:
+      /* Do nothing here.  */
+      return 0;
+
+    case SMIN:
+      val = arg0s <= arg1s ? arg0s : arg1s;
+      break;
+
+    case UMIN:
+      val = ((unsigned HOST_WIDE_INT) arg0
+            <= (unsigned HOST_WIDE_INT) arg1 ? arg0 : arg1);
+      break;
+
+    case SMAX:
+      val = arg0s > arg1s ? arg0s : arg1s;
+      break;
+
+    case UMAX:
+      val = ((unsigned HOST_WIDE_INT) arg0
+            > (unsigned HOST_WIDE_INT) arg1 ? arg0 : arg1);
+      break;
+
+    default:
+      abort ();
+    }
+
+  val = trunc_int_for_mode (val, mode);
+
+  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 ((char *) 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;
+
+         default:
+           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 = simplify_gen_binary (negs[i] ? MINUS : PLUS, mode, result, ops[i]);
+
+  return negate ? gen_rtx_NEG (mode, result) : result;
+}
+
+struct cfc_args
+{
+  /* Input */
+  rtx op0, op1;
+  /* Output */
+  int equal, op0lt, op1lt;
+};
+
+static void
+check_fold_consts (data)
+  PTR data;
+{
+  struct cfc_args * args = (struct cfc_args *) data;
+  REAL_VALUE_TYPE d0, d1;
+
+  REAL_VALUE_FROM_CONST_DOUBLE (d0, args->op0);
+  REAL_VALUE_FROM_CONST_DOUBLE (d1, args->op1);
+  args->equal = REAL_VALUES_EQUAL (d0, d1);
+  args->op0lt = REAL_VALUES_LESS (d0, d1);
+  args->op1lt = REAL_VALUES_LESS (d1, d0);
+}
+
+/* Like simplify_binary_operation except used for relational operators.
+   MODE is the mode of the operands, not that of the result.  If MODE
+   is VOIDmode, both operands must also be VOIDmode and we compare the
+   operands in "infinite precision".
+
+   If no simplification is possible, this function returns zero.  Otherwise,
+   it returns either const_true_rtx or const0_rtx.  */
+
+rtx
+simplify_relational_operation (code, mode, op0, op1)
+     enum rtx_code code;
+     enum machine_mode mode;
+     rtx op0, op1;
+{
+  int equal, op0lt, op0ltu, op1lt, op1ltu;
+  rtx tem;
+
+  /* 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);
+
+  /* We can't simplify MODE_CC values since we don't know what the
+     actual comparison is.  */
+  if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_CC
+#ifdef HAVE_cc0
+      || op0 == cc0_rtx
+#endif
+      )
+    return 0;
+
+  /* For integer comparisons of A and B maybe we can simplify A - B and can
+     then simplify a comparison of that with zero.  If A and B are both either
+     a register or a CONST_INT, this can't help; testing for these cases will
+     prevent infinite recursion here and speed things up.
+
+     If CODE is an unsigned comparison, then we can never do this optimization,
+     because it gives an incorrect result if the subtraction wraps around zero.
+     ANSI C defines unsigned operations such that they never overflow, and
+     thus such cases can not be ignored.  */
+
+  if (INTEGRAL_MODE_P (mode) && op1 != const0_rtx
+      && ! ((GET_CODE (op0) == REG || GET_CODE (op0) == CONST_INT)
+           && (GET_CODE (op1) == REG || GET_CODE (op1) == CONST_INT))
+      && 0 != (tem = simplify_binary_operation (MINUS, mode, op0, op1))
+      && code != GTU && code != GEU && code != LTU && code != LEU)
+    return simplify_relational_operation (signed_condition (code),
+                                         mode, tem, const0_rtx);
+
+  /* For non-IEEE floating-point, if the two operands are equal, we know the
+     result.  */
+  if (rtx_equal_p (op0, op1)
+      && (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
+         || ! FLOAT_MODE_P (GET_MODE (op0)) || flag_fast_math))
+    equal = 1, op0lt = 0, op0ltu = 0, op1lt = 0, op1ltu = 0;
+
+  /* If the operands are floating-point constants, see if we can fold
+     the result.  */
+#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)
+    {
+      struct cfc_args args;
+
+      /* Setup input for check_fold_consts() */
+      args.op0 = op0;
+      args.op1 = op1;
+      
+      if (do_float_handler(check_fold_consts, (PTR) &args) == 0)
+       /* We got an exception from check_fold_consts() */
+       return 0;
+
+      /* Receive output from check_fold_consts() */
+      equal = args.equal;
+      op0lt = op0ltu = args.op0lt;
+      op1lt = op1ltu = args.op1lt;
+    }
+#endif  /* not REAL_IS_NOT_DOUBLE, or REAL_ARITHMETIC */
+
+  /* Otherwise, see if the operands are both integers.  */
+  else if ((GET_MODE_CLASS (mode) == MODE_INT || mode == VOIDmode)
+          && (GET_CODE (op0) == CONST_DOUBLE || GET_CODE (op0) == CONST_INT)
+          && (GET_CODE (op1) == CONST_DOUBLE || GET_CODE (op1) == CONST_INT))
+    {
+      int width = GET_MODE_BITSIZE (mode);
+      HOST_WIDE_INT l0s, h0s, l1s, h1s;
+      unsigned HOST_WIDE_INT l0u, h0u, l1u, h1u;
+
+      /* Get the two words comprising each integer constant.  */
+      if (GET_CODE (op0) == CONST_DOUBLE)
+       {
+         l0u = l0s = CONST_DOUBLE_LOW (op0);
+         h0u = h0s = CONST_DOUBLE_HIGH (op0);
+       }
+      else
+       {
+         l0u = l0s = INTVAL (op0);
+         h0u = h0s = l0s < 0 ? -1 : 0;
+       }
+         
+      if (GET_CODE (op1) == CONST_DOUBLE)
+       {
+         l1u = l1s = CONST_DOUBLE_LOW (op1);
+         h1u = h1s = CONST_DOUBLE_HIGH (op1);
+       }
+      else
+       {
+         l1u = l1s = INTVAL (op1);
+         h1u = h1s = l1s < 0 ? -1 : 0;
+       }
+
+      /* If WIDTH is nonzero and smaller than HOST_BITS_PER_WIDE_INT,
+        we have to sign or zero-extend the values.  */
+      if (width != 0 && width <= HOST_BITS_PER_WIDE_INT)
+       h0u = h1u = 0, h0s = l0s < 0 ? -1 : 0, h1s = l1s < 0 ? -1 : 0;
+
+      if (width != 0 && width < HOST_BITS_PER_WIDE_INT)
+       {
+         l0u &= ((HOST_WIDE_INT) 1 << width) - 1;
+         l1u &= ((HOST_WIDE_INT) 1 << width) - 1;
+
+         if (l0s & ((HOST_WIDE_INT) 1 << (width - 1)))
+           l0s |= ((HOST_WIDE_INT) (-1) << width);
+
+         if (l1s & ((HOST_WIDE_INT) 1 << (width - 1)))
+           l1s |= ((HOST_WIDE_INT) (-1) << width);
+       }
+
+      equal = (h0u == h1u && l0u == l1u);
+      op0lt = (h0s < h1s || (h0s == h1s && l0s < l1s));
+      op1lt = (h1s < h0s || (h1s == h0s && l1s < l0s));
+      op0ltu = (h0u < h1u || (h0u == h1u && l0u < l1u));
+      op1ltu = (h1u < h0u || (h1u == h0u && l1u < l0u));
+    }
+
+  /* Otherwise, there are some code-specific tests we can make.  */
+  else
+    {
+      switch (code)
+       {
+       case EQ:
+         /* References to the frame plus a constant or labels cannot
+            be zero, but a SYMBOL_REF can due to #pragma weak.  */
+         if (((NONZERO_BASE_PLUS_P (op0) && op1 == const0_rtx)
+              || GET_CODE (op0) == LABEL_REF)
+#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
+             /* On some machines, the ap reg can be 0 sometimes.  */
+             && op0 != arg_pointer_rtx
+#endif
+               )
+           return const0_rtx;
+         break;
+
+       case NE:
+         if (((NONZERO_BASE_PLUS_P (op0) && op1 == const0_rtx)
+              || GET_CODE (op0) == LABEL_REF)
+#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
+             && op0 != arg_pointer_rtx
+#endif
+             )
+           return const_true_rtx;
+         break;
+
+       case GEU:
+         /* Unsigned values are never negative.  */
+         if (op1 == const0_rtx)
+           return const_true_rtx;
+         break;
+
+       case LTU:
+         if (op1 == const0_rtx)
+           return const0_rtx;
+         break;
+
+       case LEU:
+         /* Unsigned values are never greater than the largest
+            unsigned value.  */
+         if (GET_CODE (op1) == CONST_INT
+             && (unsigned HOST_WIDE_INT) INTVAL (op1) == GET_MODE_MASK (mode)
+           && INTEGRAL_MODE_P (mode))
+         return const_true_rtx;
+         break;
+
+       case GTU:
+         if (GET_CODE (op1) == CONST_INT
+             && (unsigned HOST_WIDE_INT) INTVAL (op1) == GET_MODE_MASK (mode)
+             && INTEGRAL_MODE_P (mode))
+           return const0_rtx;
+         break;
+         
+       default:
+         break;
+       }
+
+      return 0;
+    }
+
+  /* If we reach here, EQUAL, OP0LT, OP0LTU, OP1LT, and OP1LTU are set
+     as appropriate.  */
+  switch (code)
+    {
+    case EQ:
+      return equal ? const_true_rtx : const0_rtx;
+    case NE:
+      return ! equal ? const_true_rtx : const0_rtx;
+    case LT:
+      return op0lt ? const_true_rtx : const0_rtx;
+    case GT:
+      return op1lt ? const_true_rtx : const0_rtx;
+    case LTU:
+      return op0ltu ? const_true_rtx : const0_rtx;
+    case GTU:
+      return op1ltu ? const_true_rtx : const0_rtx;
+    case LE:
+      return equal || op0lt ? const_true_rtx : const0_rtx;
+    case GE:
+      return equal || op1lt ? const_true_rtx : const0_rtx;
+    case LEU:
+      return equal || op0ltu ? const_true_rtx : const0_rtx;
+    case GEU:
+      return equal || op1ltu ? const_true_rtx : const0_rtx;
+    default:
+      abort ();
+    }
+}
+\f
+/* Simplify CODE, an operation with result mode MODE and three operands,
+   OP0, OP1, and OP2.  OP0_MODE was the mode of OP0 before it became
+   a constant.  Return 0 if no simplifications is possible.  */
+
+rtx
+simplify_ternary_operation (code, mode, op0_mode, op0, op1, op2)
+     enum rtx_code code;
+     enum machine_mode mode, op0_mode;
+     rtx op0, op1, op2;
+{
+  int width = GET_MODE_BITSIZE (mode);
+
+  /* VOIDmode means "infinite" precision.  */
+  if (width == 0)
+    width = HOST_BITS_PER_WIDE_INT;
+
+  switch (code)
+    {
+    case SIGN_EXTRACT:
+    case ZERO_EXTRACT:
+      if (GET_CODE (op0) == CONST_INT
+         && GET_CODE (op1) == CONST_INT
+         && GET_CODE (op2) == CONST_INT
+         && INTVAL (op1) + INTVAL (op2) <= GET_MODE_BITSIZE (op0_mode)
+         && width <= HOST_BITS_PER_WIDE_INT)
+       {
+         /* Extracting a bit-field from a constant */
+         HOST_WIDE_INT val = INTVAL (op0);
+
+         if (BITS_BIG_ENDIAN)
+           val >>= (GET_MODE_BITSIZE (op0_mode)
+                    - INTVAL (op2) - INTVAL (op1));
+         else
+           val >>= INTVAL (op2);
+
+         if (HOST_BITS_PER_WIDE_INT != INTVAL (op1))
+           {
+             /* First zero-extend.  */
+             val &= ((HOST_WIDE_INT) 1 << INTVAL (op1)) - 1;
+             /* If desired, propagate sign bit.  */
+             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_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);
+       }
+      break;
+
+    case IF_THEN_ELSE:
+      if (GET_CODE (op0) == CONST_INT)
+       return op0 != const0_rtx ? op1 : op2;
+
+      /* Convert a == b ? b : a to "a".  */
+      if (GET_CODE (op0) == NE && ! side_effects_p (op0)
+         && rtx_equal_p (XEXP (op0, 0), op1)
+         && rtx_equal_p (XEXP (op0, 1), op2))
+       return op1;
+      else if (GET_CODE (op0) == EQ && ! side_effects_p (op0)
+         && rtx_equal_p (XEXP (op0, 1), op1)
+         && rtx_equal_p (XEXP (op0, 0), op2))
+       return op2;
+      else if (GET_RTX_CLASS (GET_CODE (op0)) == '<' && ! side_effects_p (op0))
+       {
+         rtx temp;
+         temp = simplify_relational_operation (GET_CODE (op0), op0_mode,
+                                               XEXP (op0, 0), XEXP (op0, 1));
+         /* See if any simplifications were possible.  */
+         if (temp == const0_rtx)
+           return op2;
+         else if (temp == const1_rtx)
+           return op1;
+       }
+      break;
+
+    default:
+      abort ();
+    }
+
+  return 0;
+}
+
+/* Simplify X, an rtx expression.
+
+   Return the simplified expression or NULL if no simplifications
+   were possible.
+
+   This is the preferred entry point into the simplification routines;
+   however, we still allow passes to call the more specific routines.
+
+   Right now GCC has three (yes, three) major bodies of RTL simplficiation
+   code that need to be unified.
+
+       1. fold_rtx in cse.c.  This code uses various CSE specific
+          information to aid in RTL simplification.
+
+       2. simplify_rtx in combine.c.  Similar to fold_rtx, except that
+          it uses combine specific information to aid in RTL
+          simplification.
+
+       3. The routines in this file.
+
+
+   Long term we want to only have one body of simplification code; to
+   get to that state I recommend the following steps:
+
+       1. Pour over fold_rtx & simplify_rtx and move any simplifications
+          which are not pass dependent state into these routines.
+
+       2. As code is moved by #1, change fold_rtx & simplify_rtx to
+          use this routine whenever possible.
+
+       3. Allow for pass dependent state to be provided to these
+          routines and add simplifications based on the pass dependent
+          state.  Remove code from cse.c & combine.c that becomes
+          redundant/dead.
+
+    It will take time, but ultimately the compiler will be easier to
+    maintain and improve.  It's totally silly that when we add a
+    simplification that it needs to be added to 4 places (3 for RTL
+    simplification and 1 for tree simplification.  */
+          
+rtx
+simplify_rtx (x)
+     rtx x;
+{
+  enum rtx_code code;
+  enum machine_mode mode;
+  rtx new;
+
+  mode = GET_MODE (x);
+  code = GET_CODE (x);
+
+  switch (GET_RTX_CLASS (code))
+    {
+    case '1':
+      return simplify_unary_operation (code, mode,
+                                      XEXP (x, 0), GET_MODE (XEXP (x, 0)));
+    case '2':
+    case 'c':
+      return simplify_binary_operation (code, mode, XEXP (x, 0), XEXP (x, 1));
+
+    case '3':
+    case 'b':
+      return simplify_ternary_operation (code, mode, GET_MODE (XEXP (x, 0)),
+                                        XEXP (x, 0), XEXP (x, 1), XEXP (x, 2));
+
+    case '<':
+      return simplify_relational_operation (code, GET_MODE (XEXP (x, 0)),
+                                           XEXP (x, 0), XEXP (x, 1));
+    default:
+      return NULL;
+    }
+}