fold-const.c (fold <ABS_EXPR>): Re-fold the result of folding fabs(-x) into fabs(x).
* 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. From-SVN: r67541
This commit is contained in:
parent
84cd52a9a9
commit
07bae5ad21
7 changed files with 316 additions and 17 deletions
|
@ -1,3 +1,21 @@
|
|||
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.
|
||||
|
@ -5,7 +23,8 @@ Thu Jun 5 20:51:09 CEST 2003 Jan Hubicka <jh@suse.cz>
|
|||
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>
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
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>
|
||||
|
||||
|
|
58
gcc/testsuite/gcc.dg/builtins-18.c
Normal file
58
gcc/testsuite/gcc.dg/builtins-18.c
Normal file
|
@ -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;
|
||||
}
|
||||
|
41
gcc/testsuite/gcc.dg/builtins-19.c
Normal file
41
gcc/testsuite/gcc.dg/builtins-19.c
Normal file
|
@ -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;
|
||||
}
|
||||
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue