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.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@67541
138bc75d-0d04-0410-961f-
82ee72b054a4
+2003-06-06 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.
+
Thu Jun 5 20:51:09 CEST 2003 Jan Hubicka <jh@suse.cz>
* sourcebuild.texi (Front End Directory): Document new hooks.
Fri Jun 6 11:02:35 CEST 2003 Jan Hubicka <jh@suse.cz>
* 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 <jh@suse.cz>
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. */
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. */
}
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:
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:
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. */
2003-06-06 Roger Sayle <roger@eyesopen.com>
+
+ * 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 <roger@eyesopen.com>
Jim Wilson <wilson@tuliptree.org>
* gcc.dg/uninit-C.c: Only test TImode on 64-bit platforms.
--- /dev/null
+/* 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;
+}
+
--- /dev/null
+/* 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;
+}
+
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));
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));
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));
+}
+