* fold-const.c (fold_strip_sign_ops): New function to simplify a
authorsayle <sayle@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 9 Feb 2005 21:56:35 +0000 (21:56 +0000)
committersayle <sayle@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 9 Feb 2005 21:56:35 +0000 (21:56 +0000)
floating point expression ignoring the sign of the result.
(fold) <ABS_EXPR>: Use it to simplify fabs(x).
(fold) <MULT_EXPR>: Use it to simplify x*x.
* tree.h (fold_strip_sign_ops): Prototype here.
* builtins.c (fold_builtin_copysign): Take an additional FNDECL
argument.  Use fold_strip_sign_ops to simplify the first argument.
(fold_builtin_pow):  Use fold_strip_sign_ops to simplify the
first argument when the second argument is an even integer
constant, but only with -funsafe_math_optimizations.
(fold_builtin_1): Update call to fold_builtin_copysign.

* gcc.dg/builtins-48.c: New test case.
* gcc.dg/builtins-49.c: New test case.
* gcc.dg/builtins-50.c: New test case.
* gcc.dg/builtins-51.c: New test case.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@94779 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/builtins.c
gcc/fold-const.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/builtins-48.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/builtins-49.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/builtins-50.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/builtins-51.c [new file with mode: 0644]
gcc/tree.h

index 37d3e05..f9d60df 100644 (file)
@@ -1,3 +1,17 @@
+2005-02-09  Roger Sayle  <roger@eyesopen.com>
+
+       * fold-const.c (fold_strip_sign_ops): New function to simplify a
+       floating point expression ignoring the sign of the result.
+       (fold) <ABS_EXPR>: Use it to simplify fabs(x).
+       (fold) <MULT_EXPR>: Use it to simplify x*x.
+       * tree.h (fold_strip_sign_ops): Prototype here.
+       * builtins.c (fold_builtin_copysign): Take an additional FNDECL
+       argument.  Use fold_strip_sign_ops to simplify the first argument.
+       (fold_builtin_pow):  Use fold_strip_sign_ops to simplify the
+       first argument when the second argument is an even integer
+       constant, but only with -funsafe_math_optimizations.
+       (fold_builtin_1): Update call to fold_builtin_copysign.
+
 2005-02-09  Ian Lance Taylor  <ian@airs.com>
 
        PR middle-end/19583
@@ -9,7 +23,6 @@
        * gcc/haifa-sched.c (schedule_block): Make queued sched group
        insns return to ready list in the next turn.
 
-
 2005-02-09  Richard Guenther  <rguenth@gcc.gnu.org>
 
        PR middle-end/19402
index 3631615..56e7eb0 100644 (file)
@@ -169,7 +169,7 @@ 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_copysign (tree, tree, tree);
 static tree fold_builtin_isascii (tree);
 static tree fold_builtin_toascii (tree);
 static tree fold_builtin_isdigit (tree);
@@ -6844,7 +6844,10 @@ fold_builtin_pow (tree fndecl, tree arglist, tree type)
   if (TREE_CODE (arg1) == REAL_CST
       && ! TREE_CONSTANT_OVERFLOW (arg1))
     {
+      REAL_VALUE_TYPE cint;
       REAL_VALUE_TYPE c;
+      HOST_WIDE_INT n;
+
       c = TREE_REAL_CST (arg1);
 
       /* Optimize pow(x,0.0) = 1.0.  */
@@ -6874,17 +6877,14 @@ fold_builtin_pow (tree fndecl, tree arglist, tree type)
            }
        }
 
-      /* Attempt to evaluate pow at compile-time.  */
-      if (TREE_CODE (arg0) == REAL_CST
-         && ! TREE_CONSTANT_OVERFLOW (arg0))
+      /* Check for an integer exponent.  */
+      n = real_to_integer (&c);
+      real_from_integer (&cint, VOIDmode, n, n < 0 ? -1 : 0, 0);
+      if (real_identical (&c, &cint))
        {
-         REAL_VALUE_TYPE cint;
-         HOST_WIDE_INT n;
-
-         n = real_to_integer (&c);
-         real_from_integer (&cint, VOIDmode, n,
-                            n < 0 ? -1 : 0, 0);
-         if (real_identical (&c, &cint))
+         /* Attempt to evaluate pow at compile-time.  */
+         if (TREE_CODE (arg0) == REAL_CST
+             && ! TREE_CONSTANT_OVERFLOW (arg0))
            {
              REAL_VALUE_TYPE x;
              bool inexact;
@@ -6894,6 +6894,18 @@ fold_builtin_pow (tree fndecl, tree arglist, tree type)
              if (flag_unsafe_math_optimizations || !inexact)
                return build_real (type, x);
            }
+
+         /* Strip sign ops from even integer powers.  */
+         if ((n & 1) == 0 && flag_unsafe_math_optimizations)
+           {
+             tree narg0 = fold_strip_sign_ops (arg0);
+             if (narg0)
+               {
+                 arglist = build_tree_list (NULL_TREE, arg1);
+                 arglist = tree_cons (NULL_TREE, narg0, arglist);
+                 return build_function_call_expr (fndecl, arglist);
+               }
+           }
        }
     }
 
@@ -7447,9 +7459,9 @@ fold_builtin_signbit (tree exp)
    Return NULL_TREE if no simplification can be made.  */
 
 static tree
-fold_builtin_copysign (tree arglist, tree type)
+fold_builtin_copysign (tree fndecl, tree arglist, tree type)
 {
-  tree arg1, arg2;
+  tree arg1, arg2, tem;
 
   if (!validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE))
     return NULL_TREE;
@@ -7483,6 +7495,14 @@ fold_builtin_copysign (tree arglist, tree type)
                             fold (build1 (ABS_EXPR, type, arg1)),
                             arg2);
 
+  /* Strip sign changing operations for the first argument.  */
+  tem = fold_strip_sign_ops (arg1);
+  if (tem)
+    {
+      arglist = tree_cons (NULL_TREE, tem, TREE_CHAIN (arglist));
+      return build_function_call_expr (fndecl, arglist);
+    }
+
   return NULL_TREE;
 }
 
@@ -8056,7 +8076,7 @@ fold_builtin_1 (tree exp, bool ignore)
     case BUILT_IN_COPYSIGN:
     case BUILT_IN_COPYSIGNF:
     case BUILT_IN_COPYSIGNL:
-      return fold_builtin_copysign (arglist, type);
+      return fold_builtin_copysign (fndecl, arglist, type);
 
     case BUILT_IN_FINITE:
     case BUILT_IN_FINITEF:
index 294f94c..de54258 100644 (file)
@@ -6776,6 +6776,14 @@ fold (tree expr)
        }
       else if (tree_expr_nonnegative_p (arg0))
        return arg0;
+
+      /* Strip sign ops from argument.  */
+      if (TREE_CODE (type) == REAL_TYPE)
+       {
+         tem = fold_strip_sign_ops (arg0);
+         if (tem)
+           return fold (build1 (ABS_EXPR, type, fold_convert (type, tem)));
+       }
       return t;
 
     case CONJ_EXPR:
@@ -7429,6 +7437,17 @@ fold (tree expr)
                                     TREE_OPERAND (arg0, 1)));
            }
 
+          /* Strip sign operations from X in X*X, i.e. -Y*-Y -> Y*Y.  */
+         if (operand_equal_p (arg0, arg1, 0))
+           {
+             tree tem = fold_strip_sign_ops (arg0);
+             if (tem != NULL_TREE)
+               {
+                 tem = fold_convert (type, tem);
+                 return fold (build2 (MULT_EXPR, type, tem, tem));
+               }
+           }
+
          if (flag_unsafe_math_optimizations)
            {
              enum built_in_function fcode0 = builtin_mathfn_code (arg0);
@@ -11229,3 +11248,38 @@ ptr_difference_const (tree e1, tree e2, HOST_WIDE_INT *diff)
   *diff += (bitpos1 - bitpos2) / BITS_PER_UNIT;
   return true;
 }
+
+/* Simplify the floating point expression EXP when the sign of the
+   result is not significant.  Return NULL_TREE if no simplification
+   is possible.  */
+
+tree
+fold_strip_sign_ops (tree exp)
+{
+  tree arg0, arg1;
+
+  switch (TREE_CODE (exp))
+    {
+    case ABS_EXPR:
+    case NEGATE_EXPR:
+      arg0 = fold_strip_sign_ops (TREE_OPERAND (exp, 0));
+      return arg0 ? arg0 : TREE_OPERAND (exp, 0);
+
+    case MULT_EXPR:
+    case RDIV_EXPR:
+      if (HONOR_SIGN_DEPENDENT_ROUNDING (TYPE_MODE (TREE_TYPE (exp))))
+       return NULL_TREE;
+      arg0 = fold_strip_sign_ops (TREE_OPERAND (exp, 0));
+      arg1 = fold_strip_sign_ops (TREE_OPERAND (exp, 1));
+      if (arg0 != NULL_TREE || arg1 != NULL_TREE)
+       return fold (build2 (TREE_CODE (exp), TREE_TYPE (exp),
+                            arg0 ? arg0 : TREE_OPERAND (exp, 0),
+                            arg1 ? arg1 : TREE_OPERAND (exp, 1)));
+      break;
+
+    default:
+      break;
+    }
+  return NULL_TREE;
+}
+
index 12f30eb..17a5558 100644 (file)
@@ -1,3 +1,10 @@
+2005-02-09  Roger Sayle  <roger@eyesopen.com>
+
+       * gcc.dg/builtins-48.c: New test case.
+       * gcc.dg/builtins-49.c: New test case.
+       * gcc.dg/builtins-50.c: New test case.
+       * gcc.dg/builtins-51.c: New test case.
+
 2005-02-09  Ian Lance Taylor  <ian@airs.com>
 
        PR middle-end/19583
diff --git a/gcc/testsuite/gcc.dg/builtins-48.c b/gcc/testsuite/gcc.dg/builtins-48.c
new file mode 100644 (file)
index 0000000..43710b8
--- /dev/null
@@ -0,0 +1,181 @@
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+extern double fabs(double);
+extern float fabsf(float);
+extern void abort(void);
+
+
+double test1(double x)
+{
+  return (-x)*(-x);
+}
+
+float test1f(float x)
+{
+  return (-x)*(-x);
+}
+
+double test2(double x)
+{
+  return fabs(x)*fabs(x);
+}
+
+float test2f(float x)
+{
+  return fabsf(x)*fabsf(x);
+}
+
+double test3(double x, double y)
+{
+  return (x*-y)*(x*-y);
+}
+
+float test3f(float x, float y)
+{
+  return (x*-y)*(x*-y);
+}
+
+double test4(double x, double y)
+{
+  return (x/-y)*(x/-y);
+}
+
+float test4f(float x, float y)
+{
+  return (x/-y)*(x/-y);
+}
+
+int main()
+{
+  if (test1(1.0) != 1.0)
+    abort();
+  if (test1(2.0) != 4.0)
+    abort();
+  if (test1(0.0) != 0.0)
+    abort();
+  if (test1(-1.0) != 1.0)
+    abort();
+  if (test1(-2.0) != 4.0)
+    abort();
+
+  if (test1f(1.0f) != 1.0f)
+    abort();
+  if (test1f(2.0f) != 4.0f)
+    abort();
+  if (test1f(0.0f) != 0.0f)
+    abort();
+  if (test1f(-1.0f) != 1.0f)
+    abort();
+  if (test1f(-2.0f) != 4.0f)
+    abort();
+
+  if (test2(1.0) != 1.0)
+    abort();
+  if (test2(2.0) != 4.0)
+    abort();
+  if (test2(0.0) != 0.0)
+    abort();
+  if (test2(-1.0) != 1.0)
+    abort();
+  if (test2(-2.0) != 4.0)
+    abort();
+
+  if (test2f(1.0f) != 1.0f)
+    abort();
+  if (test2f(2.0f) != 4.0f)
+    abort();
+  if (test2f(0.0f) != 0.0f)
+    abort();
+  if (test2f(-1.0f) != 1.0f)
+    abort();
+  if (test2f(-2.0f) != 4.0f)
+    abort();
+
+  if (test3(1.0,1.0) != 1.0)
+    abort();
+  if (test3(1.0,-1.0) != 1.0)
+    abort();
+  if (test3(1.0,2.0) != 4.0)
+    abort();
+  if (test3(1.0,-2.0) != 4.0)
+    abort();
+  if (test3(2.0,1.0) != 4.0)
+    abort();
+  if (test3(2.0,-1.0) != 4.0)
+    abort();
+  if (test3(2.0,2.0) != 16.0)
+    abort();
+  if (test3(2.0,-2.0) != 16.0)
+    abort();
+  if (test3(-2.0,1.0) != 4.0)
+    abort();
+  if (test3(-2.0,-1.0) != 4.0)
+    abort();
+  if (test3(-2.0,2.0) != 16.0)
+    abort();
+  if (test3(-2.0,-2.0) != 16.0)
+    abort();
+
+  if (test3f(1.0f,1.0f) != 1.0f)
+    abort();
+  if (test3f(1.0f,-1.0f) != 1.0f)
+    abort();
+  if (test3f(1.0f,2.0f) != 4.0f)
+    abort();
+  if (test3f(1.0f,-2.0f) != 4.0f)
+    abort();
+  if (test3f(2.0f,1.0f) != 4.0f)
+    abort();
+  if (test3f(2.0f,-1.0f) != 4.0f)
+    abort();
+  if (test3f(2.0f,2.0f) != 16.0f)
+    abort();
+  if (test3f(2.0f,-2.0f) != 16.0f)
+    abort();
+  if (test3f(-2.0f,1.0f) != 4.0f)
+    abort();
+  if (test3f(-2.0f,-1.0f) != 4.0f)
+    abort();
+  if (test3f(-2.0f,2.0f) != 16.0f)
+    abort();
+  if (test3f(-2.0f,-2.0f) != 16.0f)
+    abort();
+
+  if (test4(1.0,1.0) != 1.0)
+    abort();
+  if (test4(1.0,-1.0) != 1.0)
+    abort();
+  if (test4(-1.0,1.0) != 1.0)
+    abort();
+  if (test4(-1.0,-1.0) != 1.0)
+    abort();
+  if (test4(6.0,3.0) != 4.0)
+    abort();
+  if (test4(6.0,-3.0) != 4.0)
+    abort();
+  if (test4(-6.0,3.0) != 4.0)
+    abort();
+  if (test4(-6.0,-3.0) != 4.0)
+    abort();
+
+  if (test4f(1.0f,1.0f) != 1.0f)
+    abort();
+  if (test4f(1.0f,-1.0f) != 1.0f)
+    abort();
+  if (test4f(-1.0f,1.0f) != 1.0f)
+    abort();
+  if (test4f(-1.0f,-1.0f) != 1.0f)
+    abort();
+  if (test4f(6.0f,3.0f) != 4.0f)
+    abort();
+  if (test4f(6.0f,-3.0f) != 4.0f)
+    abort();
+  if (test4f(-6.0f,3.0f) != 4.0f)
+    abort();
+  if (test4f(-6.0f,-3.0f) != 4.0f)
+    abort();
+
+  return 0;
+}
+
diff --git a/gcc/testsuite/gcc.dg/builtins-49.c b/gcc/testsuite/gcc.dg/builtins-49.c
new file mode 100644 (file)
index 0000000..fdeaad4
--- /dev/null
@@ -0,0 +1,181 @@
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+extern double fabs(double);
+extern float fabsf(float);
+extern void abort(void);
+
+
+double test1(double x)
+{
+  return fabs(-x);
+}
+
+float test1f(float x)
+{
+  return fabsf(-x);
+}
+
+double test2(double x)
+{
+  return fabs(fabs(x));
+}
+
+float test2f(float x)
+{
+  return fabsf(fabsf(x));
+}
+
+double test3(double x, double y)
+{
+  return fabs(x*-y);
+}
+
+float test3f(float x, float y)
+{
+  return fabsf(x*-y);
+}
+
+double test4(double x, double y)
+{
+  return fabs(x/-y);
+}
+
+float test4f(float x, float y)
+{
+  return fabsf(x/-y);
+}
+
+int main()
+{
+  if (test1(1.0) != 1.0)
+    abort();
+  if (test1(2.0) != 2.0)
+    abort();
+  if (test1(0.0) != 0.0)
+    abort();
+  if (test1(-1.0) != 1.0)
+    abort();
+  if (test1(-2.0) != 2.0)
+    abort();
+
+  if (test1f(1.0f) != 1.0f)
+    abort();
+  if (test1f(2.0f) != 2.0f)
+    abort();
+  if (test1f(0.0f) != 0.0f)
+    abort();
+  if (test1f(-1.0f) != 1.0f)
+    abort();
+  if (test1f(-2.0f) != 2.0f)
+    abort();
+
+  if (test2(1.0) != 1.0)
+    abort();
+  if (test2(2.0) != 2.0)
+    abort();
+  if (test2(0.0) != 0.0)
+    abort();
+  if (test2(-1.0) != 1.0)
+    abort();
+  if (test2(-2.0) != 2.0)
+    abort();
+
+  if (test2f(1.0f) != 1.0f)
+    abort();
+  if (test2f(2.0f) != 2.0f)
+    abort();
+  if (test2f(0.0f) != 0.0f)
+    abort();
+  if (test2f(-1.0f) != 1.0f)
+    abort();
+  if (test2f(-2.0f) != 2.0f)
+    abort();
+
+  if (test3(1.0,1.0) != 1.0)
+    abort();
+  if (test3(1.0,-1.0) != 1.0)
+    abort();
+  if (test3(1.0,2.0) != 2.0)
+    abort();
+  if (test3(1.0,-2.0) != 2.0)
+    abort();
+  if (test3(2.0,1.0) != 2.0)
+    abort();
+  if (test3(2.0,-1.0) != 2.0)
+    abort();
+  if (test3(2.0,2.0) != 4.0)
+    abort();
+  if (test3(2.0,-2.0) != 4.0)
+    abort();
+  if (test3(-2.0,1.0) != 2.0)
+    abort();
+  if (test3(-2.0,-1.0) != 2.0)
+    abort();
+  if (test3(-2.0,2.0) != 4.0)
+    abort();
+  if (test3(-2.0,-2.0) != 4.0)
+    abort();
+
+  if (test3f(1.0f,1.0f) != 1.0f)
+    abort();
+  if (test3f(1.0f,-1.0f) != 1.0f)
+    abort();
+  if (test3f(1.0f,2.0f) != 2.0f)
+    abort();
+  if (test3f(1.0f,-2.0f) != 2.0f)
+    abort();
+  if (test3f(2.0f,1.0f) != 2.0f)
+    abort();
+  if (test3f(2.0f,-1.0f) != 2.0f)
+    abort();
+  if (test3f(2.0f,2.0f) != 4.0f)
+    abort();
+  if (test3f(2.0f,-2.0f) != 4.0f)
+    abort();
+  if (test3f(-2.0f,1.0f) != 2.0f)
+    abort();
+  if (test3f(-2.0f,-1.0f) != 2.0f)
+    abort();
+  if (test3f(-2.0f,2.0f) != 4.0f)
+    abort();
+  if (test3f(-2.0f,-2.0f) != 4.0f)
+    abort();
+
+  if (test4(1.0,1.0) != 1.0)
+    abort();
+  if (test4(1.0,-1.0) != 1.0)
+    abort();
+  if (test4(-1.0,1.0) != 1.0)
+    abort();
+  if (test4(-1.0,-1.0) != 1.0)
+    abort();
+  if (test4(6.0,3.0) != 2.0)
+    abort();
+  if (test4(6.0,-3.0) != 2.0)
+    abort();
+  if (test4(-6.0,3.0) != 2.0)
+    abort();
+  if (test4(-6.0,-3.0) != 2.0)
+    abort();
+
+  if (test4f(1.0f,1.0f) != 1.0f)
+    abort();
+  if (test4f(1.0f,-1.0f) != 1.0f)
+    abort();
+  if (test4f(-1.0f,1.0f) != 1.0f)
+    abort();
+  if (test4f(-1.0f,-1.0f) != 1.0f)
+    abort();
+  if (test4f(6.0f,3.0f) != 2.0f)
+    abort();
+  if (test4f(6.0f,-3.0f) != 2.0f)
+    abort();
+  if (test4f(-6.0f,3.0f) != 2.0f)
+    abort();
+  if (test4f(-6.0f,-3.0f) != 2.0f)
+    abort();
+
+  return 0;
+}
+
diff --git a/gcc/testsuite/gcc.dg/builtins-50.c b/gcc/testsuite/gcc.dg/builtins-50.c
new file mode 100644 (file)
index 0000000..2d32d1e
--- /dev/null
@@ -0,0 +1,159 @@
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+extern double copysign(double,double);
+extern float copysignf(float,float);
+extern double fabs(double);
+extern float fabsf(float);
+extern void abort(void);
+
+
+double test1(double x, double y)
+{
+  return copysign(-x,y);
+}
+
+float test1f(float x, float y)
+{
+  return copysignf(-x,y);
+}
+
+double test2(double x, double y)
+{
+  return copysign(fabs(x),y);
+}
+
+float test2f(float x, float y)
+{
+  return copysignf(fabsf(x),y);
+}
+
+double test3(double x, double y, double z)
+{
+  return copysign(x*-y,z);
+}
+
+float test3f(float x, float y, float z)
+{
+  return copysignf(x*-y,z);
+}
+
+double test4(double x, double y, double z)
+{
+  return copysign(x/-y,z);
+}
+
+float test4f(float x, float y, float z)
+{
+  return copysignf(x/-y,z);
+}
+
+int main()
+{
+  if (test1(3.0,2.0) != 3.0)
+    abort();
+  if (test1(3.0,-2.0) != -3.0)
+    abort();
+  if (test1(-3.0,2.0) != 3.0)
+    abort();
+  if (test1(-3.0,-2.0) != -3.0)
+    abort();
+
+  if (test1f(3.0f,2.0f) != 3.0f)
+    abort();
+  if (test1f(3.0f,-2.0f) != -3.0f)
+    abort();
+  if (test1f(-3.0f,2.0f) != 3.0f)
+    abort();
+  if (test1f(-3.0f,-2.0f) != -3.0f)
+    abort();
+
+  if (test2(3.0,2.0) != 3.0)
+    abort();
+  if (test2(3.0,-2.0) != -3.0)
+    abort();
+  if (test2(-3.0,2.0) != 3.0)
+    abort();
+  if (test2(-3.0,-2.0) != -3.0)
+    abort();
+
+  if (test2f(3.0f,2.0f) != 3.0f)
+    abort();
+  if (test2f(3.0f,-2.0f) != -3.0f)
+    abort();
+  if (test2f(-3.0f,2.0f) != 3.0f)
+    abort();
+  if (test2f(-3.0f,-2.0f) != -3.0f)
+    abort();
+
+  if (test3(2.0,3.0,4.0) != 6.0)
+    abort();
+  if (test3(2.0,3.0,-4.0) != -6.0)
+    abort();
+  if (test3(2.0,-3.0,4.0) != 6.0)
+    abort();
+  if (test3(2.0,-3.0,-4.0) != -6.0)
+    abort();
+  if (test3(-2.0,3.0,4.0) != 6.0)
+    abort();
+  if (test3(-2.0,3.0,-4.0) != -6.0)
+    abort();
+  if (test3(-2.0,-3.0,4.0) != 6.0)
+    abort();
+  if (test3(-2.0,-3.0,-4.0) != -6.0)
+    abort();
+
+  if (test3f(2.0f,3.0f,4.0f) != 6.0f)
+    abort();
+  if (test3f(2.0f,3.0f,-4.0f) != -6.0f)
+    abort();
+  if (test3f(2.0f,-3.0f,4.0f) != 6.0f)
+    abort();
+  if (test3f(2.0f,-3.0f,-4.0f) != -6.0f)
+    abort();
+  if (test3f(-2.0f,3.0f,4.0f) != 6.0f)
+    abort();
+  if (test3f(-2.0f,3.0f,-4.0f) != -6.0f)
+    abort();
+  if (test3f(-2.0f,-3.0f,4.0f) != 6.0f)
+    abort();
+  if (test3f(-2.0f,-3.0f,-4.0f) != -6.0f)
+    abort();
+
+  if (test4(8.0,2.0,3.0) != 4.0)
+    abort();
+  if (test4(8.0,2.0,-3.0) != -4.0)
+    abort();
+  if (test4(8.0,-2.0,3.0) != 4.0)
+    abort();
+  if (test4(8.0,-2.0,-3.0) != -4.0)
+    abort();
+  if (test4(-8.0,2.0,3.0) != 4.0)
+    abort();
+  if (test4(-8.0,2.0,-3.0) != -4.0)
+    abort();
+  if (test4(-8.0,-2.0,3.0) != 4.0)
+    abort();
+  if (test4(-8.0,-2.0,-3.0) != -4.0)
+    abort();
+
+  if (test4f(8.0f,2.0f,3.0f) != 4.0f)
+    abort();
+  if (test4f(8.0f,2.0f,-3.0f) != -4.0f)
+    abort();
+  if (test4f(8.0f,-2.0f,3.0f) != 4.0f)
+    abort();
+  if (test4f(8.0f,-2.0f,-3.0f) != -4.0f)
+    abort();
+  if (test4f(-8.0f,2.0f,3.0f) != 4.0f)
+    abort();
+  if (test4f(-8.0f,2.0f,-3.0f) != -4.0f)
+    abort();
+  if (test4f(-8.0f,-2.0f,3.0f) != 4.0f)
+    abort();
+  if (test4f(-8.0f,-2.0f,-3.0f) != -4.0f)
+    abort();
+
+  return 0;
+}
+
diff --git a/gcc/testsuite/gcc.dg/builtins-51.c b/gcc/testsuite/gcc.dg/builtins-51.c
new file mode 100644 (file)
index 0000000..fdfc9be
--- /dev/null
@@ -0,0 +1,157 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -ffast-math" } */
+
+extern double pow(double, double);
+extern double fabs(double);
+extern void abort(void);
+
+double test2_1(double x)
+{
+  return pow(x,2.0);
+}
+
+double test2_2(double x)
+{
+  return pow(-x,2.0);
+}
+
+double test2_3(double x)
+{
+  return pow(fabs(x),2.0);
+}
+
+double test3_1(double x)
+{
+  return pow(x,3.0);
+}
+
+double test3_2(double x)
+{
+  return pow(-x,3.0);
+}
+
+double test3_3(double x)
+{
+  return pow(fabs(x),3.0);
+}
+
+double test6_1(double x)
+{
+  return pow(x,6.0);
+}
+
+double test6_2(double x)
+{
+  return pow(-x,6.0);
+}
+
+double test6_3(double x)
+{
+  return pow(fabs(x),6.0);
+}
+
+
+int main()
+{
+  if (test2_1(1.0) != 1.0)
+    abort();
+  if (test2_1(2.0) != 4.0)
+    abort();
+  if (test2_1(0.0) != 0.0)
+    abort();
+  if (test2_1(-1.0) != 1.0)
+    abort();
+  if (test2_1(-2.0) != 4.0)
+    abort();
+
+  if (test2_2(1.0) != 1.0)
+    abort();
+  if (test2_2(2.0) != 4.0)
+    abort();
+  if (test2_2(0.0) != 0.0)
+    abort();
+  if (test2_2(-1.0) != 1.0)
+    abort();
+  if (test2_2(-2.0) != 4.0)
+    abort();
+
+  if (test2_3(1.0) != 1.0)
+    abort();
+  if (test2_3(2.0) != 4.0)
+    abort();
+  if (test2_3(0.0) != 0.0)
+    abort();
+  if (test2_3(-1.0) != 1.0)
+    abort();
+  if (test2_3(2.0) != 4.0)
+    abort();
+
+  if (test3_1(1.0) != 1.0)
+    abort();
+  if (test3_1(2.0) != 8.0)
+    abort();
+  if (test3_1(0.0) != 0.0)
+    abort();
+  if (test3_1(-1.0) != -1.0)
+    abort();
+  if (test3_1(-2.0) != -8.0)
+    abort();
+
+  if (test3_2(1.0) != -1.0)
+    abort();
+  if (test3_2(2.0) != -8.0)
+    abort();
+  if (test3_2(0.0) != -0.0)
+    abort();
+  if (test3_2(-1.0) != 1.0)
+    abort();
+  if (test3_2(-2.0) != 8.0)
+    abort();
+
+  if (test3_3(1.0) != 1.0)
+    abort();
+  if (test3_3(2.0) != 8.0)
+    abort();
+  if (test3_3(0.0) != 0.0)
+    abort();
+  if (test3_3(-1.0) != 1.0)
+    abort();
+  if (test3_3(-2.0) != 8.0)
+    abort();
+
+  if (test6_1(1.0) != 1.0)
+    abort();
+  if (test6_1(2.0) != 64.0)
+    abort();
+  if (test6_1(0.0) != 0.0)
+    abort();
+  if (test6_1(-1.0) != 1.0)
+    abort();
+  if (test6_1(-2.0) != 64.0)
+    abort();
+
+  if (test6_2(1.0) != 1.0)
+    abort();
+  if (test6_2(2.0) != 64.0)
+    abort();
+  if (test6_2(0.0) != 0.0)
+    abort();
+  if (test6_2(-1.0) != 1.0)
+    abort();
+  if (test6_2(-2.0) != 64.0)
+    abort();
+
+  if (test6_3(1.0) != 1.0)
+    abort();
+  if (test6_3(2.0) != 64.0)
+    abort();
+  if (test6_3(0.0) != 0.0)
+    abort();
+  if (test6_3(-1.0) != 1.0)
+    abort();
+  if (test6_3(-2.0) != 64.0)
+    abort();
+
+  return 0;
+}
+
index 47f65c8..e64fb99 100644 (file)
@@ -3527,7 +3527,8 @@ extern tree fold_binary_to_constant (enum tree_code, tree, tree, tree);
 extern tree fold_read_from_constant_string (tree);
 extern tree int_const_binop (enum tree_code, tree, tree, int);
 extern tree build_fold_addr_expr (tree);
-tree fold_build_cleanup_point_expr (tree type, tree expr);
+extern tree fold_build_cleanup_point_expr (tree type, tree expr);
+extern tree fold_strip_sign_ops (tree);
 extern tree build_fold_addr_expr_with_type (tree, tree);
 extern tree build_fold_indirect_ref (tree);
 extern tree constant_boolean_node (int, tree);