From 67057c537b7f1f895ff87f8616e8a122f886f1bf Mon Sep 17 00:00:00 2001 From: Roger Sayle Date: Mon, 7 Jun 2004 20:50:14 +0000 Subject: [PATCH] real.c (real_copysign): New function to implement libm's copysign. * real.c (real_copysign): New function to implement libm's copysign. * real.h (real_copysign): Prototype here. * fold-const.c (tree_expr_nonnegative_p): The result of sqrt, sqrtf and sqrtl can be negative, as sqrt(-0.0) = -0.0. Correct whitespace. * builtins.c (fold_builtin_isascii, fold_builtin_toascii, fold_builtin_isdigit): Add function prototypes. (fold_builtin_copysign): New function to fold copysign, copysignf and copysignl. Optimize copysign(x,x) as x. Evaluate copysign of constant arguments at compile-time using real_copysign. Fold copysign(X,Y) as fabs(X) if Y is always non-negative. (fold_builtin_1): Correct minor whitespace/style issues. Call fold_builtin_copysign for BUILT_IN_COPYSIGN{,F,L}. * gcc.dg/builtins-41.c: New test case. * gcc.dg/builtins-42.c: New test case. From-SVN: r82721 --- gcc/ChangeLog | 15 ++++++++ gcc/builtins.c | 60 ++++++++++++++++++++++++++++-- gcc/fold-const.c | 13 +++++-- gcc/real.c | 8 ++++ gcc/real.h | 3 ++ gcc/testsuite/ChangeLog | 5 +++ gcc/testsuite/gcc.dg/builtins-41.c | 57 ++++++++++++++++++++++++++++ gcc/testsuite/gcc.dg/builtins-42.c | 57 ++++++++++++++++++++++++++++ 8 files changed, 211 insertions(+), 7 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/builtins-41.c create mode 100644 gcc/testsuite/gcc.dg/builtins-42.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index d15e179fa3d..a119116e04b 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,18 @@ +2004-06-07 Roger Sayle + + * real.c (real_copysign): New function to implement libm's copysign. + * real.h (real_copysign): Prototype here. + * fold-const.c (tree_expr_nonnegative_p): The result of sqrt, sqrtf + and sqrtl can be negative, as sqrt(-0.0) = -0.0. Correct whitespace. + * builtins.c (fold_builtin_isascii, fold_builtin_toascii, + fold_builtin_isdigit): Add function prototypes. + (fold_builtin_copysign): New function to fold copysign, copysignf + and copysignl. Optimize copysign(x,x) as x. Evaluate copysign of + constant arguments at compile-time using real_copysign. Fold + copysign(X,Y) as fabs(X) if Y is always non-negative. + (fold_builtin_1): Correct minor whitespace/style issues. Call + fold_builtin_copysign for BUILT_IN_COPYSIGN{,F,L}. + 2004-06-07 J"orn Rennecke * tree.c (iterative_hash_expr): Use real_hash. diff --git a/gcc/builtins.c b/gcc/builtins.c index e2651866d63..d10924f7919 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -162,6 +162,10 @@ static tree fold_builtin_memcmp (tree); static tree fold_builtin_strcmp (tree); static tree fold_builtin_strncmp (tree); static tree fold_builtin_signbit (tree); +static tree fold_builtin_copysign (tree, tree); +static tree fold_builtin_isascii (tree); +static tree fold_builtin_toascii (tree); +static tree fold_builtin_isdigit (tree); static tree simplify_builtin_memcmp (tree); static tree simplify_builtin_strcmp (tree); @@ -7298,6 +7302,49 @@ fold_builtin_signbit (tree exp) return NULL_TREE; } +/* Fold function call to builtin copysign, copysignf or copysignl. + Return NULL_TREE if no simplification can be made. */ + +static tree +fold_builtin_copysign (tree arglist, tree type) +{ + tree arg1, arg2; + + if (!validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE)) + return NULL_TREE; + + arg1 = TREE_VALUE (arglist); + arg2 = TREE_VALUE (TREE_CHAIN (arglist)); + + /* copysign(X,X) is X. */ + if (operand_equal_p (arg1, arg2, 0)) + return fold_convert (type, arg1); + + /* If ARG1 and ARG2 are compile-time constants, determine the result. */ + if (TREE_CODE (arg1) == REAL_CST + && TREE_CODE (arg2) == REAL_CST + && !TREE_CONSTANT_OVERFLOW (arg1) + && !TREE_CONSTANT_OVERFLOW (arg2)) + { + REAL_VALUE_TYPE c1, c2; + + c1 = TREE_REAL_CST (arg1); + c2 = TREE_REAL_CST (arg2); + real_copysign (&c1, &c2); + return build_real (type, c1); + c1.sign = c2.sign; + } + + /* copysign(X, Y) is fabs(X) when Y is always non-negative. + Remember to evaluate Y for side-effects. */ + if (tree_expr_nonnegative_p (arg2)) + return omit_one_operand (type, + fold (build1 (ABS_EXPR, type, arg1)), + arg2); + + return NULL_TREE; +} + /* Fold a call to builtin isascii. */ static tree @@ -7577,10 +7624,12 @@ fold_builtin_1 (tree exp) case BUILT_IN_EXPF: case BUILT_IN_EXPL: return fold_builtin_exponent (exp, &dconste); + case BUILT_IN_EXP2: case BUILT_IN_EXP2F: case BUILT_IN_EXP2L: return fold_builtin_exponent (exp, &dconst2); + case BUILT_IN_EXP10: case BUILT_IN_EXP10F: case BUILT_IN_EXP10L: @@ -7588,21 +7637,21 @@ fold_builtin_1 (tree exp) case BUILT_IN_POW10F: case BUILT_IN_POW10L: return fold_builtin_exponent (exp, &dconst10); + case BUILT_IN_LOG: case BUILT_IN_LOGF: case BUILT_IN_LOGL: return fold_builtin_logarithm (exp, &dconste); - break; + case BUILT_IN_LOG2: case BUILT_IN_LOG2F: case BUILT_IN_LOG2L: return fold_builtin_logarithm (exp, &dconst2); - break; + case BUILT_IN_LOG10: case BUILT_IN_LOG10F: case BUILT_IN_LOG10L: return fold_builtin_logarithm (exp, &dconst10); - break; case BUILT_IN_TAN: case BUILT_IN_TANF: @@ -7884,6 +7933,11 @@ fold_builtin_1 (tree exp) case BUILT_IN_ISDIGIT: return fold_builtin_isdigit (arglist); + case BUILT_IN_COPYSIGN: + case BUILT_IN_COPYSIGNF: + case BUILT_IN_COPYSIGNL: + return fold_builtin_copysign (arglist, type); + default: break; } diff --git a/gcc/fold-const.c b/gcc/fold-const.c index b0d1db29237..6eee7101658 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -9024,13 +9024,18 @@ tree_expr_nonnegative_p (tree t) CASE_BUILTIN_F (BUILT_IN_FREXP) CASE_BUILTIN_F (BUILT_IN_HYPOT) CASE_BUILTIN_F (BUILT_IN_POW10) - CASE_BUILTIN_F (BUILT_IN_SQRT) CASE_BUILTIN_I (BUILT_IN_FFS) CASE_BUILTIN_I (BUILT_IN_PARITY) CASE_BUILTIN_I (BUILT_IN_POPCOUNT) /* Always true. */ return 1; + CASE_BUILTIN_F (BUILT_IN_SQRT) + /* sqrt(-0.0) is -0.0. */ + if (!HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (t)))) + return 1; + return tree_expr_nonnegative_p (TREE_VALUE (arglist)); + CASE_BUILTIN_F (BUILT_IN_ASINH) CASE_BUILTIN_F (BUILT_IN_ATAN) CASE_BUILTIN_F (BUILT_IN_ATANH) @@ -9057,17 +9062,17 @@ tree_expr_nonnegative_p (tree t) /* True if the 1st argument is nonnegative. */ return tree_expr_nonnegative_p (TREE_VALUE (arglist)); - CASE_BUILTIN_F(BUILT_IN_FMAX) + CASE_BUILTIN_F (BUILT_IN_FMAX) /* True if the 1st OR 2nd arguments are nonnegative. */ return tree_expr_nonnegative_p (TREE_VALUE (arglist)) || tree_expr_nonnegative_p (TREE_VALUE (TREE_CHAIN (arglist))); - CASE_BUILTIN_F(BUILT_IN_FMIN) + CASE_BUILTIN_F (BUILT_IN_FMIN) /* True if the 1st AND 2nd arguments are nonnegative. */ return tree_expr_nonnegative_p (TREE_VALUE (arglist)) && tree_expr_nonnegative_p (TREE_VALUE (TREE_CHAIN (arglist))); - CASE_BUILTIN_F(BUILT_IN_COPYSIGN) + CASE_BUILTIN_F (BUILT_IN_COPYSIGN) /* True if the 2nd argument is nonnegative. */ return tree_expr_nonnegative_p (TREE_VALUE (TREE_CHAIN (arglist))); diff --git a/gcc/real.c b/gcc/real.c index e702b2d675a..65d57c30a53 100644 --- a/gcc/real.c +++ b/gcc/real.c @@ -4587,3 +4587,11 @@ real_round (REAL_VALUE_TYPE *r, enum machine_mode mode, real_convert (r, mode, r); } +/* Set the sign of R to the sign of X. */ + +void +real_copysign (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *x) +{ + r->sign = x->sign; +} + diff --git a/gcc/real.h b/gcc/real.h index 475ab4563fe..4200e5ef702 100644 --- a/gcc/real.h +++ b/gcc/real.h @@ -384,4 +384,7 @@ extern void real_ceil (REAL_VALUE_TYPE *, enum machine_mode, extern void real_round (REAL_VALUE_TYPE *, enum machine_mode, const REAL_VALUE_TYPE *); +/* Set the sign of R to the sign of X. */ +extern void real_copysign (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *); + #endif /* ! GCC_REAL_H */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 1770f632aa6..35bf511e71d 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2004-06-07 Roger Sayle + + * gcc.dg/builtins-41.c: New test case. + * gcc.dg/builtins-42.c: New test case. + 2004-06-07 David Edelsohn * g++.dg/ext/altivec-1.C: XFAIL powerpc-ibm-aix*. diff --git a/gcc/testsuite/gcc.dg/builtins-41.c b/gcc/testsuite/gcc.dg/builtins-41.c new file mode 100644 index 00000000000..5b96551fb11 --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtins-41.c @@ -0,0 +1,57 @@ +/* Copyright (C) 2004 Free Software Foundation. + + Check that constant folding of copysign, copysignf and copysignl math + functions doesn't break anything and produces the expected results. + + Written by Roger Sayle, 6th June 2004. */ + +/* { dg-do link } */ +/* { dg-options "-O2" } */ + +extern void link_error(void); + +extern double copysign(double, double); +extern float copysignf(float, float); +extern long double copysignl(long double, long double); + +int main() +{ + if (copysign (2.0, 1.0) != 2.0) + link_error (); + if (copysign (2.0, -1.0) != -2.0) + link_error (); + if (copysign (-2.0, 1.0) != 2.0) + link_error (); + if (copysign (-2.0, -1.0) != -2.0) + link_error (); + + if (copysign (2.0, 1.0) != 2.0) + link_error (); + if (copysign (2.0, -1.0) != -2.0) + link_error (); + if (copysign (-2.0, 1.0) != 2.0) + link_error (); + if (copysign (-2.0, -1.0) != -2.0) + link_error (); + + if (copysignf (2.0f, 1.0f) != 2.0f) + link_error (); + if (copysignf (2.0f, -1.0f) != -2.0f) + link_error (); + if (copysignf (-2.0f, 1.0f) != 2.0f) + link_error (); + if (copysignf (-2.0f, -1.0f) != -2.0f) + link_error (); + + if (copysignl (2.0l, 1.0l) != 2.0l) + link_error (); + if (copysignl (2.0l, -1.0l) != -2.0l) + link_error (); + if (copysignl (-2.0l, 1.0l) != 2.0l) + link_error (); + if (copysignl (-2.0l, -1.0l) != -2.0l) + link_error (); + + return 0; +} + diff --git a/gcc/testsuite/gcc.dg/builtins-42.c b/gcc/testsuite/gcc.dg/builtins-42.c new file mode 100644 index 00000000000..5b96551fb11 --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtins-42.c @@ -0,0 +1,57 @@ +/* Copyright (C) 2004 Free Software Foundation. + + Check that constant folding of copysign, copysignf and copysignl math + functions doesn't break anything and produces the expected results. + + Written by Roger Sayle, 6th June 2004. */ + +/* { dg-do link } */ +/* { dg-options "-O2" } */ + +extern void link_error(void); + +extern double copysign(double, double); +extern float copysignf(float, float); +extern long double copysignl(long double, long double); + +int main() +{ + if (copysign (2.0, 1.0) != 2.0) + link_error (); + if (copysign (2.0, -1.0) != -2.0) + link_error (); + if (copysign (-2.0, 1.0) != 2.0) + link_error (); + if (copysign (-2.0, -1.0) != -2.0) + link_error (); + + if (copysign (2.0, 1.0) != 2.0) + link_error (); + if (copysign (2.0, -1.0) != -2.0) + link_error (); + if (copysign (-2.0, 1.0) != 2.0) + link_error (); + if (copysign (-2.0, -1.0) != -2.0) + link_error (); + + if (copysignf (2.0f, 1.0f) != 2.0f) + link_error (); + if (copysignf (2.0f, -1.0f) != -2.0f) + link_error (); + if (copysignf (-2.0f, 1.0f) != 2.0f) + link_error (); + if (copysignf (-2.0f, -1.0f) != -2.0f) + link_error (); + + if (copysignl (2.0l, 1.0l) != 2.0l) + link_error (); + if (copysignl (2.0l, -1.0l) != -2.0l) + link_error (); + if (copysignl (-2.0l, 1.0l) != 2.0l) + link_error (); + if (copysignl (-2.0l, -1.0l) != -2.0l) + link_error (); + + return 0; +} + -- 2.30.2