From 4b0b9adb13b6e4966e3ff7e92af5fb26f1ca7dbb Mon Sep 17 00:00:00 2001 From: sayle Date: Thu, 20 Mar 2003 17:48:26 +0000 Subject: [PATCH] * 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@64619 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 35 +++++---- gcc/fold-const.c | 155 ++++++++++++++++++++++++++++++++++++++ gcc/testsuite/ChangeLog | 4 + gcc/testsuite/gcc.dg/builtins-6.c | 80 ++++++++++++++++++++ 4 files changed, 260 insertions(+), 14 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/builtins-6.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 7ac8fc8..2b16b1b 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2003-03-20 Roger Sayle + + * 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 * 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 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 +2003-03-05 Tom Tromey * config/stormy16/stormy16.h (DWARF_LINE_MIN_INSTR_LENGTH): Define. -2002-03-05 Nick Clifton +2003-03-05 Nick Clifton * config/stormy16/stormy16.md ("*eqbranchsi"): Remove '+' on operand 2. ("*ineqbranchsi"): Likewise. -2002-03-05 Andrew Haley +2003-03-05 Andrew Haley * 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 +2003-03-05 Chris Moller * 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 (*tst_extzv_memqi_1_n): Likewise. (a peephole2): New. -2002-02-28 Richard Sandiford +2003-02-28 Richard Sandiford * 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 simplify_binary_operation): Deal with vector modes (simplify_ternary_operation): Deal with no-op VEC_MERGE. -2002-02-09 Richard Sandiford +2003-02-09 Richard Sandiford * 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 * config/ia64/unwind-ia64.c: include coretypes.h, tm.h to get config/ia64/linux.h -2002-02-05 Roger Sayle +2003-02-05 Roger Sayle * cfgloop.h (flow_bb_inside_loop_p): Correct prototype again. @@ -4605,7 +4612,7 @@ Mon Feb 3 21:19:11 CET 2003 Jan Hubicka (movups/movupd/movdqu patterns): Force one of operands to not be memory. -2002-02-03 Roger Sayle +2003-02-03 Roger Sayle * 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 * config/h8300/h8300.c (h8300_shift_needs_scratch_p): Update a comment. -2002-01-25 Richard Henderson +2003-01-25 Richard Henderson * config/m68k/m68k-none.h (ASM_SPEC): Adjust inter-option spacing. -2002-01-25 Kelley Cook +2003-01-25 Kelley Cook * ggc-simple.c (debug_ggc_tree): Add PTR cast. @@ -5646,7 +5653,7 @@ Sat Jan 25 21:04:33 CET 2003 Jan Hubicka 2002-02-19 Robert Lipe * config/i386/t-sco5gas: (CRTSTUFF_T_CFLAGS_S): Delete -mcoff. -2002-01-25 Roger Sayle +2003-01-25 Roger Sayle * 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 * combine.c (simplify_comparison, case AND): Remove a redundant test. -2002-01-25 Roger Sayle +2003-01-25 Roger Sayle * 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 * integrate.c (expand_inline_function): Set calls_constant_p if the function being inlined has calls_constant_p set. -2002-01-25 Roger Sayle +2003-01-25 Roger Sayle * 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 * builtins.c (fold_trunc_transparent_mathfn): Undo accidental commit. -2002-01-24 Stuart Hastings +2003-01-24 Stuart Hastings * config/i386/i386.c (x86_output_mi_thunk): Add Darwin/x86 support. diff --git a/gcc/fold-const.c b/gcc/fold-const.c index 4890c17..7477269 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -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. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index b1bc27d..170886f 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2003-03-20 Roger Sayle + + * gcc.dg/builtins-6.c: New test case. + 2003-03-19 Alan Modra 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 index 0000000..2ebb0b2 --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtins-6.c @@ -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 + +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; +} + -- 2.7.4