From 07bae5ad21964fd180a8f85e300cf823dfa04b53 Mon Sep 17 00:00:00 2001 From: Roger Sayle Date: Fri, 6 Jun 2003 12:36:26 +0000 Subject: [PATCH] fold-const.c (fold ): Re-fold the result of folding fabs(-x) into fabs(x). * fold-const.c (fold ): 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. From-SVN: r67541 --- gcc/ChangeLog | 21 ++++++- gcc/builtins.c | 99 ++++++++++++++++++++++++++++++ gcc/fold-const.c | 63 ++++++++++++++----- gcc/testsuite/ChangeLog | 6 ++ gcc/testsuite/gcc.dg/builtins-18.c | 58 +++++++++++++++++ gcc/testsuite/gcc.dg/builtins-19.c | 41 +++++++++++++ gcc/testsuite/gcc.dg/builtins-2.c | 45 ++++++++++++++ 7 files changed, 316 insertions(+), 17 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/builtins-18.c create mode 100644 gcc/testsuite/gcc.dg/builtins-19.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 208fff0b0c5..cc46df80755 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,21 @@ +2003-06-06 Roger Sayle + + * fold-const.c (fold ): 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. + Thu Jun 5 20:51:09 CEST 2003 Jan Hubicka * sourcebuild.texi (Front End Directory): Document new hooks. @@ -5,7 +23,8 @@ Thu Jun 5 20:51:09 CEST 2003 Jan Hubicka Fri Jun 6 11:02:35 CEST 2003 Jan Hubicka * function.c (FLOOR_ROUND, CEIL_ROUND): Fix. - * i386.md (gen_pro_epilogue_adjust_stack): Deal with gigantic stack frames. + * i386.md (gen_pro_epilogue_adjust_stack): Deal with gigantic + stack frames. (pro_epilogue_adjust_stack_rex64_2): New pattern Fri Jun 6 11:03:14 CEST 2003 Jan Hubicka diff --git a/gcc/builtins.c b/gcc/builtins.c index b227ffbcd2c..79d46bce2a0 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -177,6 +177,7 @@ static bool readonly_data_expr PARAMS ((tree)); 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. */ @@ -5135,6 +5136,92 @@ fold_trunc_transparent_mathfn (exp) 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. */ @@ -5171,6 +5258,18 @@ fold_builtin (exp) } 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: case BUILT_IN_SQRTL: diff --git a/gcc/fold-const.c b/gcc/fold-const.c index e81e8090cf0..aa99e40aaac 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -5405,29 +5405,19 @@ fold (expr) 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)); + 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, 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 convert (type, fold (build1 (ABS_EXPR, TREE_TYPE (targ0), + targ0))); } + else if (tree_expr_nonnegative_p (arg0)) + return arg0; return t; case CONJ_EXPR: @@ -7928,6 +7918,47 @@ tree_expr_nonnegative_p (t) 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))) /* Truth values evaluate to 0 or 1, which is nonnegative. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 0adc2da05f5..0454ea51aa1 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2003-06-06 Roger Sayle + + * 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. + 2003-06-06 Roger Sayle Jim Wilson diff --git a/gcc/testsuite/gcc.dg/builtins-18.c b/gcc/testsuite/gcc.dg/builtins-18.c new file mode 100644 index 00000000000..86338c03e09 --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtins-18.c @@ -0,0 +1,58 @@ +/* Copyright (C) 2003 Free Software Foundation. + + Check that built-in cabs, cabsf and cabsl functions don't + break anything and produces the expected results. + + Written by Roger Sayle, 1st June 2003. */ + +/* { dg-do link } */ +/* { dg-options "-O2 -ffast-math" } */ + +extern void link_error(void); + +extern float cabsf (float _Complex); +extern double cabs (double _Complex); +extern long double cabsl (long double _Complex); + +int +main (void) +{ + /* For each type, test both runtime and compile time (constant folding) + optimization. */ + float _Complex fc = 3.0F + 4.0iF; + double _Complex dc = 3.0 + 4.0i; + long double _Complex ldc = 3.0L + 4.0iL; + + /* Test floats. */ + if (cabsf (fc) != 5.0F) + link_error (); + if (__builtin_cabsf (fc) != 5.0F) + link_error (); + if (cabsf (3.0F + 4.0iF) != 5.0F) + link_failure (); + if (__builtin_cabsf (3.0F + 4.0iF) != 5.0F) + link_failure (); + + /* Test doubles. */ + if (cabs (dc) != 5.0) + link_error (); + if (__builtin_cabs (dc) != 5.0) + link_error (); + if (cabs (3.0 + 4.0i) != 5.0) + link_failure (); + if (__builtin_cabs (3.0 + 4.0i) != 5.0) + link_failure (); + + /* Test long doubles. */ + if (cabsl (ldc) != 5.0L) + link_error (); + if (__builtin_cabsl (ldc) != 5.0L) + link_error (); + if (cabsl (3.0L + 4.0iL) != 5.0L) + link_failure (); + if (__builtin_cabsl (3.0L + 4.0iL) != 5.0L) + link_failure (); + + return 0; +} + diff --git a/gcc/testsuite/gcc.dg/builtins-19.c b/gcc/testsuite/gcc.dg/builtins-19.c new file mode 100644 index 00000000000..064321f3214 --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtins-19.c @@ -0,0 +1,41 @@ +/* Copyright (C) 2003 Free Software Foundation. + + Check that cabs of a non-complex argument is converted into fabs. + + Written by Roger Sayle, 1st June 2003. */ + +/* { dg-do link } */ +/* { dg-options "-O2 -ansi" } */ + +double cabs (__complex__ double); +float cabsf (__complex__ float); +long double cabsl (__complex__ long double); + +void link_error (void); + +void test (double x) +{ + if (cabs (x) != fabs (x)) + link_error (); +} + +void testf (float x) +{ + if (cabsf (x) != fabsf (x)) + link_error (); +} + +void testl (long double x) +{ + if (cabsl (x) != fabsl (x)) + link_error (); +} + +int main () +{ + test (1.0); + testf (1.0f); + testl (1.0l); + return 0; +} + diff --git a/gcc/testsuite/gcc.dg/builtins-2.c b/gcc/testsuite/gcc.dg/builtins-2.c index ebd054f229a..895b80a2ef9 100644 --- a/gcc/testsuite/gcc.dg/builtins-2.c +++ b/gcc/testsuite/gcc.dg/builtins-2.c @@ -58,6 +58,21 @@ double test10(double x) return tan(atan(x)); } +double test11(double x) +{ + return fabs(fabs(x)); +} + +double test12(double x) +{ + return fabs(atan(x)); +} + +double test13(double x) +{ + return fabs(pow(2.0,x)); +} + float test1f(float x) { return logf(expf(x)); @@ -108,6 +123,21 @@ float test10f(float x) return tanf(atanf(x)); } +floatf test11f(float x) +{ + return fabsf(fabsf(x)); +} + +floatf test12f(float x) +{ + return fabsf(atanf(x)); +} + +float test13f(float x) +{ + return fabsf(powf(2.0f,x)); +} + long double test1l(long double x) { return logl(expl(x)); @@ -158,3 +188,18 @@ long double test10l(long double x) return tanl(atanl(x)); } +long double test11l(long double x) +{ + return fabsl(fabsl(x)); +} + +long double test12l(long double x) +{ + return fabsl(atanl(x)); +} + +long double test13l(long double x) +{ + return fabsl(powl(2.0l,x)); +} +