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]

Re: [RFC] Fold floating-point comparisons


Ah.  Another example of missing internals documentation.  My approach
was to document the semantics first, and then once documented propose
a patch to fix PR rtl-optimization/15649.

My patch seems to fix PR/15649 as well! :-) Thanks for mentioning it.


This is the direct benefit to a programmer of writing internal
documentation.  The person that writes the documentation gets to
define the semantics.  In this case, we get to choose that LTGT
shouldn't trap :>

Nope, rth as expected knew better than both of us! :-) I also thought that LTGT wouldn't trap.

Here's the final patch, bootstrapped/regtested i686-pc-linux-gnu. The patch has three main parts, but they're quite intertwined: the first is the addition of LTGT_EXPR, the second is the revamping of the compcode optimization (in fold_truthop), the second is supporting the inversion of floating-point comparisons in invert_truthvalue.

It includes four testcases based on those that you had introduced for
integers when writing the compcode stuff, plus the testcase for PR/15649.

Unfortunately, some of the comparisons in the testcases are not optimized because invert_truthvalue does not fold the trees it returns. For example, !(x < y) && x < y becomes (x UNGE y) && (x < y), but this is not folded further. Adding this feature to invert_truthvalue causes an ICE in builtins.c while building stage2, which I'll investigate.

Ok for mainline?

Paolo

gcc/ChangeLog:
2004-05-27  Paolo Bonzini  <bonzini@gnu.org>
	    Roger Sayle  <roger@eyesopen.com>

	PR rtl-optimization/15649
	Add LTGT_EXPR and improve pretty-printing of unordered
	comparisons.
	* c-common.c (c_common_truthvalue_conversion):
	Handle LTGT_EXPR.
	* c-typeck.c (build_binary_op): Likewise.
	* dojump.c (do_jump): Likewise.
	* expr.c (expand_expr_real_1, do_store_flag): Likewise.
	* predict.c (tree_predict_by_opcode): Likewise.
	* real.c (real_compare): Likewise.
	* tree-cfg.c (verify_expr): Likewise.
	* tree-inline.c (estimate_num_insns_1): Likewise.
	* tree-pretty-print.c (dump_generic_node): Likewise.
	Handle ORDERED_EXPR, UNORDERED_EXPR.
	(op_symbol): Print unordered comparisons differently
	than ordered ones.
	* tree.def (LTGT_EXPR): New '<' tree code.
	* doc/c-tree.texi (Expressions): Document floating-point
	comparison nodes.

	Fold comparisons between floating point values.
	* fold-const.c (enum comparison_code): New, from
	#define'd constants.  Define compcodes for unordered
	comparisons and for invalid transformations.
	(invert_truthvalue): Fold the resulting trees whenever
	useful.
	(invert_tree_comparison): Add "honor_nans" parameter.
	(fold_truthop): Revamp to work on floating-point types too.
	(comparison_to_compcode): Support unordered comparisons.
	Use new enum comparison_code.
	(compcode_to_comparison): Likewise.
	(combine_compcodes): New function.
	(invert_truthvalue): Let invert_tree_comparison decide
	whether it is valid to fold the comparison.  Fold ORDERED
	and UNORDERED even if flag_unsafe_math_optimizations is off,
	and the remaining even if flag_unsafe_math_optimizations
	is off but we are under -fno-trapping-math.
	(fold_relational_const): Integer modes do not honor NaNs.
	
gcc/testsuite/ChangeLog:
2004-05-27  Paolo Bonzini  <bonzini@gnu.org>

	* gcc.dg/compare-fp-1.c, gcc.dg/compare-fp-2.c,
	gcc.dg/compare-fp-3.c, gcc.dg/compare-fp-4.c,
	gcc.dg/pr15649-1.c: New.

? aaa
? libgcc2.s
Index: c-common.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-common.c,v
retrieving revision 1.501
diff -u -p -r1.501 c-common.c
--- c-common.c	22 May 2004 18:16:38 -0000	1.501
+++ c-common.c	27 May 2004 09:02:49 -0000
@@ -2582,7 +2582,7 @@ c_common_truthvalue_conversion (tree exp
 
   switch (TREE_CODE (expr))
     {
-    case EQ_EXPR:   case NE_EXPR:   case UNEQ_EXPR:
+    case EQ_EXPR:   case NE_EXPR:   case UNEQ_EXPR: case LTGT_EXPR:
     case LE_EXPR:   case GE_EXPR:   case LT_EXPR:   case GT_EXPR:
     case UNLE_EXPR: case UNGE_EXPR: case UNLT_EXPR: case UNGT_EXPR:
     case ORDERED_EXPR: case UNORDERED_EXPR:
Index: c-typeck.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-typeck.c,v
retrieving revision 1.304
diff -u -p -r1.304 c-typeck.c
--- c-typeck.c	14 May 2004 02:32:55 -0000	1.304
+++ c-typeck.c	27 May 2004 09:02:50 -0000
@@ -6798,6 +6798,7 @@ build_binary_op (enum tree_code code, tr
     case UNGT_EXPR:
     case UNGE_EXPR:
     case UNEQ_EXPR:
+    case LTGT_EXPR:
       build_type = integer_type_node;
       if (code0 != REAL_TYPE || code1 != REAL_TYPE)
 	{
Index: dojump.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/dojump.c,v
retrieving revision 1.16
diff -u -p -r1.16 dojump.c
--- dojump.c	29 Apr 2004 07:50:55 -0000	1.16
+++ dojump.c	27 May 2004 09:02:50 -0000
@@ -525,7 +525,8 @@ do_jump (tree exp, rtx if_false_label, r
 
     {
       enum rtx_code rcode1;
-      enum tree_code tcode2;
+      enum tree_code tcode1 = UNORDERED_EXPR, tcode2;
+      enum tree_code tcode_final = TRUTH_ORIF_EXPR;
 
       case UNLT_EXPR:
         rcode1 = UNLT;
@@ -547,6 +548,12 @@ do_jump (tree exp, rtx if_false_label, r
         rcode1 = UNEQ;
         tcode2 = EQ_EXPR;
         goto unordered_bcc;
+      case LTGT_EXPR:
+        rcode1 = LTGT;
+        tcode1 = ORDERED_EXPR;
+        tcode2 = NE_EXPR;
+	tcode_final = TRUTH_ANDIF_EXPR;
+        goto unordered_bcc;
 
       unordered_bcc:
         mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
@@ -560,10 +567,10 @@ do_jump (tree exp, rtx if_false_label, r
             tree cmp0, cmp1;
 
             /* If the target doesn't support combined unordered
-               compares, decompose into UNORDERED + comparison.  */
-            cmp0 = fold (build (UNORDERED_EXPR, TREE_TYPE (exp), op0, op1));
+               compares, decompose into two comparisons.  */
+            cmp0 = fold (build (tcode1, TREE_TYPE (exp), op0, op1));
             cmp1 = fold (build (tcode2, TREE_TYPE (exp), op0, op1));
-            exp = build (TRUTH_ORIF_EXPR, TREE_TYPE (exp), cmp0, cmp1);
+            exp = build (tcode_final, TREE_TYPE (exp), cmp0, cmp1);
             do_jump (exp, if_false_label, if_true_label);
           }
       }
Index: expr.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/expr.c,v
retrieving revision 1.647
diff -u -p -r1.647 expr.c
--- expr.c	19 May 2004 06:26:21 -0000	1.647
+++ expr.c	27 May 2004 09:02:51 -0000
@@ -8304,6 +8304,7 @@ expand_expr_real_1 (tree exp, rtx target
     case UNGT_EXPR:
     case UNGE_EXPR:
     case UNEQ_EXPR:
+    case LTGT_EXPR:
       temp = do_store_flag (exp,
 			    modifier != EXPAND_STACK_PARM ? target : NULL_RTX,
 			    tmode != VOIDmode ? tmode : mode, 0);
@@ -9814,6 +9815,9 @@ do_store_flag (tree exp, rtx target, enu
     case UNEQ_EXPR:
       code = UNEQ;
       break;
+    case LTGT_EXPR:
+      code = LTGT;
+      break;
 
     default:
       abort ();
Index: fold-const.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fold-const.c,v
retrieving revision 1.382
diff -u -p -r1.382 fold-const.c
--- fold-const.c	24 May 2004 03:02:44 -0000	1.382
+++ fold-const.c	27 May 2004 09:02:52 -0000
@@ -58,6 +58,29 @@ Software Foundation, 59 Temple Place - S
 #include "langhooks.h"
 #include "md5.h"
 
+/* The following constants represent a bit based encoding of GCC's
+   comparison operators.  This encoding simplifies transformations
+   on relational comparison operators, such as AND and OR.  */
+enum comparison_code {
+  COMPCODE_INVALID = -1,
+  COMPCODE_FALSE = 0,
+  COMPCODE_LT = 1,
+  COMPCODE_EQ = 2,
+  COMPCODE_LE = 3,
+  COMPCODE_GT = 4,
+  COMPCODE_LTGT = 5,
+  COMPCODE_GE = 6,
+  COMPCODE_ORD = 7,
+  COMPCODE_UNORD = 8,
+  COMPCODE_UNLT = 9,
+  COMPCODE_UNEQ = 10,
+  COMPCODE_UNLE = 11,
+  COMPCODE_UNGT = 12,
+  COMPCODE_NE = 13,
+  COMPCODE_UNGE = 14,
+  COMPCODE_TRUE = 15
+};
+
 static void encode (HOST_WIDE_INT *, unsigned HOST_WIDE_INT, HOST_WIDE_INT);
 static void decode (HOST_WIDE_INT *, unsigned HOST_WIDE_INT *, HOST_WIDE_INT *);
 static bool negate_mathfn_p (enum built_in_function);
@@ -69,10 +92,12 @@ static tree const_binop (enum tree_code,
 static hashval_t size_htab_hash (const void *);
 static int size_htab_eq (const void *, const void *);
 static tree fold_convert_const (enum tree_code, tree, tree);
-static enum tree_code invert_tree_comparison (enum tree_code);
+static enum tree_code invert_tree_comparison (enum tree_code, bool);
 static enum tree_code swap_tree_comparison (enum tree_code);
-static int comparison_to_compcode (enum tree_code);
-static enum tree_code compcode_to_comparison (int);
+static enum comparison_code comparison_to_compcode (enum tree_code);
+static enum tree_code compcode_to_comparison (enum comparison_code);
+static enum comparison_code combine_comparisons (enum tree_code, enum tree_code,
+						 enum tree_code, bool);
 static int truth_value_p (enum tree_code);
 static int operand_equal_for_comparison_p (tree, tree, tree);
 static int twoval_comparison_p (tree, tree *, tree *, int *);
@@ -115,18 +140,6 @@ static tree fold_abs_const (tree, tree);
 static tree fold_relational_const (enum tree_code, tree, tree, tree);
 static tree fold_relational_hi_lo (enum tree_code *, const tree, tree *, tree *);
 
-/* The following constants represent a bit based encoding of GCC's
-   comparison operators.  This encoding simplifies transformations
-   on relational comparison operators, such as AND and OR.  */
-#define COMPCODE_FALSE   0
-#define COMPCODE_LT      1
-#define COMPCODE_EQ      2
-#define COMPCODE_LE      3
-#define COMPCODE_GT      4
-#define COMPCODE_NE      5
-#define COMPCODE_GE      6
-#define COMPCODE_TRUE    7
-
 /* We know that A1 + B1 = SUM1, using 2's complement arithmetic and ignoring
    overflow.  Suppose A, B and SUM have the same respective signs as A1, B1,
    and SUM1.  Then this yields nonzero if overflow occurred during the
@@ -2057,11 +2070,15 @@ pedantic_non_lvalue (tree x)
 
 /* Given a tree comparison code, return the code that is the logical inverse
    of the given code.  It is not safe to do this for floating-point
-   comparisons, except for NE_EXPR and EQ_EXPR.  */
+   comparisons, except for NE_EXPR and EQ_EXPR, so we receive a machine mode
+   as well: if reversing the comparison is unsafe, return ERROR_MARK.  */
 
 static enum tree_code
-invert_tree_comparison (enum tree_code code)
+invert_tree_comparison (enum tree_code code, bool honor_nans)
 {
+  if (honor_nans && flag_trapping_math)
+    return ERROR_MARK;
+
   switch (code)
     {
     case EQ_EXPR:
@@ -2069,13 +2086,29 @@ invert_tree_comparison (enum tree_code c
     case NE_EXPR:
       return EQ_EXPR;
     case GT_EXPR:
-      return LE_EXPR;
+      return honor_nans ? UNLE_EXPR : LE_EXPR;
     case GE_EXPR:
-      return LT_EXPR;
+      return honor_nans ? UNLT_EXPR : LT_EXPR;
     case LT_EXPR:
-      return GE_EXPR;
+      return honor_nans ? UNGE_EXPR : GE_EXPR;
     case LE_EXPR:
+      return honor_nans ? UNGT_EXPR : GT_EXPR;
+    case LTGT_EXPR:
+      return UNEQ_EXPR;
+    case UNEQ_EXPR:
+      return LTGT_EXPR;
+    case UNGT_EXPR:
+      return LE_EXPR;
+    case UNGE_EXPR:
+      return LT_EXPR;
+    case UNLT_EXPR:
+      return GE_EXPR;
+    case UNLE_EXPR:
       return GT_EXPR;
+    case ORDERED_EXPR:
+      return UNORDERED_EXPR;
+    case UNORDERED_EXPR:
+      return ORDERED_EXPR;
     default:
       abort ();
     }
@@ -2110,7 +2143,7 @@ swap_tree_comparison (enum tree_code cod
    into a compcode bit-based encoding.  This function is the inverse of
    compcode_to_comparison.  */
 
-static int
+static enum comparison_code
 comparison_to_compcode (enum tree_code code)
 {
   switch (code)
@@ -2127,6 +2160,22 @@ comparison_to_compcode (enum tree_code c
       return COMPCODE_NE;
     case GE_EXPR:
       return COMPCODE_GE;
+    case ORDERED_EXPR:
+      return COMPCODE_ORD;
+    case UNORDERED_EXPR:
+      return COMPCODE_UNORD;
+    case UNLT_EXPR:
+      return COMPCODE_UNLT;
+    case UNEQ_EXPR:
+      return COMPCODE_UNEQ;
+    case UNLE_EXPR:
+      return COMPCODE_UNLE;
+    case UNGT_EXPR:
+      return COMPCODE_UNGT;
+    case LTGT_EXPR:
+      return COMPCODE_LTGT;
+    case UNGE_EXPR:
+      return COMPCODE_UNGE;
     default:
       abort ();
     }
@@ -2137,7 +2186,7 @@ comparison_to_compcode (enum tree_code c
    inverse of comparison_to_compcode.  */
 
 static enum tree_code
-compcode_to_comparison (int code)
+compcode_to_comparison (enum comparison_code code)
 {
   switch (code)
     {
@@ -2153,11 +2202,103 @@ compcode_to_comparison (int code)
       return NE_EXPR;
     case COMPCODE_GE:
       return GE_EXPR;
+    case COMPCODE_ORD:
+      return ORDERED_EXPR;
+    case COMPCODE_UNORD:
+      return UNORDERED_EXPR;
+    case COMPCODE_UNLT:
+      return UNLT_EXPR;
+    case COMPCODE_UNEQ:
+      return UNEQ_EXPR;
+    case COMPCODE_UNLE:
+      return UNLE_EXPR;
+    case COMPCODE_UNGT:
+      return UNGT_EXPR;
+    case COMPCODE_LTGT:
+      return LTGT_EXPR;
+    case COMPCODE_UNGE:
+      return UNGE_EXPR;
     default:
       abort ();
     }
 }
 
+/* Return a bit-based comparison code which is the combination of
+   doing the AND or OR (depending on CODE) of the two operations LCODE
+   and RCODE on identical operands.  Take into account the possibility
+   of trapping if HONOR_NANS is nonzero and we are under -ftrapping-math,
+   and return -1 if this makes the transformation invalid.  */
+
+enum comparison_code
+combine_comparisons (enum tree_code lcode, enum tree_code rcode,
+		     enum tree_code code, bool honor_nans)
+{
+  enum comparison_code lcompcode = comparison_to_compcode (lcode);
+  enum comparison_code rcompcode = comparison_to_compcode (rcode);
+  enum comparison_code compcode;
+
+  switch (code)
+    {
+    case TRUTH_AND_EXPR: case TRUTH_ANDIF_EXPR:
+      compcode = lcompcode & rcompcode;
+      break;
+
+    case TRUTH_OR_EXPR: case TRUTH_ORIF_EXPR:
+      compcode = lcompcode | rcompcode;
+      break;
+
+    default:
+      return COMPCODE_INVALID;
+    }
+
+  if (!honor_nans)
+    {
+      /* Eliminate unordered comparisons, as well as LTGT and ORD
+	 which are not used unless the mode has NaNs.  */
+      compcode &= ~COMPCODE_UNORD;
+      if (compcode == COMPCODE_LTGT)
+	return COMPCODE_NE;
+      if (compcode == COMPCODE_ORD)
+	return COMPCODE_TRUE;
+    }
+   else if (flag_trapping_math)
+     {
+	/* Check that the original operation and the optimized ones will trap 
+	   under the same condition.  */
+	bool ltrap = (lcompcode & COMPCODE_UNORD) == 0
+		     && (lcompcode != COMPCODE_EQ)
+		     && (lcompcode != COMPCODE_ORD);
+	bool rtrap = (rcompcode & COMPCODE_UNORD) == 0
+		     && (rcompcode != COMPCODE_EQ)
+		     && (rcompcode != COMPCODE_ORD);
+	bool trap = (compcode & COMPCODE_UNORD) == 0
+		    && (compcode != COMPCODE_EQ)
+		    && (compcode != COMPCODE_ORD);
+
+        /* In a short-circuited boolean expression the LHS might be
+	   such that the RHS, if evaluated, will never trap.  For
+	   example, in (x == y) || (x < y), we evaluate the RHS only
+	   if neither x nor y is NaN.  (This is a mixed blessing: for
+	   example, the expression above will never trap, hence the
+	   optimization x <= y is invalid.)  */
+        if ((code == TRUTH_ORIF_EXPR && (lcompcode & COMPCODE_UNORD))
+            || (code == TRUTH_ANDIF_EXPR && !(lcompcode & COMPCODE_UNORD)))
+          rtrap = false;
+
+        /* If the comparison was short-circuited, and only the RHS
+	   trapped, we may now generate a spurious trap.  */
+	if (rtrap && !ltrap
+	    && (code == TRUTH_ANDIF_EXPR || code == TRUTH_ORIF_EXPR))
+	  return COMPCODE_INVALID;
+
+	/* If we changed the conditions that cause a trap, we lose.  */
+	if ((ltrap || rtrap) != trap)
+	  return COMPCODE_INVALID;
+      }
+
+  return compcode;
+}
+
 /* Return nonzero if CODE is a tree code that represents a truth value.  */
 
 static int
@@ -2698,21 +2839,19 @@ invert_truthvalue (tree arg)
   if (TREE_CODE_CLASS (code) == '<')
     {
       if (FLOAT_TYPE_P (TREE_TYPE (TREE_OPERAND (arg, 0)))
-	  && !flag_unsafe_math_optimizations
-	  && code != NE_EXPR
-	  && code != EQ_EXPR)
-	return build1 (TRUTH_NOT_EXPR, type, arg);
-      else if (code == UNORDERED_EXPR
-	       || code == ORDERED_EXPR
-	       || code == UNEQ_EXPR
-	       || code == UNLT_EXPR
-	       || code == UNLE_EXPR
-	       || code == UNGT_EXPR
-	       || code == UNGE_EXPR)
+	  && flag_trapping_math
+	  && code != ORDERED_EXPR && code != UNORDERED_EXPR
+	  && code != NE_EXPR && code != EQ_EXPR)
 	return build1 (TRUTH_NOT_EXPR, type, arg);
       else
-	return build2 (invert_tree_comparison (code), type,
-		       TREE_OPERAND (arg, 0), TREE_OPERAND (arg, 1));
+	{
+	  code = invert_tree_comparison (code, HONOR_NANS (TYPE_MODE (type)));
+	  if (code == ERROR_MARK)
+	    return build1 (TRUTH_NOT_EXPR, type, arg);
+	  else
+	    return fold (build2 (code, type,
+				 TREE_OPERAND (arg, 0), TREE_OPERAND (arg, 1)));
+	}
     }
 
   switch (code)
@@ -2721,14 +2860,14 @@ invert_truthvalue (tree arg)
       return fold_convert (type, build_int_2 (integer_zerop (arg), 0));
 
     case TRUTH_AND_EXPR:
-      return build2 (TRUTH_OR_EXPR, type,
-		     invert_truthvalue (TREE_OPERAND (arg, 0)),
-		     invert_truthvalue (TREE_OPERAND (arg, 1)));
+      return fold (build2 (TRUTH_OR_EXPR, type,
+			   invert_truthvalue (TREE_OPERAND (arg, 0)),
+			   invert_truthvalue (TREE_OPERAND (arg, 1))));
 
     case TRUTH_OR_EXPR:
-      return build2 (TRUTH_AND_EXPR, type,
-		     invert_truthvalue (TREE_OPERAND (arg, 0)),
-		     invert_truthvalue (TREE_OPERAND (arg, 1)));
+      return fold (build2 (TRUTH_AND_EXPR, type,
+			   invert_truthvalue (TREE_OPERAND (arg, 0)),
+			   invert_truthvalue (TREE_OPERAND (arg, 1))));
 
     case TRUTH_XOR_EXPR:
       /* Here we can invert either operand.  We invert the first operand
@@ -2737,37 +2876,37 @@ invert_truthvalue (tree arg)
 	 negation of the second operand.  */
 
       if (TREE_CODE (TREE_OPERAND (arg, 1)) == TRUTH_NOT_EXPR)
-	return build2 (TRUTH_XOR_EXPR, type, TREE_OPERAND (arg, 0),
-		       TREE_OPERAND (TREE_OPERAND (arg, 1), 0));
+	return fold (build2 (TRUTH_XOR_EXPR, type, TREE_OPERAND (arg, 0),
+			     TREE_OPERAND (TREE_OPERAND (arg, 1), 0)));
       else
-	return build2 (TRUTH_XOR_EXPR, type,
-		       invert_truthvalue (TREE_OPERAND (arg, 0)),
-		       TREE_OPERAND (arg, 1));
+	return fold (build2 (TRUTH_XOR_EXPR, type,
+			     invert_truthvalue (TREE_OPERAND (arg, 0)),
+			     TREE_OPERAND (arg, 1)));
 
     case TRUTH_ANDIF_EXPR:
-      return build2 (TRUTH_ORIF_EXPR, type,
-		     invert_truthvalue (TREE_OPERAND (arg, 0)),
-		     invert_truthvalue (TREE_OPERAND (arg, 1)));
+      return fold (build2 (TRUTH_ORIF_EXPR, type,
+			   invert_truthvalue (TREE_OPERAND (arg, 0)),
+			   invert_truthvalue (TREE_OPERAND (arg, 1))));
 
     case TRUTH_ORIF_EXPR:
-      return build2 (TRUTH_ANDIF_EXPR, type,
-		     invert_truthvalue (TREE_OPERAND (arg, 0)),
-		     invert_truthvalue (TREE_OPERAND (arg, 1)));
+      return fold (build2 (TRUTH_ANDIF_EXPR, type,
+			   invert_truthvalue (TREE_OPERAND (arg, 0)),
+			   invert_truthvalue (TREE_OPERAND (arg, 1))));
 
     case TRUTH_NOT_EXPR:
       return TREE_OPERAND (arg, 0);
 
     case COND_EXPR:
-      return build3 (COND_EXPR, type, TREE_OPERAND (arg, 0),
-		     invert_truthvalue (TREE_OPERAND (arg, 1)),
-		     invert_truthvalue (TREE_OPERAND (arg, 2)));
+      return fold (build3 (COND_EXPR, type, TREE_OPERAND (arg, 0),
+			   invert_truthvalue (TREE_OPERAND (arg, 1)),
+			   invert_truthvalue (TREE_OPERAND (arg, 2))));
 
     case COMPOUND_EXPR:
-      return build2 (COMPOUND_EXPR, type, TREE_OPERAND (arg, 0),
-		     invert_truthvalue (TREE_OPERAND (arg, 1)));
+      return fold (build2 (COMPOUND_EXPR, type, TREE_OPERAND (arg, 0),
+			   invert_truthvalue (TREE_OPERAND (arg, 1))));
 
     case NON_LVALUE_EXPR:
-      return invert_truthvalue (TREE_OPERAND (arg, 0));
+      return fold (non_lvalue (invert_truthvalue (TREE_OPERAND (arg, 0))));
 
     case NOP_EXPR:
       if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE)
@@ -2775,8 +2914,8 @@ invert_truthvalue (tree arg)
 
     case CONVERT_EXPR:
     case FLOAT_EXPR:
-      return build1 (TREE_CODE (arg), type,
-		     invert_truthvalue (TREE_OPERAND (arg, 0)));
+      return fold (build1 (TREE_CODE (arg), type,
+			   invert_truthvalue (TREE_OPERAND (arg, 0))));
 
     case BIT_AND_EXPR:
       if (!integer_onep (TREE_OPERAND (arg, 1)))
@@ -4011,9 +4150,6 @@ fold_truthop (enum tree_code code, tree 
   if (TREE_CODE_CLASS (lcode) != '<' || TREE_CODE_CLASS (rcode) != '<')
     return 0;
 
-  code = ((code == TRUTH_AND_EXPR || code == TRUTH_ANDIF_EXPR)
-	  ? TRUTH_AND_EXPR : TRUTH_OR_EXPR);
-
   ll_arg = TREE_OPERAND (lhs, 0);
   lr_arg = TREE_OPERAND (lhs, 1);
   rl_arg = TREE_OPERAND (rhs, 0);
@@ -4021,46 +4157,34 @@ fold_truthop (enum tree_code code, tree 
 
   /* Simplify (x<y) && (x==y) into (x<=y) and related optimizations.  */
   if (simple_operand_p (ll_arg)
-      && simple_operand_p (lr_arg)
-      && !FLOAT_TYPE_P (TREE_TYPE (ll_arg)))
+      && simple_operand_p (lr_arg))
     {
       int compcode;
-
       if (operand_equal_p (ll_arg, rl_arg, 0)
           && operand_equal_p (lr_arg, rr_arg, 0))
-        {
-          int lcompcode, rcompcode;
-
-          lcompcode = comparison_to_compcode (lcode);
-          rcompcode = comparison_to_compcode (rcode);
-          compcode = (code == TRUTH_AND_EXPR)
-                     ? lcompcode & rcompcode
-                     : lcompcode | rcompcode;
-        }
+        compcode =
+	  combine_comparisons (lcode, rcode, code,
+			       HONOR_NANS (TYPE_MODE (TREE_TYPE (ll_arg))));
       else if (operand_equal_p (ll_arg, rr_arg, 0)
                && operand_equal_p (lr_arg, rl_arg, 0))
-        {
-          int lcompcode, rcompcode;
-
-          rcode = swap_tree_comparison (rcode);
-          lcompcode = comparison_to_compcode (lcode);
-          rcompcode = comparison_to_compcode (rcode);
-          compcode = (code == TRUTH_AND_EXPR)
-                     ? lcompcode & rcompcode
-                     : lcompcode | rcompcode;
-        }
+        compcode =
+	  combine_comparisons (lcode, swap_tree_comparison (rcode), code,
+			       HONOR_NANS (TYPE_MODE (TREE_TYPE (ll_arg))));
       else
-	compcode = -1;
+	compcode = COMPCODE_INVALID;
 
       if (compcode == COMPCODE_TRUE)
 	return fold_convert (truth_type, integer_one_node);
       else if (compcode == COMPCODE_FALSE)
 	return fold_convert (truth_type, integer_zero_node);
-      else if (compcode != -1)
-	return build2 (compcode_to_comparison (compcode),
-		       truth_type, ll_arg, lr_arg);
+      else if (compcode != COMPCODE_INVALID)
+	return fold (build2 (compcode_to_comparison (compcode),
+			     truth_type, ll_arg, lr_arg));
     }
 
+  code = ((code == TRUTH_AND_EXPR || code == TRUTH_ANDIF_EXPR)
+	  ? TRUTH_AND_EXPR : TRUTH_OR_EXPR);
+
   /* If the RHS can be evaluated unconditionally and its operands are
      simple, it wins to evaluate the RHS unconditionally on machines
      with expensive branches.  In this case, this isn't a comparison
@@ -9856,7 +9980,7 @@ fold_relational_const (enum tree_code co
   if (code == NE_EXPR || code == GE_EXPR)
     {
       invert = 1;
-      code = invert_tree_comparison (code);
+      code = invert_tree_comparison (code, false);
     }
 
   /* Compute a result for LT or EQ if args permit;
Index: predict.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/predict.c,v
retrieving revision 1.104
diff -u -p -r1.104 predict.c
--- predict.c	13 May 2004 06:39:44 -0000	1.104
+++ predict.c	27 May 2004 09:02:52 -0000
@@ -865,6 +865,7 @@ tree_predict_by_opcode (basic_block bb)
 	break;
 
       case NE_EXPR:
+      case LTGT_EXPR:
 	/* Floating point comparisons appears to behave in a very
 	   unpredictable way because of special role of = tests in
 	   FP code.  */
Index: real.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/real.c,v
retrieving revision 1.141
diff -u -p -r1.141 real.c
--- real.c	22 Mar 2004 00:40:44 -0000	1.141
+++ real.c	27 May 2004 09:02:53 -0000
@@ -1080,6 +1080,8 @@ real_compare (int icode, const REAL_VALU
       return do_compare (op0, op1, 1) >= 0;
     case UNEQ_EXPR:
       return do_compare (op0, op1, 0) == 0;
+    case LTGT_EXPR:
+      return do_compare (op0, op1, 0) != 0;
 
     default:
       abort ();
Index: tree-cfg.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-cfg.c,v
retrieving revision 2.4
diff -u -p -r2.4 tree-cfg.c
--- tree-cfg.c	26 May 2004 22:36:49 -0000	2.4
+++ tree-cfg.c	27 May 2004 09:02:53 -0000
@@ -3194,6 +3194,7 @@ verify_expr (tree *tp, int *walk_subtree
     case UNGT_EXPR:
     case UNGE_EXPR:
     case UNEQ_EXPR:
+    case LTGT_EXPR:
     case PLUS_EXPR:
     case MINUS_EXPR:
     case MULT_EXPR:
Index: tree-inline.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-inline.c,v
retrieving revision 1.102
diff -u -p -r1.102 tree-inline.c
--- tree-inline.c	15 May 2004 23:07:51 -0000	1.102
+++ tree-inline.c	27 May 2004 09:02:53 -0000
@@ -1324,6 +1324,7 @@ estimate_num_insns_1 (tree *tp, int *wal
     case UNGT_EXPR:
     case UNGE_EXPR:
     case UNEQ_EXPR:
+    case LTGT_EXPR:
 
     case CONVERT_EXPR:
 
Index: tree-pretty-print.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-pretty-print.c,v
retrieving revision 2.2
diff -u -p -r2.2 tree-pretty-print.c
--- tree-pretty-print.c	15 May 2004 23:07:52 -0000	2.2
+++ tree-pretty-print.c	27 May 2004 09:02:54 -0000
@@ -905,6 +905,9 @@ dump_generic_node (pretty_printer *buffe
     case UNGT_EXPR:
     case UNGE_EXPR:
     case UNEQ_EXPR:
+    case LTGT_EXPR:
+    case ORDERED_EXPR:
+    case UNORDERED_EXPR:
       {
 	const char *op = op_symbol (node);
 	op0 = TREE_OPERAND (node, 0);
@@ -999,14 +1002,6 @@ dump_generic_node (pretty_printer *buffe
       pp_character (buffer, '>');
       break;
 
-    case UNORDERED_EXPR:
-      NIY;
-      break;
-
-    case ORDERED_EXPR:
-      NIY;
-      break;
-
     case IN_EXPR:
       NIY;
       break;
@@ -1681,6 +1676,14 @@ op_prio (tree op)
     case NE_EXPR:
       return 9;
 
+    case UNLT_EXPR:
+    case UNLE_EXPR:
+    case UNGT_EXPR:
+    case UNGE_EXPR:
+    case UNEQ_EXPR:
+    case LTGT_EXPR:
+    case ORDERED_EXPR:
+    case UNORDERED_EXPR:
     case LT_EXPR:
     case LE_EXPR:
     case GT_EXPR:
@@ -1786,28 +1789,41 @@ op_symbol (tree op)
     case BIT_AND_EXPR:
       return "&";
 
+    case ORDERED_EXPR:
+      return "ord";
+    case UNORDERED_EXPR:
+      return "unord";
+
     case EQ_EXPR:
-    case UNEQ_EXPR:
       return "==";
+    case UNEQ_EXPR:
+      return "u==";
 
     case NE_EXPR:
       return "!=";
 
     case LT_EXPR:
-    case UNLT_EXPR:
       return "<";
+    case UNLT_EXPR:
+      return "u<";
 
     case LE_EXPR:
-    case UNLE_EXPR:
       return "<=";
+    case UNLE_EXPR:
+      return "u<=";
 
     case GT_EXPR:
-    case UNGT_EXPR:
       return ">";
+    case UNGT_EXPR:
+      return "u>";
 
     case GE_EXPR:
-    case UNGE_EXPR:
       return ">=";
+    case UNGE_EXPR:
+      return "u>=";
+
+    case LTGT_EXPR:
+      return "<>";
 
     case LSHIFT_EXPR:
       return "<<";
Index: tree.def
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.def,v
retrieving revision 1.76
diff -u -p -r1.76 tree.def
--- tree.def	14 May 2004 02:32:58 -0000	1.76
+++ tree.def	27 May 2004 09:02:54 -0000
@@ -681,6 +681,9 @@ DEFTREECODE (UNGT_EXPR, "ungt_expr", '<'
 DEFTREECODE (UNGE_EXPR, "unge_expr", '<', 2)
 DEFTREECODE (UNEQ_EXPR, "uneq_expr", '<', 2)
 
+/* This is the reverse of uneq_expr.  */
+DEFTREECODE (LTGT_EXPR, "ltgt_expr", '<', 2)
+
 /* Operations for Pascal sets.  Not used now.  */
 DEFTREECODE (IN_EXPR, "in_expr", '2', 2)
 DEFTREECODE (SET_LE_EXPR, "set_le_expr", '<', 2)
Index: doc/c-tree.texi
===================================================================
RCS file: /cvs/gcc/gcc/gcc/doc/c-tree.texi,v
retrieving revision 1.54
diff -u -p -r1.54 c-tree.texi
--- doc/c-tree.texi	13 May 2004 06:40:23 -0000	1.54
+++ doc/c-tree.texi	27 May 2004 09:02:55 -0000
@@ -1745,6 +1745,12 @@ This macro returns the attributes on the
 @tindex GE_EXPR
 @tindex EQ_EXPR
 @tindex NE_EXPR
+@tindex UNLT_EXPR
+@tindex UNLE_EXPR
+@tindex UNGT_EXPR
+@tindex UNGE_EXPR
+@tindex UNEQ_EXPR
+@tindex LTGT_EXPR
 @tindex INIT_EXPR
 @tindex MODIFY_EXPR
 @tindex COMPONENT_REF
@@ -2106,6 +2112,39 @@ operators.  The first and second operand
 type or both of floating type.  The result type of these expressions
 will always be of integral or boolean type.
 
+Floating-point comparison may have a fourth possible outcome for a
+comparison, other than less, greater or equal: this is @dfn{unordered},
+and two floating-point values are unordered if one of them is
+a @dfn{not-a-number} (@dfn{NaN}) value.  In this case, all of these
+nodes will be false but @code{NE_EXPR}, and the first four of these
+nodes will also raise an invalid operation trap.
+
+@item ORDERED_EXPR
+@itemx UNORDERED_EXPR
+@item UNLT_EXPR
+@itemx UNLE_EXPR
+@itemx UNGT_EXPR
+@itemx UNGE_EXPR
+@itemx UNEQ_EXPR
+@itemx LTGT_EXPR
+
+These nodes represent other relational operations that are only used
+with floating types.
+
+If the outcome of the comparison is unordered, all of these special
+comparisons will be true but @code{ORDERED_EXPR} and @code{LTGT_EXPR}.
+Only @code{LTGT_EXPR} is expected to generate an invalid floating-point
+operation trap when the outcome is unordered.
+
+@code{ORDERED_EXPR} is true if neither of its operands is a NaN,
+while its negation @code{UNORDERED_EXPR} is true if at least one of
+its operands is a NaN.
+
+For floating operations, inverting one of the standard comparison nodes 
+will result in one of these nodes, with its name prefixed by
+@code{UN}---the only exception is @code{NE_EXPR}, whose negation is
+@code{LTGT_EXPR}.
+
 @item MODIFY_EXPR
 These nodes represent assignment.  The left-hand side is the first
 operand; the right-hand side is the second operand.  The left-hand side
Index: testsuite/gcc.dg/compare-fp-1.c
===================================================================
RCS file: testsuite/gcc.dg/compare-fp-1.c
diff -N testsuite/gcc.dg/compare-fp-1.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gcc.dg/compare-fp-1.c	27 May 2004 09:02:58 -0000
@@ -0,0 +1,192 @@
+/* { dg-do execute } */
+/* { dg-options "-w" } */
+
+/* Copyright (C) 2004 Free Software Foundation.
+
+   Test for correctness of composite floating-point comparisons.
+
+   Written by Paolo Bonzini, 26th May 2004.  */
+
+extern void abort (void);
+
+#define TEST(c) if ((c) != ok) abort ();
+#define ORD(a, b) (!__builtin_isunordered ((a), (b)))
+#define UNORD(a, b) (__builtin_isunordered ((a), (b)))
+#define UNEQ(a, b) (__builtin_isunordered ((a), (b)) || ((a) == (b)))
+#define UNLT(a, b) (__builtin_isunordered ((a), (b)) || ((a) < (b)))
+#define UNLE(a, b) (__builtin_isunordered ((a), (b)) || ((a) <= (b)))
+#define UNGT(a, b) (__builtin_isunordered ((a), (b)) || ((a) > (b)))
+#define UNGE(a, b) (__builtin_isunordered ((a), (b)) || ((a) >= (b)))
+#define LTGT(a, b) (__builtin_islessgreater ((a), (b)))
+
+float pinf;
+float ninf;
+float NaN;
+
+int iuneq (float x, float y, int ok)
+{
+  TEST (UNEQ (x, y));
+  TEST (!LTGT (x, y));
+  TEST (UNLE (x, y) && UNGE (x,y));
+}
+
+int ieq (float x, float y, int ok)
+{
+  TEST (ORD (x, y) && UNEQ (x, y));
+}
+
+int iltgt (float x, float y, int ok)
+{
+  TEST (!UNEQ (x, y)); /* Not optimizable. */
+  TEST (LTGT (x, y)); /* Same, __builtin_islessgreater does not trap. */
+  TEST (ORD (x, y) && (UNLT (x, y) || UNGT (x,y)));
+}
+
+int ine (float x, float y, int ok)
+{
+  TEST (UNLT (x, y) || UNGT (x, y));
+}
+
+int iunlt (float x, float y, int ok)
+{
+  TEST (UNLT (x, y));
+  TEST (UNORD (x, y) || (x < y));
+}
+
+int ilt (float x, float y, int ok)
+{
+  TEST (ORD (x, y) && UNLT (x, y)); /* Not optimized */
+  TEST ((x <= y) && (x != y));
+  TEST ((x <= y) && (y != x));
+  TEST ((x != y) && (x <= y)); /* Not optimized */
+  TEST ((y != x) && (x <= y)); /* Not optimized */
+}
+
+int iunle (float x, float y, int ok)
+{
+  TEST (UNLE (x, y));
+  TEST (UNORD (x, y) || (x <= y));
+}
+
+int ile (float x, float y, int ok)
+{
+  TEST (ORD (x, y) && UNLE (x, y)); /* Not optimized */
+  TEST ((x < y) || (x == y));
+  TEST ((y > x) || (x == y));
+  TEST ((x == y) || (x < y)); /* Not optimized */
+  TEST ((y == x) || (x < y)); /* Not optimized */
+}
+
+int iungt (float x, float y, int ok)
+{
+  TEST (UNGT (x, y));
+  TEST (UNORD (x, y) || (x > y));
+}
+
+int igt (float x, float y, int ok)
+{
+  TEST (ORD (x, y) && UNGT (x, y)); /* Not optimized */
+  TEST ((x >= y) && (x != y));
+  TEST ((x >= y) && (y != x));
+  TEST ((x != y) && (x >= y)); /* Not optimized */
+  TEST ((y != x) && (x >= y)); /* Not optimized */
+}
+
+int iunge (float x, float y, int ok)
+{
+  TEST (UNGE (x, y));
+  TEST (UNORD (x, y) || (x >= y));
+}
+
+int ige (float x, float y, int ok)
+{
+  TEST (ORD (x, y) && UNGE (x, y)); /* Not optimized */
+  TEST ((x > y) || (x == y));
+  TEST ((y < x) || (x == y));
+  TEST ((x == y) || (x > y)); /* Not optimized */
+  TEST ((y == x) || (x > y)); /* Not optimized */
+}
+
+int
+main ()
+{
+  pinf = __builtin_inf ();
+  ninf = -__builtin_inf ();
+  NaN = __builtin_nan ("");
+
+  iuneq (ninf, pinf, 0);
+  iuneq (NaN, NaN, 1);
+  iuneq (pinf, ninf, 0);
+  iuneq (1, 4, 0);
+  iuneq (3, 3, 1);
+  iuneq (5, 2, 0);
+
+  ieq (1, 4, 0);
+  ieq (3, 3, 1);
+  ieq (5, 2, 0);
+
+  iltgt (ninf, pinf, 1);
+  iltgt (NaN, NaN, 0);
+  iltgt (pinf, ninf, 1);
+  iltgt (1, 4, 1);
+  iltgt (3, 3, 0);
+  iltgt (5, 2, 1);
+
+  ine (1, 4, 1);
+  ine (3, 3, 0);
+  ine (5, 2, 1);
+
+  iunlt (NaN, ninf, 1);
+  iunlt (pinf, NaN, 1);
+  iunlt (pinf, ninf, 0);
+  iunlt (pinf, pinf, 0);
+  iunlt (ninf, ninf, 0);
+  iunlt (1, 4, 1);
+  iunlt (3, 3, 0);
+  iunlt (5, 2, 0);
+
+  ilt (1, 4, 1);
+  ilt (3, 3, 0);
+  ilt (5, 2, 0);
+
+  iunle (NaN, ninf, 1);
+  iunle (pinf, NaN, 1);
+  iunle (pinf, ninf, 0);
+  iunle (pinf, pinf, 1);
+  iunle (ninf, ninf, 1);
+  iunle (1, 4, 1);
+  iunle (3, 3, 1);
+  iunle (5, 2, 0);
+
+  ile (1, 4, 1);
+  ile (3, 3, 1);
+  ile (5, 2, 0);
+
+  iungt (NaN, ninf, 1);
+  iungt (pinf, NaN, 1);
+  iungt (pinf, ninf, 1);
+  iungt (pinf, pinf, 0);
+  iungt (ninf, ninf, 0);
+  iungt (1, 4, 0);
+  iungt (3, 3, 0);
+  iungt (5, 2, 1);
+
+  igt (1, 4, 0);
+  igt (3, 3, 0);
+  igt (5, 2, 1);
+
+  iunge (NaN, ninf, 1);
+  iunge (pinf, NaN, 1);
+  iunge (ninf, pinf, 0);
+  iunge (pinf, pinf, 1);
+  iunge (ninf, ninf, 1);
+  iunge (1, 4, 0);
+  iunge (3, 3, 1);
+  iunge (5, 2, 1);
+
+  ige (1, 4, 0);
+  ige (3, 3, 1);
+  ige (5, 2, 1);
+
+  return 0;
+}
Index: testsuite/gcc.dg/compare-fp-2.c
===================================================================
RCS file: testsuite/gcc.dg/compare-fp-2.c
diff -N testsuite/gcc.dg/compare-fp-2.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gcc.dg/compare-fp-2.c	27 May 2004 09:02:58 -0000
@@ -0,0 +1,26 @@
+/* { dg-do execute } */
+
+/* Copyright (C) 2004 Free Software Foundation.
+
+   Ensure that the composite comparison optimization doesn't misfire
+   and attempt to combine an integer comparison with a floating-point one.
+
+   Written by Paolo Bonzini, 26th May 2004.  */
+
+extern void abort (void);
+
+int
+foo (double x, double y)
+{
+  /* If miscompiled the following may become false.  */
+  return (x > y) && ((int)x == (int)y);
+}
+
+int
+main ()
+{
+  if (! foo (1.3,1.0))
+    abort ();
+  return 0;
+}
+
Index: testsuite/gcc.dg/compare-fp-3.c
===================================================================
RCS file: testsuite/gcc.dg/compare-fp-3.c
diff -N testsuite/gcc.dg/compare-fp-3.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gcc.dg/compare-fp-3.c	27 May 2004 09:02:58 -0000
@@ -0,0 +1,100 @@
+/* { dg-do execute } */
+/* { dg-options "-fno-trapping-math" } */
+
+/* Copyright (C) 2004 Free Software Foundation.
+
+   Test for composite comparison always true/false optimization.
+
+   Written by Paolo Bonzini, 26th May 2004.  */
+
+extern void link_error0 ();
+extern void link_error1 ();
+
+void
+test1 (float x, float y)
+{
+  if ((x==y) && (x!=y))
+    link_error0();
+}
+
+void
+test2 (float x, float y)
+{
+  if ((x<y) && (x>y))
+    link_error0();
+}
+
+void
+test3 (float x, float y)
+{
+  if ((x<y) && (y<x))
+    link_error0();
+}
+
+void 
+test4 (float x, float y)
+{
+  if ((x==y) || (x!=y))
+    {
+    }
+  else
+    link_error1 ();
+}
+
+void
+test5 (float x, float y)
+{
+  if (__builtin_isunordered (x, y) || (x>=y) || (x<y))
+    {
+    }
+  else
+    link_error1 ();
+}
+
+void
+test6 (float x, float y)
+{
+  if (__builtin_isunordered (y, x) || (x<=y) || (y<x))
+    {
+    }
+  else
+    link_error1 ();
+}
+
+void
+test7 (float x, float y)
+{
+  if (__builtin_isunordered (x, y) || !__builtin_isunordered (x, y))
+    {
+    }
+  else
+    link_error1 ();
+}
+
+void
+all_tests (float x, float y)
+{
+  test1 (x, y);
+  test2 (x, y);
+  test3 (x, y);
+  test4 (x, y);
+  test5 (x, y);
+  test6 (x, y);
+  test7 (x, y);
+}
+
+int
+main ()
+{
+  all_tests (0, 0);
+  all_tests (1, 2);
+  all_tests (4, 3);
+
+  return 0;
+}
+
+#ifndef __OPTIMIZE__
+void link_error0() {}
+void link_error1() {}
+#endif /* ! __OPTIMIZE__ */
+
Index: testsuite/gcc.dg/compare-fp-4.c
===================================================================
RCS file: testsuite/gcc.dg/compare-fp-4.c
diff -N testsuite/gcc.dg/compare-fp-4.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gcc.dg/compare-fp-4.c	27 May 2004 09:02:58 -0000
@@ -0,0 +1,193 @@
+/* { dg-do execute } */
+/* { dg-options "-w -fno-trapping-math" } */
+
+/* Copyright (C) 2004 Free Software Foundation.
+
+   Test for correctness of composite floating-point comparisons.
+
+   Written by Paolo Bonzini, 26th May 2004.  */
+
+extern void abort (void);
+
+#define TEST(c) if ((c) != ok) abort ();
+#define ORD(a, b) (((a) < (b)) || (a) >= (b))
+#define UNORD(a, b) (!ORD ((a), (b)))
+#define UNEQ(a, b) (!LTGT ((a), (b)))
+#define UNLT(a, b) (((a) < (b)) || __builtin_isunordered ((a), (b)))
+#define UNLE(a, b) (((a) <= (b)) || __builtin_isunordered ((a), (b)))
+#define UNGT(a, b) (((a) > (b)) || __builtin_isunordered ((a), (b)))
+#define UNGE(a, b) (((a) >= (b)) || __builtin_isunordered ((a), (b)))
+#define LTGT(a, b) (((a) < (b)) || (a) > (b))
+
+float pinf;
+float ninf;
+float NaN;
+
+int iuneq (float x, float y, int ok)
+{
+  TEST (UNEQ (x, y));
+  TEST (!LTGT (x, y));
+  TEST (UNLE (x, y) && UNGE (x,y));
+}
+
+int ieq (float x, float y, int ok)
+{
+  TEST (ORD (x, y) && UNEQ (x, y));
+}
+
+int iltgt (float x, float y, int ok)
+{
+  TEST (!UNEQ (x, y));
+  TEST (LTGT (x, y));
+  TEST (ORD (x, y) && (UNLT (x, y) || UNGT (x,y)));
+}
+
+int ine (float x, float y, int ok)
+{
+  TEST (UNLT (x, y) || UNGT (x, y));
+  TEST ((x < y) || (x > y) || UNORD (x, y));
+}
+
+int iunlt (float x, float y, int ok)
+{
+  TEST (UNLT (x, y));
+  TEST (UNORD (x, y) || (x < y));
+}
+
+int ilt (float x, float y, int ok)
+{
+  TEST (ORD (x, y) && UNLT (x, y));
+  TEST ((x <= y) && (x != y));
+  TEST ((x <= y) && (y != x));
+  TEST ((x != y) && (x <= y));
+  TEST ((y != x) && (x <= y));
+}
+
+int iunle (float x, float y, int ok)
+{
+  TEST (UNLE (x, y));
+  TEST (UNORD (x, y) || (x <= y));
+}
+
+int ile (float x, float y, int ok)
+{
+  TEST (ORD (x, y) && UNLE (x, y));
+  TEST ((x < y) || (x == y));
+  TEST ((y > x) || (x == y));
+  TEST ((x == y) || (x < y));
+  TEST ((y == x) || (x < y));
+}
+
+int iungt (float x, float y, int ok)
+{
+  TEST (UNGT (x, y));
+  TEST (UNORD (x, y) || (x > y));
+}
+
+int igt (float x, float y, int ok)
+{
+  TEST (ORD (x, y) && UNGT (x, y));
+  TEST ((x >= y) && (x != y));
+  TEST ((x >= y) && (y != x));
+  TEST ((x != y) && (x >= y));
+  TEST ((y != x) && (x >= y));
+}
+
+int iunge (float x, float y, int ok)
+{
+  TEST (UNGE (x, y));
+  TEST (UNORD (x, y) || (x >= y));
+}
+
+int ige (float x, float y, int ok)
+{
+  TEST (ORD (x, y) && UNGE (x, y));
+  TEST ((x > y) || (x == y));
+  TEST ((y < x) || (x == y));
+  TEST ((x == y) || (x > y));
+  TEST ((y == x) || (x > y));
+}
+
+int
+main ()
+{
+  pinf = __builtin_inf ();
+  ninf = -__builtin_inf ();
+  NaN = __builtin_nan ("");
+
+  iuneq (ninf, pinf, 0);
+  iuneq (NaN, NaN, 1);
+  iuneq (pinf, ninf, 0);
+  iuneq (1, 4, 0);
+  iuneq (3, 3, 1);
+  iuneq (5, 2, 0);
+
+  ieq (1, 4, 0);
+  ieq (3, 3, 1);
+  ieq (5, 2, 0);
+
+  iltgt (ninf, pinf, 1);
+  iltgt (NaN, NaN, 0);
+  iltgt (pinf, ninf, 1);
+  iltgt (1, 4, 1);
+  iltgt (3, 3, 0);
+  iltgt (5, 2, 1);
+
+  ine (1, 4, 1);
+  ine (3, 3, 0);
+  ine (5, 2, 1);
+
+  iunlt (NaN, ninf, 1);
+  iunlt (pinf, NaN, 1);
+  iunlt (pinf, ninf, 0);
+  iunlt (pinf, pinf, 0);
+  iunlt (ninf, ninf, 0);
+  iunlt (1, 4, 1);
+  iunlt (3, 3, 0);
+  iunlt (5, 2, 0);
+
+  ilt (1, 4, 1);
+  ilt (3, 3, 0);
+  ilt (5, 2, 0);
+
+  iunle (NaN, ninf, 1);
+  iunle (pinf, NaN, 1);
+  iunle (pinf, ninf, 0);
+  iunle (pinf, pinf, 1);
+  iunle (ninf, ninf, 1);
+  iunle (1, 4, 1);
+  iunle (3, 3, 1);
+  iunle (5, 2, 0);
+
+  ile (1, 4, 1);
+  ile (3, 3, 1);
+  ile (5, 2, 0);
+
+  iungt (NaN, ninf, 1);
+  iungt (pinf, NaN, 1);
+  iungt (pinf, ninf, 1);
+  iungt (pinf, pinf, 0);
+  iungt (ninf, ninf, 0);
+  iungt (1, 4, 0);
+  iungt (3, 3, 0);
+  iungt (5, 2, 1);
+
+  igt (1, 4, 0);
+  igt (3, 3, 0);
+  igt (5, 2, 1);
+
+  iunge (NaN, ninf, 1);
+  iunge (pinf, NaN, 1);
+  iunge (ninf, pinf, 0);
+  iunge (pinf, pinf, 1);
+  iunge (ninf, ninf, 1);
+  iunge (1, 4, 0);
+  iunge (3, 3, 1);
+  iunge (5, 2, 1);
+
+  ige (1, 4, 0);
+  ige (3, 3, 1);
+  ige (5, 2, 1);
+
+  return 0;
+}
Index: testsuite/gcc.dg/pr15649-1.c
===================================================================
RCS file: testsuite/gcc.dg/pr15649-1.c
diff -N testsuite/gcc.dg/pr15649-1.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gcc.dg/pr15649-1.c	27 May 2004 09:02:58 -0000
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+
+double foo (double x)
+{
+  return __builtin_isgreater (x, 0.0) ? 0.0 : x;
+}


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