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:
Roger Sayle 2003-06-06 12:36:26 +00:00
parent 84cd52a9a9
commit 07bae5ad21
7 changed files with 316 additions and 17 deletions

View file

@ -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>

View file

@ -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:

View file

@ -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. */

View file

@ -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>

View 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;
}

View 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;
}

View file

@ -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));
}