* fold-const.c (negate_expr, associate_trees, extract_muldiv): New.
authorkenner <kenner@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 27 Nov 1999 13:50:13 +0000 (13:50 +0000)
committerkenner <kenner@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 27 Nov 1999 13:50:13 +0000 (13:50 +0000)
(split_tree): Completely rework to make more general.
(make_range, fold): Call negate_expr.
(fold, case NEGATE_EXPR): Simplify -(a-b) is -ffast-math.
(fold, associate): Call new split_tree and associate_trees.
(fold, case MULT_EXPR, case *_{DIV,MOD}_EXPR): Call extract_muldiv.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@30673 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/fold-const.c

index 7b12c26..ec399ec 100644 (file)
@@ -1,3 +1,12 @@
+Sat Nov 27 08:38:26 1999  Richard Kenner  <kenner@vlsi1.ultra.nyu.edu>
+
+       * fold-const.c (negate_expr, associate_trees, extract_muldiv): New.
+       (split_tree): Completely rework to make more general.
+       (make_range, fold): Call negate_expr.
+       (fold, case NEGATE_EXPR): Simplify -(a-b) is -ffast-math.
+       (fold, associate): Call new split_tree and associate_trees.
+       (fold, case MULT_EXPR, case *_{DIV,MOD}_EXPR): Call extract_muldiv.
+
 1999-11-26  Bernd Schmidt  <bernds@cygnus.co.uk>
 
        * loop.c (try_copy_prop): Avoid GNU C extension.
index b93f49e..e48f0e2 100644 (file)
@@ -61,8 +61,10 @@ int div_and_round_double     PROTO((enum tree_code, int, HOST_WIDE_INT,
                                       HOST_WIDE_INT, HOST_WIDE_INT *,
                                       HOST_WIDE_INT *, HOST_WIDE_INT *,
                                       HOST_WIDE_INT *));
-static int split_tree          PROTO((tree, enum tree_code, tree *,
-                                      tree *, int *));
+static tree negate_expr                PROTO((tree));
+static tree split_tree         PROTO((tree, enum tree_code, tree *, tree *,
+                                      int));
+static tree associate_trees    PROTO((tree, tree, enum tree_code, tree));
 static tree int_const_binop    PROTO((enum tree_code, tree, tree, int, int));
 static tree const_binop                PROTO((enum tree_code, tree, tree, int));
 static tree fold_convert       PROTO((tree, tree));
@@ -93,6 +95,7 @@ static tree fold_range_test   PROTO((tree));
 static tree unextend           PROTO((tree, int, int, tree));
 static tree fold_truthop       PROTO((enum tree_code, tree, tree, tree));
 static tree optimize_minmax_comparison PROTO((tree));
+static tree extract_muldiv     PROTO((tree, tree, enum tree_code, tree));
 static tree strip_compound_expr PROTO((tree, tree));
 static int multiple_of_p       PROTO((tree, tree, tree));
 static tree constant_boolean_node PROTO((int, tree));
@@ -1199,93 +1202,181 @@ real_hex_to_f (s, mode)
 
 #endif /* no REAL_ARITHMETIC */
 \f
-/* Split a tree IN into a constant and a variable part
-   that could be combined with CODE to make IN.
-   CODE must be a commutative arithmetic operation.
-   Store the constant part into *CONP and the variable in &VARP.
-   Return 1 if this was done; zero means the tree IN did not decompose
-   this way.
-
-   If CODE is PLUS_EXPR we also split trees that use MINUS_EXPR.
-   Therefore, we must tell the caller whether the variable part
-   was subtracted.  We do this by storing 1 or -1 into *VARSIGNP.
-   The value stored is the coefficient for the variable term.
-   The constant term we return should always be added;
-   we negate it if necessary.  */
+/* Given T, an expression, return the negation of T.  Allow for T to be
+   null, in which case return null.  */
 
-static int
-split_tree (in, code, varp, conp, varsignp)
+static tree
+negate_expr (t)
+     tree t;
+{
+  tree type;
+  tree tem;
+
+  if (t == 0)
+    return 0;
+
+  type = TREE_TYPE (t);
+  STRIP_SIGN_NOPS (t);
+
+  switch (TREE_CODE (t))
+    {
+    case INTEGER_CST:
+    case REAL_CST:
+      if (! TREE_UNSIGNED (type)
+         && 0 != (tem = fold (build1 (NEGATE_EXPR, type, t)))
+         && ! TREE_OVERFLOW (tem))
+       return tem;
+      break;
+
+    case NEGATE_EXPR:
+      return convert (type, TREE_OPERAND (t, 0));
+
+    case MINUS_EXPR:
+      /* - (A - B) -> B - A  */
+      if (! FLOAT_TYPE_P (type) || flag_fast_math)
+       return convert (type,
+                       fold (build (MINUS_EXPR, TREE_TYPE (t),
+                                    TREE_OPERAND (t, 1),
+                                    TREE_OPERAND (t, 0))));
+      break;
+
+    default:
+      break;
+    }
+
+  return convert (type, build1 (NEGATE_EXPR, TREE_TYPE (t), t));
+}
+\f
+/* Split a tree IN into a constant, literal and variable parts that could be
+   combined with CODE to make IN.  "constant" means an expression with
+   TREE_CONSTANT but that isn't an actual constant.  CODE must be a
+   commutative arithmetic operation.  Store the constant part into *CONP,
+   the literal in &LITP and return the variable part.  If a part isn't
+   present, set it to null.  If the tree does not decompose in this way,
+   return the entire tree as the variable part and the other parts as null.
+
+   If CODE is PLUS_EXPR we also split trees that use MINUS_EXPR.  In that
+   case, we negate an operand that was subtracted.  If NEGATE_P is true, we
+   are negating all of IN.
+
+   If IN is itself a literal or constant, return it as appropriate.
+
+   Note that we do not guarantee that any of the three values will be the
+   same type as IN, but they will have the same signedness and mode.  */
+
+static tree
+split_tree (in, code, conp, litp, negate_p)
      tree in;
      enum tree_code code;
-     tree *varp, *conp;
-     int *varsignp;
+     tree *conp, *litp;
+     int negate_p;
 {
-  register tree outtype = TREE_TYPE (in);
-  *varp = 0;
+  tree orig_in = in;
+  tree type = TREE_TYPE (in);
+  tree var = 0;
+
   *conp = 0;
+  *litp = 0;
+
+  /* Strip any conversions that don't change the machine mode or signedness. */
+  STRIP_SIGN_NOPS (in);
+
+  if (TREE_CODE (in) == INTEGER_CST || TREE_CODE (in) == REAL_CST)
+    *litp = in;
+  else if (TREE_CONSTANT (in))
+    *conp = in;
+
+  else if (TREE_CODE (in) == code
+          || (! FLOAT_TYPE_P (TREE_TYPE (in))
+              /* We can associate addition and subtraction together (even
+                 though the C standard doesn't say so) for integers because
+                 the value is not affected.  For reals, the value might be
+                 affected, so we can't.  */
+              && ((code == PLUS_EXPR && TREE_CODE (in) == MINUS_EXPR)
+                  || (code == MINUS_EXPR && TREE_CODE (in) == PLUS_EXPR))))
+    {
+      tree op0 = TREE_OPERAND (in, 0);
+      tree op1 = TREE_OPERAND (in, 1);
+      int neg1_p = TREE_CODE (in) == MINUS_EXPR;
+      int neg_litp_p = 0, neg_conp_p = 0, neg_var_p = 0;
+
+      /* First see if either of the operands is a literal, then a constant.  */
+      if (TREE_CODE (op0) == INTEGER_CST || TREE_CODE (op0) == REAL_CST)
+       *litp = op0, op0 = 0;
+      else if (TREE_CODE (op1) == INTEGER_CST || TREE_CODE (op1) == REAL_CST)
+       *litp = op1, neg_litp_p = neg1_p, op1 = 0;
+
+      if (op0 != 0 && TREE_CONSTANT (op0))
+       *conp = op0, op0 = 0;
+      else if (op1 != 0 && TREE_CONSTANT (op1))
+       *conp = op1, neg_conp_p = neg1_p, op1 = 0;
+
+      /* If we haven't dealt with either operand, this is not a case we can
+        decompose.  Otherwise, VAR is either of the ones remaining, if any. */
+      if (op0 != 0 && op1 != 0)
+       var = in;
+      else if (op0 != 0)
+       var = op0;
+      else
+       var = op1, neg_var_p = neg1_p;
 
-  /* Strip any conversions that don't change the machine mode.  */
-  while ((TREE_CODE (in) == NOP_EXPR
-         || TREE_CODE (in) == CONVERT_EXPR)
-        && (TYPE_MODE (TREE_TYPE (in))
-            == TYPE_MODE (TREE_TYPE (TREE_OPERAND (in, 0)))))
-    in = TREE_OPERAND (in, 0);
-
-  if (TREE_CODE (in) == code
-      || (! FLOAT_TYPE_P (TREE_TYPE (in))
-         /* We can associate addition and subtraction together
-            (even though the C standard doesn't say so)
-            for integers because the value is not affected.
-            For reals, the value might be affected, so we can't.  */
-         && ((code == PLUS_EXPR && TREE_CODE (in) == MINUS_EXPR)
-             || (code == MINUS_EXPR && TREE_CODE (in) == PLUS_EXPR))))
+      /* Now do any needed negations.  */
+      if (neg_litp_p) *litp = negate_expr (*litp);
+      if (neg_conp_p) *conp = negate_expr (*conp);
+      if (neg_var_p) var = negate_expr (var);
+    }
+  else
+    var = in;
+
+  if (negate_p)
     {
-      enum tree_code code = TREE_CODE (TREE_OPERAND (in, 0));
-      if (code == INTEGER_CST)
-       {
-         *conp = TREE_OPERAND (in, 0);
-         *varp = TREE_OPERAND (in, 1);
-         if (TYPE_MODE (TREE_TYPE (*varp)) != TYPE_MODE (outtype)
-             && TREE_TYPE (*varp) != outtype)
-           *varp = convert (outtype, *varp);
-         *varsignp = (TREE_CODE (in) == MINUS_EXPR) ? -1 : 1;
-         return 1;
-       }
-      if (TREE_CONSTANT (TREE_OPERAND (in, 1)))
-       {
-         *conp = TREE_OPERAND (in, 1);
-         *varp = TREE_OPERAND (in, 0);
-         *varsignp = 1;
-         if (TYPE_MODE (TREE_TYPE (*varp)) != TYPE_MODE (outtype)
-             && TREE_TYPE (*varp) != outtype)
-           *varp = convert (outtype, *varp);
-         if (TREE_CODE (in) == MINUS_EXPR)
-           {
-             /* If operation is subtraction and constant is second,
-                must negate it to get an additive constant.
-                And this cannot be done unless it is a manifest constant.
-                It could also be the address of a static variable.
-                We cannot negate that, so give up.  */
-             if (TREE_CODE (*conp) == INTEGER_CST)
-               /* Subtracting from integer_zero_node loses for long long.  */
-               *conp = fold (build1 (NEGATE_EXPR, TREE_TYPE (*conp), *conp));
-             else
-               return 0;
-           }
-         return 1;
-       }
-      if (TREE_CONSTANT (TREE_OPERAND (in, 0)))
-       {
-         *conp = TREE_OPERAND (in, 0);
-         *varp = TREE_OPERAND (in, 1);
-         if (TYPE_MODE (TREE_TYPE (*varp)) != TYPE_MODE (outtype)
-             && TREE_TYPE (*varp) != outtype)
-           *varp = convert (outtype, *varp);
-         *varsignp = (TREE_CODE (in) == MINUS_EXPR) ? -1 : 1;
-         return 1;
-       }
+      var = negate_expr (var);
+      *conp = negate_expr (*conp);
+      *litp = negate_expr (*litp);
     }
-  return 0;
+
+  return var;
+}
+
+/* Re-associate trees split by the above function.  T1 and T2 are either
+   expressions to associate or null.  Return the new expression, if any.  If
+   we build an operation, do it in TYPE and with CODE, except if CODE is a
+   MINUS_EXPR, in which case we use PLUS_EXPR since split_tree will already
+   have taken care of the negations.  */
+
+static tree
+associate_trees (t1, t2, code, type)
+     tree t1, t2;
+     enum tree_code code;
+     tree type;
+{
+  tree tem;
+
+  if (t1 == 0)
+    return t2;
+  else if (t2 == 0)
+    return t1;
+
+  if (code == MINUS_EXPR)
+    code = PLUS_EXPR;
+
+  /* If either input is CODE, a PLUS_EXPR, or a MINUS_EXPR, don't
+     try to fold this since we will have infinite recursion.  But do
+     deal with any NEGATE_EXPRs.  */
+  if (TREE_CODE (t1) == code || TREE_CODE (t2) == code
+      || TREE_CODE (t1) == MINUS_EXPR || TREE_CODE (t2) == MINUS_EXPR)
+    {
+      if (TREE_CODE (t1) == NEGATE_EXPR)
+       return build (MINUS_EXPR, type, convert (type, t2),
+                     convert (type, TREE_OPERAND (t1, 0)));
+      else if (TREE_CODE (t2) == NEGATE_EXPR)
+       return build (MINUS_EXPR, type, convert (type, t1),
+                     convert (type, TREE_OPERAND (t2, 0)));
+      else
+       return build (code, type, convert (type, t1), convert (type, t2));
+    }
+
+  return fold (build (code, type, convert (type, t1), convert (type, t2)));
 }
 \f
 /* Combine two integer constants ARG1 and ARG2 under operation CODE
@@ -3249,7 +3340,7 @@ make_range (exp, pin_p, plow, phigh)
 
        case BIT_NOT_EXPR:
          /* ~ X -> -X - 1  */
-         exp = build (MINUS_EXPR, type, build1 (NEGATE_EXPR, type, arg0),
+         exp = build (MINUS_EXPR, type, negate_expr (arg0),
                       convert (type, integer_one_node));
          continue;
 
@@ -4154,6 +4245,213 @@ optimize_minmax_comparison (t)
     }
 }
 \f
+/* T is an integer expression that is being multiplied, divided, or taken a
+   modulus (CODE says which and what kind of divide or modulus) by a
+   constant C.  See if we can eliminate that operation by folding it with
+   other operations already in T.  WIDE_TYPE, if non-null, is a type that
+   should be used for the computation if wider than our type.
+
+   For example, if we are dividing (X * 8) + (Y + 16) by 4, we can return
+   (X * 2) + (Y + 4).  We also canonicalize (X + 7) * 4 into X * 4 + 28
+   in the hope that either the machine has a multiply-accumulate insn
+   or that this is part of an addressing calculation.
+
+   If we return a non-null expression, it is an equivalent form of the
+   original computation, but need not be in the original type.  */
+
+static tree
+extract_muldiv (t, c, code, wide_type)
+     tree t;
+     tree c;
+     enum tree_code code;
+     tree wide_type;
+{
+  tree type = TREE_TYPE (t);
+  enum tree_code tcode = TREE_CODE (t);
+  tree ctype = (wide_type != 0 && (GET_MODE_SIZE (TYPE_MODE (wide_type)) 
+                                  > GET_MODE_SIZE (TYPE_MODE (type)))
+               ? wide_type : type);
+  tree t1, t2;
+  int same_p = tcode == code;
+  int cancel_p
+    = (code == MULT_EXPR && tcode == EXACT_DIV_EXPR)  || tcode == MULT_EXPR;
+  tree op0, op1;
+
+  /* Don't deal with constants of zero here; they confuse the code below.  */
+  if (integer_zerop (c))
+    return 0;
+
+  if (TREE_CODE_CLASS (tcode) == '1')
+    op0 = TREE_OPERAND (t, 0);
+
+  if (TREE_CODE_CLASS (tcode) == '2')
+    op0 = TREE_OPERAND (t, 0), op1 = TREE_OPERAND (t, 1);
+
+  /* Note that we need not handle conditional operations here since fold
+     already handles those cases.  So just do arithmetic here.  */
+  switch (tcode)
+    {
+    case INTEGER_CST:
+      /* For a constant, we can always simplify if we are a multiply
+        or (for divide and modulus) if it is a multiple of our constant.  */
+      if (code == MULT_EXPR
+         || integer_zerop (const_binop (TRUNC_MOD_EXPR, t, c, 0)))
+       return const_binop (code, convert (ctype, t), convert (ctype, c), 0);
+      break;
+
+    case CONVERT_EXPR:  case NON_LVALUE_EXPR:  case NOP_EXPR:
+
+      /* Pass the constant down and see if we can make a simplification.  If
+        we can, replace this expression with a conversion of that result to
+        our type.  */
+      if (0 != (t1 = extract_muldiv (op0, convert (TREE_TYPE (op0), c), code,
+                                    code == MULT_EXPR ? ctype : NULL_TREE)))
+       return t1;
+      break;
+
+    case NEGATE_EXPR:  case ABS_EXPR:
+      if ((t1 = extract_muldiv (op0, c, code, wide_type)) != 0)
+       return fold (build1 (tcode, ctype, convert (ctype, t1)));
+      break;
+
+    case MIN_EXPR:  case MAX_EXPR:
+      /* MIN (a, b) / 5 -> MIN (a / 5, b / 5)  */
+      if ((t1 = extract_muldiv (op0, c, code, wide_type)) != 0
+         && (t2 = extract_muldiv (op1, c, code, wide_type)) != 0)
+       return fold (build (tcode, ctype, convert (ctype, t1),
+                           convert (ctype, t2)));
+      break;
+
+    case WITH_RECORD_EXPR:
+      if ((t1 = extract_muldiv (TREE_OPERAND (t, 0), c, code, wide_type)) != 0)
+       return build (WITH_RECORD_EXPR, TREE_TYPE (t1), t1,
+                     TREE_OPERAND (t, 1));
+      break;
+
+    case SAVE_EXPR:
+      /* If this has not been evaluated, we can see if we can do
+        something inside it and make a new one.  */
+      if (SAVE_EXPR_RTL (t) == 0
+         && 0 != (t1 = extract_muldiv (TREE_OPERAND (t, 0), c, code,
+                                       wide_type)))
+       return save_expr (t1);
+      break;
+
+    case LSHIFT_EXPR:  case RSHIFT_EXPR:
+      /* If the second operand is constant, this is a multiplication
+        or floor division, by a power of two, so we can treat it that
+        way unless the multiplier or divisor overflows.  */
+      if (TREE_CODE (op1) == INTEGER_CST
+         && 0 != (t1 = convert (ctype,
+                                const_binop (LSHIFT_EXPR, size_one_node,
+                                             op1, 0)))
+         && ! TREE_OVERFLOW (t1))
+       return extract_muldiv (build (tcode == LSHIFT_EXPR
+                                     ? MULT_EXPR : FLOOR_DIV_EXPR,
+                                     ctype, convert (ctype, op0), t1),
+                              c, code, wide_type);
+      break;
+
+    case PLUS_EXPR:  case MINUS_EXPR:
+      /* See if we can eliminate the operation on both sides.  If we can, we
+        can return a new PLUS or MINUS.  If we can't, the only remaining
+        cases where we can do anything are if the second operand is a
+        constant.  */
+      t1 = extract_muldiv (op0, c, code, wide_type);
+      t2 = extract_muldiv (op1, c, code, wide_type);
+      if (t1 != 0 && t2 != 0)
+       return fold (build (tcode, ctype, convert (ctype, t1),
+                           convert (ctype, t2)));
+      else if (TREE_CODE (op1) != INTEGER_CST)
+       break;
+
+      /* If we were able to eliminate our operation from the first side,
+        apply our operation to the second side and reform the PLUS or
+        MINUS.  */
+      if (t1 != 0 && (TREE_CODE (t1) != code || code == MULT_EXPR)
+         && 0 != (t2 = const_binop (code, convert (ctype, op1),
+                                    convert (ctype, c), 0))
+         && ! TREE_OVERFLOW (t2))
+       return fold (build (tcode, ctype, convert (ctype, t1), t2));
+
+      /* The last case is if we are a multiply.  In that case, we can
+        apply the distributive law to commute the multiply and addition
+        if the multiplication of the constants doesn't overflow. */
+      if (code == MULT_EXPR
+         && 0 != (t1 = const_binop (code, convert (ctype, op1),
+                                    convert (ctype, c), 0))
+         && ! TREE_OVERFLOW (t1))
+       return fold (build (tcode, ctype, fold (build (code, ctype,
+                                                      convert (ctype, op0),
+                                                      convert (ctype, c))),
+                           t1));
+
+      break;
+
+    case MULT_EXPR:
+      /* We have a special case here if we are doing something like
+        (C * 8) % 4 since we know that's zero.  */
+      if ((code == TRUNC_MOD_EXPR || code == CEIL_MOD_EXPR
+          || code == FLOOR_MOD_EXPR || code == ROUND_MOD_EXPR)
+         && TREE_CODE (TREE_OPERAND (t, 1)) == INTEGER_CST
+         && integer_zerop (const_binop (TRUNC_MOD_EXPR, op1, c, 0)))
+       return omit_one_operand (type, integer_zero_node, op0);
+
+      /* ... fall through ... */
+
+    case TRUNC_DIV_EXPR:  case CEIL_DIV_EXPR:  case FLOOR_DIV_EXPR:
+    case ROUND_DIV_EXPR:  case EXACT_DIV_EXPR:
+      /* If we can extract our operation from the LHS, do so and return a
+        new operation.  Likewise for the RHS from a MULT_EXPR.  Otherwise,
+        do something only if the second operand is a constant.  */
+      if (same_p
+         && (t1 = extract_muldiv (op0, c, code, wide_type)) != 0)
+       return fold (build (tcode, ctype, convert (ctype, t1),
+                           convert (ctype, op1)));
+      else if (tcode == MULT_EXPR && code == MULT_EXPR
+              && (t1 = extract_muldiv (op1, c, code, wide_type)) != 0)
+       return fold (build (tcode, ctype, convert (ctype, op0),
+                           convert (ctype, t1)));
+      else if (TREE_CODE (op1) != INTEGER_CST)
+       return 0;
+
+      /* If these are the same operation types, we can associate them
+        assuming no overflow.  */
+      if (tcode == code
+         && 0 != (t1 = const_binop (MULT_EXPR, convert (ctype, op1),
+                                    convert (ctype, c), 0))
+         && ! TREE_OVERFLOW (t1))
+       return fold (build (tcode, ctype, convert (ctype, op0), t1));
+
+      /* If these operations "cancel" each other, we have the main
+        optimizations of this pass, which occur when either constant is a
+        multiple of the other, in which case we replace this with either an
+        operation or CODE or TCODE.  */
+      if ((code == MULT_EXPR && tcode == EXACT_DIV_EXPR)
+         || (tcode == MULT_EXPR
+             && code != TRUNC_MOD_EXPR && code != CEIL_MOD_EXPR
+             && code != FLOOR_MOD_EXPR && code != ROUND_MOD_EXPR))
+       {
+         if (integer_zerop (const_binop (TRUNC_MOD_EXPR, op1, c, 0)))
+           return fold (build (tcode, ctype, convert (ctype, op0),
+                               convert (ctype,
+                                        const_binop (TRUNC_DIV_EXPR,
+                                                     op1, c, 0))));
+         else if (integer_zerop (const_binop (TRUNC_MOD_EXPR, c, op1, 0)))
+           return fold (build (code, ctype, convert (ctype, op0),
+                               convert (ctype,
+                                        const_binop (TRUNC_DIV_EXPR,
+                                                     c, op1, 0))));
+       }
+      break;
+
+    default:
+      break;
+    }
+
+  return 0;
+}
+\f
 /* If T contains a COMPOUND_EXPR which was inserted merely to evaluate
    S, a SAVE_EXPR, return the expression actually being evaluated.   Note
    that we may sometimes modify the tree.  */
@@ -4772,7 +5070,8 @@ fold (expr)
        return TREE_OPERAND (arg0, 0);
 
       /* Convert - (a - b) to (b - a) for non-floating-point.  */
-      else if (TREE_CODE (arg0) == MINUS_EXPR && ! FLOAT_TYPE_P (type))
+      else if (TREE_CODE (arg0) == MINUS_EXPR
+              && (! FLOAT_TYPE_P (type) || flag_fast_math))
        return build (MINUS_EXPR, type, TREE_OPERAND (arg0, 1),
                      TREE_OPERAND (arg0, 0));
 
@@ -4816,14 +5115,10 @@ fold (expr)
       else if (TREE_CODE (arg0) == COMPLEX_EXPR)
        return build (COMPLEX_EXPR, TREE_TYPE (arg0),
                      TREE_OPERAND (arg0, 0),
-                     fold (build1 (NEGATE_EXPR,
-                                   TREE_TYPE (TREE_TYPE (arg0)),
-                                   TREE_OPERAND (arg0, 1))));
+                     negate_expr (TREE_OPERAND (arg0, 1)));
       else if (TREE_CODE (arg0) == COMPLEX_CST)
        return build_complex (type, TREE_OPERAND (arg0, 0),
-                             fold (build1 (NEGATE_EXPR,
-                                           TREE_TYPE (TREE_TYPE (arg0)),
-                                           TREE_OPERAND (arg0, 1))));
+                             negate_expr (TREE_OPERAND (arg0, 1)));
       else if (TREE_CODE (arg0) == PLUS_EXPR || TREE_CODE (arg0) == MINUS_EXPR)
        return fold (build (TREE_CODE (arg0), type,
                            fold (build1 (CONJ_EXPR, type,
@@ -5047,109 +5342,41 @@ fold (expr)
          }
       }
 
+
     associate:
-      /* In most languages, can't associate operations on floats
-        through parentheses.  Rather than remember where the parentheses
-        were, we don't associate floats at all.  It shouldn't matter much.
-        However, associating multiplications is only very slightly
-        inaccurate, so do that if -ffast-math is specified.  */
-      if (FLOAT_TYPE_P (type)
-         && ! (flag_fast_math && code == MULT_EXPR))
-       goto binary;
-
-      /* The varsign == -1 cases happen only for addition and subtraction.
-        It says that the arg that was split was really CON minus VAR.
-        The rest of the code applies to all associative operations.  */
-      if (!wins)
+      /* In most languages, can't associate operations on floats through
+        parentheses.  Rather than remember where the parentheses were, we
+        don't associate floats at all.  It shouldn't matter much.  However,
+        associating multiplications is only very slightly inaccurate, so do
+        that if -ffast-math is specified.  */
+
+      if (! wins
+         && (! FLOAT_TYPE_P (type)
+             || (flag_fast_math && code != MULT_EXPR)))
        {
-         tree var, con;
-         int varsign;
-
-         if (split_tree (arg0, code, &var, &con, &varsign))
-           {
-             if (varsign == -1)
-               {
-                 /* EXPR is (CON-VAR) +- ARG1.  */
-                 /* If it is + and VAR==ARG1, return just CONST.  */
-                 if (code == PLUS_EXPR && operand_equal_p (var, arg1, 0))
-                   return convert (TREE_TYPE (t), con);
-                   
-                 /* If ARG0 is a constant, don't change things around;
-                    instead keep all the constant computations together.  */
-
-                 if (TREE_CONSTANT (arg0))
-                   return t;
-
-                 /* Otherwise return (CON +- ARG1) - VAR.  */
-                 t = build (MINUS_EXPR, type,
-                            fold (build (code, type, con, arg1)), var);
-               }
-             else
-               {
-                 /* EXPR is (VAR+CON) +- ARG1.  */
-                 /* If it is - and VAR==ARG1, return just CONST.  */
-                 if (code == MINUS_EXPR && operand_equal_p (var, arg1, 0))
-                   return convert (TREE_TYPE (t), con);
-                   
-                 /* If ARG0 is a constant, don't change things around;
-                    instead keep all the constant computations together.  */
-
-                 if (TREE_CONSTANT (arg0))
-                   return t;
-
-                 /* Otherwise return VAR +- (ARG1 +- CON).  */
-                 tem = fold (build (code, type, arg1, con));
-                 t = build (code, type, var, tem);
-
-                 if (integer_zerop (tem)
-                     && (code == PLUS_EXPR || code == MINUS_EXPR))
-                   return convert (type, var);
-                 /* If we have x +/- (c - d) [c an explicit integer]
-                    change it to x -/+ (d - c) since if d is relocatable
-                    then the latter can be a single immediate insn
-                    and the former cannot.  */
-                 if (TREE_CODE (tem) == MINUS_EXPR
-                     && TREE_CODE (TREE_OPERAND (tem, 0)) == INTEGER_CST)
-                   {
-                     tree tem1 = TREE_OPERAND (tem, 1);
-                     TREE_OPERAND (tem, 1) = TREE_OPERAND (tem, 0);
-                     TREE_OPERAND (tem, 0) = tem1;
-                     TREE_SET_CODE (t,
-                                    (code == PLUS_EXPR ? MINUS_EXPR : PLUS_EXPR));
-                   }
-               }
-             return t;
-           }
-
-         if (split_tree (arg1, code, &var, &con, &varsign))
+         tree var0, con0, lit0, var1, con1, lit1;
+
+         /* Split both trees into variables, constants, and literals.  Then
+            associate each group together, the constants with literals,
+            then the result with variables.  This increases the chances of
+            literals being recombined later and of generating relocatable
+            expressions for the sum of a constant and literal. */
+         var0 = split_tree (arg0, code, &con0, &lit0, 0);
+         var1 = split_tree (arg1, code, &con1, &lit1, code == MINUS_EXPR);
+
+         /* Only do something if we found more than two objects.  Otherwise,
+            nothing has changed and we risk infinite recursion.  */
+         if (2 < ((var0 != 0) + (var1 != 0) + (con0 != 0) + (con1 != 0)
+                  + (lit0 != 0) + (lit1 != 0)))
            {
-             if (TREE_CONSTANT (arg1))
-               return t;
-
-             if (varsign == -1)
-               TREE_SET_CODE (t,
-                              (code == PLUS_EXPR ? MINUS_EXPR : PLUS_EXPR));
-
-             /* EXPR is ARG0 +- (CON +- VAR).  */
-             if (TREE_CODE (t) == MINUS_EXPR
-                 && operand_equal_p (var, arg0, 0))
-               {
-                 /* If VAR and ARG0 cancel, return just CON or -CON.  */
-                 if (code == PLUS_EXPR)
-                   return convert (TREE_TYPE (t), con);
-                 return fold (build1 (NEGATE_EXPR, TREE_TYPE (t),
-                                      convert (TREE_TYPE (t), con)));
-               }
-
-             t = build (TREE_CODE (t), type,
-                        fold (build (code, TREE_TYPE (t), arg0, con)), var);
-
-             if (integer_zerop (TREE_OPERAND (t, 0))
-                 && TREE_CODE (t) == PLUS_EXPR)
-               return convert (TREE_TYPE (t), var);
-             return t;
+             var0 = associate_trees (var0, var1, code, type);
+             con0 = associate_trees (con0, con1, code, type);
+             lit0 = associate_trees (lit0, lit1, code, type);
+             con0 = associate_trees (con0, lit0, code, type);
+             return convert (type, associate_trees (var0, con0, code, type));
            }
        }
+
     binary:
 #if defined (REAL_IS_NOT_DOUBLE) && ! defined (REAL_ARITHMETIC)
       if (TREE_CODE (arg1) == REAL_CST)
@@ -5183,7 +5410,7 @@ fold (expr)
       if (! FLOAT_TYPE_P (type))
        {
          if (! wins && integer_zerop (arg0))
-           return build1 (NEGATE_EXPR, type, arg1);
+           return negate_expr (arg1);
          if (integer_zerop (arg1))
            return non_lvalue (convert (type, arg0));
 
@@ -5206,7 +5433,7 @@ fold (expr)
        {
          /* Except with IEEE floating point, 0-x equals -x.  */
          if (! wins && real_zerop (arg0))
-           return build1 (NEGATE_EXPR, type, arg1);
+           return negate_expr (arg1);
          /* Except with IEEE floating point, x-0 equals x.  */
          if (real_zerop (arg1))
            return non_lvalue (convert (type, arg0));
@@ -5237,14 +5464,6 @@ fold (expr)
          if (integer_onep (arg1))
            return non_lvalue (convert (type, arg0));
 
-         /* ((A / C) * C) is A if the division is an
-            EXACT_DIV_EXPR.   Since C is normally a constant,
-            just check for one of the four possibilities.  */
-
-         if (TREE_CODE (arg0) == EXACT_DIV_EXPR
-             && operand_equal_p (TREE_OPERAND (arg0, 1), arg1, 0))
-           return TREE_OPERAND (arg0, 0);
-
          /* (a * (1 << b)) is (a << b)  */
          if (TREE_CODE (arg1) == LSHIFT_EXPR
              && integer_onep (TREE_OPERAND (arg1, 0)))
@@ -5254,6 +5473,12 @@ fold (expr)
              && integer_onep (TREE_OPERAND (arg0, 0)))
            return fold (build (LSHIFT_EXPR, type, arg1,
                                TREE_OPERAND (arg0, 1)));
+
+         if (TREE_CODE (arg1) == INTEGER_CST
+             && 0 != (tem = extract_muldiv (TREE_OPERAND (t, 0), arg1,
+                                            code, NULL_TREE)))
+           return convert (type, tem);
+
        }
       else
        {
@@ -5455,129 +5680,10 @@ fold (expr)
          && multiple_of_p (type, arg0, arg1))
        return fold (build (EXACT_DIV_EXPR, type, arg0, arg1));
 
-      /* If we have ((a / C1) / C2) where both division are the same type, try
-        to simplify.  First see if C1 * C2 overflows or not.  */
-      if (TREE_CODE (arg0) == code && TREE_CODE (arg1) == INTEGER_CST
-         && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
-       {
-         tree new_divisor;
-
-         new_divisor = const_binop (MULT_EXPR, TREE_OPERAND (arg0, 1), arg1, 0);
-         tem = const_binop (FLOOR_DIV_EXPR, new_divisor, arg1, 0);
-
-         if (TREE_INT_CST_LOW (TREE_OPERAND (arg0, 1)) == TREE_INT_CST_LOW (tem)
-             && TREE_INT_CST_HIGH (TREE_OPERAND (arg0, 1)) == TREE_INT_CST_HIGH (tem))
-           {
-             /* If no overflow, divide by C1*C2.  */
-             return fold (build (code, type, TREE_OPERAND (arg0, 0), new_divisor));
-           }
-       }
-
-      /* Look for ((a * C1) / C3) or (((a * C1) + C2) / C3),
-        where C1 % C3 == 0 or C3 % C1 == 0.  We can simplify these
-        expressions, which often appear in the offsets or sizes of
-        objects with a varying size.  Only deal with positive divisors
-        and multiplicands.   If C2 is negative, we must have C2 % C3 == 0.
-
-        Look for NOPs and SAVE_EXPRs inside.  */
-
-      if (TREE_CODE (arg1) == INTEGER_CST
-         && tree_int_cst_sgn (arg1) >= 0)
-       {
-         int have_save_expr = 0;
-         tree c2 = integer_zero_node;
-         tree xarg0 = arg0;
-
-         if (TREE_CODE (xarg0) == SAVE_EXPR && SAVE_EXPR_RTL (xarg0) == 0)
-           have_save_expr = 1, xarg0 = TREE_OPERAND (xarg0, 0);
-
-         STRIP_NOPS (xarg0);
-
-         /* Look inside the dividend and simplify using EXACT_DIV_EXPR
-            if possible.  */
-         if (TREE_CODE (xarg0) == MULT_EXPR
-             && multiple_of_p (type, TREE_OPERAND (xarg0, 0), arg1))
-           {
-             tree t;
-
-             t = fold (build (MULT_EXPR, type,
-                              fold (build (EXACT_DIV_EXPR, type,
-                                           TREE_OPERAND (xarg0, 0), arg1)),
-                              TREE_OPERAND (xarg0, 1)));
-             if (have_save_expr)
-               t = save_expr (t);
-             return t;
-
-           }
-
-         if (TREE_CODE (xarg0) == MULT_EXPR
-             && multiple_of_p (type, TREE_OPERAND (xarg0, 1), arg1))
-           {
-             tree t;
-
-             t = fold (build (MULT_EXPR, type,
-                              fold (build (EXACT_DIV_EXPR, type,
-                                           TREE_OPERAND (xarg0, 1), arg1)),
-                              TREE_OPERAND (xarg0, 0)));
-             if (have_save_expr)
-               t = save_expr (t);
-             return t;
-           }
-
-         if (TREE_CODE (xarg0) == PLUS_EXPR
-             && TREE_CODE (TREE_OPERAND (xarg0, 1)) == INTEGER_CST)
-           c2 = TREE_OPERAND (xarg0, 1), xarg0 = TREE_OPERAND (xarg0, 0);
-         else if (TREE_CODE (xarg0) == MINUS_EXPR
-                  && TREE_CODE (TREE_OPERAND (xarg0, 1)) == INTEGER_CST
-                  /* If we are doing this computation unsigned, the negate
-                     is incorrect.  */
-                  && ! TREE_UNSIGNED (type))
-           {
-             c2 = fold (build1 (NEGATE_EXPR, type, TREE_OPERAND (xarg0, 1)));
-             xarg0 = TREE_OPERAND (xarg0, 0);
-           }
-
-         if (TREE_CODE (xarg0) == SAVE_EXPR && SAVE_EXPR_RTL (xarg0) == 0)
-           have_save_expr = 1, xarg0 = TREE_OPERAND (xarg0, 0);
-
-         STRIP_NOPS (xarg0);
-
-         if (TREE_CODE (xarg0) == MULT_EXPR
-             && TREE_CODE (TREE_OPERAND (xarg0, 1)) == INTEGER_CST
-             && tree_int_cst_sgn (TREE_OPERAND (xarg0, 1)) >= 0
-             && (integer_zerop (const_binop (TRUNC_MOD_EXPR,
-                                             TREE_OPERAND (xarg0, 1), arg1, 1))
-                 || integer_zerop (const_binop (TRUNC_MOD_EXPR, arg1,
-                                                TREE_OPERAND (xarg0, 1), 1)))
-             && (tree_int_cst_sgn (c2) >= 0
-                 || integer_zerop (const_binop (TRUNC_MOD_EXPR, c2,
-                                                arg1, 1))))
-           {
-             tree outer_div = integer_one_node;
-             tree c1 = TREE_OPERAND (xarg0, 1);
-             tree c3 = arg1;
-
-             /* If C3 > C1, set them equal and do a divide by
-                C3/C1 at the end of the operation.  */
-             if (tree_int_cst_lt (c1, c3))
-               outer_div = const_binop (code, c3, c1, 0), c3 = c1;
-               
-             /* The result is A * (C1/C3) + (C2/C3).  */
-             t = fold (build (PLUS_EXPR, type,
-                              fold (build (MULT_EXPR, type,
-                                           TREE_OPERAND (xarg0, 0),
-                                           const_binop (code, c1, c3, 1))),
-                              const_binop (code, c2, c3, 1)));
-
-             if (! integer_onep (outer_div))
-               t = fold (build (code, type, t, convert (type, outer_div)));
-
-             if (have_save_expr)
-               t = save_expr (t);
-
-             return t;
-           }
-       }
+        if (TREE_CODE (arg1) == INTEGER_CST
+         && 0 != (tem = extract_muldiv (TREE_OPERAND (t, 0), arg1,
+                                        code, NULL_TREE)))
+       return convert (type, tem);
 
       goto binary;
 
@@ -5590,39 +5696,10 @@ fold (expr)
       if (integer_zerop (arg1))
        return t;
 
-      /* Look for ((a * C1) % C3) or (((a * C1) + C2) % C3),
-        where C1 % C3 == 0.  Handle similarly to the division case,
-        but don't bother with SAVE_EXPRs.  */
-
       if (TREE_CODE (arg1) == INTEGER_CST
-         && ! integer_zerop (arg1))
-       {
-         tree c2 = integer_zero_node;
-         tree xarg0 = arg0;
-
-         if (TREE_CODE (xarg0) == PLUS_EXPR
-             && TREE_CODE (TREE_OPERAND (xarg0, 1)) == INTEGER_CST)
-           c2 = TREE_OPERAND (xarg0, 1), xarg0 = TREE_OPERAND (xarg0, 0);
-         else if (TREE_CODE (xarg0) == MINUS_EXPR
-                  && TREE_CODE (TREE_OPERAND (xarg0, 1)) == INTEGER_CST
-                  && ! TREE_UNSIGNED (type))
-           {
-             c2 = fold (build1 (NEGATE_EXPR, type, TREE_OPERAND (xarg0, 1)));
-             xarg0 = TREE_OPERAND (xarg0, 0);
-           }
-
-         STRIP_NOPS (xarg0);
-
-         if (TREE_CODE (xarg0) == MULT_EXPR
-             && TREE_CODE (TREE_OPERAND (xarg0, 1)) == INTEGER_CST
-             && integer_zerop (const_binop (TRUNC_MOD_EXPR,
-                                            TREE_OPERAND (xarg0, 1),
-                                            arg1, 1))
-             && tree_int_cst_sgn (c2) >= 0)
-           /* The result is (C2%C3).  */
-           return omit_one_operand (type, const_binop (code, c2, arg1, 1),
-                                    TREE_OPERAND (xarg0, 0));
-       }
+         && 0 != (tem = extract_muldiv (TREE_OPERAND (t, 0), arg1,
+                                        code, NULL_TREE)))
+       return convert (type, tem);
 
       goto binary;
 
@@ -6046,8 +6123,7 @@ fold (expr)
       else if ((code == EQ_EXPR || code == NE_EXPR)
               && TREE_CODE (arg0) == NEGATE_EXPR
               && TREE_CODE (arg1) == INTEGER_CST
-              && 0 != (tem = fold (build1 (NEGATE_EXPR, TREE_TYPE (arg1),
-                                           arg1)))
+              && 0 != (tem = negate_expr (arg1))
               && TREE_CODE (tem) == INTEGER_CST
               && ! TREE_CONSTANT_OVERFLOW (tem))
        return fold (build (code, type, TREE_OPERAND (arg0, 0), tem));
@@ -6086,17 +6162,14 @@ fold (expr)
         and a comparison, and is probably faster.  */
       else if (code == LE_EXPR && TREE_CODE (arg1) == INTEGER_CST
               && TREE_CODE (arg0) == ABS_EXPR
-              && ! TREE_SIDE_EFFECTS (arg0))
-       {
-         tree inner = TREE_OPERAND (arg0, 0);
-
-         tem = fold (build1 (NEGATE_EXPR, TREE_TYPE (arg1), arg1));
-         if (TREE_CODE (tem) == INTEGER_CST
-             && ! TREE_CONSTANT_OVERFLOW (tem))
-           return fold (build (TRUTH_ANDIF_EXPR, type,
-                               build (GE_EXPR, type, inner, tem),
-                               build (LE_EXPR, type, inner, arg1)));
-       }
+              && ! TREE_SIDE_EFFECTS (arg0)
+              && (0 != (tem = negate_expr (arg1)))
+              && TREE_CODE (tem) == INTEGER_CST
+              && ! TREE_CONSTANT_OVERFLOW (tem))
+       return fold (build (TRUTH_ANDIF_EXPR, type,
+                           build (GE_EXPR, type, TREE_OPERAND (arg0, 0), tem),
+                           build (LE_EXPR, type,
+                                  TREE_OPERAND (arg0, 0), arg1)));
          
       /* If this is an EQ or NE comparison with zero and ARG0 is
         (1 << foo) & bar, convert it to (bar >> foo) & 1.  Both require
@@ -6635,8 +6708,7 @@ fold (expr)
            switch (comp_code)
              {
              case EQ_EXPR:
-               return pedantic_non_lvalue
-                 (fold (build1 (NEGATE_EXPR, type, arg1)));
+               return pedantic_non_lvalue (negate_expr (arg1));
              case NE_EXPR:
                return pedantic_non_lvalue (convert (type, arg1));
              case GE_EXPR:
@@ -6651,11 +6723,10 @@ fold (expr)
                if (TREE_UNSIGNED (TREE_TYPE (arg1)))
                  arg1 = convert (signed_type (TREE_TYPE (arg1)), arg1);
                return pedantic_non_lvalue
-                 (fold (build1 (NEGATE_EXPR, type,
-                                convert (type,
-                                         fold (build1 (ABS_EXPR,
-                                                       TREE_TYPE (arg1),
-                                                       arg1))))));
+                 (negate_expr (convert (type,
+                                        fold (build1 (ABS_EXPR,
+                                                      TREE_TYPE (arg1),
+                                                      arg1)))));
              default:
                abort ();
              }