builtins.c (fold_builtin_strlen, [...]): New functions.

2004-09-08  Eric Christopher  <echristo@redhat.com>

        * builtins.c (fold_builtin_strlen, fold_builtin_sqrt, fold_builtin_cbrt,
	fold_builtin_pow, fold_builtin_sin, fold_builtin_cos, fold_builtin_tan,
        fold_builtin_atan): New functions. Migrate function bodies...
        (fold_builtin_1): ... from here.

From-SVN: r87206
This commit is contained in:
Eric Christopher 2004-09-08 23:24:40 +00:00
parent 640450295e
commit 667bbbbb7b
2 changed files with 391 additions and 299 deletions

View File

@ -1,3 +1,10 @@
2004-09-08 Eric Christopher <echristo@redhat.com>
* builtins.c (fold_builtin_strlen, fold_builtin_sqrt, fold_builtin_cbrt,
fold_builtin_pow, fold_builtin_sin, fold_builtin_cos, fold_builtin_tan,
fold_builtin_atan): New functions. Migrate function bodies...
(fold_builtin_1): ... from here.
2004-09-09 Alan Modra <amodra@bigpond.net.au>
* config/rs6000/rs6000.c (rs6000_stack_info): Correct alignment of
@ -100,7 +107,7 @@
edge block.
(replace_phi_with_cond_modify_expr): Select conditional expr args
based on true edge basic block.
2004-09-08 Jan Hubicka <jh@suse.cz>
* tree-ssa-operands.c (add_stmt_operand): Use V_MUST_DEF even for
@ -149,7 +156,7 @@
(gcc_loop_to_lambda_loop): Handle all exit tests.
Handle case where we have (invariant >= induction var).
(find_induction_var_from_exit_cond): Ditto.
2004-09-08 Jie Zhang <zhangjie@magima.com.cn>
* tree-ssa-alias.c (compute_flow_insensitive_aliasing): If type
@ -289,7 +296,7 @@
force operand 0.0 into register in XFmode. Also do not force
operand 0.0 into register if !TARGET_CMOVE.
* config/i386/i386.md (*cmpfp_0): Delete. Remove comment.
(*cmpfp_0_sf, cmpfp_0_df, cmpfp_0_xf): New patterns to
(*cmpfp_0_sf, cmpfp_0_df, cmpfp_0_xf): New patterns to
implement ftst x87 instruction.
(*fp_jcc_7): New insn pattern. Change corresponding split
pattern to handle "general_operand" instead of
@ -420,7 +427,7 @@
* cfgrtl.c (rtl_verify_flow_info_1): Add new edge flag,
EDGE_CROSSING, to flags test case.
2004-09-07 Jan Hubicka <jh@suse.cz>
* tree-ssa-loop-ivopts.c (contains_abnormal_ssa_name_p): Deal with '<'
@ -520,7 +527,7 @@
check_format_types, format_type_warning,
find_char_info_specifier_index, init_dynamic_asm_fprintf_info,
init_dynamic_diag_info, handle_format_attribute): Likewise.
* c-gimplify.c (push_context, pop_context, finish_bc_block):
* c-gimplify.c (push_context, pop_context, finish_bc_block):
* c-lex.c (c_lex_with_flags, lex_string): Likewise.
* c-objc-common.c (c_tree_printer): Likewise.
* c-pch.c (pch_init): Likewise.

View File

@ -139,6 +139,7 @@ static tree stabilize_va_list (tree, int);
static rtx expand_builtin_expect (tree, rtx);
static tree fold_builtin_constant_p (tree);
static tree fold_builtin_classify_type (tree);
static tree fold_builtin_strlen (tree);
static tree fold_builtin_inf (tree, int);
static tree fold_builtin_nan (tree, tree, int);
static int validate_arglist (tree, ...);
@ -148,6 +149,13 @@ static bool readonly_data_expr (tree);
static rtx expand_builtin_fabs (tree, rtx, rtx);
static rtx expand_builtin_signbit (tree, rtx);
static tree fold_builtin_cabs (tree, tree);
static tree fold_builtin_sqrt (tree, tree);
static tree fold_builtin_cbrt (tree, tree);
static tree fold_builtin_pow (tree, tree, tree);
static tree fold_builtin_sin (tree);
static tree fold_builtin_cos (tree, tree, tree);
static tree fold_builtin_tan (tree);
static tree fold_builtin_atan (tree);
static tree fold_builtin_trunc (tree);
static tree fold_builtin_floor (tree);
static tree fold_builtin_ceil (tree);
@ -6255,6 +6263,29 @@ fold_builtin_classify_type (tree arglist)
type_to_class (TREE_TYPE (TREE_VALUE (arglist))));
}
/* Fold a call to __builtin_strlen. */
static tree
fold_builtin_strlen (tree arglist)
{
if (!validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
return NULL_TREE;
else
{
tree len = c_strlen (TREE_VALUE (arglist), 0);
if (len)
{
/* Convert from the internal "sizetype" type to "size_t". */
if (size_type_node)
len = fold_convert (size_type_node, len);
return len;
}
return NULL_TREE;
}
}
/* Fold a call to __builtin_inf or __builtin_huge_val. */
static tree
@ -6537,6 +6568,235 @@ fold_builtin_cabs (tree arglist, tree type)
return NULL_TREE;
}
/* Fold a builtin function call to sqrt, sqrtf, or sqrtl. Return
NULL_TREE if no simplification can be made. */
static tree
fold_builtin_sqrt (tree arglist, tree type)
{
enum built_in_function fcode;
tree arg = TREE_VALUE (arglist);
if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
return NULL_TREE;
/* Optimize sqrt of constant value. */
if (TREE_CODE (arg) == REAL_CST
&& ! TREE_CONSTANT_OVERFLOW (arg))
{
REAL_VALUE_TYPE r, x;
x = TREE_REAL_CST (arg);
if (real_sqrt (&r, TYPE_MODE (type), &x)
|| (!flag_trapping_math && !flag_errno_math))
return build_real (type, r);
}
/* Optimize sqrt(expN(x)) = expN(x*0.5). */
fcode = builtin_mathfn_code (arg);
if (flag_unsafe_math_optimizations && BUILTIN_EXPONENT_P (fcode))
{
tree expfn = TREE_OPERAND (TREE_OPERAND (arg, 0), 0);
arg = fold (build2 (MULT_EXPR, type,
TREE_VALUE (TREE_OPERAND (arg, 1)),
build_real (type, dconsthalf)));
arglist = build_tree_list (NULL_TREE, arg);
return build_function_call_expr (expfn, arglist);
}
/* Optimize sqrt(Nroot(x)) -> pow(x,1/(2*N)). */
if (flag_unsafe_math_optimizations && BUILTIN_ROOT_P (fcode))
{
tree powfn = mathfn_built_in (type, BUILT_IN_POW);
if (powfn)
{
tree arg0 = TREE_VALUE (TREE_OPERAND (arg, 1));
tree tree_root;
/* The inner root was either sqrt or cbrt. */
REAL_VALUE_TYPE dconstroot =
BUILTIN_SQRT_P (fcode) ? dconsthalf : dconstthird;
/* Adjust for the outer root. */
SET_REAL_EXP (&dconstroot, REAL_EXP (&dconstroot) - 1);
dconstroot = real_value_truncate (TYPE_MODE (type), dconstroot);
tree_root = build_real (type, dconstroot);
arglist = tree_cons (NULL_TREE, arg0,
build_tree_list (NULL_TREE, tree_root));
return build_function_call_expr (powfn, arglist);
}
}
/* Optimize sqrt(pow(x,y)) = pow(x,y*0.5). */
if (flag_unsafe_math_optimizations
&& (fcode == BUILT_IN_POW
|| fcode == BUILT_IN_POWF
|| fcode == BUILT_IN_POWL))
{
tree powfn = TREE_OPERAND (TREE_OPERAND (arg, 0), 0);
tree arg0 = TREE_VALUE (TREE_OPERAND (arg, 1));
tree arg1 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg, 1)));
tree narg1 = fold (build2 (MULT_EXPR, type, arg1,
build_real (type, dconsthalf)));
arglist = tree_cons (NULL_TREE, arg0,
build_tree_list (NULL_TREE, narg1));
return build_function_call_expr (powfn, arglist);
}
return NULL_TREE;
}
/* Fold a builtin function call to cbrt, cbrtf, or cbrtl. Return
NULL_TREE if no simplification can be made. */
static tree
fold_builtin_cbrt (tree arglist, tree type)
{
tree arg = TREE_VALUE (arglist);
const enum built_in_function fcode = builtin_mathfn_code (arg);
if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
return NULL_TREE;
/* Optimize cbrt of constant value. */
if (real_zerop (arg) || real_onep (arg) || real_minus_onep (arg))
return arg;
/* Optimize cbrt(expN(x)) -> expN(x/3). */
if (flag_unsafe_math_optimizations && BUILTIN_EXPONENT_P (fcode))
{
tree expfn = TREE_OPERAND (TREE_OPERAND (arg, 0), 0);
const REAL_VALUE_TYPE third_trunc =
real_value_truncate (TYPE_MODE (type), dconstthird);
arg = fold (build2 (MULT_EXPR, type,
TREE_VALUE (TREE_OPERAND (arg, 1)),
build_real (type, third_trunc)));
arglist = build_tree_list (NULL_TREE, arg);
return build_function_call_expr (expfn, arglist);
}
/* Optimize cbrt(sqrt(x)) -> pow(x,1/6). */
/* We don't optimize cbrt(cbrt(x)) -> pow(x,1/9) because if
x is negative pow will error but cbrt won't. */
if (flag_unsafe_math_optimizations && BUILTIN_SQRT_P (fcode))
{
tree powfn = mathfn_built_in (type, BUILT_IN_POW);
if (powfn)
{
tree arg0 = TREE_VALUE (TREE_OPERAND (arg, 1));
tree tree_root;
REAL_VALUE_TYPE dconstroot = dconstthird;
SET_REAL_EXP (&dconstroot, REAL_EXP (&dconstroot) - 1);
dconstroot = real_value_truncate (TYPE_MODE (type), dconstroot);
tree_root = build_real (type, dconstroot);
arglist = tree_cons (NULL_TREE, arg0,
build_tree_list (NULL_TREE, tree_root));
return build_function_call_expr (powfn, arglist);
}
}
return NULL_TREE;
}
/* Fold function call to builtin sin, sinf, or sinl. Return
NULL_TREE if no simplification can be made. */
static tree
fold_builtin_sin (tree arglist)
{
tree arg = TREE_VALUE (arglist);
if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
return NULL_TREE;
/* Optimize sin (0.0) = 0.0. */
if (real_zerop (arg))
return arg;
return NULL_TREE;
}
/* Fold function call to builtin cos, cosf, or cosl. Return
NULL_TREE if no simplification can be made. */
static tree
fold_builtin_cos (tree arglist, tree type, tree fndecl)
{
tree arg = TREE_VALUE (arglist);
if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
return NULL_TREE;
/* Optimize cos (0.0) = 1.0. */
if (real_zerop (arg))
return build_real (type, dconst1);
/* Optimize cos(-x) into cos (x). */
if (TREE_CODE (arg) == NEGATE_EXPR)
{
tree args = build_tree_list (NULL_TREE,
TREE_OPERAND (arg, 0));
return build_function_call_expr (fndecl, args);
}
return NULL_TREE;
}
/* Fold function call to builtin tan, tanf, or tanl. Return
NULL_TREE if no simplification can be made. */
static tree
fold_builtin_tan (tree arglist)
{
enum built_in_function fcode;
tree arg = TREE_VALUE (arglist);
if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
return NULL_TREE;
/* Optimize tan(0.0) = 0.0. */
if (real_zerop (arg))
return arg;
/* Optimize tan(atan(x)) = x. */
fcode = builtin_mathfn_code (arg);
if (flag_unsafe_math_optimizations
&& (fcode == BUILT_IN_ATAN
|| fcode == BUILT_IN_ATANF
|| fcode == BUILT_IN_ATANL))
return TREE_VALUE (TREE_OPERAND (arg, 1));
return NULL_TREE;
}
/* Fold function call to builtin atan, atanf, or atanl. Return
NULL_TREE if no simplification can be made. */
static tree
fold_builtin_atan (tree arglist, tree type)
{
tree arg = TREE_VALUE (arglist);
if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
return NULL_TREE;
/* Optimize atan(0.0) = 0.0. */
if (real_zerop (arg))
return arg;
/* Optimize atan(1.0) = pi/4. */
if (real_onep (arg))
{
REAL_VALUE_TYPE cst;
real_convert (&cst, TYPE_MODE (type), &dconstpi);
SET_REAL_EXP (&cst, REAL_EXP (&cst) - 2);
return build_real (type, cst);
}
return NULL_TREE;
}
/* Fold function call to builtin trunc, truncf or truncl. Return
NULL_TREE if no simplification can be made. */
@ -6935,6 +7195,117 @@ fold_builtin_logarithm (tree exp, const REAL_VALUE_TYPE *value)
return 0;
}
/* Fold a builtin function call to pow, powf, or powl. Return
NULL_TREE if no simplification can be made. */
static tree
fold_builtin_pow (tree fndecl, tree arglist, tree type)
{
enum built_in_function fcode;
tree arg0 = TREE_VALUE (arglist);
tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
if (!validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE))
return NULL_TREE;
/* Optimize pow(1.0,y) = 1.0. */
if (real_onep (arg0))
return omit_one_operand (type, build_real (type, dconst1), arg1);
if (TREE_CODE (arg1) == REAL_CST
&& ! TREE_CONSTANT_OVERFLOW (arg1))
{
REAL_VALUE_TYPE c;
c = TREE_REAL_CST (arg1);
/* Optimize pow(x,0.0) = 1.0. */
if (REAL_VALUES_EQUAL (c, dconst0))
return omit_one_operand (type, build_real (type, dconst1),
arg0);
/* Optimize pow(x,1.0) = x. */
if (REAL_VALUES_EQUAL (c, dconst1))
return arg0;
/* Optimize pow(x,-1.0) = 1.0/x. */
if (REAL_VALUES_EQUAL (c, dconstm1))
return fold (build2 (RDIV_EXPR, type,
build_real (type, dconst1), arg0));
/* Optimize pow(x,0.5) = sqrt(x). */
if (flag_unsafe_math_optimizations
&& REAL_VALUES_EQUAL (c, dconsthalf))
{
tree sqrtfn = mathfn_built_in (type, BUILT_IN_SQRT);
if (sqrtfn != NULL_TREE)
{
tree arglist = build_tree_list (NULL_TREE, arg0);
return build_function_call_expr (sqrtfn, arglist);
}
}
/* Attempt to evaluate pow at compile-time. */
if (TREE_CODE (arg0) == REAL_CST
&& ! TREE_CONSTANT_OVERFLOW (arg0))
{
REAL_VALUE_TYPE cint;
HOST_WIDE_INT n;
n = real_to_integer (&c);
real_from_integer (&cint, VOIDmode, n,
n < 0 ? -1 : 0, 0);
if (real_identical (&c, &cint))
{
REAL_VALUE_TYPE x;
bool inexact;
x = TREE_REAL_CST (arg0);
inexact = real_powi (&x, TYPE_MODE (type), &x, n);
if (flag_unsafe_math_optimizations || !inexact)
return build_real (type, x);
}
}
}
/* Optimize pow(expN(x),y) = expN(x*y). */
fcode = builtin_mathfn_code (arg0);
if (flag_unsafe_math_optimizations && BUILTIN_EXPONENT_P (fcode))
{
tree expfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
tree arg = TREE_VALUE (TREE_OPERAND (arg0, 1));
arg = fold (build2 (MULT_EXPR, type, arg, arg1));
arglist = build_tree_list (NULL_TREE, arg);
return build_function_call_expr (expfn, arglist);
}
/* Optimize pow(sqrt(x),y) = pow(x,y*0.5). */
if (flag_unsafe_math_optimizations && BUILTIN_SQRT_P (fcode))
{
tree narg0 = TREE_VALUE (TREE_OPERAND (arg0, 1));
tree narg1 = fold (build2 (MULT_EXPR, type, arg1,
build_real (type, dconsthalf)));
arglist = tree_cons (NULL_TREE, narg0,
build_tree_list (NULL_TREE, narg1));
return build_function_call_expr (fndecl, arglist);
}
/* Optimize pow(pow(x,y),z) = pow(x,y*z). */
if (flag_unsafe_math_optimizations
&& (fcode == BUILT_IN_POW
|| fcode == BUILT_IN_POWF
|| fcode == BUILT_IN_POWL))
{
tree arg00 = TREE_VALUE (TREE_OPERAND (arg0, 1));
tree arg01 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg0, 1)));
tree narg1 = fold (build2 (MULT_EXPR, type, arg01, arg1));
arglist = tree_cons (NULL_TREE, arg00,
build_tree_list (NULL_TREE, narg1));
return build_function_call_expr (fndecl, arglist);
}
return NULL_TREE;
}
/* A subroutine of fold_builtin to fold the various exponent
functions. EXP is the CALL_EXPR of a call to a builtin function.
VALUE is the value which will be raised to a power. */
@ -7834,18 +8205,7 @@ fold_builtin_1 (tree exp, bool ignore)
return fold_builtin_classify_type (arglist);
case BUILT_IN_STRLEN:
if (validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
{
tree len = c_strlen (TREE_VALUE (arglist), 0);
if (len)
{
/* Convert from the internal "sizetype" type to "size_t". */
if (size_type_node)
len = fold_convert (size_type_node, len);
return len;
}
}
break;
return fold_builtin_strlen (arglist);
case BUILT_IN_FABS:
case BUILT_IN_FABSF:
@ -7889,159 +8249,22 @@ fold_builtin_1 (tree exp, bool ignore)
case BUILT_IN_SQRT:
case BUILT_IN_SQRTF:
case BUILT_IN_SQRTL:
if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
{
enum built_in_function fcode;
tree arg = TREE_VALUE (arglist);
/* Optimize sqrt of constant value. */
if (TREE_CODE (arg) == REAL_CST
&& ! TREE_CONSTANT_OVERFLOW (arg))
{
REAL_VALUE_TYPE r, x;
x = TREE_REAL_CST (arg);
if (real_sqrt (&r, TYPE_MODE (type), &x)
|| (!flag_trapping_math && !flag_errno_math))
return build_real (type, r);
}
/* Optimize sqrt(expN(x)) = expN(x*0.5). */
fcode = builtin_mathfn_code (arg);
if (flag_unsafe_math_optimizations && BUILTIN_EXPONENT_P (fcode))
{
tree expfn = TREE_OPERAND (TREE_OPERAND (arg, 0), 0);
arg = fold (build2 (MULT_EXPR, type,
TREE_VALUE (TREE_OPERAND (arg, 1)),
build_real (type, dconsthalf)));
arglist = build_tree_list (NULL_TREE, arg);
return build_function_call_expr (expfn, arglist);
}
/* Optimize sqrt(Nroot(x)) -> pow(x,1/(2*N)). */
if (flag_unsafe_math_optimizations && BUILTIN_ROOT_P (fcode))
{
tree powfn = mathfn_built_in (type, BUILT_IN_POW);
if (powfn)
{
tree arg0 = TREE_VALUE (TREE_OPERAND (arg, 1));
tree tree_root;
/* The inner root was either sqrt or cbrt. */
REAL_VALUE_TYPE dconstroot =
BUILTIN_SQRT_P (fcode) ? dconsthalf : dconstthird;
/* Adjust for the outer root. */
SET_REAL_EXP (&dconstroot, REAL_EXP (&dconstroot) - 1);
dconstroot = real_value_truncate (TYPE_MODE (type), dconstroot);
tree_root = build_real (type, dconstroot);
arglist = tree_cons (NULL_TREE, arg0,
build_tree_list (NULL_TREE, tree_root));
return build_function_call_expr (powfn, arglist);
}
}
/* Optimize sqrt(pow(x,y)) = pow(x,y*0.5). */
if (flag_unsafe_math_optimizations
&& (fcode == BUILT_IN_POW
|| fcode == BUILT_IN_POWF
|| fcode == BUILT_IN_POWL))
{
tree powfn = TREE_OPERAND (TREE_OPERAND (arg, 0), 0);
tree arg0 = TREE_VALUE (TREE_OPERAND (arg, 1));
tree arg1 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg, 1)));
tree narg1 = fold (build2 (MULT_EXPR, type, arg1,
build_real (type, dconsthalf)));
arglist = tree_cons (NULL_TREE, arg0,
build_tree_list (NULL_TREE, narg1));
return build_function_call_expr (powfn, arglist);
}
}
break;
return fold_builtin_sqrt (arglist, type);
case BUILT_IN_CBRT:
case BUILT_IN_CBRTF:
case BUILT_IN_CBRTL:
if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
{
tree arg = TREE_VALUE (arglist);
const enum built_in_function fcode = builtin_mathfn_code (arg);
/* Optimize cbrt of constant value. */
if (real_zerop (arg) || real_onep (arg) || real_minus_onep (arg))
return arg;
/* Optimize cbrt(expN(x)) -> expN(x/3). */
if (flag_unsafe_math_optimizations && BUILTIN_EXPONENT_P (fcode))
{
tree expfn = TREE_OPERAND (TREE_OPERAND (arg, 0), 0);
const REAL_VALUE_TYPE third_trunc =
real_value_truncate (TYPE_MODE (type), dconstthird);
arg = fold (build2 (MULT_EXPR, type,
TREE_VALUE (TREE_OPERAND (arg, 1)),
build_real (type, third_trunc)));
arglist = build_tree_list (NULL_TREE, arg);
return build_function_call_expr (expfn, arglist);
}
/* Optimize cbrt(sqrt(x)) -> pow(x,1/6). */
/* We don't optimize cbrt(cbrt(x)) -> pow(x,1/9) because if
x is negative pow will error but cbrt won't. */
if (flag_unsafe_math_optimizations && BUILTIN_SQRT_P (fcode))
{
tree powfn = mathfn_built_in (type, BUILT_IN_POW);
if (powfn)
{
tree arg0 = TREE_VALUE (TREE_OPERAND (arg, 1));
tree tree_root;
REAL_VALUE_TYPE dconstroot = dconstthird;
SET_REAL_EXP (&dconstroot, REAL_EXP (&dconstroot) - 1);
dconstroot = real_value_truncate (TYPE_MODE (type), dconstroot);
tree_root = build_real (type, dconstroot);
arglist = tree_cons (NULL_TREE, arg0,
build_tree_list (NULL_TREE, tree_root));
return build_function_call_expr (powfn, arglist);
}
}
}
break;
return fold_builtin_cbrt (arglist, type);
case BUILT_IN_SIN:
case BUILT_IN_SINF:
case BUILT_IN_SINL:
if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
{
tree arg = TREE_VALUE (arglist);
/* Optimize sin(0.0) = 0.0. */
if (real_zerop (arg))
return arg;
}
break;
return fold_builtin_sin (arglist);
case BUILT_IN_COS:
case BUILT_IN_COSF:
case BUILT_IN_COSL:
if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
{
tree arg = TREE_VALUE (arglist);
/* Optimize cos(0.0) = 1.0. */
if (real_zerop (arg))
return build_real (type, dconst1);
/* Optimize cos(-x) into cos(x). */
if (TREE_CODE (arg) == NEGATE_EXPR)
{
tree arglist = build_tree_list (NULL_TREE,
TREE_OPERAND (arg, 0));
return build_function_call_expr (fndecl, arglist);
}
}
break;
return fold_builtin_cos (arglist, type, fndecl);
case BUILT_IN_EXP:
case BUILT_IN_EXPF:
@ -8079,155 +8302,17 @@ fold_builtin_1 (tree exp, bool ignore)
case BUILT_IN_TAN:
case BUILT_IN_TANF:
case BUILT_IN_TANL:
if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
{
enum built_in_function fcode;
tree arg = TREE_VALUE (arglist);
/* Optimize tan(0.0) = 0.0. */
if (real_zerop (arg))
return arg;
/* Optimize tan(atan(x)) = x. */
fcode = builtin_mathfn_code (arg);
if (flag_unsafe_math_optimizations
&& (fcode == BUILT_IN_ATAN
|| fcode == BUILT_IN_ATANF
|| fcode == BUILT_IN_ATANL))
return TREE_VALUE (TREE_OPERAND (arg, 1));
}
break;
return fold_builtin_tan (arglist);
case BUILT_IN_ATAN:
case BUILT_IN_ATANF:
case BUILT_IN_ATANL:
if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
{
tree arg = TREE_VALUE (arglist);
/* Optimize atan(0.0) = 0.0. */
if (real_zerop (arg))
return arg;
/* Optimize atan(1.0) = pi/4. */
if (real_onep (arg))
{
REAL_VALUE_TYPE cst;
real_convert (&cst, TYPE_MODE (type), &dconstpi);
SET_REAL_EXP (&cst, REAL_EXP (&cst) - 2);
return build_real (type, cst);
}
}
break;
return fold_builtin_atan (arglist, type);
case BUILT_IN_POW:
case BUILT_IN_POWF:
case BUILT_IN_POWL:
if (validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE))
{
enum built_in_function fcode;
tree arg0 = TREE_VALUE (arglist);
tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
/* Optimize pow(1.0,y) = 1.0. */
if (real_onep (arg0))
return omit_one_operand (type, build_real (type, dconst1), arg1);
if (TREE_CODE (arg1) == REAL_CST
&& ! TREE_CONSTANT_OVERFLOW (arg1))
{
REAL_VALUE_TYPE c;
c = TREE_REAL_CST (arg1);
/* Optimize pow(x,0.0) = 1.0. */
if (REAL_VALUES_EQUAL (c, dconst0))
return omit_one_operand (type, build_real (type, dconst1),
arg0);
/* Optimize pow(x,1.0) = x. */
if (REAL_VALUES_EQUAL (c, dconst1))
return arg0;
/* Optimize pow(x,-1.0) = 1.0/x. */
if (REAL_VALUES_EQUAL (c, dconstm1))
return fold (build2 (RDIV_EXPR, type,
build_real (type, dconst1), arg0));
/* Optimize pow(x,0.5) = sqrt(x). */
if (flag_unsafe_math_optimizations
&& REAL_VALUES_EQUAL (c, dconsthalf))
{
tree sqrtfn = mathfn_built_in (type, BUILT_IN_SQRT);
if (sqrtfn != NULL_TREE)
{
tree arglist = build_tree_list (NULL_TREE, arg0);
return build_function_call_expr (sqrtfn, arglist);
}
}
/* Attempt to evaluate pow at compile-time. */
if (TREE_CODE (arg0) == REAL_CST
&& ! TREE_CONSTANT_OVERFLOW (arg0))
{
REAL_VALUE_TYPE cint;
HOST_WIDE_INT n;
n = real_to_integer (&c);
real_from_integer (&cint, VOIDmode, n,
n < 0 ? -1 : 0, 0);
if (real_identical (&c, &cint))
{
REAL_VALUE_TYPE x;
bool inexact;
x = TREE_REAL_CST (arg0);
inexact = real_powi (&x, TYPE_MODE (type), &x, n);
if (flag_unsafe_math_optimizations || !inexact)
return build_real (type, x);
}
}
}
/* Optimize pow(expN(x),y) = expN(x*y). */
fcode = builtin_mathfn_code (arg0);
if (flag_unsafe_math_optimizations && BUILTIN_EXPONENT_P (fcode))
{
tree expfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
tree arg = TREE_VALUE (TREE_OPERAND (arg0, 1));
arg = fold (build2 (MULT_EXPR, type, arg, arg1));
arglist = build_tree_list (NULL_TREE, arg);
return build_function_call_expr (expfn, arglist);
}
/* Optimize pow(sqrt(x),y) = pow(x,y*0.5). */
if (flag_unsafe_math_optimizations && BUILTIN_SQRT_P (fcode))
{
tree narg0 = TREE_VALUE (TREE_OPERAND (arg0, 1));
tree narg1 = fold (build2 (MULT_EXPR, type, arg1,
build_real (type, dconsthalf)));
arglist = tree_cons (NULL_TREE, narg0,
build_tree_list (NULL_TREE, narg1));
return build_function_call_expr (fndecl, arglist);
}
/* Optimize pow(pow(x,y),z) = pow(x,y*z). */
if (flag_unsafe_math_optimizations
&& (fcode == BUILT_IN_POW
|| fcode == BUILT_IN_POWF
|| fcode == BUILT_IN_POWL))
{
tree arg00 = TREE_VALUE (TREE_OPERAND (arg0, 1));
tree arg01 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg0, 1)));
tree narg1 = fold (build2 (MULT_EXPR, type, arg01, arg1));
arglist = tree_cons (NULL_TREE, arg00,
build_tree_list (NULL_TREE, narg1));
return build_function_call_expr (fndecl, arglist);
}
}
break;
return fold_builtin_pow (fndecl, arglist, type);
case BUILT_IN_INF:
case BUILT_IN_INFF: