aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorRoger Sayle <roger@eyesopen.com>2005-02-09 21:56:35 +0000
committerRoger Sayle <sayle@gcc.gnu.org>2005-02-09 21:56:35 +0000
commite3bb43c0fef35c410538453c6a70a22822e03b10 (patch)
treeb165cf0028ec1a832fc59f34df44d639c9c318a2 /gcc
parent08c2481a791a11ac8aee6652c6fb8c57faf4d584 (diff)
downloadgcc-e3bb43c0fef35c410538453c6a70a22822e03b10.zip
gcc-e3bb43c0fef35c410538453c6a70a22822e03b10.tar.gz
gcc-e3bb43c0fef35c410538453c6a70a22822e03b10.tar.bz2
fold-const.c (fold_strip_sign_ops): New function to simplify a floating point expression ignoring the sign of the...
* 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. * 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. From-SVN: r94779
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog15
-rw-r--r--gcc/builtins.c48
-rw-r--r--gcc/fold-const.c54
-rw-r--r--gcc/testsuite/ChangeLog7
-rw-r--r--gcc/testsuite/gcc.dg/builtins-48.c181
-rw-r--r--gcc/testsuite/gcc.dg/builtins-49.c181
-rw-r--r--gcc/testsuite/gcc.dg/builtins-50.c159
-rw-r--r--gcc/testsuite/gcc.dg/builtins-51.c157
-rw-r--r--gcc/tree.h3
9 files changed, 789 insertions, 16 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 37d3e05..f9d60df 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 3631615..56e7eb0 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -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:
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 294f94c..de54258 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -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;
+}
+
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 12f30eb..17a5558 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
index 0000000..43710b8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/builtins-48.c
@@ -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
index 0000000..fdeaad4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/builtins-49.c
@@ -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
index 0000000..2d32d1e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/builtins-50.c
@@ -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
index 0000000..fdfc9be
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/builtins-51.c
@@ -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;
+}
+
diff --git a/gcc/tree.h b/gcc/tree.h
index 47f65c8..e64fb99 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -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);