size_int takes an integer value, and creates a tree constant
with type from `sizetype'.
- force_fit_type takes a constant and prior overflow indicator, and
- forces the value to fit the type. It returns an overflow indicator. */
+ force_fit_type takes a constant, an overflowable flag and prior
+ overflow indicators. It forces the value to fit the type and sets
+ TREE_OVERFLOW and TREE_CONSTANT_OVERFLOW as appropriate. */
#include "config.h"
#include "system.h"
static tree split_tree (tree, enum tree_code, tree *, tree *, tree *, int);
static tree associate_trees (tree, tree, enum tree_code, tree);
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 build_zero_vector (tree);
static tree fold_convert_const (enum tree_code, tree, tree);
static enum tree_code invert_tree_comparison (enum tree_code, bool);
static enum comparison_code comparison_to_compcode (enum tree_code);
*hi = words[2] + words[3] * BASE;
}
\f
-/* Make the integer constant T valid for its type by setting to 0 or 1 all
- the bits in the constant that don't belong in the type.
+/* T is an INT_CST node. OVERFLOWABLE indicates if we are interested
+ in overflow of the value, when >0 we are only interested in signed
+ overflow, for <0 we are interested in any overflow. OVERFLOWED
+ indicates whether overflow has already occurred. CONST_OVERFLOWED
+ indicates whether constant overflow has already occurred. We force
+ T's value to be within range of T's type (by setting to 0 or 1 all
+ the bits outside the type's range). We set TREE_OVERFLOWED if,
+ OVERFLOWED is nonzero,
+ or OVERFLOWABLE is >0 and signed overflow occurs
+ or OVERFLOWABLE is <0 and any overflow occurs
+ We set TREE_CONSTANT_OVERFLOWED if,
+ CONST_OVERFLOWED is nonzero
+ or we set TREE_OVERFLOWED.
+ We return either the original T, or a copy. */
- Return 1 if a signed overflow occurs, 0 otherwise. If OVERFLOW is
- nonzero, a signed overflow has already occurred in calculating T, so
- propagate it. */
-
-int
-force_fit_type (tree t, int overflow)
+tree
+force_fit_type (tree t, int overflowable,
+ bool overflowed, bool overflowed_const)
{
unsigned HOST_WIDE_INT low;
HOST_WIDE_INT high;
unsigned int prec;
+ int sign_extended_type;
- if (TREE_CODE (t) == REAL_CST)
- {
- /* ??? Used to check for overflow here via CHECK_FLOAT_TYPE.
- Consider doing it via real_convert now. */
- return overflow;
- }
-
- else if (TREE_CODE (t) != INTEGER_CST)
- return overflow;
+ gcc_assert (TREE_CODE (t) == INTEGER_CST);
low = TREE_INT_CST_LOW (t);
high = TREE_INT_CST_HIGH (t);
prec = POINTER_SIZE;
else
prec = TYPE_PRECISION (TREE_TYPE (t));
+ /* Size types *are* sign extended. */
+ sign_extended_type = (!TYPE_UNSIGNED (TREE_TYPE (t))
+ || (TREE_CODE (TREE_TYPE (t)) == INTEGER_TYPE
+ && TYPE_IS_SIZETYPE (TREE_TYPE (t))));
/* First clear all bits that are beyond the type's precision. */
if (prec == 2 * HOST_BITS_PER_WIDE_INT)
;
else if (prec > HOST_BITS_PER_WIDE_INT)
- TREE_INT_CST_HIGH (t)
- &= ~((HOST_WIDE_INT) (-1) << (prec - HOST_BITS_PER_WIDE_INT));
+ high &= ~((HOST_WIDE_INT) (-1) << (prec - HOST_BITS_PER_WIDE_INT));
else
{
- TREE_INT_CST_HIGH (t) = 0;
+ high = 0;
if (prec < HOST_BITS_PER_WIDE_INT)
- TREE_INT_CST_LOW (t) &= ~((unsigned HOST_WIDE_INT) (-1) << prec);
- }
-
- /* Unsigned types do not suffer sign extension or overflow unless they
- are a sizetype. */
- if (TYPE_UNSIGNED (TREE_TYPE (t))
- && ! (TREE_CODE (TREE_TYPE (t)) == INTEGER_TYPE
- && TYPE_IS_SIZETYPE (TREE_TYPE (t))))
- return overflow;
-
- /* If the value's sign bit is set, extend the sign. */
- if (prec != 2 * HOST_BITS_PER_WIDE_INT
- && (prec > HOST_BITS_PER_WIDE_INT
- ? 0 != (TREE_INT_CST_HIGH (t)
- & ((HOST_WIDE_INT) 1
- << (prec - HOST_BITS_PER_WIDE_INT - 1)))
- : 0 != (TREE_INT_CST_LOW (t)
- & ((unsigned HOST_WIDE_INT) 1 << (prec - 1)))))
- {
- /* Value is negative:
- set to 1 all the bits that are outside this type's precision. */
- if (prec > HOST_BITS_PER_WIDE_INT)
- TREE_INT_CST_HIGH (t)
- |= ((HOST_WIDE_INT) (-1) << (prec - HOST_BITS_PER_WIDE_INT));
- else
+ low &= ~((HOST_WIDE_INT) (-1) << prec);
+ }
+
+ if (!sign_extended_type)
+ /* No sign extension */;
+ else if (prec == 2 * HOST_BITS_PER_WIDE_INT)
+ /* Correct width already. */;
+ else if (prec > HOST_BITS_PER_WIDE_INT)
+ {
+ /* Sign extend top half? */
+ if (high & ((unsigned HOST_WIDE_INT)1
+ << (prec - HOST_BITS_PER_WIDE_INT - 1)))
+ high |= (HOST_WIDE_INT) (-1) << (prec - HOST_BITS_PER_WIDE_INT);
+ }
+ else if (prec == HOST_BITS_PER_WIDE_INT)
+ {
+ if ((HOST_WIDE_INT)low < 0)
+ high = -1;
+ }
+ else
+ {
+ /* Sign extend bottom half? */
+ if (low & ((unsigned HOST_WIDE_INT)1 << (prec - 1)))
{
- TREE_INT_CST_HIGH (t) = -1;
- if (prec < HOST_BITS_PER_WIDE_INT)
- TREE_INT_CST_LOW (t) |= ((unsigned HOST_WIDE_INT) (-1) << prec);
+ high = -1;
+ low |= (HOST_WIDE_INT)(-1) << prec;
}
}
- /* Return nonzero if signed overflow occurred. */
- return
- ((overflow | (low ^ TREE_INT_CST_LOW (t)) | (high ^ TREE_INT_CST_HIGH (t)))
- != 0);
+ /* If the value changed, return a new node. */
+ if (overflowed || overflowed_const
+ || low != TREE_INT_CST_LOW (t) || high != TREE_INT_CST_HIGH (t))
+ {
+ t = build_int_cst_wide (TREE_TYPE (t), low, high);
+
+ if (overflowed
+ || overflowable < 0
+ || (overflowable > 0 && sign_extended_type))
+ {
+ t = copy_node (t);
+ TREE_OVERFLOW (t) = 1;
+ TREE_CONSTANT_OVERFLOW (t) = 1;
+ }
+ else if (overflowed_const)
+ {
+ t = copy_node (t);
+ TREE_CONSTANT_OVERFLOW (t) = 1;
+ }
+ }
+
+ return t;
}
\f
/* Add two doubleword integers with doubleword result.
break;
default:
- abort ();
+ gcc_unreachable ();
}
/* Compute true remainder: rem = num - (quo * den) */
return false;
}
+/* Check whether we may negate an integer constant T without causing
+ overflow. */
+
+bool
+may_negate_without_overflow_p (tree t)
+{
+ unsigned HOST_WIDE_INT val;
+ unsigned int prec;
+ tree type;
+
+ gcc_assert (TREE_CODE (t) == INTEGER_CST);
+
+ type = TREE_TYPE (t);
+ if (TYPE_UNSIGNED (type))
+ return false;
+
+ 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));
+}
+
/* Determine whether an expression T can be cheaply negated using
the function negate_expr. */
static bool
negate_expr_p (tree t)
{
- unsigned HOST_WIDE_INT val;
- unsigned int prec;
tree type;
if (t == 0)
return true;
/* 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));
+ return may_negate_without_overflow_p (t);
case REAL_CST:
case NEGATE_EXPR:
break;
default:
- abort ();
+ gcc_unreachable ();
}
- /* If this is for a sizetype, can be represented as one (signed)
- HOST_WIDE_INT word, and doesn't overflow, use size_int since it caches
- constants. */
- if (is_sizetype
- && ((hi == 0 && (HOST_WIDE_INT) low >= 0)
- || (hi == -1 && (HOST_WIDE_INT) low < 0))
- && overflow == 0 && ! TREE_OVERFLOW (arg1) && ! TREE_OVERFLOW (arg2))
- return size_int_type (low, type);
- else
+ t = build_int_cst_wide (TREE_TYPE (arg1), low, hi);
+
+ if (notrunc)
{
- t = build_int_2 (low, hi);
- TREE_TYPE (t) = TREE_TYPE (arg1);
- }
-
- TREE_OVERFLOW (t)
- = ((notrunc
- ? (!uns || is_sizetype) && overflow
- : (force_fit_type (t, (!uns || is_sizetype) && overflow)
- && ! no_overflow))
- | TREE_OVERFLOW (arg1)
- | TREE_OVERFLOW (arg2));
-
- /* If we're doing a size calculation, unsigned arithmetic does overflow.
- So check if force_fit_type truncated the value. */
- if (is_sizetype
- && ! TREE_OVERFLOW (t)
- && (TREE_INT_CST_HIGH (t) != hi
- || TREE_INT_CST_LOW (t) != low))
- TREE_OVERFLOW (t) = 1;
-
- TREE_CONSTANT_OVERFLOW (t) = (TREE_OVERFLOW (t)
- | TREE_CONSTANT_OVERFLOW (arg1)
- | TREE_CONSTANT_OVERFLOW (arg2));
+ /* Propagate overflow flags ourselves. */
+ if (((!uns || is_sizetype) && overflow)
+ | TREE_OVERFLOW (arg1) | TREE_OVERFLOW (arg2))
+ {
+ t = copy_node (t);
+ TREE_OVERFLOW (t) = 1;
+ TREE_CONSTANT_OVERFLOW (t) = 1;
+ }
+ else if (TREE_CONSTANT_OVERFLOW (arg1) | TREE_CONSTANT_OVERFLOW (arg2))
+ {
+ t = copy_node (t);
+ TREE_CONSTANT_OVERFLOW (t) = 1;
+ }
+ }
+ else
+ t = force_fit_type (t, 1,
+ ((!uns || is_sizetype) && overflow)
+ | TREE_OVERFLOW (arg1) | TREE_OVERFLOW (arg2),
+ TREE_CONSTANT_OVERFLOW (arg1)
+ | TREE_CONSTANT_OVERFLOW (arg2));
+
return t;
}
t = build_real (type, real_value_truncate (mode, value));
- TREE_OVERFLOW (t)
- = (force_fit_type (t, 0)
- | TREE_OVERFLOW (arg1) | TREE_OVERFLOW (arg2));
+ TREE_OVERFLOW (t) = TREE_OVERFLOW (arg1) | TREE_OVERFLOW (arg2);
TREE_CONSTANT_OVERFLOW (t)
= TREE_OVERFLOW (t)
| TREE_CONSTANT_OVERFLOW (arg1)
break;
default:
- abort ();
+ gcc_unreachable ();
}
return t;
}
return 0;
}
-/* These are the hash table functions for the hash table of INTEGER_CST
- nodes of a sizetype. */
-
-/* Return the hash code code X, an INTEGER_CST. */
-
-static hashval_t
-size_htab_hash (const void *x)
-{
- tree t = (tree) x;
-
- return (TREE_INT_CST_HIGH (t) ^ TREE_INT_CST_LOW (t)
- ^ htab_hash_pointer (TREE_TYPE (t))
- ^ (TREE_OVERFLOW (t) << 20));
-}
-
-/* Return nonzero if the value represented by *X (an INTEGER_CST tree node)
- is the same as that given by *Y, which is the same. */
-
-static int
-size_htab_eq (const void *x, const void *y)
-{
- tree xt = (tree) x;
- tree yt = (tree) y;
-
- return (TREE_INT_CST_HIGH (xt) == TREE_INT_CST_HIGH (yt)
- && TREE_INT_CST_LOW (xt) == TREE_INT_CST_LOW (yt)
- && TREE_TYPE (xt) == TREE_TYPE (yt)
- && TREE_OVERFLOW (xt) == TREE_OVERFLOW (yt));
-}
-\f
-/* Return an INTEGER_CST with value whose low-order HOST_BITS_PER_WIDE_INT
- bits are given by NUMBER and of the sizetype represented by KIND. */
+/* Create a size type INT_CST node with NUMBER sign extended. KIND
+ indicates which particular sizetype to create. */
tree
size_int_kind (HOST_WIDE_INT number, enum size_type_kind kind)
{
- return size_int_type (number, sizetype_tab[(int) kind]);
-}
-
-/* Likewise, but the desired type is specified explicitly. */
-
-static GTY (()) tree new_const;
-static GTY ((if_marked ("ggc_marked_p"), param_is (union tree_node)))
- htab_t size_htab;
-
-tree
-size_int_type (HOST_WIDE_INT number, tree type)
-{
- void **slot;
-
- if (size_htab == 0)
- {
- size_htab = htab_create_ggc (1024, size_htab_hash, size_htab_eq, NULL);
- new_const = make_node (INTEGER_CST);
- }
-
- /* Adjust NEW_CONST to be the constant we want. If it's already in the
- hash table, we return the value from the hash table. Otherwise, we
- place that in the hash table and make a new node for the next time. */
- TREE_INT_CST_LOW (new_const) = number;
- TREE_INT_CST_HIGH (new_const) = number < 0 ? -1 : 0;
- TREE_TYPE (new_const) = type;
- TREE_OVERFLOW (new_const) = TREE_CONSTANT_OVERFLOW (new_const)
- = force_fit_type (new_const, 0);
-
- slot = htab_find_slot (size_htab, new_const, INSERT);
- if (*slot == 0)
- {
- tree t = new_const;
-
- *slot = new_const;
- new_const = make_node (INTEGER_CST);
- return t;
- }
- else
- return (tree) *slot;
+ return build_int_cst (sizetype_tab[(int) kind], number);
}
-
+\f
/* Combine operands OP1 and OP2 with arithmetic operation CODE. CODE
is a tree code. The type of the result is taken from the operands.
Both must be the same type integer type and it must be a size type.
{
tree type = TREE_TYPE (arg0);
- if (TREE_CODE (type) != INTEGER_TYPE || ! TYPE_IS_SIZETYPE (type)
- || type != TREE_TYPE (arg1))
- abort ();
+ gcc_assert (TREE_CODE (type) == INTEGER_TYPE && TYPE_IS_SIZETYPE (type)
+ && type == TREE_TYPE (arg1));
/* Handle the special case of two integer constants faster. */
if (TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST)
tree type = TREE_TYPE (arg0);
tree ctype;
- if (TREE_CODE (type) != INTEGER_TYPE || ! TYPE_IS_SIZETYPE (type)
- || type != TREE_TYPE (arg1))
- abort ();
+ gcc_assert (TREE_CODE (type) == INTEGER_TYPE && TYPE_IS_SIZETYPE (type)
+ && type == TREE_TYPE (arg1));
/* If the type is already signed, just do the simple thing. */
if (!TYPE_UNSIGNED (type))
return size_binop (MINUS_EXPR, arg0, arg1);
- ctype = (type == bitsizetype || type == ubitsizetype
- ? sbitsizetype : ssizetype);
+ ctype = type == bitsizetype ? sbitsizetype : ssizetype;
/* If either operand is not a constant, do the conversions to the signed
type and subtract. The hardware will do the right thing with any
arg1, arg0)));
}
\f
+/* Construct a vector of zero elements of vector type TYPE. */
+
+static tree
+build_zero_vector (tree type)
+{
+ tree elem, list;
+ int i, units;
+
+ elem = fold_convert_const (NOP_EXPR, TREE_TYPE (type), integer_zero_node);
+ units = TYPE_VECTOR_SUBPARTS (type);
+
+ list = NULL_TREE;
+ for (i = 0; i < units; i++)
+ list = tree_cons (NULL_TREE, elem, list);
+ return build_vector (type, list);
+}
+
/* Attempt to fold type conversion operation CODE of expression ARG1 to
type TYPE. If no simplification can be done return NULL_TREE. */
if (TYPE_PRECISION (type) > 2 * HOST_BITS_PER_WIDE_INT)
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. */
- if (TREE_CODE (type) == INTEGER_TYPE && TYPE_IS_SIZETYPE (type)
- && !TREE_CONSTANT_OVERFLOW (arg1)
- && compare_tree_int (arg1, 10000) < 0)
- return size_int_type (TREE_INT_CST_LOW (arg1), type);
-
/* Given an integer constant, make new constant with new type,
appropriately sign-extended or truncated. */
- t = build_int_2 (TREE_INT_CST_LOW (arg1),
- TREE_INT_CST_HIGH (arg1));
- TREE_TYPE (t) = type;
- /* Indicate an overflow if (1) ARG1 already overflowed,
- or (2) force_fit_type indicates an overflow.
- Tell force_fit_type that an overflow has already occurred
- if ARG1 is a too-large unsigned value and T is signed.
- But don't indicate an overflow if converting a pointer. */
- TREE_OVERFLOW (t)
- = ((force_fit_type (t,
- (TREE_INT_CST_HIGH (arg1) < 0
- && (TYPE_UNSIGNED (type)
- < TYPE_UNSIGNED (TREE_TYPE (arg1)))))
- && ! POINTER_TYPE_P (TREE_TYPE (arg1)))
- || TREE_OVERFLOW (arg1));
- TREE_CONSTANT_OVERFLOW (t)
- = TREE_OVERFLOW (t) | TREE_CONSTANT_OVERFLOW (arg1);
+ t = build_int_cst_wide (type, TREE_INT_CST_LOW (arg1),
+ TREE_INT_CST_HIGH (arg1));
+
+ t = force_fit_type (t,
+ /* Don't set the overflow when
+ converting a pointer */
+ !POINTER_TYPE_P (TREE_TYPE (arg1)),
+ (TREE_INT_CST_HIGH (arg1) < 0
+ && (TYPE_UNSIGNED (type)
+ < TYPE_UNSIGNED (TREE_TYPE (arg1))))
+ | TREE_OVERFLOW (arg1),
+ TREE_CONSTANT_OVERFLOW (arg1));
return t;
}
else if (TREE_CODE (arg1) == REAL_CST)
FP-to-integer conversion is unspecified upon overflow. */
HOST_WIDE_INT high, low;
-
REAL_VALUE_TYPE r;
REAL_VALUE_TYPE x = TREE_REAL_CST (arg1);
break;
default:
- abort ();
+ gcc_unreachable ();
}
/* If R is NaN, return zero and show we have an overflow. */
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);
+ t = build_int_cst_wide (type, low, high);
+
+ t = force_fit_type (t, -1, overflow | TREE_OVERFLOW (arg1),
+ TREE_CONSTANT_OVERFLOW (arg1));
return t;
}
}
real_value_truncate (TYPE_MODE (type),
TREE_REAL_CST (arg1)));
- TREE_OVERFLOW (t)
- = TREE_OVERFLOW (arg1) | force_fit_type (t, 0);
+ TREE_OVERFLOW (t) = TREE_OVERFLOW (arg1);
TREE_CONSTANT_OVERFLOW (t)
= TREE_OVERFLOW (t) | TREE_CONSTANT_OVERFLOW (arg1);
return t;
TYPE_MAIN_VARIANT (orig)))
return fold (build1 (NOP_EXPR, type, arg));
- if (INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type)
- || TREE_CODE (type) == OFFSET_TYPE)
+ switch (TREE_CODE (type))
{
+ case INTEGER_TYPE: case CHAR_TYPE: case ENUMERAL_TYPE: case BOOLEAN_TYPE:
+ case POINTER_TYPE: case REFERENCE_TYPE:
+ case OFFSET_TYPE:
if (TREE_CODE (arg) == INTEGER_CST)
{
tem = fold_convert_const (NOP_EXPR, type, arg);
tem = fold (build1 (REALPART_EXPR, TREE_TYPE (orig), arg));
return fold_convert (type, tem);
}
- if (TREE_CODE (orig) == VECTOR_TYPE
- && tree_int_cst_equal (TYPE_SIZE (type), TYPE_SIZE (orig)))
- return fold (build1 (NOP_EXPR, type, arg));
- }
- else if (TREE_CODE (type) == REAL_TYPE)
- {
+ gcc_assert (TREE_CODE (orig) == VECTOR_TYPE
+ && tree_int_cst_equal (TYPE_SIZE (type), TYPE_SIZE (orig)));
+ return fold (build1 (NOP_EXPR, type, arg));
+
+ case REAL_TYPE:
if (TREE_CODE (arg) == INTEGER_CST)
{
tem = fold_convert_const (FLOAT_EXPR, type, arg);
return tem;
}
- if (INTEGRAL_TYPE_P (orig) || POINTER_TYPE_P (orig))
- return fold (build1 (FLOAT_EXPR, type, arg));
- if (TREE_CODE (orig) == REAL_TYPE)
- return fold (build1 (flag_float_store ? CONVERT_EXPR : NOP_EXPR,
- type, arg));
- if (TREE_CODE (orig) == COMPLEX_TYPE)
+ switch (TREE_CODE (orig))
{
+ case INTEGER_TYPE: case CHAR_TYPE:
+ case BOOLEAN_TYPE: case ENUMERAL_TYPE:
+ case POINTER_TYPE: case REFERENCE_TYPE:
+ return fold (build1 (FLOAT_EXPR, type, arg));
+
+ case REAL_TYPE:
+ return fold (build1 (flag_float_store ? CONVERT_EXPR : NOP_EXPR,
+ type, arg));
+
+ case COMPLEX_TYPE:
tem = fold (build1 (REALPART_EXPR, TREE_TYPE (orig), arg));
return fold_convert (type, tem);
+
+ default:
+ gcc_unreachable ();
}
- }
- else if (TREE_CODE (type) == COMPLEX_TYPE)
- {
- if (INTEGRAL_TYPE_P (orig)
- || POINTER_TYPE_P (orig)
- || TREE_CODE (orig) == REAL_TYPE)
- return build2 (COMPLEX_EXPR, type,
- fold_convert (TREE_TYPE (type), arg),
- fold_convert (TREE_TYPE (type), integer_zero_node));
- if (TREE_CODE (orig) == COMPLEX_TYPE)
+
+ case COMPLEX_TYPE:
+ switch (TREE_CODE (orig))
{
- tree rpart, ipart;
+ case INTEGER_TYPE: case CHAR_TYPE:
+ case BOOLEAN_TYPE: case ENUMERAL_TYPE:
+ case POINTER_TYPE: case REFERENCE_TYPE:
+ case REAL_TYPE:
+ return build2 (COMPLEX_EXPR, type,
+ fold_convert (TREE_TYPE (type), arg),
+ fold_convert (TREE_TYPE (type), integer_zero_node));
+ case COMPLEX_TYPE:
+ {
+ tree rpart, ipart;
- if (TREE_CODE (arg) == COMPLEX_EXPR)
- {
- rpart = fold_convert (TREE_TYPE (type), TREE_OPERAND (arg, 0));
- ipart = fold_convert (TREE_TYPE (type), TREE_OPERAND (arg, 1));
- return fold (build2 (COMPLEX_EXPR, type, rpart, ipart));
- }
+ if (TREE_CODE (arg) == COMPLEX_EXPR)
+ {
+ rpart = fold_convert (TREE_TYPE (type), TREE_OPERAND (arg, 0));
+ ipart = fold_convert (TREE_TYPE (type), TREE_OPERAND (arg, 1));
+ return fold (build2 (COMPLEX_EXPR, type, rpart, ipart));
+ }
- arg = save_expr (arg);
- rpart = fold (build1 (REALPART_EXPR, TREE_TYPE (orig), arg));
- ipart = fold (build1 (IMAGPART_EXPR, TREE_TYPE (orig), arg));
- rpart = fold_convert (TREE_TYPE (type), rpart);
- ipart = fold_convert (TREE_TYPE (type), ipart);
- return fold (build2 (COMPLEX_EXPR, type, rpart, ipart));
+ arg = save_expr (arg);
+ rpart = fold (build1 (REALPART_EXPR, TREE_TYPE (orig), arg));
+ ipart = fold (build1 (IMAGPART_EXPR, TREE_TYPE (orig), arg));
+ rpart = fold_convert (TREE_TYPE (type), rpart);
+ ipart = fold_convert (TREE_TYPE (type), ipart);
+ return fold (build2 (COMPLEX_EXPR, type, rpart, ipart));
+ }
+
+ default:
+ gcc_unreachable ();
}
+
+ case VECTOR_TYPE:
+ if (integer_zerop (arg))
+ return build_zero_vector (type);
+ gcc_assert (tree_int_cst_equal (TYPE_SIZE (type), TYPE_SIZE (orig)));
+ gcc_assert (INTEGRAL_TYPE_P (orig) || POINTER_TYPE_P (orig)
+ || TREE_CODE (orig) == VECTOR_TYPE);
+ return fold (build1 (NOP_EXPR, type, arg));
+
+ case VOID_TYPE:
+ return fold (build1 (CONVERT_EXPR, type, fold_ignored_result (arg)));
+
+ default:
+ gcc_unreachable ();
}
- else if (TREE_CODE (type) == VECTOR_TYPE)
- {
- if ((INTEGRAL_TYPE_P (orig) || POINTER_TYPE_P (orig))
- && tree_int_cst_equal (TYPE_SIZE (type), TYPE_SIZE (orig)))
- return fold (build1 (NOP_EXPR, type, arg));
- if (TREE_CODE (orig) == VECTOR_TYPE
- && tree_int_cst_equal (TYPE_SIZE (type), TYPE_SIZE (orig)))
- return fold (build1 (NOP_EXPR, type, arg));
- }
- else if (VOID_TYPE_P (type))
- return fold (build1 (CONVERT_EXPR, type, fold_ignored_result (arg)));
- abort ();
}
\f
/* Return an expr equal to X but certainly not valid as an lvalue. */
case COMPONENT_REF:
case INDIRECT_REF:
+ case ALIGN_INDIRECT_REF:
+ case MISALIGNED_INDIRECT_REF:
case ARRAY_REF:
case ARRAY_RANGE_REF:
case BIT_FIELD_REF:
case UNORDERED_EXPR:
return ORDERED_EXPR;
default:
- abort ();
+ gcc_unreachable ();
}
}
case LE_EXPR:
return GE_EXPR;
default:
- abort ();
+ gcc_unreachable ();
}
}
case UNGE_EXPR:
return COMPCODE_UNGE;
default:
- abort ();
+ gcc_unreachable ();
}
}
case COMPCODE_UNGE:
return UNGE_EXPR;
default:
- abort ();
+ gcc_unreachable ();
}
}
static int
truth_value_p (enum tree_code code)
{
- return (TREE_CODE_CLASS (code) == '<'
+ return (TREE_CODE_CLASS (code) == tcc_comparison
|| code == TRUTH_AND_EXPR || code == TRUTH_ANDIF_EXPR
|| code == TRUTH_OR_EXPR || code == TRUTH_ORIF_EXPR
|| code == TRUTH_XOR_EXPR || code == TRUTH_NOT_EXPR);
switch (TREE_CODE_CLASS (TREE_CODE (arg0)))
{
- case '1':
+ case tcc_unary:
/* Two conversions are equal only if signedness and modes match. */
- if ((TREE_CODE (arg0) == NOP_EXPR || TREE_CODE (arg0) == CONVERT_EXPR)
- && (TYPE_UNSIGNED (TREE_TYPE (arg0))
- != TYPE_UNSIGNED (TREE_TYPE (arg1))))
- return 0;
+ switch (TREE_CODE (arg0))
+ {
+ case NOP_EXPR:
+ case CONVERT_EXPR:
+ case FIX_CEIL_EXPR:
+ case FIX_TRUNC_EXPR:
+ case FIX_FLOOR_EXPR:
+ case FIX_ROUND_EXPR:
+ if (TYPE_UNSIGNED (TREE_TYPE (arg0))
+ != TYPE_UNSIGNED (TREE_TYPE (arg1)))
+ return 0;
+ break;
+ default:
+ break;
+ }
return operand_equal_p (TREE_OPERAND (arg0, 0),
TREE_OPERAND (arg1, 0), flags);
- case '<':
- case '2':
+ case tcc_comparison:
+ case tcc_binary:
if (operand_equal_p (TREE_OPERAND (arg0, 0),
TREE_OPERAND (arg1, 0), flags)
&& operand_equal_p (TREE_OPERAND (arg0, 1),
&& operand_equal_p (TREE_OPERAND (arg0, 1),
TREE_OPERAND (arg1, 0), flags));
- case 'r':
+ case tcc_reference:
/* If either of the pointer (or reference) expressions we are
dereferencing contain a side effect, these cannot be equal. */
if (TREE_SIDE_EFFECTS (arg0)
switch (TREE_CODE (arg0))
{
case INDIRECT_REF:
+ case ALIGN_INDIRECT_REF:
+ case MISALIGNED_INDIRECT_REF:
case REALPART_EXPR:
case IMAGPART_EXPR:
return operand_equal_p (TREE_OPERAND (arg0, 0),
return 0;
}
- case 'e':
+ case tcc_expression:
switch (TREE_CODE (arg0))
{
case ADDR_EXPR:
return 0;
}
- case 'd':
+ case tcc_declaration:
/* Consider __builtin_sqrt equal to sqrt. */
return (TREE_CODE (arg0) == FUNCTION_DECL
&& DECL_BUILT_IN (arg0) && DECL_BUILT_IN (arg1)
twoval_comparison_p (tree arg, tree *cval1, tree *cval2, int *save_p)
{
enum tree_code code = TREE_CODE (arg);
- char class = TREE_CODE_CLASS (code);
+ enum tree_code_class class = TREE_CODE_CLASS (code);
- /* We can handle some of the 'e' cases here. */
- if (class == 'e' && code == TRUTH_NOT_EXPR)
- class = '1';
- else if (class == 'e'
+ /* We can handle some of the tcc_expression cases here. */
+ if (class == tcc_expression && code == TRUTH_NOT_EXPR)
+ class = tcc_unary;
+ else if (class == tcc_expression
&& (code == TRUTH_ANDIF_EXPR || code == TRUTH_ORIF_EXPR
|| code == COMPOUND_EXPR))
- class = '2';
+ class = tcc_binary;
- else if (class == 'e' && code == SAVE_EXPR
+ else if (class == tcc_expression && code == SAVE_EXPR
&& ! TREE_SIDE_EFFECTS (TREE_OPERAND (arg, 0)))
{
/* If we've already found a CVAL1 or CVAL2, this expression is
if (*cval1 || *cval2)
return 0;
- class = '1';
+ class = tcc_unary;
*save_p = 1;
}
switch (class)
{
- case '1':
+ case tcc_unary:
return twoval_comparison_p (TREE_OPERAND (arg, 0), cval1, cval2, save_p);
- case '2':
+ case tcc_binary:
return (twoval_comparison_p (TREE_OPERAND (arg, 0), cval1, cval2, save_p)
&& twoval_comparison_p (TREE_OPERAND (arg, 1),
cval1, cval2, save_p));
- case 'c':
+ case tcc_constant:
return 1;
- case 'e':
+ case tcc_expression:
if (code == COND_EXPR)
return (twoval_comparison_p (TREE_OPERAND (arg, 0),
cval1, cval2, save_p)
cval1, cval2, save_p));
return 0;
- case '<':
+ case tcc_comparison:
/* First see if we can handle the first operand, then the second. For
the second operand, we know *CVAL1 can't be zero. It must be that
one side of the comparison is each of the values; test for the
{
tree type = TREE_TYPE (arg);
enum tree_code code = TREE_CODE (arg);
- char class = TREE_CODE_CLASS (code);
+ enum tree_code_class class = TREE_CODE_CLASS (code);
- /* We can handle some of the 'e' cases here. */
- if (class == 'e' && code == TRUTH_NOT_EXPR)
- class = '1';
- else if (class == 'e'
+ /* We can handle some of the tcc_expression cases here. */
+ if (class == tcc_expression && code == TRUTH_NOT_EXPR)
+ class = tcc_unary;
+ else if (class == tcc_expression
&& (code == TRUTH_ANDIF_EXPR || code == TRUTH_ORIF_EXPR))
- class = '2';
+ class = tcc_binary;
switch (class)
{
- case '1':
+ case tcc_unary:
return fold (build1 (code, type,
eval_subst (TREE_OPERAND (arg, 0),
old0, new0, old1, new1)));
- case '2':
+ case tcc_binary:
return fold (build2 (code, type,
eval_subst (TREE_OPERAND (arg, 0),
old0, new0, old1, new1),
eval_subst (TREE_OPERAND (arg, 1),
old0, new0, old1, new1)));
- case 'e':
+ case tcc_expression:
switch (code)
{
case SAVE_EXPR:
}
/* Fall through - ??? */
- case '<':
+ case tcc_comparison:
{
tree arg0 = TREE_OPERAND (arg, 0);
tree arg1 = TREE_OPERAND (arg, 1);
floating-point non-equality comparisons, in which case we just
enclose a TRUTH_NOT_EXPR around what we have. */
- if (TREE_CODE_CLASS (code) == '<')
+ if (TREE_CODE_CLASS (code) == tcc_comparison)
{
tree op_type = TREE_TYPE (TREE_OPERAND (arg, 0));
if (FLOAT_TYPE_P (op_type)
switch (code)
{
case INTEGER_CST:
- return fold_convert (type, build_int_2 (integer_zerop (arg), 0));
+ return fold_convert (type,
+ build_int_cst (NULL_TREE, integer_zerop (arg)));
case TRUTH_AND_EXPR:
return build2 (TRUTH_OR_EXPR, type,
default:
break;
}
- if (TREE_CODE (TREE_TYPE (arg)) != BOOLEAN_TYPE)
- abort ();
+ gcc_assert (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE);
return build1 (TRUTH_NOT_EXPR, type, arg);
}
lbitpos = nbitsize - lbitsize - lbitpos;
/* Make the mask to be used against the extracted field. */
- mask = build_int_2 (~0, ~0);
- TREE_TYPE (mask) = unsigned_type;
- force_fit_type (mask, 0);
+ mask = build_int_cst (unsigned_type, -1);
+ mask = force_fit_type (mask, 0, false, false);
mask = fold_convert (unsigned_type, mask);
mask = const_binop (LSHIFT_EXPR, mask, size_int (nbitsize - lbitsize), 0);
mask = const_binop (RSHIFT_EXPR, mask,
unsigned_type = lang_hooks.types.type_for_size (*pbitsize, 1);
precision = TYPE_PRECISION (unsigned_type);
- mask = build_int_2 (~0, ~0);
- TREE_TYPE (mask) = unsigned_type;
- force_fit_type (mask, 0);
+ mask = build_int_cst (unsigned_type, -1);
+ mask = force_fit_type (mask, 0, false, false);
+
mask = const_binop (LSHIFT_EXPR, mask, size_int (precision - *pbitsize), 0);
mask = const_binop (RSHIFT_EXPR, mask, size_int (precision - *pbitsize), 0);
unsigned int precision = TYPE_PRECISION (type);
tree tmask;
- tmask = build_int_2 (~0, ~0);
- TREE_TYPE (tmask) = lang_hooks.types.signed_type (type);
- force_fit_type (tmask, 0);
+ tmask = build_int_cst (lang_hooks.types.signed_type (type), -1);
+ tmask = force_fit_type (tmask, 0, false, false);
+
return
tree_int_cst_equal (mask,
const_binop (RSHIFT_EXPR,
== TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)))))
exp = TREE_OPERAND (exp, 0);
- return (TREE_CODE_CLASS (TREE_CODE (exp)) == 'c'
+ return (CONSTANT_CLASS_P (exp)
|| (DECL_P (exp)
&& ! TREE_ADDRESSABLE (exp)
&& ! TREE_THIS_VOLATILE (exp)
return TREE_CODE (tem) == INTEGER_CST ? tem : 0;
}
- if (TREE_CODE_CLASS (code) != '<')
+ if (TREE_CODE_CLASS (code) != tcc_comparison)
return 0;
/* Set SGN[01] to -1 if ARG[01] is a lower bound, 1 for upper, and 0
result = sgn0 >= sgn1;
break;
default:
- abort ();
+ gcc_unreachable ();
}
return constant_boolean_node (result, type);
{
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')
+ if (TREE_CODE_CLASS (code) == tcc_comparison
+ || TREE_CODE_CLASS (code) == tcc_unary
+ || TREE_CODE_CLASS (code) == tcc_binary)
arg0_type = TREE_TYPE (arg0);
- if (TREE_CODE_CLASS (code) == '2'
- || TREE_CODE_CLASS (code) == '<'
- || (TREE_CODE_CLASS (code) == 'e'
+ if (TREE_CODE_CLASS (code) == tcc_binary
+ || TREE_CODE_CLASS (code) == tcc_comparison
+ || (TREE_CODE_CLASS (code) == tcc_expression
&& TREE_CODE_LENGTH (code) > 1))
arg1 = TREE_OPERAND (exp, 1);
}
in_p = ! in_p, low = 0, high = arg1;
break;
default:
- abort ();
+ gcc_unreachable ();
}
/* If this is an unsigned comparison, we also know that EXP is
switch (comp_code)
{
case EQ_EXPR:
+ case UNEQ_EXPR:
tem = fold_convert (arg1_type, arg1);
return pedantic_non_lvalue (fold_convert (type, negate_expr (tem)));
case NE_EXPR:
+ case LTGT_EXPR:
return pedantic_non_lvalue (fold_convert (type, arg1));
+ case UNGE_EXPR:
+ case UNGT_EXPR:
+ if (flag_trapping_math)
+ break;
+ /* Fall through. */
case GE_EXPR:
case GT_EXPR:
if (TYPE_UNSIGNED (TREE_TYPE (arg1)))
(TREE_TYPE (arg1)), arg1);
tem = fold (build1 (ABS_EXPR, TREE_TYPE (arg1), arg1));
return pedantic_non_lvalue (fold_convert (type, tem));
+ case UNLE_EXPR:
+ case UNLT_EXPR:
+ if (flag_trapping_math)
+ break;
case LE_EXPR:
case LT_EXPR:
if (TYPE_UNSIGNED (TREE_TYPE (arg1)))
tem = fold (build1 (ABS_EXPR, TREE_TYPE (arg1), arg1));
return negate_expr (fold_convert (type, tem));
default:
- abort ();
+ gcc_assert (TREE_CODE_CLASS (comp_code) == tcc_comparison);
+ break;
}
/* A != 0 ? A : 0 is simply A, unless A is -0. Likewise
return pedantic_non_lvalue (fold_convert (type, arg1));
case LE_EXPR:
case LT_EXPR:
+ case UNLE_EXPR:
+ case UNLT_EXPR:
/* In C++ a ?: expression can be an lvalue, so put the
operand which will be used if they are equal first
so that we can convert this back to the
{
comp_op0 = fold_convert (comp_type, comp_op0);
comp_op1 = fold_convert (comp_type, comp_op1);
- tem = fold (build2 (MIN_EXPR, comp_type,
- (comp_code == LE_EXPR
- ? comp_op0 : comp_op1),
- (comp_code == LE_EXPR
- ? comp_op1 : comp_op0)));
+ tem = (comp_code == LE_EXPR || comp_code == UNLE_EXPR)
+ ? fold (build2 (MIN_EXPR, comp_type, comp_op0, comp_op1))
+ : fold (build2 (MIN_EXPR, comp_type, comp_op1, comp_op0));
return pedantic_non_lvalue (fold_convert (type, tem));
}
break;
case GE_EXPR:
case GT_EXPR:
+ case UNGE_EXPR:
+ case UNGT_EXPR:
if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (arg1))))
{
comp_op0 = fold_convert (comp_type, comp_op0);
comp_op1 = fold_convert (comp_type, comp_op1);
- tem = fold (build2 (MAX_EXPR, comp_type,
- (comp_code == GE_EXPR
- ? comp_op0 : comp_op1),
- (comp_code == GE_EXPR
- ? comp_op1 : comp_op0)));
- tem = fold (build2 (MAX_EXPR, comp_type, comp_op0, comp_op1));
+ tem = (comp_code == GE_EXPR || comp_code == UNGE_EXPR)
+ ? fold (build2 (MAX_EXPR, comp_type, comp_op0, comp_op1))
+ : fold (build2 (MAX_EXPR, comp_type, comp_op1, comp_op0));
return pedantic_non_lvalue (fold_convert (type, tem));
}
break;
+ case UNEQ_EXPR:
+ if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (arg1))))
+ return pedantic_non_lvalue (fold_convert (type, arg2));
+ break;
+ case LTGT_EXPR:
+ if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (arg1))))
+ return pedantic_non_lvalue (fold_convert (type, arg1));
+ break;
default:
- abort ();
+ gcc_assert (TREE_CODE_CLASS (comp_code) == tcc_comparison);
+ break;
}
}
case NE_EXPR:
break;
default:
- abort ();
+ gcc_unreachable ();
}
return NULL_TREE;
rcode = NE_EXPR;
}
- if (TREE_CODE_CLASS (lcode) != '<' || TREE_CODE_CLASS (rcode) != '<')
+ if (TREE_CODE_CLASS (lcode) != tcc_comparison
+ || TREE_CODE_CLASS (rcode) != tcc_comparison)
return 0;
ll_arg = TREE_OPERAND (lhs, 0);
{
if (wanted_code == NE_EXPR)
{
- warning ("`or' of unmatched not-equal tests is always 1");
+ warning ("%<or%> of unmatched not-equal tests is always 1");
return constant_boolean_node (true, truth_type);
}
else
{
- warning ("`and' of mutually exclusive equal-tests is always 0");
+ warning ("%<and%> of mutually exclusive equal-tests is always 0");
return constant_boolean_node (false, truth_type);
}
}
if (integer_zerop (c))
return NULL_TREE;
- if (TREE_CODE_CLASS (tcode) == '1')
+ if (TREE_CODE_CLASS (tcode) == tcc_unary)
op0 = TREE_OPERAND (t, 0);
- if (TREE_CODE_CLASS (tcode) == '2')
+ if (TREE_CODE_CLASS (tcode) == tcc_binary)
op0 = TREE_OPERAND (t, 0), op1 = TREE_OPERAND (t, 1);
/* Note that we need not handle conditional operations here since fold
case CONVERT_EXPR: case NON_LVALUE_EXPR: case NOP_EXPR:
/* If op0 is an expression ... */
- if ((TREE_CODE_CLASS (TREE_CODE (op0)) == '<'
- || TREE_CODE_CLASS (TREE_CODE (op0)) == '1'
- || TREE_CODE_CLASS (TREE_CODE (op0)) == '2'
- || TREE_CODE_CLASS (TREE_CODE (op0)) == 'e')
+ if ((COMPARISON_CLASS_P (op0)
+ || UNARY_CLASS_P (op0)
+ || BINARY_CLASS_P (op0)
+ || EXPRESSION_CLASS_P (op0))
/* ... and is unsigned, and its type is smaller than ctype,
then we cannot pass through as widening. */
&& ((TYPE_UNSIGNED (TREE_TYPE (op0))
&& TYPE_IS_SIZETYPE (TREE_TYPE (op0)))
&& (GET_MODE_SIZE (TYPE_MODE (ctype))
> GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op0)))))
- /* ... or its type is larger than ctype,
- then we cannot pass through this truncation. */
- || (GET_MODE_SIZE (TYPE_MODE (ctype))
+ /* ... or this is a truncation (t is narrower than op0),
+ then we cannot pass through this narrowing. */
+ || (GET_MODE_SIZE (TYPE_MODE (type))
< GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op0))))
/* ... or signedness changes for division or modulus,
then we cannot pass through this conversion. */
return lang_hooks.truthvalue_conversion (value ? integer_one_node
: integer_zero_node);
else
- {
- tree t = build_int_2 (value, 0);
-
- TREE_TYPE (t) = type;
- return t;
- }
+ return build_int_cst (type, value);
}
/* Transform `a + (b ? x : y)' into `b ? (a + x) : (a + y)'.
TREE_INT_CST_HIGH (arg01),
TREE_INT_CST_LOW (arg1),
TREE_INT_CST_HIGH (arg1), &lpart, &hpart);
- prod = build_int_2 (lpart, hpart);
- TREE_TYPE (prod) = TREE_TYPE (arg00);
- TREE_OVERFLOW (prod) = force_fit_type (prod, overflow)
- || TREE_INT_CST_HIGH (prod) != hpart
- || TREE_INT_CST_LOW (prod) != lpart;
- TREE_CONSTANT_OVERFLOW (prod) = TREE_OVERFLOW (prod);
+ prod = build_int_cst_wide (TREE_TYPE (arg00), lpart, hpart);
+ prod = force_fit_type (prod, -1, overflow, false);
if (TYPE_UNSIGNED (TREE_TYPE (arg0)))
{
TREE_INT_CST_LOW (tmp),
TREE_INT_CST_HIGH (tmp),
&lpart, &hpart);
- hi = build_int_2 (lpart, hpart);
- TREE_TYPE (hi) = TREE_TYPE (arg00);
- TREE_OVERFLOW (hi) = force_fit_type (hi, overflow)
- || TREE_INT_CST_HIGH (hi) != hpart
- || TREE_INT_CST_LOW (hi) != lpart
- || TREE_OVERFLOW (prod);
- TREE_CONSTANT_OVERFLOW (hi) = TREE_OVERFLOW (hi);
+ hi = build_int_cst_wide (TREE_TYPE (arg00), lpart, hpart);
+ hi = force_fit_type (hi, -1, overflow | TREE_OVERFLOW (prod),
+ TREE_CONSTANT_OVERFLOW (prod));
}
else if (tree_int_cst_sgn (arg01) >= 0)
{
break;
default:
- abort ();
+ gcc_unreachable ();
}
}
else
break;
default:
- abort ();
+ gcc_unreachable ();
}
}
reorder_operands_p (tree arg0, tree arg1)
{
if (! flag_evaluation_order)
- return true;
+ return true;
if (TREE_CONSTANT (arg0) || TREE_CONSTANT (arg1))
return true;
return ! TREE_SIDE_EFFECTS (arg0)
if (DECL_P (arg0))
return 1;
- if (reorder && flag_evaluation_order
- && (TREE_SIDE_EFFECTS (arg0) || TREE_SIDE_EFFECTS (arg1)))
- return 0;
-
- if (DECL_P (arg1))
- return 0;
- if (DECL_P (arg0))
- return 1;
-
/* It is preferable to swap two SSA_NAME to ensure a canonical form
for commutative and comparison operators. Ensuring a canonical
form allows the optimizers to find additional redundancies without
tree tem;
tree arg0 = NULL_TREE, arg1 = NULL_TREE;
enum tree_code code = TREE_CODE (t);
- int kind = TREE_CODE_CLASS (code);
+ enum tree_code_class kind = TREE_CODE_CLASS (code);
/* WINS will be nonzero when the switch is done
if all operands are constant. */
int wins = 1;
/* Return right away if a constant. */
- if (kind == 'c')
+ if (kind == tcc_constant)
return t;
if (code == NOP_EXPR || code == FLOAT_EXPR || code == CONVERT_EXPR)
of the arguments so that their form can be studied. In any
cases, the appropriate type conversions should be put back in
the tree that will get out of the constant folder. */
- if (kind == '<')
+ if (kind == tcc_comparison)
STRIP_SIGN_NOPS (op);
else
STRIP_NOPS (op);
return tem;
}
- if (TREE_CODE_CLASS (code) == '1')
+ if (TREE_CODE_CLASS (code) == tcc_unary)
{
if (TREE_CODE (arg0) == COMPOUND_EXPR)
return build2 (COMPOUND_EXPR, type, TREE_OPERAND (arg0, 0),
TREE_OPERAND (TREE_OPERAND (tem, 2), 0)));
return tem;
}
- else if (TREE_CODE_CLASS (TREE_CODE (arg0)) == '<')
+ else if (COMPARISON_CLASS_P (arg0))
{
if (TREE_CODE (type) == BOOLEAN_TYPE)
{
integer_zero_node))));
}
}
- else if (TREE_CODE_CLASS (code) == '<'
+ else if (TREE_CODE_CLASS (code) == tcc_comparison
&& TREE_CODE (arg0) == COMPOUND_EXPR)
return build2 (COMPOUND_EXPR, type, TREE_OPERAND (arg0, 0),
fold (build2 (code, type, TREE_OPERAND (arg0, 1), arg1)));
- else if (TREE_CODE_CLASS (code) == '<'
+ else if (TREE_CODE_CLASS (code) == tcc_comparison
&& TREE_CODE (arg1) == COMPOUND_EXPR)
return build2 (COMPOUND_EXPR, type, TREE_OPERAND (arg1, 0),
fold (build2 (code, type, arg0, TREE_OPERAND (arg1, 1))));
- else if (TREE_CODE_CLASS (code) == '2'
- || TREE_CODE_CLASS (code) == '<')
+ else if (TREE_CODE_CLASS (code) == tcc_binary
+ || TREE_CODE_CLASS (code) == tcc_comparison)
{
if (TREE_CODE (arg0) == COMPOUND_EXPR)
return build2 (COMPOUND_EXPR, type, TREE_OPERAND (arg0, 0),
fold (build2 (code, type,
arg0, TREE_OPERAND (arg1, 1))));
- if (TREE_CODE (arg0) == COND_EXPR
- || TREE_CODE_CLASS (TREE_CODE (arg0)) == '<')
+ if (TREE_CODE (arg0) == COND_EXPR || COMPARISON_CLASS_P (arg0))
{
tem = fold_binary_op_with_conditional_arg (code, type, arg0, arg1,
/*cond_first_p=*/1);
return tem;
}
- if (TREE_CODE (arg1) == COND_EXPR
- || TREE_CODE_CLASS (TREE_CODE (arg1)) == '<')
+ if (TREE_CODE (arg1) == COND_EXPR || COMPARISON_CLASS_P (arg1))
{
tem = fold_binary_op_with_conditional_arg (code, type, arg1, arg0,
/*cond_first_p=*/0);
/* Convert (T1)((T2)X op Y) into (T1)X op Y, for pointer types T1 and
T2 being pointers to types of the same size. */
if (POINTER_TYPE_P (TREE_TYPE (t))
- && TREE_CODE_CLASS (TREE_CODE (arg0)) == '2'
+ && BINARY_CLASS_P (arg0)
&& TREE_CODE (TREE_OPERAND (arg0, 0)) == NOP_EXPR
&& POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (arg0, 0))))
{
if (exact_log2 (int11) > 0 && int01 % int11 == 0)
{
alt0 = fold (build2 (MULT_EXPR, type, arg00,
- build_int_2 (int01 / int11, 0)));
+ build_int_cst (NULL_TREE,
+ int01 / int11)));
alt1 = arg10;
same = arg11;
}
TREE_OPERAND (arg0, 0),
build_real (type, c1)));
}
- /* Convert a + (b*c + d*e) into (a + b*c) + d*e */
+ /* Convert a + (b*c + d*e) into (a + b*c) + d*e. */
if (flag_unsafe_math_optimizations
&& TREE_CODE (arg1) == PLUS_EXPR
&& TREE_CODE (arg0) != MULT_EXPR)
return fold (build2 (PLUS_EXPR, type, tree0, tree11));
}
}
- /* Convert (b*c + d*e) + a into b*c + (d*e +a) */
+ /* Convert (b*c + d*e) + a into b*c + (d*e +a). */
if (flag_unsafe_math_optimizations
&& TREE_CODE (arg0) == PLUS_EXPR
&& TREE_CODE (arg1) != MULT_EXPR)
|| (INTEGRAL_TYPE_P (type) && flag_wrapv && !flag_trapv)))
return fold (build2 (PLUS_EXPR, type, arg0, negate_expr (arg1)));
+ /* Try folding difference of addresses. */
+ {
+ HOST_WIDE_INT diff;
+
+ if (TREE_CODE (arg0) == ADDR_EXPR
+ && TREE_CODE (arg1) == ADDR_EXPR
+ && ptr_difference_const (TREE_OPERAND (arg0, 0),
+ TREE_OPERAND (arg1, 0),
+ &diff))
+ return build_int_cst_type (type, diff);
+ }
+
if (TREE_CODE (arg0) == MULT_EXPR
&& TREE_CODE (arg1) == MULT_EXPR
&& (INTEGRAL_TYPE_P (type) || flag_unsafe_math_optimizations))
if (TREE_CODE (arg0) == BIT_NOT_EXPR
&& operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0))
{
- t1 = build_int_2 (-1, -1);
- TREE_TYPE (t1) = type;
- force_fit_type (t1, 0);
+ t1 = build_int_cst (type, -1);
+ t1 = force_fit_type (t1, 0, false, false);
return omit_one_operand (type, t1, arg1);
}
if (TREE_CODE (arg1) == BIT_NOT_EXPR
&& operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0))
{
- t1 = build_int_2 (-1, -1);
- TREE_TYPE (t1) = type;
- force_fit_type (t1, 0);
+ t1 = build_int_cst (type, -1);
+ t1 = force_fit_type (t1, 0, false, false);
return omit_one_operand (type, t1, arg0);
}
if (TREE_CODE (arg0) == BIT_NOT_EXPR
&& operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0))
{
- t1 = build_int_2 (-1, -1);
- TREE_TYPE (t1) = type;
- force_fit_type (t1, 0);
+ t1 = build_int_cst (type, -1);
+ t1 = force_fit_type (t1, 0, false, false);
return omit_one_operand (type, t1, arg1);
}
if (TREE_CODE (arg1) == BIT_NOT_EXPR
&& operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0))
{
- t1 = build_int_2 (-1, -1);
- TREE_TYPE (t1) = type;
- force_fit_type (t1, 0);
+ t1 = build_int_cst (type, -1);
+ t1 = force_fit_type (t1, 0, false, false);
return omit_one_operand (type, t1, arg0);
}
low = ((unsigned HOST_WIDE_INT) 1 << l) - 1;
}
- mask = build_int_2 (low, high);
- TREE_TYPE (mask) = type;
+ mask = build_int_cst_wide (type, low, high);
return fold (build2 (BIT_AND_EXPR, type,
fold_convert (type, arg0), mask));
}
- /* X % -C is the same as X % C (for all rounding moduli). */
- if (!TYPE_UNSIGNED (type)
+ /* X % -C is the same as X % C. */
+ if (code == TRUNC_MOD_EXPR
+ && !TYPE_UNSIGNED (type)
&& TREE_CODE (arg1) == INTEGER_CST
&& TREE_INT_CST_HIGH (arg1) < 0
&& !flag_trapv
return fold (build2 (code, type, fold_convert (type, arg0),
fold_convert (type, negate_expr (arg1))));
- /* X % -Y is the same as X % Y (for all rounding moduli). */
- if (!TYPE_UNSIGNED (type)
+ /* X % -Y is the same as X % Y. */
+ if (code == TRUNC_MOD_EXPR
+ && !TYPE_UNSIGNED (type)
&& TREE_CODE (arg1) == NEGATE_EXPR
&& !flag_trapv)
return fold (build2 (code, type, fold_convert (type, arg0),
RROTATE_EXPR by a new constant. */
if (code == LROTATE_EXPR && TREE_CODE (arg1) == INTEGER_CST)
{
- tree tem = build_int_2 (GET_MODE_BITSIZE (TYPE_MODE (type)), 0);
+ tree tem = build_int_cst (NULL_TREE,
+ GET_MODE_BITSIZE (TYPE_MODE (type)));
tem = fold_convert (TREE_TYPE (arg1), tem);
tem = const_binop (MINUS_EXPR, tem, arg1, 0);
return fold (build2 (RROTATE_EXPR, type, arg0, tem));
|| integer_onep (folded_compare))
return omit_one_operand (type, folded_compare, varop);
- shift = build_int_2 (TYPE_PRECISION (TREE_TYPE (varop)) - size,
- 0);
+ shift = build_int_cst (NULL_TREE,
+ TYPE_PRECISION (TREE_TYPE (varop)) - size);
shift = fold_convert (TREE_TYPE (varop), shift);
newconst = fold (build2 (LSHIFT_EXPR, TREE_TYPE (varop),
newconst, shift));
&& (t1 = get_unwidened (arg1, TREE_TYPE (tem))) != 0
&& (TREE_TYPE (t1) == TREE_TYPE (tem)
|| (TREE_CODE (t1) == INTEGER_CST
+ && TREE_CODE (TREE_TYPE (tem)) == INTEGER_TYPE
&& int_fits_type_p (t1, TREE_TYPE (tem)))))
return fold (build2 (code, type, tem,
fold_convert (TREE_TYPE (tem), t1)));
&& TREE_CODE (arg1) == INTEGER_CST
&& TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
{
- tree dandnotc
- = fold (build2 (BIT_AND_EXPR, TREE_TYPE (arg0),
- arg1, build1 (BIT_NOT_EXPR,
- TREE_TYPE (TREE_OPERAND (arg0, 1)),
- TREE_OPERAND (arg0, 1))));
+ tree notc = fold (build1 (BIT_NOT_EXPR,
+ TREE_TYPE (TREE_OPERAND (arg0, 1)),
+ TREE_OPERAND (arg0, 1)));
+ tree dandnotc = fold (build2 (BIT_AND_EXPR, TREE_TYPE (arg0),
+ arg1, notc));
tree rslt = code == EQ_EXPR ? integer_zero_node : integer_one_node;
if (integer_nonzerop (dandnotc))
return omit_one_operand (type, rslt, arg0);
&& TREE_CODE (arg1) == INTEGER_CST
&& TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
{
- tree candnotd
- = fold (build2 (BIT_AND_EXPR, TREE_TYPE (arg0),
- TREE_OPERAND (arg0, 1),
- build1 (BIT_NOT_EXPR, TREE_TYPE (arg1), arg1)));
+ tree notd = fold (build1 (BIT_NOT_EXPR, TREE_TYPE (arg1), arg1));
+ tree candnotd = fold (build2 (BIT_AND_EXPR, TREE_TYPE (arg0),
+ TREE_OPERAND (arg0, 1), notd));
tree rslt = code == EQ_EXPR ? integer_zero_node : integer_one_node;
if (integer_nonzerop (candnotd))
return omit_one_operand (type, rslt, arg0);
case LT_EXPR:
return constant_boolean_node (0, type);
default:
- abort ();
+ gcc_unreachable ();
}
}
for reasons given above each one.
Also try swapping the arguments and inverting the conditional. */
- if (TREE_CODE_CLASS (TREE_CODE (arg0)) == '<'
+ if (COMPARISON_CLASS_P (arg0)
&& operand_equal_for_comparison_p (TREE_OPERAND (arg0, 0),
arg1, TREE_OPERAND (arg0, 1))
&& !HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (arg1))))
return tem;
}
- if (TREE_CODE_CLASS (TREE_CODE (arg0)) == '<'
+ if (COMPARISON_CLASS_P (arg0)
&& operand_equal_for_comparison_p (TREE_OPERAND (arg0, 0),
TREE_OPERAND (t, 2),
TREE_OPERAND (arg0, 1))
&& !HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (TREE_OPERAND (t, 2)))))
{
tem = invert_truthvalue (arg0);
- if (TREE_CODE_CLASS (TREE_CODE (tem)) == '<')
+ if (COMPARISON_CLASS_P (tem))
{
tem = fold_cond_expr_with_comparison (type, tem,
TREE_OPERAND (t, 2),
tree tem = TREE_OPERAND (arg0, 0);
STRIP_NOPS (tem);
if (TREE_CODE (tem) == RSHIFT_EXPR
+ && TREE_CODE (TREE_OPERAND (tem, 1)) == INTEGER_CST
&& (unsigned HOST_WIDE_INT) tree_log2 (arg1) ==
TREE_INT_CST_LOW (TREE_OPERAND (tem, 1)))
return fold (build2 (BIT_AND_EXPR, type,
TREE_OPERAND (arg0, 1)))));
return t;
- /* Pull arithmetic ops out of the CLEANUP_POINT_EXPR where
- appropriate. */
- case CLEANUP_POINT_EXPR:
- if (! has_cleanups (arg0))
- return TREE_OPERAND (t, 0);
-
- {
- enum tree_code code0 = TREE_CODE (arg0);
- int kind0 = TREE_CODE_CLASS (code0);
- tree arg00 = TREE_OPERAND (arg0, 0);
- tree arg01;
-
- if (kind0 == '1' || code0 == TRUTH_NOT_EXPR)
- return fold (build1 (code0, type,
- fold (build1 (CLEANUP_POINT_EXPR,
- TREE_TYPE (arg00), arg00))));
-
- if (kind0 == '<' || kind0 == '2'
- || code0 == TRUTH_ANDIF_EXPR || code0 == TRUTH_ORIF_EXPR
- || code0 == TRUTH_AND_EXPR || code0 == TRUTH_OR_EXPR
- || code0 == TRUTH_XOR_EXPR)
- {
- arg01 = TREE_OPERAND (arg0, 1);
-
- if (TREE_CONSTANT (arg00)
- || ((code0 == TRUTH_ANDIF_EXPR || code0 == TRUTH_ORIF_EXPR)
- && ! has_cleanups (arg00)))
- return fold (build2 (code0, type, arg00,
- fold (build1 (CLEANUP_POINT_EXPR,
- TREE_TYPE (arg01), arg01))));
-
- if (TREE_CONSTANT (arg01))
- return fold (build2 (code0, type,
- fold (build1 (CLEANUP_POINT_EXPR,
- TREE_TYPE (arg00), arg00)),
- arg01));
- }
-
- return t;
- }
-
case CALL_EXPR:
/* Check for a built-in function. */
if (TREE_CODE (TREE_OPERAND (t, 0)) == ADDR_EXPR
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 ();
+ gcc_assert ((sizeof (struct tree_exp) + 5 * sizeof (tree)
+ <= sizeof (struct tree_decl))
+ && sizeof (struct tree_type) <= sizeof (struct tree_decl));
if (expr == NULL)
return;
slot = htab_find_slot (ht, expr, INSERT);
return;
*slot = expr;
code = TREE_CODE (expr);
- if (TREE_CODE_CLASS (code) == 'd' && DECL_ASSEMBLER_NAME_SET_P (expr))
+ if (TREE_CODE_CLASS (code) == tcc_declaration
+ && 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)))
+ else if (TREE_CODE_CLASS (code) == tcc_type
+ && (TYPE_POINTER_TO (expr) || TYPE_REFERENCE_TO (expr)
+ || TYPE_CACHED_VALUES_P (expr)))
{
- /* Allow TYPE_POINTER_TO and TYPE_REFERENCE_TO to be modified. */
+ /* Allow these fields to be modified. */
memcpy (buf, expr, tree_size (expr));
expr = (tree) buf;
TYPE_POINTER_TO (expr) = NULL;
TYPE_REFERENCE_TO (expr) = NULL;
+ TYPE_CACHED_VALUES_P (expr) = 0;
+ TYPE_CACHED_VALUES (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')
+ if (TREE_CODE_CLASS (code) != tcc_type
+ && TREE_CODE_CLASS (code) != tcc_declaration)
fold_checksum_tree (TREE_CHAIN (expr), ctx, ht);
switch (TREE_CODE_CLASS (code))
{
- case 'c':
+ case tcc_constant:
switch (code)
{
case STRING_CST:
break;
}
break;
- case 'x':
+ case tcc_exceptional:
switch (code)
{
case TREE_LIST:
break;
}
break;
- case 'e':
- case 'r':
- case '<':
- case '1':
- case '2':
- case 's':
+ case tcc_expression:
+ case tcc_reference:
+ case tcc_comparison:
+ case tcc_unary:
+ case tcc_binary:
+ case tcc_statement:
len = first_rtl_op (code);
for (i = 0; i < len; ++i)
fold_checksum_tree (TREE_OPERAND (expr, i), ctx, ht);
break;
- case 'd':
+ case tcc_declaration:
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_ATTRIBUTES (expr), ctx, ht);
fold_checksum_tree (DECL_VINDEX (expr), ctx, ht);
break;
- case 't':
+ case tcc_type:
if (TREE_CODE (expr) == ENUMERAL_TYPE)
fold_checksum_tree (TYPE_VALUES (expr), ctx, ht);
fold_checksum_tree (TYPE_SIZE (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);
+ if (TREE_CODE (expr) == RECORD_TYPE
+ || TREE_CODE (expr) == UNION_TYPE
+ || TREE_CODE (expr) == QUAL_UNION_TYPE)
+ fold_checksum_tree (TYPE_BINFO (expr), ctx, ht);
fold_checksum_tree (TYPE_CONTEXT (expr), ctx, ht);
break;
default:
/* Return true when T is an address and is known to be nonzero.
For floating point we further ensure that T is not denormal.
- Similar logic is present in nonzero_address in rtlanal.h */
+ Similar logic is present in nonzero_address in rtlanal.h. */
static bool
tree_expr_nonzero_p (tree t)
return tree_expr_nonzero_p (TREE_OPERAND (t, 0));
case INTEGER_CST:
- return !integer_zerop (t);
+ /* We used to test for !integer_zerop here. This does not work correctly
+ if TREE_CONSTANT_OVERFLOW (t). */
+ return (TREE_INT_CST_LOW (t) != 0
+ || TREE_INT_CST_HIGH (t) != 0);
case PLUS_EXPR:
if (!TYPE_UNSIGNED (type) && !flag_wrapv)
break;
case ADDR_EXPR:
- /* Weak declarations may link to NULL. */
- if (DECL_P (TREE_OPERAND (t, 0)))
- return !DECL_WEAK (TREE_OPERAND (t, 0));
- /* Constants and all other cases are never weak. */
- return true;
+ {
+ tree base = get_base_address (TREE_OPERAND (t, 0));
+
+ if (!base)
+ return false;
+
+ /* Weak declarations may link to NULL. */
+ if (DECL_P (base))
+ return !DECL_WEAK (base);
+
+ /* Constants are never weak. */
+ if (CONSTANT_CLASS_P (base))
+ return true;
+
+ return false;
+ }
case COND_EXPR:
return (tree_expr_nonzero_p (TREE_OPERAND (t, 1))
return false;
}
-/* Return true if `r' is known to be non-negative.
- Only handles constants at the moment. */
-
-int
-rtl_expr_nonnegative_p (rtx r)
-{
- switch (GET_CODE (r))
- {
- case CONST_INT:
- return INTVAL (r) >= 0;
-
- case CONST_DOUBLE:
- if (GET_MODE (r) == VOIDmode)
- return CONST_DOUBLE_HIGH (r) >= 0;
- return 0;
-
- case CONST_VECTOR:
- {
- int units, i;
- rtx elt;
-
- units = CONST_VECTOR_NUNITS (r);
-
- for (i = 0; i < units; ++i)
- {
- elt = CONST_VECTOR_ELT (r, i);
- if (!rtl_expr_nonnegative_p (elt))
- return 0;
- }
-
- return 1;
- }
-
- case SYMBOL_REF:
- case LABEL_REF:
- /* These are always nonnegative. */
- return 1;
-
- default:
- return 0;
- }
-}
-
-
/* See if we are applying CODE, a relational to the highest or lowest
possible integer of TYPE. If so, then the result is a compile
time constant. */
== MODE_INT)
&& (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (TREE_TYPE (string)))) == 1))
return fold_convert (TREE_TYPE (exp),
- build_int_2 ((TREE_STRING_POINTER (string)
- [TREE_INT_CST_LOW (index)]), 0));
+ build_int_cst (NULL_TREE,
+ (TREE_STRING_POINTER (string)
+ [TREE_INT_CST_LOW (index)])));
}
return NULL;
}
{
tree t = NULL_TREE;
- if (TREE_CODE (arg0) == INTEGER_CST)
+ switch (TREE_CODE (arg0))
{
- 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 && !TYPE_UNSIGNED (type)));
- TREE_CONSTANT_OVERFLOW (t)
- = TREE_OVERFLOW (t) | TREE_CONSTANT_OVERFLOW (arg0);
+ case 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_cst_wide (type, low, high);
+ t = force_fit_type (t, 1,
+ (overflow | TREE_OVERFLOW (arg0))
+ && !TYPE_UNSIGNED (type),
+ TREE_CONSTANT_OVERFLOW (arg0));
+ break;
+ }
+
+ case REAL_CST:
+ t = build_real (type, REAL_VALUE_NEGATE (TREE_REAL_CST (arg0)));
+ break;
+
+ default:
+ gcc_unreachable ();
}
- else if (TREE_CODE (arg0) == REAL_CST)
- t = build_real (type, REAL_VALUE_NEGATE (TREE_REAL_CST (arg0)));
-#ifdef ENABLE_CHECKING
- else
- abort ();
-#endif
return t;
}
{
tree t = NULL_TREE;
- if (TREE_CODE (arg0) == INTEGER_CST)
+ switch (TREE_CODE (arg0))
{
+ case INTEGER_CST:
/* If the value is unsigned, then the absolute value is
the same as the ordinary value. */
if (TYPE_UNSIGNED (type))
- return arg0;
+ t = arg0;
/* Similarly, if the value is non-negative. */
else if (INT_CST_LT (integer_minus_one_node, arg0))
- return arg0;
+ t = arg0;
/* If the value is negative, then the absolute value is
its negation. */
else
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_CONSTANT_OVERFLOW (t)
- = TREE_OVERFLOW (t) | TREE_CONSTANT_OVERFLOW (arg0);
- return t;
+ t = build_int_cst_wide (type, low, high);
+ t = force_fit_type (t, -1, overflow | TREE_OVERFLOW (arg0),
+ TREE_CONSTANT_OVERFLOW (arg0));
}
- }
- else if (TREE_CODE (arg0) == REAL_CST)
- {
+ break;
+
+ case REAL_CST:
if (REAL_VALUE_NEGATIVE (TREE_REAL_CST (arg0)))
- return build_real (type, REAL_VALUE_NEGATE (TREE_REAL_CST (arg0)));
+ t = build_real (type, REAL_VALUE_NEGATE (TREE_REAL_CST (arg0)));
else
- return arg0;
+ t = arg0;
+ break;
+
+ default:
+ gcc_unreachable ();
}
-#ifdef ENABLE_CHECKING
- else
- abort ();
-#endif
return t;
}
{
tree t = NULL_TREE;
- if (TREE_CODE (arg0) == INTEGER_CST)
- {
- t = build_int_2 (~ TREE_INT_CST_LOW (arg0),
- ~ TREE_INT_CST_HIGH (arg0));
- TREE_TYPE (t) = type;
- force_fit_type (t, 0);
- TREE_OVERFLOW (t) = TREE_OVERFLOW (arg0);
- TREE_CONSTANT_OVERFLOW (t) = TREE_CONSTANT_OVERFLOW (arg0);
- }
-#ifdef ENABLE_CHECKING
- else
- abort ();
-#endif
+ gcc_assert (TREE_CODE (arg0) == INTEGER_CST);
+
+ t = build_int_cst_wide (type,
+ ~ TREE_INT_CST_LOW (arg0),
+ ~ TREE_INT_CST_HIGH (arg0));
+ t = force_fit_type (t, 0, TREE_OVERFLOW (arg0),
+ TREE_CONSTANT_OVERFLOW (arg0));
return t;
}
break;
default:
- abort ();
+ gcc_unreachable ();
}
return constant_boolean_node (result, type);
tree
build_fold_addr_expr_with_type (tree t, tree ptrtype)
{
- if (TREE_CODE (t) == INDIRECT_REF)
+ /* The size of the object is not relevant when talking about its address. */
+ if (TREE_CODE (t) == WITH_SIZE_EXPR)
+ t = TREE_OPERAND (t, 0);
+
+ /* Note: doesn't apply to ALIGN_INDIRECT_REF */
+ if (TREE_CODE (t) == INDIRECT_REF
+ || TREE_CODE (t) == MISALIGNED_INDIRECT_REF)
{
t = TREE_OPERAND (t, 0);
if (TREE_TYPE (t) != ptrtype)
for (;;)
switch (TREE_CODE_CLASS (TREE_CODE (t)))
{
- case '1':
+ case tcc_unary:
t = TREE_OPERAND (t, 0);
break;
- case '2':
- case '<':
+ case tcc_binary:
+ case tcc_comparison:
if (!TREE_SIDE_EFFECTS (TREE_OPERAND (t, 1)))
t = TREE_OPERAND (t, 0);
else if (!TREE_SIDE_EFFECTS (TREE_OPERAND (t, 0)))
return t;
break;
- case 'e':
+ case tcc_expression:
switch (TREE_CODE (t))
{
case COMPOUND_EXPR:
}
}
-#include "gt-fold-const.h"
+/* Return the value of VALUE, rounded up to a multiple of DIVISOR.
+ This can only be applied to objects of a sizetype. */
+
+tree
+round_up (tree value, int divisor)
+{
+ tree div = NULL_TREE;
+
+ gcc_assert (divisor > 0);
+ if (divisor == 1)
+ return value;
+
+ /* See if VALUE is already a multiple of DIVISOR. If so, we don't
+ have to do anything. Only do this when we are not given a const,
+ because in that case, this check is more expensive than just
+ doing it. */
+ if (TREE_CODE (value) != INTEGER_CST)
+ {
+ div = build_int_cst (TREE_TYPE (value), divisor);
+
+ if (multiple_of_p (TREE_TYPE (value), value, div))
+ return value;
+ }
+
+ /* If divisor is a power of two, simplify this to bit manipulation. */
+ if (divisor == (divisor & -divisor))
+ {
+ tree t;
+
+ t = build_int_cst (TREE_TYPE (value), divisor - 1);
+ value = size_binop (PLUS_EXPR, value, t);
+ t = build_int_cst (TREE_TYPE (value), -divisor);
+ value = size_binop (BIT_AND_EXPR, value, t);
+ }
+ else
+ {
+ if (!div)
+ div = build_int_cst (TREE_TYPE (value), divisor);
+ value = size_binop (CEIL_DIV_EXPR, value, div);
+ value = size_binop (MULT_EXPR, value, div);
+ }
+
+ return value;
+}
+
+/* Likewise, but round down. */
+
+tree
+round_down (tree value, int divisor)
+{
+ tree div = NULL_TREE;
+
+ gcc_assert (divisor > 0);
+ if (divisor == 1)
+ return value;
+
+ /* See if VALUE is already a multiple of DIVISOR. If so, we don't
+ have to do anything. Only do this when we are not given a const,
+ because in that case, this check is more expensive than just
+ doing it. */
+ if (TREE_CODE (value) != INTEGER_CST)
+ {
+ div = build_int_cst (TREE_TYPE (value), divisor);
+
+ if (multiple_of_p (TREE_TYPE (value), value, div))
+ return value;
+ }
+
+ /* If divisor is a power of two, simplify this to bit manipulation. */
+ if (divisor == (divisor & -divisor))
+ {
+ tree t;
+
+ t = build_int_cst (TREE_TYPE (value), -divisor);
+ value = size_binop (BIT_AND_EXPR, value, t);
+ }
+ else
+ {
+ if (!div)
+ div = build_int_cst (TREE_TYPE (value), divisor);
+ value = size_binop (FLOOR_DIV_EXPR, value, div);
+ value = size_binop (MULT_EXPR, value, div);
+ }
+
+ return value;
+}
+
+/* Returns true if addresses of E1 and E2 differ by a constant, false
+ otherwise. If they do, &E1 - &E2 is stored in *DIFF. */
+
+bool
+ptr_difference_const (tree e1, tree e2, HOST_WIDE_INT *diff)
+{
+ tree core1, core2;
+ HOST_WIDE_INT bitsize1, bitsize2;
+ HOST_WIDE_INT bitpos1, bitpos2;
+ tree toffset1, toffset2, tdiff, type;
+ enum machine_mode mode1, mode2;
+ int unsignedp1, unsignedp2, volatilep1, volatilep2;
+
+ core1 = get_inner_reference (e1, &bitsize1, &bitpos1, &toffset1, &mode1,
+ &unsignedp1, &volatilep1);
+ core2 = get_inner_reference (e2, &bitsize2, &bitpos2, &toffset2, &mode2,
+ &unsignedp2, &volatilep2);
+
+ if (bitpos1 % BITS_PER_UNIT != 0
+ || bitpos2 % BITS_PER_UNIT != 0
+ || !operand_equal_p (core1, core2, 0))
+ return false;
+
+ if (toffset1 && toffset2)
+ {
+ type = TREE_TYPE (toffset1);
+ if (type != TREE_TYPE (toffset2))
+ toffset2 = fold_convert (type, toffset2);
+
+ tdiff = fold (build2 (MINUS_EXPR, type, toffset1, toffset2));
+ if (!host_integerp (tdiff, 0))
+ return false;
+
+ *diff = tree_low_cst (tdiff, 0);
+ }
+ else if (toffset1 || toffset2)
+ {
+ /* If only one of the offsets is non-constant, the difference cannot
+ be a constant. */
+ return false;
+ }
+ else
+ *diff = 0;
+
+ *diff += (bitpos1 - bitpos2) / BITS_PER_UNIT;
+ return true;
+}