public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] Constant fold copysign
@ 2004-06-06 17:02 Roger Sayle
  2004-06-07 19:04 ` Richard Henderson
  0 siblings, 1 reply; 2+ messages in thread
From: Roger Sayle @ 2004-06-06 17:02 UTC (permalink / raw)
  To: gcc-patches


The following patch implements some constant folding transformations
of libm's copysign, copysignf and copysignl, including compile-time
evaluation of constant arguments.  Additionally, we now transform
copysign(x,x) as x, and copysign(x,y) as fabs(x) when y is known to
be non-negative.

There may also be some minor benefits to converting "copysign(x,y)"
into "copysign(fabs(x),y)" when x is a compile-time constants.  This
may reduce the size of constant pools, and for example, on x86 allow
us to use the "fld1" instruction for "copysign(-1.0,y)".

I also caught a potential problem with tree_expr_nonnegative_p.  The
functions sqrt, sqrtf and sqrtl can potentially return negative results
when using IEEE arithmetic, as sqrt(-0.0) is -0.0.  This case is caught
below by checking that the argument to sqrt is non-negative when we
honor signed zeros.


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.

If there are no objections, I propose to commit this to mainline CVS
in few days.




2004-06-06  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}.

	* gcc.dg/builtins-41.c: New test case.
	* gcc.dg/builtins-42.c: New test case.


Index: real.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/real.c,v
retrieving revision 1.142
diff -c -3 -p -r1.142 real.c
*** real.c	28 May 2004 16:37:01 -0000	1.142
--- real.c	6 Jun 2004 04:09:27 -0000
*************** real_round (REAL_VALUE_TYPE *r, enum mac
*** 4587,4589 ****
--- 4587,4597 ----
      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: real.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/real.h,v
retrieving revision 1.77
diff -c -3 -p -r1.77 real.h
*** real.h	22 Mar 2004 00:40:44 -0000	1.77
--- real.h	6 Jun 2004 04:09:27 -0000
*************** extern void real_ceil (REAL_VALUE_TYPE *
*** 384,387 ****
--- 384,390 ----
  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: fold-const.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fold-const.c,v
retrieving revision 1.387
diff -c -3 -p -r1.387 fold-const.c
*** fold-const.c	31 May 2004 17:01:16 -0000	1.387
--- fold-const.c	6 Jun 2004 04:09:29 -0000
*************** tree_expr_nonnegative_p (tree t)
*** 9024,9036 ****
  	    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_ASINH)
  	    CASE_BUILTIN_F (BUILT_IN_ATAN)
  	    CASE_BUILTIN_F (BUILT_IN_ATANH)
--- 9024,9041 ----
  	    CASE_BUILTIN_F (BUILT_IN_FREXP)
  	    CASE_BUILTIN_F (BUILT_IN_HYPOT)
  	    CASE_BUILTIN_F (BUILT_IN_POW10)
  	    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)
*************** tree_expr_nonnegative_p (tree t)
*** 9057,9073 ****
  	      /* True if the 1st argument is nonnegative.  */
  	      return tree_expr_nonnegative_p (TREE_VALUE (arglist));

! 	    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)
  	      /* 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)
  	      /* True if the 2nd argument is nonnegative.  */
  	      return tree_expr_nonnegative_p (TREE_VALUE (TREE_CHAIN (arglist)));

--- 9062,9078 ----
  	      /* True if the 1st argument is nonnegative.  */
  	      return tree_expr_nonnegative_p (TREE_VALUE (arglist));

! 	    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)
  	      /* 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)
  	      /* True if the 2nd argument is nonnegative.  */
  	      return tree_expr_nonnegative_p (TREE_VALUE (TREE_CHAIN (arglist)));

Index: builtins.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/builtins.c,v
retrieving revision 1.331
diff -c -3 -p -r1.331 builtins.c
*** builtins.c	2 Jun 2004 18:41:40 -0000	1.331
--- builtins.c	6 Jun 2004 04:09:31 -0000
*************** static tree fold_builtin_memcmp (tree);
*** 162,167 ****
--- 162,171 ----
  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);
*************** fold_builtin_signbit (tree exp)
*** 7298,7303 ****
--- 7302,7350 ----
    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
*************** fold_builtin_1 (tree exp)
*** 7577,7586 ****
--- 7624,7635 ----
      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:
*************** fold_builtin_1 (tree exp)
*** 7588,7608 ****
      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:
--- 7637,7657 ----
      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);
!
      case BUILT_IN_LOG2:
      case BUILT_IN_LOG2F:
      case BUILT_IN_LOG2L:
        return fold_builtin_logarithm (exp, &dconst2);
!
      case BUILT_IN_LOG10:
      case BUILT_IN_LOG10F:
      case BUILT_IN_LOG10L:
        return fold_builtin_logarithm (exp, &dconst10);

      case BUILT_IN_TAN:
      case BUILT_IN_TANF:
*************** fold_builtin_1 (tree exp)
*** 7884,7889 ****
--- 7933,7943 ----
      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;
      }


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


/* 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 -ffast-math" } */

extern void link_error(void);

extern double fabs(double);
extern float fabsf(float);

extern double copysign(double, double);
extern float copysignf(float, float);


void test1(double x)
{
  if (copysign(x,x) != x)
    link_error ();
}

void test1f(float x)
{
  if (copysignf(x,x) != x)
    link_error ();
}


void test2(double x)
{
  if (copysign(x, 1.0) != fabs(x))
    link_error ();
}

void test2f(float x)
{
  if (copysign(x, 1.0f) != fabsf(x))
    link_error ();
}



int main()
{
  test1(1.0);
  test2(1.0);

  test1f(1.0f);
  test2f(1.0f);

  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

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [PATCH] Constant fold copysign
  2004-06-06 17:02 [PATCH] Constant fold copysign Roger Sayle
@ 2004-06-07 19:04 ` Richard Henderson
  0 siblings, 0 replies; 2+ messages in thread
From: Richard Henderson @ 2004-06-07 19:04 UTC (permalink / raw)
  To: Roger Sayle; +Cc: gcc-patches

On Sun, Jun 06, 2004 at 10:12:30AM -0600, Roger Sayle wrote:
> 	* 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.

Ok.


r~

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2004-06-07 18:27 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-06-06 17:02 [PATCH] Constant fold copysign Roger Sayle
2004-06-07 19:04 ` Richard Henderson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).