This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[patch] fold-const.c: Reorganize fold - Part 6/n


Hi,

Attached is part 6 of my patch to reorganize fold.

This patch extracts handling of binary expressions out of fold and
creates a new function fold_binary.

I deliberately did not remove handling of binary expressions from
fold.  If I did, the diff would be messed up.  I'll address this issue
in a subsequent patch.

Tested on i686-pc-linux-gnu.  OK to apply?

Kazu Hirata

2005-03-05  Kazu Hirata  <kazu@cs.umass.edu>

	* fold-const.c (fold_binary): New.
	(fold): Call fold_binary on binary expressions.

Index: fold-const.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fold-const.c,v
retrieving revision 1.524
diff -u -d -p -r1.524 fold-const.c
--- fold-const.c	4 Mar 2005 19:59:45 -0000	1.524
+++ fold-const.c	4 Mar 2005 20:30:18 -0000
@@ -7014,6 +7014,2621 @@ fold_unary (tree expr)
     } /* switch (code) */
 }
 
+/* Fold a binary expression EXPR.  Return the folded expression if
+   folding is successful.  Otherwise, return the original
+   expression.  */
+
+static tree
+fold_binary (tree expr)
+{
+  const tree t = expr;
+  const tree type = TREE_TYPE (expr);
+  tree t1 = NULL_TREE;
+  tree tem;
+  tree arg0 = NULL_TREE, arg1 = NULL_TREE;
+  enum tree_code code = TREE_CODE (t);
+  enum tree_code_class kind = TREE_CODE_CLASS (code);
+
+  /* WINS will be nonzero when the switch is done
+     if all operands are constant.  */
+  int wins = 1;
+  int i;
+
+  gcc_assert (IS_EXPR_CODE_CLASS (kind)
+	      && TREE_CODE_LENGTH (code) == 2);
+
+  for (i = 0; i < 2; i++)
+    {
+      tree op = TREE_OPERAND (t, i);
+      tree subop;
+
+      if (op == 0)
+	continue;		/* Valid for CALL_EXPR, at least.  */
+
+      /* Strip any conversions that don't change the mode.  This is
+	 safe for every expression, except for a comparison expression
+	 because its signedness is derived from its operands.  So, in
+	 the latter case, only strip conversions that don't change the
+	 signedness.
+
+	 Note that this is done as an internal manipulation within the
+	 constant folder, in order to find the simplest representation
+	 of the arguments so that their form can be studied.  In any
+	 cases, the appropriate type conversions should be put back in
+	 the tree that will get out of the constant folder.  */
+      if (kind == tcc_comparison)
+	STRIP_SIGN_NOPS (op);
+      else
+	STRIP_NOPS (op);
+
+      if (TREE_CODE (op) == COMPLEX_CST)
+	subop = TREE_REALPART (op);
+      else
+	subop = op;
+
+      if (TREE_CODE (subop) != INTEGER_CST
+	  && TREE_CODE (subop) != REAL_CST)
+	/* Note that TREE_CONSTANT isn't enough:
+	   static var addresses are constant but we can't
+	   do arithmetic on them.  */
+	wins = 0;
+
+      if (i == 0)
+	arg0 = op;
+      else if (i == 1)
+	arg1 = op;
+    }
+
+  /* If this is a commutative operation, and ARG0 is a constant, move it
+     to ARG1 to reduce the number of tests below.  */
+  if (commutative_tree_code (code)
+      && tree_swap_operands_p (arg0, arg1, true))
+    return fold (build2 (code, type, TREE_OPERAND (t, 1),
+			 TREE_OPERAND (t, 0)));
+
+  /* Now WINS is set as described above,
+     ARG0 is the first operand of EXPR,
+     and ARG1 is the second operand (if it has more than one operand).
+
+     First check for cases where an arithmetic operation is applied to a
+     compound, conditional, or comparison operation.  Push the arithmetic
+     operation inside the compound or conditional to see if any folding
+     can then be done.  Convert comparison to conditional for this purpose.
+     The also optimizes non-constant cases that used to be done in
+     expand_expr.
+
+     Before we do that, see if this is a BIT_AND_EXPR or a BIT_IOR_EXPR,
+     one of the operands is a comparison and the other is a comparison, a
+     BIT_AND_EXPR with the constant 1, or a truth value.  In that case, the
+     code below would make the expression more complex.  Change it to a
+     TRUTH_{AND,OR}_EXPR.  Likewise, convert a similar NE_EXPR to
+     TRUTH_XOR_EXPR and an EQ_EXPR to the inversion of a TRUTH_XOR_EXPR.  */
+
+  if ((code == BIT_AND_EXPR || code == BIT_IOR_EXPR
+       || code == EQ_EXPR || code == NE_EXPR)
+      && ((truth_value_p (TREE_CODE (arg0))
+	   && (truth_value_p (TREE_CODE (arg1))
+	       || (TREE_CODE (arg1) == BIT_AND_EXPR
+		   && integer_onep (TREE_OPERAND (arg1, 1)))))
+	  || (truth_value_p (TREE_CODE (arg1))
+	      && (truth_value_p (TREE_CODE (arg0))
+		  || (TREE_CODE (arg0) == BIT_AND_EXPR
+		      && integer_onep (TREE_OPERAND (arg0, 1)))))))
+    {
+      tem = fold (build2 (code == BIT_AND_EXPR ? TRUTH_AND_EXPR
+			  : code == BIT_IOR_EXPR ? TRUTH_OR_EXPR
+			  : TRUTH_XOR_EXPR,
+			  type, fold_convert (boolean_type_node, arg0),
+			  fold_convert (boolean_type_node, arg1)));
+
+      if (code == EQ_EXPR)
+	tem = invert_truthvalue (tem);
+
+      return tem;
+    }
+
+  if (TREE_CODE_CLASS (code) == tcc_comparison
+	   && TREE_CODE (arg0) == COMPOUND_EXPR)
+    return build2 (COMPOUND_EXPR, type, TREE_OPERAND (arg0, 0),
+		   fold (build2 (code, type, TREE_OPERAND (arg0, 1), arg1)));
+  else if (TREE_CODE_CLASS (code) == tcc_comparison
+	   && TREE_CODE (arg1) == COMPOUND_EXPR)
+    return build2 (COMPOUND_EXPR, type, TREE_OPERAND (arg1, 0),
+		   fold (build2 (code, type, arg0, TREE_OPERAND (arg1, 1))));
+  else if (TREE_CODE_CLASS (code) == tcc_binary
+	   || TREE_CODE_CLASS (code) == tcc_comparison)
+    {
+      if (TREE_CODE (arg0) == COMPOUND_EXPR)
+	return build2 (COMPOUND_EXPR, type, TREE_OPERAND (arg0, 0),
+		       fold (build2 (code, type, TREE_OPERAND (arg0, 1),
+				     arg1)));
+      if (TREE_CODE (arg1) == COMPOUND_EXPR
+	  && reorder_operands_p (arg0, TREE_OPERAND (arg1, 0)))
+	return build2 (COMPOUND_EXPR, type, TREE_OPERAND (arg1, 0),
+		       fold (build2 (code, type,
+				     arg0, TREE_OPERAND (arg1, 1))));
+
+      if (TREE_CODE (arg0) == COND_EXPR || COMPARISON_CLASS_P (arg0))
+	{
+	  tem = fold_binary_op_with_conditional_arg (t, code, arg0, arg1, 
+						     /*cond_first_p=*/1);
+	  if (tem != NULL_TREE)
+	    return tem;
+	}
+
+      if (TREE_CODE (arg1) == COND_EXPR || COMPARISON_CLASS_P (arg1))
+	{
+	  tem = fold_binary_op_with_conditional_arg (t, code, arg1, arg0, 
+					             /*cond_first_p=*/0);
+	  if (tem != NULL_TREE)
+	    return tem;
+	}
+    }
+
+  switch (code)
+    {
+    case RANGE_EXPR:
+      if (TREE_CONSTANT (t) != wins)
+	{
+	  tem = copy_node (t);
+	  TREE_CONSTANT (tem) = wins;
+	  TREE_INVARIANT (tem) = wins;
+	  return tem;
+	}
+      return t;
+
+    case PLUS_EXPR:
+      /* A + (-B) -> A - B */
+      if (TREE_CODE (arg1) == NEGATE_EXPR)
+	return fold (build2 (MINUS_EXPR, type, arg0, TREE_OPERAND (arg1, 0)));
+      /* (-A) + B -> B - A */
+      if (TREE_CODE (arg0) == NEGATE_EXPR
+	  && reorder_operands_p (TREE_OPERAND (arg0, 0), arg1))
+	return fold (build2 (MINUS_EXPR, type, arg1, TREE_OPERAND (arg0, 0)));
+
+      if (TREE_CODE (type) == COMPLEX_TYPE)
+	{
+	  tem = fold_complex_add (type, arg0, arg1, PLUS_EXPR);
+	  if (tem)
+	    return tem;
+	}
+
+      if (! FLOAT_TYPE_P (type))
+	{
+	  if (integer_zerop (arg1))
+	    return non_lvalue (fold_convert (type, arg0));
+
+	  /* If we are adding two BIT_AND_EXPR's, both of which are and'ing
+	     with a constant, and the two constants have no bits in common,
+	     we should treat this as a BIT_IOR_EXPR since this may produce more
+	     simplifications.  */
+	  if (TREE_CODE (arg0) == BIT_AND_EXPR
+	      && TREE_CODE (arg1) == BIT_AND_EXPR
+	      && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
+	      && TREE_CODE (TREE_OPERAND (arg1, 1)) == INTEGER_CST
+	      && integer_zerop (const_binop (BIT_AND_EXPR,
+					     TREE_OPERAND (arg0, 1),
+					     TREE_OPERAND (arg1, 1), 0)))
+	    {
+	      code = BIT_IOR_EXPR;
+	      goto bit_ior;
+	    }
+
+	  /* Reassociate (plus (plus (mult) (foo)) (mult)) as
+	     (plus (plus (mult) (mult)) (foo)) so that we can
+	     take advantage of the factoring cases below.  */
+	  if (((TREE_CODE (arg0) == PLUS_EXPR
+		|| TREE_CODE (arg0) == MINUS_EXPR)
+	       && TREE_CODE (arg1) == MULT_EXPR)
+	      || ((TREE_CODE (arg1) == PLUS_EXPR
+		   || TREE_CODE (arg1) == MINUS_EXPR)
+		  && TREE_CODE (arg0) == MULT_EXPR))
+	    {
+	      tree parg0, parg1, parg, marg;
+	      enum tree_code pcode;
+
+	      if (TREE_CODE (arg1) == MULT_EXPR)
+		parg = arg0, marg = arg1;
+	      else
+		parg = arg1, marg = arg0;
+	      pcode = TREE_CODE (parg);
+	      parg0 = TREE_OPERAND (parg, 0);
+	      parg1 = TREE_OPERAND (parg, 1);
+	      STRIP_NOPS (parg0);
+	      STRIP_NOPS (parg1);
+
+	      if (TREE_CODE (parg0) == MULT_EXPR
+		  && TREE_CODE (parg1) != MULT_EXPR)
+		return fold (build2 (pcode, type,
+				     fold (build2 (PLUS_EXPR, type,
+						   fold_convert (type, parg0),
+						   fold_convert (type, marg))),
+				     fold_convert (type, parg1)));
+	      if (TREE_CODE (parg0) != MULT_EXPR
+		  && TREE_CODE (parg1) == MULT_EXPR)
+		return fold (build2 (PLUS_EXPR, type,
+				     fold_convert (type, parg0),
+				     fold (build2 (pcode, type,
+						   fold_convert (type, marg),
+						   fold_convert (type,
+								 parg1)))));
+	    }
+
+	  if (TREE_CODE (arg0) == MULT_EXPR && TREE_CODE (arg1) == MULT_EXPR)
+	    {
+	      tree arg00, arg01, arg10, arg11;
+	      tree alt0 = NULL_TREE, alt1 = NULL_TREE, same;
+
+	      /* (A * C) + (B * C) -> (A+B) * C.
+		 We are most concerned about the case where C is a constant,
+		 but other combinations show up during loop reduction.  Since
+		 it is not difficult, try all four possibilities.  */
+
+	      arg00 = TREE_OPERAND (arg0, 0);
+	      arg01 = TREE_OPERAND (arg0, 1);
+	      arg10 = TREE_OPERAND (arg1, 0);
+	      arg11 = TREE_OPERAND (arg1, 1);
+	      same = NULL_TREE;
+
+	      if (operand_equal_p (arg01, arg11, 0))
+		same = arg01, alt0 = arg00, alt1 = arg10;
+	      else if (operand_equal_p (arg00, arg10, 0))
+		same = arg00, alt0 = arg01, alt1 = arg11;
+	      else if (operand_equal_p (arg00, arg11, 0))
+		same = arg00, alt0 = arg01, alt1 = arg10;
+	      else if (operand_equal_p (arg01, arg10, 0))
+		same = arg01, alt0 = arg00, alt1 = arg11;
+
+	      /* No identical multiplicands; see if we can find a common
+		 power-of-two factor in non-power-of-two multiplies.  This
+		 can help in multi-dimensional array access.  */
+	      else if (TREE_CODE (arg01) == INTEGER_CST
+		       && TREE_CODE (arg11) == INTEGER_CST
+		       && TREE_INT_CST_HIGH (arg01) == 0
+		       && TREE_INT_CST_HIGH (arg11) == 0)
+		{
+		  HOST_WIDE_INT int01, int11, tmp;
+		  int01 = TREE_INT_CST_LOW (arg01);
+		  int11 = TREE_INT_CST_LOW (arg11);
+
+		  /* Move min of absolute values to int11.  */
+		  if ((int01 >= 0 ? int01 : -int01)
+		      < (int11 >= 0 ? int11 : -int11))
+		    {
+		      tmp = int01, int01 = int11, int11 = tmp;
+		      alt0 = arg00, arg00 = arg10, arg10 = alt0;
+		      alt0 = arg01, arg01 = arg11, arg11 = alt0;
+		    }
+
+		  if (exact_log2 (int11) > 0 && int01 % int11 == 0)
+		    {
+		      alt0 = fold (build2 (MULT_EXPR, type, arg00,
+					   build_int_cst (NULL_TREE,
+							  int01 / int11)));
+		      alt1 = arg10;
+		      same = arg11;
+		    }
+		}
+
+	      if (same)
+		return fold (build2 (MULT_EXPR, type,
+				     fold (build2 (PLUS_EXPR, type,
+						   fold_convert (type, alt0),
+						   fold_convert (type, alt1))),
+				     same));
+	    }
+
+	  /* Try replacing &a[i1] + c * i2 with &a[i1 + i2], if c is step
+	     of the array.  Loop optimizer sometimes produce this type of
+	     expressions.  */
+	  if (TREE_CODE (arg0) == ADDR_EXPR
+	      && TREE_CODE (arg1) == MULT_EXPR)
+	    {
+	      tem = try_move_mult_to_index (PLUS_EXPR, arg0, arg1);
+	      if (tem)
+		return fold_convert (type, fold (tem));
+	    }
+	  else if (TREE_CODE (arg1) == ADDR_EXPR
+		   && TREE_CODE (arg0) == MULT_EXPR)
+	    {
+	      tem = try_move_mult_to_index (PLUS_EXPR, arg1, arg0);
+	      if (tem)
+		return fold_convert (type, fold (tem));
+	    }
+	}
+      else
+	{
+	  /* See if ARG1 is zero and X + ARG1 reduces to X.  */
+	  if (fold_real_zero_addition_p (TREE_TYPE (arg0), arg1, 0))
+	    return non_lvalue (fold_convert (type, arg0));
+
+	  /* Likewise if the operands are reversed.  */
+	  if (fold_real_zero_addition_p (TREE_TYPE (arg1), arg0, 0))
+	    return non_lvalue (fold_convert (type, arg1));
+
+	  /* Convert X + -C into X - C.  */
+	  if (TREE_CODE (arg1) == REAL_CST
+	      && REAL_VALUE_NEGATIVE (TREE_REAL_CST (arg1)))
+	    {
+	      tem = fold_negate_const (arg1, type);
+	      if (!TREE_OVERFLOW (arg1) || !flag_trapping_math)
+		return fold (build2 (MINUS_EXPR, type,
+				     fold_convert (type, arg0),
+				     fold_convert (type, tem)));
+	    }
+
+	  /* Convert x+x into x*2.0.  */
+	  if (operand_equal_p (arg0, arg1, 0)
+	      && SCALAR_FLOAT_TYPE_P (type))
+	    return fold (build2 (MULT_EXPR, type, arg0,
+				 build_real (type, dconst2)));
+
+	  /* Convert x*c+x into x*(c+1).  */
+	  if (flag_unsafe_math_optimizations
+	      && TREE_CODE (arg0) == MULT_EXPR
+	      && TREE_CODE (TREE_OPERAND (arg0, 1)) == REAL_CST
+	      && ! TREE_CONSTANT_OVERFLOW (TREE_OPERAND (arg0, 1))
+	      && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0))
+	    {
+	      REAL_VALUE_TYPE c;
+
+	      c = TREE_REAL_CST (TREE_OPERAND (arg0, 1));
+	      real_arithmetic (&c, PLUS_EXPR, &c, &dconst1);
+	      return fold (build2 (MULT_EXPR, type, arg1,
+				   build_real (type, c)));
+	    }
+
+	  /* Convert x+x*c into x*(c+1).  */
+	  if (flag_unsafe_math_optimizations
+	      && TREE_CODE (arg1) == MULT_EXPR
+	      && TREE_CODE (TREE_OPERAND (arg1, 1)) == REAL_CST
+	      && ! TREE_CONSTANT_OVERFLOW (TREE_OPERAND (arg1, 1))
+	      && operand_equal_p (TREE_OPERAND (arg1, 0), arg0, 0))
+	    {
+	      REAL_VALUE_TYPE c;
+
+	      c = TREE_REAL_CST (TREE_OPERAND (arg1, 1));
+	      real_arithmetic (&c, PLUS_EXPR, &c, &dconst1);
+	      return fold (build2 (MULT_EXPR, type, arg0,
+				   build_real (type, c)));
+	    }
+
+	  /* Convert x*c1+x*c2 into x*(c1+c2).  */
+	  if (flag_unsafe_math_optimizations
+	      && TREE_CODE (arg0) == MULT_EXPR
+	      && TREE_CODE (arg1) == MULT_EXPR
+	      && TREE_CODE (TREE_OPERAND (arg0, 1)) == REAL_CST
+	      && ! TREE_CONSTANT_OVERFLOW (TREE_OPERAND (arg0, 1))
+	      && TREE_CODE (TREE_OPERAND (arg1, 1)) == REAL_CST
+	      && ! TREE_CONSTANT_OVERFLOW (TREE_OPERAND (arg1, 1))
+	      && operand_equal_p (TREE_OPERAND (arg0, 0),
+				  TREE_OPERAND (arg1, 0), 0))
+	    {
+	      REAL_VALUE_TYPE c1, c2;
+
+	      c1 = TREE_REAL_CST (TREE_OPERAND (arg0, 1));
+	      c2 = TREE_REAL_CST (TREE_OPERAND (arg1, 1));
+	      real_arithmetic (&c1, PLUS_EXPR, &c1, &c2);
+	      return fold (build2 (MULT_EXPR, type,
+				   TREE_OPERAND (arg0, 0),
+				   build_real (type, c1)));
+	    }
+          /* Convert a + (b*c + d*e) into (a + b*c) + d*e.  */
+          if (flag_unsafe_math_optimizations
+              && TREE_CODE (arg1) == PLUS_EXPR
+              && TREE_CODE (arg0) != MULT_EXPR)
+            {
+              tree tree10 = TREE_OPERAND (arg1, 0);
+              tree tree11 = TREE_OPERAND (arg1, 1);
+              if (TREE_CODE (tree11) == MULT_EXPR
+		  && TREE_CODE (tree10) == MULT_EXPR)
+                {
+                  tree tree0;
+                  tree0 = fold (build2 (PLUS_EXPR, type, arg0, tree10));
+                  return fold (build2 (PLUS_EXPR, type, tree0, tree11));
+                }
+            }
+          /* Convert (b*c + d*e) + a into b*c + (d*e +a).  */
+          if (flag_unsafe_math_optimizations
+              && TREE_CODE (arg0) == PLUS_EXPR
+              && TREE_CODE (arg1) != MULT_EXPR)
+            {
+              tree tree00 = TREE_OPERAND (arg0, 0);
+              tree tree01 = TREE_OPERAND (arg0, 1);
+              if (TREE_CODE (tree01) == MULT_EXPR
+		  && TREE_CODE (tree00) == MULT_EXPR)
+                {
+                  tree tree0;
+                  tree0 = fold (build2 (PLUS_EXPR, type, tree01, arg1));
+                  return fold (build2 (PLUS_EXPR, type, tree00, tree0));
+                }
+            }
+	}
+
+     bit_rotate:
+      /* (A << C1) + (A >> C2) if A is unsigned and C1+C2 is the size of A
+	 is a rotate of A by C1 bits.  */
+      /* (A << B) + (A >> (Z - B)) if A is unsigned and Z is the size of A
+	 is a rotate of A by B bits.  */
+      {
+	enum tree_code code0, code1;
+	code0 = TREE_CODE (arg0);
+	code1 = TREE_CODE (arg1);
+	if (((code0 == RSHIFT_EXPR && code1 == LSHIFT_EXPR)
+	     || (code1 == RSHIFT_EXPR && code0 == LSHIFT_EXPR))
+	    && operand_equal_p (TREE_OPERAND (arg0, 0),
+			        TREE_OPERAND (arg1, 0), 0)
+	    && TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (arg0, 0))))
+	  {
+	    tree tree01, tree11;
+	    enum tree_code code01, code11;
+
+	    tree01 = TREE_OPERAND (arg0, 1);
+	    tree11 = TREE_OPERAND (arg1, 1);
+	    STRIP_NOPS (tree01);
+	    STRIP_NOPS (tree11);
+	    code01 = TREE_CODE (tree01);
+	    code11 = TREE_CODE (tree11);
+	    if (code01 == INTEGER_CST
+		&& code11 == INTEGER_CST
+		&& TREE_INT_CST_HIGH (tree01) == 0
+		&& TREE_INT_CST_HIGH (tree11) == 0
+		&& ((TREE_INT_CST_LOW (tree01) + TREE_INT_CST_LOW (tree11))
+		    == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg0, 0)))))
+	      return build2 (LROTATE_EXPR, type, TREE_OPERAND (arg0, 0),
+			     code0 == LSHIFT_EXPR ? tree01 : tree11);
+	    else if (code11 == MINUS_EXPR)
+	      {
+		tree tree110, tree111;
+		tree110 = TREE_OPERAND (tree11, 0);
+		tree111 = TREE_OPERAND (tree11, 1);
+		STRIP_NOPS (tree110);
+		STRIP_NOPS (tree111);
+		if (TREE_CODE (tree110) == INTEGER_CST
+		    && 0 == compare_tree_int (tree110,
+					      TYPE_PRECISION
+					      (TREE_TYPE (TREE_OPERAND
+							  (arg0, 0))))
+		    && operand_equal_p (tree01, tree111, 0))
+		  return build2 ((code0 == LSHIFT_EXPR
+				  ? LROTATE_EXPR
+				  : RROTATE_EXPR),
+				 type, TREE_OPERAND (arg0, 0), tree01);
+	      }
+	    else if (code01 == MINUS_EXPR)
+	      {
+		tree tree010, tree011;
+		tree010 = TREE_OPERAND (tree01, 0);
+		tree011 = TREE_OPERAND (tree01, 1);
+		STRIP_NOPS (tree010);
+		STRIP_NOPS (tree011);
+		if (TREE_CODE (tree010) == INTEGER_CST
+		    && 0 == compare_tree_int (tree010,
+					      TYPE_PRECISION
+					      (TREE_TYPE (TREE_OPERAND
+							  (arg0, 0))))
+		    && operand_equal_p (tree11, tree011, 0))
+		  return build2 ((code0 != LSHIFT_EXPR
+				  ? LROTATE_EXPR
+				  : RROTATE_EXPR),
+				 type, TREE_OPERAND (arg0, 0), tree11);
+	      }
+	  }
+      }
+
+    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, unless the user has specified
+	 -funsafe-math-optimizations.  */
+
+      if (! wins
+	  && (! FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations))
+	{
+	  tree var0, con0, lit0, minus_lit0;
+	  tree var1, con1, lit1, minus_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, &minus_lit0, 0);
+	  var1 = split_tree (arg1, code, &con1, &lit1, &minus_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)
+		   + (minus_lit0 != 0) + (minus_lit1 != 0)))
+	    {
+	      /* Recombine MINUS_EXPR operands by using PLUS_EXPR.  */
+	      if (code == MINUS_EXPR)
+		code = PLUS_EXPR;
+
+	      var0 = associate_trees (var0, var1, code, type);
+	      con0 = associate_trees (con0, con1, code, type);
+	      lit0 = associate_trees (lit0, lit1, code, type);
+	      minus_lit0 = associate_trees (minus_lit0, minus_lit1, code, type);
+
+	      /* Preserve the MINUS_EXPR if the negative part of the literal is
+		 greater than the positive part.  Otherwise, the multiplicative
+		 folding code (i.e extract_muldiv) may be fooled in case
+		 unsigned constants are subtracted, like in the following
+		 example: ((X*2 + 4) - 8U)/2.  */
+	      if (minus_lit0 && lit0)
+		{
+		  if (TREE_CODE (lit0) == INTEGER_CST
+		      && TREE_CODE (minus_lit0) == INTEGER_CST
+		      && tree_int_cst_lt (lit0, minus_lit0))
+		    {
+		      minus_lit0 = associate_trees (minus_lit0, lit0,
+						    MINUS_EXPR, type);
+		      lit0 = 0;
+		    }
+		  else
+		    {
+		      lit0 = associate_trees (lit0, minus_lit0,
+					      MINUS_EXPR, type);
+		      minus_lit0 = 0;
+		    }
+		}
+	      if (minus_lit0)
+		{
+		  if (con0 == 0)
+		    return fold_convert (type,
+					 associate_trees (var0, minus_lit0,
+							  MINUS_EXPR, type));
+		  else
+		    {
+		      con0 = associate_trees (con0, minus_lit0,
+					      MINUS_EXPR, type);
+		      return fold_convert (type,
+					   associate_trees (var0, con0,
+							    PLUS_EXPR, type));
+		    }
+		}
+
+	      con0 = associate_trees (con0, lit0, code, type);
+	      return fold_convert (type, associate_trees (var0, con0,
+							  code, type));
+	    }
+	}
+
+    binary:
+      if (wins)
+	t1 = const_binop (code, arg0, arg1, 0);
+      if (t1 != NULL_TREE)
+	{
+	  /* The return value should always have
+	     the same type as the original expression.  */
+	  if (TREE_TYPE (t1) != type)
+	    t1 = fold_convert (type, t1);
+
+	  return t1;
+	}
+      return t;
+
+    case MINUS_EXPR:
+      /* A - (-B) -> A + B */
+      if (TREE_CODE (arg1) == NEGATE_EXPR)
+	return fold (build2 (PLUS_EXPR, type, arg0, TREE_OPERAND (arg1, 0)));
+      /* (-A) - B -> (-B) - A  where B is easily negated and we can swap.  */
+      if (TREE_CODE (arg0) == NEGATE_EXPR
+	  && (FLOAT_TYPE_P (type)
+	      || (INTEGRAL_TYPE_P (type) && flag_wrapv && !flag_trapv))
+	  && negate_expr_p (arg1)
+	  && reorder_operands_p (arg0, arg1))
+	return fold (build2 (MINUS_EXPR, type, negate_expr (arg1),
+			     TREE_OPERAND (arg0, 0)));
+
+      if (TREE_CODE (type) == COMPLEX_TYPE)
+	{
+	  tem = fold_complex_add (type, arg0, arg1, MINUS_EXPR);
+	  if (tem)
+	    return tem;
+	}
+
+      if (! FLOAT_TYPE_P (type))
+	{
+	  if (! wins && integer_zerop (arg0))
+	    return negate_expr (fold_convert (type, arg1));
+	  if (integer_zerop (arg1))
+	    return non_lvalue (fold_convert (type, arg0));
+
+	  /* Fold A - (A & B) into ~B & A.  */
+	  if (!TREE_SIDE_EFFECTS (arg0)
+	      && TREE_CODE (arg1) == BIT_AND_EXPR)
+	    {
+	      if (operand_equal_p (arg0, TREE_OPERAND (arg1, 1), 0))
+		return fold (build2 (BIT_AND_EXPR, type,
+				     fold (build1 (BIT_NOT_EXPR, type,
+						   TREE_OPERAND (arg1, 0))),
+				     arg0));
+	      if (operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0))
+		return fold (build2 (BIT_AND_EXPR, type,
+				     fold (build1 (BIT_NOT_EXPR, type,
+						   TREE_OPERAND (arg1, 1))),
+				     arg0));
+	    }
+
+	  /* Fold (A & ~B) - (A & B) into (A ^ B) - B, where B is
+	     any power of 2 minus 1.  */
+	  if (TREE_CODE (arg0) == BIT_AND_EXPR
+	      && TREE_CODE (arg1) == BIT_AND_EXPR
+	      && operand_equal_p (TREE_OPERAND (arg0, 0),
+				  TREE_OPERAND (arg1, 0), 0))
+	    {
+	      tree mask0 = TREE_OPERAND (arg0, 1);
+	      tree mask1 = TREE_OPERAND (arg1, 1);
+	      tree tem = fold (build1 (BIT_NOT_EXPR, type, mask0));
+
+	      if (operand_equal_p (tem, mask1, 0))
+		{
+		  tem = fold (build2 (BIT_XOR_EXPR, type,
+				      TREE_OPERAND (arg0, 0), mask1));
+		  return fold (build2 (MINUS_EXPR, type, tem, mask1));
+		}
+	    }
+	}
+
+      /* See if ARG1 is zero and X - ARG1 reduces to X.  */
+      else if (fold_real_zero_addition_p (TREE_TYPE (arg0), arg1, 1))
+	return non_lvalue (fold_convert (type, arg0));
+
+      /* (ARG0 - ARG1) is the same as (-ARG1 + ARG0).  So check whether
+	 ARG0 is zero and X + ARG0 reduces to X, since that would mean
+	 (-ARG1 + ARG0) reduces to -ARG1.  */
+      else if (!wins && fold_real_zero_addition_p (TREE_TYPE (arg1), arg0, 0))
+	return negate_expr (fold_convert (type, arg1));
+
+      /* Fold &x - &x.  This can happen from &x.foo - &x.
+	 This is unsafe for certain floats even in non-IEEE formats.
+	 In IEEE, it is unsafe because it does wrong for NaNs.
+	 Also note that operand_equal_p is always false if an operand
+	 is volatile.  */
+
+      if ((! FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations)
+	  && operand_equal_p (arg0, arg1, 0))
+	return fold_convert (type, integer_zero_node);
+
+      /* A - B -> A + (-B) if B is easily negatable.  */
+      if (!wins && negate_expr_p (arg1)
+	  && ((FLOAT_TYPE_P (type)
+               /* Avoid this transformation if B is a positive REAL_CST.  */
+	       && (TREE_CODE (arg1) != REAL_CST
+		   ||  REAL_VALUE_NEGATIVE (TREE_REAL_CST (arg1))))
+	      || (INTEGRAL_TYPE_P (type) && flag_wrapv && !flag_trapv)))
+	return fold (build2 (PLUS_EXPR, type, arg0, negate_expr (arg1)));
+
+      /* Try folding difference of addresses.  */
+      {
+	HOST_WIDE_INT diff;
+
+	if ((TREE_CODE (arg0) == ADDR_EXPR
+	     || TREE_CODE (arg1) == ADDR_EXPR)
+	    && ptr_difference_const (arg0, arg1, &diff))
+	  return build_int_cst_type (type, diff);
+      }
+	  
+      /* Try replacing &a[i1] - c * i2 with &a[i1 - i2], if c is step
+	 of the array.  Loop optimizer sometimes produce this type of
+	 expressions.  */
+      if (TREE_CODE (arg0) == ADDR_EXPR
+	  && TREE_CODE (arg1) == MULT_EXPR)
+	{
+	  tem = try_move_mult_to_index (MINUS_EXPR, arg0, arg1);
+	  if (tem)
+	    return fold_convert (type, fold (tem));
+	}
+
+      if (TREE_CODE (arg0) == MULT_EXPR
+	  && TREE_CODE (arg1) == MULT_EXPR
+	  && (!FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations))
+	{
+          /* (A * C) - (B * C) -> (A-B) * C.  */
+	  if (operand_equal_p (TREE_OPERAND (arg0, 1),
+			       TREE_OPERAND (arg1, 1), 0))
+	    return fold (build2 (MULT_EXPR, type,
+				 fold (build2 (MINUS_EXPR, type,
+					       TREE_OPERAND (arg0, 0),
+					       TREE_OPERAND (arg1, 0))),
+				 TREE_OPERAND (arg0, 1)));
+          /* (A * C1) - (A * C2) -> A * (C1-C2).  */
+	  if (operand_equal_p (TREE_OPERAND (arg0, 0),
+			       TREE_OPERAND (arg1, 0), 0))
+	    return fold (build2 (MULT_EXPR, type,
+				 TREE_OPERAND (arg0, 0),
+				 fold (build2 (MINUS_EXPR, type,
+					       TREE_OPERAND (arg0, 1),
+					       TREE_OPERAND (arg1, 1)))));
+	}
+
+      goto associate;
+
+    case MULT_EXPR:
+      /* (-A) * (-B) -> A * B  */
+      if (TREE_CODE (arg0) == NEGATE_EXPR && negate_expr_p (arg1))
+	return fold (build2 (MULT_EXPR, type,
+			     TREE_OPERAND (arg0, 0),
+			     negate_expr (arg1)));
+      if (TREE_CODE (arg1) == NEGATE_EXPR && negate_expr_p (arg0))
+	return fold (build2 (MULT_EXPR, type,
+			     negate_expr (arg0),
+			     TREE_OPERAND (arg1, 0)));
+
+      if (TREE_CODE (type) == COMPLEX_TYPE)
+	{
+	  tem = fold_complex_mult (type, arg0, arg1);
+	  if (tem)
+	    return tem;
+	}
+
+      if (! FLOAT_TYPE_P (type))
+	{
+	  if (integer_zerop (arg1))
+	    return omit_one_operand (type, arg1, arg0);
+	  if (integer_onep (arg1))
+	    return non_lvalue (fold_convert (type, arg0));
+
+	  /* (a * (1 << b)) is (a << b)  */
+	  if (TREE_CODE (arg1) == LSHIFT_EXPR
+	      && integer_onep (TREE_OPERAND (arg1, 0)))
+	    return fold (build2 (LSHIFT_EXPR, type, arg0,
+				 TREE_OPERAND (arg1, 1)));
+	  if (TREE_CODE (arg0) == LSHIFT_EXPR
+	      && integer_onep (TREE_OPERAND (arg0, 0)))
+	    return fold (build2 (LSHIFT_EXPR, type, arg1,
+				 TREE_OPERAND (arg0, 1)));
+
+	  if (TREE_CODE (arg1) == INTEGER_CST
+	      && 0 != (tem = extract_muldiv (TREE_OPERAND (t, 0),
+					     fold_convert (type, arg1),
+					     code, NULL_TREE)))
+	    return fold_convert (type, tem);
+
+	}
+      else
+	{
+	  /* Maybe fold x * 0 to 0.  The expressions aren't the same
+	     when x is NaN, since x * 0 is also NaN.  Nor are they the
+	     same in modes with signed zeros, since multiplying a
+	     negative value by 0 gives -0, not +0.  */
+	  if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0)))
+	      && !HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (arg0)))
+	      && real_zerop (arg1))
+	    return omit_one_operand (type, arg1, arg0);
+	  /* In IEEE floating point, x*1 is not equivalent to x for snans.  */
+	  if (!HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg0)))
+	      && real_onep (arg1))
+	    return non_lvalue (fold_convert (type, arg0));
+
+	  /* Transform x * -1.0 into -x.  */
+	  if (!HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg0)))
+	      && real_minus_onep (arg1))
+	    return fold_convert (type, negate_expr (arg0));
+
+	  /* Convert (C1/X)*C2 into (C1*C2)/X.  */
+	  if (flag_unsafe_math_optimizations
+	      && TREE_CODE (arg0) == RDIV_EXPR
+	      && TREE_CODE (arg1) == REAL_CST
+	      && TREE_CODE (TREE_OPERAND (arg0, 0)) == REAL_CST)
+	    {
+	      tree tem = const_binop (MULT_EXPR, TREE_OPERAND (arg0, 0),
+				      arg1, 0);
+	      if (tem)
+		return fold (build2 (RDIV_EXPR, type, tem,
+				     TREE_OPERAND (arg0, 1)));
+	    }
+
+          /* Strip sign operations from X in X*X, i.e. -Y*-Y -> Y*Y.  */
+	  if (operand_equal_p (arg0, arg1, 0))
+	    {
+	      tree tem = fold_strip_sign_ops (arg0);
+	      if (tem != NULL_TREE)
+		{
+		  tem = fold_convert (type, tem);
+		  return fold (build2 (MULT_EXPR, type, tem, tem));
+		}
+	    }
+
+	  if (flag_unsafe_math_optimizations)
+	    {
+	      enum built_in_function fcode0 = builtin_mathfn_code (arg0);
+	      enum built_in_function fcode1 = builtin_mathfn_code (arg1);
+
+	      /* Optimizations of root(...)*root(...).  */
+	      if (fcode0 == fcode1 && BUILTIN_ROOT_P (fcode0))
+		{
+		  tree rootfn, arg, arglist;
+		  tree arg00 = TREE_VALUE (TREE_OPERAND (arg0, 1));
+		  tree arg10 = TREE_VALUE (TREE_OPERAND (arg1, 1));
+
+		  /* Optimize sqrt(x)*sqrt(x) as x.  */
+		  if (BUILTIN_SQRT_P (fcode0)
+		      && operand_equal_p (arg00, arg10, 0)
+		      && ! HONOR_SNANS (TYPE_MODE (type)))
+		    return arg00;
+
+	          /* Optimize root(x)*root(y) as root(x*y).  */
+		  rootfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
+		  arg = fold (build2 (MULT_EXPR, type, arg00, arg10));
+		  arglist = build_tree_list (NULL_TREE, arg);
+		  return build_function_call_expr (rootfn, arglist);
+		}
+
+	      /* Optimize expN(x)*expN(y) as expN(x+y).  */
+	      if (fcode0 == fcode1 && BUILTIN_EXPONENT_P (fcode0))
+		{
+		  tree expfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
+		  tree arg = build2 (PLUS_EXPR, type,
+				     TREE_VALUE (TREE_OPERAND (arg0, 1)),
+				     TREE_VALUE (TREE_OPERAND (arg1, 1)));
+		  tree arglist = build_tree_list (NULL_TREE, fold (arg));
+		  return build_function_call_expr (expfn, arglist);
+		}
+
+	      /* Optimizations of pow(...)*pow(...).  */
+	      if ((fcode0 == BUILT_IN_POW && fcode1 == BUILT_IN_POW)
+		  || (fcode0 == BUILT_IN_POWF && fcode1 == BUILT_IN_POWF)
+		  || (fcode0 == BUILT_IN_POWL && fcode1 == BUILT_IN_POWL))
+		{
+		  tree arg00 = TREE_VALUE (TREE_OPERAND (arg0, 1));
+		  tree arg01 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg0,
+								     1)));
+		  tree arg10 = TREE_VALUE (TREE_OPERAND (arg1, 1));
+		  tree arg11 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg1,
+								     1)));
+
+		  /* Optimize pow(x,y)*pow(z,y) as pow(x*z,y).  */
+		  if (operand_equal_p (arg01, arg11, 0))
+		    {
+		      tree powfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
+		      tree arg = build2 (MULT_EXPR, type, arg00, arg10);
+		      tree arglist = tree_cons (NULL_TREE, fold (arg),
+						build_tree_list (NULL_TREE,
+								 arg01));
+		      return build_function_call_expr (powfn, arglist);
+		    }
+
+		  /* Optimize pow(x,y)*pow(x,z) as pow(x,y+z).  */
+		  if (operand_equal_p (arg00, arg10, 0))
+		    {
+		      tree powfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
+		      tree arg = fold (build2 (PLUS_EXPR, type, arg01, arg11));
+		      tree arglist = tree_cons (NULL_TREE, arg00,
+						build_tree_list (NULL_TREE,
+								 arg));
+		      return build_function_call_expr (powfn, arglist);
+		    }
+		}
+
+	      /* Optimize tan(x)*cos(x) as sin(x).  */
+	      if (((fcode0 == BUILT_IN_TAN && fcode1 == BUILT_IN_COS)
+		   || (fcode0 == BUILT_IN_TANF && fcode1 == BUILT_IN_COSF)
+		   || (fcode0 == BUILT_IN_TANL && fcode1 == BUILT_IN_COSL)
+		   || (fcode0 == BUILT_IN_COS && fcode1 == BUILT_IN_TAN)
+		   || (fcode0 == BUILT_IN_COSF && fcode1 == BUILT_IN_TANF)
+		   || (fcode0 == BUILT_IN_COSL && fcode1 == BUILT_IN_TANL))
+		  && operand_equal_p (TREE_VALUE (TREE_OPERAND (arg0, 1)),
+				      TREE_VALUE (TREE_OPERAND (arg1, 1)), 0))
+		{
+		  tree sinfn = mathfn_built_in (type, BUILT_IN_SIN);
+
+		  if (sinfn != NULL_TREE)
+		    return build_function_call_expr (sinfn,
+						     TREE_OPERAND (arg0, 1));
+		}
+
+	      /* Optimize x*pow(x,c) as pow(x,c+1).  */
+	      if (fcode1 == BUILT_IN_POW
+		  || fcode1 == BUILT_IN_POWF
+		  || fcode1 == BUILT_IN_POWL)
+		{
+		  tree arg10 = TREE_VALUE (TREE_OPERAND (arg1, 1));
+		  tree arg11 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg1,
+								     1)));
+		  if (TREE_CODE (arg11) == REAL_CST
+		      && ! TREE_CONSTANT_OVERFLOW (arg11)
+		      && operand_equal_p (arg0, arg10, 0))
+		    {
+		      tree powfn = TREE_OPERAND (TREE_OPERAND (arg1, 0), 0);
+		      REAL_VALUE_TYPE c;
+		      tree arg, arglist;
+
+		      c = TREE_REAL_CST (arg11);
+		      real_arithmetic (&c, PLUS_EXPR, &c, &dconst1);
+		      arg = build_real (type, c);
+		      arglist = build_tree_list (NULL_TREE, arg);
+		      arglist = tree_cons (NULL_TREE, arg0, arglist);
+		      return build_function_call_expr (powfn, arglist);
+		    }
+		}
+
+	      /* Optimize pow(x,c)*x as pow(x,c+1).  */
+	      if (fcode0 == BUILT_IN_POW
+		  || fcode0 == BUILT_IN_POWF
+		  || fcode0 == BUILT_IN_POWL)
+		{
+		  tree arg00 = TREE_VALUE (TREE_OPERAND (arg0, 1));
+		  tree arg01 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg0,
+								     1)));
+		  if (TREE_CODE (arg01) == REAL_CST
+		      && ! TREE_CONSTANT_OVERFLOW (arg01)
+		      && operand_equal_p (arg1, arg00, 0))
+		    {
+		      tree powfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
+		      REAL_VALUE_TYPE c;
+		      tree arg, arglist;
+
+		      c = TREE_REAL_CST (arg01);
+		      real_arithmetic (&c, PLUS_EXPR, &c, &dconst1);
+		      arg = build_real (type, c);
+		      arglist = build_tree_list (NULL_TREE, arg);
+		      arglist = tree_cons (NULL_TREE, arg1, arglist);
+		      return build_function_call_expr (powfn, arglist);
+		    }
+		}
+
+	      /* Optimize x*x as pow(x,2.0), which is expanded as x*x.  */
+	      if (! optimize_size
+		  && operand_equal_p (arg0, arg1, 0))
+		{
+		  tree powfn = mathfn_built_in (type, BUILT_IN_POW);
+
+		  if (powfn)
+		    {
+		      tree arg = build_real (type, dconst2);
+		      tree arglist = build_tree_list (NULL_TREE, arg);
+		      arglist = tree_cons (NULL_TREE, arg0, arglist);
+		      return build_function_call_expr (powfn, arglist);
+		    }
+		}
+	    }
+	}
+      goto associate;
+
+    case BIT_IOR_EXPR:
+    bit_ior:
+      if (integer_all_onesp (arg1))
+	return omit_one_operand (type, arg1, arg0);
+      if (integer_zerop (arg1))
+	return non_lvalue (fold_convert (type, arg0));
+      if (operand_equal_p (arg0, arg1, 0))
+	return non_lvalue (fold_convert (type, arg0));
+
+      /* ~X | X is -1.  */
+      if (TREE_CODE (arg0) == BIT_NOT_EXPR
+	  && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0))
+	{
+	  t1 = build_int_cst (type, -1);
+	  t1 = force_fit_type (t1, 0, false, false);
+	  return omit_one_operand (type, t1, arg1);
+	}
+
+      /* X | ~X is -1.  */
+      if (TREE_CODE (arg1) == BIT_NOT_EXPR
+	  && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0))
+	{
+	  t1 = build_int_cst (type, -1);
+	  t1 = force_fit_type (t1, 0, false, false);
+	  return omit_one_operand (type, t1, arg0);
+	}
+
+      t1 = distribute_bit_expr (code, type, arg0, arg1);
+      if (t1 != NULL_TREE)
+	return t1;
+
+      /* Convert (or (not arg0) (not arg1)) to (not (and (arg0) (arg1))).
+
+	 This results in more efficient code for machines without a NAND
+	 instruction.  Combine will canonicalize to the first form
+	 which will allow use of NAND instructions provided by the
+	 backend if they exist.  */
+      if (TREE_CODE (arg0) == BIT_NOT_EXPR
+	  && TREE_CODE (arg1) == BIT_NOT_EXPR)
+	{
+	  return fold (build1 (BIT_NOT_EXPR, type,
+			       build2 (BIT_AND_EXPR, type,
+				       TREE_OPERAND (arg0, 0),
+				       TREE_OPERAND (arg1, 0))));
+	}
+
+      /* See if this can be simplified into a rotate first.  If that
+	 is unsuccessful continue in the association code.  */
+      goto bit_rotate;
+
+    case BIT_XOR_EXPR:
+      if (integer_zerop (arg1))
+	return non_lvalue (fold_convert (type, arg0));
+      if (integer_all_onesp (arg1))
+	return fold (build1 (BIT_NOT_EXPR, type, arg0));
+      if (operand_equal_p (arg0, arg1, 0))
+	return omit_one_operand (type, integer_zero_node, arg0);
+
+      /* ~X ^ X is -1.  */
+      if (TREE_CODE (arg0) == BIT_NOT_EXPR
+	  && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0))
+	{
+	  t1 = build_int_cst (type, -1);
+	  t1 = force_fit_type (t1, 0, false, false);
+	  return omit_one_operand (type, t1, arg1);
+	}
+
+      /* X ^ ~X is -1.  */
+      if (TREE_CODE (arg1) == BIT_NOT_EXPR
+	  && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0))
+	{
+	  t1 = build_int_cst (type, -1);
+	  t1 = force_fit_type (t1, 0, false, false);
+	  return omit_one_operand (type, t1, arg0);
+	}
+
+      /* If we are XORing two BIT_AND_EXPR's, both of which are and'ing
+         with a constant, and the two constants have no bits in common,
+	 we should treat this as a BIT_IOR_EXPR since this may produce more
+	 simplifications.  */
+      if (TREE_CODE (arg0) == BIT_AND_EXPR
+	  && TREE_CODE (arg1) == BIT_AND_EXPR
+	  && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
+	  && TREE_CODE (TREE_OPERAND (arg1, 1)) == INTEGER_CST
+	  && integer_zerop (const_binop (BIT_AND_EXPR,
+					 TREE_OPERAND (arg0, 1),
+					 TREE_OPERAND (arg1, 1), 0)))
+	{
+	  code = BIT_IOR_EXPR;
+	  goto bit_ior;
+	}
+
+      /* See if this can be simplified into a rotate first.  If that
+	 is unsuccessful continue in the association code.  */
+      goto bit_rotate;
+
+    case BIT_AND_EXPR:
+      if (integer_all_onesp (arg1))
+	return non_lvalue (fold_convert (type, arg0));
+      if (integer_zerop (arg1))
+	return omit_one_operand (type, arg1, arg0);
+      if (operand_equal_p (arg0, arg1, 0))
+	return non_lvalue (fold_convert (type, arg0));
+
+      /* ~X & X is always zero.  */
+      if (TREE_CODE (arg0) == BIT_NOT_EXPR
+	  && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0))
+	return omit_one_operand (type, integer_zero_node, arg1);
+
+      /* X & ~X is always zero.  */
+      if (TREE_CODE (arg1) == BIT_NOT_EXPR
+	  && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0))
+	return omit_one_operand (type, integer_zero_node, arg0);
+
+      t1 = distribute_bit_expr (code, type, arg0, arg1);
+      if (t1 != NULL_TREE)
+	return t1;
+      /* Simplify ((int)c & 0377) into (int)c, if c is unsigned char.  */
+      if (TREE_CODE (arg1) == INTEGER_CST && TREE_CODE (arg0) == NOP_EXPR
+	  && TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (arg0, 0))))
+	{
+	  unsigned int prec
+	    = TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg0, 0)));
+
+	  if (prec < BITS_PER_WORD && prec < HOST_BITS_PER_WIDE_INT
+	      && (~TREE_INT_CST_LOW (arg1)
+		  & (((HOST_WIDE_INT) 1 << prec) - 1)) == 0)
+	    return fold_convert (type, TREE_OPERAND (arg0, 0));
+	}
+
+      /* Convert (and (not arg0) (not arg1)) to (not (or (arg0) (arg1))).
+
+	 This results in more efficient code for machines without a NOR
+	 instruction.  Combine will canonicalize to the first form
+	 which will allow use of NOR instructions provided by the
+	 backend if they exist.  */
+      if (TREE_CODE (arg0) == BIT_NOT_EXPR
+	  && TREE_CODE (arg1) == BIT_NOT_EXPR)
+	{
+	  return fold (build1 (BIT_NOT_EXPR, type,
+			       build2 (BIT_IOR_EXPR, type,
+				       TREE_OPERAND (arg0, 0),
+				       TREE_OPERAND (arg1, 0))));
+	}
+
+      goto associate;
+
+    case RDIV_EXPR:
+      /* Don't touch a floating-point divide by zero unless the mode
+	 of the constant can represent infinity.  */
+      if (TREE_CODE (arg1) == REAL_CST
+	  && !MODE_HAS_INFINITIES (TYPE_MODE (TREE_TYPE (arg1)))
+	  && real_zerop (arg1))
+	return t;
+
+      /* (-A) / (-B) -> A / B  */
+      if (TREE_CODE (arg0) == NEGATE_EXPR && negate_expr_p (arg1))
+	return fold (build2 (RDIV_EXPR, type,
+			     TREE_OPERAND (arg0, 0),
+			     negate_expr (arg1)));
+      if (TREE_CODE (arg1) == NEGATE_EXPR && negate_expr_p (arg0))
+	return fold (build2 (RDIV_EXPR, type,
+			     negate_expr (arg0),
+			     TREE_OPERAND (arg1, 0)));
+
+      /* In IEEE floating point, x/1 is not equivalent to x for snans.  */
+      if (!HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg0)))
+	  && real_onep (arg1))
+	return non_lvalue (fold_convert (type, arg0));
+
+      /* In IEEE floating point, x/-1 is not equivalent to -x for snans.  */
+      if (!HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg0)))
+	  && real_minus_onep (arg1))
+	return non_lvalue (fold_convert (type, negate_expr (arg0)));
+
+      /* If ARG1 is a constant, we can convert this to a multiply by the
+	 reciprocal.  This does not have the same rounding properties,
+	 so only do this if -funsafe-math-optimizations.  We can actually
+	 always safely do it if ARG1 is a power of two, but it's hard to
+	 tell if it is or not in a portable manner.  */
+      if (TREE_CODE (arg1) == REAL_CST)
+	{
+	  if (flag_unsafe_math_optimizations
+	      && 0 != (tem = const_binop (code, build_real (type, dconst1),
+					  arg1, 0)))
+	    return fold (build2 (MULT_EXPR, type, arg0, tem));
+	  /* Find the reciprocal if optimizing and the result is exact.  */
+	  if (optimize)
+	    {
+	      REAL_VALUE_TYPE r;
+	      r = TREE_REAL_CST (arg1);
+	      if (exact_real_inverse (TYPE_MODE(TREE_TYPE(arg0)), &r))
+		{
+		  tem = build_real (type, r);
+		  return fold (build2 (MULT_EXPR, type, arg0, tem));
+		}
+	    }
+	}
+      /* Convert A/B/C to A/(B*C).  */
+      if (flag_unsafe_math_optimizations
+	  && TREE_CODE (arg0) == RDIV_EXPR)
+	return fold (build2 (RDIV_EXPR, type, TREE_OPERAND (arg0, 0),
+			     fold (build2 (MULT_EXPR, type,
+					   TREE_OPERAND (arg0, 1), arg1))));
+
+      /* Convert A/(B/C) to (A/B)*C.  */
+      if (flag_unsafe_math_optimizations
+	  && TREE_CODE (arg1) == RDIV_EXPR)
+	return fold (build2 (MULT_EXPR, type,
+			     fold (build2 (RDIV_EXPR, type, arg0,
+					   TREE_OPERAND (arg1, 0))),
+			     TREE_OPERAND (arg1, 1)));
+
+      /* Convert C1/(X*C2) into (C1/C2)/X.  */
+      if (flag_unsafe_math_optimizations
+	  && TREE_CODE (arg1) == MULT_EXPR
+	  && TREE_CODE (arg0) == REAL_CST
+	  && TREE_CODE (TREE_OPERAND (arg1, 1)) == REAL_CST)
+	{
+	  tree tem = const_binop (RDIV_EXPR, arg0,
+				  TREE_OPERAND (arg1, 1), 0);
+	  if (tem)
+	    return fold (build2 (RDIV_EXPR, type, tem,
+				 TREE_OPERAND (arg1, 0)));
+	}
+
+      if (TREE_CODE (type) == COMPLEX_TYPE)
+	{
+	  tem = fold_complex_div (type, arg0, arg1, code);
+	  if (tem)
+	    return tem;
+	}
+
+      if (flag_unsafe_math_optimizations)
+	{
+	  enum built_in_function fcode = builtin_mathfn_code (arg1);
+	  /* Optimize x/expN(y) into x*expN(-y).  */
+	  if (BUILTIN_EXPONENT_P (fcode))
+	    {
+	      tree expfn = TREE_OPERAND (TREE_OPERAND (arg1, 0), 0);
+	      tree arg = negate_expr (TREE_VALUE (TREE_OPERAND (arg1, 1)));
+	      tree arglist = build_tree_list (NULL_TREE,
+					      fold_convert (type, arg));
+	      arg1 = build_function_call_expr (expfn, arglist);
+	      return fold (build2 (MULT_EXPR, type, arg0, arg1));
+	    }
+
+	  /* Optimize x/pow(y,z) into x*pow(y,-z).  */
+	  if (fcode == BUILT_IN_POW
+	      || fcode == BUILT_IN_POWF
+	      || fcode == BUILT_IN_POWL)
+	    {
+	      tree powfn = TREE_OPERAND (TREE_OPERAND (arg1, 0), 0);
+	      tree arg10 = TREE_VALUE (TREE_OPERAND (arg1, 1));
+	      tree arg11 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg1, 1)));
+	      tree neg11 = fold_convert (type, negate_expr (arg11));
+	      tree arglist = tree_cons(NULL_TREE, arg10,
+				       build_tree_list (NULL_TREE, neg11));
+	      arg1 = build_function_call_expr (powfn, arglist);
+	      return fold (build2 (MULT_EXPR, type, arg0, arg1));
+	    }
+	}
+
+      if (flag_unsafe_math_optimizations)
+	{
+	  enum built_in_function fcode0 = builtin_mathfn_code (arg0);
+	  enum built_in_function fcode1 = builtin_mathfn_code (arg1);
+
+	  /* Optimize sin(x)/cos(x) as tan(x).  */
+	  if (((fcode0 == BUILT_IN_SIN && fcode1 == BUILT_IN_COS)
+	       || (fcode0 == BUILT_IN_SINF && fcode1 == BUILT_IN_COSF)
+	       || (fcode0 == BUILT_IN_SINL && fcode1 == BUILT_IN_COSL))
+	      && operand_equal_p (TREE_VALUE (TREE_OPERAND (arg0, 1)),
+				  TREE_VALUE (TREE_OPERAND (arg1, 1)), 0))
+	    {
+	      tree tanfn = mathfn_built_in (type, BUILT_IN_TAN);
+
+	      if (tanfn != NULL_TREE)
+		return build_function_call_expr (tanfn,
+						 TREE_OPERAND (arg0, 1));
+	    }
+
+	  /* Optimize cos(x)/sin(x) as 1.0/tan(x).  */
+	  if (((fcode0 == BUILT_IN_COS && fcode1 == BUILT_IN_SIN)
+	       || (fcode0 == BUILT_IN_COSF && fcode1 == BUILT_IN_SINF)
+	       || (fcode0 == BUILT_IN_COSL && fcode1 == BUILT_IN_SINL))
+	      && operand_equal_p (TREE_VALUE (TREE_OPERAND (arg0, 1)),
+				  TREE_VALUE (TREE_OPERAND (arg1, 1)), 0))
+	    {
+	      tree tanfn = mathfn_built_in (type, BUILT_IN_TAN);
+
+	      if (tanfn != NULL_TREE)
+		{
+		  tree tmp = TREE_OPERAND (arg0, 1);
+		  tmp = build_function_call_expr (tanfn, tmp);
+		  return fold (build2 (RDIV_EXPR, type,
+				       build_real (type, dconst1), tmp));
+		}
+	    }
+
+	  /* Optimize pow(x,c)/x as pow(x,c-1).  */
+	  if (fcode0 == BUILT_IN_POW
+	      || fcode0 == BUILT_IN_POWF
+	      || fcode0 == BUILT_IN_POWL)
+	    {
+	      tree arg00 = TREE_VALUE (TREE_OPERAND (arg0, 1));
+	      tree arg01 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg0, 1)));
+	      if (TREE_CODE (arg01) == REAL_CST
+		  && ! TREE_CONSTANT_OVERFLOW (arg01)
+		  && operand_equal_p (arg1, arg00, 0))
+		{
+		  tree powfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
+		  REAL_VALUE_TYPE c;
+		  tree arg, arglist;
+
+		  c = TREE_REAL_CST (arg01);
+		  real_arithmetic (&c, MINUS_EXPR, &c, &dconst1);
+		  arg = build_real (type, c);
+		  arglist = build_tree_list (NULL_TREE, arg);
+		  arglist = tree_cons (NULL_TREE, arg1, arglist);
+		  return build_function_call_expr (powfn, arglist);
+		}
+	    }
+	}
+      goto binary;
+
+    case TRUNC_DIV_EXPR:
+    case ROUND_DIV_EXPR:
+    case FLOOR_DIV_EXPR:
+    case CEIL_DIV_EXPR:
+    case EXACT_DIV_EXPR:
+      if (integer_onep (arg1))
+	return non_lvalue (fold_convert (type, arg0));
+      if (integer_zerop (arg1))
+	return t;
+      /* X / -1 is -X.  */
+      if (!TYPE_UNSIGNED (type)
+	  && TREE_CODE (arg1) == INTEGER_CST
+	  && TREE_INT_CST_LOW (arg1) == (unsigned HOST_WIDE_INT) -1
+	  && TREE_INT_CST_HIGH (arg1) == -1)
+	return fold_convert (type, negate_expr (arg0));
+
+      /* If arg0 is a multiple of arg1, then rewrite to the fastest div
+	 operation, EXACT_DIV_EXPR.
+
+	 Note that only CEIL_DIV_EXPR and FLOOR_DIV_EXPR are rewritten now.
+	 At one time others generated faster code, it's not clear if they do
+	 after the last round to changes to the DIV code in expmed.c.  */
+      if ((code == CEIL_DIV_EXPR || code == FLOOR_DIV_EXPR)
+	  && multiple_of_p (type, arg0, arg1))
+	return fold (build2 (EXACT_DIV_EXPR, type, arg0, arg1));
+
+      if (TREE_CODE (arg1) == INTEGER_CST
+	  && 0 != (tem = extract_muldiv (TREE_OPERAND (t, 0), arg1,
+					 code, NULL_TREE)))
+	return fold_convert (type, tem);
+
+      if (TREE_CODE (type) == COMPLEX_TYPE)
+	{
+	  tem = fold_complex_div (type, arg0, arg1, code);
+	  if (tem)
+	    return tem;
+	}
+      goto binary;
+
+    case CEIL_MOD_EXPR:
+    case FLOOR_MOD_EXPR:
+    case ROUND_MOD_EXPR:
+    case TRUNC_MOD_EXPR:
+      /* X % 1 is always zero, but be sure to preserve any side
+	 effects in X.  */
+      if (integer_onep (arg1))
+	return omit_one_operand (type, integer_zero_node, arg0);
+
+      /* X % 0, return X % 0 unchanged so that we can get the
+	 proper warnings and errors.  */
+      if (integer_zerop (arg1))
+	return t;
+
+      /* 0 % X is always zero, but be sure to preserve any side
+	 effects in X.  Place this after checking for X == 0.  */
+      if (integer_zerop (arg0))
+	return omit_one_operand (type, integer_zero_node, arg1);
+
+      /* X % -1 is zero.  */
+      if (!TYPE_UNSIGNED (type)
+	  && TREE_CODE (arg1) == INTEGER_CST
+	  && TREE_INT_CST_LOW (arg1) == (unsigned HOST_WIDE_INT) -1
+	  && TREE_INT_CST_HIGH (arg1) == -1)
+	return omit_one_operand (type, integer_zero_node, arg0);
+
+      /* Optimize unsigned TRUNC_MOD_EXPR by a power of two into a
+	 BIT_AND_EXPR, i.e. "X % C" into "X & C2".  */
+      if (code == TRUNC_MOD_EXPR
+	  && TYPE_UNSIGNED (type)
+	  && integer_pow2p (arg1))
+	{
+	  unsigned HOST_WIDE_INT high, low;
+	  tree mask;
+	  int l;
+
+	  l = tree_log2 (arg1);
+	  if (l >= HOST_BITS_PER_WIDE_INT)
+	    {
+	      high = ((unsigned HOST_WIDE_INT) 1
+		      << (l - HOST_BITS_PER_WIDE_INT)) - 1;
+	      low = -1;
+	    }
+	  else
+	    {
+	      high = 0;
+	      low = ((unsigned HOST_WIDE_INT) 1 << l) - 1;
+	    }
+
+	  mask = build_int_cst_wide (type, low, high);
+	  return fold (build2 (BIT_AND_EXPR, type,
+			       fold_convert (type, arg0), mask));
+	}
+
+      /* X % -C is the same as X % C.  */
+      if (code == TRUNC_MOD_EXPR
+	  && !TYPE_UNSIGNED (type)
+	  && TREE_CODE (arg1) == INTEGER_CST
+	  && TREE_INT_CST_HIGH (arg1) < 0
+	  && !flag_trapv
+	  /* Avoid this transformation if C is INT_MIN, i.e. C == -C.  */
+	  && !sign_bit_p (arg1, arg1))
+	return fold (build2 (code, type, fold_convert (type, arg0),
+			     fold_convert (type, negate_expr (arg1))));
+
+      /* X % -Y is the same as X % Y.  */
+      if (code == TRUNC_MOD_EXPR
+	  && !TYPE_UNSIGNED (type)
+	  && TREE_CODE (arg1) == NEGATE_EXPR
+	  && !flag_trapv)
+	return fold (build2 (code, type, fold_convert (type, arg0),
+			     fold_convert (type, TREE_OPERAND (arg1, 0))));
+
+      if (TREE_CODE (arg1) == INTEGER_CST
+	  && 0 != (tem = extract_muldiv (TREE_OPERAND (t, 0), arg1,
+					 code, NULL_TREE)))
+	return fold_convert (type, tem);
+
+      goto binary;
+
+    case LROTATE_EXPR:
+    case RROTATE_EXPR:
+      if (integer_all_onesp (arg0))
+	return omit_one_operand (type, arg0, arg1);
+      goto shift;
+
+    case RSHIFT_EXPR:
+      /* Optimize -1 >> x for arithmetic right shifts.  */
+      if (integer_all_onesp (arg0) && !TYPE_UNSIGNED (type))
+	return omit_one_operand (type, arg0, arg1);
+      /* ... fall through ...  */
+
+    case LSHIFT_EXPR:
+    shift:
+      if (integer_zerop (arg1))
+	return non_lvalue (fold_convert (type, arg0));
+      if (integer_zerop (arg0))
+	return omit_one_operand (type, arg0, arg1);
+
+      /* Since negative shift count is not well-defined,
+	 don't try to compute it in the compiler.  */
+      if (TREE_CODE (arg1) == INTEGER_CST && tree_int_cst_sgn (arg1) < 0)
+	return t;
+      /* Rewrite an LROTATE_EXPR by a constant into an
+	 RROTATE_EXPR by a new constant.  */
+      if (code == LROTATE_EXPR && TREE_CODE (arg1) == INTEGER_CST)
+	{
+	  tree tem = build_int_cst (NULL_TREE,
+				    GET_MODE_BITSIZE (TYPE_MODE (type)));
+	  tem = fold_convert (TREE_TYPE (arg1), tem);
+	  tem = const_binop (MINUS_EXPR, tem, arg1, 0);
+	  return fold (build2 (RROTATE_EXPR, type, arg0, tem));
+	}
+
+      /* If we have a rotate of a bit operation with the rotate count and
+	 the second operand of the bit operation both constant,
+	 permute the two operations.  */
+      if (code == RROTATE_EXPR && TREE_CODE (arg1) == INTEGER_CST
+	  && (TREE_CODE (arg0) == BIT_AND_EXPR
+	      || TREE_CODE (arg0) == BIT_IOR_EXPR
+	      || TREE_CODE (arg0) == BIT_XOR_EXPR)
+	  && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
+	return fold (build2 (TREE_CODE (arg0), type,
+			     fold (build2 (code, type,
+					   TREE_OPERAND (arg0, 0), arg1)),
+			     fold (build2 (code, type,
+					   TREE_OPERAND (arg0, 1), arg1))));
+
+      /* Two consecutive rotates adding up to the width of the mode can
+	 be ignored.  */
+      if (code == RROTATE_EXPR && TREE_CODE (arg1) == INTEGER_CST
+	  && TREE_CODE (arg0) == RROTATE_EXPR
+	  && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
+	  && TREE_INT_CST_HIGH (arg1) == 0
+	  && TREE_INT_CST_HIGH (TREE_OPERAND (arg0, 1)) == 0
+	  && ((TREE_INT_CST_LOW (arg1)
+	       + TREE_INT_CST_LOW (TREE_OPERAND (arg0, 1)))
+	      == (unsigned int) GET_MODE_BITSIZE (TYPE_MODE (type))))
+	return TREE_OPERAND (arg0, 0);
+
+      goto binary;
+
+    case MIN_EXPR:
+      if (operand_equal_p (arg0, arg1, 0))
+	return omit_one_operand (type, arg0, arg1);
+      if (INTEGRAL_TYPE_P (type)
+	  && operand_equal_p (arg1, TYPE_MIN_VALUE (type), OEP_ONLY_CONST))
+	return omit_one_operand (type, arg1, arg0);
+      goto associate;
+
+    case MAX_EXPR:
+      if (operand_equal_p (arg0, arg1, 0))
+	return omit_one_operand (type, arg0, arg1);
+      if (INTEGRAL_TYPE_P (type)
+	  && TYPE_MAX_VALUE (type)
+	  && operand_equal_p (arg1, TYPE_MAX_VALUE (type), OEP_ONLY_CONST))
+	return omit_one_operand (type, arg1, arg0);
+      goto associate;
+
+    case TRUTH_ANDIF_EXPR:
+      /* Note that the operands of this must be ints
+	 and their values must be 0 or 1.
+	 ("true" is a fixed value perhaps depending on the language.)  */
+      /* If first arg is constant zero, return it.  */
+      if (integer_zerop (arg0))
+	return fold_convert (type, arg0);
+    case TRUTH_AND_EXPR:
+      /* If either arg is constant true, drop it.  */
+      if (TREE_CODE (arg0) == INTEGER_CST && ! integer_zerop (arg0))
+	return non_lvalue (fold_convert (type, arg1));
+      if (TREE_CODE (arg1) == INTEGER_CST && ! integer_zerop (arg1)
+	  /* Preserve sequence points.  */
+	  && (code != TRUTH_ANDIF_EXPR || ! TREE_SIDE_EFFECTS (arg0)))
+	return non_lvalue (fold_convert (type, arg0));
+      /* If second arg is constant zero, result is zero, but first arg
+	 must be evaluated.  */
+      if (integer_zerop (arg1))
+	return omit_one_operand (type, arg1, arg0);
+      /* Likewise for first arg, but note that only the TRUTH_AND_EXPR
+	 case will be handled here.  */
+      if (integer_zerop (arg0))
+	return omit_one_operand (type, arg0, arg1);
+
+      /* !X && X is always false.  */
+      if (TREE_CODE (arg0) == TRUTH_NOT_EXPR
+	  && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0))
+	return omit_one_operand (type, integer_zero_node, arg1);
+      /* X && !X is always false.  */
+      if (TREE_CODE (arg1) == TRUTH_NOT_EXPR
+	  && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0))
+	return omit_one_operand (type, integer_zero_node, arg0);
+
+      /* A < X && A + 1 > Y ==> A < X && A >= Y.  Normally A + 1 > Y
+	 means A >= Y && A != MAX, but in this case we know that
+	 A < X <= MAX.  */
+
+      if (!TREE_SIDE_EFFECTS (arg0)
+	  && !TREE_SIDE_EFFECTS (arg1))
+	{
+	  tem = fold_to_nonsharp_ineq_using_bound (arg0, arg1);
+	  if (tem)
+	    return fold (build2 (code, type, tem, arg1));
+
+	  tem = fold_to_nonsharp_ineq_using_bound (arg1, arg0);
+	  if (tem)
+	    return fold (build2 (code, type, arg0, tem));
+	}
+
+    truth_andor:
+      /* We only do these simplifications if we are optimizing.  */
+      if (!optimize)
+	return t;
+
+      /* Check for things like (A || B) && (A || C).  We can convert this
+	 to A || (B && C).  Note that either operator can be any of the four
+	 truth and/or operations and the transformation will still be
+	 valid.   Also note that we only care about order for the
+	 ANDIF and ORIF operators.  If B contains side effects, this
+	 might change the truth-value of A.  */
+      if (TREE_CODE (arg0) == TREE_CODE (arg1)
+	  && (TREE_CODE (arg0) == TRUTH_ANDIF_EXPR
+	      || TREE_CODE (arg0) == TRUTH_ORIF_EXPR
+	      || TREE_CODE (arg0) == TRUTH_AND_EXPR
+	      || TREE_CODE (arg0) == TRUTH_OR_EXPR)
+	  && ! TREE_SIDE_EFFECTS (TREE_OPERAND (arg0, 1)))
+	{
+	  tree a00 = TREE_OPERAND (arg0, 0);
+	  tree a01 = TREE_OPERAND (arg0, 1);
+	  tree a10 = TREE_OPERAND (arg1, 0);
+	  tree a11 = TREE_OPERAND (arg1, 1);
+	  int commutative = ((TREE_CODE (arg0) == TRUTH_OR_EXPR
+			      || TREE_CODE (arg0) == TRUTH_AND_EXPR)
+			     && (code == TRUTH_AND_EXPR
+				 || code == TRUTH_OR_EXPR));
+
+	  if (operand_equal_p (a00, a10, 0))
+	    return fold (build2 (TREE_CODE (arg0), type, a00,
+				 fold (build2 (code, type, a01, a11))));
+	  else if (commutative && operand_equal_p (a00, a11, 0))
+	    return fold (build2 (TREE_CODE (arg0), type, a00,
+				 fold (build2 (code, type, a01, a10))));
+	  else if (commutative && operand_equal_p (a01, a10, 0))
+	    return fold (build2 (TREE_CODE (arg0), type, a01,
+				 fold (build2 (code, type, a00, a11))));
+
+	  /* This case if tricky because we must either have commutative
+	     operators or else A10 must not have side-effects.  */
+
+	  else if ((commutative || ! TREE_SIDE_EFFECTS (a10))
+		   && operand_equal_p (a01, a11, 0))
+	    return fold (build2 (TREE_CODE (arg0), type,
+				 fold (build2 (code, type, a00, a10)),
+				 a01));
+	}
+
+      /* See if we can build a range comparison.  */
+      if (0 != (tem = fold_range_test (t)))
+	return tem;
+
+      /* Check for the possibility of merging component references.  If our
+	 lhs is another similar operation, try to merge its rhs with our
+	 rhs.  Then try to merge our lhs and rhs.  */
+      if (TREE_CODE (arg0) == code
+	  && 0 != (tem = fold_truthop (code, type,
+				       TREE_OPERAND (arg0, 1), arg1)))
+	return fold (build2 (code, type, TREE_OPERAND (arg0, 0), tem));
+
+      if ((tem = fold_truthop (code, type, arg0, arg1)) != 0)
+	return tem;
+
+      return t;
+
+    case TRUTH_ORIF_EXPR:
+      /* Note that the operands of this must be ints
+	 and their values must be 0 or true.
+	 ("true" is a fixed value perhaps depending on the language.)  */
+      /* If first arg is constant true, return it.  */
+      if (TREE_CODE (arg0) == INTEGER_CST && ! integer_zerop (arg0))
+	return fold_convert (type, arg0);
+    case TRUTH_OR_EXPR:
+      /* If either arg is constant zero, drop it.  */
+      if (TREE_CODE (arg0) == INTEGER_CST && integer_zerop (arg0))
+	return non_lvalue (fold_convert (type, arg1));
+      if (TREE_CODE (arg1) == INTEGER_CST && integer_zerop (arg1)
+	  /* Preserve sequence points.  */
+	  && (code != TRUTH_ORIF_EXPR || ! TREE_SIDE_EFFECTS (arg0)))
+	return non_lvalue (fold_convert (type, arg0));
+      /* If second arg is constant true, result is true, but we must
+	 evaluate first arg.  */
+      if (TREE_CODE (arg1) == INTEGER_CST && ! integer_zerop (arg1))
+	return omit_one_operand (type, arg1, arg0);
+      /* Likewise for first arg, but note this only occurs here for
+	 TRUTH_OR_EXPR.  */
+      if (TREE_CODE (arg0) == INTEGER_CST && ! integer_zerop (arg0))
+	return omit_one_operand (type, arg0, arg1);
+
+      /* !X || X is always true.  */
+      if (TREE_CODE (arg0) == TRUTH_NOT_EXPR
+	  && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0))
+	return omit_one_operand (type, integer_one_node, arg1);
+      /* X || !X is always true.  */
+      if (TREE_CODE (arg1) == TRUTH_NOT_EXPR
+	  && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0))
+	return omit_one_operand (type, integer_one_node, arg0);
+
+      goto truth_andor;
+
+    case TRUTH_XOR_EXPR:
+      /* If the second arg is constant zero, drop it.  */
+      if (integer_zerop (arg1))
+	return non_lvalue (fold_convert (type, arg0));
+      /* If the second arg is constant true, this is a logical inversion.  */
+      if (integer_onep (arg1))
+	return non_lvalue (fold_convert (type, invert_truthvalue (arg0)));
+      /* Identical arguments cancel to zero.  */
+      if (operand_equal_p (arg0, arg1, 0))
+	return omit_one_operand (type, integer_zero_node, arg0);
+
+      /* !X ^ X is always true.  */
+      if (TREE_CODE (arg0) == TRUTH_NOT_EXPR
+	  && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0))
+	return omit_one_operand (type, integer_one_node, arg1);
+
+      /* X ^ !X is always true.  */
+      if (TREE_CODE (arg1) == TRUTH_NOT_EXPR
+	  && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0))
+	return omit_one_operand (type, integer_one_node, arg0);
+
+      return t;
+
+    case EQ_EXPR:
+    case NE_EXPR:
+    case LT_EXPR:
+    case GT_EXPR:
+    case LE_EXPR:
+    case GE_EXPR:
+      /* If one arg is a real or integer constant, put it last.  */
+      if (tree_swap_operands_p (arg0, arg1, true))
+	return fold (build2 (swap_tree_comparison (code), type, arg1, arg0));
+
+      /* If this is an equality comparison of the address of a non-weak
+	 object against zero, then we know the result.  */
+      if ((code == EQ_EXPR || code == NE_EXPR)
+	  && TREE_CODE (arg0) == ADDR_EXPR
+	  && DECL_P (TREE_OPERAND (arg0, 0))
+	  && ! DECL_WEAK (TREE_OPERAND (arg0, 0))
+	  && integer_zerop (arg1))
+	return constant_boolean_node (code != EQ_EXPR, type);
+
+      /* If this is an equality comparison of the address of two non-weak,
+	 unaliased symbols neither of which are extern (since we do not
+	 have access to attributes for externs), then we know the result.  */
+      if ((code == EQ_EXPR || code == NE_EXPR)
+	  && TREE_CODE (arg0) == ADDR_EXPR
+	  && DECL_P (TREE_OPERAND (arg0, 0))
+	  && ! DECL_WEAK (TREE_OPERAND (arg0, 0))
+	  && ! lookup_attribute ("alias",
+				 DECL_ATTRIBUTES (TREE_OPERAND (arg0, 0)))
+	  && ! DECL_EXTERNAL (TREE_OPERAND (arg0, 0))
+	  && TREE_CODE (arg1) == ADDR_EXPR
+	  && DECL_P (TREE_OPERAND (arg1, 0))
+	  && ! DECL_WEAK (TREE_OPERAND (arg1, 0))
+	  && ! lookup_attribute ("alias",
+				 DECL_ATTRIBUTES (TREE_OPERAND (arg1, 0)))
+	  && ! DECL_EXTERNAL (TREE_OPERAND (arg1, 0)))
+	return constant_boolean_node (operand_equal_p (arg0, arg1, 0)
+				      ? code == EQ_EXPR : code != EQ_EXPR,
+				      type);
+
+      /* If this is a comparison of two exprs that look like an
+	 ARRAY_REF of the same object, then we can fold this to a
+	 comparison of the two offsets.  */
+      if (COMPARISON_CLASS_P (t))
+	{
+	  tree base0, offset0, base1, offset1;
+
+	  if (extract_array_ref (arg0, &base0, &offset0)
+	      && extract_array_ref (arg1, &base1, &offset1)
+	      && operand_equal_p (base0, base1, 0))
+	    {
+	      if (offset0 == NULL_TREE
+		  && offset1 == NULL_TREE)
+		{
+		  offset0 = integer_zero_node;
+		  offset1 = integer_zero_node;
+		}
+	      else if (offset0 == NULL_TREE)
+		offset0 = build_int_cst (TREE_TYPE (offset1), 0);
+	      else if (offset1 == NULL_TREE)
+		offset1 = build_int_cst (TREE_TYPE (offset0), 0);
+
+	      if (TREE_TYPE (offset0) == TREE_TYPE (offset1))
+		return fold (build2 (code, type, offset0, offset1));
+	    }
+	}
+
+      if (FLOAT_TYPE_P (TREE_TYPE (arg0)))
+	{
+	  tree targ0 = strip_float_extensions (arg0);
+	  tree targ1 = strip_float_extensions (arg1);
+	  tree newtype = TREE_TYPE (targ0);
+
+	  if (TYPE_PRECISION (TREE_TYPE (targ1)) > TYPE_PRECISION (newtype))
+	    newtype = TREE_TYPE (targ1);
+
+	  /* Fold (double)float1 CMP (double)float2 into float1 CMP float2.  */
+	  if (TYPE_PRECISION (newtype) < TYPE_PRECISION (TREE_TYPE (arg0)))
+	    return fold (build2 (code, type, fold_convert (newtype, targ0),
+				 fold_convert (newtype, targ1)));
+
+	  /* (-a) CMP (-b) -> b CMP a  */
+	  if (TREE_CODE (arg0) == NEGATE_EXPR
+	      && TREE_CODE (arg1) == NEGATE_EXPR)
+	    return fold (build2 (code, type, TREE_OPERAND (arg1, 0),
+				 TREE_OPERAND (arg0, 0)));
+
+	  if (TREE_CODE (arg1) == REAL_CST)
+	  {
+	    REAL_VALUE_TYPE cst;
+	    cst = TREE_REAL_CST (arg1);
+
+	    /* (-a) CMP CST -> a swap(CMP) (-CST)  */
+	    if (TREE_CODE (arg0) == NEGATE_EXPR)
+	      return
+		fold (build2 (swap_tree_comparison (code), type,
+			      TREE_OPERAND (arg0, 0),
+			      build_real (TREE_TYPE (arg1),
+					  REAL_VALUE_NEGATE (cst))));
+
+	    /* IEEE doesn't distinguish +0 and -0 in comparisons.  */
+	    /* a CMP (-0) -> a CMP 0  */
+	    if (REAL_VALUE_MINUS_ZERO (cst))
+	      return fold (build2 (code, type, arg0,
+				   build_real (TREE_TYPE (arg1), dconst0)));
+
+	    /* x != NaN is always true, other ops are always false.  */
+	    if (REAL_VALUE_ISNAN (cst)
+		&& ! HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg1))))
+	      {
+		tem = (code == NE_EXPR) ? integer_one_node : integer_zero_node;
+		return omit_one_operand (type, tem, arg0);
+	      }
+
+	    /* Fold comparisons against infinity.  */
+	    if (REAL_VALUE_ISINF (cst))
+	      {
+		tem = fold_inf_compare (code, type, arg0, arg1);
+		if (tem != NULL_TREE)
+		  return tem;
+	      }
+	  }
+
+	  /* If this is a comparison of a real constant with a PLUS_EXPR
+	     or a MINUS_EXPR of a real constant, we can convert it into a
+	     comparison with a revised real constant as long as no overflow
+	     occurs when unsafe_math_optimizations are enabled.  */
+	  if (flag_unsafe_math_optimizations
+	      && TREE_CODE (arg1) == REAL_CST
+	      && (TREE_CODE (arg0) == PLUS_EXPR
+		  || TREE_CODE (arg0) == MINUS_EXPR)
+	      && TREE_CODE (TREE_OPERAND (arg0, 1)) == REAL_CST
+	      && 0 != (tem = const_binop (TREE_CODE (arg0) == PLUS_EXPR
+					  ? MINUS_EXPR : PLUS_EXPR,
+					  arg1, TREE_OPERAND (arg0, 1), 0))
+	      && ! TREE_CONSTANT_OVERFLOW (tem))
+	    return fold (build2 (code, type, TREE_OPERAND (arg0, 0), tem));
+
+	  /* Likewise, we can simplify a comparison of a real constant with
+	     a MINUS_EXPR whose first operand is also a real constant, i.e.
+	     (c1 - x) < c2 becomes x > c1-c2.  */
+	  if (flag_unsafe_math_optimizations
+	      && TREE_CODE (arg1) == REAL_CST
+	      && TREE_CODE (arg0) == MINUS_EXPR
+	      && TREE_CODE (TREE_OPERAND (arg0, 0)) == REAL_CST
+	      && 0 != (tem = const_binop (MINUS_EXPR, TREE_OPERAND (arg0, 0),
+					  arg1, 0))
+	      && ! TREE_CONSTANT_OVERFLOW (tem))
+	    return fold (build2 (swap_tree_comparison (code), type,
+				 TREE_OPERAND (arg0, 1), tem));
+
+	  /* Fold comparisons against built-in math functions.  */
+	  if (TREE_CODE (arg1) == REAL_CST
+	      && flag_unsafe_math_optimizations
+	      && ! flag_errno_math)
+	    {
+	      enum built_in_function fcode = builtin_mathfn_code (arg0);
+
+	      if (fcode != END_BUILTINS)
+		{
+		  tem = fold_mathfn_compare (fcode, code, type, arg0, arg1);
+		  if (tem != NULL_TREE)
+		    return tem;
+		}
+	    }
+	}
+
+      /* Convert foo++ == CONST into ++foo == CONST + INCR.  */
+      if (TREE_CONSTANT (arg1)
+	  && (TREE_CODE (arg0) == POSTINCREMENT_EXPR
+	      || TREE_CODE (arg0) == POSTDECREMENT_EXPR)
+	  /* This optimization is invalid for ordered comparisons
+	     if CONST+INCR overflows or if foo+incr might overflow.
+	     This optimization is invalid for floating point due to rounding.
+	     For pointer types we assume overflow doesn't happen.  */
+	  && (POINTER_TYPE_P (TREE_TYPE (arg0))
+	      || (INTEGRAL_TYPE_P (TREE_TYPE (arg0))
+		  && (code == EQ_EXPR || code == NE_EXPR))))
+	{
+	  tree varop, newconst;
+
+	  if (TREE_CODE (arg0) == POSTINCREMENT_EXPR)
+	    {
+	      newconst = fold (build2 (PLUS_EXPR, TREE_TYPE (arg0),
+				       arg1, TREE_OPERAND (arg0, 1)));
+	      varop = build2 (PREINCREMENT_EXPR, TREE_TYPE (arg0),
+			      TREE_OPERAND (arg0, 0),
+			      TREE_OPERAND (arg0, 1));
+	    }
+	  else
+	    {
+	      newconst = fold (build2 (MINUS_EXPR, TREE_TYPE (arg0),
+				       arg1, TREE_OPERAND (arg0, 1)));
+	      varop = build2 (PREDECREMENT_EXPR, TREE_TYPE (arg0),
+			      TREE_OPERAND (arg0, 0),
+			      TREE_OPERAND (arg0, 1));
+	    }
+
+
+	  /* If VAROP is a reference to a bitfield, we must mask
+	     the constant by the width of the field.  */
+	  if (TREE_CODE (TREE_OPERAND (varop, 0)) == COMPONENT_REF
+	      && DECL_BIT_FIELD (TREE_OPERAND (TREE_OPERAND (varop, 0), 1))
+	      && host_integerp (DECL_SIZE (TREE_OPERAND
+					   (TREE_OPERAND (varop, 0), 1)), 1))
+	    {
+	      tree fielddecl = TREE_OPERAND (TREE_OPERAND (varop, 0), 1);
+	      HOST_WIDE_INT size = tree_low_cst (DECL_SIZE (fielddecl), 1);
+	      tree folded_compare, shift;
+
+	      /* First check whether the comparison would come out
+		 always the same.  If we don't do that we would
+		 change the meaning with the masking.  */
+	      folded_compare = fold (build2 (code, type,
+					     TREE_OPERAND (varop, 0), arg1));
+	      if (integer_zerop (folded_compare)
+		  || integer_onep (folded_compare))
+		return omit_one_operand (type, folded_compare, varop);
+
+	      shift = build_int_cst (NULL_TREE,
+				     TYPE_PRECISION (TREE_TYPE (varop)) - size);
+	      shift = fold_convert (TREE_TYPE (varop), shift);
+	      newconst = fold (build2 (LSHIFT_EXPR, TREE_TYPE (varop),
+				       newconst, shift));
+	      newconst = fold (build2 (RSHIFT_EXPR, TREE_TYPE (varop),
+				       newconst, shift));
+	    }
+
+	  return fold (build2 (code, type, varop, newconst));
+	}
+
+      /* Change X >= C to X > (C - 1) and X < C to X <= (C - 1) if C > 0.
+	 This transformation affects the cases which are handled in later
+	 optimizations involving comparisons with non-negative constants.  */
+      if (TREE_CODE (arg1) == INTEGER_CST
+	  && TREE_CODE (arg0) != INTEGER_CST
+	  && tree_int_cst_sgn (arg1) > 0)
+	{
+	  switch (code)
+	    {
+	    case GE_EXPR:
+	      arg1 = const_binop (MINUS_EXPR, arg1, integer_one_node, 0);
+	      return fold (build2 (GT_EXPR, type, arg0, arg1));
+
+	    case LT_EXPR:
+	      arg1 = const_binop (MINUS_EXPR, arg1, integer_one_node, 0);
+	      return fold (build2 (LE_EXPR, type, arg0, arg1));
+
+	    default:
+	      break;
+	    }
+	}
+
+      /* Comparisons with the highest or lowest possible integer of
+	 the specified size will have known values.
+
+	 This is quite similar to fold_relational_hi_lo, however,
+	 attempts to share the code have been nothing but trouble.  */
+      {
+	int width = GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (arg1)));
+
+	if (TREE_CODE (arg1) == INTEGER_CST
+	    && ! TREE_CONSTANT_OVERFLOW (arg1)
+	    && width <= 2 * HOST_BITS_PER_WIDE_INT
+	    && (INTEGRAL_TYPE_P (TREE_TYPE (arg1))
+		|| POINTER_TYPE_P (TREE_TYPE (arg1))))
+	  {
+	    HOST_WIDE_INT signed_max_hi;
+	    unsigned HOST_WIDE_INT signed_max_lo;
+	    unsigned HOST_WIDE_INT max_hi, max_lo, min_hi, min_lo;
+
+	    if (width <= HOST_BITS_PER_WIDE_INT)
+	      {
+		signed_max_lo = ((unsigned HOST_WIDE_INT) 1 << (width - 1))
+				- 1;
+		signed_max_hi = 0;
+		max_hi = 0;
+
+		if (TYPE_UNSIGNED (TREE_TYPE (arg1)))
+		  {
+		    max_lo = ((unsigned HOST_WIDE_INT) 2 << (width - 1)) - 1;
+		    min_lo = 0;
+		    min_hi = 0;
+		  }
+		else
+		  {
+		    max_lo = signed_max_lo;
+		    min_lo = ((unsigned HOST_WIDE_INT) -1 << (width - 1));
+		    min_hi = -1;
+		  }
+	      }
+	    else
+	      {
+		width -= HOST_BITS_PER_WIDE_INT;
+		signed_max_lo = -1;
+		signed_max_hi = ((unsigned HOST_WIDE_INT) 1 << (width - 1))
+				- 1;
+		max_lo = -1;
+		min_lo = 0;
+
+		if (TYPE_UNSIGNED (TREE_TYPE (arg1)))
+		  {
+		    max_hi = ((unsigned HOST_WIDE_INT) 2 << (width - 1)) - 1;
+		    min_hi = 0;
+		  }
+		else
+		  {
+		    max_hi = signed_max_hi;
+		    min_hi = ((unsigned HOST_WIDE_INT) -1 << (width - 1));
+		  }
+	      }
+
+	    if ((unsigned HOST_WIDE_INT) TREE_INT_CST_HIGH (arg1) == max_hi
+		&& TREE_INT_CST_LOW (arg1) == max_lo)
+	      switch (code)
+		{
+		case GT_EXPR:
+		  return omit_one_operand (type, integer_zero_node, arg0);
+
+		case GE_EXPR:
+		  return fold (build2 (EQ_EXPR, type, arg0, arg1));
+
+		case LE_EXPR:
+		  return omit_one_operand (type, integer_one_node, arg0);
+
+		case LT_EXPR:
+		  return fold (build2 (NE_EXPR, type, arg0, arg1));
+
+		/* The GE_EXPR and LT_EXPR cases above are not normally
+		   reached because of previous transformations.  */
+
+		default:
+		  break;
+		}
+	    else if ((unsigned HOST_WIDE_INT) TREE_INT_CST_HIGH (arg1)
+		     == max_hi
+		     && TREE_INT_CST_LOW (arg1) == max_lo - 1)
+	      switch (code)
+		{
+		case GT_EXPR:
+		  arg1 = const_binop (PLUS_EXPR, arg1, integer_one_node, 0);
+		  return fold (build2 (EQ_EXPR, type, arg0, arg1));
+		case LE_EXPR:
+		  arg1 = const_binop (PLUS_EXPR, arg1, integer_one_node, 0);
+		  return fold (build2 (NE_EXPR, type, arg0, arg1));
+		default:
+		  break;
+		}
+	    else if ((unsigned HOST_WIDE_INT) TREE_INT_CST_HIGH (arg1)
+		     == min_hi
+		     && TREE_INT_CST_LOW (arg1) == min_lo)
+	      switch (code)
+		{
+		case LT_EXPR:
+		  return omit_one_operand (type, integer_zero_node, arg0);
+
+		case LE_EXPR:
+		  return fold (build2 (EQ_EXPR, type, arg0, arg1));
+
+		case GE_EXPR:
+		  return omit_one_operand (type, integer_one_node, arg0);
+
+		case GT_EXPR:
+		  return fold (build2 (NE_EXPR, type, arg0, arg1));
+
+		default:
+		  break;
+		}
+	    else if ((unsigned HOST_WIDE_INT) TREE_INT_CST_HIGH (arg1)
+		     == min_hi
+		     && TREE_INT_CST_LOW (arg1) == min_lo + 1)
+	      switch (code)
+		{
+		case GE_EXPR:
+		  arg1 = const_binop (MINUS_EXPR, arg1, integer_one_node, 0);
+		  return fold (build2 (NE_EXPR, type, arg0, arg1));
+		case LT_EXPR:
+		  arg1 = const_binop (MINUS_EXPR, arg1, integer_one_node, 0);
+		  return fold (build2 (EQ_EXPR, type, arg0, arg1));
+		default:
+		  break;
+		}
+
+	    else if (!in_gimple_form
+		     && TREE_INT_CST_HIGH (arg1) == signed_max_hi
+		     && TREE_INT_CST_LOW (arg1) == signed_max_lo
+		     && TYPE_UNSIGNED (TREE_TYPE (arg1))
+		     /* signed_type does not work on pointer types.  */
+		     && INTEGRAL_TYPE_P (TREE_TYPE (arg1)))
+	      {
+		/* The following case also applies to X < signed_max+1
+		   and X >= signed_max+1 because previous transformations.  */
+		if (code == LE_EXPR || code == GT_EXPR)
+		  {
+		    tree st0, st1;
+		    st0 = lang_hooks.types.signed_type (TREE_TYPE (arg0));
+		    st1 = lang_hooks.types.signed_type (TREE_TYPE (arg1));
+		    return fold
+		      (build2 (code == LE_EXPR ? GE_EXPR: LT_EXPR,
+			       type, fold_convert (st0, arg0),
+			       fold_convert (st1, integer_zero_node)));
+		  }
+	      }
+	  }
+      }
+
+      /* If this is an EQ or NE comparison of a constant with a PLUS_EXPR or
+	 a MINUS_EXPR of a constant, we can convert it into a comparison with
+	 a revised constant as long as no overflow occurs.  */
+      if ((code == EQ_EXPR || code == NE_EXPR)
+	  && TREE_CODE (arg1) == INTEGER_CST
+	  && (TREE_CODE (arg0) == PLUS_EXPR
+	      || TREE_CODE (arg0) == MINUS_EXPR)
+	  && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
+	  && 0 != (tem = const_binop (TREE_CODE (arg0) == PLUS_EXPR
+				      ? MINUS_EXPR : PLUS_EXPR,
+				      arg1, TREE_OPERAND (arg0, 1), 0))
+	  && ! TREE_CONSTANT_OVERFLOW (tem))
+	return fold (build2 (code, type, TREE_OPERAND (arg0, 0), tem));
+
+      /* Similarly for a NEGATE_EXPR.  */
+      else if ((code == EQ_EXPR || code == NE_EXPR)
+	       && TREE_CODE (arg0) == NEGATE_EXPR
+	       && TREE_CODE (arg1) == INTEGER_CST
+	       && 0 != (tem = negate_expr (arg1))
+	       && TREE_CODE (tem) == INTEGER_CST
+	       && ! TREE_CONSTANT_OVERFLOW (tem))
+	return fold (build2 (code, type, TREE_OPERAND (arg0, 0), tem));
+
+      /* If we have X - Y == 0, we can convert that to X == Y and similarly
+	 for !=.  Don't do this for ordered comparisons due to overflow.  */
+      else if ((code == NE_EXPR || code == EQ_EXPR)
+	       && integer_zerop (arg1) && TREE_CODE (arg0) == MINUS_EXPR)
+	return fold (build2 (code, type,
+			     TREE_OPERAND (arg0, 0), TREE_OPERAND (arg0, 1)));
+
+      else if (TREE_CODE (TREE_TYPE (arg0)) == INTEGER_TYPE
+	       && TREE_CODE (arg0) == NOP_EXPR)
+	{
+	  /* If we are widening one operand of an integer comparison,
+	     see if the other operand is similarly being widened.  Perhaps we
+	     can do the comparison in the narrower type.  */
+	  tem = fold_widened_comparison (code, type, arg0, arg1);
+	  if (tem)
+	    return tem;
+
+	  /* Or if we are changing signedness.  */
+	  tem = fold_sign_changed_comparison (code, type, arg0, arg1);
+	  if (tem)
+	    return tem;
+	}
+
+      /* If this is comparing a constant with a MIN_EXPR or a MAX_EXPR of a
+	 constant, we can simplify it.  */
+      else if (TREE_CODE (arg1) == INTEGER_CST
+	       && (TREE_CODE (arg0) == MIN_EXPR
+		   || TREE_CODE (arg0) == MAX_EXPR)
+	       && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
+	return optimize_minmax_comparison (t);
+
+      /* If we are comparing an ABS_EXPR with a constant, we can
+	 convert all the cases into explicit comparisons, but they may
+	 well not be faster than doing the ABS and one comparison.
+	 But ABS (X) <= C is a range comparison, which becomes a subtraction
+	 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)
+	       && (0 != (tem = negate_expr (arg1)))
+	       && TREE_CODE (tem) == INTEGER_CST
+	       && ! TREE_CONSTANT_OVERFLOW (tem))
+	return fold (build2 (TRUTH_ANDIF_EXPR, type,
+			     build2 (GE_EXPR, type,
+				     TREE_OPERAND (arg0, 0), tem),
+			     build2 (LE_EXPR, type,
+				     TREE_OPERAND (arg0, 0), arg1)));
+
+      /* Convert ABS_EXPR<x> >= 0 to true.  */
+      else if (code == GE_EXPR
+	       && tree_expr_nonnegative_p (arg0)
+	       && (integer_zerop (arg1)
+		   || (! HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0)))
+                       && real_zerop (arg1))))
+	return omit_one_operand (type, integer_one_node, arg0);
+
+      /* Convert ABS_EXPR<x> < 0 to false.  */
+      else if (code == LT_EXPR
+	       && tree_expr_nonnegative_p (arg0)
+	       && (integer_zerop (arg1) || real_zerop (arg1)))
+	return omit_one_operand (type, integer_zero_node, arg0);
+
+      /* Convert ABS_EXPR<x> == 0 or ABS_EXPR<x> != 0 to x == 0 or x != 0.  */
+      else if ((code == EQ_EXPR || code == NE_EXPR)
+	       && TREE_CODE (arg0) == ABS_EXPR
+	       && (integer_zerop (arg1) || real_zerop (arg1)))
+	return fold (build2 (code, 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
+	 two operations, but the latter can be done in one less insn
+	 on machines that have only two-operand insns or on which a
+	 constant cannot be the first operand.  */
+      if (integer_zerop (arg1) && (code == EQ_EXPR || code == NE_EXPR)
+	  && TREE_CODE (arg0) == BIT_AND_EXPR)
+	{
+	  tree arg00 = TREE_OPERAND (arg0, 0);
+	  tree arg01 = TREE_OPERAND (arg0, 1);
+	  if (TREE_CODE (arg00) == LSHIFT_EXPR
+	      && integer_onep (TREE_OPERAND (arg00, 0)))
+	    return
+	      fold (build2 (code, type,
+			    build2 (BIT_AND_EXPR, TREE_TYPE (arg0),
+				    build2 (RSHIFT_EXPR, TREE_TYPE (arg00),
+					    arg01, TREE_OPERAND (arg00, 1)),
+				    fold_convert (TREE_TYPE (arg0),
+						  integer_one_node)),
+			    arg1));
+	  else if (TREE_CODE (TREE_OPERAND (arg0, 1)) == LSHIFT_EXPR
+		   && integer_onep (TREE_OPERAND (TREE_OPERAND (arg0, 1), 0)))
+	    return
+	      fold (build2 (code, type,
+			    build2 (BIT_AND_EXPR, TREE_TYPE (arg0),
+				    build2 (RSHIFT_EXPR, TREE_TYPE (arg01),
+					    arg00, TREE_OPERAND (arg01, 1)),
+				    fold_convert (TREE_TYPE (arg0),
+						  integer_one_node)),
+			    arg1));
+	}
+
+      /* If this is an NE or EQ comparison of zero against the result of a
+	 signed MOD operation whose second operand is a power of 2, make
+	 the MOD operation unsigned since it is simpler and equivalent.  */
+      if ((code == NE_EXPR || code == EQ_EXPR)
+	  && integer_zerop (arg1)
+	  && !TYPE_UNSIGNED (TREE_TYPE (arg0))
+	  && (TREE_CODE (arg0) == TRUNC_MOD_EXPR
+	      || TREE_CODE (arg0) == CEIL_MOD_EXPR
+	      || TREE_CODE (arg0) == FLOOR_MOD_EXPR
+	      || TREE_CODE (arg0) == ROUND_MOD_EXPR)
+	  && integer_pow2p (TREE_OPERAND (arg0, 1)))
+	{
+	  tree newtype = lang_hooks.types.unsigned_type (TREE_TYPE (arg0));
+	  tree newmod = fold (build2 (TREE_CODE (arg0), newtype,
+				      fold_convert (newtype,
+						    TREE_OPERAND (arg0, 0)),
+				      fold_convert (newtype,
+						    TREE_OPERAND (arg0, 1))));
+
+	  return fold (build2 (code, type, newmod,
+			       fold_convert (newtype, arg1)));
+	}
+
+      /* If this is an NE comparison of zero with an AND of one, remove the
+	 comparison since the AND will give the correct value.  */
+      if (code == NE_EXPR && integer_zerop (arg1)
+	  && TREE_CODE (arg0) == BIT_AND_EXPR
+	  && integer_onep (TREE_OPERAND (arg0, 1)))
+	return fold_convert (type, arg0);
+
+      /* If we have (A & C) == C where C is a power of 2, convert this into
+	 (A & C) != 0.  Similarly for NE_EXPR.  */
+      if ((code == EQ_EXPR || code == NE_EXPR)
+	  && TREE_CODE (arg0) == BIT_AND_EXPR
+	  && integer_pow2p (TREE_OPERAND (arg0, 1))
+	  && operand_equal_p (TREE_OPERAND (arg0, 1), arg1, 0))
+	return fold (build2 (code == EQ_EXPR ? NE_EXPR : EQ_EXPR, type,
+			     arg0, fold_convert (TREE_TYPE (arg0),
+						 integer_zero_node)));
+
+      /* If we have (A & C) != 0 or (A & C) == 0 and C is a power of
+	 2, then fold the expression into shifts and logical operations.  */
+      tem = fold_single_bit_test (code, arg0, arg1, type);
+      if (tem)
+	return tem;
+
+      /* If we have (A & C) == D where D & ~C != 0, convert this into 0.
+	 Similarly for NE_EXPR.  */
+      if ((code == EQ_EXPR || code == NE_EXPR)
+	  && TREE_CODE (arg0) == BIT_AND_EXPR
+	  && TREE_CODE (arg1) == INTEGER_CST
+	  && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
+	{
+	  tree notc = fold (build1 (BIT_NOT_EXPR,
+				    TREE_TYPE (TREE_OPERAND (arg0, 1)),
+				    TREE_OPERAND (arg0, 1)));
+	  tree dandnotc = fold (build2 (BIT_AND_EXPR, TREE_TYPE (arg0),
+					arg1, notc));
+	  tree rslt = code == EQ_EXPR ? integer_zero_node : integer_one_node;
+	  if (integer_nonzerop (dandnotc))
+	    return omit_one_operand (type, rslt, arg0);
+	}
+
+      /* If we have (A | C) == D where C & ~D != 0, convert this into 0.
+	 Similarly for NE_EXPR.  */
+      if ((code == EQ_EXPR || code == NE_EXPR)
+	  && TREE_CODE (arg0) == BIT_IOR_EXPR
+	  && TREE_CODE (arg1) == INTEGER_CST
+	  && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
+	{
+	  tree notd = fold (build1 (BIT_NOT_EXPR, TREE_TYPE (arg1), arg1));
+	  tree candnotd = fold (build2 (BIT_AND_EXPR, TREE_TYPE (arg0),
+					TREE_OPERAND (arg0, 1), notd));
+	  tree rslt = code == EQ_EXPR ? integer_zero_node : integer_one_node;
+	  if (integer_nonzerop (candnotd))
+	    return omit_one_operand (type, rslt, arg0);
+	}
+
+      /* If X is unsigned, convert X < (1 << Y) into X >> Y == 0
+	 and similarly for >= into !=.  */
+      if ((code == LT_EXPR || code == GE_EXPR)
+	  && TYPE_UNSIGNED (TREE_TYPE (arg0))
+	  && TREE_CODE (arg1) == LSHIFT_EXPR
+	  && integer_onep (TREE_OPERAND (arg1, 0)))
+	return build2 (code == LT_EXPR ? EQ_EXPR : NE_EXPR, type,
+		       build2 (RSHIFT_EXPR, TREE_TYPE (arg0), arg0,
+			       TREE_OPERAND (arg1, 1)),
+		       fold_convert (TREE_TYPE (arg0), integer_zero_node));
+
+      else if ((code == LT_EXPR || code == GE_EXPR)
+	       && TYPE_UNSIGNED (TREE_TYPE (arg0))
+	       && (TREE_CODE (arg1) == NOP_EXPR
+		   || TREE_CODE (arg1) == CONVERT_EXPR)
+	       && TREE_CODE (TREE_OPERAND (arg1, 0)) == LSHIFT_EXPR
+	       && integer_onep (TREE_OPERAND (TREE_OPERAND (arg1, 0), 0)))
+	return
+	  build2 (code == LT_EXPR ? EQ_EXPR : NE_EXPR, type,
+		  fold_convert (TREE_TYPE (arg0),
+				build2 (RSHIFT_EXPR, TREE_TYPE (arg0), arg0,
+					TREE_OPERAND (TREE_OPERAND (arg1, 0),
+						      1))),
+		  fold_convert (TREE_TYPE (arg0), integer_zero_node));
+
+      /* Simplify comparison of something with itself.  (For IEEE
+	 floating-point, we can only do some of these simplifications.)  */
+      if (operand_equal_p (arg0, arg1, 0))
+	{
+	  switch (code)
+	    {
+	    case EQ_EXPR:
+	      if (! FLOAT_TYPE_P (TREE_TYPE (arg0))
+		  || ! HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0))))
+		return constant_boolean_node (1, type);
+	      break;
+
+	    case GE_EXPR:
+	    case LE_EXPR:
+	      if (! FLOAT_TYPE_P (TREE_TYPE (arg0))
+		  || ! HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0))))
+		return constant_boolean_node (1, type);
+	      return fold (build2 (EQ_EXPR, type, arg0, arg1));
+
+	    case NE_EXPR:
+	      /* For NE, we can only do this simplification if integer
+		 or we don't honor IEEE floating point NaNs.  */
+	      if (FLOAT_TYPE_P (TREE_TYPE (arg0))
+		  && HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0))))
+		break;
+	      /* ... fall through ...  */
+	    case GT_EXPR:
+	    case LT_EXPR:
+	      return constant_boolean_node (0, type);
+	    default:
+	      gcc_unreachable ();
+	    }
+	}
+
+      /* If we are comparing an expression that just has comparisons
+	 of two integer values, arithmetic expressions of those comparisons,
+	 and constants, we can simplify it.  There are only three cases
+	 to check: the two values can either be equal, the first can be
+	 greater, or the second can be greater.  Fold the expression for
+	 those three values.  Since each value must be 0 or 1, we have
+	 eight possibilities, each of which corresponds to the constant 0
+	 or 1 or one of the six possible comparisons.
+
+	 This handles common cases like (a > b) == 0 but also handles
+	 expressions like  ((x > y) - (y > x)) > 0, which supposedly
+	 occur in macroized code.  */
+
+      if (TREE_CODE (arg1) == INTEGER_CST && TREE_CODE (arg0) != INTEGER_CST)
+	{
+	  tree cval1 = 0, cval2 = 0;
+	  int save_p = 0;
+
+	  if (twoval_comparison_p (arg0, &cval1, &cval2, &save_p)
+	      /* Don't handle degenerate cases here; they should already
+		 have been handled anyway.  */
+	      && cval1 != 0 && cval2 != 0
+	      && ! (TREE_CONSTANT (cval1) && TREE_CONSTANT (cval2))
+	      && TREE_TYPE (cval1) == TREE_TYPE (cval2)
+	      && INTEGRAL_TYPE_P (TREE_TYPE (cval1))
+	      && TYPE_MAX_VALUE (TREE_TYPE (cval1))
+	      && TYPE_MAX_VALUE (TREE_TYPE (cval2))
+	      && ! operand_equal_p (TYPE_MIN_VALUE (TREE_TYPE (cval1)),
+				    TYPE_MAX_VALUE (TREE_TYPE (cval2)), 0))
+	    {
+	      tree maxval = TYPE_MAX_VALUE (TREE_TYPE (cval1));
+	      tree minval = TYPE_MIN_VALUE (TREE_TYPE (cval1));
+
+	      /* We can't just pass T to eval_subst in case cval1 or cval2
+		 was the same as ARG1.  */
+
+	      tree high_result
+		= fold (build2 (code, type,
+				eval_subst (arg0, cval1, maxval,
+					    cval2, minval),
+				arg1));
+	      tree equal_result
+		= fold (build2 (code, type,
+				eval_subst (arg0, cval1, maxval,
+					    cval2, maxval),
+				arg1));
+	      tree low_result
+		= fold (build2 (code, type,
+				eval_subst (arg0, cval1, minval,
+					    cval2, maxval),
+				arg1));
+
+	      /* All three of these results should be 0 or 1.  Confirm they
+		 are.  Then use those values to select the proper code
+		 to use.  */
+
+	      if ((integer_zerop (high_result)
+		   || integer_onep (high_result))
+		  && (integer_zerop (equal_result)
+		      || integer_onep (equal_result))
+		  && (integer_zerop (low_result)
+		      || integer_onep (low_result)))
+		{
+		  /* Make a 3-bit mask with the high-order bit being the
+		     value for `>', the next for '=', and the low for '<'.  */
+		  switch ((integer_onep (high_result) * 4)
+			  + (integer_onep (equal_result) * 2)
+			  + integer_onep (low_result))
+		    {
+		    case 0:
+		      /* Always false.  */
+		      return omit_one_operand (type, integer_zero_node, arg0);
+		    case 1:
+		      code = LT_EXPR;
+		      break;
+		    case 2:
+		      code = EQ_EXPR;
+		      break;
+		    case 3:
+		      code = LE_EXPR;
+		      break;
+		    case 4:
+		      code = GT_EXPR;
+		      break;
+		    case 5:
+		      code = NE_EXPR;
+		      break;
+		    case 6:
+		      code = GE_EXPR;
+		      break;
+		    case 7:
+		      /* Always true.  */
+		      return omit_one_operand (type, integer_one_node, arg0);
+		    }
+
+		  tem = build2 (code, type, cval1, cval2);
+		  if (save_p)
+		    return save_expr (tem);
+		  else
+		    return fold (tem);
+		}
+	    }
+	}
+
+      /* If this is a comparison of a field, we may be able to simplify it.  */
+      if (((TREE_CODE (arg0) == COMPONENT_REF
+	    && lang_hooks.can_use_bit_fields_p ())
+	   || TREE_CODE (arg0) == BIT_FIELD_REF)
+	  && (code == EQ_EXPR || code == NE_EXPR)
+	  /* Handle the constant case even without -O
+	     to make sure the warnings are given.  */
+	  && (optimize || TREE_CODE (arg1) == INTEGER_CST))
+	{
+	  t1 = optimize_bit_field_compare (code, type, arg0, arg1);
+	  if (t1)
+	    return t1;
+	}
+
+      /* If this is a comparison of complex values and either or both sides
+	 are a COMPLEX_EXPR or COMPLEX_CST, it is best to split up the
+	 comparisons and join them with a TRUTH_ANDIF_EXPR or TRUTH_ORIF_EXPR.
+	 This may prevent needless evaluations.  */
+      if ((code == EQ_EXPR || code == NE_EXPR)
+	  && TREE_CODE (TREE_TYPE (arg0)) == COMPLEX_TYPE
+	  && (TREE_CODE (arg0) == COMPLEX_EXPR
+	      || TREE_CODE (arg1) == COMPLEX_EXPR
+	      || TREE_CODE (arg0) == COMPLEX_CST
+	      || TREE_CODE (arg1) == COMPLEX_CST))
+	{
+	  tree subtype = TREE_TYPE (TREE_TYPE (arg0));
+	  tree real0, imag0, real1, imag1;
+
+	  arg0 = save_expr (arg0);
+	  arg1 = save_expr (arg1);
+	  real0 = fold (build1 (REALPART_EXPR, subtype, arg0));
+	  imag0 = fold (build1 (IMAGPART_EXPR, subtype, arg0));
+	  real1 = fold (build1 (REALPART_EXPR, subtype, arg1));
+	  imag1 = fold (build1 (IMAGPART_EXPR, subtype, arg1));
+
+	  return fold (build2 ((code == EQ_EXPR ? TRUTH_ANDIF_EXPR
+				: TRUTH_ORIF_EXPR),
+			       type,
+			       fold (build2 (code, type, real0, real1)),
+			       fold (build2 (code, type, imag0, imag1))));
+	}
+
+      /* Optimize comparisons of strlen vs zero to a compare of the
+	 first character of the string vs zero.  To wit,
+		strlen(ptr) == 0   =>  *ptr == 0
+		strlen(ptr) != 0   =>  *ptr != 0
+	 Other cases should reduce to one of these two (or a constant)
+	 due to the return value of strlen being unsigned.  */
+      if ((code == EQ_EXPR || code == NE_EXPR)
+	  && integer_zerop (arg1)
+	  && TREE_CODE (arg0) == CALL_EXPR)
+	{
+	  tree fndecl = get_callee_fndecl (arg0);
+	  tree arglist;
+
+	  if (fndecl
+	      && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
+	      && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_STRLEN
+	      && (arglist = TREE_OPERAND (arg0, 1))
+	      && TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) == POINTER_TYPE
+	      && ! TREE_CHAIN (arglist))
+	    return fold (build2 (code, type,
+				 build1 (INDIRECT_REF, char_type_node,
+					 TREE_VALUE (arglist)),
+				 fold_convert (char_type_node,
+					       integer_zero_node)));
+	}
+
+      /* We can fold X/C1 op C2 where C1 and C2 are integer constants
+	 into a single range test.  */
+      if ((TREE_CODE (arg0) == TRUNC_DIV_EXPR
+	   || TREE_CODE (arg0) == EXACT_DIV_EXPR)
+	  && TREE_CODE (arg1) == INTEGER_CST
+	  && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
+	  && !integer_zerop (TREE_OPERAND (arg0, 1))
+	  && !TREE_OVERFLOW (TREE_OPERAND (arg0, 1))
+	  && !TREE_OVERFLOW (arg1))
+	{
+	  t1 = fold_div_compare (code, type, arg0, arg1);
+	  if (t1 != NULL_TREE)
+	    return t1;
+	}
+
+      if ((code == EQ_EXPR || code == NE_EXPR)
+	  && !TREE_SIDE_EFFECTS (arg0)
+	  && integer_zerop (arg1)
+	  && tree_expr_nonzero_p (arg0))
+	return constant_boolean_node (code==NE_EXPR, type);
+
+      t1 = fold_relational_const (code, type, arg0, arg1);
+      return t1 == NULL_TREE ? t : t1;
+
+    case UNORDERED_EXPR:
+    case ORDERED_EXPR:
+    case UNLT_EXPR:
+    case UNLE_EXPR:
+    case UNGT_EXPR:
+    case UNGE_EXPR:
+    case UNEQ_EXPR:
+    case LTGT_EXPR:
+      if (TREE_CODE (arg0) == REAL_CST && TREE_CODE (arg1) == REAL_CST)
+	{
+	  t1 = fold_relational_const (code, type, arg0, arg1);
+	  if (t1 != NULL_TREE)
+	    return t1;
+	}
+
+      /* If the first operand is NaN, the result is constant.  */
+      if (TREE_CODE (arg0) == REAL_CST
+	  && REAL_VALUE_ISNAN (TREE_REAL_CST (arg0))
+	  && (code != LTGT_EXPR || ! flag_trapping_math))
+	{
+	  t1 = (code == ORDERED_EXPR || code == LTGT_EXPR)
+	       ? integer_zero_node
+	       : integer_one_node;
+	  return omit_one_operand (type, t1, arg1);
+	}
+
+      /* If the second operand is NaN, the result is constant.  */
+      if (TREE_CODE (arg1) == REAL_CST
+	  && REAL_VALUE_ISNAN (TREE_REAL_CST (arg1))
+	  && (code != LTGT_EXPR || ! flag_trapping_math))
+	{
+	  t1 = (code == ORDERED_EXPR || code == LTGT_EXPR)
+	       ? integer_zero_node
+	       : integer_one_node;
+	  return omit_one_operand (type, t1, arg0);
+	}
+
+      /* Simplify unordered comparison of something with itself.  */
+      if ((code == UNLE_EXPR || code == UNGE_EXPR || code == UNEQ_EXPR)
+	  && operand_equal_p (arg0, arg1, 0))
+	return constant_boolean_node (1, type);
+
+      if (code == LTGT_EXPR
+	  && !flag_trapping_math
+	  && operand_equal_p (arg0, arg1, 0))
+	return constant_boolean_node (0, type);
+
+      /* Fold (double)float1 CMP (double)float2 into float1 CMP float2.  */
+      {
+	tree targ0 = strip_float_extensions (arg0);
+	tree targ1 = strip_float_extensions (arg1);
+	tree newtype = TREE_TYPE (targ0);
+
+	if (TYPE_PRECISION (TREE_TYPE (targ1)) > TYPE_PRECISION (newtype))
+	  newtype = TREE_TYPE (targ1);
+
+	if (TYPE_PRECISION (newtype) < TYPE_PRECISION (TREE_TYPE (arg0)))
+	  return fold (build2 (code, type, fold_convert (newtype, targ0),
+			       fold_convert (newtype, targ1)));
+      }
+
+      return t;
+
+    case COMPOUND_EXPR:
+      /* When pedantic, a compound expression can be neither an lvalue
+	 nor an integer constant expression.  */
+      if (TREE_SIDE_EFFECTS (arg0) || TREE_CONSTANT (arg1))
+	return t;
+      /* Don't let (0, 0) be null pointer constant.  */
+      tem = integer_zerop (arg1) ? build1 (NOP_EXPR, type, arg1)
+				 : fold_convert (type, arg1);
+      return pedantic_non_lvalue (tem);
+
+    case COMPLEX_EXPR:
+      if (wins)
+	return build_complex (type, arg0, arg1);
+      return t;
+
+    default:
+      return t;
+    } /* switch (code) */
+}
+
 /* Fold a ternary expression EXPR.  Return the folded expression if
    folding is successful.  Otherwise, return the original
    expression.  */
@@ -7279,6 +9894,8 @@ fold (tree expr)
 	{
 	case 1:
 	  return fold_unary (expr);
+	case 2:
+	  return fold_binary (expr);
 	case 3:
 	  return fold_ternary (expr);
 	default:


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]