OSDN Git Service

* fold-const.c (fold_inf_compare): New function to simplify FP
authorsayle <sayle@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 28 Mar 2003 02:41:14 +0000 (02:41 +0000)
committersayle <sayle@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 28 Mar 2003 02:41:14 +0000 (02:41 +0000)
comparisons against +Infinity or -Infinity.
(fold):  Optimize floating point comparisons against Infs and NaNs.

* gcc.c-torture/execute/ieee/fp-cmp-6.c: New test case.
* gcc.c-torture/execute/ieee/fp-cmp-7.c: New test case.

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

gcc/ChangeLog
gcc/fold-const.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.c-torture/execute/ieee/fp-cmp-6.c [new file with mode: 0644]
gcc/testsuite/gcc.c-torture/execute/ieee/fp-cmp-7.c [new file with mode: 0644]

index 93c1921..80acf51 100644 (file)
@@ -1,3 +1,9 @@
+2003-03-27  Roger Sayle  <roger@eyesopen.com>
+
+       * fold-const.c (fold_inf_compare):  New function to simplify FP
+       comparisons against +Infinity or -Infinity.
+       (fold):  Optimize floating point comparisons against Infs and NaNs.
+
 2003-03-27  Janis Johnson  <janis187@us.ibm.com>
 
        * libgcov.c: Provide only dummy functions if libc is not available.
index 0f9f3d4..6e17e00 100644 (file)
@@ -114,6 +114,7 @@ static tree fold_binary_op_with_conditional_arg
 static bool fold_real_zero_addition_p  PARAMS ((tree, tree, int));
 static tree fold_mathfn_compare        PARAMS ((enum built_in_function,
                                         enum tree_code, tree, tree, tree));
+static tree fold_inf_compare   PARAMS ((enum tree_code, tree, tree, tree));
 
 /* The following constants represent a bit based encoding of GCC's
    comparison operators.  This encoding simplifies transformations
@@ -4798,6 +4799,62 @@ fold_mathfn_compare (fcode, code, type, arg0, arg1)
   return NULL_TREE;
 }
 
+/* Subroutine of fold() that optimizes comparisons against Infinities,
+   either +Inf or -Inf.
+
+   CODE is the comparison operator: EQ_EXPR, NE_EXPR, GT_EXPR, LT_EXPR,
+   GE_EXPR or LE_EXPR.  TYPE is the type of the result and ARG0 and ARG1
+   are the operands of the comparison.  ARG1 must be a TREE_REAL_CST.
+
+   The function returns the constant folded tree if a simplification
+   can be made, and NULL_TREE otherwise.  */
+
+static tree
+fold_inf_compare (code, type, arg0, arg1)
+     enum tree_code code;
+     tree type, arg0, arg1;
+{
+  /* For negative infinity swap the sense of the comparison.  */
+  if (REAL_VALUE_NEGATIVE (TREE_REAL_CST (arg1)))
+    code = swap_tree_comparison (code);
+
+  switch (code)
+    {
+    case GT_EXPR:
+      /* x > +Inf is always false, if with ignore sNANs.  */
+      if (HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg0))))
+        return NULL_TREE;
+      return omit_one_operand (type,
+                              convert (type, integer_zero_node),
+                              arg0);
+
+    case LE_EXPR:
+      /* x <= +Inf is always true, if we don't case about NaNs.  */
+      if (! HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0))))
+       return omit_one_operand (type,
+                                convert (type, integer_one_node),
+                                arg0);
+
+      /* x <= +Inf is the same as x == x, i.e. isfinite(x).  */
+      if ((*lang_hooks.decls.global_bindings_p) () == 0
+         && ! contains_placeholder_p (arg0))
+       {
+         arg0 = save_expr (arg0);
+         return fold (build (EQ_EXPR, type, arg0, arg0));
+       }
+      break;
+
+    case EQ_EXPR:  /* ??? x == +Inf is x > DBL_MAX  */
+    case GE_EXPR:  /* ??? x >= +Inf is x > DBL_MAX  */
+    case LT_EXPR:  /* ??? x < +Inf is x <= DBL_MAX  */
+    case NE_EXPR:  /* ??? x != +Inf is !(x > DBL_MAX)  */
+
+    default:
+      break;
+    }
+
+  return NULL_TREE;
+}
 
 /* Perform constant folding and related simplification of EXPR.
    The related simplifications include x*1 => x, x*0 => 0, etc.,
@@ -6317,20 +6374,42 @@ fold (expr)
              && TREE_CODE (arg1) == NEGATE_EXPR)
            return fold (build (code, type, TREE_OPERAND (arg1, 0),
                                TREE_OPERAND (arg0, 0)));
-         /* (-a) CMP CST -> a swap(CMP) (-CST)  */
-         if (TREE_CODE (arg0) == NEGATE_EXPR && TREE_CODE (arg1) == REAL_CST)
-           return
-             fold (build
-                   (swap_tree_comparison (code), type,
-                    TREE_OPERAND (arg0, 0),
-                    build_real (TREE_TYPE (arg1),
-                                REAL_VALUE_NEGATE (TREE_REAL_CST (arg1)))));
-         /* IEEE doesn't distinguish +0 and -0 in comparisons.  */
-         /* a CMP (-0) -> a CMP 0  */
-         if (TREE_CODE (arg1) == REAL_CST
-             && REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (arg1)))
-           return fold (build (code, type, arg0,
-                               build_real (TREE_TYPE (arg1), dconst0)));
+
+         if (TREE_CODE (arg1) == REAL_CST)
+         {
+           REAL_VALUE_TYPE cst;
+           cst = TREE_REAL_CST (arg1);
+
+           /* (-a) CMP CST -> a swap(CMP) (-CST)  */
+           if (TREE_CODE (arg0) == NEGATE_EXPR)
+             return
+               fold (build (swap_tree_comparison (code), type,
+                            TREE_OPERAND (arg0, 0),
+                            build_real (TREE_TYPE (arg1),
+                                        REAL_VALUE_NEGATE (cst))));
+
+           /* IEEE doesn't distinguish +0 and -0 in comparisons.  */
+           /* a CMP (-0) -> a CMP 0  */
+           if (REAL_VALUE_MINUS_ZERO (cst))
+             return fold (build (code, type, arg0,
+                                 build_real (TREE_TYPE (arg1), dconst0)));
+
+           /* x != NaN is always true, other ops are always false.  */
+           if (REAL_VALUE_ISNAN (cst)
+               && ! HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg1))))
+             {
+               t = (code == NE_EXPR) ? integer_one_node : integer_zero_node;
+               return omit_one_operand (type, convert (type, t), arg0);
+             }
+
+           /* Fold comparisons against infinity.  */
+           if (REAL_VALUE_ISINF (cst))
+             {
+               tem = fold_inf_compare (code, type, arg0, arg1);
+               if (tem != NULL_TREE)
+                 return tem;
+             }
+         }
 
          /* If this is a comparison of a real constant with a PLUS_EXPR
             or a MINUS_EXPR of a real constant, we can convert it into a
index c438ad3..f9d63b2 100644 (file)
@@ -1,3 +1,8 @@
+2003-03-27  Roger Sayle  <roger@eyesopen.com>
+
+       * gcc.c-torture/execute/ieee/fp-cmp-6.c: New test case.
+       * gcc.c-torture/execute/ieee/fp-cmp-7.c: New test case.
+
 2003-03-27  Mark Mitchell  <mark@codesourcery.com>
 
        * lib/gcov.exp (run-gcov): Add branches and calls options, rather
diff --git a/gcc/testsuite/gcc.c-torture/execute/ieee/fp-cmp-6.c b/gcc/testsuite/gcc.c-torture/execute/ieee/fp-cmp-6.c
new file mode 100644 (file)
index 0000000..9111d6e
--- /dev/null
@@ -0,0 +1,31 @@
+
+const double dnan = 1.0/0.0 - 1.0/0.0;
+double x = 1.0;
+
+extern void link_error ();
+
+main ()
+{
+#if ! defined (__vax__) && ! defined (_CRAY)
+  /* NaN is an IEEE unordered operand.  All these test should be false.  */
+  if (dnan == dnan)
+    link_error ();
+  if (dnan != x)
+    x = 1.0;
+  else
+    link_error ();
+
+  if (dnan < x)
+    link_error ();
+  if (dnan > x)
+    link_error ();
+  if (dnan <= x)
+    link_error ();
+  if (dnan >= x)
+    link_error ();
+  if (dnan == x)
+    link_error ();
+#endif
+  exit (0);
+}
+
diff --git a/gcc/testsuite/gcc.c-torture/execute/ieee/fp-cmp-7.c b/gcc/testsuite/gcc.c-torture/execute/ieee/fp-cmp-7.c
new file mode 100644 (file)
index 0000000..385acaf
--- /dev/null
@@ -0,0 +1,14 @@
+extern void link_error ();
+
+void foo(double x)
+{
+  if (x > __builtin_inf())
+    link_error ();
+}
+
+int main ()
+{
+  foo (1.0);
+  return 0;
+}
+