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] Move beef from simplify_comparison to simplify_relational_operation


Hi,

As an additional step towards unification of the RTL simplifiers,
Roger Sayle committed on March 9th his patch that provides a
fully functional simplify_relational_operation function, that is
able to perform simplifications of comparisons and is not limited
to finding tautologies. He did not fill simplify_relational_operation with any such transform, since the few that were already in simplify-rtx.c were left in simplify_gen_relational.


This patch redesigns that change in order to actually enable several
simplifications to be moved from combine's simplify_comparison
to simplify-rtx.c; many transforms there still use combine-specific
functions like nonzero_bits, but more than 500 lines of code are
moved, and having hookized gen_lowpart last February started to pay
off.  These transforms are in a separate function local to
simplify-rtx.c, simplify_relational_operation_1, which is only used
for non-CCmode relational operations.

The patch also enables the expander to use these transforms, in
particular in emit_store_flag, compare_from_rtx and
do_compare_rtx_and_jump.

Roger's simplify_const_relational_operation is modified to return
an int and then renamed (it does not fit the usual simplify_*
prototypes), since most of the time the result was simply checked
for being const0_rtx/const_true_rtx---and if not, the caller can be
updated to use the complete function simplify_relational_operation.
The result of this part of the folding is made available also to
users of simplify_relational_operation through an additional "int *"
argument.

Finally, I removed a place where fold transformed unsigned comparisons to signed. This is not appropriate in my opinion, because it causes the original semantics to be hidden at the tree level, which is especially important in tree-ssa (I implemented constant folding to create saturated minus and plus tree nodes, and this particular transform got in the way in the famous gzip case).

This was bootstrapped/regtested on i686-pc-linux-gnu. I'll ask for approval now. Though, I'd like to get more coverage, especially for cc0 targets (or a reviewer saying that this is not a problem?). Can anybody help?

2004-04-20 Paolo Bonzini <bonzini@gnu.org>

	* combine.c (combine_simplify_rtx): Adjust call to
	simplify_relational_operation.
	(simplify_set): simplify_relational_operation now
	may return another relational expression.  Do not
	use SELECT_CC_MODE when the LHS of a comparison is
	already a condition code.
	(gen_binary): Use simplify_gen_relational and
	simplify_gen_binary.
	(simplify_comparison): Remove code which is moved
	to simplify-rtx.c.
	* cse.c (fold_rtx): simplify_relational_operation now
	takes of computing the comparison mode.
	* dojump.c (compare_from_rtx): Use
	simplify_relational_operation, remove dead code.
	(do_compare_rtx_and_jump): Likewise.
	* expmed.c (emit_store_flag): Use simplify_relational_operation
	instead of hard-coding some simplifications.
	* fold-const.c (fold): Do not fold unsigned comparisons
	to signed.
	* integrate.c (subst_constants): simplify_relational_operation
	now takes care of FLOAT_STORE_FLAG_VALUE.
	* rtl.h (simplify_relational_operation): Adjust prototype.
	(relational_operation_const_result): New prototype.
	(simplify_const_relational_operation): Remove prototype.
	* simplify-rtx.c (relational_operation_const_result): New
	name of the old simplify_relational_operation.  Return an
	integer instead of an rtx.
	(simplify_gen_relational): Move most code to the new
	simplify_relational_operation and
	simplify_relational_operation_1.
	(simplify_relational_operation): Rewritten.
	(simplify_relational_operation_1): New function.
	(simplify_ternary_operation): simplify_relational_operation
         may return another relational expression.
	(simplify_rtx): Remove unnecessary temp variable.
	* unroll.c (simplify_cmp_and_jump_insns): Use
	relational_operation_const_result.



Index: combine.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/combine.c,v
retrieving revision 1.422
diff -u -r1.422 combine.c
--- combine.c	16 Mar 2004 16:14:50 -0000	1.422
+++ combine.c	26 Apr 2004 14:17:56 -0000
@@ -3738,7 +3738,7 @@
 	      cmp_mode = op0_mode;
 	  }
 	temp = simplify_relational_operation (code, mode, cmp_mode,
-					      XEXP (x, 0), XEXP (x, 1));
+	                                      XEXP (x, 0), XEXP (x, 1), NULL);
       }
       break;
     case RTX_COMM_ARITH:
@@ -4992,25 +4992,19 @@
       enum rtx_code old_code = GET_CODE (*cc_use);
       enum rtx_code new_code;
       rtx op0, op1, tmp;
-      int other_changed = 0;
+      int result, other_changed = 0;
+      enum machine_mode mode;
       enum machine_mode compare_mode = GET_MODE (dest);
-      enum machine_mode tmp_mode;
 
       if (GET_CODE (src) == COMPARE)
-	op0 = XEXP (src, 0), op1 = XEXP (src, 1);
+	op0 = XEXP (src, 0), op1 = XEXP (src, 1),
+	mode = GET_MODE (op0) != VOIDmode ? GET_MODE (op0) : GET_MODE (op1);
       else
-	op0 = src, op1 = const0_rtx;
+	op0 = src, op1 = const0_rtx, mode = GET_MODE (op0);
 
-      /* Check whether the comparison is known at compile time.  */
-      if (GET_MODE (op0) != VOIDmode)
-	tmp_mode = GET_MODE (op0);
-      else if (GET_MODE (op1) != VOIDmode)
-	tmp_mode = GET_MODE (op1);
-      else
-	tmp_mode = compare_mode;
-      tmp = simplify_const_relational_operation (old_code, tmp_mode,
-						 op0, op1);
-      if (tmp != NULL_RTX)
+      tmp = simplify_relational_operation (old_code, mode, VOIDmode,
+					   op0, op1, &result);
+      if (result != -1)
 	{
 	  rtx pat = PATTERN (other_insn);
 	  undobuf.other_insn = other_insn;
@@ -5029,14 +5023,25 @@
 	  SUBST (SET_SRC (x), pc_rtx);
 	  return x;
 	}
+      else if (tmp)
+        {
+          new_code = GET_CODE (tmp);
+          op0 = XEXP (tmp, 0);
+          op1 = XEXP (tmp, 1);
+        }
+      else
+        new_code = old_code;
 
       /* Simplify our comparison, if possible.  */
-      new_code = simplify_comparison (old_code, &op0, &op1);
+      new_code = simplify_comparison (new_code, &op0, &op1);
 
 #ifdef SELECT_CC_MODE
       /* If this machine has CC modes other than CCmode, check to see if we
 	 need to use a different CC mode here.  */
-      compare_mode = SELECT_CC_MODE (new_code, op0, op1);
+      if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_CC)
+	compare_mode = GET_MODE (op0);
+      else
+	compare_mode = SELECT_CC_MODE (new_code, op0, op1);
 
 #ifndef HAVE_cc0
       /* If the mode changed, we have to change SET_DEST, the mode in the
@@ -10102,7 +10107,6 @@
 static rtx
 gen_binary (enum rtx_code code, enum machine_mode mode, rtx op0, rtx op1)
 {
-  rtx result;
   rtx tem;
 
   if (GET_CODE (op0) == CLOBBER)
@@ -10110,47 +10114,30 @@
   else if (GET_CODE (op1) == CLOBBER)
     return op1;
   
-  if (GET_RTX_CLASS (code) == RTX_COMM_ARITH
-      && swap_commutative_operands_p (op0, op1))
-    tem = op0, op0 = op1, op1 = tem;
-
   if (GET_RTX_CLASS (code) == RTX_COMPARE
       || GET_RTX_CLASS (code) == RTX_COMM_COMPARE)
     {
       enum machine_mode op_mode = GET_MODE (op0);
 
-      /* Strip the COMPARE from (REL_OP (compare X Y) 0) to get
-	 just (REL_OP X Y).  */
-      if (GET_CODE (op0) == COMPARE && op1 == const0_rtx)
-	{
-	  op1 = XEXP (op0, 1);
-	  op0 = XEXP (op0, 0);
-	  op_mode = GET_MODE (op0);
-	}
-
       if (op_mode == VOIDmode)
 	op_mode = GET_MODE (op1);
-      result = simplify_relational_operation (code, mode, op_mode, op0, op1);
+      return simplify_gen_relational (code, mode, op_mode, op0, op1);
     }
-  else
-    result = simplify_binary_operation (code, mode, op0, op1);
-
-  if (result)
-    return result;
 
   /* Put complex operands first and constants second.  */
   if (GET_RTX_CLASS (code) == RTX_COMM_ARITH
       && swap_commutative_operands_p (op0, op1))
-    return gen_rtx_fmt_ee (code, mode, op1, op0);
+    tem = op0, op0 = op1, op1 = tem;
 
   /* If we are turning off bits already known off in OP0, we need not do
-     an AND.  */
-  else if (code == AND && GET_CODE (op1) == CONST_INT
-	   && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
-	   && (nonzero_bits (op0, mode) & ~INTVAL (op1)) == 0)
+     an AND.  TODO: We should hookize nonzero_bits so that this and
+     other transforms can be made in simplify-rtx.c.  */
+  if (code == AND && GET_CODE (op1) == CONST_INT
+      && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
+      && (nonzero_bits (op0, mode) & ~INTVAL (op1)) == 0)
     return op0;
-
-  return gen_rtx_fmt_ee (code, mode, op0, op1);
+   
+  return simplify_gen_binary (code, mode, op0, op1);
 }
 
 /* Simplify a comparison between *POP0 and *POP1 where CODE is the
@@ -10170,7 +10157,6 @@
   rtx op0 = *pop0;
   rtx op1 = *pop1;
   rtx tem, tem1;
-  int i;
   enum machine_mode mode, tmode;
 
   /* Try a few ways of applying the same transformation to both operands.  */
@@ -10376,145 +10362,17 @@
 	  op1 = const0_rtx, const_op = 0;
 	}
 
-      /* Do some canonicalizations based on the comparison code.  We prefer
-	 comparisons against zero and then prefer equality comparisons.
-	 If we can reduce the size of a constant, we will do that too.  */
-
-      switch (code)
-	{
-	case LT:
-	  /* < C is equivalent to <= (C - 1) */
-	  if (const_op > 0)
-	    {
-	      const_op -= 1;
-	      op1 = GEN_INT (const_op);
-	      code = LE;
-	      /* ... fall through to LE case below.  */
-	    }
-	  else
-	    break;
-
-	case LE:
-	  /* <= C is equivalent to < (C + 1); we do this for C < 0  */
-	  if (const_op < 0)
-	    {
-	      const_op += 1;
-	      op1 = GEN_INT (const_op);
-	      code = LT;
-	    }
-
-	  /* If we are doing a <= 0 comparison on a value known to have
-	     a zero sign bit, we can replace this with == 0.  */
-	  else if (const_op == 0
-		   && mode_width <= HOST_BITS_PER_WIDE_INT
-		   && (nonzero_bits (op0, mode)
-		       & ((HOST_WIDE_INT) 1 << (mode_width - 1))) == 0)
-	    code = EQ;
-	  break;
-
-	case GE:
-	  /* >= C is equivalent to > (C - 1).  */
-	  if (const_op > 0)
-	    {
-	      const_op -= 1;
-	      op1 = GEN_INT (const_op);
-	      code = GT;
-	      /* ... fall through to GT below.  */
-	    }
-	  else
-	    break;
-
-	case GT:
-	  /* > C is equivalent to >= (C + 1); we do this for C < 0.  */
-	  if (const_op < 0)
-	    {
-	      const_op += 1;
-	      op1 = GEN_INT (const_op);
-	      code = GE;
-	    }
-
-	  /* If we are doing a > 0 comparison on a value known to have
-	     a zero sign bit, we can replace this with != 0.  */
-	  else if (const_op == 0
-		   && mode_width <= HOST_BITS_PER_WIDE_INT
-		   && (nonzero_bits (op0, mode)
-		       & ((HOST_WIDE_INT) 1 << (mode_width - 1))) == 0)
-	    code = NE;
-	  break;
-
-	case LTU:
-	  /* < C is equivalent to <= (C - 1).  */
-	  if (const_op > 0)
-	    {
-	      const_op -= 1;
-	      op1 = GEN_INT (const_op);
-	      code = LEU;
-	      /* ... fall through ...  */
-	    }
-
-	  /* (unsigned) < 0x80000000 is equivalent to >= 0.  */
-	  else if ((mode_width <= HOST_BITS_PER_WIDE_INT)
-		   && (const_op == (HOST_WIDE_INT) 1 << (mode_width - 1)))
-	    {
-	      const_op = 0, op1 = const0_rtx;
-	      code = GE;
-	      break;
-	    }
-	  else
-	    break;
-
-	case LEU:
-	  /* unsigned <= 0 is equivalent to == 0 */
-	  if (const_op == 0)
-	    code = EQ;
-
-	  /* (unsigned) <= 0x7fffffff is equivalent to >= 0.  */
-	  else if ((mode_width <= HOST_BITS_PER_WIDE_INT)
-		   && (const_op == ((HOST_WIDE_INT) 1 << (mode_width - 1)) - 1))
-	    {
-	      const_op = 0, op1 = const0_rtx;
-	      code = GE;
-	    }
-	  break;
-
-	case GEU:
-	  /* >= C is equivalent to < (C - 1).  */
-	  if (const_op > 1)
-	    {
-	      const_op -= 1;
-	      op1 = GEN_INT (const_op);
-	      code = GTU;
-	      /* ... fall through ...  */
-	    }
-
-	  /* (unsigned) >= 0x80000000 is equivalent to < 0.  */
-	  else if ((mode_width <= HOST_BITS_PER_WIDE_INT)
-		   && (const_op == (HOST_WIDE_INT) 1 << (mode_width - 1)))
-	    {
-	      const_op = 0, op1 = const0_rtx;
-	      code = LT;
-	      break;
-	    }
-	  else
-	    break;
-
-	case GTU:
-	  /* unsigned > 0 is equivalent to != 0 */
-	  if (const_op == 0)
-	    code = NE;
-
-	  /* (unsigned) > 0x7fffffff is equivalent to < 0.  */
-	  else if ((mode_width <= HOST_BITS_PER_WIDE_INT)
-		   && (const_op == ((HOST_WIDE_INT) 1 << (mode_width - 1)) - 1))
-	    {
-	      const_op = 0, op1 = const0_rtx;
-	      code = LT;
-	    }
-	  break;
-
-	default:
-	  break;
-	}
+       /* If we are doing a <= 0 comparison on a value known to have
+          a zero sign bit, we can replace this with == 0.  Similarly,
+          if we are doing a > 0 comparison on a value known to have
+          a zero sign bit, we can replace this with != 0.  */
+
+       if (const_op == 0
+           && (code == LE || code == GT)
+           && mode_width <= HOST_BITS_PER_WIDE_INT
+           && (nonzero_bits (op0, mode)
+               & ((HOST_WIDE_INT) 1 << (mode_width - 1))) == 0)
+         code = (code == LE) ? EQ : NE;
 
       /* Compute some predicates to simplify code below.  */
 
@@ -10539,42 +10397,6 @@
       switch (GET_CODE (op0))
 	{
 	case ZERO_EXTRACT:
-	  /* If we are extracting a single bit from a variable position in
-	     a constant that has only a single bit set and are comparing it
-	     with zero, we can convert this into an equality comparison
-	     between the position and the location of the single bit.  */
-	  /* Except we can't if SHIFT_COUNT_TRUNCATED is set, since we might
-	     have already reduced the shift count modulo the word size.  */
-	  if (!SHIFT_COUNT_TRUNCATED
-	      && GET_CODE (XEXP (op0, 0)) == CONST_INT
-	      && XEXP (op0, 1) == const1_rtx
-	      && equality_comparison_p && const_op == 0
-	      && (i = exact_log2 (INTVAL (XEXP (op0, 0)))) >= 0)
-	    {
-	      if (BITS_BIG_ENDIAN)
-		{
-		  enum machine_mode new_mode
-		    = mode_for_extraction (EP_extzv, 1);
-		  if (new_mode == MAX_MACHINE_MODE)
-		    i = BITS_PER_WORD - 1 - i;
-		  else
-		    {
-		      mode = new_mode;
-		      i = (GET_MODE_BITSIZE (mode) - 1 - i);
-		    }
-		}
-
-	      op0 = XEXP (op0, 2);
-	      op1 = GEN_INT (i);
-	      const_op = i;
-
-	      /* Result is nonzero iff shift count is equal to I.  */
-	      code = reverse_condition (code);
-	      continue;
-	    }
-
-	  /* ... fall through ...  */
-
 	case SIGN_EXTRACT:
 	  tem = expand_compound_operation (op0);
 	  if (tem != op0)
@@ -10584,37 +10406,8 @@
 	    }
 	  break;
 
-	case NOT:
-	  /* If testing for equality, we can take the NOT of the constant.  */
-	  if (equality_comparison_p
-	      && (tem = simplify_unary_operation (NOT, mode, op1, mode)) != 0)
-	    {
-	      op0 = XEXP (op0, 0);
-	      op1 = tem;
-	      continue;
-	    }
-
-	  /* If just looking at the sign bit, reverse the sense of the
-	     comparison.  */
-	  if (sign_bit_comparison_p)
-	    {
-	      op0 = XEXP (op0, 0);
-	      code = (code == GE ? LT : GE);
-	      continue;
-	    }
-	  break;
-
 	case NEG:
-	  /* If testing for equality, we can take the NEG of the constant.  */
-	  if (equality_comparison_p
-	      && (tem = simplify_unary_operation (NEG, mode, op1, mode)) != 0)
-	    {
-	      op0 = XEXP (op0, 0);
-	      op1 = tem;
-	      continue;
-	    }
-
-	  /* The remaining cases only apply to comparisons with zero.  */
+	  /* These cases only apply to comparisons with zero.  */
 	  if (const_op != 0)
 	    break;
 
@@ -10643,17 +10436,6 @@
 	  break;
 
 	case ROTATE:
-	  /* If we are testing equality and our count is a constant, we
-	     can perform the inverse operation on our RHS.  */
-	  if (equality_comparison_p && GET_CODE (XEXP (op0, 1)) == CONST_INT
-	      && (tem = simplify_binary_operation (ROTATERT, mode,
-						   op1, XEXP (op0, 1))) != 0)
-	    {
-	      op0 = XEXP (op0, 0);
-	      op1 = tem;
-	      continue;
-	    }
-
 	  /* If we are doing a < 0 or >= 0 comparison, it means we are testing
 	     a particular bit.  Convert it to an AND of a constant of that
 	     bit.  This will be converted into a ZERO_EXTRACT.  */
@@ -10669,15 +10451,6 @@
 	      continue;
 	    }
 
-	  /* Fall through.  */
-
-	case ABS:
-	  /* ABS is ignorable inside an equality comparison with zero.  */
-	  if (const_op == 0 && equality_comparison_p)
-	    {
-	      op0 = XEXP (op0, 0);
-	      continue;
-	    }
 	  break;
 
 	case SIGN_EXTEND:
@@ -10750,84 +10523,6 @@
 	    }
 	  break;
 
-	case PLUS:
-	  /* (eq (plus X A) B) -> (eq X (minus B A)).  We can only do
-	     this for equality comparisons due to pathological cases involving
-	     overflows.  */
-	  if (equality_comparison_p
-	      && 0 != (tem = simplify_binary_operation (MINUS, mode,
-							op1, XEXP (op0, 1))))
-	    {
-	      op0 = XEXP (op0, 0);
-	      op1 = tem;
-	      continue;
-	    }
-
-	  /* (plus (abs X) (const_int -1)) is < 0 if and only if X == 0.  */
-	  if (const_op == 0 && XEXP (op0, 1) == constm1_rtx
-	      && GET_CODE (XEXP (op0, 0)) == ABS && sign_bit_comparison_p)
-	    {
-	      op0 = XEXP (XEXP (op0, 0), 0);
-	      code = (code == LT ? EQ : NE);
-	      continue;
-	    }
-	  break;
-
-	case MINUS:
-	  /* We used to optimize signed comparisons against zero, but that
-	     was incorrect.  Unsigned comparisons against zero (GTU, LEU)
-	     arrive here as equality comparisons, or (GEU, LTU) are
-	     optimized away.  No need to special-case them.  */
-
-	  /* (eq (minus A B) C) -> (eq A (plus B C)) or
-	     (eq B (minus A C)), whichever simplifies.  We can only do
-	     this for equality comparisons due to pathological cases involving
-	     overflows.  */
-	  if (equality_comparison_p
-	      && 0 != (tem = simplify_binary_operation (PLUS, mode,
-							XEXP (op0, 1), op1)))
-	    {
-	      op0 = XEXP (op0, 0);
-	      op1 = tem;
-	      continue;
-	    }
-
-	  if (equality_comparison_p
-	      && 0 != (tem = simplify_binary_operation (MINUS, mode,
-							XEXP (op0, 0), op1)))
-	    {
-	      op0 = XEXP (op0, 1);
-	      op1 = tem;
-	      continue;
-	    }
-
-	  /* The sign bit of (minus (ashiftrt X C) X), where C is the number
-	     of bits in X minus 1, is one iff X > 0.  */
-	  if (sign_bit_comparison_p && GET_CODE (XEXP (op0, 0)) == ASHIFTRT
-	      && GET_CODE (XEXP (XEXP (op0, 0), 1)) == CONST_INT
-	      && (unsigned HOST_WIDE_INT) INTVAL (XEXP (XEXP (op0, 0), 1))
-		 == mode_width - 1
-	      && rtx_equal_p (XEXP (XEXP (op0, 0), 0), XEXP (op0, 1)))
-	    {
-	      op0 = XEXP (op0, 1);
-	      code = (code == GE ? LE : GT);
-	      continue;
-	    }
-	  break;
-
-	case XOR:
-	  /* (eq (xor A B) C) -> (eq A (xor B C)).  This is a simplification
-	     if C is zero or B is a constant.  */
-	  if (equality_comparison_p
-	      && 0 != (tem = simplify_binary_operation (XOR, mode,
-							XEXP (op0, 1), op1)))
-	    {
-	      op0 = XEXP (op0, 0);
-	      op1 = tem;
-	      continue;
-	    }
-	  break;
-
 	case EQ:  case NE:
 	case UNEQ:  case LTGT:
 	case LT:  case LTU:  case UNLT:  case LE:  case LEU:  case UNLE:
@@ -10872,19 +10567,6 @@
 	    }
 	  break;
 
-	case IOR:
-	  /* The sign bit of (ior (plus X (const_int -1)) X) is nonzero
-	     iff X <= 0.  */
-	  if (sign_bit_comparison_p && GET_CODE (XEXP (op0, 0)) == PLUS
-	      && XEXP (XEXP (op0, 0), 1) == constm1_rtx
-	      && rtx_equal_p (XEXP (XEXP (op0, 0), 0), XEXP (op0, 1)))
-	    {
-	      op0 = XEXP (op0, 1);
-	      code = (code == GE ? GT : LE);
-	      continue;
-	    }
-	  break;
-
 	case AND:
 	  /* Convert (and (xshift 1 X) Y) to (and (lshiftrt Y X) 1).  This
 	     will be converted to a ZERO_EXTRACT later.  */
@@ -10923,37 +10605,6 @@
 		}
 	    }
 
-	  /* If we are doing an equality comparison of an AND of a bit equal
-	     to the sign bit, replace this with a LT or GE comparison of
-	     the underlying value.  */
-	  if (equality_comparison_p
-	      && const_op == 0
-	      && GET_CODE (XEXP (op0, 1)) == CONST_INT
-	      && mode_width <= HOST_BITS_PER_WIDE_INT
-	      && ((INTVAL (XEXP (op0, 1)) & GET_MODE_MASK (mode))
-		  == (unsigned HOST_WIDE_INT) 1 << (mode_width - 1)))
-	    {
-	      op0 = XEXP (op0, 0);
-	      code = (code == EQ ? GE : LT);
-	      continue;
-	    }
-
-	  /* If this AND operation is really a ZERO_EXTEND from a narrower
-	     mode, the constant fits within that mode, and this is either an
-	     equality or unsigned comparison, try to do this comparison in
-	     the narrower mode.  */
-	  if ((equality_comparison_p || unsigned_comparison_p)
-	      && GET_CODE (XEXP (op0, 1)) == CONST_INT
-	      && (i = exact_log2 ((INTVAL (XEXP (op0, 1))
-				   & GET_MODE_MASK (mode))
-				  + 1)) >= 0
-	      && const_op >> i == 0
-	      && (tmode = mode_for_size (i, MODE_INT, 1)) != BLKmode)
-	    {
-	      op0 = gen_lowpart (tmode, XEXP (op0, 0));
-	      continue;
-	    }
-
 	  /* If this is (and:M1 (subreg:M2 X 0) (const_int C1)) where C1
 	     fits in both M1 and M2 and the SUBREG is either paradoxical
 	     or represents the low part, permute the SUBREG and the AND
@@ -11100,22 +10751,6 @@
 	      continue;
 	    }
 
-	  /* If OP0 is a sign extension and CODE is not an unsigned comparison,
-	     do the comparison in a narrower mode.  */
-	  if (! unsigned_comparison_p
-	      && GET_CODE (XEXP (op0, 1)) == CONST_INT
-	      && GET_CODE (XEXP (op0, 0)) == ASHIFT
-	      && XEXP (op0, 1) == XEXP (XEXP (op0, 0), 1)
-	      && (tmode = mode_for_size (mode_width - INTVAL (XEXP (op0, 1)),
-					 MODE_INT, 1)) != BLKmode
-	      && (((unsigned HOST_WIDE_INT) const_op
-		   + (GET_MODE_MASK (tmode) >> 1) + 1)
-		  <= GET_MODE_MASK (tmode)))
-	    {
-	      op0 = gen_lowpart (tmode, XEXP (XEXP (op0, 0), 0));
-	      continue;
-	    }
-
 	  /* Likewise if OP0 is a PLUS of a sign extension with a
 	     constant, which is usually represented with the PLUS
 	     between the shifts.  */
@@ -11169,19 +10804,6 @@
 	      const_op <<= INTVAL (XEXP (op0, 1));
 	      op1 = GEN_INT (const_op);
 	      op0 = XEXP (op0, 0);
-	      continue;
-	    }
-
-	  /* If we are using this shift to extract just the sign bit, we
-	     can replace this with an LT or GE comparison.  */
-	  if (const_op == 0
-	      && (equality_comparison_p || sign_bit_comparison_p)
-	      && GET_CODE (XEXP (op0, 1)) == CONST_INT
-	      && (unsigned HOST_WIDE_INT) INTVAL (XEXP (op0, 1))
-		 == mode_width - 1)
-	    {
-	      op0 = XEXP (op0, 0);
-	      code = (code == NE || code == GT ? LT : GE);
 	      continue;
 	    }
 	  break;
Index: cse.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cse.c,v
retrieving revision 1.298
diff -u -r1.298 cse.c
--- cse.c	4 Apr 2004 21:44:41 -0000	1.298
+++ cse.c	26 Apr 2004 14:17:56 -0000
@@ -3924,21 +3924,12 @@
 	    }
 	}
 
-      new = simplify_relational_operation (code, mode,
-					   (mode_arg0 != VOIDmode
-					    ? mode_arg0
-					    : (GET_MODE (const_arg0
-							 ? const_arg0
-							 : folded_arg0)
-					       != VOIDmode)
-					    ? GET_MODE (const_arg0
-							? const_arg0
-							: folded_arg0)
-					    : GET_MODE (const_arg1
-							? const_arg1
-							: folded_arg1)),
-					   const_arg0 ? const_arg0 : folded_arg0,
-					   const_arg1 ? const_arg1 : folded_arg1);
+      {
+	rtx op0 = const_arg0 ? const_arg0 : folded_arg0;
+	rtx op1 = const_arg1 ? const_arg1 : folded_arg1;
+        new = simplify_relational_operation (code, mode, mode_arg0,
+					     op0, op1, NULL);
+      }
       break;
 
     case RTX_BIN_ARITH:
Index: dojump.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/dojump.c,v
retrieving revision 1.15
diff -u -r1.15 dojump.c
--- dojump.c	1 Apr 2004 03:50:28 -0000	1.15
+++ dojump.c	26 Apr 2004 14:17:56 -0000
@@ -820,7 +820,7 @@
 compare_from_rtx (rtx op0, rtx op1, enum rtx_code code, int unsignedp,
 		  enum machine_mode mode, rtx size)
 {
-  enum rtx_code ucode;
+  int result;
   rtx tem;
 
   /* If one operand is constant, make it the second one.  Only do this
@@ -842,32 +842,19 @@
 
   do_pending_stack_adjust ();
 
-  ucode = unsignedp ? unsigned_condition (code) : code;
-  tem = simplify_const_relational_operation (ucode, mode, op0, op1);
-  if (tem != 0)
-    return tem;
-
-#if 0
-  /* There's no need to do this now that combine.c can eliminate lots of
-     sign extensions.  This can be less efficient in certain cases on other
-     machines.  */
-
-  /* If this is a signed equality comparison, we can do it as an
-     unsigned comparison since zero-extension is cheaper than sign
-     extension and comparisons with zero are done as unsigned.  This is
-     the case even on machines that can do fast sign extension, since
-     zero-extension is easier to combine with other operations than
-     sign-extension is.  If we are comparing against a constant, we must
-     convert it to what it would look like unsigned.  */
-  if ((code == EQ || code == NE) && ! unsignedp
-      && GET_MODE_BITSIZE (GET_MODE (op0)) <= HOST_BITS_PER_WIDE_INT)
-    {
-      if (GET_CODE (op1) == CONST_INT
-          && (INTVAL (op1) & GET_MODE_MASK (GET_MODE (op0))) != INTVAL (op1))
-        op1 = GEN_INT (INTVAL (op1) & GET_MODE_MASK (GET_MODE (op0)));
-      unsignedp = 1;
+  code = unsignedp ? unsigned_condition (code) : code;
+  if (0 != (tem = simplify_relational_operation (code, mode, VOIDmode,
+						 op0, op1, &result)))
+    {
+      if (result != -1)
+	return tem;
+
+      code = GET_CODE (tem);
+      mode = GET_MODE (tem);
+      op0 = XEXP (tem, 0);
+      op1 = XEXP (tem, 1);
+      unsignedp = (code == GTU || code == LTU || code == GEU || code == LEU);
     }
-#endif
 
   emit_cmp_insn (op0, op1, code, size, mode, unsignedp);
 
@@ -889,9 +876,9 @@
 			 enum machine_mode mode, rtx size, rtx if_false_label,
 			 rtx if_true_label)
 {
-  enum rtx_code ucode;
   rtx tem;
   int dummy_true_label = 0;
+  int result;
 
   /* Reverse the comparison if that is safe and we want to jump if it is
      false.  */
@@ -921,44 +908,29 @@
 
   do_pending_stack_adjust ();
 
-  ucode = unsignedp ? unsigned_condition (code) : code;
-  tem = simplify_const_relational_operation (ucode, mode, op0, op1);
-  if (tem != 0)
+  code = unsignedp ? unsigned_condition (code) : code;
+  if ((tem = simplify_relational_operation (code, mode, VOIDmode,
+					    op0, op1, &result)) != 0)
     {
-      if (tem == const_true_rtx)
+      if (result == 1)
         {
           if (if_true_label)
             emit_jump (if_true_label);
+	  return;
         }
-      else
+      else if (result == 0)
         {
           if (if_false_label)
             emit_jump (if_false_label);
+	  return;
         }
-      return;
-    }
 
-#if 0
-  /* There's no need to do this now that combine.c can eliminate lots of
-     sign extensions.  This can be less efficient in certain cases on other
-     machines.  */
-
-  /* If this is a signed equality comparison, we can do it as an
-     unsigned comparison since zero-extension is cheaper than sign
-     extension and comparisons with zero are done as unsigned.  This is
-     the case even on machines that can do fast sign extension, since
-     zero-extension is easier to combine with other operations than
-     sign-extension is.  If we are comparing against a constant, we must
-     convert it to what it would look like unsigned.  */
-  if ((code == EQ || code == NE) && ! unsignedp
-      && GET_MODE_BITSIZE (GET_MODE (op0)) <= HOST_BITS_PER_WIDE_INT)
-    {
-      if (GET_CODE (op1) == CONST_INT
-          && (INTVAL (op1) & GET_MODE_MASK (GET_MODE (op0))) != INTVAL (op1))
-        op1 = GEN_INT (INTVAL (op1) & GET_MODE_MASK (GET_MODE (op0)));
-      unsignedp = 1;
+      code = GET_CODE (tem);
+      mode = GET_MODE (tem);
+      op0 = XEXP (tem, 0);
+      op1 = XEXP (tem, 1);
+      unsignedp = (code == GTU || code == LTU || code == GEU || code == LEU);
     }
-#endif
 
   if (! if_true_label)
     {
Index: expmed.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/expmed.c,v
retrieving revision 1.158
diff -u -r1.158 expmed.c
--- expmed.c	24 Apr 2004 01:03:11 -0000	1.158
+++ expmed.c	26 Apr 2004 14:17:57 -0000
@@ -4395,6 +4395,7 @@
   enum insn_code icode;
   enum machine_mode compare_mode;
   enum machine_mode target_mode = GET_MODE (target);
+  int result;
   rtx tem;
   rtx last = get_last_insn ();
   rtx pattern, comparison;
@@ -4420,38 +4421,18 @@
   if (mode == VOIDmode)
     mode = GET_MODE (op0);
 
-  /* For some comparisons with 1 and -1, we can convert this to
-     comparisons with zero.  This will often produce more opportunities for
-     store-flag insns.  */
-
-  switch (code)
+  if (0 != (tem = simplify_relational_operation (code, mode, VOIDmode,	
+						 op0, op1, &result)))
     {
-    case LT:
-      if (op1 == const1_rtx)
-	op1 = const0_rtx, code = LE;
-      break;
-    case LE:
-      if (op1 == constm1_rtx)
-	op1 = const0_rtx, code = LT;
-      break;
-    case GE:
-      if (op1 == const1_rtx)
-	op1 = const0_rtx, code = GT;
-      break;
-    case GT:
-      if (op1 == constm1_rtx)
-	op1 = const0_rtx, code = GE;
-      break;
-    case GEU:
-      if (op1 == const1_rtx)
-	op1 = const0_rtx, code = NE;
-      break;
-    case LTU:
-      if (op1 == const1_rtx)
-	op1 = const0_rtx, code = EQ;
-      break;
-    default:
-      break;
+      if (result != -1)
+	{
+	  emit_move_insn (target, tem);
+	  return target;
+        }
+
+      code = GET_CODE (tem);
+      op0 = XEXP (tem, 0);
+      op1 = XEXP (tem, 1);
     }
 
   /* If we are comparing a double-word integer with zero, we can convert
Index: fold-const.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fold-const.c,v
retrieving revision 1.370
diff -u -r1.370 fold-const.c
--- fold-const.c	26 Apr 2004 03:43:17 -0000	1.370
+++ fold-const.c	26 Apr 2004 14:17:57 -0000
@@ -7465,26 +7465,6 @@
 		default:
 		  break;
 		}
-
-	    else if (TREE_INT_CST_HIGH (arg1) == 0
-		     && TREE_INT_CST_LOW (arg1) == signed_max
-		     && 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
-		      (build (code == LE_EXPR ? GE_EXPR: LT_EXPR,
-			      type, fold_convert (st0, arg0),
-			      fold_convert (st1, integer_zero_node)));
-		  }
-	      }
 	  }
       }
 
Index: integrate.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/integrate.c,v
retrieving revision 1.254
diff -u -r1.254 integrate.c
--- integrate.c	1 Apr 2004 03:50:29 -0000	1.254
+++ integrate.c	26 Apr 2004 14:17:58 -0000
@@ -2738,8 +2738,10 @@
 
 	  if (op_mode == VOIDmode)
 	    op_mode = GET_MODE (XEXP (x, 1));
-	  new = simplify_relational_operation (code, GET_MODE (x), op_mode,
-					       XEXP (x, 0), XEXP (x, 1));
+
+	  new = simplify_relational_operation (code, op_mode, GET_MODE (x),
+					       XEXP (x, 0), XEXP (x, 1),
+					       NULL);
 	  break;
 	}
 
@@ -2766,16 +2768,22 @@
 	      {
 		/* We have compare of two VOIDmode constants for which
 		   we recorded the comparison mode.  */
-		rtx temp =
-		  simplify_const_relational_operation (GET_CODE (op0),
-						       map->compare_mode,
-						       XEXP (op0, 0),
-						       XEXP (op0, 1));
+		int result;
+		rtx tem =
+		  simplify_relational_operation (GET_CODE (op0),
+						 GET_MODE (op0),
+						 map->compare_mode,
+						 XEXP (op0, 0),
+						 XEXP (op0, 1),
+						 &result);
 
-		if (temp == const0_rtx)
+		if (result == 0)
 		  new = XEXP (x, 2);
-		else if (temp == const1_rtx)
+		else if (result == 1)
 		  new = XEXP (x, 1);
+		else
+		  new = simplify_ternary_operation (code, GET_MODE (x), op0_mode,
+						    tem, XEXP (x, 1), XEXP (x, 2));
 	      }
 	  }
 	if (!new)
Index: rtl.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/rtl.h,v
retrieving revision 1.469
diff -u -r1.469 rtl.h
--- rtl.h	20 Apr 2004 03:57:57 -0000	1.469
+++ rtl.h	26 Apr 2004 14:17:58 -0000
@@ -1764,10 +1764,10 @@
 				      rtx);
 extern rtx simplify_ternary_operation (enum rtx_code, enum machine_mode,
 				       enum machine_mode, rtx, rtx, rtx);
-extern rtx simplify_const_relational_operation (enum rtx_code,
-						enum machine_mode, rtx, rtx);
+extern int relational_operation_const_result (enum rtx_code,
+					      enum machine_mode, rtx, rtx);
 extern rtx simplify_relational_operation (enum rtx_code, enum machine_mode,
-					  enum machine_mode, rtx, rtx);
+					  enum machine_mode, rtx, rtx, int *);
 extern rtx simplify_gen_binary (enum rtx_code, enum machine_mode, rtx, rtx);
 extern rtx simplify_gen_unary (enum rtx_code, enum machine_mode, rtx,
 			       enum machine_mode);
Index: simplify-rtx.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/simplify-rtx.c,v
retrieving revision 1.187
diff -u -r1.187 simplify-rtx.c
--- simplify-rtx.c	12 Apr 2004 17:28:11 -0000	1.187
+++ simplify-rtx.c	26 Apr 2004 14:17:58 -0000
@@ -58,6 +58,8 @@
 				  unsigned int);
 static rtx simplify_associative_operation (enum rtx_code, enum machine_mode,
 					   rtx, rtx);
+static rtx simplify_relational_operation_1 (enum rtx_code, enum machine_mode,
+					    enum machine_mode, rtx, rtx);
 
 /* Negate a CONST_INT rtx, truncating (because a conversion from a
    maximally negative number can overflow).  */
@@ -221,10 +223,9 @@
 
   return gen_rtx_fmt_eee (code, mode, op0, op1, op2);
 }
-
+
 /* Likewise, for relational operations.
-   CMP_MODE specifies mode comparison is done in.
-  */
+   CMP_MODE specifies mode comparison is done in.  */
 
 rtx
 simplify_gen_relational (enum rtx_code code, enum machine_mode mode,
@@ -232,46 +233,9 @@
 {
   rtx tem;
 
-  if (cmp_mode == VOIDmode)
-    cmp_mode = GET_MODE (op0);
-  if (cmp_mode == VOIDmode)
-    cmp_mode = GET_MODE (op1);
-
-  if (cmp_mode != VOIDmode)
-    {
-      tem = simplify_relational_operation (code, mode, cmp_mode, op0, op1);
-      if (tem)
-	return tem;
-    }
-
-  /* For the following tests, ensure const0_rtx is op1.  */
-  if (swap_commutative_operands_p (op0, op1)
-      || (op0 == const0_rtx && op1 != const0_rtx))
-    tem = op0, op0 = op1, op1 = tem, code = swap_condition (code);
-
-  /* If op0 is a compare, extract the comparison arguments from it.  */
-  if (GET_CODE (op0) == COMPARE && op1 == const0_rtx)
-    return simplify_gen_relational (code, mode, VOIDmode,
-				    XEXP (op0, 0), XEXP (op0, 1));
-
-  /* If op0 is a comparison, extract the comparison arguments form it.  */
-  if (COMPARISON_P (op0) && op1 == const0_rtx)
-    {
-      if (code == NE)
-	{
-	  if (GET_MODE (op0) == mode)
-	    return op0;
-	  return simplify_gen_relational (GET_CODE (op0), mode, VOIDmode,
-					  XEXP (op0, 0), XEXP (op0, 1));
-	}
-      else if (code == EQ)
-	{
-	  enum rtx_code new = reversed_comparison_code (op0, NULL_RTX);
-	  if (new != UNKNOWN)
-	    return simplify_gen_relational (new, mode, VOIDmode,
-					    XEXP (op0, 0), XEXP (op0, 1));
-        }
-    }
+  if (0 != (tem = simplify_relational_operation (code, mode, cmp_mode,
+						 op0, op1, NULL)))
+    return tem;
 
   return gen_rtx_fmt_ee (code, mode, op0, op1);
 }
@@ -1201,7 +1165,6 @@
 
    Don't use this for relational operations such as EQ or LT.
    Use simplify_relational_operation instead.  */
-
 rtx
 simplify_binary_operation (enum rtx_code code, enum machine_mode mode,
 			   rtx op0, rtx op1)
@@ -2662,17 +2625,542 @@
 }
 
 /* Like simplify_binary_operation except used for relational operators.
-   MODE is the mode of the operands, not that of the result.  If MODE
-   is VOIDmode, both operands must also be VOIDmode and we compare the
-   operands in "infinite precision".
+   MODE is the mode of the result. If MODE is VOIDmode, both operands must
+   also be VOIDmode.
 
-   If no simplification is possible, this function returns zero.
-   Otherwise, it returns either const_true_rtx or const0_rtx.  */
+   CMP_MODE specifies in which mode the comparison is done in, so it is
+   the mode of the operands.  If CMP_MODE is VOIDmode, it is taken from
+   the operands or, if both are VOIDmode, the operands are compared in
+   "infinite precision".  */
+rtx
+simplify_relational_operation (enum rtx_code code, enum machine_mode mode,
+			       enum machine_mode cmp_mode, rtx op0, rtx op1,
+			       int *result)
+{
+  rtx tem, trueop0, trueop1;
+  int constval;
 
+  if (cmp_mode == VOIDmode)
+    cmp_mode = GET_MODE (op0);
+  if (cmp_mode == VOIDmode)
+    cmp_mode = GET_MODE (op1);
+
+  constval = relational_operation_const_result (code, cmp_mode, op0, op1);
+  if (result)
+    *result = constval;
+  if (constval == 0)
+    {
+#ifdef FLOAT_STORE_FLAG_VALUE
+      if (GET_MODE_CLASS (mode) == MODE_FLOAT)
+        return CONST0_RTX (mode);
+#endif
+      return const0_rtx;
+    }
+  else if (constval == 1)
+    {
+#ifdef FLOAT_STORE_FLAG_VALUE
+      if (GET_MODE_CLASS (mode) == MODE_FLOAT)
+	{
+	  REAL_VALUE_TYPE val;
+	  val = FLOAT_STORE_FLAG_VALUE (mode);
+	  return CONST_DOUBLE_FROM_REAL_VALUE (val, mode);
+	}
+#endif
+      return const_true_rtx;
+    }
+
+  /* For the following tests, ensure const0_rtx is op1.  */
+  if (swap_commutative_operands_p (op0, op1)
+      || (op0 == const0_rtx && op1 != const0_rtx))
+    tem = op0, op0 = op1, op1 = tem, code = swap_condition (code);
+
+  /* If op0 is a compare, extract the comparison arguments from it.  */
+  if (GET_CODE (op0) == COMPARE && op1 == const0_rtx)
+    return simplify_relational_operation (code, mode, VOIDmode,
+				          XEXP (op0, 0), XEXP (op0, 1),
+					  result);
+
+  if (mode == VOIDmode
+      || GET_MODE_CLASS (cmp_mode) == MODE_CC
+      || CC0_P (op0))
+    return NULL_RTX;
+
+  trueop0 = avoid_constant_pool_reference (op0);
+  trueop1 = avoid_constant_pool_reference (op1);
+  return simplify_relational_operation_1 (code, mode, cmp_mode, trueop0, trueop1);
+}
+
+/* This part of simplify_relational_operation is only used when CMP_MODE
+   is not in class MODE_CC (i.e. it is a real comparison).
+
+   MODE is the mode of the result, while CMP_MODE specifies in which
+   mode the comparison is done in, so it is the mode of the operands.  */
 rtx
-simplify_const_relational_operation (enum rtx_code code,
-				     enum machine_mode mode,
-				     rtx op0, rtx op1)
+simplify_relational_operation_1 (enum rtx_code code, enum machine_mode mode,
+				 enum machine_mode cmp_mode, rtx op0, rtx op1)
+{
+  enum machine_mode tmode;
+  int changed = 0;
+  rtx tem;
+
+  /* Do some canonicalizations based on the comparison code.  We prefer
+     comparisons against zero and then prefer equality comparisons.
+     If we can reduce the size of a constant, we will do that too.  */
+
+  while (GET_CODE (op1) == CONST_INT)
+    {
+      HOST_WIDE_INT const_op;
+      unsigned int mode_width = GET_MODE_BITSIZE (cmp_mode);
+      int equality_comparison_p;
+      int sign_bit_comparison_p;
+      int unsigned_comparison_p;
+      int i;
+
+      /* Get the constant we are comparing against and turn off all bits
+	 not on in our mode.  */
+      const_op = INTVAL (op1);
+      if (cmp_mode != VOIDmode)
+	const_op = trunc_int_for_mode (const_op, cmp_mode);
+      op1 = GEN_INT (const_op);
+
+      switch (code)
+	{
+	case LT:
+	  /* < C is equivalent to <= (C - 1) */
+	  if (const_op > 0)
+	    {
+	      changed = 1;
+	      const_op--;
+	      op1 = GEN_INT (const_op);
+	      code = LE;
+	    }
+	  break;
+
+	case LE:
+	  /* <= C is equivalent to < (C + 1); we do this for C < 0  */
+	  if (const_op < 0)
+	    {
+	      changed = 1;
+	      const_op++;
+	      op1 = GEN_INT (const_op);
+	      code = LT;
+	    }
+	  break;
+
+	case GE:
+	  /* >= C is equivalent to > (C - 1).  */
+	  if (const_op > 0)
+	    {
+	      changed = 1;
+	      const_op--;
+	      op1 = GEN_INT (const_op);
+	      code = GT;
+	    }
+	  break;
+
+	case GT:
+	  /* > C is equivalent to >= (C + 1); we do this for C < 0.  */
+	  if (const_op < 0)
+	    {
+	      changed = 1;
+	      const_op++;
+	      op1 = GEN_INT (const_op);
+	      code = GE;
+	    }
+	  break;
+
+	case LTU:
+	  /* (unsigned) < 0x80000000 is equivalent to >= 0.  */
+	  if ((mode_width <= HOST_BITS_PER_WIDE_INT)
+	           && (const_op == (HOST_WIDE_INT) 1 << (mode_width - 1)))
+	    {
+	      changed = 1;
+	      const_op = 0, op1 = const0_rtx;
+	      code = GE;
+	      break;
+	    }
+
+	  /* < C is equivalent to <= (C - 1).  */
+	  else if (const_op > 0)
+	    {
+	      changed = 1;
+	      const_op--;
+	      op1 = GEN_INT (const_op);
+	      code = LEU;
+	      /* ... fall through ...  */
+	    }
+
+	  else
+	    break;
+
+	case LEU:
+	  /* unsigned <= 0 is equivalent to == 0 */
+	  if (const_op == 0)
+	    {
+	      changed = 1;
+	      code = EQ;
+	    }
+
+	  /* (unsigned) <= 0x7fffffff is equivalent to >= 0.  */
+	  else if ((mode_width <= HOST_BITS_PER_WIDE_INT)
+	           && (const_op == ((HOST_WIDE_INT) 1 << (mode_width - 1)) - 1))
+	    {
+	      changed = 1;
+	      const_op = 0, op1 = const0_rtx;
+	      code = GE;
+	    }
+	  break;
+
+	case GEU:
+	  /* (unsigned) >= 0x80000000 is equivalent to < 0.  */
+	  if ((mode_width <= HOST_BITS_PER_WIDE_INT)
+	           && (const_op == (HOST_WIDE_INT) 1 << (mode_width - 1)))
+	    {
+	      changed = 1;
+	      const_op = 0, op1 = const0_rtx;
+	      code = LT;
+	      break;
+	    }
+
+	  /* >= C is equivalent to < (C - 1).  */
+	  else if (const_op > 1)
+	    {
+	      changed = 1;
+	      const_op--;
+	      op1 = GEN_INT (const_op);
+	      code = GTU;
+	      /* ... fall through ...  */
+	    }
+
+	  else
+	    break;
+
+	case GTU:
+	  /* unsigned > 0 is equivalent to != 0 */
+	  if (const_op == 0)
+	    {
+	      changed = 1;
+	      code = NE;
+	    }
+
+	  /* (unsigned) > 0x7fffffff is equivalent to < 0.  */
+	  else if ((mode_width <= HOST_BITS_PER_WIDE_INT)
+	           && (const_op == ((HOST_WIDE_INT) 1 << (mode_width - 1)) - 1))
+	    {
+	      changed = 1;
+	      const_op = 0, op1 = const0_rtx;
+	      code = LT;
+	    }
+	  break;
+
+	default:
+	  break;
+	}
+
+      /* Compute some predicates to simplify code below.  */
+
+      equality_comparison_p = (code == EQ || code == NE);
+      sign_bit_comparison_p = ((code == LT || code == GE) && const_op == 0);
+      unsigned_comparison_p = (code == LTU || code == LEU || code == GTU
+	                       || code == GEU);
+
+      switch (GET_CODE (op0))
+	{
+        case ZERO_EXTRACT:
+	  /* If we are extracting a single bit from a variable position in
+	     a constant that has only a single bit set and are comparing it
+	     with zero, we can convert this into an equality comparison
+	     between the position and the location of the single bit.  */
+	  /* Except we can't if SHIFT_COUNT_TRUNCATED is set, since we might
+	     have already reduced the shift count modulo the word size.  */
+	  if (!SHIFT_COUNT_TRUNCATED
+	      && GET_CODE (XEXP (op0, 0)) == CONST_INT
+	      && XEXP (op0, 1) == const1_rtx
+	      && equality_comparison_p && const_op == 0
+	      && (i = exact_log2 (INTVAL (XEXP (op0, 0)))) >= 0)
+	    {
+	      if (BITS_BIG_ENDIAN)
+		{
+		  enum machine_mode new_mode
+		    = mode_for_extraction (EP_extzv, 1);
+		  if (new_mode == MAX_MACHINE_MODE)
+		    i = BITS_PER_WORD - 1 - i;
+		  else
+		    {
+		      cmp_mode = new_mode;
+		      i = (GET_MODE_BITSIZE (cmp_mode) - 1 - i);
+		    }
+		}
+
+	      changed = 1;
+	      op0 = XEXP (op0, 2);
+	      op1 = GEN_INT (i);
+	      const_op = i;
+
+	      /* Result is nonzero iff shift count is equal to I.  */
+	      code = reverse_condition (code);
+	      continue;
+	    }
+
+	  break;
+
+	case NOT:
+	  /* If just looking at the sign bit, reverse the sense of the
+	     comparison.  */
+	  if (sign_bit_comparison_p)
+	    {
+	      changed = 1;
+	      op0 = XEXP (op0, 0);
+	      code = (code == GE ? LT : GE);
+	      continue;
+	    }
+	  /* ... fall through ... */
+
+	case NEG:
+	  /* If testing for equality, we can take the NEG or NOT of the constant.  */
+	  if (equality_comparison_p
+	      && 0 != (tem = simplify_unary_operation (GET_CODE (op0), cmp_mode,
+						       op1, cmp_mode)))
+	    {
+	      changed = 1;
+	      op0 = XEXP (op0, 0);
+	      op1 = tem;
+	      continue;
+	    }
+	  break;
+
+	case ROTATE:
+	  /* If we are testing equality and our count is a constant, we
+	     can perform the inverse operation on our RHS.  */
+	  if (equality_comparison_p && GET_CODE (XEXP (op0, 1)) == CONST_INT
+	      && (tem = simplify_binary_operation (ROTATERT, cmp_mode,
+	                                           op1, XEXP (op0, 1))) != 0)
+	    {
+	      changed = 1;
+	      op0 = XEXP (op0, 0);
+	      op1 = tem;
+	      continue;
+	    }
+	  /* ... fall through ... */
+
+	case ABS:
+	  /* ROTATE and ABS are ignorable inside an equality comparison with zero.  */
+	  if (const_op == 0 && equality_comparison_p)
+	    {
+	      changed = 1;
+	      op0 = XEXP (op0, 0);
+	      continue;
+	    }
+	  break;
+
+
+	case PLUS:
+	  /* (eq (plus X A) B) -> (eq X (minus B A)).  We can only do
+	     this for equality comparisons due to pathological cases involving
+	     overflows.  */
+	  if (equality_comparison_p
+	      && 0 != (tem = simplify_binary_operation (MINUS, cmp_mode,
+	                                                op1, XEXP (op0, 1))))
+	    {
+	      changed = 1;
+	      op0 = XEXP (op0, 0);
+	      op1 = tem;
+	      continue;
+	    }
+
+	  /* (plus (abs X) (const_int -1)) is < 0 if and only if X == 0.  */
+	  if (const_op == 0 && XEXP (op0, 1) == constm1_rtx
+	      && GET_CODE (XEXP (op0, 0)) == ABS && sign_bit_comparison_p)
+	    {
+	      changed = 1;
+	      op0 = XEXP (XEXP (op0, 0), 0);
+	      code = (code == LT ? EQ : NE);
+	      continue;
+	    }
+	  break;
+
+	case MINUS:
+	  /* We used to optimize signed comparisons against zero, but that
+	     was incorrect.  Unsigned comparisons against zero (GTU, LEU)
+	     arrive here as equality comparisons, or (GEU, LTU) are
+	     optimized away.  No need to special-case them.  */
+
+	  /* (eq (minus A B) C) -> (eq A (plus B C)) or
+	     (eq B (minus A C)), whichever simplifies.  We can only do
+	     this for equality comparisons due to pathological cases involving
+	     overflows.  */
+	  if (equality_comparison_p
+	      && 0 != (tem = simplify_binary_operation (PLUS, cmp_mode,
+	                                                XEXP (op0, 1), op1)))
+	    {
+	      changed = 1;
+	      op0 = XEXP (op0, 0);
+	      op1 = tem;
+	      continue;
+	    }
+
+	  if (equality_comparison_p
+	      && 0 != (tem = simplify_binary_operation (MINUS, cmp_mode,
+	                                                XEXP (op0, 0), op1)))
+	    {
+	      changed = 1;
+	      op0 = XEXP (op0, 1);
+	      op1 = tem;
+	      continue;
+	    }
+
+	  /* The sign bit of (minus (ashiftrt X C) X), where C is the number
+	     of bits in X minus 1, is one iff X > 0.  */
+	  if (sign_bit_comparison_p && GET_CODE (XEXP (op0, 0)) == ASHIFTRT
+	      && GET_CODE (XEXP (XEXP (op0, 0), 1)) == CONST_INT
+	      && (unsigned HOST_WIDE_INT) INTVAL (XEXP (XEXP (op0, 0), 1))
+	         == mode_width - 1
+	      && rtx_equal_p (XEXP (XEXP (op0, 0), 0), XEXP (op0, 1)))
+	    {
+	      changed = 1;
+	      op0 = XEXP (op0, 1);
+	      code = (code == GE ? LE : GT);
+	      continue;
+	    }
+	  break;
+
+	case XOR:
+	  /* (eq (xor A B) C) -> (eq A (xor B C)).  This is a simplification
+	     if C is zero or B is a constant.  */
+	  if (equality_comparison_p
+	      && 0 != (tem = simplify_binary_operation (XOR, cmp_mode,
+	                                                XEXP (op0, 1), op1)))
+	    {
+	      changed = 1;
+	      op0 = XEXP (op0, 0);
+	      op1 = tem;
+	      continue;
+	    }
+	  break;
+
+	case IOR:
+	  /* The sign bit of (ior (plus X (const_int -1)) X) is nonzero
+	     iff X <= 0.  */
+	  if (sign_bit_comparison_p && GET_CODE (XEXP (op0, 0)) == PLUS
+	      && XEXP (XEXP (op0, 0), 1) == constm1_rtx
+	      && rtx_equal_p (XEXP (XEXP (op0, 0), 0), XEXP (op0, 1)))
+	    {
+	      changed = 1;
+	      op0 = XEXP (op0, 1);
+	      code = (code == GE ? GT : LE);
+	      continue;
+	    }
+	  break;
+
+	case AND:
+	  /* If we are doing an equality comparison of an AND of a bit equal
+	     to the sign bit, replace this with a LT or GE comparison of
+	     the underlying value.  */
+	  if (equality_comparison_p
+	      && const_op == 0
+	      && GET_CODE (XEXP (op0, 1)) == CONST_INT
+	      && mode_width <= HOST_BITS_PER_WIDE_INT
+	      && ((INTVAL (XEXP (op0, 1)) & GET_MODE_MASK (cmp_mode))
+	          == (unsigned HOST_WIDE_INT) 1 << (mode_width - 1)))
+	    {
+	      changed = 1;
+	      op0 = XEXP (op0, 0);
+	      code = (code == EQ ? GE : LT);
+	      continue;
+	    }
+
+	  /* If this AND operation is really a ZERO_EXTEND from a narrower
+	     mode, the constant fits within that mode, and this is either an
+	     equality or unsigned comparison, try to do this comparison in
+	     the narrower mode.  */
+	  if ((equality_comparison_p || unsigned_comparison_p)
+	      && GET_CODE (XEXP (op0, 1)) == CONST_INT
+	      && (i = exact_log2 ((INTVAL (XEXP (op0, 1))
+	                           & GET_MODE_MASK (cmp_mode))
+	                          + 1)) >= 0
+	      && const_op >> i == 0
+	      && (tmode = mode_for_size (i, MODE_INT, 1)) != BLKmode)
+	    {
+	      changed = 1;
+	      op0 = gen_lowpart (tmode, XEXP (op0, 0));
+	      continue;
+	    }
+	  break;
+
+	case ASHIFTRT:
+	  /* If OP0 is a sign extension and CODE is not an unsigned comparison,
+	     do the comparison in a narrower mode.  */
+	  if (! unsigned_comparison_p
+	      && GET_CODE (XEXP (op0, 1)) == CONST_INT
+	      && GET_CODE (XEXP (op0, 0)) == ASHIFT
+	      && XEXP (op0, 1) == XEXP (XEXP (op0, 0), 1)
+	      && (tmode = mode_for_size (mode_width - INTVAL (XEXP (op0, 1)),
+	                                 MODE_INT, 1)) != BLKmode
+	      && (((unsigned HOST_WIDE_INT) const_op
+	           + (GET_MODE_MASK (tmode) >> 1) + 1)
+	          <= GET_MODE_MASK (tmode)))
+	    {
+	      changed = 1;
+	      op0 = gen_lowpart (tmode, XEXP (XEXP (op0, 0), 0));
+	      continue;
+	    }
+	  /* ... fall through ... */
+
+	case LSHIFTRT:
+	  /* If we are using this shift to extract just the sign bit, we
+	     can replace this with an LT or GE comparison.  */
+	  if (const_op == 0
+	      && (equality_comparison_p || sign_bit_comparison_p)
+	      && GET_CODE (XEXP (op0, 1)) == CONST_INT
+	      && (unsigned HOST_WIDE_INT) INTVAL (XEXP (op0, 1))
+	         == mode_width - 1)
+	    {
+	      changed = 1;
+	      op0 = XEXP (op0, 0);
+	      code = (code == NE || code == GT ? LT : GE);
+	      continue;
+	    }
+	  break;
+
+	default:
+	  if (!COMPARISON_P (op0)
+	      || const_op != 0)
+	    break;
+
+	  /* If op0 is a comparison, extract the comparison arguments form it.  */
+	  if (code == NE)
+	    {
+	      if (GET_MODE (op0) == cmp_mode)
+		return simplify_rtx (op0);
+	      else
+		return simplify_gen_relational (GET_CODE (op0), mode, VOIDmode,
+					        XEXP (op0, 0), XEXP (op0, 1));
+	    }
+	  else if (code == EQ)
+	    {
+	      enum rtx_code new = reversed_comparison_code (op0, NULL_RTX);
+	      if (new != UNKNOWN)
+	        return simplify_gen_relational (new, mode, VOIDmode,
+					        XEXP (op0, 0), XEXP (op0, 1));
+	    }
+	  break;
+	}
+
+      break;
+    }
+
+  if (changed)
+    return gen_rtx_fmt_ee (code, mode, op0, op1);
+  else
+    return NULL_RTX;
+}
+
+/* Check if the given comparison (done in the given MODE) is actually a
+   tautology or a contradiction and return a logic value (0/1) if so.
+   Return -1 if nothing can be said on this relational operation.  */
+int
+relational_operation_const_result (enum rtx_code code, enum machine_mode mode,
+				   rtx op0, rtx op1)
 {
   int equal, op0lt, op0ltu, op1lt, op1ltu;
   rtx tem;
@@ -2691,7 +3179,7 @@
   /* We can't simplify MODE_CC values since we don't know what the
      actual comparison is.  */
   if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_CC || CC0_P (op0))
-    return 0;
+    return -1;
 
   /* Make sure the constant is second.  */
   if (swap_commutative_operands_p (op0, op1))
@@ -2721,14 +3209,14 @@
       /* We cannot do this for == or != if tem is a nonzero address.  */
       && ((code != EQ && code != NE) || ! nonzero_address_p (tem))
       && code != GTU && code != GEU && code != LTU && code != LEU)
-    return simplify_const_relational_operation (signed_condition (code),
-						mode, tem, const0_rtx);
+    return relational_operation_const_result (signed_condition (code),
+					      mode, tem, const0_rtx);
 
   if (flag_unsafe_math_optimizations && code == ORDERED)
-    return const_true_rtx;
+    return 1;
 
   if (flag_unsafe_math_optimizations && code == UNORDERED)
-    return const0_rtx;
+    return 0;
 
   /* For modes without NaNs, if the two operands are equal, we know the
      result except if they have side-effects.  */
@@ -2759,7 +3247,7 @@
 	  case UNGE:
 	  case NE:
 	  case UNORDERED:
-	    return const_true_rtx;
+	    return 1;
 	  case EQ:
 	  case LT:
 	  case GT:
@@ -2767,9 +3255,9 @@
 	  case GE:
 	  case LTGT:
 	  case ORDERED:
-	    return const0_rtx;
-	  default:
 	    return 0;
+	  default:
+	    return -1;
 	  }
 
       equal = REAL_VALUES_EQUAL (d0, d1);
@@ -2841,23 +3329,23 @@
 	{
 	case EQ:
 	  if (trueop1 == const0_rtx && nonzero_address_p (op0))
-	    return const0_rtx;
+	    return 0;
 	  break;
 
 	case NE:
 	  if (trueop1 == const0_rtx && nonzero_address_p (op0))
-	    return const_true_rtx;
+	    return 1;
 	  break;
 
 	case GEU:
 	  /* Unsigned values are never negative.  */
 	  if (trueop1 == const0_rtx)
-	    return const_true_rtx;
+	    return 1;
 	  break;
 
 	case LTU:
 	  if (trueop1 == const0_rtx)
-	    return const0_rtx;
+	    return 0;
 	  break;
 
 	case LEU:
@@ -2866,14 +3354,14 @@
 	  if (GET_CODE (trueop1) == CONST_INT
 	      && (unsigned HOST_WIDE_INT) INTVAL (trueop1) == GET_MODE_MASK (mode)
 	    && INTEGRAL_MODE_P (mode))
-	  return const_true_rtx;
+	  return 1;
 	  break;
 
 	case GTU:
 	  if (GET_CODE (trueop1) == CONST_INT
 	      && (unsigned HOST_WIDE_INT) INTVAL (trueop1) == GET_MODE_MASK (mode)
 	      && INTEGRAL_MODE_P (mode))
-	    return const0_rtx;
+	    return 0;
 	  break;
 
 	case LT:
@@ -2883,7 +3371,7 @@
 	      tem = GET_CODE (trueop0) == FLOAT_EXTEND ? XEXP (trueop0, 0)
 						       : trueop0;
 	      if (GET_CODE (tem) == ABS)
-		return const0_rtx;
+		return 0;
 	    }
 	  break;
 
@@ -2894,7 +3382,7 @@
 	      tem = GET_CODE (trueop0) == FLOAT_EXTEND ? XEXP (trueop0, 0)
 						       : trueop0;
 	      if (GET_CODE (tem) == ABS)
-		return const_true_rtx;
+		return 1;
 	    }
 	  break;
 
@@ -2905,7 +3393,7 @@
 	      tem = GET_CODE (trueop0) == FLOAT_EXTEND ? XEXP (trueop0, 0)
 						       : trueop0;
 	      if (GET_CODE (tem) == ABS)
-		return const_true_rtx;
+		return 1;
 	    }
 	  break;
 
@@ -2913,7 +3401,7 @@
 	  break;
 	}
 
-      return 0;
+      return -1;
     }
 
   /* If we reach here, EQUAL, OP0LT, OP0LTU, OP1LT, and OP1LTU are set
@@ -2922,68 +3410,38 @@
     {
     case EQ:
     case UNEQ:
-      return equal ? const_true_rtx : const0_rtx;
+      return equal;
     case NE:
     case LTGT:
-      return ! equal ? const_true_rtx : const0_rtx;
+      return !equal;
     case LT:
     case UNLT:
-      return op0lt ? const_true_rtx : const0_rtx;
+      return op0lt;
     case GT:
     case UNGT:
-      return op1lt ? const_true_rtx : const0_rtx;
+      return op1lt;
     case LTU:
-      return op0ltu ? const_true_rtx : const0_rtx;
+      return op0ltu;
     case GTU:
-      return op1ltu ? const_true_rtx : const0_rtx;
+      return op1ltu;
     case LE:
     case UNLE:
-      return equal || op0lt ? const_true_rtx : const0_rtx;
+      return equal || op0lt;
     case GE:
     case UNGE:
-      return equal || op1lt ? const_true_rtx : const0_rtx;
+      return equal || op1lt;
     case LEU:
-      return equal || op0ltu ? const_true_rtx : const0_rtx;
+      return equal || op0ltu;
     case GEU:
-      return equal || op1ltu ? const_true_rtx : const0_rtx;
+      return equal || op1ltu;
     case ORDERED:
-      return const_true_rtx;
+      return 1;
     case UNORDERED:
-      return const0_rtx;
+      return 0;
     default:
       abort ();
     }
 }
-
-/* Like simplify_binary_operation except used for relational operators.
-   MODE is the mode of the result, and CMP_MODE is the mode of the operands.
-   If CMP_MODE is VOIDmode, both operands must also be VOIDmode and we
-   compare the operands in "infinite precision".  */
-
-rtx
-simplify_relational_operation (enum rtx_code code,
-			       enum machine_mode mode ATTRIBUTE_UNUSED,
-			       enum machine_mode cmp_mode, rtx op0, rtx op1)
-{
-  rtx tmp;
-
-  tmp = simplify_const_relational_operation (code, cmp_mode, op0, op1);
-  if (tmp)
-    {
-#ifdef FLOAT_STORE_FLAG_VALUE
-      if (GET_MODE_CLASS (mode) == MODE_FLOAT)
-	{
-	  if (tmp == const0_rtx)
-	    return CONST0_RTX (mode);
-	  return CONST_DOUBLE_FROM_REAL_VALUE (FLOAT_STORE_FLAG_VALUE (mode),
-					       mode);
-	}
-#endif
-      return tmp;
-    }
-
-  return NULL_RTX;
-}
 
 /* Simplify CODE, an operation with result mode MODE and three operands,
    OP0, OP1, and OP2.  OP0_MODE was the mode of OP0 before it became
@@ -3078,20 +3536,7 @@
 					? GET_MODE (XEXP (op0, 1))
 					: GET_MODE (XEXP (op0, 0)));
 	  rtx temp;
-	  if (cmp_mode == VOIDmode)
-	    cmp_mode = op0_mode;
-	  temp = simplify_const_relational_operation (GET_CODE (op0),
-						      cmp_mode,
-						      XEXP (op0, 0),
-						      XEXP (op0, 1));
-
-	  /* See if any simplifications were possible.  */
-	  if (temp == const0_rtx)
-	    return op2;
-	  else if (temp == const_true_rtx)
-	    return op1;
-	  else if (temp)
-	    abort ();
+	  int result;
 
 	  /* Look for happy constants in op1 and op2.  */
 	  if (GET_CODE (op1) == CONST_INT && GET_CODE (op2) == CONST_INT)
@@ -3112,8 +3557,23 @@
 	      else
 		break;
 
-	      return gen_rtx_fmt_ee (code, mode, XEXP (op0, 0), XEXP (op0, 1));
+	      return simplify_gen_relational (code, op0_mode, cmp_mode,
+					      XEXP (op0, 0), XEXP (op0, 1));
 	    }
+
+	  if (cmp_mode == VOIDmode)
+	    cmp_mode = op0_mode;
+	  temp = simplify_relational_operation (GET_CODE (op0), op0_mode, cmp_mode,
+					        XEXP (op0, 0), XEXP (op0, 1),
+						&result);
+
+	  /* See if any simplifications were possible.  */
+	  if (result == 0)
+	    return op2;
+	  else if (result == 1)
+	    return op1;
+	  else if (temp)
+	    return gen_rtx_IF_THEN_ELSE (mode, temp, op1, op2);
 	}
       break;
 
@@ -3721,7 +4181,6 @@
 {
   enum rtx_code code = GET_CODE (x);
   enum machine_mode mode = GET_MODE (x);
-  rtx temp;
 
   switch (GET_RTX_CLASS (code))
     {
@@ -3745,13 +4204,13 @@
 
     case RTX_COMPARE:
     case RTX_COMM_COMPARE:
-      temp = simplify_relational_operation (code, mode,
-					    ((GET_MODE (XEXP (x, 0))
-					      != VOIDmode)
-					     ? GET_MODE (XEXP (x, 0))
-					     : GET_MODE (XEXP (x, 1))),
-					    XEXP (x, 0), XEXP (x, 1));
-      return temp;
+      return simplify_relational_operation (code, mode,
+                                            ((GET_MODE (XEXP (x, 0))
+                                             != VOIDmode)
+                                            ? GET_MODE (XEXP (x, 0))
+                                            : GET_MODE (XEXP (x, 1))),
+                                            XEXP (x, 0),
+                                            XEXP (x, 1), NULL);
 
     case RTX_EXTRA:
       if (code == SUBREG)
Index: unroll.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/unroll.c,v
retrieving revision 1.207
diff -u -r1.207 unroll.c
--- unroll.c	9 Mar 2004 17:06:25 -0000	1.207
+++ unroll.c	26 Apr 2004 14:17:59 -0000
@@ -1336,10 +1336,11 @@
 simplify_cmp_and_jump_insns (enum rtx_code code, enum machine_mode mode,
 			     rtx op0, rtx op1, rtx label)
 {
-  rtx t, insn;
+  int t;
+  rtx insn;
 
-  t = simplify_const_relational_operation (code, mode, op0, op1);
-  if (!t)
+  t = relational_operation_const_result (code, mode, op0, op1);
+  if (t == -1)
     {
       enum rtx_code scode = signed_condition (code);
       emit_cmp_and_jump_insns (op0, op1, scode, NULL_RTX, mode,
@@ -1351,7 +1352,7 @@
 
       return insn;
     }
-  else if (t == const_true_rtx)
+  else if (t == 1)
     {
       insn = emit_jump_insn (gen_jump (label));
       emit_barrier ();

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