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 folding for cabs and fabs (take 2)


On Thu, 5 Jun 2003, Richard Henderson wrote:
> On Thu, Jun 05, 2003 at 08:29:59AM -0600, Roger Sayle wrote:
> > +     case BUILT_IN_CABS:
> > +     case BUILT_IN_CABSF:
> > +     case BUILT_IN_CABSL:
>
> Please break this out into a separate function.
> Otherwise I think the cleanups are generally ok.

The following patch implements this recommedation.  Whilst I was
at it, I also guarded the compile-time evaluation of cabs* with
flag_unsafe_math_optimizations.  I still believe the code in
question is fine, but life's too short to spend arguing with
Joseph.  All of OpenEye Scientific's products are compiled
with -ffast-math anyway :>

The following patch has been retested on i686-pc-linux-gnu with a
full "make bootstrap", all languages except treelang, and regression
tested with a top-level "make -k check" with no new failures.
For brevity, the testsuite changes are as posted previously.

Ok for mainline?


2003-06-05  Roger Sayle  <roger@eyesopen.com>

	* fold-const.c (fold <ABS_EXPR>):  Re-fold the result of folding
	fabs(-x) into fabs(x).  Use tree_expr_nonnegative_p to determine
	when the ABS_EXPR (fabs or abs) is not required.
  	(tree_expr_nonnegative_p): Move the logic that sqrt and exp are
	always nonnegative from fold to here.  Additionally, cabs and fabs
	are always non-negative, and pow and atan are non-negative if
	their first argument is non-negative.

	* builtins.c (fold_builtin_cabs): New function to fold cabs{,f,l}.
	Evaluate cabs of a constant at compile-time.  Convert cabs of a
	non-complex argument into fabs.  Convert cabs(z) into
	sqrt(z.r*z.r + z.i*z.i) at the tree-level with -ffast-math or
	-funsafe-math-optimizations or -ffast-math.
	(fold_builtin): Convert BUILT_IN_FABS{,F,L} into an ABS_EXPR.
	Fold BUILT_IN_CABS{,F,L} using fold_builtin_cabs.

	* gcc.dg/builtins-2.c: Add some more tests.
	* gcc.dg/builtins-18.c: New test case.
	* gcc.dg/builtins-19.c: New test case.


Index: fold-const.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fold-const.c,v
retrieving revision 1.254
diff -c -3 -p -r1.254 fold-const.c
*** fold-const.c	31 May 2003 13:23:28 -0000	1.254
--- fold-const.c	5 Jun 2003 23:41:46 -0000
*************** fold (expr)
*** 5405,5433 ****
  				REAL_VALUE_NEGATE (TREE_REAL_CST (arg0)));
  	    }
  	}
!       else if (TREE_CODE (arg0) == ABS_EXPR || TREE_CODE (arg0) == NEGATE_EXPR)
! 	return build1 (ABS_EXPR, type, TREE_OPERAND (arg0, 0));
        /* Convert fabs((double)float) into (double)fabsf(float).  */
        else if (TREE_CODE (arg0) == NOP_EXPR
  	       && TREE_CODE (type) == REAL_TYPE)
  	{
  	  tree targ0 = strip_float_extensions (arg0);
  	  if (targ0 != arg0)
! 	    return convert (type, build1 (ABS_EXPR, TREE_TYPE (targ0), targ0));
!
! 	}
!       else
! 	{
! 	  /* fabs(sqrt(x)) = sqrt(x) and fabs(exp(x)) = exp(x).  */
! 	  enum built_in_function fcode = builtin_mathfn_code (arg0);
! 	  if (fcode == BUILT_IN_SQRT
! 	      || fcode == BUILT_IN_SQRTF
! 	      || fcode == BUILT_IN_SQRTL
! 	      || fcode == BUILT_IN_EXP
! 	      || fcode == BUILT_IN_EXPF
! 	      || fcode == BUILT_IN_EXPL)
! 	    t = arg0;
  	}
        return t;

      case CONJ_EXPR:
--- 5405,5423 ----
  				REAL_VALUE_NEGATE (TREE_REAL_CST (arg0)));
  	    }
  	}
!       else if (TREE_CODE (arg0) == NEGATE_EXPR)
! 	return fold (build1 (ABS_EXPR, type, TREE_OPERAND (arg0, 0)));
        /* Convert fabs((double)float) into (double)fabsf(float).  */
        else if (TREE_CODE (arg0) == NOP_EXPR
  	       && TREE_CODE (type) == REAL_TYPE)
  	{
  	  tree targ0 = strip_float_extensions (arg0);
  	  if (targ0 != arg0)
! 	    return convert (type, fold (build1 (ABS_EXPR, TREE_TYPE (targ0),
! 						targ0)));
  	}
+       else if (tree_expr_nonnegative_p (arg0))
+ 	return arg0;
        return t;

      case CONJ_EXPR:
*************** tree_expr_nonnegative_p (t)
*** 7927,7932 ****
--- 7917,7963 ----
        return tree_expr_nonnegative_p (TREE_OPERAND (t, 0));
      case RTL_EXPR:
        return rtl_expr_nonnegative_p (RTL_EXPR_RTL (t));
+
+     case CALL_EXPR:
+       if (TREE_CODE (TREE_OPERAND (t, 0)) == ADDR_EXPR)
+ 	{
+ 	  tree fndecl = TREE_OPERAND (TREE_OPERAND (t, 0), 0);
+ 	  tree arglist = TREE_OPERAND (t, 1);
+ 	  if (TREE_CODE (fndecl) == FUNCTION_DECL
+ 	      && DECL_BUILT_IN (fndecl)
+ 	      && DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_MD)
+ 	    switch (DECL_FUNCTION_CODE (fndecl))
+ 	      {
+ 	      case BUILT_IN_CABS:
+ 	      case BUILT_IN_CABSL:
+ 	      case BUILT_IN_CABSF:
+ 	      case BUILT_IN_EXP:
+ 	      case BUILT_IN_EXPF:
+ 	      case BUILT_IN_EXPL:
+ 	      case BUILT_IN_FABS:
+ 	      case BUILT_IN_FABSF:
+ 	      case BUILT_IN_FABSL:
+ 	      case BUILT_IN_SQRT:
+ 	      case BUILT_IN_SQRTF:
+ 	      case BUILT_IN_SQRTL:
+ 		return 1;
+
+ 	      case BUILT_IN_ATAN:
+ 	      case BUILT_IN_ATANF:
+ 	      case BUILT_IN_ATANL:
+ 		return tree_expr_nonnegative_p (TREE_VALUE (arglist));
+
+ 	      case BUILT_IN_POW:
+ 	      case BUILT_IN_POWF:
+ 	      case BUILT_IN_POWL:
+ 		return tree_expr_nonnegative_p (TREE_VALUE (arglist));
+
+ 	      default:
+ 		break;
+ 	      }
+ 	}
+
+       /* ... fall through ... */

      default:
        if (truth_value_p (TREE_CODE (t)))
Index: builtins.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/builtins.c,v
retrieving revision 1.208
diff -c -3 -p -r1.208 builtins.c
*** builtins.c	4 Jun 2003 12:20:35 -0000	1.208
--- builtins.c	5 Jun 2003 23:41:48 -0000
*************** static bool readonly_data_expr		PARAMS (
*** 177,182 ****
--- 177,183 ----
  static rtx expand_builtin_fabs		PARAMS ((tree, rtx, rtx));
  static rtx expand_builtin_cabs		PARAMS ((tree, rtx));
  static void init_builtin_dconsts	PARAMS ((void));
+ static tree fold_builtin_cabs		PARAMS ((tree, tree, tree));

  /* Initialize mathematical constants for constant folding builtins.
     These constants need to be given to atleast 160 bits precision.  */
*************** fold_trunc_transparent_mathfn (exp)
*** 5135,5140 ****
--- 5136,5227 ----
    return 0;
  }

+ /* Fold function call to builtin cabs, cabsf or cabsl.  FNDECL is the
+    function's DECL, ARGLIST is the argument list and TYPE is the return
+    type.  Return NULL_TREE if no simplification can be made.  */
+
+ static tree
+ fold_builtin_cabs (fndecl, arglist, type)
+      tree fndecl, arglist, type;
+ {
+   tree arg;
+
+   if (!arglist || TREE_CHAIN (arglist))
+     return NULL_TREE;
+
+   arg = TREE_VALUE (arglist);
+   if (TREE_CODE (TREE_TYPE (arg)) != COMPLEX_TYPE
+       || TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) != REAL_TYPE)
+     return NULL_TREE;
+
+   /* Evaluate cabs of a constant at compile-time.  */
+   if (flag_unsafe_math_optimizations
+       && TREE_CODE (arg) == COMPLEX_CST
+       && TREE_CODE (TREE_REALPART (arg)) == REAL_CST
+       && TREE_CODE (TREE_IMAGPART (arg)) == REAL_CST
+       && ! TREE_CONSTANT_OVERFLOW (TREE_REALPART (arg))
+       && ! TREE_CONSTANT_OVERFLOW (TREE_IMAGPART (arg)))
+     {
+       REAL_VALUE_TYPE r, i;
+
+       r = TREE_REAL_CST (TREE_REALPART (arg));
+       i = TREE_REAL_CST (TREE_IMAGPART (arg));
+
+       real_arithmetic (&r, MULT_EXPR, &r, &r);
+       real_arithmetic (&i, MULT_EXPR, &i, &i);
+       real_arithmetic (&r, PLUS_EXPR, &r, &i);
+       if (real_sqrt (&r, TYPE_MODE (type), &r)
+ 	  || ! flag_trapping_math)
+ 	return build_real (type, r);
+     }
+
+   /* If either part is zero, cabs is fabs of the other.  */
+   if (TREE_CODE (arg) == COMPLEX_EXPR
+       && real_zerop (TREE_OPERAND (arg, 0)))
+     return fold (build1 (ABS_EXPR, type, TREE_OPERAND (arg, 1)));
+   if (TREE_CODE (arg) == COMPLEX_EXPR
+       && real_zerop (TREE_OPERAND (arg, 1)))
+     return fold (build1 (ABS_EXPR, type, TREE_OPERAND (arg, 0)));
+
+   if (flag_unsafe_math_optimizations)
+     {
+       enum built_in_function fcode;
+       tree sqrtfn;
+
+       fcode = DECL_FUNCTION_CODE (fndecl);
+       if (fcode == BUILT_IN_CABS)
+ 	sqrtfn = implicit_built_in_decls[BUILT_IN_SQRT];
+       else if (fcode == BUILT_IN_CABSF)
+ 	sqrtfn = implicit_built_in_decls[BUILT_IN_SQRTF];
+       else if (fcode == BUILT_IN_CABSL)
+ 	sqrtfn = implicit_built_in_decls[BUILT_IN_SQRTL];
+       else
+ 	sqrtfn = NULL_TREE;
+
+       if (sqrtfn != NULL_TREE)
+ 	{
+ 	  tree rpart, ipart, result, arglist;
+
+ 	  rpart = fold (build1 (REALPART_EXPR, type, arg));
+ 	  ipart = fold (build1 (IMAGPART_EXPR, type, arg));
+
+ 	  rpart = save_expr (rpart);
+ 	  ipart = save_expr (ipart);
+
+ 	  result = fold (build (PLUS_EXPR, type,
+ 				fold (build (MULT_EXPR, type,
+ 					     rpart, rpart)),
+ 				fold (build (MULT_EXPR, type,
+ 					     ipart, ipart))));
+
+ 	  arglist = build_tree_list (NULL_TREE, result);
+ 	  return build_function_call_expr (sqrtfn, arglist);
+ 	}
+     }
+
+   return NULL_TREE;
+ }
+
  /* Used by constant folding to eliminate some builtin calls early.  EXP is
     the CALL_EXPR of a call to a builtin function.  */

*************** fold_builtin (exp)
*** 5170,5175 ****
--- 5257,5274 ----
  	    }
  	}
        break;
+
+     case BUILT_IN_FABS:
+     case BUILT_IN_FABSF:
+     case BUILT_IN_FABSL:
+       if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
+ 	return fold (build1 (ABS_EXPR, type, TREE_VALUE (arglist)));
+       break;
+
+     case BUILT_IN_CABS:
+     case BUILT_IN_CABSF:
+     case BUILT_IN_CABSL:
+       return fold_builtin_cabs (fndecl, arglist, type);

      case BUILT_IN_SQRT:
      case BUILT_IN_SQRTF:

Roger
--


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