fold-const.c (fold_mathfn_compare): New function to simplify comparisons against...
authorRoger Sayle <sayle@gcc.gnu.org>
Thu, 20 Mar 2003 17:48:26 +0000 (17:48 +0000)
committerRoger Sayle <sayle@gcc.gnu.org>
Thu, 20 Mar 2003 17:48:26 +0000 (17:48 +0000)
* fold-const.c (fold_mathfn_compare): New function to simplify
comparisons against built-in math functions.  Fold comparisons
of sqrt against constants.
(fold): Call fold_mathfn_compare when appropriate.

* gcc.dg/builtins-6.c: New test case.

From-SVN: r64619

gcc/ChangeLog
gcc/fold-const.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/builtins-6.c [new file with mode: 0644]

index 7ac8fc88f071feaa0a8b516c4eeb49715ae53ae8..2b16b1b95f94f2e7cd79b12d0d014df1aac49585 100644 (file)
@@ -1,3 +1,10 @@
+2003-03-20  Roger Sayle  <roger@eyesopen.com>
+
+       * fold-const.c (fold_mathfn_compare): New function to simplify
+       comparisons against built-in math functions.  Fold comparisons
+       of sqrt against constants.
+       (fold): Call fold_mathfn_compare when appropriate.
+
 2003-03-20 Richard Earnshaw  <rearnsha@arm.com>
 
        * ifcvt.c (find_if_case_1): If we add a new bb, update the dominance
@@ -1542,24 +1549,24 @@ Sat Mar  8 14:13:35 CET 2003  Jan Hubicka  <jh@suse.cz>
        MEM, try loading the MEM into a register and taking the low-part
        of that, to help CSE see the use of the MEM in its true mode.
 
-2002-03-05  Tom Tromey  <tromey@redhat.com>
+2003-03-05  Tom Tromey  <tromey@redhat.com>
 
        * config/stormy16/stormy16.h (DWARF_LINE_MIN_INSTR_LENGTH):
        Define.
 
-2002-03-05  Nick Clifton  <nickc@cambridge.redhat.com>
+2003-03-05  Nick Clifton  <nickc@cambridge.redhat.com>
 
        * config/stormy16/stormy16.md ("*eqbranchsi"): Remove '+' on
        operand 2.
        ("*ineqbranchsi"): Likewise.
 
-2002-03-05  Andrew Haley  <aph@cambridge.redhat.com>
+2003-03-05  Andrew Haley  <aph@cambridge.redhat.com>
 
        * config/stormy16/stormy16.c (xstormy16_expand_prologue): Delete
        mem_fake_push_rtx.  Instead construct a SEQUENCE to show the
        register store followed by a stack increment.
 
-2002-03-05  Chris Moller  <cmoller@redhat.com>
+2003-03-05  Chris Moller  <cmoller@redhat.com>
 
        * config/stormy16/stormy16.c (REG_NEEDS_SAVE): added a term
        to inhibit saving CARRY_REGS.
@@ -2328,7 +2335,7 @@ Mon Mar  3 19:07:21 CET 2003  Jan Hubicka  <jh@suse.cz>
        (*tst_extzv_memqi_1_n): Likewise.
        (a peephole2): New.
 
-2002-02-28  Richard Sandiford  <rsandifo@redhat.com>
+2003-02-28  Richard Sandiford  <rsandifo@redhat.com>
 
        * config/mips/mips.h (CRT_CALL_STATIC_FUNCTION): Wrap in
        #ifndef __mips16.
@@ -4123,7 +4130,7 @@ Sun Feb  9 23:54:59 CET 2003  Jan Hubicka  <jh@suse.cz>
        simplify_binary_operation):  Deal with vector modes
        (simplify_ternary_operation):  Deal with no-op VEC_MERGE.
 
-2002-02-09  Richard Sandiford  <rsandifo@redhat.com>
+2003-02-09  Richard Sandiford  <rsandifo@redhat.com>
 
        * toplev.c (rest_of_compilation): Recompute register usage after
        split_all_insns.
@@ -4489,7 +4496,7 @@ Wed Feb  5 23:12:57 CET 2003  Jan Hubicka  <jh@suse.cz>
        * config/ia64/unwind-ia64.c: include coretypes.h, tm.h to get
          config/ia64/linux.h
 
-2002-02-05  Roger Sayle  <roger@eyesopen.com>
+2003-02-05  Roger Sayle  <roger@eyesopen.com>
 
        * cfgloop.h (flow_bb_inside_loop_p): Correct prototype again.
 
@@ -4605,7 +4612,7 @@ Mon Feb  3 21:19:11 CET 2003  Jan Hubicka  <jh@suse.cz>
        (movups/movupd/movdqu patterns): Force one of operands to not be
        memory.
 
-2002-02-03  Roger Sayle  <roger@eyesopen.com>
+2003-02-03  Roger Sayle  <roger@eyesopen.com>
 
        * hooks.c (hook_rtx_rtx_identity): Generic hook function that
        takes a single rtx and returns it unmodified.
@@ -5624,11 +5631,11 @@ Sat Jan 25 21:04:33 CET 2003  Jan Hubicka  <jh@suse.cz>
        * config/h8300/h8300.c (h8300_shift_needs_scratch_p): Update a
        comment.
 
-2002-01-25  Richard Henderson  <rth@redhat.com>
+2003-01-25  Richard Henderson  <rth@redhat.com>
 
        * config/m68k/m68k-none.h (ASM_SPEC): Adjust inter-option spacing.
 
-2002-01-25  Kelley Cook <kelleycook@comcast.net>
+2003-01-25  Kelley Cook <kelleycook@comcast.net>
 
        * ggc-simple.c (debug_ggc_tree): Add PTR cast.
 
@@ -5646,7 +5653,7 @@ Sat Jan 25 21:04:33 CET 2003  Jan Hubicka  <jh@suse.cz>
        2002-02-19  Robert Lipe  <robertlipe@usa.net>
        * config/i386/t-sco5gas: (CRTSTUFF_T_CFLAGS_S): Delete -mcoff.
 
-2002-01-25  Roger Sayle  <roger@eyesopen.com>
+2003-01-25  Roger Sayle  <roger@eyesopen.com>
 
        * builtins.c (purge_builtin_constant_p): Scan insn stream
        sequentially rather than by basic block.
@@ -5656,7 +5663,7 @@ Sat Jan 25 21:04:33 CET 2003  Jan Hubicka  <jh@suse.cz>
 
        * combine.c (simplify_comparison, case AND): Remove a redundant test.
 
-2002-01-25  Roger Sayle  <roger@eyesopen.com>
+2003-01-25  Roger Sayle  <roger@eyesopen.com>
 
        * function.h (struct function): New field calls_constant_p.
        (current_function_calls_constant_p): New macro for above.
@@ -5668,7 +5675,7 @@ Sat Jan 25 21:04:33 CET 2003  Jan Hubicka  <jh@suse.cz>
        * integrate.c (expand_inline_function): Set calls_constant_p if
        the function being inlined has calls_constant_p set.
 
-2002-01-25  Roger Sayle  <roger@eyesopen.com>
+2003-01-25  Roger Sayle  <roger@eyesopen.com>
 
        * cse.c (fold_rtx): Instantiate CONSTANT_P_RTX to 0 when not
        optimizing, even if flag_gcse is true.
@@ -5728,7 +5735,7 @@ Sat Jan 25 11:10:03 CET 2003  Jan Hubicka  <jh@suse.cz>
 
        * builtins.c (fold_trunc_transparent_mathfn):  Undo accidental commit.
 
-2002-01-24  Stuart Hastings  <stuart@apple.com>
+2003-01-24  Stuart Hastings  <stuart@apple.com>
 
        * config/i386/i386.c (x86_output_mi_thunk): Add Darwin/x86 support.
 
index 4890c173e816fa1f5d80397e549dd34b60cb2d29..74772690c310edb0dce4e49b6da9ad6468dc8d85 100644 (file)
@@ -112,6 +112,8 @@ static int count_cond               PARAMS ((tree, int));
 static tree fold_binary_op_with_conditional_arg
   PARAMS ((enum tree_code, tree, tree, tree, int));
 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));
 
 /* The following constants represent a bit based encoding of GCC's
    comparison operators.  This encoding simplifies transformations
@@ -4661,6 +4663,144 @@ fold_real_zero_addition_p (type, addend, negate)
   return negate && !HONOR_SIGN_DEPENDENT_ROUNDING (TYPE_MODE (type));
 }
 
+/* Subroutine of fold() that checks comparisons of built-in math
+   functions against real constants.
+
+   FCODE is the DECL_FUNCTION_CODE of the built-in, 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_mathfn_compare (fcode, code, type, arg0, arg1)
+     enum built_in_function fcode;
+     enum tree_code code;
+     tree type, arg0, arg1;
+{
+  REAL_VALUE_TYPE c;
+
+  if (fcode == BUILT_IN_SQRT
+      || fcode == BUILT_IN_SQRTF
+      || fcode == BUILT_IN_SQRTL)
+    {
+      tree arg = TREE_VALUE (TREE_OPERAND (arg0, 1));
+      enum machine_mode mode = TYPE_MODE (TREE_TYPE (arg0));
+
+      c = TREE_REAL_CST (arg1);
+      if (REAL_VALUE_NEGATIVE (c))
+       {
+         /* sqrt(x) < y is always false, if y is negative.  */
+         if (code == EQ_EXPR || code == LT_EXPR || code == LE_EXPR)
+           return omit_one_operand (type,
+                                    convert (type, integer_zero_node),
+                                    arg);
+
+         /* sqrt(x) > y is always true, if y is negative and we
+            don't care about NaNs, i.e. negative values of x.  */
+         if (code == NE_EXPR || !HONOR_NANS (mode))
+           return omit_one_operand (type,
+                                    convert (type, integer_one_node),
+                                    arg);
+
+         /* sqrt(x) > y is the same as x >= 0, if y is negative.  */
+         return fold (build (GE_EXPR, type, arg,
+                             build_real (TREE_TYPE (arg), dconst0)));
+       }
+      else if (code == GT_EXPR || code == GE_EXPR)
+       {
+         REAL_VALUE_TYPE c2;
+
+         REAL_ARITHMETIC (c2, MULT_EXPR, c, c);
+         real_convert (&c2, mode, &c2);
+
+         if (REAL_VALUE_ISINF (c2))
+           {
+             /* sqrt(x) > y is x == +Inf, when y is very large.  */
+             if (HONOR_INFINITIES (mode))
+               return fold (build (EQ_EXPR, type, arg,
+                                   build_real (TREE_TYPE (arg), c2)));
+
+             /* sqrt(x) > y is always false, when y is very large
+                and we don't care about infinities.  */
+             return omit_one_operand (type,
+                                      convert (type, integer_zero_node),
+                                      arg);
+           }
+
+         /* sqrt(x) > c is the same as x > c*c.  */
+         return fold (build (code, type, arg,
+                             build_real (TREE_TYPE (arg), c2)));
+       }
+      else if (code == LT_EXPR || code == LE_EXPR)
+       {
+         REAL_VALUE_TYPE c2;
+
+         REAL_ARITHMETIC (c2, MULT_EXPR, c, c);
+         real_convert (&c2, mode, &c2);
+
+         if (REAL_VALUE_ISINF (c2))
+           {
+             /* sqrt(x) < y is always true, when y is a very large
+                value and we don't care about NaNs or Infinities.  */
+             if (! HONOR_NANS (mode) && ! HONOR_INFINITIES (mode))
+               return omit_one_operand (type,
+                                        convert (type, integer_one_node),
+                                        arg);
+
+             /* sqrt(x) < y is x != +Inf when y is very large and we
+                don't care about NaNs.  */
+             if (! HONOR_NANS (mode))
+               return fold (build (NE_EXPR, type, arg,
+                                   build_real (TREE_TYPE (arg), c2)));
+
+             /* sqrt(x) < y is x >= 0 when y is very large and we
+                don't care about Infinities.  */
+             if (! HONOR_INFINITIES (mode))
+               return fold (build (GE_EXPR, type, arg,
+                                   build_real (TREE_TYPE (arg), dconst0)));
+
+             /* sqrt(x) < y is x >= 0 && x != +Inf, when y is large.  */
+             if ((*lang_hooks.decls.global_bindings_p) () != 0
+                 || contains_placeholder_p (arg))
+               return NULL_TREE;
+
+             arg = save_expr (arg);
+             return fold (build (TRUTH_ANDIF_EXPR, type,
+                                 fold (build (GE_EXPR, type, arg,
+                                              build_real (TREE_TYPE (arg),
+                                                          dconst0))),
+                                 fold (build (NE_EXPR, type, arg,
+                                              build_real (TREE_TYPE (arg),
+                                                          c2)))));
+           }
+
+         /* sqrt(x) < c is the same as x < c*c, if we ignore NaNs.  */
+         if (! HONOR_NANS (mode))
+           return fold (build (code, type, arg,
+                               build_real (TREE_TYPE (arg), c2)));
+
+         /* sqrt(x) < c is the same as x >= 0 && x < c*c.  */
+         if ((*lang_hooks.decls.global_bindings_p) () == 0
+             && ! contains_placeholder_p (arg))
+           {
+             arg = save_expr (arg);
+             return fold (build (TRUTH_ANDIF_EXPR, type,
+                                 fold (build (GE_EXPR, type, arg,
+                                              build_real (TREE_TYPE (arg),
+                                                          dconst0))),
+                                 fold (build (code, type, arg,
+                                              build_real (TREE_TYPE (arg),
+                                                          c2)))));
+           }
+       }
+    }
+
+  return NULL_TREE;
+}
+
 
 /* Perform constant folding and related simplification of EXPR.
    The related simplifications include x*1 => x, x*0 => 0, etc.,
@@ -6209,6 +6349,21 @@ fold (expr)
                                          arg1, TREE_OPERAND (arg0, 1), 0))
              && ! TREE_CONSTANT_OVERFLOW (tem))
            return fold (build (code, type, TREE_OPERAND (arg0, 0), tem));
+
+         /* Fold comparisons against built-in math functions.  */
+         if (TREE_CODE (arg1) == REAL_CST
+             && flag_unsafe_math_optimizations
+             && ! flag_errno_math)
+           {
+             enum built_in_function fcode = builtin_mathfn_code (arg0);
+
+             if (fcode != END_BUILTINS)
+               {
+                 tem = fold_mathfn_compare (fcode, code, type, arg0, arg1);
+                 if (tem != NULL_TREE)
+                   return tem;
+               }
+           }
        }
 
       /* Convert foo++ == CONST into ++foo == CONST + INCR.
index b1bc27d7cfd19b4d8c0957678cccebcc8b697923..170886f1b5ea1e05c1d4b78659b9102215f341d0 100644 (file)
@@ -1,3 +1,7 @@
+2003-03-20  Roger Sayle  <roger@eyesopen.com>
+
+       * gcc.dg/builtins-6.c: New test case.
+
 2003-03-19  Alan Modra  <amodra@bigpond.net.au>
 
        PR target/10073
diff --git a/gcc/testsuite/gcc.dg/builtins-6.c b/gcc/testsuite/gcc.dg/builtins-6.c
new file mode 100644 (file)
index 0000000..2ebb0b2
--- /dev/null
@@ -0,0 +1,80 @@
+/* Copyright (C) 2003  Free Software Foundation.
+
+   Verify that constant folding comparisons against built-in math functions
+   don't cause any problems for the compiler, and produce expected results.
+
+   Written by Roger Sayle, 15th March 2003.  */
+
+/* { dg-do run } */
+/* { dg-options "-O2 -ffast-math" } */
+
+#include <float.h>
+
+extern void abort (void);
+extern double sqrt (double);
+
+int test1(double x)
+{
+  return sqrt(x) < -9.0;
+}
+
+int test2(double x)
+{
+  return sqrt(x) > -9.0;
+}
+
+int test3(double x)
+{
+  return sqrt(x) < 9.0;
+}
+
+int test4(double x)
+{
+  return sqrt(x) > 9.0;
+}
+
+int test5(double x)
+{
+  return sqrt(x) < DBL_MAX;
+}
+
+int test6(double x)
+{
+  return sqrt(x) > DBL_MAX;
+}
+
+int main()
+{
+  double x;
+
+  x = 80.0;
+  if (test1 (x))
+    abort ();
+  if (! test2 (x))
+    abort ();
+  if (! test3 (x))
+    abort ();
+  if (test4 (x))
+    abort ();
+  if (! test5 (x))
+    abort ();
+  if (test6 (x))
+    abort ();
+
+  x = 100.0;
+  if (test1 (x))
+    abort ();
+  if (! test2 (x))
+    abort ();
+  if (test3 (x))
+    abort ();
+  if (! test4 (x))
+    abort ();
+  if (! test5 (x))
+    abort ();
+  if (test6 (x))
+    abort ();
+
+  return 0;
+}
+