mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-18 14:30:42 +08:00
fold-const.c (negate_mathfn_p): New function to determine whether a built-in mathematical function is sign...
* fold-const.c (negate_mathfn_p): New function to determine whether a built-in mathematical function is sign preserving, f(-x) == -f(x). Add support for BUILT_IN_ASIN, BUILT_IN_ASINF and BUILT_IN_ASINL. (tree_swap_operands_p): Change API to take an additional argument indicating that the swapped operands evaluate in reverse order. Canonicalize VAR_DECLs and PARM_DECLs last if we can, i.e. neither operand side-effects or we don't care about flag_evaluation_order. (reorder_operands_p): New function to check whether its safe to evaluate the given operands in reverse order. (negate_expr_p): We can always negate integer constants unless we honor -ftrapv and the signed type would overflow. Only allow -(A-B) into B-A if reorder_operands_p says that its OK. Allow negation of COMPLEX_CST if both real and imaginary parts can be negated. Allow negation through floating point extensions and sign-preserving built-in functions. (negate_expr): Move the code to negate integers from "fold" to here. Always negate integer constants unless we honor -ftrapv and the signed type would overflow. Always negate real constants unless we honor -ftrapping-math. Only convert -(A-B) into B-A if allowed by reorder_operands_p. Add support for COMPLEX_CST. Optimize negation through floating point extensions and sign-preserving built-in functions (as defined by negate_mathfn_p). (fold): Adjust calls to tree_swap_operands_p. (fold <NEGATE_EXPR>): Move the remaining negation optimizations to negate_expr_p/negate_expr. (fold <MINUS_EXPR>): Use reorder_operands_p to check whether we're allowed to convert (-A) - B into (-B) - A. From-SVN: r72381
This commit is contained in:
parent
c43fa1f51a
commit
05d362b88d
@ -1,3 +1,33 @@
|
||||
2003-10-11 Roger Sayle <roger@eyesopen.com>
|
||||
|
||||
* fold-const.c (negate_mathfn_p): New function to determine whether
|
||||
a built-in mathematical function is sign preserving, f(-x) == -f(x).
|
||||
Add support for BUILT_IN_ASIN, BUILT_IN_ASINF and BUILT_IN_ASINL.
|
||||
(tree_swap_operands_p): Change API to take an additional argument
|
||||
indicating that the swapped operands evaluate in reverse order.
|
||||
Canonicalize VAR_DECLs and PARM_DECLs last if we can, i.e. neither
|
||||
operand side-effects or we don't care about flag_evaluation_order.
|
||||
(reorder_operands_p): New function to check whether its safe to
|
||||
evaluate the given operands in reverse order.
|
||||
(negate_expr_p): We can always negate integer constants unless
|
||||
we honor -ftrapv and the signed type would overflow. Only allow
|
||||
-(A-B) into B-A if reorder_operands_p says that its OK. Allow
|
||||
negation of COMPLEX_CST if both real and imaginary parts can be
|
||||
negated. Allow negation through floating point extensions and
|
||||
sign-preserving built-in functions.
|
||||
(negate_expr): Move the code to negate integers from "fold" to
|
||||
here. Always negate integer constants unless we honor -ftrapv
|
||||
and the signed type would overflow. Always negate real constants
|
||||
unless we honor -ftrapping-math. Only convert -(A-B) into B-A
|
||||
if allowed by reorder_operands_p. Add support for COMPLEX_CST.
|
||||
Optimize negation through floating point extensions and
|
||||
sign-preserving built-in functions (as defined by negate_mathfn_p).
|
||||
(fold): Adjust calls to tree_swap_operands_p.
|
||||
(fold <NEGATE_EXPR>): Move the remaining negation optimizations
|
||||
to negate_expr_p/negate_expr.
|
||||
(fold <MINUS_EXPR>): Use reorder_operands_p to check whether we're
|
||||
allowed to convert (-A) - B into (-B) - A.
|
||||
|
||||
2003-10-11 Roger Sayle <roger@eyesopen.com>
|
||||
|
||||
* builtins.c (expand_builtin_strcmp): Defend against the possibility
|
||||
|
232
gcc/fold-const.c
232
gcc/fold-const.c
@ -60,6 +60,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
|
||||
static void encode (HOST_WIDE_INT *, unsigned HOST_WIDE_INT, HOST_WIDE_INT);
|
||||
static void decode (HOST_WIDE_INT *, unsigned HOST_WIDE_INT *, HOST_WIDE_INT *);
|
||||
static bool negate_mathfn_p (enum built_in_function);
|
||||
static bool negate_expr_p (tree);
|
||||
static tree negate_expr (tree);
|
||||
static tree split_tree (tree, enum tree_code, tree *, tree *, tree *, int);
|
||||
@ -108,7 +109,8 @@ static bool fold_real_zero_addition_p (tree, tree, int);
|
||||
static tree fold_mathfn_compare (enum built_in_function, enum tree_code,
|
||||
tree, tree, tree);
|
||||
static tree fold_inf_compare (enum tree_code, tree, tree, tree);
|
||||
static bool tree_swap_operands_p (tree, tree);
|
||||
static bool reorder_operands_p (tree, tree);
|
||||
static bool tree_swap_operands_p (tree, tree, bool);
|
||||
|
||||
/* The following constants represent a bit based encoding of GCC's
|
||||
comparison operators. This encoding simplifies transformations
|
||||
@ -803,6 +805,35 @@ div_and_round_double (enum tree_code code, int uns,
|
||||
return overflow;
|
||||
}
|
||||
|
||||
/* Return true if built-in mathematical function specified by CODE
|
||||
preserves the sign of it argument, i.e. -f(x) == f(-x). */
|
||||
|
||||
static bool
|
||||
negate_mathfn_p (enum built_in_function code)
|
||||
{
|
||||
switch (code)
|
||||
{
|
||||
case BUILT_IN_ASIN:
|
||||
case BUILT_IN_ASINF:
|
||||
case BUILT_IN_ASINL:
|
||||
case BUILT_IN_ATAN:
|
||||
case BUILT_IN_ATANF:
|
||||
case BUILT_IN_ATANL:
|
||||
case BUILT_IN_SIN:
|
||||
case BUILT_IN_SINF:
|
||||
case BUILT_IN_SINL:
|
||||
case BUILT_IN_TAN:
|
||||
case BUILT_IN_TANF:
|
||||
case BUILT_IN_TANL:
|
||||
return true;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* Determine whether an expression T can be cheaply negated using
|
||||
the function negate_expr. */
|
||||
|
||||
@ -822,8 +853,8 @@ negate_expr_p (tree t)
|
||||
switch (TREE_CODE (t))
|
||||
{
|
||||
case INTEGER_CST:
|
||||
if (TREE_UNSIGNED (type))
|
||||
return false;
|
||||
if (TREE_UNSIGNED (type) || ! flag_trapv)
|
||||
return true;
|
||||
|
||||
/* Check that -CST will not overflow type. */
|
||||
prec = TYPE_PRECISION (type);
|
||||
@ -844,9 +875,15 @@ negate_expr_p (tree t)
|
||||
case NEGATE_EXPR:
|
||||
return true;
|
||||
|
||||
case COMPLEX_CST:
|
||||
return negate_expr_p (TREE_REALPART (t))
|
||||
&& negate_expr_p (TREE_IMAGPART (t));
|
||||
|
||||
case MINUS_EXPR:
|
||||
/* We can't turn -(A-B) into B-A when we honor signed zeros. */
|
||||
return ! FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations;
|
||||
return (! FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations)
|
||||
&& reorder_operands_p (TREE_OPERAND (t, 0),
|
||||
TREE_OPERAND (t, 1));
|
||||
|
||||
case MULT_EXPR:
|
||||
if (TREE_UNSIGNED (TREE_TYPE (t)))
|
||||
@ -860,6 +897,22 @@ negate_expr_p (tree t)
|
||||
|| negate_expr_p (TREE_OPERAND (t, 0));
|
||||
break;
|
||||
|
||||
case NOP_EXPR:
|
||||
/* Negate -((double)float) as (double)(-float). */
|
||||
if (TREE_CODE (type) == REAL_TYPE)
|
||||
{
|
||||
tree tem = strip_float_extensions (t);
|
||||
if (tem != t)
|
||||
return negate_expr_p (tem);
|
||||
}
|
||||
break;
|
||||
|
||||
case CALL_EXPR:
|
||||
/* Negate -f(x) as f(-x). */
|
||||
if (negate_mathfn_p (builtin_mathfn_code (t)))
|
||||
return negate_expr_p (TREE_VALUE (TREE_OPERAND (t, 1)));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -884,25 +937,53 @@ negate_expr (tree t)
|
||||
switch (TREE_CODE (t))
|
||||
{
|
||||
case INTEGER_CST:
|
||||
if (! TREE_UNSIGNED (type)
|
||||
&& 0 != (tem = fold (build1 (NEGATE_EXPR, type, t)))
|
||||
&& ! TREE_OVERFLOW (tem))
|
||||
{
|
||||
unsigned HOST_WIDE_INT low;
|
||||
HOST_WIDE_INT high;
|
||||
int overflow = neg_double (TREE_INT_CST_LOW (t),
|
||||
TREE_INT_CST_HIGH (t),
|
||||
&low, &high);
|
||||
tem = build_int_2 (low, high);
|
||||
TREE_TYPE (tem) = type;
|
||||
TREE_OVERFLOW (tem)
|
||||
= (TREE_OVERFLOW (t)
|
||||
| force_fit_type (tem, overflow && !TREE_UNSIGNED (type)));
|
||||
TREE_CONSTANT_OVERFLOW (tem)
|
||||
= TREE_OVERFLOW (tem) | TREE_CONSTANT_OVERFLOW (t);
|
||||
}
|
||||
if (! TREE_OVERFLOW (tem)
|
||||
|| TREE_UNSIGNED (type)
|
||||
|| ! flag_trapv)
|
||||
return tem;
|
||||
break;
|
||||
|
||||
case REAL_CST:
|
||||
tem = build_real (type, REAL_VALUE_NEGATE (TREE_REAL_CST (t)));
|
||||
/* Two's complement FP formats, such as c4x, may overflow. */
|
||||
if (! TREE_OVERFLOW (tem))
|
||||
if (! TREE_OVERFLOW (tem) || ! flag_trapping_math)
|
||||
return convert (type, tem);
|
||||
break;
|
||||
|
||||
case COMPLEX_CST:
|
||||
{
|
||||
tree rpart = negate_expr (TREE_REALPART (t));
|
||||
tree ipart = negate_expr (TREE_IMAGPART (t));
|
||||
|
||||
if ((TREE_CODE (rpart) == REAL_CST
|
||||
&& TREE_CODE (ipart) == REAL_CST)
|
||||
|| (TREE_CODE (rpart) == INTEGER_CST
|
||||
&& TREE_CODE (ipart) == INTEGER_CST))
|
||||
return build_complex (type, rpart, ipart);
|
||||
}
|
||||
break;
|
||||
|
||||
case NEGATE_EXPR:
|
||||
return convert (type, TREE_OPERAND (t, 0));
|
||||
|
||||
case MINUS_EXPR:
|
||||
/* - (A - B) -> B - A */
|
||||
if (! FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations)
|
||||
if ((! FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations)
|
||||
&& reorder_operands_p (TREE_OPERAND (t, 0), TREE_OPERAND (t, 1)))
|
||||
return convert (type,
|
||||
fold (build (MINUS_EXPR, TREE_TYPE (t),
|
||||
TREE_OPERAND (t, 1),
|
||||
@ -933,6 +1014,30 @@ negate_expr (tree t)
|
||||
}
|
||||
break;
|
||||
|
||||
case NOP_EXPR:
|
||||
/* Convert -((double)float) into (double)(-float). */
|
||||
if (TREE_CODE (type) == REAL_TYPE)
|
||||
{
|
||||
tem = strip_float_extensions (t);
|
||||
if (tem != t && negate_expr_p (tem))
|
||||
return convert (type, negate_expr (tem));
|
||||
}
|
||||
break;
|
||||
|
||||
case CALL_EXPR:
|
||||
/* Negate -f(x) as f(-x). */
|
||||
if (negate_mathfn_p (builtin_mathfn_code (t))
|
||||
&& negate_expr_p (TREE_VALUE (TREE_OPERAND (t, 1))))
|
||||
{
|
||||
tree fndecl, arg, arglist;
|
||||
|
||||
fndecl = get_callee_fndecl (t);
|
||||
arg = negate_expr (TREE_VALUE (TREE_OPERAND (t, 1)));
|
||||
arglist = build_tree_list (NULL_TREE, arg);
|
||||
return build_function_call_expr (fndecl, arglist);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -4999,12 +5104,27 @@ fold_single_bit_test (enum tree_code code, tree arg0, tree arg1,
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
/* Test whether it is preferable two swap two operands, ARG0 and
|
||||
ARG1, for example because ARG0 is an integer constant and ARG1
|
||||
isn't. */
|
||||
/* Check whether we are allowed to reorder operands arg0 and arg1,
|
||||
such that the evaluation of arg1 occurs before arg0. */
|
||||
|
||||
static bool
|
||||
tree_swap_operands_p (tree arg0, tree arg1)
|
||||
reorder_operands_p (tree arg0, tree arg1)
|
||||
{
|
||||
if (! flag_evaluation_order)
|
||||
return true;
|
||||
if (TREE_CONSTANT (arg0) || TREE_CONSTANT (arg1))
|
||||
return true;
|
||||
return ! TREE_SIDE_EFFECTS (arg0)
|
||||
&& ! TREE_SIDE_EFFECTS (arg1);
|
||||
}
|
||||
|
||||
/* Test whether it is preferable two swap two operands, ARG0 and
|
||||
ARG1, for example because ARG0 is an integer constant and ARG1
|
||||
isn't. If REORDER is true, only recommend swapping if we can
|
||||
evaluate the operands in reverse order. */
|
||||
|
||||
static bool
|
||||
tree_swap_operands_p (tree arg0, tree arg1, bool reorder)
|
||||
{
|
||||
STRIP_SIGN_NOPS (arg0);
|
||||
STRIP_SIGN_NOPS (arg1);
|
||||
@ -5029,6 +5149,15 @@ tree_swap_operands_p (tree arg0, tree arg1)
|
||||
if (TREE_CONSTANT (arg0))
|
||||
return 1;
|
||||
|
||||
if (reorder && flag_evaluation_order
|
||||
&& (TREE_SIDE_EFFECTS (arg0) || TREE_SIDE_EFFECTS (arg1)))
|
||||
return 0;
|
||||
|
||||
if (DECL_P (arg1))
|
||||
return 0;
|
||||
if (DECL_P (arg0))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -5143,7 +5272,7 @@ fold (tree expr)
|
||||
if ((code == PLUS_EXPR || code == MULT_EXPR || code == MIN_EXPR
|
||||
|| code == MAX_EXPR || code == BIT_IOR_EXPR || code == BIT_XOR_EXPR
|
||||
|| code == BIT_AND_EXPR)
|
||||
&& tree_swap_operands_p (arg0, arg1))
|
||||
&& tree_swap_operands_p (arg0, arg1, true))
|
||||
return fold (build (code, type, arg1, arg0));
|
||||
|
||||
/* Now WINS is set as described above,
|
||||
@ -5482,71 +5611,8 @@ fold (tree expr)
|
||||
return t;
|
||||
|
||||
case NEGATE_EXPR:
|
||||
if (wins)
|
||||
{
|
||||
if (TREE_CODE (arg0) == INTEGER_CST)
|
||||
{
|
||||
unsigned HOST_WIDE_INT low;
|
||||
HOST_WIDE_INT high;
|
||||
int overflow = neg_double (TREE_INT_CST_LOW (arg0),
|
||||
TREE_INT_CST_HIGH (arg0),
|
||||
&low, &high);
|
||||
t = build_int_2 (low, high);
|
||||
TREE_TYPE (t) = type;
|
||||
TREE_OVERFLOW (t)
|
||||
= (TREE_OVERFLOW (arg0)
|
||||
| force_fit_type (t, overflow && !TREE_UNSIGNED (type)));
|
||||
TREE_CONSTANT_OVERFLOW (t)
|
||||
= TREE_OVERFLOW (t) | TREE_CONSTANT_OVERFLOW (arg0);
|
||||
}
|
||||
else if (TREE_CODE (arg0) == REAL_CST)
|
||||
t = build_real (type, REAL_VALUE_NEGATE (TREE_REAL_CST (arg0)));
|
||||
}
|
||||
else if (TREE_CODE (arg0) == NEGATE_EXPR)
|
||||
return TREE_OPERAND (arg0, 0);
|
||||
/* Convert -((double)float) into (double)(-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 (NEGATE_EXPR, TREE_TYPE (targ0), targ0));
|
||||
|
||||
}
|
||||
|
||||
/* Convert - (a - b) to (b - a) for non-floating-point. */
|
||||
else if (TREE_CODE (arg0) == MINUS_EXPR
|
||||
&& (! FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations))
|
||||
return build (MINUS_EXPR, type, TREE_OPERAND (arg0, 1),
|
||||
TREE_OPERAND (arg0, 0));
|
||||
|
||||
/* Convert -f(x) into f(-x) where f is sin, tan or atan. */
|
||||
switch (builtin_mathfn_code (arg0))
|
||||
{
|
||||
case BUILT_IN_SIN:
|
||||
case BUILT_IN_SINF:
|
||||
case BUILT_IN_SINL:
|
||||
case BUILT_IN_TAN:
|
||||
case BUILT_IN_TANF:
|
||||
case BUILT_IN_TANL:
|
||||
case BUILT_IN_ATAN:
|
||||
case BUILT_IN_ATANF:
|
||||
case BUILT_IN_ATANL:
|
||||
if (negate_expr_p (TREE_VALUE (TREE_OPERAND (arg0, 1))))
|
||||
{
|
||||
tree fndecl, arg, arglist;
|
||||
|
||||
fndecl = get_callee_fndecl (arg0);
|
||||
arg = TREE_VALUE (TREE_OPERAND (arg0, 1));
|
||||
arg = fold (build1 (NEGATE_EXPR, type, arg));
|
||||
arglist = build_tree_list (NULL_TREE, arg);
|
||||
return build_function_call_expr (fndecl, arglist);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (negate_expr_p (arg0))
|
||||
return negate_expr (arg0);
|
||||
return t;
|
||||
|
||||
case ABS_EXPR:
|
||||
@ -5999,8 +6065,7 @@ fold (tree expr)
|
||||
&& (FLOAT_TYPE_P (type)
|
||||
|| (INTEGRAL_TYPE_P (type) && flag_wrapv && !flag_trapv))
|
||||
&& negate_expr_p (arg1)
|
||||
&& (! TREE_SIDE_EFFECTS (arg0) || TREE_CONSTANT (arg1))
|
||||
&& (! TREE_SIDE_EFFECTS (arg1) || TREE_CONSTANT (arg0)))
|
||||
&& reorder_operands_p (arg0, arg1))
|
||||
return fold (build (MINUS_EXPR, type, negate_expr (arg1),
|
||||
TREE_OPERAND (arg0, 0)));
|
||||
|
||||
@ -6911,7 +6976,7 @@ fold (tree expr)
|
||||
case LE_EXPR:
|
||||
case GE_EXPR:
|
||||
/* If one arg is a real or integer constant, put it last. */
|
||||
if (tree_swap_operands_p (arg0, arg1))
|
||||
if (tree_swap_operands_p (arg0, arg1, true))
|
||||
return fold (build (swap_tree_comparison (code), type, arg1, arg0));
|
||||
|
||||
if (FLOAT_TYPE_P (TREE_TYPE (arg0)))
|
||||
@ -8025,7 +8090,8 @@ fold (tree expr)
|
||||
|
||||
/* If the second operand is simpler than the third, swap them
|
||||
since that produces better jump optimization results. */
|
||||
if (tree_swap_operands_p (TREE_OPERAND (t, 1), TREE_OPERAND (t, 2)))
|
||||
if (tree_swap_operands_p (TREE_OPERAND (t, 1),
|
||||
TREE_OPERAND (t, 2), false))
|
||||
{
|
||||
/* See if this can be inverted. If it can't, possibly because
|
||||
it was a floating-point inequality comparison, don't do
|
||||
|
Loading…
x
Reference in New Issue
Block a user