summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog15
-rw-r--r--gcc/builtins.c60
-rw-r--r--gcc/fold-const.c13
-rw-r--r--gcc/real.c8
-rw-r--r--gcc/real.h3
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.dg/builtins-41.c57
-rw-r--r--gcc/testsuite/gcc.dg/builtins-42.c57
8 files changed, 211 insertions, 7 deletions
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 <roger@eyesopen.com>
+
+ * 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 <joern.rennecke@superh.com>
* 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 <roger@eyesopen.com>
+
+ * gcc.dg/builtins-41.c: New test case.
+ * gcc.dg/builtins-42.c: New test case.
+
2004-06-07 David Edelsohn <edelsohn@gnu.org>
* 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;
+}
+