/* Fold a constant sub-tree into a single node for C-compiler
- Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 2002,
- 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+ Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+ 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
This file is part of GCC.
#include "config.h"
#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
#include "flags.h"
#include "tree.h"
#include "real.h"
static void decode PARAMS ((HOST_WIDE_INT *,
unsigned HOST_WIDE_INT *,
HOST_WIDE_INT *));
+static bool negate_expr_p PARAMS ((tree));
static tree negate_expr PARAMS ((tree));
static tree split_tree PARAMS ((tree, enum tree_code, tree *, tree *,
tree *, int));
static int operand_equal_for_comparison_p PARAMS ((tree, tree, tree));
static int twoval_comparison_p PARAMS ((tree, tree *, tree *, int *));
static tree eval_subst PARAMS ((tree, tree, tree, tree, tree));
-static tree omit_one_operand PARAMS ((tree, tree, tree));
static tree pedantic_omit_one_operand PARAMS ((tree, tree, tree));
static tree distribute_bit_expr PARAMS ((enum tree_code, tree, tree, tree));
static tree make_bit_field_ref PARAMS ((tree, tree, int, int, int));
static tree fold_truthop PARAMS ((enum tree_code, tree, tree, tree));
static tree optimize_minmax_comparison PARAMS ((tree));
static tree extract_muldiv PARAMS ((tree, tree, enum tree_code, tree));
+static tree extract_muldiv_1 PARAMS ((tree, tree, enum tree_code, tree));
static tree strip_compound_expr PARAMS ((tree, tree));
static int multiple_of_p PARAMS ((tree, tree, tree));
static tree constant_boolean_node PARAMS ((int, tree));
static tree fold_binary_op_with_conditional_arg
PARAMS ((enum tree_code, tree, tree, tree, int));
static bool fold_real_zero_addition_p PARAMS ((tree, tree, int));
+static tree fold_mathfn_compare PARAMS ((enum built_in_function,
+ enum tree_code, tree, tree, tree));
+static tree fold_inf_compare PARAMS ((enum tree_code, tree, tree, tree));
/* The following constants represent a bit based encoding of GCC's
comparison operators. This encoding simplifies transformations
return overflow;
}
\f
+/* Determine whether an expression T can be cheaply negated using
+ the function negate_expr. */
+
+static bool
+negate_expr_p (t)
+ tree t;
+{
+ unsigned HOST_WIDE_INT val;
+ unsigned int prec;
+ tree type;
+
+ if (t == 0)
+ return false;
+
+ type = TREE_TYPE (t);
+
+ STRIP_SIGN_NOPS (t);
+ switch (TREE_CODE (t))
+ {
+ case INTEGER_CST:
+ if (TREE_UNSIGNED (type))
+ return false;
+
+ /* Check that -CST will not overflow type. */
+ prec = TYPE_PRECISION (type);
+ if (prec > HOST_BITS_PER_WIDE_INT)
+ {
+ if (TREE_INT_CST_LOW (t) != 0)
+ return true;
+ prec -= HOST_BITS_PER_WIDE_INT;
+ val = TREE_INT_CST_HIGH (t);
+ }
+ else
+ val = TREE_INT_CST_LOW (t);
+ if (prec < HOST_BITS_PER_WIDE_INT)
+ val &= ((unsigned HOST_WIDE_INT) 1 << prec) - 1;
+ return val != ((unsigned HOST_WIDE_INT) 1 << (prec - 1));
+
+ case REAL_CST:
+ case NEGATE_EXPR:
+ case MINUS_EXPR:
+ return true;
+
+ default:
+ break;
+ }
+ return false;
+}
+
/* Given T, an expression, return the negation of T. Allow for T to be
null, in which case return null. */
if (size_htab == 0)
{
- size_htab = htab_create (1024, size_htab_hash, size_htab_eq, NULL);
+ size_htab = htab_create_ggc (1024, size_htab_hash, size_htab_eq, NULL);
new_const = make_node (INTEGER_CST);
}
If OMITTED has side effects, we must evaluate it. Otherwise, just do
the conversion of RESULT to TYPE. */
-static tree
+tree
omit_one_operand (type, result, omitted)
tree type, result, omitted;
{
enum tree_code code;
tree wide_type;
{
+ /* To avoid exponential search depth, refuse to allow recursion past
+ three levels. Beyond that (1) it's highly unlikely that we'll find
+ something interesting and (2) we've probably processed it before
+ when we built the inner expression. */
+
+ static int depth;
+ tree ret;
+
+ if (depth > 3)
+ return NULL;
+
+ depth++;
+ ret = extract_muldiv_1 (t, c, code, wide_type);
+ depth--;
+
+ return ret;
+}
+
+static tree
+extract_muldiv_1 (t, c, code, wide_type)
+ tree t;
+ tree c;
+ enum tree_code code;
+ tree wide_type;
+{
tree type = TREE_TYPE (t);
enum tree_code tcode = TREE_CODE (t);
tree ctype = (wide_type != 0 && (GET_MODE_SIZE (TYPE_MODE (wide_type))
/* ... or its type is larger than ctype,
then we cannot pass through this truncation. */
|| (GET_MODE_SIZE (TYPE_MODE (ctype))
- < GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op0))))))
+ < GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op0))))
+ /* ... or signedness changes for division or modulus,
+ then we cannot pass through this conversion. */
+ || (code != MULT_EXPR
+ && (TREE_UNSIGNED (ctype)
+ != TREE_UNSIGNED (TREE_TYPE (op0))))))
break;
/* Pass the constant down and see if we can make a simplification. If
if (!real_zerop (addend))
return false;
+ /* Don't allow the fold with -fsignaling-nans. */
+ if (HONOR_SNANS (TYPE_MODE (type)))
+ return false;
+
/* Allow the fold if zeros aren't signed, or their sign isn't important. */
if (!HONOR_SIGNED_ZEROS (TYPE_MODE (type)))
return true;
return negate && !HONOR_SIGN_DEPENDENT_ROUNDING (TYPE_MODE (type));
}
+/* Subroutine of fold() that checks comparisons of built-in math
+ functions against real constants.
+
+ FCODE is the DECL_FUNCTION_CODE of the built-in, CODE is the comparison
+ operator: EQ_EXPR, NE_EXPR, GT_EXPR, LT_EXPR, GE_EXPR or LE_EXPR. TYPE
+ is the type of the result and ARG0 and ARG1 are the operands of the
+ comparison. ARG1 must be a TREE_REAL_CST.
+
+ The function returns the constant folded tree if a simplification
+ can be made, and NULL_TREE otherwise. */
+
+static tree
+fold_mathfn_compare (fcode, code, type, arg0, arg1)
+ enum built_in_function fcode;
+ enum tree_code code;
+ tree type, arg0, arg1;
+{
+ REAL_VALUE_TYPE c;
+
+ if (fcode == BUILT_IN_SQRT
+ || fcode == BUILT_IN_SQRTF
+ || fcode == BUILT_IN_SQRTL)
+ {
+ tree arg = TREE_VALUE (TREE_OPERAND (arg0, 1));
+ enum machine_mode mode = TYPE_MODE (TREE_TYPE (arg0));
+
+ c = TREE_REAL_CST (arg1);
+ if (REAL_VALUE_NEGATIVE (c))
+ {
+ /* sqrt(x) < y is always false, if y is negative. */
+ if (code == EQ_EXPR || code == LT_EXPR || code == LE_EXPR)
+ return omit_one_operand (type,
+ convert (type, integer_zero_node),
+ arg);
+
+ /* sqrt(x) > y is always true, if y is negative and we
+ don't care about NaNs, i.e. negative values of x. */
+ if (code == NE_EXPR || !HONOR_NANS (mode))
+ return omit_one_operand (type,
+ convert (type, integer_one_node),
+ arg);
+
+ /* sqrt(x) > y is the same as x >= 0, if y is negative. */
+ return fold (build (GE_EXPR, type, arg,
+ build_real (TREE_TYPE (arg), dconst0)));
+ }
+ else if (code == GT_EXPR || code == GE_EXPR)
+ {
+ REAL_VALUE_TYPE c2;
+
+ REAL_ARITHMETIC (c2, MULT_EXPR, c, c);
+ real_convert (&c2, mode, &c2);
+
+ if (REAL_VALUE_ISINF (c2))
+ {
+ /* sqrt(x) > y is x == +Inf, when y is very large. */
+ if (HONOR_INFINITIES (mode))
+ return fold (build (EQ_EXPR, type, arg,
+ build_real (TREE_TYPE (arg), c2)));
+
+ /* sqrt(x) > y is always false, when y is very large
+ and we don't care about infinities. */
+ return omit_one_operand (type,
+ convert (type, integer_zero_node),
+ arg);
+ }
+
+ /* sqrt(x) > c is the same as x > c*c. */
+ return fold (build (code, type, arg,
+ build_real (TREE_TYPE (arg), c2)));
+ }
+ else if (code == LT_EXPR || code == LE_EXPR)
+ {
+ REAL_VALUE_TYPE c2;
+
+ REAL_ARITHMETIC (c2, MULT_EXPR, c, c);
+ real_convert (&c2, mode, &c2);
+
+ if (REAL_VALUE_ISINF (c2))
+ {
+ /* sqrt(x) < y is always true, when y is a very large
+ value and we don't care about NaNs or Infinities. */
+ if (! HONOR_NANS (mode) && ! HONOR_INFINITIES (mode))
+ return omit_one_operand (type,
+ convert (type, integer_one_node),
+ arg);
+
+ /* sqrt(x) < y is x != +Inf when y is very large and we
+ don't care about NaNs. */
+ if (! HONOR_NANS (mode))
+ return fold (build (NE_EXPR, type, arg,
+ build_real (TREE_TYPE (arg), c2)));
+
+ /* sqrt(x) < y is x >= 0 when y is very large and we
+ don't care about Infinities. */
+ if (! HONOR_INFINITIES (mode))
+ return fold (build (GE_EXPR, type, arg,
+ build_real (TREE_TYPE (arg), dconst0)));
+
+ /* sqrt(x) < y is x >= 0 && x != +Inf, when y is large. */
+ if ((*lang_hooks.decls.global_bindings_p) () != 0
+ || contains_placeholder_p (arg))
+ return NULL_TREE;
+
+ arg = save_expr (arg);
+ return fold (build (TRUTH_ANDIF_EXPR, type,
+ fold (build (GE_EXPR, type, arg,
+ build_real (TREE_TYPE (arg),
+ dconst0))),
+ fold (build (NE_EXPR, type, arg,
+ build_real (TREE_TYPE (arg),
+ c2)))));
+ }
+
+ /* sqrt(x) < c is the same as x < c*c, if we ignore NaNs. */
+ if (! HONOR_NANS (mode))
+ return fold (build (code, type, arg,
+ build_real (TREE_TYPE (arg), c2)));
+
+ /* sqrt(x) < c is the same as x >= 0 && x < c*c. */
+ if ((*lang_hooks.decls.global_bindings_p) () == 0
+ && ! contains_placeholder_p (arg))
+ {
+ arg = save_expr (arg);
+ return fold (build (TRUTH_ANDIF_EXPR, type,
+ fold (build (GE_EXPR, type, arg,
+ build_real (TREE_TYPE (arg),
+ dconst0))),
+ fold (build (code, type, arg,
+ build_real (TREE_TYPE (arg),
+ c2)))));
+ }
+ }
+ }
+
+ return NULL_TREE;
+}
+
+/* Subroutine of fold() that optimizes comparisons against Infinities,
+ either +Inf or -Inf.
+
+ CODE is the comparison operator: EQ_EXPR, NE_EXPR, GT_EXPR, LT_EXPR,
+ GE_EXPR or LE_EXPR. TYPE is the type of the result and ARG0 and ARG1
+ are the operands of the comparison. ARG1 must be a TREE_REAL_CST.
+
+ The function returns the constant folded tree if a simplification
+ can be made, and NULL_TREE otherwise. */
+
+static tree
+fold_inf_compare (code, type, arg0, arg1)
+ enum tree_code code;
+ tree type, arg0, arg1;
+{
+ /* For negative infinity swap the sense of the comparison. */
+ if (REAL_VALUE_NEGATIVE (TREE_REAL_CST (arg1)))
+ code = swap_tree_comparison (code);
+
+ switch (code)
+ {
+ case GT_EXPR:
+ /* x > +Inf is always false, if with ignore sNANs. */
+ if (HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg0))))
+ return NULL_TREE;
+ return omit_one_operand (type,
+ convert (type, integer_zero_node),
+ arg0);
+
+ case LE_EXPR:
+ /* x <= +Inf is always true, if we don't case about NaNs. */
+ if (! HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0))))
+ return omit_one_operand (type,
+ convert (type, integer_one_node),
+ arg0);
+
+ /* x <= +Inf is the same as x == x, i.e. isfinite(x). */
+ if ((*lang_hooks.decls.global_bindings_p) () == 0
+ && ! contains_placeholder_p (arg0))
+ {
+ arg0 = save_expr (arg0);
+ return fold (build (EQ_EXPR, type, arg0, arg0));
+ }
+ break;
+
+ case EQ_EXPR: /* ??? x == +Inf is x > DBL_MAX */
+ case GE_EXPR: /* ??? x >= +Inf is x > DBL_MAX */
+ case LT_EXPR: /* ??? x < +Inf is x <= DBL_MAX */
+ case NE_EXPR: /* ??? x != +Inf is !(x > DBL_MAX) */
+
+ default:
+ break;
+ }
+
+ return NULL_TREE;
+}
/* Perform constant folding and related simplification of EXPR.
The related simplifications include x*1 => x, x*0 => 0, etc.,
fold (build1 (code, type, integer_one_node)),
fold (build1 (code, type, integer_zero_node))));
}
+ else if (TREE_CODE_CLASS (code) == '<'
+ && TREE_CODE (arg0) == COMPOUND_EXPR)
+ return build (COMPOUND_EXPR, type, TREE_OPERAND (arg0, 0),
+ fold (build (code, type, TREE_OPERAND (arg0, 1), arg1)));
+ else if (TREE_CODE_CLASS (code) == '<'
+ && TREE_CODE (arg1) == COMPOUND_EXPR)
+ return build (COMPOUND_EXPR, type, TREE_OPERAND (arg1, 0),
+ fold (build (code, type, arg0, TREE_OPERAND (arg1, 1))));
else if (TREE_CODE_CLASS (code) == '2'
|| TREE_CODE_CLASS (code) == '<')
{
fold_binary_op_with_conditional_arg (code, type, arg0, arg1,
/*cond_first_p=*/1);
}
- else if (TREE_CODE_CLASS (code) == '<'
- && TREE_CODE (arg0) == COMPOUND_EXPR)
- return build (COMPOUND_EXPR, type, TREE_OPERAND (arg0, 0),
- fold (build (code, type, TREE_OPERAND (arg0, 1), arg1)));
- else if (TREE_CODE_CLASS (code) == '<'
- && TREE_CODE (arg1) == COMPOUND_EXPR)
- return build (COMPOUND_EXPR, type, TREE_OPERAND (arg1, 0),
- fold (build (code, type, arg0, TREE_OPERAND (arg1, 1))));
switch (code)
{
}
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
}
else if (TREE_CODE (arg0) == ABS_EXPR || TREE_CODE (arg0) == NEGATE_EXPR)
return build1 (ABS_EXPR, type, TREE_OPERAND (arg0, 0));
+ /* Convert fabs((double)float) into (double)fabsf(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 (ABS_EXPR, TREE_TYPE (targ0), targ0));
+
+ }
+ else
+ {
+ /* fabs(sqrt(x)) = sqrt(x) and fabs(exp(x)) = exp(x). */
+ enum built_in_function fcode = builtin_mathfn_code (arg0);
+ if (fcode == BUILT_IN_SQRT
+ || fcode == BUILT_IN_SQRTF
+ || fcode == BUILT_IN_SQRTL
+ || fcode == BUILT_IN_EXP
+ || fcode == BUILT_IN_EXPF
+ || fcode == BUILT_IN_EXPL)
+ t = arg0;
+ }
return t;
case CONJ_EXPR:
/* A - (-B) -> A + B */
if (TREE_CODE (arg1) == NEGATE_EXPR)
return fold (build (PLUS_EXPR, type, arg0, TREE_OPERAND (arg1, 0)));
- /* (-A) - CST -> (-CST) - A for floating point (what about ints ?) */
- if (TREE_CODE (arg0) == NEGATE_EXPR && TREE_CODE (arg1) == REAL_CST)
- return
- fold (build (MINUS_EXPR, type,
- build_real (TREE_TYPE (arg1),
- REAL_VALUE_NEGATE (TREE_REAL_CST (arg1))),
- TREE_OPERAND (arg0, 0)));
+ /* (-A) - B -> (-B) - A where B is easily negated and we can swap. */
+ if (TREE_CODE (arg0) == NEGATE_EXPR
+ && FLOAT_TYPE_P (type)
+ && negate_expr_p (arg1)
+ && (! TREE_SIDE_EFFECTS (arg0) || TREE_CONSTANT (arg1))
+ && (! TREE_SIDE_EFFECTS (arg1) || TREE_CONSTANT (arg0)))
+ return fold (build (MINUS_EXPR, type, negate_expr (arg1),
+ TREE_OPERAND (arg0, 0)));
if (! FLOAT_TYPE_P (type))
{
TREE_OPERAND (arg0, 0),
TREE_OPERAND (arg1, 0))),
TREE_OPERAND (arg0, 1)));
+
+ /* Fold A - (A & B) into ~B & A. */
+ if (!TREE_SIDE_EFFECTS (arg0)
+ && TREE_CODE (arg1) == BIT_AND_EXPR)
+ {
+ if (operand_equal_p (arg0, TREE_OPERAND (arg1, 1), 0))
+ return fold (build (BIT_AND_EXPR, type,
+ fold (build1 (BIT_NOT_EXPR, type,
+ TREE_OPERAND (arg1, 0))),
+ arg0));
+ if (operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0))
+ return fold (build (BIT_AND_EXPR, type,
+ fold (build1 (BIT_NOT_EXPR, type,
+ TREE_OPERAND (arg1, 1))),
+ arg0));
+ }
}
/* See if ARG1 is zero and X - ARG1 reduces to X. */
&& ! contains_placeholder_p (arg0))
{
tree arg = save_expr (arg0);
- return build (PLUS_EXPR, type, arg, arg);
+ return fold (build (PLUS_EXPR, type, arg, arg));
+ }
+
+ if (flag_unsafe_math_optimizations)
+ {
+ enum built_in_function fcode0 = builtin_mathfn_code (arg0);
+ enum built_in_function fcode1 = builtin_mathfn_code (arg1);
+
+ /* Optimizations of sqrt(...)*sqrt(...). */
+ if ((fcode0 == BUILT_IN_SQRT && fcode1 == BUILT_IN_SQRT)
+ || (fcode0 == BUILT_IN_SQRTF && fcode1 == BUILT_IN_SQRTF)
+ || (fcode0 == BUILT_IN_SQRTL && fcode1 == BUILT_IN_SQRTL))
+ {
+ tree sqrtfn, arg, arglist;
+ tree arg00 = TREE_VALUE (TREE_OPERAND (arg0, 1));
+ tree arg10 = TREE_VALUE (TREE_OPERAND (arg1, 1));
+
+ /* Optimize sqrt(x)*sqrt(x) as x. */
+ if (operand_equal_p (arg00, arg10, 0)
+ && ! HONOR_SNANS (TYPE_MODE (type)))
+ return arg00;
+
+ /* Optimize sqrt(x)*sqrt(y) as sqrt(x*y). */
+ sqrtfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
+ arg = fold (build (MULT_EXPR, type, arg00, arg10));
+ arglist = build_tree_list (NULL_TREE, arg);
+ 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))
+ {
+ tree expfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
+ tree arg = build (PLUS_EXPR, type,
+ TREE_VALUE (TREE_OPERAND (arg0, 1)),
+ TREE_VALUE (TREE_OPERAND (arg1, 1)));
+ tree arglist = build_tree_list (NULL_TREE, fold (arg));
+ return build_function_call_expr (expfn, arglist);
+ }
+
+ /* Optimizations of pow(...)*pow(...). */
+ if ((fcode0 == BUILT_IN_POW && fcode1 == BUILT_IN_POW)
+ || (fcode0 == BUILT_IN_POWF && fcode1 == BUILT_IN_POWF)
+ || (fcode0 == BUILT_IN_POWL && fcode1 == BUILT_IN_POWL))
+ {
+ tree arg00 = TREE_VALUE (TREE_OPERAND (arg0, 1));
+ tree arg01 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg0,
+ 1)));
+ tree arg10 = TREE_VALUE (TREE_OPERAND (arg1, 1));
+ tree arg11 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg1,
+ 1)));
+
+ /* Optimize pow(x,y)*pow(z,y) as pow(x*z,y). */
+ if (operand_equal_p (arg01, arg11, 0))
+ {
+ tree powfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
+ tree arg = build (MULT_EXPR, type, arg00, arg10);
+ tree arglist = tree_cons (NULL_TREE, fold (arg),
+ build_tree_list (NULL_TREE,
+ arg01));
+ return build_function_call_expr (powfn, arglist);
+ }
+
+ /* Optimize pow(x,y)*pow(x,z) as pow(x,y+z). */
+ if (operand_equal_p (arg00, arg10, 0))
+ {
+ tree powfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
+ tree arg = fold (build (PLUS_EXPR, type, arg01, arg11));
+ tree arglist = tree_cons (NULL_TREE, arg00,
+ build_tree_list (NULL_TREE,
+ arg));
+ return build_function_call_expr (powfn, arglist);
+ }
+ }
}
}
goto associate;
TREE_OPERAND (arg1, 0)),
TREE_OPERAND (arg1, 1)));
}
+
+ if (flag_unsafe_math_optimizations)
+ {
+ enum built_in_function fcode = builtin_mathfn_code (arg1);
+ /* Optimize x/exp(y) into x*exp(-y). */
+ if (fcode == BUILT_IN_EXP
+ || fcode == BUILT_IN_EXPF
+ || fcode == BUILT_IN_EXPL)
+ {
+ tree expfn = TREE_OPERAND (TREE_OPERAND (arg1, 0), 0);
+ tree arg = build1 (NEGATE_EXPR, type,
+ TREE_VALUE (TREE_OPERAND (arg1, 1)));
+ tree arglist = build_tree_list (NULL_TREE, fold (arg));
+ arg1 = build_function_call_expr (expfn, arglist);
+ return fold (build (MULT_EXPR, type, arg0, arg1));
+ }
+
+ /* Optimize x/pow(y,z) into x*pow(y,-z). */
+ if (fcode == BUILT_IN_POW
+ || fcode == BUILT_IN_POWF
+ || fcode == BUILT_IN_POWL)
+ {
+ tree powfn = TREE_OPERAND (TREE_OPERAND (arg1, 0), 0);
+ tree arg10 = TREE_VALUE (TREE_OPERAND (arg1, 1));
+ tree arg11 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg1, 1)));
+ tree neg11 = fold (build1 (NEGATE_EXPR, type, arg11));
+ tree arglist = tree_cons(NULL_TREE, arg10,
+ build_tree_list (NULL_TREE, neg11));
+ arg1 = build_function_call_expr (powfn, arglist);
+ return fold (build (MULT_EXPR, type, arg0, arg1));
+ }
+ }
goto binary;
case TRUNC_DIV_EXPR:
goto binary;
- case LSHIFT_EXPR:
- case RSHIFT_EXPR:
case LROTATE_EXPR:
case RROTATE_EXPR:
+ if (integer_all_onesp (arg0))
+ return omit_one_operand (type, arg0, arg1);
+ goto shift;
+
+ case RSHIFT_EXPR:
+ /* Optimize -1 >> x for arithmetic right shifts. */
+ if (integer_all_onesp (arg0) && ! TREE_UNSIGNED (type))
+ return omit_one_operand (type, arg0, arg1);
+ /* ... fall through ... */
+
+ case LSHIFT_EXPR:
+ shift:
if (integer_zerop (arg1))
return non_lvalue (convert (type, arg0));
+ if (integer_zerop (arg0))
+ return omit_one_operand (type, arg0, arg1);
+
/* Since negative shift count is not well-defined,
don't try to compute it in the compiler. */
if (TREE_CODE (arg1) == INTEGER_CST && tree_int_cst_sgn (arg1) < 0)
if (FLOAT_TYPE_P (TREE_TYPE (arg0)))
{
+ tree targ0 = strip_float_extensions (arg0);
+ tree targ1 = strip_float_extensions (arg1);
+ tree newtype = TREE_TYPE (targ0);
+
+ if (TYPE_PRECISION (TREE_TYPE (targ1)) > TYPE_PRECISION (newtype))
+ newtype = TREE_TYPE (targ1);
+
+ /* Fold (double)float1 CMP (double)float2 into float1 CMP float2. */
+ if (TYPE_PRECISION (newtype) < TYPE_PRECISION (TREE_TYPE (arg0)))
+ return fold (build (code, type, convert (newtype, targ0),
+ convert (newtype, targ1)));
+
/* (-a) CMP (-b) -> b CMP a */
if (TREE_CODE (arg0) == NEGATE_EXPR
&& TREE_CODE (arg1) == NEGATE_EXPR)
return fold (build (code, type, TREE_OPERAND (arg1, 0),
TREE_OPERAND (arg0, 0)));
- /* (-a) CMP CST -> a swap(CMP) (-CST) */
- if (TREE_CODE (arg0) == NEGATE_EXPR && TREE_CODE (arg1) == REAL_CST)
- return
- fold (build
- (swap_tree_comparison (code), type,
- TREE_OPERAND (arg0, 0),
- build_real (TREE_TYPE (arg1),
- REAL_VALUE_NEGATE (TREE_REAL_CST (arg1)))));
- /* IEEE doesn't distinguish +0 and -0 in comparisons. */
- /* a CMP (-0) -> a CMP 0 */
- if (TREE_CODE (arg1) == REAL_CST
- && REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (arg1)))
- return fold (build (code, type, arg0,
- build_real (TREE_TYPE (arg1), dconst0)));
+
+ if (TREE_CODE (arg1) == REAL_CST)
+ {
+ REAL_VALUE_TYPE cst;
+ cst = TREE_REAL_CST (arg1);
+
+ /* (-a) CMP CST -> a swap(CMP) (-CST) */
+ if (TREE_CODE (arg0) == NEGATE_EXPR)
+ return
+ fold (build (swap_tree_comparison (code), type,
+ TREE_OPERAND (arg0, 0),
+ build_real (TREE_TYPE (arg1),
+ REAL_VALUE_NEGATE (cst))));
+
+ /* IEEE doesn't distinguish +0 and -0 in comparisons. */
+ /* a CMP (-0) -> a CMP 0 */
+ if (REAL_VALUE_MINUS_ZERO (cst))
+ return fold (build (code, type, arg0,
+ build_real (TREE_TYPE (arg1), dconst0)));
+
+ /* x != NaN is always true, other ops are always false. */
+ if (REAL_VALUE_ISNAN (cst)
+ && ! HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg1))))
+ {
+ t = (code == NE_EXPR) ? integer_one_node : integer_zero_node;
+ return omit_one_operand (type, convert (type, t), arg0);
+ }
+
+ /* Fold comparisons against infinity. */
+ if (REAL_VALUE_ISINF (cst))
+ {
+ tem = fold_inf_compare (code, type, arg0, arg1);
+ if (tem != NULL_TREE)
+ return tem;
+ }
+ }
/* If this is a comparison of a real constant with a PLUS_EXPR
or a MINUS_EXPR of a real constant, we can convert it into a
arg1, TREE_OPERAND (arg0, 1), 0))
&& ! TREE_CONSTANT_OVERFLOW (tem))
return fold (build (code, type, TREE_OPERAND (arg0, 0), tem));
+
+ /* Likewise, we can simplify a comparison of a real constant with
+ a MINUS_EXPR whose first operand is also a real constant, i.e.
+ (c1 - x) < c2 becomes x > c1-c2. */
+ if (flag_unsafe_math_optimizations
+ && TREE_CODE (arg1) == REAL_CST
+ && TREE_CODE (arg0) == MINUS_EXPR
+ && TREE_CODE (TREE_OPERAND (arg0, 0)) == REAL_CST
+ && 0 != (tem = const_binop (MINUS_EXPR, TREE_OPERAND (arg0, 0),
+ arg1, 0))
+ && ! TREE_CONSTANT_OVERFLOW (tem))
+ return fold (build (swap_tree_comparison (code), type,
+ TREE_OPERAND (arg0, 1), tem));
+
+ /* Fold comparisons against built-in math functions. */
+ if (TREE_CODE (arg1) == REAL_CST
+ && flag_unsafe_math_optimizations
+ && ! flag_errno_math)
+ {
+ enum built_in_function fcode = builtin_mathfn_code (arg0);
+
+ if (fcode != END_BUILTINS)
+ {
+ tem = fold_mathfn_compare (fcode, code, type, arg0, arg1);
+ if (tem != NULL_TREE)
+ return tem;
+ }
+ }
}
/* Convert foo++ == CONST into ++foo == CONST + INCR.
/* Avoid adding NOP_EXPRs in case this is an lvalue. */
if (TYPE_MAIN_VARIANT (comp_type) == TYPE_MAIN_VARIANT (type))
- comp_type = type;
+ {
+ comp_type = type;
+ comp_op0 = arg1;
+ comp_op1 = arg2;
+ }
switch (comp_code)
{
{
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 TRUNC_DIV_EXPR: