This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Constant fold fabs(x)*fabs(x) as x*x


This patch addresses a missed constant folding optimization highlighted
by the recent partial fix to PR middle-end/19775.  As pointed out by
Richard Guenther in a posting now lost from gcc.gnu.org/ml/gcc-patches,
we currently fail to recognize that fabs(x)*fabs(x) == x*x, which leads
to a regression in our optimization of sqrt(pow(x,4.0)).

The patch below implements this via a new function "fold_strip_sign_ops"
that is intended to simplify a floating point expression under the
assumption that the sign of the result isn't relevant.  For example,
-x reduces to x, fabs(x) reduces to x, and x/-y reduces to x/y when
we don't care about sign dependent rounding.  This handy subroutine
can then be used in several places in addition to the "squaring" x*x
multiplications above, including the arguments to "fabs" and "fabsf",
the first argument to "copysign", and also the first argument to "pow"
when we know the second argument is an even-valued integer.  The last
of these I've guarded with flag_unsafe_math_optimizations just in case
the system provided pow doesn't guarantee pow(x,n) == pow(-x,n) for
some values of x and even n.

There are plenty more tricks that can be played, for example with "cos"
and floating point constants, but the patch below is enough to resolve
this regression, and demonstrate the proof-of-concept.


The following patch has been tested on i686-pc-linux-gnu with a full
"make bootstrap", all default languages, and regression tested with a
top-level "make -k check" with no new failures.

Ok for mainline?



2005-02-08  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.

	* 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.


Index: fold-const.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fold-const.c,v
retrieving revision 1.502
diff -c -3 -p -r1.502 fold-const.c
*** fold-const.c	3 Feb 2005 06:44:34 -0000	1.502
--- fold-const.c	8 Feb 2005 03:34:20 -0000
*************** fold (tree expr)
*** 6776,6781 ****
--- 6776,6789 ----
  	}
        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:
*************** fold (tree expr)
*** 7429,7434 ****
--- 7437,7453 ----
  				     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);
*************** ptr_difference_const (tree e1, tree e2,
*** 11229,11231 ****
--- 11248,11285 ----
    *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: tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.h,v
retrieving revision 1.685
diff -c -3 -p -r1.685 tree.h
*** tree.h	7 Feb 2005 10:06:53 -0000	1.685
--- tree.h	8 Feb 2005 03:34:21 -0000
*************** extern tree fold_binary_to_constant (enu
*** 3527,3533 ****
  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 build_fold_addr_expr_with_type (tree, tree);
  extern tree build_fold_indirect_ref (tree);
  extern tree constant_boolean_node (int, tree);
--- 3527,3534 ----
  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);
! 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);
Index: builtins.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/builtins.c,v
retrieving revision 1.416
diff -c -3 -p -r1.416 builtins.c
*** builtins.c	7 Feb 2005 13:24:35 -0000	1.416
--- builtins.c	8 Feb 2005 03:34:27 -0000
*************** static tree fold_builtin_memcmp (tree);
*** 169,175 ****
  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);
--- 169,175 ----
  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, tree);
  static tree fold_builtin_isascii (tree);
  static tree fold_builtin_toascii (tree);
  static tree fold_builtin_isdigit (tree);
*************** fold_builtin_pow (tree fndecl, tree argl
*** 6775,6781 ****
--- 6775,6784 ----
    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.  */
*************** fold_builtin_pow (tree fndecl, tree argl
*** 6805,6821 ****
  	    }
  	}

!       /* Attempt to evaluate pow at compile-time.  */
!       if (TREE_CODE (arg0) == REAL_CST
! 	  && ! TREE_CONSTANT_OVERFLOW (arg0))
  	{
! 	  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))
  	    {
  	      REAL_VALUE_TYPE x;
  	      bool inexact;
--- 6808,6821 ----
  	    }
  	}

!       /* 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))
  	{
! 	  /* Attempt to evaluate pow at compile-time.  */
! 	  if (TREE_CODE (arg0) == REAL_CST
! 	      && ! TREE_CONSTANT_OVERFLOW (arg0))
  	    {
  	      REAL_VALUE_TYPE x;
  	      bool inexact;
*************** fold_builtin_pow (tree fndecl, tree argl
*** 6825,6830 ****
--- 6825,6841 ----
  	      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 = tree_cons (NULL_TREE, narg0, TREE_CHAIN (arglist));
+ 		  return build_function_call_expr (fndecl, arglist);
+ 		}
+ 	    }
  	}
      }

*************** fold_builtin_signbit (tree exp)
*** 7378,7386 ****
     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;
--- 7389,7397 ----
     Return NULL_TREE if no simplification can be made.  */

  static tree
! fold_builtin_copysign (tree fndecl, tree arglist, tree type)
  {
!   tree arg1, arg2, tem;

    if (!validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE))
      return NULL_TREE;
*************** fold_builtin_copysign (tree arglist, tre
*** 7414,7419 ****
--- 7425,7438 ----
  			     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;
  }

*************** fold_builtin_1 (tree exp, bool ignore)
*** 7987,7993 ****
      case BUILT_IN_COPYSIGN:
      case BUILT_IN_COPYSIGNF:
      case BUILT_IN_COPYSIGNL:
!       return fold_builtin_copysign (arglist, type);

      case BUILT_IN_FINITE:
      case BUILT_IN_FINITEF:
--- 8006,8012 ----
      case BUILT_IN_COPYSIGN:
      case BUILT_IN_COPYSIGNF:
      case BUILT_IN_COPYSIGNL:
!       return fold_builtin_copysign (fndecl, arglist, type);

      case BUILT_IN_FINITE:
      case BUILT_IN_FINITEF:


/* { 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;
}


/* { 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;
}


/* { 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;
}


/* { 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;
}


Roger
--
Roger Sayle,                         E-mail: roger@eyesopen.com
OpenEye Scientific Software,         WWW: http://www.eyesopen.com/
Suite 1107, 3600 Cerrillos Road,     Tel: (+1) 505-473-7385
Santa Fe, New Mexico, 87507.         Fax: (+1) 505-473-0833


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]