Move fold_trunc_transparent_mathfn to match.pd
This moves the fold rules for trunc, floor, ceil, round, nearbyint and rint in one go, since they're tested as a group. Most of the code is supporting the f(x)->x fold when x is known to be integer-valued. Like with the non-negative test, this is probably more elegantly handled by tracking range information for reals, but until that happens, I think we should handle it analogously to tree_expr_nonnegative_p. I've incorporated the fix for PR68031 in the new version of integer_valued_real_p. However, it seemed confusing to test for an SSA name at the head of the function rather than the case statement, and not fall through to tree_simple_nonnegative_warnv_p (which conceptually shouldn't care whether an update is in progress). But tree_simple_nonnegative_warnv_p is a no-op for SSA names, so I simply changed it to: return (!name_registered_for_update_p (t) && depth < PARAM_VALUE (PARAM_MAX_SSA_NAME_QUERY_DEPTH) && gimple_stmt_nonnegative_warnv_p (SSA_NAME_DEF_STMT (t), strict_overflow_p, depth)); and used that in the new code too. Doing these folds later meant that IPA would start to use information about the aborting sinf and floor in 20030125-1.c before the folds kicked in. I changed them from noinline to weak to stop that. Tested on x86_64-linux-gnu, aarch64-linux-gnu and arm-linux-gnueabi. gcc/ * builtins.c (integer_valued_real_p): Move to fold-const.c. (fold_trunc_transparent_mathfn, fold_builtin_trunc, fold_builtin_floor) (fold_builtin_ceil, fold_builtin_round): Delete. (fold_builtin_1): Handle constant trunc, floor, ceil and round arguments here. * convert.c (convert_to_real): Remove narrowing of rounding functions. * fold-const.h (integer_valued_real_unary_p) (integer_valued_real_binary_p, integer_valued_real_call_p) (integer_valued_real_single_p, integer_valued_real_p): Declare. * fold-const.c (tree_single_nonnegative_warnv_p): Move name_registered_for_update_p check to SSA_NAME case statement. Don't call tree_simple_nonnegative_warnv_p for SSA names. (integer_valued_real_unary_p, integer_valued_real_binary_p) (integer_valued_real_call_p, integer_valued_real_single_p) (integer_valued_real_invalid_p): New functions. (integer_valued_real_p): Move from fold-const.c and rework to call the functions above. Handle SSA names. * gimple-fold.h (gimple_stmt_integer_valued_real_p): Declare. * gimple-fold.c (gimple_assign_integer_valued_real_p) (gimple_call_integer_valued_real_p, gimple_phi_integer_valued_real_p) (gimple_stmt_integer_valued_real_p): New functions. * match.pd: Fold f(f(x))->f(x) for fp->fp rounding functions f. Fold f(x)->x for the same f if x is known to be integer-valued. Fold f(extend(x))->extend(f'(x)) if doing so doesn't affect the result. Canonicalize floor(x) as trunc(x) if x is nonnegative. gcc/testsuite/ * gcc.c-torture/execute/20030125-1.c (floor, floorf, sin, sinf): Make weak rather than noinline. * gcc.dg/builtins-57.c: Compile with -O. * gcc.dg/torture/builtin-integral-1.c: Skip for -O0. From-SVN: r229221
This commit is contained in:
parent
735a559c68
commit
67dbe5829e
|
@ -1,3 +1,33 @@
|
||||||
|
2015-10-23 Richard Sandiford <richard.sandiford@arm.com>
|
||||||
|
|
||||||
|
* builtins.c (integer_valued_real_p): Move to fold-const.c.
|
||||||
|
(fold_trunc_transparent_mathfn, fold_builtin_trunc, fold_builtin_floor)
|
||||||
|
(fold_builtin_ceil, fold_builtin_round): Delete.
|
||||||
|
(fold_builtin_1): Handle constant trunc, floor, ceil and round
|
||||||
|
arguments here.
|
||||||
|
* convert.c (convert_to_real): Remove narrowing of rounding
|
||||||
|
functions.
|
||||||
|
* fold-const.h (integer_valued_real_unary_p)
|
||||||
|
(integer_valued_real_binary_p, integer_valued_real_call_p)
|
||||||
|
(integer_valued_real_single_p, integer_valued_real_p): Declare.
|
||||||
|
* fold-const.c (tree_single_nonnegative_warnv_p): Move
|
||||||
|
name_registered_for_update_p check to SSA_NAME case statement.
|
||||||
|
Don't call tree_simple_nonnegative_warnv_p for SSA names.
|
||||||
|
(integer_valued_real_unary_p, integer_valued_real_binary_p)
|
||||||
|
(integer_valued_real_call_p, integer_valued_real_single_p)
|
||||||
|
(integer_valued_real_invalid_p): New functions.
|
||||||
|
(integer_valued_real_p): Move from fold-const.c and rework
|
||||||
|
to call the functions above. Handle SSA names.
|
||||||
|
* gimple-fold.h (gimple_stmt_integer_valued_real_p): Declare.
|
||||||
|
* gimple-fold.c (gimple_assign_integer_valued_real_p)
|
||||||
|
(gimple_call_integer_valued_real_p, gimple_phi_integer_valued_real_p)
|
||||||
|
(gimple_stmt_integer_valued_real_p): New functions.
|
||||||
|
* match.pd: Fold f(f(x))->f(x) for fp->fp rounding functions f.
|
||||||
|
Fold f(x)->x for the same f if x is known to be integer-valued.
|
||||||
|
Fold f(extend(x))->extend(f'(x)) if doing so doesn't affect
|
||||||
|
the result. Canonicalize floor(x) as trunc(x) if x is
|
||||||
|
nonnegative.
|
||||||
|
|
||||||
2015-10-23 Tom de Vries <tom@codesourcery.com>
|
2015-10-23 Tom de Vries <tom@codesourcery.com>
|
||||||
|
|
||||||
* tree-ssa-structalias.c (intra_create_variable_infos): Use
|
* tree-ssa-structalias.c (intra_create_variable_infos): Use
|
||||||
|
|
284
gcc/builtins.c
284
gcc/builtins.c
|
@ -154,16 +154,10 @@ static tree fold_builtin_inf (location_t, tree, int);
|
||||||
static tree fold_builtin_nan (tree, tree, int);
|
static tree fold_builtin_nan (tree, tree, int);
|
||||||
static tree rewrite_call_expr (location_t, tree, int, tree, int, ...);
|
static tree rewrite_call_expr (location_t, tree, int, tree, int, ...);
|
||||||
static bool validate_arg (const_tree, enum tree_code code);
|
static bool validate_arg (const_tree, enum tree_code code);
|
||||||
static bool integer_valued_real_p (tree);
|
|
||||||
static tree fold_trunc_transparent_mathfn (location_t, tree, tree);
|
|
||||||
static rtx expand_builtin_fabs (tree, rtx, rtx);
|
static rtx expand_builtin_fabs (tree, rtx, rtx);
|
||||||
static rtx expand_builtin_signbit (tree, rtx);
|
static rtx expand_builtin_signbit (tree, rtx);
|
||||||
static tree fold_builtin_pow (location_t, tree, tree, tree, tree);
|
static tree fold_builtin_pow (location_t, tree, tree, tree, tree);
|
||||||
static tree fold_builtin_powi (location_t, tree, tree, tree, tree);
|
static tree fold_builtin_powi (location_t, tree, tree, tree, tree);
|
||||||
static tree fold_builtin_trunc (location_t, tree, tree);
|
|
||||||
static tree fold_builtin_floor (location_t, tree, tree);
|
|
||||||
static tree fold_builtin_ceil (location_t, tree, tree);
|
|
||||||
static tree fold_builtin_round (location_t, tree, tree);
|
|
||||||
static tree fold_builtin_int_roundingfn (location_t, tree, tree);
|
static tree fold_builtin_int_roundingfn (location_t, tree, tree);
|
||||||
static tree fold_builtin_bitop (tree, tree);
|
static tree fold_builtin_bitop (tree, tree);
|
||||||
static tree fold_builtin_strchr (location_t, tree, tree, tree);
|
static tree fold_builtin_strchr (location_t, tree, tree, tree);
|
||||||
|
@ -7320,117 +7314,6 @@ fold_builtin_nan (tree arg, tree type, int quiet)
|
||||||
return build_real (type, real);
|
return build_real (type, real);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return true if the floating point expression T has an integer value.
|
|
||||||
We also allow +Inf, -Inf and NaN to be considered integer values. */
|
|
||||||
|
|
||||||
static bool
|
|
||||||
integer_valued_real_p (tree t)
|
|
||||||
{
|
|
||||||
switch (TREE_CODE (t))
|
|
||||||
{
|
|
||||||
case FLOAT_EXPR:
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case ABS_EXPR:
|
|
||||||
case SAVE_EXPR:
|
|
||||||
return integer_valued_real_p (TREE_OPERAND (t, 0));
|
|
||||||
|
|
||||||
case COMPOUND_EXPR:
|
|
||||||
case MODIFY_EXPR:
|
|
||||||
case BIND_EXPR:
|
|
||||||
return integer_valued_real_p (TREE_OPERAND (t, 1));
|
|
||||||
|
|
||||||
case PLUS_EXPR:
|
|
||||||
case MINUS_EXPR:
|
|
||||||
case MULT_EXPR:
|
|
||||||
case MIN_EXPR:
|
|
||||||
case MAX_EXPR:
|
|
||||||
return integer_valued_real_p (TREE_OPERAND (t, 0))
|
|
||||||
&& integer_valued_real_p (TREE_OPERAND (t, 1));
|
|
||||||
|
|
||||||
case COND_EXPR:
|
|
||||||
return integer_valued_real_p (TREE_OPERAND (t, 1))
|
|
||||||
&& integer_valued_real_p (TREE_OPERAND (t, 2));
|
|
||||||
|
|
||||||
case REAL_CST:
|
|
||||||
return real_isinteger (TREE_REAL_CST_PTR (t), TYPE_MODE (TREE_TYPE (t)));
|
|
||||||
|
|
||||||
CASE_CONVERT:
|
|
||||||
{
|
|
||||||
tree type = TREE_TYPE (TREE_OPERAND (t, 0));
|
|
||||||
if (TREE_CODE (type) == INTEGER_TYPE)
|
|
||||||
return true;
|
|
||||||
if (TREE_CODE (type) == REAL_TYPE)
|
|
||||||
return integer_valued_real_p (TREE_OPERAND (t, 0));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case CALL_EXPR:
|
|
||||||
switch (builtin_mathfn_code (t))
|
|
||||||
{
|
|
||||||
CASE_FLT_FN (BUILT_IN_CEIL):
|
|
||||||
CASE_FLT_FN (BUILT_IN_FLOOR):
|
|
||||||
CASE_FLT_FN (BUILT_IN_NEARBYINT):
|
|
||||||
CASE_FLT_FN (BUILT_IN_RINT):
|
|
||||||
CASE_FLT_FN (BUILT_IN_ROUND):
|
|
||||||
CASE_FLT_FN (BUILT_IN_TRUNC):
|
|
||||||
return true;
|
|
||||||
|
|
||||||
CASE_FLT_FN (BUILT_IN_FMIN):
|
|
||||||
CASE_FLT_FN (BUILT_IN_FMAX):
|
|
||||||
return integer_valued_real_p (CALL_EXPR_ARG (t, 0))
|
|
||||||
&& integer_valued_real_p (CALL_EXPR_ARG (t, 1));
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* FNDECL is assumed to be a builtin where truncation can be propagated
|
|
||||||
across (for instance floor((double)f) == (double)floorf (f).
|
|
||||||
Do the transformation for a call with argument ARG. */
|
|
||||||
|
|
||||||
static tree
|
|
||||||
fold_trunc_transparent_mathfn (location_t loc, tree fndecl, tree arg)
|
|
||||||
{
|
|
||||||
enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
|
|
||||||
|
|
||||||
if (!validate_arg (arg, REAL_TYPE))
|
|
||||||
return NULL_TREE;
|
|
||||||
|
|
||||||
/* Integer rounding functions are idempotent. */
|
|
||||||
if (fcode == builtin_mathfn_code (arg))
|
|
||||||
return arg;
|
|
||||||
|
|
||||||
/* If argument is already integer valued, and we don't need to worry
|
|
||||||
about setting errno, there's no need to perform rounding. */
|
|
||||||
if (! flag_errno_math && integer_valued_real_p (arg))
|
|
||||||
return arg;
|
|
||||||
|
|
||||||
if (optimize)
|
|
||||||
{
|
|
||||||
tree arg0 = strip_float_extensions (arg);
|
|
||||||
tree ftype = TREE_TYPE (TREE_TYPE (fndecl));
|
|
||||||
tree newtype = TREE_TYPE (arg0);
|
|
||||||
tree decl;
|
|
||||||
|
|
||||||
if (TYPE_PRECISION (newtype) < TYPE_PRECISION (ftype)
|
|
||||||
&& (decl = mathfn_built_in (newtype, fcode)))
|
|
||||||
return fold_convert_loc (loc, ftype,
|
|
||||||
build_call_expr_loc (loc, decl, 1,
|
|
||||||
fold_convert_loc (loc,
|
|
||||||
newtype,
|
|
||||||
arg0)));
|
|
||||||
}
|
|
||||||
return NULL_TREE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* FNDECL is assumed to be builtin which can narrow the FP type of
|
/* FNDECL is assumed to be builtin which can narrow the FP type of
|
||||||
the argument, for instance lround((double)f) -> lroundf (f).
|
the argument, for instance lround((double)f) -> lroundf (f).
|
||||||
Do the transformation for a call with argument ARG. */
|
Do the transformation for a call with argument ARG. */
|
||||||
|
@ -7645,121 +7528,6 @@ fold_builtin_cexp (location_t loc, tree arg0, tree type)
|
||||||
return NULL_TREE;
|
return NULL_TREE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fold function call to builtin trunc, truncf or truncl with argument ARG.
|
|
||||||
Return NULL_TREE if no simplification can be made. */
|
|
||||||
|
|
||||||
static tree
|
|
||||||
fold_builtin_trunc (location_t loc, tree fndecl, tree arg)
|
|
||||||
{
|
|
||||||
if (!validate_arg (arg, REAL_TYPE))
|
|
||||||
return NULL_TREE;
|
|
||||||
|
|
||||||
/* Optimize trunc of constant value. */
|
|
||||||
if (TREE_CODE (arg) == REAL_CST && !TREE_OVERFLOW (arg))
|
|
||||||
{
|
|
||||||
REAL_VALUE_TYPE r, x;
|
|
||||||
tree type = TREE_TYPE (TREE_TYPE (fndecl));
|
|
||||||
|
|
||||||
x = TREE_REAL_CST (arg);
|
|
||||||
real_trunc (&r, TYPE_MODE (type), &x);
|
|
||||||
return build_real (type, r);
|
|
||||||
}
|
|
||||||
|
|
||||||
return fold_trunc_transparent_mathfn (loc, fndecl, arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Fold function call to builtin floor, floorf or floorl with argument ARG.
|
|
||||||
Return NULL_TREE if no simplification can be made. */
|
|
||||||
|
|
||||||
static tree
|
|
||||||
fold_builtin_floor (location_t loc, tree fndecl, tree arg)
|
|
||||||
{
|
|
||||||
if (!validate_arg (arg, REAL_TYPE))
|
|
||||||
return NULL_TREE;
|
|
||||||
|
|
||||||
/* Optimize floor of constant value. */
|
|
||||||
if (TREE_CODE (arg) == REAL_CST && !TREE_OVERFLOW (arg))
|
|
||||||
{
|
|
||||||
REAL_VALUE_TYPE x;
|
|
||||||
|
|
||||||
x = TREE_REAL_CST (arg);
|
|
||||||
if (! REAL_VALUE_ISNAN (x) || ! flag_errno_math)
|
|
||||||
{
|
|
||||||
tree type = TREE_TYPE (TREE_TYPE (fndecl));
|
|
||||||
REAL_VALUE_TYPE r;
|
|
||||||
|
|
||||||
real_floor (&r, TYPE_MODE (type), &x);
|
|
||||||
return build_real (type, r);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Fold floor (x) where x is nonnegative to trunc (x). */
|
|
||||||
if (tree_expr_nonnegative_p (arg))
|
|
||||||
{
|
|
||||||
tree truncfn = mathfn_built_in (TREE_TYPE (arg), BUILT_IN_TRUNC);
|
|
||||||
if (truncfn)
|
|
||||||
return build_call_expr_loc (loc, truncfn, 1, arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
return fold_trunc_transparent_mathfn (loc, fndecl, arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Fold function call to builtin ceil, ceilf or ceill with argument ARG.
|
|
||||||
Return NULL_TREE if no simplification can be made. */
|
|
||||||
|
|
||||||
static tree
|
|
||||||
fold_builtin_ceil (location_t loc, tree fndecl, tree arg)
|
|
||||||
{
|
|
||||||
if (!validate_arg (arg, REAL_TYPE))
|
|
||||||
return NULL_TREE;
|
|
||||||
|
|
||||||
/* Optimize ceil of constant value. */
|
|
||||||
if (TREE_CODE (arg) == REAL_CST && !TREE_OVERFLOW (arg))
|
|
||||||
{
|
|
||||||
REAL_VALUE_TYPE x;
|
|
||||||
|
|
||||||
x = TREE_REAL_CST (arg);
|
|
||||||
if (! REAL_VALUE_ISNAN (x) || ! flag_errno_math)
|
|
||||||
{
|
|
||||||
tree type = TREE_TYPE (TREE_TYPE (fndecl));
|
|
||||||
REAL_VALUE_TYPE r;
|
|
||||||
|
|
||||||
real_ceil (&r, TYPE_MODE (type), &x);
|
|
||||||
return build_real (type, r);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return fold_trunc_transparent_mathfn (loc, fndecl, arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Fold function call to builtin round, roundf or roundl with argument ARG.
|
|
||||||
Return NULL_TREE if no simplification can be made. */
|
|
||||||
|
|
||||||
static tree
|
|
||||||
fold_builtin_round (location_t loc, tree fndecl, tree arg)
|
|
||||||
{
|
|
||||||
if (!validate_arg (arg, REAL_TYPE))
|
|
||||||
return NULL_TREE;
|
|
||||||
|
|
||||||
/* Optimize round of constant value. */
|
|
||||||
if (TREE_CODE (arg) == REAL_CST && !TREE_OVERFLOW (arg))
|
|
||||||
{
|
|
||||||
REAL_VALUE_TYPE x;
|
|
||||||
|
|
||||||
x = TREE_REAL_CST (arg);
|
|
||||||
if (! REAL_VALUE_ISNAN (x) || ! flag_errno_math)
|
|
||||||
{
|
|
||||||
tree type = TREE_TYPE (TREE_TYPE (fndecl));
|
|
||||||
REAL_VALUE_TYPE r;
|
|
||||||
|
|
||||||
real_round (&r, TYPE_MODE (type), &x);
|
|
||||||
return build_real (type, r);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return fold_trunc_transparent_mathfn (loc, fndecl, arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Fold function call to builtin lround, lroundf or lroundl (or the
|
/* Fold function call to builtin lround, lroundf or lroundl (or the
|
||||||
corresponding long long versions) and other rounding functions. ARG
|
corresponding long long versions) and other rounding functions. ARG
|
||||||
is the argument to the call. Return NULL_TREE if no simplification
|
is the argument to the call. Return NULL_TREE if no simplification
|
||||||
|
@ -9696,20 +9464,56 @@ fold_builtin_1 (location_t loc, tree fndecl, tree arg0)
|
||||||
return fold_builtin_nan (arg0, type, false);
|
return fold_builtin_nan (arg0, type, false);
|
||||||
|
|
||||||
CASE_FLT_FN (BUILT_IN_FLOOR):
|
CASE_FLT_FN (BUILT_IN_FLOOR):
|
||||||
return fold_builtin_floor (loc, fndecl, arg0);
|
if (TREE_CODE (arg0) == REAL_CST && !TREE_OVERFLOW (arg0))
|
||||||
|
{
|
||||||
|
REAL_VALUE_TYPE x = TREE_REAL_CST (arg0);
|
||||||
|
if (!REAL_VALUE_ISNAN (x) || !flag_errno_math)
|
||||||
|
{
|
||||||
|
tree type = TREE_TYPE (TREE_TYPE (fndecl));
|
||||||
|
REAL_VALUE_TYPE r;
|
||||||
|
real_floor (&r, TYPE_MODE (type), &x);
|
||||||
|
return build_real (type, r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
CASE_FLT_FN (BUILT_IN_CEIL):
|
CASE_FLT_FN (BUILT_IN_CEIL):
|
||||||
return fold_builtin_ceil (loc, fndecl, arg0);
|
if (TREE_CODE (arg0) == REAL_CST && !TREE_OVERFLOW (arg0))
|
||||||
|
{
|
||||||
|
REAL_VALUE_TYPE x = TREE_REAL_CST (arg0);
|
||||||
|
if (!REAL_VALUE_ISNAN (x) || !flag_errno_math)
|
||||||
|
{
|
||||||
|
tree type = TREE_TYPE (TREE_TYPE (fndecl));
|
||||||
|
REAL_VALUE_TYPE r;
|
||||||
|
real_ceil (&r, TYPE_MODE (type), &x);
|
||||||
|
return build_real (type, r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
CASE_FLT_FN (BUILT_IN_TRUNC):
|
CASE_FLT_FN (BUILT_IN_TRUNC):
|
||||||
return fold_builtin_trunc (loc, fndecl, arg0);
|
if (TREE_CODE (arg0) == REAL_CST && !TREE_OVERFLOW (arg0))
|
||||||
|
{
|
||||||
|
REAL_VALUE_TYPE x = TREE_REAL_CST (arg0);
|
||||||
|
REAL_VALUE_TYPE r;
|
||||||
|
real_trunc (&r, TYPE_MODE (type), &x);
|
||||||
|
return build_real (type, r);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
CASE_FLT_FN (BUILT_IN_ROUND):
|
CASE_FLT_FN (BUILT_IN_ROUND):
|
||||||
return fold_builtin_round (loc, fndecl, arg0);
|
if (TREE_CODE (arg0) == REAL_CST && !TREE_OVERFLOW (arg0))
|
||||||
|
{
|
||||||
CASE_FLT_FN (BUILT_IN_NEARBYINT):
|
REAL_VALUE_TYPE x = TREE_REAL_CST (arg0);
|
||||||
CASE_FLT_FN (BUILT_IN_RINT):
|
if (!REAL_VALUE_ISNAN (x) || !flag_errno_math)
|
||||||
return fold_trunc_transparent_mathfn (loc, fndecl, arg0);
|
{
|
||||||
|
tree type = TREE_TYPE (TREE_TYPE (fndecl));
|
||||||
|
REAL_VALUE_TYPE r;
|
||||||
|
real_round (&r, TYPE_MODE (type), &x);
|
||||||
|
return build_real (type, r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
CASE_FLT_FN (BUILT_IN_ICEIL):
|
CASE_FLT_FN (BUILT_IN_ICEIL):
|
||||||
CASE_FLT_FN (BUILT_IN_LCEIL):
|
CASE_FLT_FN (BUILT_IN_LCEIL):
|
||||||
|
|
|
@ -225,37 +225,6 @@ convert_to_real (tree type, tree expr)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (optimize
|
|
||||||
&& (((fcode == BUILT_IN_FLOORL
|
|
||||||
|| fcode == BUILT_IN_CEILL
|
|
||||||
|| fcode == BUILT_IN_ROUNDL
|
|
||||||
|| fcode == BUILT_IN_RINTL
|
|
||||||
|| fcode == BUILT_IN_TRUNCL
|
|
||||||
|| fcode == BUILT_IN_NEARBYINTL)
|
|
||||||
&& (TYPE_MODE (type) == TYPE_MODE (double_type_node)
|
|
||||||
|| TYPE_MODE (type) == TYPE_MODE (float_type_node)))
|
|
||||||
|| ((fcode == BUILT_IN_FLOOR
|
|
||||||
|| fcode == BUILT_IN_CEIL
|
|
||||||
|| fcode == BUILT_IN_ROUND
|
|
||||||
|| fcode == BUILT_IN_RINT
|
|
||||||
|| fcode == BUILT_IN_TRUNC
|
|
||||||
|| fcode == BUILT_IN_NEARBYINT)
|
|
||||||
&& (TYPE_MODE (type) == TYPE_MODE (float_type_node)))))
|
|
||||||
{
|
|
||||||
tree fn = mathfn_built_in (type, fcode);
|
|
||||||
|
|
||||||
if (fn)
|
|
||||||
{
|
|
||||||
tree arg = strip_float_extensions (CALL_EXPR_ARG (expr, 0));
|
|
||||||
|
|
||||||
/* Make sure (type)arg0 is an extension, otherwise we could end up
|
|
||||||
changing (float)floor(double d) into floorf((float)d), which is
|
|
||||||
incorrect because (float)d uses round-to-nearest and can round
|
|
||||||
up to the next integer. */
|
|
||||||
if (TYPE_PRECISION (type) >= TYPE_PRECISION (TREE_TYPE (arg)))
|
|
||||||
return build_call_expr (fn, 1, fold (convert_to_real (type, arg)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Propagate the cast into the operation. */
|
/* Propagate the cast into the operation. */
|
||||||
if (itype != type && FLOAT_TYPE_P (type))
|
if (itype != type && FLOAT_TYPE_P (type))
|
||||||
|
|
222
gcc/fold-const.c
222
gcc/fold-const.c
|
@ -12896,10 +12896,6 @@ tree_binary_nonnegative_warnv_p (enum tree_code code, tree type, tree op0,
|
||||||
bool
|
bool
|
||||||
tree_single_nonnegative_warnv_p (tree t, bool *strict_overflow_p, int depth)
|
tree_single_nonnegative_warnv_p (tree t, bool *strict_overflow_p, int depth)
|
||||||
{
|
{
|
||||||
if (TREE_CODE (t) == SSA_NAME
|
|
||||||
&& name_registered_for_update_p (t))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (TYPE_UNSIGNED (TREE_TYPE (t)))
|
if (TYPE_UNSIGNED (TREE_TYPE (t)))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@ -12923,11 +12919,11 @@ tree_single_nonnegative_warnv_p (tree t, bool *strict_overflow_p, int depth)
|
||||||
If this code misses important cases that unbounded recursion
|
If this code misses important cases that unbounded recursion
|
||||||
would not, passes that need this information could be revised
|
would not, passes that need this information could be revised
|
||||||
to provide it through dataflow propagation. */
|
to provide it through dataflow propagation. */
|
||||||
if (depth < PARAM_VALUE (PARAM_MAX_SSA_NAME_QUERY_DEPTH))
|
return (!name_registered_for_update_p (t)
|
||||||
return gimple_stmt_nonnegative_warnv_p (SSA_NAME_DEF_STMT (t),
|
&& depth < PARAM_VALUE (PARAM_MAX_SSA_NAME_QUERY_DEPTH)
|
||||||
strict_overflow_p, depth);
|
&& gimple_stmt_nonnegative_warnv_p (SSA_NAME_DEF_STMT (t),
|
||||||
|
strict_overflow_p, depth));
|
||||||
|
|
||||||
/* Fallthru. */
|
|
||||||
default:
|
default:
|
||||||
return tree_simple_nonnegative_warnv_p (TREE_CODE (t), TREE_TYPE (t));
|
return tree_simple_nonnegative_warnv_p (TREE_CODE (t), TREE_TYPE (t));
|
||||||
}
|
}
|
||||||
|
@ -13440,6 +13436,216 @@ tree_single_nonzero_warnv_p (tree t, bool *strict_overflow_p)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define integer_valued_real_p(X) \
|
||||||
|
_Pragma ("GCC error \"Use RECURSE for recursive calls\"") 0
|
||||||
|
|
||||||
|
#define RECURSE(X) \
|
||||||
|
((integer_valued_real_p) (X, depth + 1))
|
||||||
|
|
||||||
|
/* Return true if the floating point result of (CODE OP0) has an
|
||||||
|
integer value. We also allow +Inf, -Inf and NaN to be considered
|
||||||
|
integer values.
|
||||||
|
|
||||||
|
DEPTH is the current nesting depth of the query. */
|
||||||
|
|
||||||
|
bool
|
||||||
|
integer_valued_real_unary_p (tree_code code, tree op0, int depth)
|
||||||
|
{
|
||||||
|
switch (code)
|
||||||
|
{
|
||||||
|
case FLOAT_EXPR:
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case ABS_EXPR:
|
||||||
|
return RECURSE (op0);
|
||||||
|
|
||||||
|
CASE_CONVERT:
|
||||||
|
{
|
||||||
|
tree type = TREE_TYPE (op0);
|
||||||
|
if (TREE_CODE (type) == INTEGER_TYPE)
|
||||||
|
return true;
|
||||||
|
if (TREE_CODE (type) == REAL_TYPE)
|
||||||
|
return RECURSE (op0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return true if the floating point result of (CODE OP0 OP1) has an
|
||||||
|
integer value. We also allow +Inf, -Inf and NaN to be considered
|
||||||
|
integer values.
|
||||||
|
|
||||||
|
DEPTH is the current nesting depth of the query. */
|
||||||
|
|
||||||
|
bool
|
||||||
|
integer_valued_real_binary_p (tree_code code, tree op0, tree op1, int depth)
|
||||||
|
{
|
||||||
|
switch (code)
|
||||||
|
{
|
||||||
|
case PLUS_EXPR:
|
||||||
|
case MINUS_EXPR:
|
||||||
|
case MULT_EXPR:
|
||||||
|
case MIN_EXPR:
|
||||||
|
case MAX_EXPR:
|
||||||
|
return RECURSE (op0) && RECURSE (op1);
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return true if the floating point result of calling FNDECL with arguments
|
||||||
|
ARG0 and ARG1 has an integer value. We also allow +Inf, -Inf and NaN to be
|
||||||
|
considered integer values. If FNDECL takes fewer than 2 arguments,
|
||||||
|
the remaining ARGn are null.
|
||||||
|
|
||||||
|
DEPTH is the current nesting depth of the query. */
|
||||||
|
|
||||||
|
bool
|
||||||
|
integer_valued_real_call_p (tree fndecl, tree arg0, tree arg1, int depth)
|
||||||
|
{
|
||||||
|
if (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
|
||||||
|
switch (DECL_FUNCTION_CODE (fndecl))
|
||||||
|
{
|
||||||
|
CASE_FLT_FN (BUILT_IN_CEIL):
|
||||||
|
CASE_FLT_FN (BUILT_IN_FLOOR):
|
||||||
|
CASE_FLT_FN (BUILT_IN_NEARBYINT):
|
||||||
|
CASE_FLT_FN (BUILT_IN_RINT):
|
||||||
|
CASE_FLT_FN (BUILT_IN_ROUND):
|
||||||
|
CASE_FLT_FN (BUILT_IN_TRUNC):
|
||||||
|
return true;
|
||||||
|
|
||||||
|
CASE_FLT_FN (BUILT_IN_FMIN):
|
||||||
|
CASE_FLT_FN (BUILT_IN_FMAX):
|
||||||
|
return RECURSE (arg0) && RECURSE (arg1);
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return true if the floating point expression T (a GIMPLE_SINGLE_RHS)
|
||||||
|
has an integer value. We also allow +Inf, -Inf and NaN to be
|
||||||
|
considered integer values.
|
||||||
|
|
||||||
|
DEPTH is the current nesting depth of the query. */
|
||||||
|
|
||||||
|
bool
|
||||||
|
integer_valued_real_single_p (tree t, int depth)
|
||||||
|
{
|
||||||
|
switch (TREE_CODE (t))
|
||||||
|
{
|
||||||
|
case REAL_CST:
|
||||||
|
return real_isinteger (TREE_REAL_CST_PTR (t), TYPE_MODE (TREE_TYPE (t)));
|
||||||
|
|
||||||
|
case COND_EXPR:
|
||||||
|
return RECURSE (TREE_OPERAND (t, 1)) && RECURSE (TREE_OPERAND (t, 2));
|
||||||
|
|
||||||
|
case SSA_NAME:
|
||||||
|
/* Limit the depth of recursion to avoid quadratic behavior.
|
||||||
|
This is expected to catch almost all occurrences in practice.
|
||||||
|
If this code misses important cases that unbounded recursion
|
||||||
|
would not, passes that need this information could be revised
|
||||||
|
to provide it through dataflow propagation. */
|
||||||
|
return (!name_registered_for_update_p (t)
|
||||||
|
&& depth < PARAM_VALUE (PARAM_MAX_SSA_NAME_QUERY_DEPTH)
|
||||||
|
&& gimple_stmt_integer_valued_real_p (SSA_NAME_DEF_STMT (t),
|
||||||
|
depth));
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return true if the floating point expression T (a GIMPLE_INVALID_RHS)
|
||||||
|
has an integer value. We also allow +Inf, -Inf and NaN to be
|
||||||
|
considered integer values.
|
||||||
|
|
||||||
|
DEPTH is the current nesting depth of the query. */
|
||||||
|
|
||||||
|
static bool
|
||||||
|
integer_valued_real_invalid_p (tree t, int depth)
|
||||||
|
{
|
||||||
|
switch (TREE_CODE (t))
|
||||||
|
{
|
||||||
|
case COMPOUND_EXPR:
|
||||||
|
case MODIFY_EXPR:
|
||||||
|
case BIND_EXPR:
|
||||||
|
return RECURSE (TREE_OPERAND (t, 1));
|
||||||
|
|
||||||
|
case SAVE_EXPR:
|
||||||
|
return RECURSE (TREE_OPERAND (t, 0));
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef RECURSE
|
||||||
|
#undef integer_valued_real_p
|
||||||
|
|
||||||
|
/* Return true if the floating point expression T has an integer value.
|
||||||
|
We also allow +Inf, -Inf and NaN to be considered integer values.
|
||||||
|
|
||||||
|
DEPTH is the current nesting depth of the query. */
|
||||||
|
|
||||||
|
bool
|
||||||
|
integer_valued_real_p (tree t, int depth)
|
||||||
|
{
|
||||||
|
if (t == error_mark_node)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
tree_code code = TREE_CODE (t);
|
||||||
|
switch (TREE_CODE_CLASS (code))
|
||||||
|
{
|
||||||
|
case tcc_binary:
|
||||||
|
case tcc_comparison:
|
||||||
|
return integer_valued_real_binary_p (code, TREE_OPERAND (t, 0),
|
||||||
|
TREE_OPERAND (t, 1), depth);
|
||||||
|
|
||||||
|
case tcc_unary:
|
||||||
|
return integer_valued_real_unary_p (code, TREE_OPERAND (t, 0), depth);
|
||||||
|
|
||||||
|
case tcc_constant:
|
||||||
|
case tcc_declaration:
|
||||||
|
case tcc_reference:
|
||||||
|
return integer_valued_real_single_p (t, depth);
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (code)
|
||||||
|
{
|
||||||
|
case COND_EXPR:
|
||||||
|
case SSA_NAME:
|
||||||
|
return integer_valued_real_single_p (t, depth);
|
||||||
|
|
||||||
|
case CALL_EXPR:
|
||||||
|
{
|
||||||
|
tree arg0 = (call_expr_nargs (t) > 0
|
||||||
|
? CALL_EXPR_ARG (t, 0)
|
||||||
|
: NULL_TREE);
|
||||||
|
tree arg1 = (call_expr_nargs (t) > 1
|
||||||
|
? CALL_EXPR_ARG (t, 1)
|
||||||
|
: NULL_TREE);
|
||||||
|
return integer_valued_real_call_p (get_callee_fndecl (t),
|
||||||
|
arg0, arg1, depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return integer_valued_real_invalid_p (t, depth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Given the components of a binary expression CODE, TYPE, OP0 and OP1,
|
/* Given the components of a binary expression CODE, TYPE, OP0 and OP1,
|
||||||
attempt to fold the expression to a constant without modifying TYPE,
|
attempt to fold the expression to a constant without modifying TYPE,
|
||||||
OP0 or OP1.
|
OP0 or OP1.
|
||||||
|
|
|
@ -139,6 +139,12 @@ extern bool tree_single_nonnegative_warnv_p (tree, bool *, int);
|
||||||
extern bool tree_call_nonnegative_warnv_p (tree, tree, tree, tree, bool *,
|
extern bool tree_call_nonnegative_warnv_p (tree, tree, tree, tree, bool *,
|
||||||
int);
|
int);
|
||||||
|
|
||||||
|
extern bool integer_valued_real_unary_p (tree_code, tree, int);
|
||||||
|
extern bool integer_valued_real_binary_p (tree_code, tree, tree, int);
|
||||||
|
extern bool integer_valued_real_call_p (tree, tree, tree, int);
|
||||||
|
extern bool integer_valued_real_single_p (tree, int);
|
||||||
|
extern bool integer_valued_real_p (tree, int = 0);
|
||||||
|
|
||||||
extern bool fold_real_zero_addition_p (const_tree, const_tree, int);
|
extern bool fold_real_zero_addition_p (const_tree, const_tree, int);
|
||||||
extern tree combine_comparisons (location_t, enum tree_code, enum tree_code,
|
extern tree combine_comparisons (location_t, enum tree_code, enum tree_code,
|
||||||
enum tree_code, tree, tree, tree);
|
enum tree_code, tree, tree, tree);
|
||||||
|
|
|
@ -6266,3 +6266,91 @@ gimple_stmt_nonnegative_warnv_p (gimple *stmt, bool *strict_overflow_p,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return true if the floating-point value computed by assignment STMT
|
||||||
|
is known to have an integer value. We also allow +Inf, -Inf and NaN
|
||||||
|
to be considered integer values.
|
||||||
|
|
||||||
|
DEPTH is the current nesting depth of the query. */
|
||||||
|
|
||||||
|
static bool
|
||||||
|
gimple_assign_integer_valued_real_p (gimple *stmt, int depth)
|
||||||
|
{
|
||||||
|
enum tree_code code = gimple_assign_rhs_code (stmt);
|
||||||
|
switch (get_gimple_rhs_class (code))
|
||||||
|
{
|
||||||
|
case GIMPLE_UNARY_RHS:
|
||||||
|
return integer_valued_real_unary_p (gimple_assign_rhs_code (stmt),
|
||||||
|
gimple_assign_rhs1 (stmt), depth);
|
||||||
|
case GIMPLE_BINARY_RHS:
|
||||||
|
return integer_valued_real_binary_p (gimple_assign_rhs_code (stmt),
|
||||||
|
gimple_assign_rhs1 (stmt),
|
||||||
|
gimple_assign_rhs2 (stmt), depth);
|
||||||
|
case GIMPLE_TERNARY_RHS:
|
||||||
|
return false;
|
||||||
|
case GIMPLE_SINGLE_RHS:
|
||||||
|
return integer_valued_real_single_p (gimple_assign_rhs1 (stmt), depth);
|
||||||
|
case GIMPLE_INVALID_RHS:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
gcc_unreachable ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return true if the floating-point value computed by call STMT is known
|
||||||
|
to have an integer value. We also allow +Inf, -Inf and NaN to be
|
||||||
|
considered integer values.
|
||||||
|
|
||||||
|
DEPTH is the current nesting depth of the query. */
|
||||||
|
|
||||||
|
static bool
|
||||||
|
gimple_call_integer_valued_real_p (gimple *stmt, int depth)
|
||||||
|
{
|
||||||
|
tree arg0 = (gimple_call_num_args (stmt) > 0
|
||||||
|
? gimple_call_arg (stmt, 0)
|
||||||
|
: NULL_TREE);
|
||||||
|
tree arg1 = (gimple_call_num_args (stmt) > 1
|
||||||
|
? gimple_call_arg (stmt, 1)
|
||||||
|
: NULL_TREE);
|
||||||
|
return integer_valued_real_call_p (gimple_call_fndecl (stmt),
|
||||||
|
arg0, arg1, depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return true if the floating-point result of phi STMT is known to have
|
||||||
|
an integer value. We also allow +Inf, -Inf and NaN to be considered
|
||||||
|
integer values.
|
||||||
|
|
||||||
|
DEPTH is the current nesting depth of the query. */
|
||||||
|
|
||||||
|
static bool
|
||||||
|
gimple_phi_integer_valued_real_p (gimple *stmt, int depth)
|
||||||
|
{
|
||||||
|
for (unsigned i = 0; i < gimple_phi_num_args (stmt); ++i)
|
||||||
|
{
|
||||||
|
tree arg = gimple_phi_arg_def (stmt, i);
|
||||||
|
if (!integer_valued_real_single_p (arg, depth + 1))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return true if the floating-point value computed by STMT is known
|
||||||
|
to have an integer value. We also allow +Inf, -Inf and NaN to be
|
||||||
|
considered integer values.
|
||||||
|
|
||||||
|
DEPTH is the current nesting depth of the query. */
|
||||||
|
|
||||||
|
bool
|
||||||
|
gimple_stmt_integer_valued_real_p (gimple *stmt, int depth)
|
||||||
|
{
|
||||||
|
switch (gimple_code (stmt))
|
||||||
|
{
|
||||||
|
case GIMPLE_ASSIGN:
|
||||||
|
return gimple_assign_integer_valued_real_p (stmt, depth);
|
||||||
|
case GIMPLE_CALL:
|
||||||
|
return gimple_call_integer_valued_real_p (stmt, depth);
|
||||||
|
case GIMPLE_PHI:
|
||||||
|
return gimple_phi_integer_valued_real_p (stmt, depth);
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -120,6 +120,7 @@ gimple_convert_to_ptrofftype (gimple_seq *seq, tree op)
|
||||||
}
|
}
|
||||||
|
|
||||||
extern bool gimple_stmt_nonnegative_warnv_p (gimple *, bool *, int = 0);
|
extern bool gimple_stmt_nonnegative_warnv_p (gimple *, bool *, int = 0);
|
||||||
|
extern bool gimple_stmt_integer_valued_real_p (gimple *, int = 0);
|
||||||
|
|
||||||
/* In gimple-match.c. */
|
/* In gimple-match.c. */
|
||||||
extern tree gimple_simplify (enum tree_code, tree, tree,
|
extern tree gimple_simplify (enum tree_code, tree, tree,
|
||||||
|
|
77
gcc/match.pd
77
gcc/match.pd
|
@ -31,6 +31,7 @@ along with GCC; see the file COPYING3. If not see
|
||||||
zerop
|
zerop
|
||||||
CONSTANT_CLASS_P
|
CONSTANT_CLASS_P
|
||||||
tree_expr_nonnegative_p
|
tree_expr_nonnegative_p
|
||||||
|
integer_valued_real_p
|
||||||
integer_pow2p
|
integer_pow2p
|
||||||
HONOR_NANS)
|
HONOR_NANS)
|
||||||
|
|
||||||
|
@ -70,6 +71,14 @@ along with GCC; see the file COPYING3. If not see
|
||||||
BUILT_IN_COPYSIGN
|
BUILT_IN_COPYSIGN
|
||||||
BUILT_IN_COPYSIGNL)
|
BUILT_IN_COPYSIGNL)
|
||||||
(define_operator_list CABS BUILT_IN_CABSF BUILT_IN_CABS BUILT_IN_CABSL)
|
(define_operator_list CABS BUILT_IN_CABSF BUILT_IN_CABS BUILT_IN_CABSL)
|
||||||
|
(define_operator_list TRUNC BUILT_IN_TRUNCF BUILT_IN_TRUNC BUILT_IN_TRUNCL)
|
||||||
|
(define_operator_list FLOOR BUILT_IN_FLOORF BUILT_IN_FLOOR BUILT_IN_FLOORL)
|
||||||
|
(define_operator_list CEIL BUILT_IN_CEILF BUILT_IN_CEIL BUILT_IN_CEILL)
|
||||||
|
(define_operator_list ROUND BUILT_IN_ROUNDF BUILT_IN_ROUND BUILT_IN_ROUNDL)
|
||||||
|
(define_operator_list NEARBYINT BUILT_IN_NEARBYINTF
|
||||||
|
BUILT_IN_NEARBYINT
|
||||||
|
BUILT_IN_NEARBYINTL)
|
||||||
|
(define_operator_list RINT BUILT_IN_RINTF BUILT_IN_RINT BUILT_IN_RINTL)
|
||||||
|
|
||||||
/* Simplifications of operations with one constant operand and
|
/* Simplifications of operations with one constant operand and
|
||||||
simplifications to constants or single values. */
|
simplifications to constants or single values. */
|
||||||
|
@ -2439,6 +2448,23 @@ along with GCC; see the file COPYING3. If not see
|
||||||
(CABS (complex:c @0 real_zerop@1))
|
(CABS (complex:c @0 real_zerop@1))
|
||||||
(abs @0))
|
(abs @0))
|
||||||
|
|
||||||
|
/* trunc(trunc(x)) -> trunc(x), etc. */
|
||||||
|
(for fns (TRUNC FLOOR CEIL ROUND NEARBYINT RINT)
|
||||||
|
(simplify
|
||||||
|
(fns (fns @0))
|
||||||
|
(fns @0)))
|
||||||
|
/* f(x) -> x if x is integer valued and f does nothing for such values. */
|
||||||
|
(for fns (TRUNC FLOOR CEIL ROUND NEARBYINT)
|
||||||
|
(simplify
|
||||||
|
(fns integer_valued_real_p@0)
|
||||||
|
@0))
|
||||||
|
/* Same for rint. We have to check flag_errno_math because
|
||||||
|
integer_valued_real_p accepts +Inf, -Inf and NaNs as integers. */
|
||||||
|
(if (!flag_errno_math)
|
||||||
|
(simplify
|
||||||
|
(RINT integer_valued_real_p@0)
|
||||||
|
@0))
|
||||||
|
|
||||||
/* Canonicalization of sequences of math builtins. These rules represent
|
/* Canonicalization of sequences of math builtins. These rules represent
|
||||||
IL simplifications but are not necessarily optimizations.
|
IL simplifications but are not necessarily optimizations.
|
||||||
|
|
||||||
|
@ -2537,6 +2563,57 @@ along with GCC; see the file COPYING3. If not see
|
||||||
(CABS (complex @0 @0))
|
(CABS (complex @0 @0))
|
||||||
(mult (abs @0) { build_real_truncate (type, dconst_sqrt2 ()); })))
|
(mult (abs @0) { build_real_truncate (type, dconst_sqrt2 ()); })))
|
||||||
|
|
||||||
|
(if (canonicalize_math_p ())
|
||||||
|
/* floor(x) -> trunc(x) if x is nonnegative. */
|
||||||
|
(for floors (FLOOR)
|
||||||
|
truncs (TRUNC)
|
||||||
|
(simplify
|
||||||
|
(floors tree_expr_nonnegative_p@0)
|
||||||
|
(truncs @0))))
|
||||||
|
|
||||||
|
(match double_value_p
|
||||||
|
@0
|
||||||
|
(if (TYPE_MAIN_VARIANT (TREE_TYPE (@0)) == double_type_node)))
|
||||||
|
(for froms (BUILT_IN_TRUNCL
|
||||||
|
BUILT_IN_FLOORL
|
||||||
|
BUILT_IN_CEILL
|
||||||
|
BUILT_IN_ROUNDL
|
||||||
|
BUILT_IN_NEARBYINTL
|
||||||
|
BUILT_IN_RINTL)
|
||||||
|
tos (BUILT_IN_TRUNC
|
||||||
|
BUILT_IN_FLOOR
|
||||||
|
BUILT_IN_CEIL
|
||||||
|
BUILT_IN_ROUND
|
||||||
|
BUILT_IN_NEARBYINT
|
||||||
|
BUILT_IN_RINT)
|
||||||
|
/* truncl(extend(x)) -> extend(trunc(x)), etc., if x is a double. */
|
||||||
|
(if (optimize && canonicalize_math_p ())
|
||||||
|
(simplify
|
||||||
|
(froms (convert double_value_p@0))
|
||||||
|
(convert (tos @0)))))
|
||||||
|
|
||||||
|
(match float_value_p
|
||||||
|
@0
|
||||||
|
(if (TYPE_MAIN_VARIANT (TREE_TYPE (@0)) == float_type_node)))
|
||||||
|
(for froms (BUILT_IN_TRUNCL BUILT_IN_TRUNC
|
||||||
|
BUILT_IN_FLOORL BUILT_IN_FLOOR
|
||||||
|
BUILT_IN_CEILL BUILT_IN_CEIL
|
||||||
|
BUILT_IN_ROUNDL BUILT_IN_ROUND
|
||||||
|
BUILT_IN_NEARBYINTL BUILT_IN_NEARBYINT
|
||||||
|
BUILT_IN_RINTL BUILT_IN_RINT)
|
||||||
|
tos (BUILT_IN_TRUNCF BUILT_IN_TRUNCF
|
||||||
|
BUILT_IN_FLOORF BUILT_IN_FLOORF
|
||||||
|
BUILT_IN_CEILF BUILT_IN_CEILF
|
||||||
|
BUILT_IN_ROUNDF BUILT_IN_ROUNDF
|
||||||
|
BUILT_IN_NEARBYINTF BUILT_IN_NEARBYINTF
|
||||||
|
BUILT_IN_RINTF BUILT_IN_RINTF)
|
||||||
|
/* truncl(extend(x)) and trunc(extend(x)) -> extend(truncf(x)), etc.,
|
||||||
|
if x is a float. */
|
||||||
|
(if (optimize && canonicalize_math_p ())
|
||||||
|
(simplify
|
||||||
|
(froms (convert float_value_p@0))
|
||||||
|
(convert (tos @0)))))
|
||||||
|
|
||||||
/* cproj(x) -> x if we're ignoring infinities. */
|
/* cproj(x) -> x if we're ignoring infinities. */
|
||||||
(simplify
|
(simplify
|
||||||
(CPROJ @0)
|
(CPROJ @0)
|
||||||
|
|
|
@ -1,3 +1,10 @@
|
||||||
|
2015-10-23 Richard Sandiford <richard.sandiford@arm.com>
|
||||||
|
|
||||||
|
* gcc.c-torture/execute/20030125-1.c (floor, floorf, sin, sinf):
|
||||||
|
Make weak rather than noinline.
|
||||||
|
* gcc.dg/builtins-57.c: Compile with -O.
|
||||||
|
* gcc.dg/torture/builtin-integral-1.c: Skip for -O0.
|
||||||
|
|
||||||
2015-10-23 Tom de Vries <tom@codesourcery.com>
|
2015-10-23 Tom de Vries <tom@codesourcery.com>
|
||||||
|
|
||||||
* gcc.dg/tree-ssa/restrict-4.c: Add -fno-ipa-icf to dg-options.
|
* gcc.dg/tree-ssa/restrict-4.c: Add -fno-ipa-icf to dg-options.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
/* Verify whether math functions are simplified. */
|
/* Verify whether math functions are simplified. */
|
||||||
/* { dg-require-effective-target c99_runtime } */
|
/* { dg-require-effective-target c99_runtime } */
|
||||||
|
/* { dg-require-weak } */
|
||||||
double sin(double);
|
double sin(double);
|
||||||
double floor(double);
|
double floor(double);
|
||||||
float
|
float
|
||||||
|
@ -29,25 +30,25 @@ main()
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
__attribute__ ((noinline))
|
__attribute__ ((weak))
|
||||||
double
|
double
|
||||||
floor(double a)
|
floor(double a)
|
||||||
{
|
{
|
||||||
abort ();
|
abort ();
|
||||||
}
|
}
|
||||||
__attribute__ ((noinline))
|
__attribute__ ((weak))
|
||||||
float
|
float
|
||||||
floorf(float a)
|
floorf(float a)
|
||||||
{
|
{
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
__attribute__ ((noinline))
|
__attribute__ ((weak))
|
||||||
double
|
double
|
||||||
sin(double a)
|
sin(double a)
|
||||||
{
|
{
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
__attribute__ ((noinline))
|
__attribute__ ((weak))
|
||||||
float
|
float
|
||||||
sinf(float a)
|
sinf(float a)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/* { dg-do link } */
|
/* { dg-do link } */
|
||||||
/* { dg-options "-std=c99 -ffinite-math-only" } */
|
/* { dg-options "-std=c99 -ffinite-math-only -O" } */
|
||||||
|
|
||||||
#include "builtins-config.h"
|
#include "builtins-config.h"
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
that various math functions are marked const/pure and can be
|
that various math functions are marked const/pure and can be
|
||||||
folded. */
|
folded. */
|
||||||
/* { dg-options "-ffinite-math-only -fno-math-errno" } */
|
/* { dg-options "-ffinite-math-only -fno-math-errno" } */
|
||||||
|
/* { dg-skip-if "" { *-*-* } { "-O0" } { "" } } */
|
||||||
|
|
||||||
extern int link_failure (int);
|
extern int link_failure (int);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue