/* Fold a constant sub-tree into a single node for C-compiler
Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+ 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
This file is part of GCC.
#include "ggc.h"
#include "hashtab.h"
#include "langhooks.h"
+#include "md5.h"
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);
static tree const_binop (enum tree_code, tree, tree, int);
static hashval_t size_htab_hash (const void *);
static int size_htab_eq (const void *, const void *);
-static tree fold_convert (tree, tree);
+static tree fold_convert_const (enum tree_code, tree, tree);
static enum tree_code invert_tree_comparison (enum tree_code);
static enum tree_code swap_tree_comparison (enum tree_code);
static int comparison_to_compcode (enum tree_code);
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 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
The integer is stored into *LOW and *HI as two `HOST_WIDE_INT' pieces. */
static void
-decode (HOST_WIDE_INT *words, unsigned HOST_WIDE_INT *low, HOST_WIDE_INT *hi)
+decode (HOST_WIDE_INT *words, unsigned HOST_WIDE_INT *low,
+ HOST_WIDE_INT *hi)
{
*low = words[0] + words[1] * BASE;
*hi = words[2] + words[3] * BASE;
low = TREE_INT_CST_LOW (t);
high = TREE_INT_CST_HIGH (t);
- if (POINTER_TYPE_P (TREE_TYPE (t)))
+ if (POINTER_TYPE_P (TREE_TYPE (t))
+ || TREE_CODE (TREE_TYPE (t)) == OFFSET_TYPE)
prec = POINTER_SIZE;
else
prec = TYPE_PRECISION (TREE_TYPE (t));
The value is stored as two `HOST_WIDE_INT' pieces in *LV and *HV. */
int
-add_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1, unsigned HOST_WIDE_INT l2,
- HOST_WIDE_INT h2, unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv)
+add_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1,
+ unsigned HOST_WIDE_INT l2, HOST_WIDE_INT h2,
+ unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv)
{
unsigned HOST_WIDE_INT l;
HOST_WIDE_INT h;
The value is stored as two `HOST_WIDE_INT' pieces in *LV and *HV. */
int
-neg_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1, unsigned HOST_WIDE_INT *lv,
- HOST_WIDE_INT *hv)
+neg_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1,
+ unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv)
{
if (l1 == 0)
{
The value is stored as two `HOST_WIDE_INT' pieces in *LV and *HV. */
int
-mul_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1, unsigned HOST_WIDE_INT l2,
- HOST_WIDE_INT h2, unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv)
+mul_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1,
+ unsigned HOST_WIDE_INT l2, HOST_WIDE_INT h2,
+ unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv)
{
HOST_WIDE_INT arg1[4];
HOST_WIDE_INT arg2[4];
encode (arg1, l1, h1);
encode (arg2, l2, h2);
- memset ((char *) prod, 0, sizeof prod);
+ memset (prod, 0, sizeof prod);
for (i = 0; i < 4; i++)
{
Store the value as two `HOST_WIDE_INT' pieces in *LV and *HV. */
void
-lshift_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1, HOST_WIDE_INT count,
- unsigned int prec, unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv,
- int arith)
+lshift_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1,
+ HOST_WIDE_INT count, unsigned int prec,
+ unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv, int arith)
{
unsigned HOST_WIDE_INT signmask;
Store the value as two `HOST_WIDE_INT' pieces in *LV and *HV. */
void
-rshift_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1, HOST_WIDE_INT count,
- unsigned int prec, unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv,
+rshift_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1,
+ HOST_WIDE_INT count, unsigned int prec,
+ unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv,
int arith)
{
unsigned HOST_WIDE_INT signmask;
Store the value as two `HOST_WIDE_INT' pieces in *LV and *HV. */
void
-lrotate_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1, HOST_WIDE_INT count,
- unsigned int prec, unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv)
+lrotate_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1,
+ HOST_WIDE_INT count, unsigned int prec,
+ unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv)
{
unsigned HOST_WIDE_INT s1l, s2l;
HOST_WIDE_INT s1h, s2h;
Store the value as two `HOST_WIDE_INT' pieces in *LV and *HV. */
void
-rrotate_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1, HOST_WIDE_INT count,
- unsigned int prec, unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv)
+rrotate_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1,
+ HOST_WIDE_INT count, unsigned int prec,
+ unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv)
{
unsigned HOST_WIDE_INT s1l, s2l;
HOST_WIDE_INT s1h, s2h;
unsigned HOST_WIDE_INT lnum_orig, /* num == numerator == dividend */
HOST_WIDE_INT hnum_orig,
unsigned HOST_WIDE_INT lden_orig, /* den == denominator == divisor */
- HOST_WIDE_INT hden_orig, unsigned HOST_WIDE_INT *lquo,
+ HOST_WIDE_INT hden_orig,
+ unsigned HOST_WIDE_INT *lquo,
HOST_WIDE_INT *hquo, unsigned HOST_WIDE_INT *lrem,
HOST_WIDE_INT *hrem)
{
if (hden == 0 && lden == 0)
overflow = 1, lden = 1;
- /* calculate quotient sign and convert operands to unsigned. */
+ /* Calculate quotient sign and convert operands to unsigned. */
if (!uns)
{
if (hnum < 0)
goto finish_up;
}
- memset ((char *) quo, 0, sizeof quo);
+ memset (quo, 0, sizeof quo);
- memset ((char *) num, 0, sizeof num); /* to zero 9th element */
- memset ((char *) den, 0, sizeof den);
+ memset (num, 0, sizeof num); /* to zero 9th element */
+ memset (den, 0, sizeof den);
encode (num, lnum, hnum);
encode (den, lden, hden);
decode (quo, lquo, hquo);
finish_up:
- /* if result is negative, make it so. */
+ /* If result is negative, make it so. */
if (quo_neg)
neg_double (*lquo, *hquo, lquo, hquo);
abort ();
}
- /* compute true remainder: rem = num - (quo * den) */
+ /* Compute true remainder: rem = num - (quo * den) */
mul_double (*lquo, *hquo, lden_orig, hden_orig, lrem, hrem);
neg_double (*lrem, *hrem, lrem, hrem);
add_double (lnum_orig, hnum_orig, *lrem, *hrem, lrem, hrem);
return overflow;
}
\f
+/* 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. */
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);
case REAL_CST:
case NEGATE_EXPR:
- case MINUS_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)
+ && reorder_operands_p (TREE_OPERAND (t, 0),
+ TREE_OPERAND (t, 1));
+
+ case MULT_EXPR:
+ if (TREE_UNSIGNED (TREE_TYPE (t)))
+ break;
+
+ /* Fall through. */
+
+ case RDIV_EXPR:
+ if (! HONOR_SIGN_DEPENDENT_ROUNDING (TYPE_MODE (TREE_TYPE (t))))
+ return negate_expr_p (TREE_OPERAND (t, 1))
+ || 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;
}
switch (TREE_CODE (t))
{
case INTEGER_CST:
- case REAL_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) || ! 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),
TREE_OPERAND (t, 0))));
break;
+ case MULT_EXPR:
+ if (TREE_UNSIGNED (TREE_TYPE (t)))
+ break;
+
+ /* Fall through. */
+
+ case RDIV_EXPR:
+ if (! HONOR_SIGN_DEPENDENT_ROUNDING (TYPE_MODE (TREE_TYPE (t))))
+ {
+ tem = TREE_OPERAND (t, 1);
+ if (negate_expr_p (tem))
+ return convert (type,
+ fold (build (TREE_CODE (t), TREE_TYPE (t),
+ TREE_OPERAND (t, 0),
+ negate_expr (tem))));
+ tem = TREE_OPERAND (t, 0);
+ if (negate_expr_p (tem))
+ return convert (type,
+ fold (build (TREE_CODE (t), TREE_TYPE (t),
+ negate_expr (tem),
+ TREE_OPERAND (t, 1))));
+ }
+ 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;
}
same type as IN, but they will have the same signedness and mode. */
static tree
-split_tree (tree in, enum tree_code code, tree *conp, tree *litp, tree *minus_litp, int negate_p)
+split_tree (tree in, enum tree_code code, tree *conp, tree *litp,
+ tree *minus_litp, int negate_p)
{
tree var = 0;
low = int1l & int2l, hi = int1h & int2h;
break;
- case BIT_ANDTC_EXPR:
- low = int1l & ~int2l, hi = int1h & ~int2h;
- break;
-
case RSHIFT_EXPR:
int2l = -int2l;
case LSHIFT_EXPR:
if (TREE_CODE (arg1) == REAL_CST)
{
+ enum machine_mode mode;
REAL_VALUE_TYPE d1;
REAL_VALUE_TYPE d2;
REAL_VALUE_TYPE value;
- tree t;
+ tree t, type;
d1 = TREE_REAL_CST (arg1);
d2 = TREE_REAL_CST (arg2);
+ type = TREE_TYPE (arg1);
+ mode = TYPE_MODE (type);
+
+ /* Don't perform operation if we honor signaling NaNs and
+ either operand is a NaN. */
+ if (HONOR_SNANS (mode)
+ && (REAL_VALUE_ISNAN (d1) || REAL_VALUE_ISNAN (d2)))
+ return NULL_TREE;
+
+ /* Don't perform operation if it would raise a division
+ by zero exception. */
+ if (code == RDIV_EXPR
+ && REAL_VALUES_EQUAL (d2, dconst0)
+ && (flag_trapping_math || ! MODE_HAS_INFINITIES (mode)))
+ return NULL_TREE;
+
/* If either operand is a NaN, just return it. Otherwise, set up
for floating-point trap; we return an overflow. */
if (REAL_VALUE_ISNAN (d1))
REAL_ARITHMETIC (value, code, d1, d2);
- t = build_real (TREE_TYPE (arg1),
- real_value_truncate (TYPE_MODE (TREE_TYPE (arg1)),
- value));
+ t = build_real (type, real_value_truncate (mode, value));
TREE_OVERFLOW (t)
= (force_fit_type (t, 0)
}
\f
-/* Given T, a tree representing type conversion of ARG1, a constant,
- return a constant tree representing the result of conversion. */
+/* Attempt to fold type conversion operation CODE of expression ARG1 to
+ type TYPE. If no simplification can be done return NULL_TREE. */
static tree
-fold_convert (tree t, tree arg1)
+fold_convert_const (enum tree_code code, tree type, tree arg1)
{
- tree type = TREE_TYPE (t);
int overflow = 0;
+ tree t;
+
+ if (TREE_TYPE (arg1) == type)
+ return arg1;
if (POINTER_TYPE_P (type) || INTEGRAL_TYPE_P (type))
{
/* If we would build a constant wider than GCC supports,
leave the conversion unfolded. */
if (TYPE_PRECISION (type) > 2 * HOST_BITS_PER_WIDE_INT)
- return t;
+ return NULL_TREE;
/* If we are trying to make a sizetype for a small integer, use
size_int to pick up cached types to reduce duplicate nodes. */
|| TREE_OVERFLOW (arg1));
TREE_CONSTANT_OVERFLOW (t)
= TREE_OVERFLOW (t) | TREE_CONSTANT_OVERFLOW (arg1);
+ return t;
}
else if (TREE_CODE (arg1) == REAL_CST)
{
- /* Don't initialize these, use assignments.
- Initialized local aggregates don't work on old compilers. */
- REAL_VALUE_TYPE x;
- REAL_VALUE_TYPE l;
- REAL_VALUE_TYPE u;
- tree type1 = TREE_TYPE (arg1);
- int no_upper_bound;
-
- x = TREE_REAL_CST (arg1);
- l = real_value_from_int_cst (type1, TYPE_MIN_VALUE (type));
-
- no_upper_bound = (TYPE_MAX_VALUE (type) == NULL);
- if (!no_upper_bound)
- u = real_value_from_int_cst (type1, TYPE_MAX_VALUE (type));
-
- /* See if X will be in range after truncation towards 0.
- To compensate for truncation, move the bounds away from 0,
- but reject if X exactly equals the adjusted bounds. */
- REAL_ARITHMETIC (l, MINUS_EXPR, l, dconst1);
- if (!no_upper_bound)
- REAL_ARITHMETIC (u, PLUS_EXPR, u, dconst1);
- /* If X is a NaN, use zero instead and show we have an overflow.
- Otherwise, range check. */
- if (REAL_VALUE_ISNAN (x))
- overflow = 1, x = dconst0;
- else if (! (REAL_VALUES_LESS (l, x)
- && !no_upper_bound
- && REAL_VALUES_LESS (x, u)))
- overflow = 1;
+ /* The following code implements the floating point to integer
+ conversion rules required by the Java Language Specification,
+ that IEEE NaNs are mapped to zero and values that overflow
+ the target precision saturate, i.e. values greater than
+ INT_MAX are mapped to INT_MAX, and values less than INT_MIN
+ are mapped to INT_MIN. These semantics are allowed by the
+ C and C++ standards that simply state that the behavior of
+ FP-to-integer conversion is unspecified upon overflow. */
- {
- HOST_WIDE_INT low, high;
- REAL_VALUE_TO_INT (&low, &high, x);
- t = build_int_2 (low, high);
- }
+ HOST_WIDE_INT high, low;
+
+ REAL_VALUE_TYPE r;
+ REAL_VALUE_TYPE x = TREE_REAL_CST (arg1);
+
+ switch (code)
+ {
+ case FIX_TRUNC_EXPR:
+ real_trunc (&r, VOIDmode, &x);
+ break;
+
+ case FIX_CEIL_EXPR:
+ real_ceil (&r, VOIDmode, &x);
+ break;
+
+ case FIX_FLOOR_EXPR:
+ real_floor (&r, VOIDmode, &x);
+ break;
+
+ default:
+ abort ();
+ }
+
+ /* If R is NaN, return zero and show we have an overflow. */
+ if (REAL_VALUE_ISNAN (r))
+ {
+ overflow = 1;
+ high = 0;
+ low = 0;
+ }
+
+ /* See if R is less than the lower bound or greater than the
+ upper bound. */
+
+ if (! overflow)
+ {
+ tree lt = TYPE_MIN_VALUE (type);
+ REAL_VALUE_TYPE l = real_value_from_int_cst (NULL_TREE, lt);
+ if (REAL_VALUES_LESS (r, l))
+ {
+ overflow = 1;
+ high = TREE_INT_CST_HIGH (lt);
+ low = TREE_INT_CST_LOW (lt);
+ }
+ }
+
+ if (! overflow)
+ {
+ tree ut = TYPE_MAX_VALUE (type);
+ if (ut)
+ {
+ REAL_VALUE_TYPE u = real_value_from_int_cst (NULL_TREE, ut);
+ if (REAL_VALUES_LESS (u, r))
+ {
+ overflow = 1;
+ high = TREE_INT_CST_HIGH (ut);
+ low = TREE_INT_CST_LOW (ut);
+ }
+ }
+ }
+
+ if (! overflow)
+ REAL_VALUE_TO_INT (&low, &high, r);
+
+ t = build_int_2 (low, high);
TREE_TYPE (t) = type;
TREE_OVERFLOW (t)
= TREE_OVERFLOW (arg1) | force_fit_type (t, overflow);
TREE_CONSTANT_OVERFLOW (t)
= TREE_OVERFLOW (t) | TREE_CONSTANT_OVERFLOW (arg1);
+ return t;
}
- TREE_TYPE (t) = type;
}
else if (TREE_CODE (type) == REAL_TYPE)
{
return t;
}
}
- TREE_CONSTANT (t) = 1;
- return t;
+ return NULL_TREE;
}
\f
/* Return an expr equal to X but certainly not valid as an lvalue. */
|| code == TRUTH_XOR_EXPR || code == TRUTH_NOT_EXPR);
}
\f
-/* Return nonzero if two operands are necessarily equal.
+/* Return nonzero if two operands (typically of the same tree node)
+ are necessarily equal. If either argument has side-effects this
+ function returns zero.
+
If ONLY_CONST is nonzero, only return nonzero for constants.
This function tests whether the operands are indistinguishable;
it does not test whether they are equal using C's == operation.
The distinction is important for IEEE floating point, because
(1) -0.0 and 0.0 are distinguishable, but -0.0==0.0, and
- (2) two NaNs may be indistinguishable, but NaN!=NaN. */
+ (2) two NaNs may be indistinguishable, but NaN!=NaN.
+
+ If ONLY_CONST is zero, a VAR_DECL is considered equal to itself
+ even though it may hold multiple values during a function.
+ This is because a GCC tree node guarantees that nothing else is
+ executed between the evaluation of its "operands" (which may often
+ be evaluated in arbitrary order). Hence if the operands themselves
+ don't side-effect, the VAR_DECLs, PARM_DECLs etc... must hold the
+ 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 nonzero. */
int
operand_equal_p (tree arg0, tree arg1, int only_const)
{
+ tree fndecl;
+
/* If both types don't have the same signedness, then we can't consider
them equal. We must check this before the STRIP_NOPS calls
because they may change the signedness of the arguments. */
return 0;
/* Only consider const functions equivalent. */
- if (TREE_CODE (TREE_OPERAND (arg0, 0)) == ADDR_EXPR)
- {
- tree fndecl = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
- if (! (flags_from_decl_or_type (fndecl) & ECF_CONST))
- return 0;
- }
- else
+ fndecl = get_callee_fndecl (arg0);
+ if (fndecl == NULL_TREE
+ || ! (flags_from_decl_or_type (fndecl) & ECF_CONST))
return 0;
/* Now see if all the arguments are the same. operand_equal_p
default:
break;
}
- /* fall through - ??? */
+ /* Fall through - ??? */
case '<':
{
starting at BITPOS. The field is unsigned if UNSIGNEDP is nonzero. */
static tree
-make_bit_field_ref (tree inner, tree type, int bitsize, int bitpos, int unsignedp)
+make_bit_field_ref (tree inner, tree type, int bitsize, int bitpos,
+ int unsignedp)
{
tree result = build (BIT_FIELD_REF, type, inner,
size_int (bitsize), bitsize_int (bitpos));
tree. Otherwise we return zero. */
static tree
-optimize_bit_field_compare (enum tree_code code, tree compare_type, tree lhs, tree rhs)
+optimize_bit_field_compare (enum tree_code code, tree compare_type,
+ tree lhs, tree rhs)
{
HOST_WIDE_INT lbitpos, lbitsize, rbitpos, rbitsize, nbitpos, nbitsize;
tree type = TREE_TYPE (lhs);
do anything with. */
static tree
-decode_field_reference (tree exp, HOST_WIDE_INT *pbitsize, HOST_WIDE_INT *pbitpos,
- enum machine_mode *pmode, int *punsignedp, int *pvolatilep,
+decode_field_reference (tree exp, HOST_WIDE_INT *pbitsize,
+ HOST_WIDE_INT *pbitpos, enum machine_mode *pmode,
+ int *punsignedp, int *pvolatilep,
tree *pmask, tree *pand_mask)
{
tree outer_type = 0;
static tree
sign_bit_p (tree exp, tree val)
{
- unsigned HOST_WIDE_INT lo;
- HOST_WIDE_INT hi;
+ unsigned HOST_WIDE_INT mask_lo, lo;
+ HOST_WIDE_INT mask_hi, hi;
int width;
tree t;
{
hi = (unsigned HOST_WIDE_INT) 1 << (width - HOST_BITS_PER_WIDE_INT - 1);
lo = 0;
+
+ mask_hi = ((unsigned HOST_WIDE_INT) -1
+ >> (2 * HOST_BITS_PER_WIDE_INT - width));
+ mask_lo = -1;
}
else
{
hi = 0;
lo = (unsigned HOST_WIDE_INT) 1 << (width - 1);
+
+ mask_hi = 0;
+ mask_lo = ((unsigned HOST_WIDE_INT) -1
+ >> (HOST_BITS_PER_WIDE_INT - width));
}
- if (TREE_INT_CST_HIGH (val) == hi && TREE_INT_CST_LOW (val) == lo)
+ /* We mask off those bits beyond TREE_TYPE (exp) so that we can
+ treat VAL as if it were unsigned. */
+ if ((TREE_INT_CST_HIGH (val) & mask_hi) == hi
+ && (TREE_INT_CST_LOW (val) & mask_lo) == lo)
return exp;
/* Handle extension from a narrower type. */
type if both are specified. */
static tree
-range_binop (enum tree_code code, tree type, tree arg0, int upper0_p, tree arg1,
- int upper1_p)
+range_binop (enum tree_code code, tree type, tree arg0, int upper0_p,
+ tree arg1, int upper1_p)
{
tree tem;
int result;
if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code)))
{
- arg0 = TREE_OPERAND (exp, 0);
+ if (first_rtl_op (code) > 0)
+ arg0 = TREE_OPERAND (exp, 0);
if (TREE_CODE_CLASS (code) == '<'
|| TREE_CODE_CLASS (code) == '1'
|| TREE_CODE_CLASS (code) == '2')
in_p = n_in_p, low = n_low, high = n_high;
- /* If the high bound is missing, but we
- have a low bound, reverse the range so
- it goes from zero to the low bound minus 1. */
- if (high == 0 && low)
+ /* If the high bound is missing, but we have a nonzero low
+ bound, reverse the range so it goes from zero to the low bound
+ minus 1. */
+ if (high == 0 && low && ! integer_zerop (low))
{
in_p = ! in_p;
high = range_binop (MINUS_EXPR, NULL_TREE, low, 0,
can, 0 if we can't. Set the output range into the specified parameters. */
static int
-merge_ranges (int *pin_p, tree *plow, tree *phigh, int in0_p, tree low0, tree high0,
- int in1_p, tree low1, tree high1)
+merge_ranges (int *pin_p, tree *plow, tree *phigh, int in0_p, tree low0,
+ tree high0, int in1_p, tree low1, tree high1)
{
int no_overlap;
int subset;
if (code == MULT_EXPR
|| integer_zerop (const_binop (TRUNC_MOD_EXPR, op1, c, 0)))
{
- op1 = const_binop (code, convert (ctype, op1), convert (ctype, c), 0);
- if (op1 == 0 || TREE_OVERFLOW (op1))
+ op1 = const_binop (code, convert (ctype, op1),
+ convert (ctype, c), 0);
+ /* We allow the constant to overflow with wrapping semantics. */
+ if (op1 == 0
+ || (TREE_OVERFLOW (op1) && ! flag_wrapv))
break;
}
else
original expression. */
static tree
-fold_binary_op_with_conditional_arg (enum tree_code code, tree type, tree cond, tree arg, int cond_first_p)
+fold_binary_op_with_conditional_arg (enum tree_code code, tree type,
+ tree cond, tree arg, int cond_first_p)
{
tree test, true_value, false_value;
tree lhs = NULL_TREE;
can be made, and NULL_TREE otherwise. */
static tree
-fold_mathfn_compare (enum built_in_function fcode, enum tree_code code, tree type, tree arg0, tree arg1)
+fold_mathfn_compare (enum built_in_function fcode, enum tree_code code,
+ tree type, tree arg0, tree arg1)
{
REAL_VALUE_TYPE c;
NULL. TYPE is the desired result type. */
tree
-fold_single_bit_test (code, arg0, arg1, result_type)
- enum tree_code code;
- tree arg0;
- tree arg1;
- tree result_type;
+fold_single_bit_test (enum tree_code code, tree arg0, tree arg1,
+ tree result_type)
{
/* If this is a TRUTH_NOT_EXPR, it may have a single bit test inside
operand 0. */
int bitnum = tree_log2 (TREE_OPERAND (arg0, 1));
enum machine_mode operand_mode = TYPE_MODE (type);
int ops_unsigned;
- tree signed_type, unsigned_type;
+ tree signed_type, unsigned_type, intermediate_type;
tree arg00;
/* If we have (A & C) != 0 where C is the sign bit of A, convert
convert (stype, arg00),
convert (stype, integer_zero_node)));
}
+
+ /* At this point, we know that arg0 is not testing the sign bit. */
+ if (TYPE_PRECISION (type) - 1 == bitnum)
+ abort ();
/* Otherwise we have (A & C) != 0 where C is a single bit,
convert that into ((A >> C2) & 1). Where C2 = log2(C).
/* If we are going to be able to omit the AND below, we must do our
operations as unsigned. If we must use the AND, we have a choice.
Normally unsigned is faster, but for some machines signed is. */
- ops_unsigned = (bitnum == TYPE_PRECISION (type) - 1 ? 1
#ifdef LOAD_EXTEND_OP
- : (LOAD_EXTEND_OP (operand_mode) == SIGN_EXTEND ? 0 : 1)
+ ops_unsigned = (LOAD_EXTEND_OP (operand_mode) == SIGN_EXTEND ? 0 : 1);
#else
- : 1
+ ops_unsigned = 1;
#endif
- );
signed_type = (*lang_hooks.types.type_for_mode) (operand_mode, 0);
unsigned_type = (*lang_hooks.types.type_for_mode) (operand_mode, 1);
+ intermediate_type = ops_unsigned ? unsigned_type : signed_type;
+ inner = convert (intermediate_type, inner);
if (bitnum != 0)
- inner = build (RSHIFT_EXPR, ops_unsigned ? unsigned_type : signed_type,
+ inner = build (RSHIFT_EXPR, intermediate_type,
inner, size_int (bitnum));
if (code == EQ_EXPR)
- inner = build (BIT_XOR_EXPR, ops_unsigned ? unsigned_type : signed_type,
+ inner = build (BIT_XOR_EXPR, intermediate_type,
inner, integer_one_node);
/* Put the AND last so it can combine with more things. */
- if (bitnum != TYPE_PRECISION (type) - 1)
- inner = build (BIT_AND_EXPR, ops_unsigned ? unsigned_type : signed_type,
- inner, integer_one_node);
+ inner = build (BIT_AND_EXPR, intermediate_type,
+ inner, integer_one_node);
/* Make sure to return the proper type. */
- if (TREE_TYPE (inner) != result_type)
- inner = convert (result_type, inner);
+ inner = convert (result_type, inner);
return inner;
}
return NULL_TREE;
}
-
+
+/* Check whether we are allowed to reorder operands arg0 and arg1,
+ such that the evaluation of arg1 occurs before arg0. */
+
+static bool
+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);
+
+ 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;
+
+ if (optimize_size)
+ return 0;
+
+ 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;
+}
+
/* 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.
We cannot simplify through a CONVERT_EXPR, FIX_EXPR or FLOAT_EXPR,
but we can constant-fold them if they have constant operands. */
+#ifdef ENABLE_FOLD_CHECKING
+# define fold(x) fold_1 (x)
+static tree fold_1 (tree);
+static
+#endif
tree
fold (tree expr)
{
- tree t = expr;
+ tree t = expr, orig_t;
tree t1 = NULL_TREE;
tree tem;
tree type = TREE_TYPE (expr);
if (kind == 'c')
return t;
-#ifdef MAX_INTEGER_COMPUTATION_MODE
- check_max_integer_computation_mode (expr);
-#endif
+ orig_t = t;
if (code == NOP_EXPR || code == FLOAT_EXPR || code == CONVERT_EXPR)
{
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. */
wins = 0;
}
- else if (IS_EXPR_CODE_CLASS (kind) || kind == 'r')
+ else if (IS_EXPR_CODE_CLASS (kind))
{
int len = first_rtl_op (code);
int i;
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 (arg0) == REAL_CST))
- {
- tem = arg0; arg0 = arg1; arg1 = tem;
-
- tem = TREE_OPERAND (t, 0); TREE_OPERAND (t, 0) = TREE_OPERAND (t, 1);
- TREE_OPERAND (t, 1) = tem;
- }
+ && tree_swap_operands_p (arg0, arg1, true))
+ return fold (build (code, type, arg1, arg0));
/* Now WINS is set as described above,
ARG0 is the first operand of EXPR,
case FLOAT_EXPR:
case CONVERT_EXPR:
case FIX_TRUNC_EXPR:
- /* Other kinds of FIX are not handled properly by fold_convert. */
-
+ case FIX_CEIL_EXPR:
+ case FIX_FLOOR_EXPR:
if (TREE_TYPE (TREE_OPERAND (t, 0)) == TREE_TYPE (t))
return TREE_OPERAND (t, 0);
/* Don't leave an assignment inside a conversion
unless assigning a bitfield. */
tree prev = TREE_OPERAND (t, 0);
+ if (t == orig_t)
+ t = copy_node (t);
TREE_OPERAND (t, 0) = TREE_OPERAND (prev, 1);
/* First do the assignment, then return converted constant. */
t = build (COMPOUND_EXPR, TREE_TYPE (t), prev, fold (t));
convert (TREE_TYPE (t), and1)));
}
- if (!wins)
- {
- TREE_CONSTANT (t) = TREE_CONSTANT (arg0);
- return t;
- }
- return fold_convert (t, arg0);
+ tem = fold_convert_const (code, TREE_TYPE (t), arg0);
+ return tem ? tem : t;
case VIEW_CONVERT_EXPR:
if (TREE_CODE (TREE_OPERAND (t, 0)) == VIEW_CONVERT_EXPR)
return t;
case RANGE_EXPR:
- TREE_CONSTANT (t) = wins;
- 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)
+ if (TREE_CONSTANT (t) != wins)
{
- tree targ0 = strip_float_extensions (arg0);
- if (targ0 != arg0)
- return convert (type, build1 (NEGATE_EXPR, TREE_TYPE (targ0), targ0));
-
+ if (t == orig_t)
+ t = copy_node (t);
+ TREE_CONSTANT (t) = wins;
}
+ return t;
- /* 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 = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
- 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;
- }
+ case NEGATE_EXPR:
+ if (negate_expr_p (arg0))
+ return negate_expr (arg0);
return t;
case ABS_EXPR:
same));
}
}
+ else
+ {
+ /* See if ARG1 is zero and X + ARG1 reduces to X. */
+ if (fold_real_zero_addition_p (TREE_TYPE (arg0), arg1, 0))
+ return non_lvalue (convert (type, arg0));
- /* See if ARG1 is zero and X + ARG1 reduces to X. */
- else if (fold_real_zero_addition_p (TREE_TYPE (arg0), arg1, 0))
- return non_lvalue (convert (type, arg0));
+ /* Likewise if the operands are reversed. */
+ if (fold_real_zero_addition_p (TREE_TYPE (arg1), arg0, 0))
+ return non_lvalue (convert (type, arg1));
- /* Likewise if the operands are reversed. */
- else if (fold_real_zero_addition_p (TREE_TYPE (arg1), arg0, 0))
- return non_lvalue (convert (type, arg1));
+ /* Convert x+x into x*2.0. */
+ if (operand_equal_p (arg0, arg1, 0)
+ && SCALAR_FLOAT_TYPE_P (type))
+ return fold (build (MULT_EXPR, type, arg0,
+ build_real (type, dconst2)));
+
+ /* Convert x*c+x into x*(c+1). */
+ if (flag_unsafe_math_optimizations
+ && TREE_CODE (arg0) == MULT_EXPR
+ && TREE_CODE (TREE_OPERAND (arg0, 1)) == REAL_CST
+ && ! TREE_CONSTANT_OVERFLOW (TREE_OPERAND (arg0, 1))
+ && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0))
+ {
+ REAL_VALUE_TYPE c;
+
+ c = TREE_REAL_CST (TREE_OPERAND (arg0, 1));
+ real_arithmetic (&c, PLUS_EXPR, &c, &dconst1);
+ return fold (build (MULT_EXPR, type, arg1,
+ build_real (type, c)));
+ }
+
+ /* Convert x+x*c into x*(c+1). */
+ if (flag_unsafe_math_optimizations
+ && TREE_CODE (arg1) == MULT_EXPR
+ && TREE_CODE (TREE_OPERAND (arg1, 1)) == REAL_CST
+ && ! TREE_CONSTANT_OVERFLOW (TREE_OPERAND (arg1, 1))
+ && operand_equal_p (TREE_OPERAND (arg1, 0), arg0, 0))
+ {
+ REAL_VALUE_TYPE c;
+
+ c = TREE_REAL_CST (TREE_OPERAND (arg1, 1));
+ real_arithmetic (&c, PLUS_EXPR, &c, &dconst1);
+ return fold (build (MULT_EXPR, type, arg0,
+ build_real (type, c)));
+ }
+
+ /* Convert x*c1+x*c2 into x*(c1+c2). */
+ if (flag_unsafe_math_optimizations
+ && TREE_CODE (arg0) == MULT_EXPR
+ && TREE_CODE (arg1) == MULT_EXPR
+ && TREE_CODE (TREE_OPERAND (arg0, 1)) == REAL_CST
+ && ! TREE_CONSTANT_OVERFLOW (TREE_OPERAND (arg0, 1))
+ && TREE_CODE (TREE_OPERAND (arg1, 1)) == REAL_CST
+ && ! TREE_CONSTANT_OVERFLOW (TREE_OPERAND (arg1, 1))
+ && operand_equal_p (TREE_OPERAND (arg0, 0),
+ TREE_OPERAND (arg1, 0), 0))
+ {
+ REAL_VALUE_TYPE c1, c2;
+
+ c1 = TREE_REAL_CST (TREE_OPERAND (arg0, 1));
+ c2 = TREE_REAL_CST (TREE_OPERAND (arg1, 1));
+ real_arithmetic (&c1, PLUS_EXPR, &c1, &c2);
+ return fold (build (MULT_EXPR, type,
+ TREE_OPERAND (arg0, 0),
+ build_real (type, c1)));
+ }
+ }
bit_rotate:
/* (A << C1) + (A >> C2) if A is unsigned and C1+C2 is the size of A
associate:
/* In most languages, can't associate operations on floats through
parentheses. Rather than remember where the parentheses were, we
- don't associate floats at all. It shouldn't matter much. However,
- associating multiplications is only very slightly inaccurate, so do
- that if -funsafe-math-optimizations is specified. */
+ don't associate floats at all, unless the user has specified
+ -funsafe-math-optimizations. */
if (! wins
- && (! FLOAT_TYPE_P (type)
- || (flag_unsafe_math_optimizations && code == MULT_EXPR)))
+ && (! FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations))
{
tree var0, con0, lit0, minus_lit0;
tree var1, con1, lit1, minus_lit1;
example: ((X*2 + 4) - 8U)/2. */
if (minus_lit0 && lit0)
{
- if (tree_int_cst_lt (lit0, minus_lit0))
+ if (TREE_CODE (lit0) == INTEGER_CST
+ && TREE_CODE (minus_lit0) == INTEGER_CST
+ && tree_int_cst_lt (lit0, minus_lit0))
{
minus_lit0 = associate_trees (minus_lit0, lit0,
MINUS_EXPR, type);
&& (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)));
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 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))
+ {
+ 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. */
case MULT_EXPR:
/* (-A) * (-B) -> A * B */
- if (TREE_CODE (arg0) == NEGATE_EXPR && TREE_CODE (arg1) == NEGATE_EXPR)
- return fold (build (MULT_EXPR, type, TREE_OPERAND (arg0, 0),
+ if (TREE_CODE (arg0) == NEGATE_EXPR && negate_expr_p (arg1))
+ return fold (build (MULT_EXPR, type,
+ TREE_OPERAND (arg0, 0),
+ negate_expr (arg1)));
+ if (TREE_CODE (arg1) == NEGATE_EXPR && negate_expr_p (arg0))
+ return fold (build (MULT_EXPR, type,
+ negate_expr (arg0),
TREE_OPERAND (arg1, 0)));
if (! FLOAT_TYPE_P (type))
&& real_minus_onep (arg1))
return fold (build1 (NEGATE_EXPR, type, arg0));
- /* x*2 is x+x */
- if (! wins && real_twop (arg1)
- && (*lang_hooks.decls.global_bindings_p) () == 0
- && ! CONTAINS_PLACEHOLDER_P (arg0))
+ /* Convert (C1/X)*C2 into (C1*C2)/X. */
+ if (flag_unsafe_math_optimizations
+ && TREE_CODE (arg0) == RDIV_EXPR
+ && TREE_CODE (arg1) == REAL_CST
+ && TREE_CODE (TREE_OPERAND (arg0, 0)) == REAL_CST)
{
- tree arg = save_expr (arg0);
- return fold (build (PLUS_EXPR, type, arg, arg));
+ tree tem = const_binop (MULT_EXPR, TREE_OPERAND (arg0, 0),
+ arg1, 0);
+ if (tem)
+ return fold (build (RDIV_EXPR, type, tem,
+ TREE_OPERAND (arg0, 1)));
}
if (flag_unsafe_math_optimizations)
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,
return build_function_call_expr (sinfn,
TREE_OPERAND (arg0, 1));
}
+
+ /* Optimize x*pow(x,c) as pow(x,c+1). */
+ if (fcode1 == BUILT_IN_POW
+ || fcode1 == BUILT_IN_POWF
+ || fcode1 == BUILT_IN_POWL)
+ {
+ tree arg10 = TREE_VALUE (TREE_OPERAND (arg1, 1));
+ tree arg11 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg1,
+ 1)));
+ if (TREE_CODE (arg11) == REAL_CST
+ && ! TREE_CONSTANT_OVERFLOW (arg11)
+ && operand_equal_p (arg0, arg10, 0))
+ {
+ tree powfn = TREE_OPERAND (TREE_OPERAND (arg1, 0), 0);
+ REAL_VALUE_TYPE c;
+ tree arg, arglist;
+
+ c = TREE_REAL_CST (arg11);
+ real_arithmetic (&c, PLUS_EXPR, &c, &dconst1);
+ arg = build_real (type, c);
+ arglist = build_tree_list (NULL_TREE, arg);
+ arglist = tree_cons (NULL_TREE, arg0, arglist);
+ return build_function_call_expr (powfn, arglist);
+ }
+ }
+
+ /* Optimize pow(x,c)*x as pow(x,c+1). */
+ if (fcode0 == BUILT_IN_POW
+ || fcode0 == BUILT_IN_POWF
+ || fcode0 == BUILT_IN_POWL)
+ {
+ tree arg00 = TREE_VALUE (TREE_OPERAND (arg0, 1));
+ tree arg01 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg0,
+ 1)));
+ if (TREE_CODE (arg01) == REAL_CST
+ && ! TREE_CONSTANT_OVERFLOW (arg01)
+ && operand_equal_p (arg1, arg00, 0))
+ {
+ tree powfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
+ REAL_VALUE_TYPE c;
+ tree arg, arglist;
+
+ c = TREE_REAL_CST (arg01);
+ real_arithmetic (&c, PLUS_EXPR, &c, &dconst1);
+ arg = build_real (type, c);
+ arglist = build_tree_list (NULL_TREE, arg);
+ arglist = tree_cons (NULL_TREE, arg1, arglist);
+ return build_function_call_expr (powfn, arglist);
+ }
+ }
+
+ /* Optimize x*x as pow(x,2.0), which is expanded as x*x. */
+ if (! optimize_size
+ && operand_equal_p (arg0, arg1, 0))
+ {
+ tree powfn;
+
+ if (type == double_type_node)
+ powfn = implicit_built_in_decls[BUILT_IN_POW];
+ else if (type == float_type_node)
+ powfn = implicit_built_in_decls[BUILT_IN_POWF];
+ else if (type == long_double_type_node)
+ powfn = implicit_built_in_decls[BUILT_IN_POWL];
+ else
+ powfn = NULL_TREE;
+
+ if (powfn)
+ {
+ tree arg = build_real (type, dconst2);
+ tree arglist = build_tree_list (NULL_TREE, arg);
+ arglist = tree_cons (NULL_TREE, arg0, arglist);
+ return build_function_call_expr (powfn, arglist);
+ }
+ }
}
}
goto associate;
goto bit_rotate;
case BIT_AND_EXPR:
- bit_and:
if (integer_all_onesp (arg1))
return non_lvalue (convert (type, arg0));
if (integer_zerop (arg1))
goto associate;
- case BIT_ANDTC_EXPR:
- if (integer_all_onesp (arg0))
- return non_lvalue (convert (type, arg1));
- if (integer_zerop (arg0))
- return omit_one_operand (type, arg0, arg1);
- if (TREE_CODE (arg1) == INTEGER_CST)
- {
- arg1 = fold (build1 (BIT_NOT_EXPR, type, arg1));
- code = BIT_AND_EXPR;
- goto bit_and;
- }
- goto binary;
-
case RDIV_EXPR:
/* Don't touch a floating-point divide by zero unless the mode
of the constant can represent infinity. */
return t;
/* (-A) / (-B) -> A / B */
- if (TREE_CODE (arg0) == NEGATE_EXPR && TREE_CODE (arg1) == NEGATE_EXPR)
- return fold (build (RDIV_EXPR, type, TREE_OPERAND (arg0, 0),
+ if (TREE_CODE (arg0) == NEGATE_EXPR && negate_expr_p (arg1))
+ return fold (build (RDIV_EXPR, type,
+ TREE_OPERAND (arg0, 0),
+ negate_expr (arg1)));
+ if (TREE_CODE (arg1) == NEGATE_EXPR && negate_expr_p (arg0))
+ return fold (build (RDIV_EXPR, type,
+ negate_expr (arg0),
TREE_OPERAND (arg1, 0)));
/* In IEEE floating point, x/1 is not equivalent to x for snans. */
&& real_onep (arg1))
return non_lvalue (convert (type, arg0));
+ /* In IEEE floating point, x/-1 is not equivalent to -x for snans. */
+ if (!HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg0)))
+ && real_minus_onep (arg1))
+ return non_lvalue (convert (type, negate_expr (arg0)));
+
/* If ARG1 is a constant, we can convert this to a multiply by the
reciprocal. This does not have the same rounding properties,
so only do this if -funsafe-math-optimizations. We can actually
arg1, 0)))
return fold (build (MULT_EXPR, type, arg0, tem));
/* Find the reciprocal if optimizing and the result is exact. */
- else if (optimize)
+ if (optimize)
{
REAL_VALUE_TYPE r;
r = TREE_REAL_CST (arg1);
/* Convert A/B/C to A/(B*C). */
if (flag_unsafe_math_optimizations
&& TREE_CODE (arg0) == RDIV_EXPR)
- {
- return fold (build (RDIV_EXPR, type, TREE_OPERAND (arg0, 0),
- build (MULT_EXPR, type, TREE_OPERAND (arg0, 1),
- arg1)));
- }
+ return fold (build (RDIV_EXPR, type, TREE_OPERAND (arg0, 0),
+ fold (build (MULT_EXPR, type,
+ TREE_OPERAND (arg0, 1), arg1))));
+
/* Convert A/(B/C) to (A/B)*C. */
if (flag_unsafe_math_optimizations
&& TREE_CODE (arg1) == RDIV_EXPR)
+ return fold (build (MULT_EXPR, type,
+ fold (build (RDIV_EXPR, type, arg0,
+ TREE_OPERAND (arg1, 0))),
+ TREE_OPERAND (arg1, 1)));
+
+ /* Convert C1/(X*C2) into (C1/C2)/X. */
+ if (flag_unsafe_math_optimizations
+ && TREE_CODE (arg1) == MULT_EXPR
+ && TREE_CODE (arg0) == REAL_CST
+ && TREE_CODE (TREE_OPERAND (arg1, 1)) == REAL_CST)
{
- return fold (build (MULT_EXPR, type,
- build (RDIV_EXPR, type, arg0,
- TREE_OPERAND (arg1, 0)),
- TREE_OPERAND (arg1, 1)));
+ tree tem = const_binop (RDIV_EXPR, arg0,
+ TREE_OPERAND (arg1, 1), 0);
+ if (tem)
+ return fold (build (RDIV_EXPR, type, tem,
+ TREE_OPERAND (arg1, 0)));
}
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,
tmp));
}
}
+
+ /* Optimize pow(x,c)/x as pow(x,c-1). */
+ if (fcode0 == BUILT_IN_POW
+ || fcode0 == BUILT_IN_POWF
+ || fcode0 == BUILT_IN_POWL)
+ {
+ tree arg00 = TREE_VALUE (TREE_OPERAND (arg0, 1));
+ tree arg01 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg0, 1)));
+ if (TREE_CODE (arg01) == REAL_CST
+ && ! TREE_CONSTANT_OVERFLOW (arg01)
+ && operand_equal_p (arg1, arg00, 0))
+ {
+ tree powfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
+ REAL_VALUE_TYPE c;
+ tree arg, arglist;
+
+ c = TREE_REAL_CST (arg01);
+ real_arithmetic (&c, MINUS_EXPR, &c, &dconst1);
+ arg = build_real (type, c);
+ arglist = build_tree_list (NULL_TREE, arg);
+ arglist = tree_cons (NULL_TREE, arg1, arglist);
+ return build_function_call_expr (powfn, arglist);
+ }
+ }
}
goto binary;
RROTATE_EXPR by a new constant. */
if (code == LROTATE_EXPR && TREE_CODE (arg1) == INTEGER_CST)
{
- 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
permute the two operations. */
if (code == RROTATE_EXPR && TREE_CODE (arg1) == INTEGER_CST
&& (TREE_CODE (arg0) == BIT_AND_EXPR
- || TREE_CODE (arg0) == BIT_ANDTC_EXPR
|| TREE_CODE (arg0) == BIT_IOR_EXPR
|| TREE_CODE (arg0) == BIT_XOR_EXPR)
&& TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
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))
- {
- 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, true))
+ 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;
- 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;
- 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;
- 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;
- 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;
}
if (tem)
return tem;
+ /* If we have (A & C) == D where D & ~C != 0, convert this into 0.
+ Similarly for NE_EXPR. */
+ if ((code == EQ_EXPR || code == NE_EXPR)
+ && TREE_CODE (arg0) == BIT_AND_EXPR
+ && TREE_CODE (arg1) == INTEGER_CST
+ && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
+ {
+ tree dandnotc
+ = fold (build (BIT_AND_EXPR, TREE_TYPE (arg0),
+ arg1, build1 (BIT_NOT_EXPR,
+ TREE_TYPE (TREE_OPERAND (arg0, 1)),
+ TREE_OPERAND (arg0, 1))));
+ tree rslt = code == EQ_EXPR ? integer_zero_node : integer_one_node;
+ if (integer_nonzerop (dandnotc))
+ return omit_one_operand (type, rslt, arg0);
+ }
+
+ /* If we have (A | C) == D where C & ~D != 0, convert this into 0.
+ Similarly for NE_EXPR. */
+ if ((code == EQ_EXPR || code == NE_EXPR)
+ && TREE_CODE (arg0) == BIT_IOR_EXPR
+ && TREE_CODE (arg1) == INTEGER_CST
+ && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
+ {
+ tree candnotd
+ = fold (build (BIT_AND_EXPR, TREE_TYPE (arg0),
+ TREE_OPERAND (arg0, 1),
+ build1 (BIT_NOT_EXPR, TREE_TYPE (arg1), arg1)));
+ tree rslt = code == EQ_EXPR ? integer_zero_node : integer_one_node;
+ if (integer_nonzerop (candnotd))
+ return omit_one_operand (type, rslt, arg0);
+ }
+
/* If X is unsigned, convert X < (1 << Y) into X >> Y == 0
and similarly for >= into !=. */
if ((code == LT_EXPR || code == GE_EXPR)
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;
- 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
&& (optimize || TREE_CODE (arg1) == INTEGER_CST))
{
t1 = optimize_bit_field_compare (code, type, arg0, arg1);
- return t1 ? t1 : t;
+ if (t1)
+ return t1;
}
/* If this is a comparison of complex values and either or both sides
due to the return value of strlen being unsigned. */
if ((code == EQ_EXPR || code == NE_EXPR)
&& integer_zerop (arg1)
- && TREE_CODE (arg0) == CALL_EXPR
- && TREE_CODE (TREE_OPERAND (arg0, 0)) == ADDR_EXPR)
+ && TREE_CODE (arg0) == CALL_EXPR)
{
- tree fndecl = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
+ tree fndecl = get_callee_fndecl (arg0);
tree arglist;
- if (TREE_CODE (fndecl) == FUNCTION_DECL
+ if (fndecl
&& DECL_BUILT_IN (fndecl)
&& DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_MD
&& DECL_FUNCTION_CODE (fndecl) == BUILT_IN_STRLEN
/* Pedantic ANSI C says that a conditional expression is never an lvalue,
so all simple results must be passed through pedantic_non_lvalue. */
if (TREE_CODE (arg0) == INTEGER_CST)
- return pedantic_non_lvalue
- (TREE_OPERAND (t, (integer_zerop (arg0) ? 2 : 1)));
- 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);
- }
+ tem = TREE_OPERAND (t, (integer_zerop (arg0) ? 2 : 1));
+ /* Only optimize constant conditions when the selected branch
+ has the same type as the COND_EXPR. This avoids optimizing
+ away "c ? x : throw", where the throw has a void type. */
+ if (! VOID_TYPE_P (TREE_TYPE (tem))
+ || VOID_TYPE_P (TREE_TYPE (t)))
+ return pedantic_non_lvalue (tem);
+ return t;
}
+ if (operand_equal_p (arg1, TREE_OPERAND (expr, 2), 0))
+ return pedantic_omit_one_operand (type, arg1, arg0);
/* 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
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), false))
{
/* 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. */
case COMPOUND_EXPR:
/* When pedantic, a compound expression can be neither an lvalue
nor an integer constant expression. */
- if (TREE_SIDE_EFFECTS (arg0) || pedantic)
+ if (TREE_SIDE_EFFECTS (arg0) || TREE_CONSTANT (arg1))
return t;
/* Don't let (0, 0) be null pointer constant. */
if (integer_zerop (arg1))
- return build1 (NOP_EXPR, type, arg1);
- return convert (type, arg1);
+ return pedantic_non_lvalue (build1 (NOP_EXPR, type, arg1));
+ return pedantic_non_lvalue (convert (type, arg1));
case COMPLEX_EXPR:
if (wins)
} /* switch (code) */
}
+#ifdef ENABLE_FOLD_CHECKING
+#undef fold
+
+static void fold_checksum_tree (tree, struct md5_ctx *, htab_t);
+static void fold_check_failed (tree, tree);
+void print_fold_checksum (tree);
+
+/* When --enable-checking=fold, compute a digest of expr before
+ and after actual fold call to see if fold did not accidentally
+ change original expr. */
+
+tree
+fold (tree expr)
+{
+ tree ret;
+ struct md5_ctx ctx;
+ unsigned char checksum_before[16], checksum_after[16];
+ htab_t ht;
+
+ ht = htab_create (32, htab_hash_pointer, htab_eq_pointer, NULL);
+ md5_init_ctx (&ctx);
+ fold_checksum_tree (expr, &ctx, ht);
+ md5_finish_ctx (&ctx, checksum_before);
+ htab_empty (ht);
+
+ ret = fold_1 (expr);
+
+ md5_init_ctx (&ctx);
+ fold_checksum_tree (expr, &ctx, ht);
+ md5_finish_ctx (&ctx, checksum_after);
+ htab_delete (ht);
+
+ if (memcmp (checksum_before, checksum_after, 16))
+ fold_check_failed (expr, ret);
+
+ return ret;
+}
+
+void
+print_fold_checksum (tree expr)
+{
+ struct md5_ctx ctx;
+ unsigned char checksum[16], cnt;
+ htab_t ht;
+
+ ht = htab_create (32, htab_hash_pointer, htab_eq_pointer, NULL);
+ md5_init_ctx (&ctx);
+ fold_checksum_tree (expr, &ctx, ht);
+ md5_finish_ctx (&ctx, checksum);
+ htab_delete (ht);
+ for (cnt = 0; cnt < 16; ++cnt)
+ fprintf (stderr, "%02x", checksum[cnt]);
+ putc ('\n', stderr);
+}
+
+static void
+fold_check_failed (tree expr ATTRIBUTE_UNUSED, tree ret ATTRIBUTE_UNUSED)
+{
+ internal_error ("fold check: original tree changed by fold");
+}
+
+static void
+fold_checksum_tree (tree expr, struct md5_ctx *ctx, htab_t ht)
+{
+ void **slot;
+ enum tree_code code;
+ char buf[sizeof (struct tree_decl)];
+ int i, len;
+
+ if (sizeof (struct tree_exp) + 5 * sizeof (tree)
+ > sizeof (struct tree_decl)
+ || sizeof (struct tree_type) > sizeof (struct tree_decl))
+ abort ();
+ if (expr == NULL)
+ return;
+ slot = htab_find_slot (ht, expr, INSERT);
+ if (*slot != NULL)
+ return;
+ *slot = expr;
+ code = TREE_CODE (expr);
+ if (code == SAVE_EXPR && SAVE_EXPR_NOPLACEHOLDER (expr))
+ {
+ /* Allow SAVE_EXPR_NOPLACEHOLDER flag to be modified. */
+ memcpy (buf, expr, tree_size (expr));
+ expr = (tree) buf;
+ SAVE_EXPR_NOPLACEHOLDER (expr) = 0;
+ }
+ else if (TREE_CODE_CLASS (code) == 'd' && DECL_ASSEMBLER_NAME_SET_P (expr))
+ {
+ /* Allow DECL_ASSEMBLER_NAME to be modified. */
+ memcpy (buf, expr, tree_size (expr));
+ expr = (tree) buf;
+ SET_DECL_ASSEMBLER_NAME (expr, NULL);
+ }
+ else if (TREE_CODE_CLASS (code) == 't'
+ && (TYPE_POINTER_TO (expr) || TYPE_REFERENCE_TO (expr)))
+ {
+ /* Allow TYPE_POINTER_TO and TYPE_REFERENCE_TO to be modified. */
+ memcpy (buf, expr, tree_size (expr));
+ expr = (tree) buf;
+ TYPE_POINTER_TO (expr) = NULL;
+ TYPE_REFERENCE_TO (expr) = NULL;
+ }
+ md5_process_bytes (expr, tree_size (expr), ctx);
+ fold_checksum_tree (TREE_TYPE (expr), ctx, ht);
+ if (TREE_CODE_CLASS (code) != 't' && TREE_CODE_CLASS (code) != 'd')
+ fold_checksum_tree (TREE_CHAIN (expr), ctx, ht);
+ len = TREE_CODE_LENGTH (code);
+ switch (TREE_CODE_CLASS (code))
+ {
+ case 'c':
+ switch (code)
+ {
+ case STRING_CST:
+ md5_process_bytes (TREE_STRING_POINTER (expr),
+ TREE_STRING_LENGTH (expr), ctx);
+ break;
+ case COMPLEX_CST:
+ fold_checksum_tree (TREE_REALPART (expr), ctx, ht);
+ fold_checksum_tree (TREE_IMAGPART (expr), ctx, ht);
+ break;
+ case VECTOR_CST:
+ fold_checksum_tree (TREE_VECTOR_CST_ELTS (expr), ctx, ht);
+ break;
+ default:
+ break;
+ }
+ break;
+ case 'x':
+ switch (code)
+ {
+ case TREE_LIST:
+ fold_checksum_tree (TREE_PURPOSE (expr), ctx, ht);
+ fold_checksum_tree (TREE_VALUE (expr), ctx, ht);
+ break;
+ case TREE_VEC:
+ for (i = 0; i < TREE_VEC_LENGTH (expr); ++i)
+ fold_checksum_tree (TREE_VEC_ELT (expr, i), ctx, ht);
+ break;
+ default:
+ break;
+ }
+ break;
+ case 'e':
+ switch (code)
+ {
+ case SAVE_EXPR: len = 2; break;
+ case GOTO_SUBROUTINE_EXPR: len = 0; break;
+ case RTL_EXPR: len = 0; break;
+ case WITH_CLEANUP_EXPR: len = 2; break;
+ default: break;
+ }
+ /* Fall through. */
+ case 'r':
+ case '<':
+ case '1':
+ case '2':
+ case 's':
+ for (i = 0; i < len; ++i)
+ fold_checksum_tree (TREE_OPERAND (expr, i), ctx, ht);
+ break;
+ case 'd':
+ fold_checksum_tree (DECL_SIZE (expr), ctx, ht);
+ fold_checksum_tree (DECL_SIZE_UNIT (expr), ctx, ht);
+ fold_checksum_tree (DECL_NAME (expr), ctx, ht);
+ fold_checksum_tree (DECL_CONTEXT (expr), ctx, ht);
+ fold_checksum_tree (DECL_ARGUMENTS (expr), ctx, ht);
+ fold_checksum_tree (DECL_RESULT_FLD (expr), ctx, ht);
+ fold_checksum_tree (DECL_INITIAL (expr), ctx, ht);
+ fold_checksum_tree (DECL_ABSTRACT_ORIGIN (expr), ctx, ht);
+ fold_checksum_tree (DECL_SECTION_NAME (expr), ctx, ht);
+ fold_checksum_tree (DECL_ATTRIBUTES (expr), ctx, ht);
+ fold_checksum_tree (DECL_VINDEX (expr), ctx, ht);
+ break;
+ case 't':
+ fold_checksum_tree (TYPE_VALUES (expr), ctx, ht);
+ fold_checksum_tree (TYPE_SIZE (expr), ctx, ht);
+ fold_checksum_tree (TYPE_SIZE_UNIT (expr), ctx, ht);
+ fold_checksum_tree (TYPE_ATTRIBUTES (expr), ctx, ht);
+ fold_checksum_tree (TYPE_NAME (expr), ctx, ht);
+ fold_checksum_tree (TYPE_MIN_VALUE (expr), ctx, ht);
+ fold_checksum_tree (TYPE_MAX_VALUE (expr), ctx, ht);
+ fold_checksum_tree (TYPE_MAIN_VARIANT (expr), ctx, ht);
+ fold_checksum_tree (TYPE_BINFO (expr), ctx, ht);
+ fold_checksum_tree (TYPE_CONTEXT (expr), ctx, ht);
+ break;
+ default:
+ break;
+ }
+}
+
+#endif
+
+/* Perform constant folding and related simplification of initializer
+ expression EXPR. This behaves identically to "fold" but ignores
+ potential run-time traps and exceptions that fold must preserve. */
+
+tree
+fold_initializer (tree expr)
+{
+ int saved_signaling_nans = flag_signaling_nans;
+ int saved_trapping_math = flag_trapping_math;
+ int saved_trapv = flag_trapv;
+ tree result;
+
+ flag_signaling_nans = 0;
+ flag_trapping_math = 0;
+ flag_trapv = 0;
+
+ result = fold (expr);
+
+ flag_signaling_nans = saved_signaling_nans;
+ flag_trapping_math = saved_trapping_math;
+ flag_trapv = saved_trapv;
+
+ return result;
+}
+
/* Determine if first argument is a multiple of second argument. Return 0 if
it is not, or we cannot easily determined it to be.
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;
return rtl_expr_nonnegative_p (RTL_EXPR_RTL (t));
case CALL_EXPR:
- if (TREE_CODE (TREE_OPERAND (t, 0)) == ADDR_EXPR)
- {
- tree fndecl = TREE_OPERAND (TREE_OPERAND (t, 0), 0);
- tree arglist = TREE_OPERAND (t, 1);
- if (TREE_CODE (fndecl) == FUNCTION_DECL
- && DECL_BUILT_IN (fndecl)
- && DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_MD)
- switch (DECL_FUNCTION_CODE (fndecl))
- {
- case BUILT_IN_CABS:
- case BUILT_IN_CABSL:
- case BUILT_IN_CABSF:
- case BUILT_IN_EXP:
- case BUILT_IN_EXPF:
- case BUILT_IN_EXPL:
- case BUILT_IN_FABS:
- case BUILT_IN_FABSF:
- case BUILT_IN_FABSL:
- case BUILT_IN_SQRT:
- case BUILT_IN_SQRTF:
- case BUILT_IN_SQRTL:
- return 1;
-
- case BUILT_IN_ATAN:
- case BUILT_IN_ATANF:
- case BUILT_IN_ATANL:
- case BUILT_IN_CEIL:
- case BUILT_IN_CEILF:
- case BUILT_IN_CEILL:
- case BUILT_IN_FLOOR:
- case BUILT_IN_FLOORF:
- case BUILT_IN_FLOORL:
- case BUILT_IN_NEARBYINT:
- case BUILT_IN_NEARBYINTF:
- case BUILT_IN_NEARBYINTL:
- case BUILT_IN_ROUND:
- case BUILT_IN_ROUNDF:
- case BUILT_IN_ROUNDL:
- case BUILT_IN_TRUNC:
- case BUILT_IN_TRUNCF:
- case BUILT_IN_TRUNCL:
- return tree_expr_nonnegative_p (TREE_VALUE (arglist));
-
- case BUILT_IN_POW:
- case BUILT_IN_POWF:
- case BUILT_IN_POWL:
- return tree_expr_nonnegative_p (TREE_VALUE (arglist));
+ {
+ tree fndecl = get_callee_fndecl (t);
+ tree arglist = TREE_OPERAND (t, 1);
+ if (fndecl
+ && DECL_BUILT_IN (fndecl)
+ && DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_MD)
+ switch (DECL_FUNCTION_CODE (fndecl))
+ {
+ case BUILT_IN_CABS:
+ case BUILT_IN_CABSL:
+ case BUILT_IN_CABSF:
+ 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:
+ return 1;
+
+ case BUILT_IN_ATAN:
+ case BUILT_IN_ATANF:
+ case BUILT_IN_ATANL:
+ case BUILT_IN_CEIL:
+ case BUILT_IN_CEILF:
+ case BUILT_IN_CEILL:
+ case BUILT_IN_FLOOR:
+ case BUILT_IN_FLOORF:
+ case BUILT_IN_FLOORL:
+ case BUILT_IN_NEARBYINT:
+ case BUILT_IN_NEARBYINTF:
+ case BUILT_IN_NEARBYINTL:
+ case BUILT_IN_ROUND:
+ case BUILT_IN_ROUNDF:
+ case BUILT_IN_ROUNDL:
+ case BUILT_IN_TRUNC:
+ case BUILT_IN_TRUNCF:
+ case BUILT_IN_TRUNCL:
+ return tree_expr_nonnegative_p (TREE_VALUE (arglist));
+
+ case BUILT_IN_POW:
+ case BUILT_IN_POWF:
+ case BUILT_IN_POWL:
+ return tree_expr_nonnegative_p (TREE_VALUE (arglist));
- default:
- break;
- }
- }
+ default:
+ break;
+ }
+ }
/* ... fall through ... */