[PATCH] Fix PR30197, folding of cexp ()
Richard Guenther
rguenther@suse.de
Wed Dec 13 17:16:00 GMT 2006
This adds folding of cexp ( __complex__ (x, y) ) to exp (x) * cexpi (y)
for unsafe_math if x != 0 and always in case x == 0. I don't have a
strong opinion on guarding the exp (x) * cexpi (y) transformation with
unsafe_math as all library implementations also suffer from this
extra rounding (they all decompose cexpi to exp() and sincos()).
The tree-ssa-pre.c part is to allow FRE combine and simplify
c = COMPLEX_EXPR <D.1979, D.1982>;
D.1984 = REALPART_EXPR <c>;
which no other pass does at the moment :/
(I can leave this part out and XFAIL the test4 check)
Bootstrapped and tested on x86_64-unknown-linux-gnu.
Will apply to mainline later.
Richard.
2006-12-06 Richard Guenther <rguenther@suse.de>
PR tree-optimization/30197
* builtins.c (fold_builtin_cexp): New function to fold cexp
to cexpi and exp parts.
* tree-ssa-pre.c (try_combine_conversion): Also handle
REALPART_EXPR and IMAGPART_EXPR.
* gcc.c-torture/execute/complex-1.c: Fix function name.
* gcc.dg/builtins-61.c: New testcase.
Index: builtins.c
===================================================================
*** builtins.c (revision 119828)
--- builtins.c (working copy)
*************** fold_builtin_sincos (tree arglist)
*** 7367,7372 ****
--- 7367,7433 ----
build1 (REALPART_EXPR, type, call)));
}
+ /* Fold function call to builtin cexp, cexpf, or cexpl. Return
+ NULL_TREE if no simplification can be made. */
+
+ static tree
+ fold_builtin_cexp (tree arglist, tree type)
+ {
+ tree arg0, rtype;
+ tree realp, imagp, ifn;
+
+ if (!validate_arglist (arglist, COMPLEX_TYPE, VOID_TYPE))
+ return NULL_TREE;
+
+ arg0 = TREE_VALUE (arglist);
+ rtype = TREE_TYPE (TREE_TYPE (arg0));
+
+ /* In case we can figure out the real part of arg0 and it is constant zero
+ fold to cexpi. */
+ ifn = mathfn_built_in (rtype, BUILT_IN_CEXPI);
+ if (!ifn)
+ return NULL_TREE;
+
+ if ((realp = fold_unary (REALPART_EXPR, rtype, arg0))
+ && real_zerop (realp))
+ {
+ tree narg = fold_build1 (IMAGPART_EXPR, rtype, arg0);
+ return build_function_call_expr (ifn, build_tree_list (NULL_TREE, narg));
+ }
+
+ /* In case we can easily decompose real and imaginary parts split cexp
+ to exp (r) * cexpi (i). */
+ if (flag_unsafe_math_optimizations
+ && realp)
+ {
+ tree rfn, rcall, icall;
+
+ rfn = mathfn_built_in (rtype, BUILT_IN_EXP);
+ if (!rfn)
+ return NULL_TREE;
+
+ imagp = fold_unary (IMAGPART_EXPR, rtype, arg0);
+ if (!imagp)
+ return NULL_TREE;
+
+ icall = build_function_call_expr (ifn,
+ build_tree_list (NULL_TREE, imagp));
+ icall = builtin_save_expr (icall);
+ rcall = build_function_call_expr (rfn,
+ build_tree_list (NULL_TREE, realp));
+ rcall = builtin_save_expr (rcall);
+ return build2 (COMPLEX_EXPR, type,
+ build2 (MULT_EXPR, rtype,
+ rcall,
+ build1 (REALPART_EXPR, rtype, icall)),
+ build2 (MULT_EXPR, rtype,
+ rcall,
+ build1 (IMAGPART_EXPR, rtype, icall)));
+ }
+
+ return NULL_TREE;
+ }
+
/* Fold function call to builtin trunc, truncf or truncl. Return
NULL_TREE if no simplification can be made. */
*************** fold_builtin_1 (tree fndecl, tree arglis
*** 9312,9317 ****
--- 9373,9381 ----
CASE_FLT_FN (BUILT_IN_SINCOS):
return fold_builtin_sincos (arglist);
+ CASE_FLT_FN (BUILT_IN_CEXP):
+ return fold_builtin_cexp (arglist, type);
+
CASE_FLT_FN (BUILT_IN_CEXPI):
if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
return do_mpfr_sincos (TREE_VALUE (arglist), NULL_TREE, NULL_TREE);
Index: testsuite/gcc.dg/builtins-61.c
===================================================================
*** testsuite/gcc.dg/builtins-61.c (revision 0)
--- testsuite/gcc.dg/builtins-61.c (revision 0)
***************
*** 0 ****
--- 1,31 ----
+ /* { dg-do compile } */
+ /* { dg-options "-O -ffast-math -fdump-tree-optimized" } */
+
+ double test1 (double x)
+ {
+ return __real __builtin_cexp(x * (__extension__ 1.0iF));
+ }
+
+ double test2(double x)
+ {
+ return __imag __builtin_cexp((__extension__ 1.0iF) * x);
+ }
+
+ double test3(double x)
+ {
+ _Complex c = __builtin_cexp(x * (__extension__ 1.0iF));
+ return __imag c + __real c;
+ }
+
+ double test4(double x, double y)
+ {
+ _Complex c = __builtin_cexp(x);
+ x = __builtin_exp (x);
+ return x - __real c;
+ }
+
+ /* { dg-final { scan-tree-dump "cexpi" "optimized" } } */
+ /* { dg-final { scan-tree-dump "sin" "optimized" } } */
+ /* { dg-final { scan-tree-dump "cos" "optimized" } } */
+ /* { dg-final { scan-tree-dump "return 0.0" "optimized" } } */
+ /* { dg-final { cleanup-tree-dump "optimized" } } */
Index: testsuite/gcc.c-torture/execute/complex-1.c
===================================================================
*** testsuite/gcc.c-torture/execute/complex-1.c (revision 119650)
--- testsuite/gcc.c-torture/execute/complex-1.c (working copy)
*************** g2 (double x)
*** 17,23 ****
}
__complex__ double
! cexp (__complex__ double x)
{
double r;
--- 17,23 ----
}
__complex__ double
! xcexp (__complex__ double x)
{
double r;
*************** main ()
*** 31,37 ****
{
__complex__ double x;
! x = cexp (1.0i);
if (__real__ x != -1.0)
abort ();
if (__imag__ x != 0.0)
--- 31,37 ----
{
__complex__ double x;
! x = xcexp (1.0i);
if (__real__ x != -1.0)
abort ();
if (__imag__ x != 0.0)
Index: tree-ssa-pre.c
===================================================================
*** tree-ssa-pre.c (revision 119828)
--- tree-ssa-pre.c (working copy)
*************** try_combine_conversion (tree *expr_p)
*** 3613,3619 ****
unsigned int firstbit;
if (!((TREE_CODE (expr) == NOP_EXPR
! || TREE_CODE (expr) == CONVERT_EXPR)
&& TREE_CODE (TREE_OPERAND (expr, 0)) == VALUE_HANDLE
&& !VALUE_HANDLE_VUSES (TREE_OPERAND (expr, 0))))
return false;
--- 3613,3621 ----
unsigned int firstbit;
if (!((TREE_CODE (expr) == NOP_EXPR
! || TREE_CODE (expr) == CONVERT_EXPR
! || TREE_CODE (expr) == REALPART_EXPR
! || TREE_CODE (expr) == IMAGPART_EXPR)
&& TREE_CODE (TREE_OPERAND (expr, 0)) == VALUE_HANDLE
&& !VALUE_HANDLE_VUSES (TREE_OPERAND (expr, 0))))
return false;
More information about the Gcc-patches
mailing list