diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 71123fc..be4c46b 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,10 @@
+2003-09-11  Roger Sayle  <roger@eyesopen.com>
+
+	* combine.c (combine_simplify_rtx): Move several NOT and NEG
+	optimizations from here...
+	* simplify-rtx.c (simplify_unary_operation): to here.  Recursively
+	simplify expressions using simplify_gen_*ary instead of gen_rtx_*.
+
 2003-09-11  Richard Henderson  <rth@redhat.com>
 
 	* cgraphunit.c (cgraph_finalize_function): Add nested arg.
diff --git a/gcc/combine.c b/gcc/combine.c
index 5f005e4..2567ca9 100644
--- a/gcc/combine.c
+++ b/gcc/combine.c
@@ -3847,33 +3847,6 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int last,
       break;
 
     case NOT:
-      /* (not (plus X -1)) can become (neg X).  */
-      if (GET_CODE (XEXP (x, 0)) == PLUS
-	  && XEXP (XEXP (x, 0), 1) == constm1_rtx)
-	return gen_rtx_NEG (mode, XEXP (XEXP (x, 0), 0));
-
-      /* Similarly, (not (neg X)) is (plus X -1).  */
-      if (GET_CODE (XEXP (x, 0)) == NEG)
-	return gen_rtx_PLUS (mode, XEXP (XEXP (x, 0), 0), constm1_rtx);
-
-      /* (not (xor X C)) for C constant is (xor X D) with D = ~C.  */
-      if (GET_CODE (XEXP (x, 0)) == XOR
-	  && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
-	  && (temp = simplify_unary_operation (NOT, mode,
-					       XEXP (XEXP (x, 0), 1),
-					       mode)) != 0)
-	return gen_binary (XOR, mode, XEXP (XEXP (x, 0), 0), temp);
-
-      /* (not (ashift 1 X)) is (rotate ~1 X).  We used to do this for operands
-	 other than 1, but that is not valid.  We could do a similar
-	 simplification for (not (lshiftrt C X)) where C is just the sign bit,
-	 but this doesn't seem common enough to bother with.  */
-      if (GET_CODE (XEXP (x, 0)) == ASHIFT
-	  && XEXP (XEXP (x, 0), 0) == const1_rtx)
-	return gen_rtx_ROTATE (mode, simplify_gen_unary (NOT, mode,
-							 const1_rtx, mode),
-			       XEXP (XEXP (x, 0), 1));
-
       if (GET_CODE (XEXP (x, 0)) == SUBREG
 	  && subreg_lowpart_p (XEXP (x, 0))
 	  && (GET_MODE_SIZE (GET_MODE (XEXP (x, 0)))
@@ -3890,24 +3863,6 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int last,
 	  return gen_lowpart_for_combine (mode, x);
 	}
 
-      /* If STORE_FLAG_VALUE is -1, (not (comparison foo bar)) can be done by
-	 reversing the comparison code if valid.  */
-      if (STORE_FLAG_VALUE == -1
-	  && GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
-	  && (reversed = reversed_comparison (x, mode, XEXP (XEXP (x, 0), 0),
-					      XEXP (XEXP (x, 0), 1))))
-	return reversed;
-
-      /* (not (ashiftrt foo C)) where C is the number of bits in FOO minus 1
-	 is (ge foo (const_int 0)) if STORE_FLAG_VALUE is -1, so we can
-	 perform the above simplification.  */
-
-      if (STORE_FLAG_VALUE == -1
-	  && GET_CODE (XEXP (x, 0)) == ASHIFTRT
-	  && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
-	  && INTVAL (XEXP (XEXP (x, 0), 1)) == GET_MODE_BITSIZE (mode) - 1)
-	return gen_rtx_GE (mode, XEXP (XEXP (x, 0), 0), const0_rtx);
-
       /* Apply De Morgan's laws to reduce number of patterns for machines
 	 with negating logical insns (and-not, nand, etc.).  If result has
 	 only one NOT, put it first, since that is how the patterns are
@@ -3938,63 +3893,12 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int last,
       break;
 
     case NEG:
-      /* (neg (plus X 1)) can become (not X).  */
-      if (GET_CODE (XEXP (x, 0)) == PLUS
-	  && XEXP (XEXP (x, 0), 1) == const1_rtx)
-	return gen_rtx_NOT (mode, XEXP (XEXP (x, 0), 0));
-
-      /* Similarly, (neg (not X)) is (plus X 1).  */
-      if (GET_CODE (XEXP (x, 0)) == NOT)
-	return plus_constant (XEXP (XEXP (x, 0), 0), 1);
-
-      /* (neg (minus X Y)) can become (minus Y X).  This transformation
-	 isn't safe for modes with signed zeros, since if X and Y are
-	 both +0, (minus Y X) is the same as (minus X Y).  If the rounding
-	 mode is towards +infinity (or -infinity) then the two expressions
-	 will be rounded differently.  */
-      if (GET_CODE (XEXP (x, 0)) == MINUS
-	  && !HONOR_SIGNED_ZEROS (mode)
-	  && !HONOR_SIGN_DEPENDENT_ROUNDING (mode))
-	return gen_binary (MINUS, mode, XEXP (XEXP (x, 0), 1),
-			   XEXP (XEXP (x, 0), 0));
-
-      /* (neg (plus A B)) is canonicalized to (minus (neg A) B).  */
-      if (GET_CODE (XEXP (x, 0)) == PLUS
-	  && !HONOR_SIGNED_ZEROS (mode)
-	  && !HONOR_SIGN_DEPENDENT_ROUNDING (mode))
-	{
-	  temp = simplify_gen_unary (NEG, mode, XEXP (XEXP (x, 0), 0), mode);
-	  temp = combine_simplify_rtx (temp, mode, last, in_dest);
-	  return gen_binary (MINUS, mode, temp, XEXP (XEXP (x, 0), 1));
-	}
-
-      /* (neg (mult A B)) becomes (mult (neg A) B).
-         This works even for floating-point values.  */
-      if (GET_CODE (XEXP (x, 0)) == MULT
-	  && !HONOR_SIGN_DEPENDENT_ROUNDING (mode))
-	{
-	  temp = simplify_gen_unary (NEG, mode, XEXP (XEXP (x, 0), 0), mode);
-	  return gen_binary (MULT, mode, temp, XEXP (XEXP (x, 0), 1));
-	}
-
       /* (neg (xor A 1)) is (plus A -1) if A is known to be either 0 or 1.  */
       if (GET_CODE (XEXP (x, 0)) == XOR
 	  && XEXP (XEXP (x, 0), 1) == const1_rtx
 	  && nonzero_bits (XEXP (XEXP (x, 0), 0), mode) == 1)
 	return gen_binary (PLUS, mode, XEXP (XEXP (x, 0), 0), constm1_rtx);
 
-      /* NEG commutes with ASHIFT since it is multiplication.  Only do this
-	 if we can then eliminate the NEG (e.g.,
-	 if the operand is a constant).  */
-
-      if (GET_CODE (XEXP (x, 0)) == ASHIFT)
-	{
-	  temp = simplify_unary_operation (NEG, mode,
-					   XEXP (XEXP (x, 0), 0), mode);
-	  if (temp)
-	    return gen_binary (ASHIFT, mode, temp, XEXP (XEXP (x, 0), 1));
-	}
-
       temp = expand_compound_operation (XEXP (x, 0));
 
       /* For C equal to the width of MODE minus 1, (neg (ashiftrt X C)) can be
diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c
index 6ace348..aa16af8 100644
--- a/gcc/simplify-rtx.c
+++ b/gcc/simplify-rtx.c
@@ -788,6 +788,8 @@ simplify_unary_operation (enum rtx_code code, enum machine_mode mode,
   else
     {
       enum rtx_code reversed;
+      rtx temp;
+
       /* There are some simplifications we can do even if the operands
 	 aren't constant.  */
       switch (code)
@@ -801,14 +803,116 @@ simplify_unary_operation (enum rtx_code code, enum machine_mode mode,
 	  if (mode == BImode && GET_RTX_CLASS (GET_CODE (op)) == '<'
 	      && ((reversed = reversed_comparison_code (op, NULL_RTX))
 		  != UNKNOWN))
-	    return gen_rtx_fmt_ee (reversed,
-				   op_mode, XEXP (op, 0), XEXP (op, 1));
+	    return simplify_gen_relational (reversed, op_mode, op_mode,
+					    XEXP (op, 0), XEXP (op, 1));
+
+          /* (not (plus X -1)) can become (neg X).  */
+          if (GET_CODE (op) == PLUS
+	      && XEXP (op, 1) == constm1_rtx)
+	    return simplify_gen_unary (NEG, mode, XEXP (op, 0), mode);
+
+	  /* Similarly, (not (neg X)) is (plus X -1).  */
+	  if (GET_CODE (op) == NEG)
+	    return plus_constant (XEXP (op, 0), -1);
+
+	  /* (not (xor X C)) for C constant is (xor X D) with D = ~C.  */
+	  if (GET_CODE (op) == XOR
+	      && GET_CODE (XEXP (op, 1)) == CONST_INT
+	      && (temp = simplify_unary_operation (NOT, mode,
+						   XEXP (op, 1),
+						   mode)) != 0)
+	    return simplify_gen_binary (XOR, mode, XEXP (op, 0), temp);
+
+
+	  /* (not (ashift 1 X)) is (rotate ~1 X).  We used to do this for
+	     operands other than 1, but that is not valid.  We could do a
+	     similar simplification for (not (lshiftrt C X)) where C is
+	     just the sign bit, but this doesn't seem common enough to
+	     bother with.  */
+	  if (GET_CODE (op) == ASHIFT
+	      && XEXP (op, 0) == const1_rtx)
+	    {
+	      temp = simplify_gen_unary (NOT, mode, const1_rtx, mode);
+	      return simplify_gen_binary (ROTATE, mode, temp, XEXP (op, 1));
+	    }
+
+	  /* If STORE_FLAG_VALUE is -1, (not (comparison X Y)) can be done
+	     by reversing the comparison code if valid.  */
+	  if (STORE_FLAG_VALUE == -1
+	      && GET_RTX_CLASS (GET_CODE (op)) == '<'
+	      && (reversed = reversed_comparison_code (op, NULL_RTX))
+		 != UNKNOWN)
+	    return simplify_gen_relational (reversed, op_mode, op_mode,
+					    XEXP (op, 0), XEXP (op, 1));
+
+	  /* (not (ashiftrt foo C)) where C is the number of bits in FOO
+	     minus 1 is (ge foo (const_int 0)) if STORE_FLAG_VALUE is -1,
+	     so we can perform the above simplification.  */
+
+	  if (STORE_FLAG_VALUE == -1
+	      && GET_CODE (op) == ASHIFTRT
+	      && GET_CODE (XEXP (op, 1)) == CONST_INT
+	      && INTVAL (XEXP (op, 1)) == GET_MODE_BITSIZE (mode) - 1)
+	    return simplify_gen_relational (GE, mode, mode, XEXP (op, 0),
+					    const0_rtx);
+
 	  break;
 
 	case NEG:
 	  /* (neg (neg X)) == X.  */
 	  if (GET_CODE (op) == NEG)
 	    return XEXP (op, 0);
+
+	  /* (neg (plus X 1)) can become (not X).  */
+	  if (GET_CODE (op) == PLUS
+	      && XEXP (op, 1) == const1_rtx)
+	    return simplify_gen_unary (NOT, mode, XEXP (op, 0), mode);
+
+	  /* Similarly, (neg (not X)) is (plus X 1).  */
+	  if (GET_CODE (op) == NOT)
+	    return plus_constant (XEXP (op, 0), 1);
+
+	  /* (neg (minus X Y)) can become (minus Y X).  This transformation
+	     isn't safe for modes with signed zeros, since if X and Y are
+	     both +0, (minus Y X) is the same as (minus X Y).  If the
+	     rounding mode is towards +infinity (or -infinity) then the two
+	     expressions will be rounded differently.  */
+	  if (GET_CODE (op) == MINUS
+	      && !HONOR_SIGNED_ZEROS (mode)
+	      && !HONOR_SIGN_DEPENDENT_ROUNDING (mode))
+	    return simplify_gen_binary (MINUS, mode, XEXP (op, 1),
+					XEXP (op, 0));
+
+	  /* (neg (plus A B)) is canonicalized to (minus (neg A) B).  */
+	  if (GET_CODE (op) == PLUS
+	      && !HONOR_SIGNED_ZEROS (mode)
+	      && !HONOR_SIGN_DEPENDENT_ROUNDING (mode))
+	    {
+	      temp = simplify_gen_unary (NEG, mode, XEXP (op, 0), mode);
+	      return simplify_gen_binary (MINUS, mode, temp, XEXP (op, 1));
+	    }
+
+	  /* (neg (mult A B)) becomes (mult (neg A) B).
+	     This works even for floating-point values.  */
+	  if (GET_CODE (op) == MULT
+	      && !HONOR_SIGN_DEPENDENT_ROUNDING (mode))
+	    {
+	      temp = simplify_gen_unary (NEG, mode, XEXP (op, 0), mode);
+	      return simplify_gen_binary (MULT, mode, temp, XEXP (op, 1));
+	    }
+
+	  /* NEG commutes with ASHIFT since it is multiplication.  Only do
+	     this if we can then eliminate the NEG (e.g., if the operand
+	     is a constant).  */
+	  if (GET_CODE (op) == ASHIFT)
+	    {
+	      temp = simplify_unary_operation (NEG, mode, XEXP (op, 0),
+					       mode);
+	      if (temp)
+		return simplify_gen_binary (ASHIFT, mode, temp,
+					    XEXP (op, 1));
+	    }
+
 	  break;
 
 	case SIGN_EXTEND: