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:
Roger Sayle 2003-10-11 21:15:08 +00:00 committed by Roger Sayle
parent c43fa1f51a
commit 05d362b88d
2 changed files with 179 additions and 83 deletions

View File

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

View File

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