From d4a43a03641af1a48c5bae7f323614d7d69e0819 Mon Sep 17 00:00:00 2001 From: ghazi <ghazi@138bc75d-0d04-0410-961f-82ee72b054a4> Date: Sat, 18 Nov 2006 20:38:40 +0000 Subject: [PATCH] * builtins.c (integer_valued_real_p): Handle fmin/fmax. (fold_builtin_fmin_fmax): New. (fold_builtin_1): Use it. testsuite: * gcc.dg/builtins-20.c: Add fmin/fmax cases. * gcc.dg/torture/builtin-minmax-1.c: New. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@118976 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 4 + gcc/builtins.c | 49 +++++++-- gcc/testsuite/ChangeLog | 3 + gcc/testsuite/gcc.dg/builtins-20.c | 78 ++++++++++++++ .../gcc.dg/torture/builtin-minmax-1.c | 100 ++++++++++++++++++ 5 files changed, 224 insertions(+), 10 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/torture/builtin-minmax-1.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 0df21ccca998..86b2a3724eb2 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,9 @@ 2006-11-18 Kaveh R. Ghazi <ghazi@caip.rutgers.edu> + * builtins.c (integer_valued_real_p): Handle fmin/fmax. + (fold_builtin_fmin_fmax): New. + (fold_builtin_1): Use it. + * fold-const.c (fold_strip_sign_ops): Handle copysign. 2006-11-18 Richard Guenther <rguenther@suse.de> diff --git a/gcc/builtins.c b/gcc/builtins.c index b9005b48799c..4e4ea969cd78 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -6708,6 +6708,11 @@ integer_valued_real_p (tree t) CASE_FLT_FN (BUILT_IN_TRUNC): return true; + CASE_FLT_FN (BUILT_IN_FMIN): + CASE_FLT_FN (BUILT_IN_FMAX): + return integer_valued_real_p (TREE_VALUE (TREE_OPERAND (t, 1))) + && integer_valued_real_p (TREE_VALUE (TREE_CHAIN (TREE_OPERAND (t, 1)))); + default: break; } @@ -8722,6 +8727,38 @@ fold_builtin_abs (tree arglist, tree type) return fold_build1 (ABS_EXPR, type, arg); } +/* Fold a call to builtin fmin or fmax. */ + +static tree +fold_builtin_fmin_fmax (tree arglist, tree type, bool max) +{ + if (validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE)) + { + tree arg0 = TREE_VALUE (arglist); + tree arg1 = TREE_VALUE (TREE_CHAIN (arglist)); + /* Calculate the result when the argument is a constant. */ + tree res = do_mpfr_arg2 (arg0, arg1, type, (max ? mpfr_max : mpfr_min)); + + if (res) + return res; + + /* Transform fmin/fmax(x,x) -> x. */ + if (operand_equal_p (arg0, arg1, OEP_PURE_SAME)) + return omit_one_operand (type, arg0, arg1); + + /* Convert fmin/fmax to MIN_EXPR/MAX_EXPR. C99 requires these + functions to return the numeric arg if the other one is NaN. + These tree codes don't honor that, so only transform if + -ffinite-math-only is set. C99 doesn't require -0.0 to be + handled, so we don't have to worry about it either. */ + if (flag_finite_math_only) + return fold_build2 ((max ? MAX_EXPR : MIN_EXPR), type, + fold_convert (type, arg0), + fold_convert (type, arg1)); + } + return NULL_TREE; +} + /* Fold a call to __builtin_isnan(), __builtin_isinf, __builtin_finite. EXP is the CALL_EXPR for the call. */ @@ -9143,18 +9180,10 @@ fold_builtin_1 (tree fndecl, tree arglist, bool ignore) break; CASE_FLT_FN (BUILT_IN_FMIN): - if (validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE)) - return do_mpfr_arg2 (TREE_VALUE (arglist), - TREE_VALUE (TREE_CHAIN (arglist)), - type, mpfr_min); - break; + return fold_builtin_fmin_fmax (arglist, type, /*max=*/false); CASE_FLT_FN (BUILT_IN_FMAX): - if (validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE)) - return do_mpfr_arg2 (TREE_VALUE (arglist), - TREE_VALUE (TREE_CHAIN (arglist)), - type, mpfr_max); - break; + return fold_builtin_fmin_fmax (arglist, type, /*max=*/true); CASE_FLT_FN (BUILT_IN_HYPOT): return fold_builtin_hypot (fndecl, arglist, type); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index c23dae9fb653..25c827e54673 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,8 @@ 2006-11-18 Kaveh R. Ghazi <ghazi@caip.rutgers.edu> + * gcc.dg/builtins-20.c: Add fmin/fmax cases. + * gcc.dg/torture/builtin-minmax-1.c: New. + * gcc.dg/builtins-20.c: Add cases for copysign. 2006-11-18 Francois-Xavier Coudert <coudert@clipper.ens.fr> diff --git a/gcc/testsuite/gcc.dg/builtins-20.c b/gcc/testsuite/gcc.dg/builtins-20.c index bb90aec9672a..1211cf0b6cd4 100644 --- a/gcc/testsuite/gcc.dg/builtins-20.c +++ b/gcc/testsuite/gcc.dg/builtins-20.c @@ -17,6 +17,8 @@ extern double sin (double); extern double tan (double); extern double fabs (double); extern double copysign (double, double); +extern double fmin (double, double); +extern double fmax (double, double); extern double hypot (double, double); extern double pure (double) __attribute__ ((__pure__)); extern float cosf (float); @@ -24,6 +26,8 @@ extern float sinf (float); extern float tanf (float); extern float fabsf (float); extern float copysignf (float, float); +extern float fminf (float, float); +extern float fmaxf (float, float); extern float hypotf (float, float); extern float puref (float) __attribute__ ((__pure__)); extern long double cosl (long double); @@ -31,6 +35,8 @@ extern long double sinl (long double); extern long double tanl (long double); extern long double fabsl (long double); extern long double copysignl (long double, long double); +extern long double fminl (long double, long double); +extern long double fmaxl (long double, long double); extern long double hypotl (long double, long double); extern long double purel (long double) __attribute__ ((__pure__)); @@ -155,6 +161,30 @@ void test2(double x, double y) if (hypot (tan(-x), tan(-fabs(y))) != hypot (tan(x), tan(y))) link_error (); + + if (fmin (fmax(x,y),y) != y) + link_error (); + + if (fmin (fmax(y,x),y) != y) + link_error (); + + if (fmin (x,fmax(x,y)) != x) + link_error (); + + if (fmin (x,fmax(y,x)) != x) + link_error (); + + if (fmax (fmin(x,y),y) != y) + link_error (); + + if (fmax (fmin(y,x),y) != y) + link_error (); + + if (fmax (x,fmin(x,y)) != x) + link_error (); + + if (fmax (x,fmin(y,x)) != x) + link_error (); } void test1f(float x) @@ -278,6 +308,30 @@ void test2f(float x, float y) if (hypotf (tanf(-x), tanf(-fabsf(y))) != hypotf (tanf(x), tanf(y))) link_error (); + + if (fminf (fmaxf(x,y),y) != y) + link_error (); + + if (fminf (fmaxf(y,x),y) != y) + link_error (); + + if (fminf (x,fmaxf(x,y)) != x) + link_error (); + + if (fminf (x,fmaxf(y,x)) != x) + link_error (); + + if (fmaxf (fminf(x,y),y) != y) + link_error (); + + if (fmaxf (fminf(y,x),y) != y) + link_error (); + + if (fmaxf (x,fminf(x,y)) != x) + link_error (); + + if (fmaxf (x,fminf(y,x)) != x) + link_error (); } @@ -402,6 +456,30 @@ void test2l(long double x, long double y) if (hypotl (tanl(-x), tanl(-fabsl(y))) != hypotl (tanl(x), tanl(y))) link_error (); + + if (fminl (fmaxl(x,y),y) != y) + link_error (); + + if (fminl (fmaxl(y,x),y) != y) + link_error (); + + if (fminl (x,fmaxl(x,y)) != x) + link_error (); + + if (fminl (x,fmaxl(y,x)) != x) + link_error (); + + if (fmaxl (fminl(x,y),y) != y) + link_error (); + + if (fmaxl (fminl(y,x),y) != y) + link_error (); + + if (fmaxl (x,fminl(x,y)) != x) + link_error (); + + if (fmaxl (x,fminl(y,x)) != x) + link_error (); } int main() diff --git a/gcc/testsuite/gcc.dg/torture/builtin-minmax-1.c b/gcc/testsuite/gcc.dg/torture/builtin-minmax-1.c new file mode 100644 index 000000000000..280d3564e373 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/builtin-minmax-1.c @@ -0,0 +1,100 @@ +/* Copyright (C) 2006 Free Software Foundation. + + Verify that built-in math function folding of fmin/fmax is + correctly performed by the compiler. + + Origin: Kaveh R. Ghazi, November 13, 2006. */ + +/* { dg-do link } */ +/* { dg-options "-fno-math-errno" } */ + +/* All references to link_error should go away at compile-time. */ +extern void link_error(int); + +#define DECLARE(FUNC) \ + extern float FUNC##f (float); \ + extern double FUNC (double); \ + extern long double FUNC##l (long double) +#define DECLARE_L(FUNC) \ + extern long FUNC##f (float); \ + extern long FUNC (double); \ + extern long FUNC##l (long double) +#define DECLARE2(FUNC) \ + extern float FUNC##f (float, float); \ + extern double FUNC (double, double); \ + extern long double FUNC##l (long double, long double) + +DECLARE2(fmin); +DECLARE2(fmax); +DECLARE_L(lround); +DECLARE_L(lrint); +DECLARE(sqrt); +DECLARE(fabs); +extern int pure(int) __attribute__ ((__pure__)); + +/* Test that FUNC(x,x) == x. We cast to (long) so "!=" folds. */ +#define TEST_EQ(FUNC) do { \ + if ((long)FUNC##f(xf,xf) != (long)xf) \ + link_error(__LINE__); \ + if ((long)FUNC(x,x) != (long)x) \ + link_error(__LINE__); \ + if ((long)FUNC##l(xl,xl) != (long)xl) \ + link_error(__LINE__); \ + } while (0) + +/* Test that FUNC(purefn,purefn) == purefn. We cast to (long) so "!=" folds. */ +#define TEST_EQ_PURE(FUNC) do { \ + if ((long)FUNC##f(pure(i),pure(i)) != (long)FUNC##f(pure(i),pure(i))) \ + link_error(__LINE__); \ + if ((long)FUNC(pure(i),pure(i)) != (long)FUNC(pure(i),pure(i))) \ + link_error(__LINE__); \ + if ((long)FUNC##l(pure(i),pure(i)) != (long)FUNC##l(pure(i),pure(i))) \ + link_error(__LINE__); \ + } while (0) + +/* Test that lround(FUNC(int,int)) == lrint(FUNC(int,int)), i.e. both + lround() and lrint() should be folded away. */ +#define TEST_NONNEG(FUNC) do { \ + if (lroundf(FUNC##f(i,j)) != lrintf(FUNC##f(i,j))) \ + link_error(__LINE__); \ + if (lround(FUNC(i,j)) != lrint(FUNC(i,j))) \ + link_error(__LINE__); \ + if (lroundl(FUNC##l(i,j)) != lrintl(FUNC##l(i,j))) \ + link_error(__LINE__); \ + } while (0) + +/* Test that (long)fabs(FUNC(fabs(x),fabs(y))) == + (long)FUNC(fabs(x),fabs(y)). We cast to (long) so "!=" folds. */ +#define TEST_INT(FUNC) do { \ + if ((long)fabsf(FUNC##f(fabsf(xf),fabsf(yf))) != (long)FUNC##f(fabsf(xf),fabsf(yf))) \ + link_error(__LINE__); \ + if ((long)fabs(FUNC(fabs(x),fabs(y))) != (long)FUNC(fabs(x),fabs(y))) \ + link_error(__LINE__); \ + if ((long)fabsl(FUNC##l(fabsl(xl),fabsl(yl))) != (long)FUNC##l(fabsl(xl),fabsl(yl))) \ + link_error(__LINE__); \ + } while (0) + +void foo (float xf, double x, long double xl, + float yf, double y, long double yl, + int i, int j) +{ + TEST_EQ(fmin); + TEST_EQ(fmax); + +#ifdef __OPTIMIZE__ + TEST_EQ_PURE(fmin); + TEST_EQ_PURE(fmax); +#endif + + TEST_INT(fmin); + TEST_INT(fmax); + + TEST_NONNEG(fmin); + TEST_NONNEG(fmax); +} + +int main() +{ + foo (1,1,1,1,1,1,1,1); + return 0; +} -- GitLab