[PATCH] Constant folding for cabs and fabs (take 2)
Roger Sayle
roger@eyesopen.com
Fri Jun 6 03:47:00 GMT 2003
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
--
More information about the Gcc-patches
mailing list