real.c (real_copysign): New function to implement libm's copysign.
authorRoger Sayle <roger@eyesopen.com>
Mon, 7 Jun 2004 20:50:14 +0000 (20:50 +0000)
committerRoger Sayle <sayle@gcc.gnu.org>
Mon, 7 Jun 2004 20:50:14 +0000 (20:50 +0000)
* 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
gcc/builtins.c
gcc/fold-const.c
gcc/real.c
gcc/real.h
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/builtins-41.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/builtins-42.c [new file with mode: 0644]

index d15e179fa3da9fb6e9c2f24d625f71f6c03646d1..a119116e04b41a859df8143154d90a62ae58bdf6 100644 (file)
@@ -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.
index e2651866d6360e713d5eea214a2f8a2828811e32..d10924f7919ad086fbfa626b4673925f375d7b11 100644 (file)
@@ -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;
     }
index b0d1db29237d4fcd2422ecb6f03963cf77332afb..6eee71016585eb5c54d886e936e25945eb20024f 100644 (file)
@@ -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)));
 
index e702b2d675ae27320771d0d54cb8002f4f568b29..65d57c30a53d5bd7a5752279272c545aa51d89fb 100644 (file)
@@ -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;
+}
+
index 475ab4563fe709397de08cdedc2a60d240fc647b..4200e5ef702a131d4084a60196068a79d2a06839 100644 (file)
@@ -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 */
index 1770f632aa6c6a53861a144bac11e1477c05655f..35bf511e71de9ce222c9791469a6b49d0b6e3126 100644 (file)
@@ -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 (file)
index 0000000..5b96551
--- /dev/null
@@ -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 (file)
index 0000000..5b96551
--- /dev/null
@@ -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;
+}
+