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);
/* The following constants represent a bit based encoding of GCC's
comparison operators. This encoding simplifies transformations
same value in each operand/subexpression. Hence a zero value for
ONLY_CONST assumes isochronic (or instantaneous) tree equivalence.
If comparing arbitrary expression trees, such as from different
- statements, ONLY_CONST must usually be non-zero. */
+ statements, ONLY_CONST must usually be nonzero. */
int
operand_equal_p (tree arg0, tree arg1, int only_const)
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. */
+
+static bool
+tree_swap_operands_p (tree arg0, tree arg1)
+{
+ STRIP_SIGN_NOPS (arg0);
+ STRIP_SIGN_NOPS (arg1);
+
+ if (TREE_CODE (arg1) == INTEGER_CST)
+ return 0;
+ if (TREE_CODE (arg0) == INTEGER_CST)
+ return 1;
+
+ if (TREE_CODE (arg1) == REAL_CST)
+ return 0;
+ if (TREE_CODE (arg0) == REAL_CST)
+ return 1;
+
+ if (TREE_CODE (arg1) == COMPLEX_CST)
+ return 0;
+ if (TREE_CODE (arg0) == COMPLEX_CST)
+ return 1;
+
+ if (TREE_CONSTANT (arg1))
+ return 0;
+ if (TREE_CONSTANT (arg0))
+ return 1;
+
+ return 0;
+}
+
/* Perform constant folding and related simplification of EXPR.
The related simplifications include x*1 => x, x*0 => 0, etc.,
and application of the associative law.
subop = arg0;
if (subop != 0 && TREE_CODE (subop) != INTEGER_CST
- && TREE_CODE (subop) != REAL_CST
- )
+ && TREE_CODE (subop) != REAL_CST)
/* Note that TREE_CONSTANT isn't enough:
static var addresses are constant but we can't
do arithmetic on them. */
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_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) != INTEGER_CST)
- || (TREE_CODE (arg0) == REAL_CST && TREE_CODE (arg1) != REAL_CST)))
- {
- tem = arg0; arg0 = arg1; arg1 = tem;
-
- if (t == orig_t)
- t = copy_node (t);
- TREE_OPERAND (t, 0) = arg0;
- TREE_OPERAND (t, 1) = arg1;
- }
+ && tree_swap_operands_p (arg0, arg1))
+ return fold (build (code, type, arg1, arg0));
/* Now WINS is set as described above,
ARG0 is the first operand of EXPR,
TREE_OPERAND (arg1, 1))),
arg0));
}
+
+ /* Fold (A & ~B) - (A & B) into (A ^ B) - B, where B is
+ any power of 2 minus 1. */
+ if (TREE_CODE (arg0) == BIT_AND_EXPR
+ && TREE_CODE (arg1) == BIT_AND_EXPR
+ && operand_equal_p (TREE_OPERAND (arg0, 0),
+ TREE_OPERAND (arg1, 0), 0)
+ && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
+ && TREE_CODE (TREE_OPERAND (arg1, 1)) == INTEGER_CST)
+ {
+ tree mask0 = TREE_OPERAND (arg0, 1);
+ tree mask1 = TREE_OPERAND (arg1, 1);
+ tree tem = fold (build1 (BIT_NOT_EXPR, type, mask0));
+
+ if (operand_equal_p (tem, mask1, 0)
+ && integer_pow2p (fold (build (PLUS_EXPR, type,
+ mask1, integer_one_node))))
+ {
+ tem = fold (build (BIT_XOR_EXPR, type,
+ TREE_OPERAND (arg0, 0), mask1));
+ return fold (build (MINUS_EXPR, type, tem, mask1));
+ }
+ }
}
/* See if ARG1 is zero and X - ARG1 reduces to X. */
return build_function_call_expr (sqrtfn, arglist);
}
- /* Optimize exp(x)*exp(y) as exp(x+y). */
- if ((fcode0 == BUILT_IN_EXP && fcode1 == BUILT_IN_EXP)
- || (fcode0 == BUILT_IN_EXPF && fcode1 == BUILT_IN_EXPF)
- || (fcode0 == BUILT_IN_EXPL && fcode1 == BUILT_IN_EXPL))
+ /* Optimize expN(x)*expN(y) as expN(x+y). */
+ if (fcode0 == fcode1
+ && (fcode0 == BUILT_IN_EXP
+ || fcode0 == BUILT_IN_EXPF
+ || fcode0 == BUILT_IN_EXPL
+ || fcode0 == BUILT_IN_EXP2
+ || fcode0 == BUILT_IN_EXP2F
+ || fcode0 == BUILT_IN_EXP2L
+ || fcode0 == BUILT_IN_EXP10
+ || fcode0 == BUILT_IN_EXP10F
+ || fcode0 == BUILT_IN_EXP10L
+ || fcode0 == BUILT_IN_POW10
+ || fcode0 == BUILT_IN_POW10F
+ || fcode0 == BUILT_IN_POW10L))
{
tree expfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
tree arg = build (PLUS_EXPR, type,
if (flag_unsafe_math_optimizations)
{
enum built_in_function fcode = builtin_mathfn_code (arg1);
- /* Optimize x/exp(y) into x*exp(-y). */
+ /* Optimize x/expN(y) into x*expN(-y). */
if (fcode == BUILT_IN_EXP
|| fcode == BUILT_IN_EXPF
- || fcode == BUILT_IN_EXPL)
+ || fcode == BUILT_IN_EXPL
+ || fcode == BUILT_IN_EXP2
+ || fcode == BUILT_IN_EXP2F
+ || fcode == BUILT_IN_EXP2L
+ || fcode == BUILT_IN_EXP10
+ || fcode == BUILT_IN_EXP10F
+ || fcode == BUILT_IN_EXP10L
+ || fcode == BUILT_IN_POW10
+ || fcode == BUILT_IN_POW10F
+ || fcode == BUILT_IN_POW10L)
{
tree expfn = TREE_OPERAND (TREE_OPERAND (arg1, 0), 0);
tree arg = build1 (NEGATE_EXPR, type,
RROTATE_EXPR by a new constant. */
if (code == LROTATE_EXPR && TREE_CODE (arg1) == INTEGER_CST)
{
- if (t == orig_t)
- t = copy_node (t);
- TREE_SET_CODE (t, RROTATE_EXPR);
- code = RROTATE_EXPR;
- TREE_OPERAND (t, 1) = arg1
- = const_binop
- (MINUS_EXPR,
- convert (TREE_TYPE (arg1),
- build_int_2 (GET_MODE_BITSIZE (TYPE_MODE (type)), 0)),
- arg1, 0);
- if (tree_int_cst_sgn (arg1) < 0)
- return t;
+ tree tem = build_int_2 (GET_MODE_BITSIZE (TYPE_MODE (type)), 0);
+ tem = convert (TREE_TYPE (arg1), tem);
+ tem = const_binop (MINUS_EXPR, tem, arg1, 0);
+ return fold (build (RROTATE_EXPR, type, arg0, tem));
}
/* If we have a rotate of a bit operation with the rotate count and
case LE_EXPR:
case GE_EXPR:
/* If one arg is a real or integer constant, put it last. */
- if ((TREE_CODE (arg0) == INTEGER_CST
- && TREE_CODE (arg1) != INTEGER_CST)
- || (TREE_CODE (arg0) == REAL_CST
- && TREE_CODE (arg0) != REAL_CST))
- {
- if (t == orig_t)
- t = copy_node (t);
- TREE_OPERAND (t, 0) = arg1;
- TREE_OPERAND (t, 1) = arg0;
- arg0 = TREE_OPERAND (t, 0);
- arg1 = TREE_OPERAND (t, 1);
- code = swap_tree_comparison (code);
- TREE_SET_CODE (t, code);
- }
+ if (tree_swap_operands_p (arg0, arg1))
+ return fold (build (swap_tree_comparison (code), type, arg1, arg0));
if (FLOAT_TYPE_P (TREE_TYPE (arg0)))
{
switch (code)
{
case GE_EXPR:
- code = GT_EXPR;
arg1 = const_binop (MINUS_EXPR, arg1, integer_one_node, 0);
- t = build (code, type, TREE_OPERAND (t, 0), arg1);
- break;
+ return fold (build (GT_EXPR, type, arg0, arg1));
case LT_EXPR:
- code = LE_EXPR;
arg1 = const_binop (MINUS_EXPR, arg1, integer_one_node, 0);
- t = build (code, type, TREE_OPERAND (t, 0), arg1);
- break;
+ return fold (build (LE_EXPR, type, arg0, arg1));
default:
break;
convert (type, integer_zero_node),
arg0);
case GE_EXPR:
- code = EQ_EXPR;
- if (t == orig_t)
- t = copy_node (t);
- TREE_SET_CODE (t, EQ_EXPR);
- break;
+ return fold (build (EQ_EXPR, type, arg0, arg1));
+
case LE_EXPR:
return omit_one_operand (type,
convert (type, integer_one_node),
arg0);
case LT_EXPR:
- code = NE_EXPR;
- if (t == orig_t)
- t = copy_node (t);
- TREE_SET_CODE (t, NE_EXPR);
- break;
+ return fold (build (NE_EXPR, type, arg0, arg1));
/* The GE_EXPR and LT_EXPR cases above are not normally
- reached because of previous transformations. */
+ reached because of previous transformations. */
default:
break;
switch (code)
{
case GT_EXPR:
- code = EQ_EXPR;
arg1 = const_binop (PLUS_EXPR, arg1, integer_one_node, 0);
- t = build (code, type, TREE_OPERAND (t, 0), arg1);
- break;
+ return fold (build (EQ_EXPR, type, arg0, arg1));
case LE_EXPR:
- code = NE_EXPR;
arg1 = const_binop (PLUS_EXPR, arg1, integer_one_node, 0);
- t = build (code, type, TREE_OPERAND (t, 0), arg1);
- break;
+ return fold (build (NE_EXPR, type, arg0, arg1));
default:
break;
}
convert (type, integer_zero_node),
arg0);
case LE_EXPR:
- code = EQ_EXPR;
- if (t == orig_t)
- t = copy_node (t);
- TREE_SET_CODE (t, EQ_EXPR);
- break;
+ return fold (build (EQ_EXPR, type, arg0, arg1));
case GE_EXPR:
return omit_one_operand (type,
convert (type, integer_one_node),
arg0);
case GT_EXPR:
- code = NE_EXPR;
- if (t == orig_t)
- t = copy_node (t);
- TREE_SET_CODE (t, NE_EXPR);
- break;
+ return fold (build (NE_EXPR, type, arg0, arg1));
default:
break;
switch (code)
{
case GE_EXPR:
- code = NE_EXPR;
arg1 = const_binop (MINUS_EXPR, arg1, integer_one_node, 0);
- t = build (code, type, TREE_OPERAND (t, 0), arg1);
- break;
+ return fold (build (NE_EXPR, type, arg0, arg1));
case LT_EXPR:
- code = EQ_EXPR;
arg1 = const_binop (MINUS_EXPR, arg1, integer_one_node, 0);
- t = build (code, type, TREE_OPERAND (t, 0), arg1);
- break;
+ return fold (build (EQ_EXPR, type, arg0, arg1));
default:
break;
}
switch (code)
{
case EQ_EXPR:
+ if (! FLOAT_TYPE_P (TREE_TYPE (arg0))
+ || ! HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0))))
+ return constant_boolean_node (1, type);
+ break;
+
case GE_EXPR:
case LE_EXPR:
if (! FLOAT_TYPE_P (TREE_TYPE (arg0))
|| ! HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0))))
return constant_boolean_node (1, type);
- code = EQ_EXPR;
- if (t == orig_t)
- t = copy_node (t);
- TREE_SET_CODE (t, code);
- break;
+ return fold (build (EQ_EXPR, type, arg0, arg1));
case NE_EXPR:
/* For NE, we can only do this simplification if integer
else if (operand_equal_p (arg1, TREE_OPERAND (expr, 2), 0))
return pedantic_omit_one_operand (type, arg1, arg0);
- /* If the second operand is zero, invert the comparison and swap
- the second and third operands. Likewise if the second operand
- is constant and the third is not or if the third operand is
- equivalent to the first operand of the comparison. */
-
- if (integer_zerop (arg1)
- || (TREE_CONSTANT (arg1) && ! TREE_CONSTANT (TREE_OPERAND (t, 2)))
- || (TREE_CODE_CLASS (TREE_CODE (arg0)) == '<'
- && operand_equal_for_comparison_p (TREE_OPERAND (arg0, 0),
- TREE_OPERAND (t, 2),
- TREE_OPERAND (arg0, 1))))
- {
- /* See if this can be inverted. If it can't, possibly because
- it was a floating-point inequality comparison, don't do
- anything. */
- tem = invert_truthvalue (arg0);
-
- if (TREE_CODE (tem) != TRUTH_NOT_EXPR)
- {
- t = build (code, type, tem,
- TREE_OPERAND (t, 2), TREE_OPERAND (t, 1));
- arg0 = tem;
- /* arg1 should be the first argument of the new T. */
- arg1 = TREE_OPERAND (t, 1);
- STRIP_NOPS (arg1);
- }
- }
-
/* If we have A op B ? A : C, we may be able to convert this to a
simpler expression, depending on the operation and the values
of B and C. Signed zeros prevent all of these transformations,
case EQ_EXPR:
/* We can replace A with C1 in this case. */
arg1 = convert (type, TREE_OPERAND (arg0, 1));
- t = build (code, type, TREE_OPERAND (t, 0), arg1,
- TREE_OPERAND (t, 2));
- break;
+ return fold (build (code, type, TREE_OPERAND (t, 0), arg1,
+ TREE_OPERAND (t, 2)));
case LT_EXPR:
/* If C1 is C2 + 1, this is min(A, C2). */
/* If the second operand is simpler than the third, swap them
since that produces better jump optimization results. */
- if ((TREE_CONSTANT (arg1) || DECL_P (arg1)
- || TREE_CODE (arg1) == SAVE_EXPR)
- && ! (TREE_CONSTANT (TREE_OPERAND (t, 2))
- || DECL_P (TREE_OPERAND (t, 2))
- || TREE_CODE (TREE_OPERAND (t, 2)) == SAVE_EXPR))
+ if (tree_swap_operands_p (TREE_OPERAND (t, 1), TREE_OPERAND (t, 2)))
{
/* See if this can be inverted. If it can't, possibly because
it was a floating-point inequality comparison, don't do
tem = invert_truthvalue (arg0);
if (TREE_CODE (tem) != TRUTH_NOT_EXPR)
- {
- t = build (code, type, tem,
- TREE_OPERAND (t, 2), TREE_OPERAND (t, 1));
- arg0 = tem;
- /* arg1 should be the first argument of the new T. */
- arg1 = TREE_OPERAND (t, 1);
- STRIP_NOPS (arg1);
- }
+ return fold (build (code, type, tem,
+ TREE_OPERAND (t, 2), TREE_OPERAND (t, 1)));
}
/* Convert A ? 1 : 0 to simply A. */
switch (TREE_CODE (t))
{
case ABS_EXPR:
- case FFS_EXPR:
- case POPCOUNT_EXPR:
- case PARITY_EXPR:
return 1;
- case CLZ_EXPR:
- case CTZ_EXPR:
- /* These are undefined at zero. This is true even if
- C[LT]Z_DEFINED_VALUE_AT_ZERO is set, since what we're
- computing here is a user-visible property. */
- return 0;
-
case INTEGER_CST:
return tree_int_cst_sgn (t) >= 0;
case BUILT_IN_EXP:
case BUILT_IN_EXPF:
case BUILT_IN_EXPL:
+ case BUILT_IN_EXP2:
+ case BUILT_IN_EXP2F:
+ case BUILT_IN_EXP2L:
+ case BUILT_IN_EXP10:
+ case BUILT_IN_EXP10F:
+ case BUILT_IN_EXP10L:
case BUILT_IN_FABS:
case BUILT_IN_FABSF:
case BUILT_IN_FABSL:
+ case BUILT_IN_FFS:
+ case BUILT_IN_FFSL:
+ case BUILT_IN_FFSLL:
+ case BUILT_IN_PARITY:
+ case BUILT_IN_PARITYL:
+ case BUILT_IN_PARITYLL:
+ case BUILT_IN_POPCOUNT:
+ case BUILT_IN_POPCOUNTL:
+ case BUILT_IN_POPCOUNTLL:
+ case BUILT_IN_POW10:
+ case BUILT_IN_POW10F:
+ case BUILT_IN_POW10L:
case BUILT_IN_SQRT:
case BUILT_IN_SQRTF:
case BUILT_IN_SQRTL: