#include "flags.h"
#include "tree.h"
#include "real.h"
+#include "fixed-value.h"
#include "rtl.h"
#include "expr.h"
#include "tm_p.h"
static tree decode_field_reference (tree, HOST_WIDE_INT *, HOST_WIDE_INT *,
enum machine_mode *, int *, int *,
tree *, tree *);
-static int all_ones_mask_p (tree, int);
-static tree sign_bit_p (tree, tree);
-static int simple_operand_p (tree);
+static int all_ones_mask_p (const_tree, int);
+static tree sign_bit_p (tree, const_tree);
+static int simple_operand_p (const_tree);
static tree range_binop (enum tree_code, tree, tree, int, tree, int);
static tree range_predecessor (tree);
static tree range_successor (tree);
static tree fold_binary_op_with_conditional_arg (enum tree_code, tree,
tree, tree,
tree, tree, int);
-static bool fold_real_zero_addition_p (tree, tree, int);
+static bool fold_real_zero_addition_p (const_tree, const_tree, int);
static tree fold_mathfn_compare (enum built_in_function, enum tree_code,
tree, tree, tree);
static tree fold_inf_compare (enum tree_code, tree, tree, tree);
static tree fold_div_compare (enum tree_code, tree, tree, tree);
-static bool reorder_operands_p (tree, tree);
+static bool reorder_operands_p (const_tree, const_tree);
static tree fold_negate_const (tree, tree);
static tree fold_not_const (tree, tree);
static tree fold_relational_const (enum tree_code, tree, tree, tree);
Otherwise returns NULL_TREE. */
static tree
-div_if_zero_remainder (enum tree_code code, tree arg1, tree arg2)
+div_if_zero_remainder (enum tree_code code, const_tree arg1, const_tree arg2)
{
unsigned HOST_WIDE_INT int1l, int2l;
HOST_WIDE_INT int1h, int2h;
deferred code. */
void
-fold_undefer_overflow_warnings (bool issue, tree stmt, int code)
+fold_undefer_overflow_warnings (bool issue, const_tree stmt, int code)
{
const char *warnmsg;
location_t locus;
if (!issue || warnmsg == NULL)
return;
+ if (stmt != NULL_TREE && TREE_NO_WARNING (stmt))
+ return;
+
/* Use the smallest code level when deciding to issue the
warning. */
if (code == 0 || code > (int) fold_deferred_overflow_code)
return (INTEGRAL_TYPE_P (type)
&& TYPE_OVERFLOW_WRAPS (type));
+ case FIXED_CST:
case REAL_CST:
case NEGATE_EXPR:
return true;
return tem;
break;
+ case FIXED_CST:
+ tem = fold_negate_const (t, type);
+ return tem;
+
case COMPLEX_CST:
{
tree rpart = negate_expr (TREE_REALPART (t));
/* Strip any conversions that don't change the machine mode or signedness. */
STRIP_SIGN_NOPS (in);
- if (TREE_CODE (in) == INTEGER_CST || TREE_CODE (in) == REAL_CST)
+ if (TREE_CODE (in) == INTEGER_CST || TREE_CODE (in) == REAL_CST
+ || TREE_CODE (in) == FIXED_CST)
*litp = in;
else if (TREE_CODE (in) == code
|| (! FLOAT_TYPE_P (TREE_TYPE (in))
+ && ! SAT_FIXED_POINT_TYPE_P (TREE_TYPE (in))
/* We can associate addition and subtraction together (even
though the C standard doesn't say so) for integers because
the value is not affected. For reals, the value might be
int neg_litp_p = 0, neg_conp_p = 0, neg_var_p = 0;
/* First see if either of the operands is a literal, then a constant. */
- if (TREE_CODE (op0) == INTEGER_CST || TREE_CODE (op0) == REAL_CST)
+ if (TREE_CODE (op0) == INTEGER_CST || TREE_CODE (op0) == REAL_CST
+ || TREE_CODE (op0) == FIXED_CST)
*litp = op0, op0 = 0;
- else if (TREE_CODE (op1) == INTEGER_CST || TREE_CODE (op1) == REAL_CST)
+ else if (TREE_CODE (op1) == INTEGER_CST || TREE_CODE (op1) == REAL_CST
+ || TREE_CODE (op1) == FIXED_CST)
*litp = op1, neg_litp_p = neg1_p, op1 = 0;
if (op0 != 0 && TREE_CONSTANT (op0))
for use in int_const_binop, size_binop and size_diffop. */
static bool
-int_binop_types_match_p (enum tree_code code, tree type1, tree type2)
+int_binop_types_match_p (enum tree_code code, const_tree type1, const_tree type2)
{
if (TREE_CODE (type1) != INTEGER_TYPE && !POINTER_TYPE_P (type1))
return false;
return t;
}
+ if (TREE_CODE (arg1) == FIXED_CST)
+ {
+ FIXED_VALUE_TYPE f1;
+ FIXED_VALUE_TYPE f2;
+ FIXED_VALUE_TYPE result;
+ tree t, type;
+ int sat_p;
+ bool overflow_p;
+
+ /* The following codes are handled by fixed_arithmetic. */
+ switch (code)
+ {
+ case PLUS_EXPR:
+ case MINUS_EXPR:
+ case MULT_EXPR:
+ case TRUNC_DIV_EXPR:
+ f2 = TREE_FIXED_CST (arg2);
+ break;
+
+ case LSHIFT_EXPR:
+ case RSHIFT_EXPR:
+ f2.data.high = TREE_INT_CST_HIGH (arg2);
+ f2.data.low = TREE_INT_CST_LOW (arg2);
+ f2.mode = SImode;
+ break;
+
+ default:
+ return NULL_TREE;
+ }
+
+ f1 = TREE_FIXED_CST (arg1);
+ type = TREE_TYPE (arg1);
+ sat_p = TYPE_SATURATING (type);
+ overflow_p = fixed_arithmetic (&result, code, &f1, &f2, sat_p);
+ t = build_fixed (type, result);
+ /* Propagate overflow flags. */
+ if (overflow_p | TREE_OVERFLOW (arg1) | TREE_OVERFLOW (arg2))
+ {
+ TREE_OVERFLOW (t) = 1;
+ TREE_CONSTANT_OVERFLOW (t) = 1;
+ }
+ else if (TREE_CONSTANT_OVERFLOW (arg1) | TREE_CONSTANT_OVERFLOW (arg2))
+ TREE_CONSTANT_OVERFLOW (t) = 1;
+ return t;
+ }
+
if (TREE_CODE (arg1) == COMPLEX_CST)
{
tree type = TREE_TYPE (arg1);
INTEGER_CST to another integer type. */
static tree
-fold_convert_const_int_from_int (tree type, tree arg1)
+fold_convert_const_int_from_int (tree type, const_tree arg1)
{
tree t;
to an integer type. */
static tree
-fold_convert_const_int_from_real (enum tree_code code, tree type, tree arg1)
+fold_convert_const_int_from_real (enum tree_code code, tree type, const_tree arg1)
{
int overflow = 0;
tree t;
return t;
}
+/* A subroutine of fold_convert_const handling conversions of a
+ FIXED_CST to an integer type. */
+
+static tree
+fold_convert_const_int_from_fixed (tree type, const_tree arg1)
+{
+ tree t;
+ double_int temp, temp_trunc;
+ unsigned int mode;
+
+ /* Right shift FIXED_CST to temp by fbit. */
+ temp = TREE_FIXED_CST (arg1).data;
+ mode = TREE_FIXED_CST (arg1).mode;
+ if (GET_MODE_FBIT (mode) < 2 * HOST_BITS_PER_WIDE_INT)
+ {
+ lshift_double (temp.low, temp.high,
+ - GET_MODE_FBIT (mode), 2 * HOST_BITS_PER_WIDE_INT,
+ &temp.low, &temp.high, SIGNED_FIXED_POINT_MODE_P (mode));
+
+ /* Left shift temp to temp_trunc by fbit. */
+ lshift_double (temp.low, temp.high,
+ GET_MODE_FBIT (mode), 2 * HOST_BITS_PER_WIDE_INT,
+ &temp_trunc.low, &temp_trunc.high,
+ SIGNED_FIXED_POINT_MODE_P (mode));
+ }
+ else
+ {
+ temp.low = 0;
+ temp.high = 0;
+ temp_trunc.low = 0;
+ temp_trunc.high = 0;
+ }
+
+ /* If FIXED_CST is negative, we need to round the value toward 0.
+ By checking if the fractional bits are not zero to add 1 to temp. */
+ if (SIGNED_FIXED_POINT_MODE_P (mode) && temp_trunc.high < 0
+ && !double_int_equal_p (TREE_FIXED_CST (arg1).data, temp_trunc))
+ {
+ double_int one;
+ one.low = 1;
+ one.high = 0;
+ temp = double_int_add (temp, one);
+ }
+
+ /* Given a fixed-point constant, make new constant with new type,
+ appropriately sign-extended or truncated. */
+ t = force_fit_type_double (type, temp.low, temp.high, -1,
+ (temp.high < 0
+ && (TYPE_UNSIGNED (type)
+ < TYPE_UNSIGNED (TREE_TYPE (arg1))))
+ | TREE_OVERFLOW (arg1));
+
+ return t;
+}
+
/* A subroutine of fold_convert_const handling conversions a REAL_CST
to another floating point type. */
static tree
-fold_convert_const_real_from_real (tree type, tree arg1)
+fold_convert_const_real_from_real (tree type, const_tree arg1)
{
REAL_VALUE_TYPE value;
tree t;
return t;
}
+/* A subroutine of fold_convert_const handling conversions a FIXED_CST
+ to a floating point type. */
+
+static tree
+fold_convert_const_real_from_fixed (tree type, const_tree arg1)
+{
+ REAL_VALUE_TYPE value;
+ tree t;
+
+ real_convert_from_fixed (&value, TYPE_MODE (type), &TREE_FIXED_CST (arg1));
+ t = build_real (type, value);
+
+ TREE_OVERFLOW (t) = TREE_OVERFLOW (arg1);
+ TREE_CONSTANT_OVERFLOW (t)
+ = TREE_OVERFLOW (t) | TREE_CONSTANT_OVERFLOW (arg1);
+ return t;
+}
+
+/* A subroutine of fold_convert_const handling conversions a FIXED_CST
+ to another fixed-point type. */
+
+static tree
+fold_convert_const_fixed_from_fixed (tree type, const_tree arg1)
+{
+ FIXED_VALUE_TYPE value;
+ tree t;
+ bool overflow_p;
+
+ overflow_p = fixed_convert (&value, TYPE_MODE (type), &TREE_FIXED_CST (arg1),
+ TYPE_SATURATING (type));
+ t = build_fixed (type, value);
+
+ /* Propagate overflow flags. */
+ if (overflow_p | TREE_OVERFLOW (arg1))
+ {
+ TREE_OVERFLOW (t) = 1;
+ TREE_CONSTANT_OVERFLOW (t) = 1;
+ }
+ else if (TREE_CONSTANT_OVERFLOW (arg1))
+ TREE_CONSTANT_OVERFLOW (t) = 1;
+ return t;
+}
+
+/* A subroutine of fold_convert_const handling conversions an INTEGER_CST
+ to a fixed-point type. */
+
+static tree
+fold_convert_const_fixed_from_int (tree type, const_tree arg1)
+{
+ FIXED_VALUE_TYPE value;
+ tree t;
+ bool overflow_p;
+
+ overflow_p = fixed_convert_from_int (&value, TYPE_MODE (type),
+ TREE_INT_CST (arg1),
+ TYPE_UNSIGNED (TREE_TYPE (arg1)),
+ TYPE_SATURATING (type));
+ t = build_fixed (type, value);
+
+ /* Propagate overflow flags. */
+ if (overflow_p | TREE_OVERFLOW (arg1))
+ {
+ TREE_OVERFLOW (t) = 1;
+ TREE_CONSTANT_OVERFLOW (t) = 1;
+ }
+ else if (TREE_CONSTANT_OVERFLOW (arg1))
+ TREE_CONSTANT_OVERFLOW (t) = 1;
+ return t;
+}
+
+/* A subroutine of fold_convert_const handling conversions a REAL_CST
+ to a fixed-point type. */
+
+static tree
+fold_convert_const_fixed_from_real (tree type, const_tree arg1)
+{
+ FIXED_VALUE_TYPE value;
+ tree t;
+ bool overflow_p;
+
+ overflow_p = fixed_convert_from_real (&value, TYPE_MODE (type),
+ &TREE_REAL_CST (arg1),
+ TYPE_SATURATING (type));
+ t = build_fixed (type, value);
+
+ /* Propagate overflow flags. */
+ if (overflow_p | TREE_OVERFLOW (arg1))
+ {
+ TREE_OVERFLOW (t) = 1;
+ TREE_CONSTANT_OVERFLOW (t) = 1;
+ }
+ else if (TREE_CONSTANT_OVERFLOW (arg1))
+ TREE_CONSTANT_OVERFLOW (t) = 1;
+ return t;
+}
+
/* Attempt to fold type conversion operation CODE of expression ARG1 to
type TYPE. If no simplification can be done return NULL_TREE. */
return fold_convert_const_int_from_int (type, arg1);
else if (TREE_CODE (arg1) == REAL_CST)
return fold_convert_const_int_from_real (code, type, arg1);
+ else if (TREE_CODE (arg1) == FIXED_CST)
+ return fold_convert_const_int_from_fixed (type, arg1);
}
else if (TREE_CODE (type) == REAL_TYPE)
{
if (TREE_CODE (arg1) == INTEGER_CST)
return build_real_from_int_cst (type, arg1);
- if (TREE_CODE (arg1) == REAL_CST)
+ else if (TREE_CODE (arg1) == REAL_CST)
return fold_convert_const_real_from_real (type, arg1);
+ else if (TREE_CODE (arg1) == FIXED_CST)
+ return fold_convert_const_real_from_fixed (type, arg1);
+ }
+ else if (TREE_CODE (type) == FIXED_POINT_TYPE)
+ {
+ if (TREE_CODE (arg1) == FIXED_CST)
+ return fold_convert_const_fixed_from_fixed (type, arg1);
+ else if (TREE_CODE (arg1) == INTEGER_CST)
+ return fold_convert_const_fixed_from_int (type, arg1);
+ else if (TREE_CODE (arg1) == REAL_CST)
+ return fold_convert_const_fixed_from_real (type, arg1);
}
return NULL_TREE;
}
if (tem != NULL_TREE)
return tem;
}
+ else if (TREE_CODE (arg) == FIXED_CST)
+ {
+ tem = fold_convert_const (FIXED_CONVERT_EXPR, type, arg);
+ if (tem != NULL_TREE)
+ return tem;
+ }
switch (TREE_CODE (orig))
{
case REAL_TYPE:
return fold_build1 (NOP_EXPR, type, arg);
+ case FIXED_POINT_TYPE:
+ return fold_build1 (FIXED_CONVERT_EXPR, type, arg);
+
+ case COMPLEX_TYPE:
+ tem = fold_build1 (REALPART_EXPR, TREE_TYPE (orig), arg);
+ return fold_convert (type, tem);
+
+ default:
+ gcc_unreachable ();
+ }
+
+ case FIXED_POINT_TYPE:
+ if (TREE_CODE (arg) == FIXED_CST || TREE_CODE (arg) == INTEGER_CST
+ || TREE_CODE (arg) == REAL_CST)
+ {
+ tem = fold_convert_const (FIXED_CONVERT_EXPR, type, arg);
+ if (tem != NULL_TREE)
+ return tem;
+ }
+
+ switch (TREE_CODE (orig))
+ {
+ case FIXED_POINT_TYPE:
+ case INTEGER_TYPE:
+ case ENUMERAL_TYPE:
+ case BOOLEAN_TYPE:
+ case REAL_TYPE:
+ return fold_build1 (FIXED_CONVERT_EXPR, type, arg);
+
case COMPLEX_TYPE:
tem = fold_build1 (REALPART_EXPR, TREE_TYPE (orig), arg);
return fold_convert (type, tem);
case BOOLEAN_TYPE: case ENUMERAL_TYPE:
case POINTER_TYPE: case REFERENCE_TYPE:
case REAL_TYPE:
+ case FIXED_POINT_TYPE:
return build2 (COMPLEX_EXPR, type,
fold_convert (TREE_TYPE (type), arg),
fold_convert (TREE_TYPE (type), integer_zero_node));
otherwise. */
static bool
-maybe_lvalue_p (tree x)
+maybe_lvalue_p (const_tree x)
{
/* We only need to wrap lvalue tree codes. */
switch (TREE_CODE (x))
case INTEGER_CST:
return tree_int_cst_equal (arg0, arg1);
+ case FIXED_CST:
+ return FIXED_VALUES_IDENTICAL (TREE_FIXED_CST (arg0),
+ TREE_FIXED_CST (arg1));
+
case REAL_CST:
if (REAL_VALUES_IDENTICAL (TREE_REAL_CST (arg0),
TREE_REAL_CST (arg1)))
{
tree t = fold_convert (type, result);
+ /* If the resulting operand is an empty statement, just return the omitted
+ statement casted to void. */
+ if (IS_EMPTY_STMT (t) && TREE_SIDE_EFFECTS (omitted))
+ return build1 (NOP_EXPR, void_type_node, fold_ignored_result (omitted));
+
if (TREE_SIDE_EFFECTS (omitted))
return build2 (COMPOUND_EXPR, type, fold_ignored_result (omitted), t);
{
tree t = fold_convert (type, result);
+ /* If the resulting operand is an empty statement, just return the omitted
+ statement casted to void. */
+ if (IS_EMPTY_STMT (t) && TREE_SIDE_EFFECTS (omitted))
+ return build1 (NOP_EXPR, void_type_node, fold_ignored_result (omitted));
+
if (TREE_SIDE_EFFECTS (omitted))
return build2 (COMPOUND_EXPR, type, fold_ignored_result (omitted), t);
bit positions. */
static int
-all_ones_mask_p (tree mask, int size)
+all_ones_mask_p (const_tree mask, int size)
{
tree type = TREE_TYPE (mask);
unsigned int precision = TYPE_PRECISION (type);
or NULL_TREE otherwise. */
static tree
-sign_bit_p (tree exp, tree val)
+sign_bit_p (tree exp, const_tree val)
{
unsigned HOST_WIDE_INT mask_lo, lo;
HOST_WIDE_INT mask_hi, hi;
to be evaluated unconditionally. */
static int
-simple_operand_p (tree exp)
+simple_operand_p (const_tree exp)
{
/* Strip any conversions that don't change the machine mode. */
STRIP_NOPS (exp);
if (!TYPE_UNSIGNED (exp_type) && TYPE_UNSIGNED (arg0_type))
{
tree high_positive;
- tree equiv_type = lang_hooks.types.type_for_mode
- (TYPE_MODE (arg0_type), 1);
+ tree equiv_type;
+ /* For fixed-point modes, we need to pass the saturating flag
+ as the 2nd parameter. */
+ if (ALL_FIXED_POINT_MODE_P (TYPE_MODE (arg0_type)))
+ equiv_type = lang_hooks.types.type_for_mode
+ (TYPE_MODE (arg0_type),
+ TYPE_SATURATING (arg0_type));
+ else
+ equiv_type = lang_hooks.types.type_for_mode
+ (TYPE_MODE (arg0_type), 1);
/* A range without an upper bound is, naturally, unbounded.
Since convert would have cropped a very large value, use
then we cannot pass through this conversion. */
|| (code != MULT_EXPR
&& (TYPE_UNSIGNED (ctype)
- != TYPE_UNSIGNED (TREE_TYPE (op0))))))
+ != TYPE_UNSIGNED (TREE_TYPE (op0))))
+ /* ... or has undefined overflow while the converted to
+ type has not, we cannot do the operation in the inner type
+ as that would introduce undefined overflow. */
+ || (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (op0))
+ && !TYPE_OVERFLOW_UNDEFINED (type))))
break;
/* Pass the constant down and see if we can make a simplification. If
}
break;
}
+ /* If the constant is negative, we cannot simplify this. */
+ if (tree_int_cst_sgn (c) == -1)
+ break;
/* FALLTHROUGH */
case NEGATE_EXPR:
if ((t1 = extract_muldiv (op0, c, code, wide_type, strict_overflow_p))
&& ((code == MULT_EXPR && tcode == EXACT_DIV_EXPR)
|| (tcode == MULT_EXPR
&& code != TRUNC_MOD_EXPR && code != CEIL_MOD_EXPR
- && code != FLOOR_MOD_EXPR && code != ROUND_MOD_EXPR)))
+ && code != FLOOR_MOD_EXPR && code != ROUND_MOD_EXPR
+ && code != MULT_EXPR)))
{
if (integer_zerop (const_binop (TRUNC_MOD_EXPR, op1, c, 0)))
{
}
-/* Return true if expr looks like an ARRAY_REF and set base and
- offset to the appropriate trees. If there is no offset,
- offset is set to NULL_TREE. Base will be canonicalized to
- something you can get the element type from using
- TREE_TYPE (TREE_TYPE (base)). Offset will be the offset
- in bytes to the base in sizetype. */
-
-static bool
-extract_array_ref (tree expr, tree *base, tree *offset)
-{
- /* One canonical form is a PLUS_EXPR with the first
- argument being an ADDR_EXPR with a possible NOP_EXPR
- attached. */
- if (TREE_CODE (expr) == POINTER_PLUS_EXPR)
- {
- tree op0 = TREE_OPERAND (expr, 0);
- tree inner_base, dummy1;
- /* Strip NOP_EXPRs here because the C frontends and/or
- folders present us (int *)&x.a p+ 4 possibly. */
- STRIP_NOPS (op0);
- if (extract_array_ref (op0, &inner_base, &dummy1))
- {
- *base = inner_base;
- *offset = fold_convert (sizetype, TREE_OPERAND (expr, 1));
- if (dummy1 != NULL_TREE)
- *offset = fold_build2 (PLUS_EXPR, sizetype,
- dummy1, *offset);
- return true;
- }
- }
- /* Other canonical form is an ADDR_EXPR of an ARRAY_REF,
- which we transform into an ADDR_EXPR with appropriate
- offset. For other arguments to the ADDR_EXPR we assume
- zero offset and as such do not care about the ADDR_EXPR
- type and strip possible nops from it. */
- else if (TREE_CODE (expr) == ADDR_EXPR)
- {
- tree op0 = TREE_OPERAND (expr, 0);
- if (TREE_CODE (op0) == ARRAY_REF)
- {
- tree idx = TREE_OPERAND (op0, 1);
- *base = TREE_OPERAND (op0, 0);
- *offset = fold_build2 (MULT_EXPR, TREE_TYPE (idx), idx,
- array_ref_element_size (op0));
- *offset = fold_convert (sizetype, *offset);
- }
- else
- {
- /* Handle array-to-pointer decay as &a. */
- if (TREE_CODE (TREE_TYPE (op0)) == ARRAY_TYPE)
- *base = TREE_OPERAND (expr, 0);
- else
- *base = expr;
- *offset = NULL_TREE;
- }
- return true;
- }
- /* The next canonical form is a VAR_DECL with POINTER_TYPE. */
- else if (SSA_VAR_P (expr)
- && TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE)
- {
- *base = expr;
- *offset = NULL_TREE;
- return true;
- }
-
- return false;
-}
-
-
/* Transform `a + (b ? x : y)' into `b ? (a + x) : (a + y)'.
Transform, `a + (x < y)' into `(x < y) ? (a + 1) : (a + 0)'. Here
CODE corresponds to the `+', COND to the `(b ? x : y)' or `(x < y)'
modes, X + 0 is not the same as X because -0 + 0 is 0. */
static bool
-fold_real_zero_addition_p (tree type, tree addend, int negate)
+fold_real_zero_addition_p (const_tree type, const_tree addend, int negate)
{
if (!real_zerop (addend))
return false;
such that the evaluation of arg1 occurs before arg0. */
static bool
-reorder_operands_p (tree arg0, tree arg1)
+reorder_operands_p (const_tree arg0, const_tree arg1)
{
if (! flag_evaluation_order)
return true;
if (TREE_CODE (arg0) == REAL_CST)
return 1;
+ if (TREE_CODE (arg1) == FIXED_CST)
+ return 0;
+ if (TREE_CODE (arg0) == FIXED_CST)
+ return 1;
+
if (TREE_CODE (arg1) == COMPLEX_CST)
return 0;
if (TREE_CODE (arg0) == COMPLEX_CST)
}
else
{
+ /* We cannot generate constant 1 for fract. */
+ if (ALL_FRACT_MODE_P (TYPE_MODE (type)))
+ return NULL_TREE;
arg00 = arg0;
arg01 = build_one_cst (type);
}
}
else
{
+ /* We cannot generate constant 1 for fract. */
+ if (ALL_FRACT_MODE_P (TYPE_MODE (type)))
+ return NULL_TREE;
arg10 = arg1;
arg11 = build_one_cst (type);
}
(for integers). Avoid this if the final type is a pointer
since then we sometimes need the inner conversion. Likewise if
the outer has a precision not equal to the size of its mode. */
- if ((((inter_int || inter_ptr) && (inside_int || inside_ptr))
+ if (((inter_int && inside_int)
|| (inter_float && inside_float)
|| (inter_vec && inside_vec))
&& inter_prec >= inside_prec
intermediate and final types differ, or
- the final type is a pointer type and the precisions of the
initial and intermediate types differ.
- - the final type is a pointer type and the initial type not
- the initial type is a pointer to an array and the final type
not. */
if (! inside_float && ! inter_float && ! final_float
&& ! (final_ptr && inside_prec != inter_prec)
&& ! (final_prec != GET_MODE_BITSIZE (TYPE_MODE (type))
&& TYPE_MODE (type) == TYPE_MODE (inter_type))
- && final_ptr == inside_ptr
- && ! (inside_ptr
+ && ! (inside_ptr && final_ptr
&& TREE_CODE (TREE_TYPE (inside_type)) == ARRAY_TYPE
&& TREE_CODE (TREE_TYPE (type)) != ARRAY_TYPE))
return fold_build1 (code, type, TREE_OPERAND (op0, 0));
tem = fold_convert_const (code, type, op0);
return tem ? tem : NULL_TREE;
+ case FIXED_CONVERT_EXPR:
+ tem = fold_convert_const (code, type, arg0);
+ return tem ? tem : NULL_TREE;
+
case VIEW_CONVERT_EXPR:
if (TREE_TYPE (op0) == type)
return op0;
if (TREE_CODE (arg0) == INTEGER_CST)
return fold_not_const (arg0, type);
else if (TREE_CODE (arg0) == BIT_NOT_EXPR)
- return TREE_OPERAND (arg0, 0);
+ return TREE_OPERAND (op0, 0);
/* Convert ~ (-A) to A - 1. */
else if (INTEGRAL_TYPE_P (type) && TREE_CODE (arg0) == NEGATE_EXPR)
- return fold_build2 (MINUS_EXPR, type, TREE_OPERAND (arg0, 0),
+ return fold_build2 (MINUS_EXPR, type,
+ fold_convert (type, TREE_OPERAND (arg0, 0)),
build_int_cst (type, 1));
/* Convert ~ (A - 1) or ~ (A + -1) to -A. */
else if (INTEGRAL_TYPE_P (type)
&& integer_onep (TREE_OPERAND (arg0, 1)))
|| (TREE_CODE (arg0) == PLUS_EXPR
&& integer_all_onesp (TREE_OPERAND (arg0, 1)))))
- return fold_build1 (NEGATE_EXPR, type, TREE_OPERAND (arg0, 0));
+ return fold_build1 (NEGATE_EXPR, type,
+ fold_convert (type, TREE_OPERAND (arg0, 0)));
/* Convert ~(X ^ Y) to ~X ^ Y or X ^ ~Y if ~X or ~Y simplify. */
else if (TREE_CODE (arg0) == BIT_XOR_EXPR
&& (tem = fold_unary (BIT_NOT_EXPR, type,
TREE_OPERAND (arg0, 1)))))
return fold_build2 (BIT_XOR_EXPR, type,
fold_convert (type, TREE_OPERAND (arg0, 0)), tem);
+ /* Perform BIT_NOT_EXPR on each element individually. */
+ else if (TREE_CODE (arg0) == VECTOR_CST)
+ {
+ tree elements = TREE_VECTOR_CST_ELTS (arg0), elem, list = NULL_TREE;
+ int count = TYPE_VECTOR_SUBPARTS (type), i;
+
+ for (i = 0; i < count; i++)
+ {
+ if (elements)
+ {
+ elem = TREE_VALUE (elements);
+ elem = fold_unary (BIT_NOT_EXPR, TREE_TYPE (type), elem);
+ if (elem == NULL_TREE)
+ break;
+ elements = TREE_CHAIN (elements);
+ }
+ else
+ elem = build_int_cst (TREE_TYPE (type), -1);
+ list = tree_cons (NULL_TREE, elem, list);
+ }
+ if (i == count)
+ return build_vector (type, nreverse (list));
+ }
return NULL_TREE;
if (TREE_CODE (arg0) == CALL_EXPR)
{
tree fn = get_callee_fndecl (arg0);
- if (DECL_BUILT_IN_CLASS (fn) == BUILT_IN_NORMAL)
+ if (fn && DECL_BUILT_IN_CLASS (fn) == BUILT_IN_NORMAL)
switch (DECL_FUNCTION_CODE (fn))
{
CASE_FLT_FN (BUILT_IN_CEXPI):
if (TREE_CODE (arg0) == CALL_EXPR)
{
tree fn = get_callee_fndecl (arg0);
- if (DECL_BUILT_IN_CLASS (fn) == BUILT_IN_NORMAL)
+ if (fn && DECL_BUILT_IN_CLASS (fn) == BUILT_IN_NORMAL)
switch (DECL_FUNCTION_CODE (fn))
{
CASE_FLT_FN (BUILT_IN_CEXPI):
/* For comparisons of pointers we can decompose it to a compile time
comparison of the base objects and the offsets into the object.
- This requires at least one operand being an ADDR_EXPR to do more
- than the operand_equal_p test below. */
+ This requires at least one operand being an ADDR_EXPR or a
+ POINTER_PLUS_EXPR to do more than the operand_equal_p test below. */
if (POINTER_TYPE_P (TREE_TYPE (arg0))
&& (TREE_CODE (arg0) == ADDR_EXPR
- || TREE_CODE (arg1) == ADDR_EXPR))
+ || TREE_CODE (arg1) == ADDR_EXPR
+ || TREE_CODE (arg0) == POINTER_PLUS_EXPR
+ || TREE_CODE (arg1) == POINTER_PLUS_EXPR))
{
tree base0, base1, offset0 = NULL_TREE, offset1 = NULL_TREE;
HOST_WIDE_INT bitsize, bitpos0 = 0, bitpos1 = 0;
else
indirect_base0 = true;
}
+ else if (TREE_CODE (arg0) == POINTER_PLUS_EXPR)
+ {
+ base0 = TREE_OPERAND (arg0, 0);
+ offset0 = TREE_OPERAND (arg0, 1);
+ }
base1 = arg1;
if (TREE_CODE (arg1) == ADDR_EXPR)
else if (!indirect_base0)
base1 = NULL_TREE;
}
+ else if (TREE_CODE (arg1) == POINTER_PLUS_EXPR)
+ {
+ base1 = TREE_OPERAND (arg1, 0);
+ offset1 = TREE_OPERAND (arg1, 1);
+ }
else if (indirect_base0)
base1 = NULL_TREE;
}
}
- /* If this is a comparison of two exprs that look like an ARRAY_REF of the
- same object, then we can fold this to a comparison of the two offsets in
- signed size type. This is possible because pointer arithmetic is
- restricted to retain within an object and overflow on pointer differences
- is undefined as of 6.5.6/8 and /9 with respect to the signed ptrdiff_t.
-
- We check flag_wrapv directly because pointers types are unsigned,
- and therefore TYPE_OVERFLOW_WRAPS returns true for them. That is
- normally what we want to avoid certain odd overflow cases, but
- not here. */
- if (POINTER_TYPE_P (TREE_TYPE (arg0))
- && !flag_wrapv
- && !TYPE_OVERFLOW_TRAPS (TREE_TYPE (arg0)))
- {
- tree base0, offset0, base1, offset1;
-
- if (extract_array_ref (arg0, &base0, &offset0)
- && extract_array_ref (arg1, &base1, &offset1)
- && operand_equal_p (base0, base1, 0))
- {
- tree signed_size_type_node;
- signed_size_type_node = signed_type_for (size_type_node);
-
- /* By converting to signed size type we cover middle-end pointer
- arithmetic which operates on unsigned pointer types of size
- type size and ARRAY_REF offsets which are properly sign or
- zero extended from their type in case it is narrower than
- size type. */
- if (offset0 == NULL_TREE)
- offset0 = build_int_cst (signed_size_type_node, 0);
- else
- offset0 = fold_convert (signed_size_type_node, offset0);
- if (offset1 == NULL_TREE)
- offset1 = build_int_cst (signed_size_type_node, 0);
- else
- offset1 = fold_convert (signed_size_type_node, offset1);
-
- return fold_build2 (code, type, offset0, offset1);
- }
- }
-
/* Transform comparisons of the form X +- C1 CMP Y +- C2 to
X CMP Y +- C2 +- C1 for signed X, Y. This is valid if
the resulting offset is smaller in absolute value than the
/* Likewise, we can simplify a comparison of a real constant with
a MINUS_EXPR whose first operand is also a real constant, i.e.
- (c1 - x) < c2 becomes x > c1-c2. */
- if (flag_unsafe_math_optimizations
+ (c1 - x) < c2 becomes x > c1-c2. Reordering is allowed on
+ floating-point types only if -fassociative-math is set. */
+ if (flag_associative_math
&& TREE_CODE (arg1) == REAL_CST
&& TREE_CODE (arg0) == MINUS_EXPR
&& TREE_CODE (TREE_OPERAND (arg0, 0)) == REAL_CST
}
+/* Subroutine of fold_binary. If P is the value of EXPR, computes
+ power-of-two M and (arbitrary) N such that M divides (P-N). This condition
+ guarantees that P and N have the same least significant log2(M) bits.
+ N is not otherwise constrained. In particular, N is not normalized to
+ 0 <= N < M as is common. In general, the precise value of P is unknown.
+ M is chosen as large as possible such that constant N can be determined.
+
+ Returns M and sets *RESIDUE to N. */
+
+static unsigned HOST_WIDE_INT
+get_pointer_modulus_and_residue (tree expr, unsigned HOST_WIDE_INT *residue)
+{
+ enum tree_code code;
+
+ *residue = 0;
+
+ code = TREE_CODE (expr);
+ if (code == ADDR_EXPR)
+ {
+ expr = TREE_OPERAND (expr, 0);
+ if (handled_component_p (expr))
+ {
+ HOST_WIDE_INT bitsize, bitpos;
+ tree offset;
+ enum machine_mode mode;
+ int unsignedp, volatilep;
+
+ expr = get_inner_reference (expr, &bitsize, &bitpos, &offset,
+ &mode, &unsignedp, &volatilep, false);
+ *residue = bitpos / BITS_PER_UNIT;
+ if (offset)
+ {
+ if (TREE_CODE (offset) == INTEGER_CST)
+ *residue += TREE_INT_CST_LOW (offset);
+ else
+ /* We don't handle more complicated offset expressions. */
+ return 1;
+ }
+ }
+
+ if (DECL_P (expr))
+ return DECL_ALIGN_UNIT (expr);
+ }
+ else if (code == POINTER_PLUS_EXPR)
+ {
+ tree op0, op1;
+ unsigned HOST_WIDE_INT modulus;
+ enum tree_code inner_code;
+
+ op0 = TREE_OPERAND (expr, 0);
+ STRIP_NOPS (op0);
+ modulus = get_pointer_modulus_and_residue (op0, residue);
+
+ op1 = TREE_OPERAND (expr, 1);
+ STRIP_NOPS (op1);
+ inner_code = TREE_CODE (op1);
+ if (inner_code == INTEGER_CST)
+ {
+ *residue += TREE_INT_CST_LOW (op1);
+ return modulus;
+ }
+ else if (inner_code == MULT_EXPR)
+ {
+ op1 = TREE_OPERAND (op1, 1);
+ if (TREE_CODE (op1) == INTEGER_CST)
+ {
+ unsigned HOST_WIDE_INT align;
+
+ /* Compute the greatest power-of-2 divisor of op1. */
+ align = TREE_INT_CST_LOW (op1);
+ align &= -align;
+
+ /* If align is non-zero and less than *modulus, replace
+ *modulus with align., If align is 0, then either op1 is 0
+ or the greatest power-of-2 divisor of op1 doesn't fit in an
+ unsigned HOST_WIDE_INT. In either case, no additional
+ constraint is imposed. */
+ if (align)
+ modulus = MIN (modulus, align);
+
+ return modulus;
+ }
+ }
+ }
+
+ /* If we get here, we were unable to determine anything useful about the
+ expression. */
+ return 1;
+}
+
+
/* Fold a binary expression of code CODE and type TYPE with operands
OP0 and OP1. Return the folded expression if folding is
successful. Otherwise, return NULL_TREE. */
constant but we can't do arithmetic on them. */
if ((TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST)
|| (TREE_CODE (arg0) == REAL_CST && TREE_CODE (arg1) == REAL_CST)
+ || (TREE_CODE (arg0) == FIXED_CST && TREE_CODE (arg1) == FIXED_CST)
+ || (TREE_CODE (arg0) == FIXED_CST && TREE_CODE (arg1) == INTEGER_CST)
|| (TREE_CODE (arg0) == COMPLEX_CST && TREE_CODE (arg1) == COMPLEX_CST)
|| (TREE_CODE (arg0) == VECTOR_CST && TREE_CODE (arg1) == VECTOR_CST))
{
if (kind == tcc_binary)
- tem = const_binop (code, arg0, arg1, 0);
+ {
+ /* Make sure type and arg0 have the same saturating flag. */
+ gcc_assert (TYPE_SATURATING (type)
+ == TYPE_SATURATING (TREE_TYPE (arg0)));
+ tem = const_binop (code, arg0, arg1, 0);
+ }
else if (kind == tcc_comparison)
tem = fold_relational_const (code, type, arg0, arg1);
else
if (TREE_CODE (arg0) == COMPOUND_EXPR)
return build2 (COMPOUND_EXPR, type, TREE_OPERAND (arg0, 0),
fold_build2 (code, type,
- TREE_OPERAND (arg0, 1), op1));
+ fold_convert (TREE_TYPE (op0),
+ TREE_OPERAND (arg0, 1)),
+ op1));
if (TREE_CODE (arg1) == COMPOUND_EXPR
&& reorder_operands_p (arg0, TREE_OPERAND (arg1, 0)))
return build2 (COMPOUND_EXPR, type, TREE_OPERAND (arg1, 0),
- fold_build2 (code, type,
- op0, TREE_OPERAND (arg1, 1)));
+ fold_build2 (code, type, op0,
+ fold_convert (TREE_TYPE (op1),
+ TREE_OPERAND (arg1, 1))));
if (TREE_CODE (arg0) == COND_EXPR || COMPARISON_CLASS_P (arg0))
{
if (POINTER_TYPE_P (TREE_TYPE (arg1))
&& INTEGRAL_TYPE_P (TREE_TYPE (arg0)))
return fold_build2 (POINTER_PLUS_EXPR, type,
- fold_convert (type, arg1), fold_convert (sizetype, arg0));
+ fold_convert (type, arg1),
+ fold_convert (sizetype, arg0));
/* (PTR +p B) +p A -> PTR +p (B + A) */
if (TREE_CODE (arg0) == POINTER_PLUS_EXPR)
tree inner;
tree arg01 = fold_convert (sizetype, TREE_OPERAND (arg0, 1));
tree arg00 = TREE_OPERAND (arg0, 0);
- inner = fold_build2 (PLUS_EXPR, sizetype, arg01, fold_convert (sizetype, arg1));
- return fold_build2 (POINTER_PLUS_EXPR, type, arg00, inner);
+ inner = fold_build2 (PLUS_EXPR, sizetype,
+ arg01, fold_convert (sizetype, arg1));
+ return fold_convert (type,
+ fold_build2 (POINTER_PLUS_EXPR,
+ TREE_TYPE (arg00), arg00, inner));
}
/* PTR_CST +p CST -> CST1 */
}
return NULL_TREE;
+
case PLUS_EXPR:
/* PTR + INT -> (INT)(PTR p+ INT) */
if (POINTER_TYPE_P (TREE_TYPE (arg0))
return omit_one_operand (type, t1, arg0);
}
}
+
+ /* X + (X / CST) * -CST is X % CST. */
+ if (TREE_CODE (arg1) == MULT_EXPR
+ && TREE_CODE (TREE_OPERAND (arg1, 0)) == TRUNC_DIV_EXPR
+ && operand_equal_p (arg0,
+ TREE_OPERAND (TREE_OPERAND (arg1, 0), 0), 0))
+ {
+ tree cst0 = TREE_OPERAND (TREE_OPERAND (arg1, 0), 1);
+ tree cst1 = TREE_OPERAND (arg1, 1);
+ tree sum = fold_binary (PLUS_EXPR, TREE_TYPE (cst1), cst1, cst0);
+ if (sum && integer_zerop (sum))
+ return fold_convert (type,
+ fold_build2 (TRUNC_MOD_EXPR,
+ TREE_TYPE (arg0), arg0, cst0));
+ }
}
/* Handle (A1 * C1) + (A2 * C2) with A1, A2 or C1, C2 being the
- same or one. */
+ same or one. Make sure type is not saturating.
+ fold_plusminus_mult_expr will re-associate. */
if ((TREE_CODE (arg0) == MULT_EXPR
|| TREE_CODE (arg1) == MULT_EXPR)
- && (!FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations))
+ && !TYPE_SATURATING (type)
+ && (!FLOAT_TYPE_P (type) || flag_associative_math))
{
tree tem = fold_plusminus_mult_expr (code, type, arg0, arg1);
if (tem)
return fold_build2 (MULT_EXPR, type, arg0,
build_real (type, dconst2));
- /* Convert a + (b*c + d*e) into (a + b*c) + d*e. */
- if (flag_unsafe_math_optimizations
+ /* Convert a + (b*c + d*e) into (a + b*c) + d*e.
+ We associate floats only if the user has specified
+ -fassociative-math. */
+ if (flag_associative_math
&& 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). */
- if (flag_unsafe_math_optimizations
+ /* Convert (b*c + d*e) + a into b*c + (d*e +a).
+ We associate floats only if the user has specified
+ -fassociative-math. */
+ if (flag_associative_math
&& TREE_CODE (arg0) == PLUS_EXPR
&& TREE_CODE (arg1) != MULT_EXPR)
{
/* 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, unless the user has specified
- -funsafe-math-optimizations. */
+ -fassociative-math.
+ And, we need to make sure type is not saturating. */
- if (! FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations)
+ if ((! FLOAT_TYPE_P (type) || flag_associative_math)
+ && !TYPE_SATURATING (type))
{
tree var0, con0, lit0, minus_lit0;
tree var1, con1, lit1, minus_lit1;
}
/* A - (-B) -> A + B */
if (TREE_CODE (arg1) == NEGATE_EXPR)
- return fold_build2 (PLUS_EXPR, type, arg0, TREE_OPERAND (arg1, 0));
+ return fold_build2 (PLUS_EXPR, type, op0,
+ fold_convert (type, TREE_OPERAND (arg1, 0)));
/* (-A) - B -> (-B) - A where B is easily negated and we can swap. */
if (TREE_CODE (arg0) == NEGATE_EXPR
&& (FLOAT_TYPE_P (type)
|| INTEGRAL_TYPE_P (type))
&& negate_expr_p (arg1)
&& reorder_operands_p (arg0, arg1))
- return fold_build2 (MINUS_EXPR, type, negate_expr (arg1),
- TREE_OPERAND (arg0, 0));
+ return fold_build2 (MINUS_EXPR, type,
+ fold_convert (type, negate_expr (arg1)),
+ fold_convert (type, TREE_OPERAND (arg0, 0)));
/* Convert -A - 1 to ~A. */
if (INTEGRAL_TYPE_P (type)
&& TREE_CODE (arg0) == NEGATE_EXPR
&& integer_all_onesp (arg0))
return fold_build1 (BIT_NOT_EXPR, type, op1);
+
+ /* X - (X / CST) * CST is X % CST. */
+ if (INTEGRAL_TYPE_P (type)
+ && TREE_CODE (arg1) == MULT_EXPR
+ && TREE_CODE (TREE_OPERAND (arg1, 0)) == TRUNC_DIV_EXPR
+ && operand_equal_p (arg0,
+ TREE_OPERAND (TREE_OPERAND (arg1, 0), 0), 0)
+ && operand_equal_p (TREE_OPERAND (TREE_OPERAND (arg1, 0), 1),
+ TREE_OPERAND (arg1, 1), 0))
+ return fold_convert (type,
+ fold_build2 (TRUNC_MOD_EXPR, TREE_TYPE (arg0),
+ arg0, TREE_OPERAND (arg1, 1)));
+
if (! FLOAT_TYPE_P (type))
{
if (integer_zerop (arg0))
Also note that operand_equal_p is always false if an operand
is volatile. */
- if ((! FLOAT_TYPE_P (type)
- || (flag_unsafe_math_optimizations
- && !HONOR_NANS (TYPE_MODE (type))
- && !HONOR_INFINITIES (TYPE_MODE (type))))
+ if ((!FLOAT_TYPE_P (type) || !HONOR_NANS (TYPE_MODE (type)))
&& operand_equal_p (arg0, arg1, 0))
return fold_convert (type, integer_zero_node);
return tem;
/* Handle (A1 * C1) - (A2 * C2) with A1, A2 or C1, C2 being the
- same or one. */
+ same or one. Make sure type is not saturating.
+ fold_plusminus_mult_expr will re-associate. */
if ((TREE_CODE (arg0) == MULT_EXPR
|| TREE_CODE (arg1) == MULT_EXPR)
- && (!FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations))
+ && !TYPE_SATURATING (type)
+ && (!FLOAT_TYPE_P (type) || flag_associative_math))
{
tree tem = fold_plusminus_mult_expr (code, type, arg0, arg1);
if (tem)
return omit_one_operand (type, arg1, arg0);
if (integer_onep (arg1))
return non_lvalue (fold_convert (type, arg0));
- /* Transform x * -1 into -x. */
+ /* Transform x * -1 into -x. Make sure to do the negation
+ on the original operand with conversions not stripped
+ because we can only strip non-sign-changing conversions. */
if (integer_all_onesp (arg1))
- return fold_convert (type, negate_expr (arg0));
+ return fold_convert (type, negate_expr (op0));
/* Transform x * -C into -x * C if x is easily negatable. */
if (TREE_CODE (arg1) == INTEGER_CST
&& tree_int_cst_sgn (arg1) == -1
&& (tem = negate_expr (arg1)) != arg1
&& !TREE_OVERFLOW (tem))
return fold_build2 (MULT_EXPR, type,
- negate_expr (arg0), tem);
+ fold_convert (type, negate_expr (arg0)), tem);
/* (a * (1 << b)) is (a << b) */
if (TREE_CODE (arg1) == LSHIFT_EXPR
&& integer_onep (TREE_OPERAND (arg1, 0)))
- return fold_build2 (LSHIFT_EXPR, type, arg0,
+ return fold_build2 (LSHIFT_EXPR, type, op0,
TREE_OPERAND (arg1, 1));
if (TREE_CODE (arg0) == LSHIFT_EXPR
&& integer_onep (TREE_OPERAND (arg0, 0)))
- return fold_build2 (LSHIFT_EXPR, type, arg1,
+ return fold_build2 (LSHIFT_EXPR, type, op1,
TREE_OPERAND (arg0, 1));
strict_overflow_p = false;
if (TREE_CODE (arg1) == INTEGER_CST
- && 0 != (tem = extract_muldiv (op0,
- fold_convert (type, arg1),
- code, NULL_TREE,
+ && 0 != (tem = extract_muldiv (op0, arg1, code, NULL_TREE,
&strict_overflow_p)))
{
if (strict_overflow_p)
&& real_minus_onep (arg1))
return fold_convert (type, negate_expr (arg0));
- /* Convert (C1/X)*C2 into (C1*C2)/X. */
- if (flag_unsafe_math_optimizations
+ /* Convert (C1/X)*C2 into (C1*C2)/X. This transformation may change
+ the result for floating point types due to rounding so it is applied
+ only if -fassociative-math was specify. */
+ if (flag_associative_math
&& TREE_CODE (arg0) == RDIV_EXPR
&& TREE_CODE (arg1) == REAL_CST
&& TREE_CODE (TREE_OPERAND (arg0, 0)) == REAL_CST)
if (TREE_CODE (arg0) == BIT_NOT_EXPR
&& operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0))
{
- t1 = build_int_cst_type (type, -1);
+ t1 = fold_convert (type, integer_zero_node);
+ t1 = fold_unary (BIT_NOT_EXPR, type, t1);
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_cst_type (type, -1);
+ t1 = fold_convert (type, integer_zero_node);
+ t1 = fold_unary (BIT_NOT_EXPR, type, t1);
return omit_one_operand (type, t1, arg0);
}
&& TREE_CODE (arg1) == INTEGER_CST
&& TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
{
- unsigned HOST_WIDE_INT hi1, lo1, hi2, lo2, mlo, mhi;
- int width = TYPE_PRECISION (type);
+ unsigned HOST_WIDE_INT hi1, lo1, hi2, lo2, hi3, lo3, mlo, mhi;
+ int width = TYPE_PRECISION (type), w;
hi1 = TREE_INT_CST_HIGH (TREE_OPERAND (arg0, 1));
lo1 = TREE_INT_CST_LOW (TREE_OPERAND (arg0, 1));
hi2 = TREE_INT_CST_HIGH (arg1);
return fold_build2 (BIT_IOR_EXPR, type,
TREE_OPERAND (arg0, 0), arg1);
- /* Minimize the number of bits set in C1, i.e. C1 := C1 & ~C2. */
+ /* Minimize the number of bits set in C1, i.e. C1 := C1 & ~C2,
+ unless (C1 & ~C2) | (C2 & C3) for some C3 is a mask of some
+ mode which allows further optimizations. */
hi1 &= mhi;
lo1 &= mlo;
- if ((hi1 & ~hi2) != hi1 || (lo1 & ~lo2) != lo1)
+ hi2 &= mhi;
+ lo2 &= mlo;
+ hi3 = hi1 & ~hi2;
+ lo3 = lo1 & ~lo2;
+ for (w = BITS_PER_UNIT;
+ w <= width && w <= HOST_BITS_PER_WIDE_INT;
+ w <<= 1)
+ {
+ unsigned HOST_WIDE_INT mask
+ = (unsigned HOST_WIDE_INT) -1 >> (HOST_BITS_PER_WIDE_INT - w);
+ if (((lo1 | lo2) & mask) == mask
+ && (lo1 & ~mask) == 0 && hi1 == 0)
+ {
+ hi3 = 0;
+ lo3 = mask;
+ break;
+ }
+ }
+ if (hi3 != hi1 || lo3 != lo1)
return fold_build2 (BIT_IOR_EXPR, type,
fold_build2 (BIT_AND_EXPR, type,
TREE_OPERAND (arg0, 0),
build_int_cst_wide (type,
- lo1 & ~lo2,
- hi1 & ~hi2)),
+ lo3, hi3)),
arg1);
}
if (TREE_CODE (arg0) == BIT_NOT_EXPR
&& operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0))
{
- t1 = build_int_cst_type (type, -1);
+ t1 = fold_convert (type, integer_zero_node);
+ t1 = fold_unary (BIT_NOT_EXPR, type, t1);
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_cst_type (type, -1);
+ t1 = fold_convert (type, integer_zero_node);
+ t1 = fold_unary (BIT_NOT_EXPR, type, t1);
return omit_one_operand (type, t1, arg0);
}
if (TREE_CODE (arg0) == BIT_IOR_EXPR
&& TREE_CODE (arg1) == INTEGER_CST
&& TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
- return fold_build2 (BIT_IOR_EXPR, type,
- fold_build2 (BIT_AND_EXPR, type,
- TREE_OPERAND (arg0, 0), arg1),
- fold_build2 (BIT_AND_EXPR, type,
- TREE_OPERAND (arg0, 1), arg1));
+ {
+ tree tmp1 = fold_convert (TREE_TYPE (arg0), arg1);
+ tree tmp2 = fold_build2 (BIT_AND_EXPR, TREE_TYPE (arg0),
+ TREE_OPERAND (arg0, 0), tmp1);
+ tree tmp3 = fold_build2 (BIT_AND_EXPR, TREE_TYPE (arg0),
+ TREE_OPERAND (arg0, 1), tmp1);
+ return fold_convert (type,
+ fold_build2 (BIT_IOR_EXPR, TREE_TYPE (arg0),
+ tmp2, tmp3));
+ }
/* (X | Y) & Y is (X, Y). */
if (TREE_CODE (arg0) == BIT_IOR_EXPR
{
return fold_build1 (BIT_NOT_EXPR, type,
build2 (BIT_IOR_EXPR, type,
- TREE_OPERAND (arg0, 0),
- TREE_OPERAND (arg1, 0)));
+ fold_convert (type,
+ TREE_OPERAND (arg0, 0)),
+ fold_convert (type,
+ TREE_OPERAND (arg1, 0))));
+ }
+
+ /* If arg0 is derived from the address of an object or function, we may
+ be able to fold this expression using the object or function's
+ alignment. */
+ if (POINTER_TYPE_P (TREE_TYPE (arg0)) && host_integerp (arg1, 1))
+ {
+ unsigned HOST_WIDE_INT modulus, residue;
+ unsigned HOST_WIDE_INT low = TREE_INT_CST_LOW (arg1);
+
+ modulus = get_pointer_modulus_and_residue (arg0, &residue);
+
+ /* This works because modulus is a power of 2. If this weren't the
+ case, we'd have to replace it by its greatest power-of-2
+ divisor: modulus & -modulus. */
+ if (low < modulus)
+ return build_int_cst (type, residue & low);
+ }
+
+ /* Fold (X << C1) & C2 into (X << C1) & (C2 | ((1 << C1) - 1))
+ (X >> C1) & C2 into (X >> C1) & (C2 | ~((type) -1 >> C1))
+ if the new mask might be further optimized. */
+ if ((TREE_CODE (arg0) == LSHIFT_EXPR
+ || TREE_CODE (arg0) == RSHIFT_EXPR)
+ && host_integerp (TREE_OPERAND (arg0, 1), 1)
+ && host_integerp (arg1, TYPE_UNSIGNED (TREE_TYPE (arg1)))
+ && tree_low_cst (TREE_OPERAND (arg0, 1), 1)
+ < TYPE_PRECISION (TREE_TYPE (arg0))
+ && TYPE_PRECISION (TREE_TYPE (arg0)) <= HOST_BITS_PER_WIDE_INT
+ && tree_low_cst (TREE_OPERAND (arg0, 1), 1) > 0)
+ {
+ unsigned int shiftc = tree_low_cst (TREE_OPERAND (arg0, 1), 1);
+ unsigned HOST_WIDE_INT mask
+ = tree_low_cst (arg1, TYPE_UNSIGNED (TREE_TYPE (arg1)));
+ unsigned HOST_WIDE_INT newmask, zerobits = 0;
+ tree shift_type = TREE_TYPE (arg0);
+
+ if (TREE_CODE (arg0) == LSHIFT_EXPR)
+ zerobits = ((((unsigned HOST_WIDE_INT) 1) << shiftc) - 1);
+ else if (TREE_CODE (arg0) == RSHIFT_EXPR
+ && TYPE_PRECISION (TREE_TYPE (arg0))
+ == GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (arg0))))
+ {
+ unsigned int prec = TYPE_PRECISION (TREE_TYPE (arg0));
+ tree arg00 = TREE_OPERAND (arg0, 0);
+ /* See if more bits can be proven as zero because of
+ zero extension. */
+ if (TREE_CODE (arg00) == NOP_EXPR
+ && TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (arg00, 0))))
+ {
+ tree inner_type = TREE_TYPE (TREE_OPERAND (arg00, 0));
+ if (TYPE_PRECISION (inner_type)
+ == GET_MODE_BITSIZE (TYPE_MODE (inner_type))
+ && TYPE_PRECISION (inner_type) < prec)
+ {
+ prec = TYPE_PRECISION (inner_type);
+ /* See if we can shorten the right shift. */
+ if (shiftc < prec)
+ shift_type = inner_type;
+ }
+ }
+ zerobits = ~(unsigned HOST_WIDE_INT) 0;
+ zerobits >>= HOST_BITS_PER_WIDE_INT - shiftc;
+ zerobits <<= prec - shiftc;
+ /* For arithmetic shift if sign bit could be set, zerobits
+ can contain actually sign bits, so no transformation is
+ possible, unless MASK masks them all away. In that
+ case the shift needs to be converted into logical shift. */
+ if (!TYPE_UNSIGNED (TREE_TYPE (arg0))
+ && prec == TYPE_PRECISION (TREE_TYPE (arg0)))
+ {
+ if ((mask & zerobits) == 0)
+ shift_type = unsigned_type_for (TREE_TYPE (arg0));
+ else
+ zerobits = 0;
+ }
+ }
+
+ /* ((X << 16) & 0xff00) is (X, 0). */
+ if ((mask & zerobits) == mask)
+ return omit_one_operand (type, build_int_cst (type, 0), arg0);
+
+ newmask = mask | zerobits;
+ if (newmask != mask && (newmask & (newmask + 1)) == 0)
+ {
+ unsigned int prec;
+
+ /* Only do the transformation if NEWMASK is some integer
+ mode's mask. */
+ for (prec = BITS_PER_UNIT;
+ prec < HOST_BITS_PER_WIDE_INT; prec <<= 1)
+ if (newmask == (((unsigned HOST_WIDE_INT) 1) << prec) - 1)
+ break;
+ if (prec < HOST_BITS_PER_WIDE_INT
+ || newmask == ~(unsigned HOST_WIDE_INT) 0)
+ {
+ if (shift_type != TREE_TYPE (arg0))
+ {
+ tem = fold_build2 (TREE_CODE (arg0), shift_type,
+ fold_convert (shift_type,
+ TREE_OPERAND (arg0, 0)),
+ TREE_OPERAND (arg0, 1));
+ tem = fold_convert (type, tem);
+ }
+ else
+ tem = op0;
+ return fold_build2 (BIT_AND_EXPR, type, tem,
+ build_int_cst_type (TREE_TYPE (op1),
+ newmask));
+ }
+ }
}
goto associate;
/* 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
+ so only do this if -freciprocal-math. We can actually
always safely do it if ARG1 is a power of two, but it's hard to
tell if it is or not in a portable manner. */
if (TREE_CODE (arg1) == REAL_CST)
{
- if (flag_unsafe_math_optimizations
+ if (flag_reciprocal_math
&& 0 != (tem = const_binop (code, build_real (type, dconst1),
arg1, 0)))
return fold_build2 (MULT_EXPR, type, arg0, tem);
}
}
}
- /* Convert A/B/C to A/(B*C). */
- if (flag_unsafe_math_optimizations
+ /* Convert A/B/C to A/(B*C). */
+ if (flag_reciprocal_math
&& TREE_CODE (arg0) == RDIV_EXPR)
return fold_build2 (RDIV_EXPR, type, TREE_OPERAND (arg0, 0),
fold_build2 (MULT_EXPR, type,
TREE_OPERAND (arg0, 1), arg1));
/* Convert A/(B/C) to (A/B)*C. */
- if (flag_unsafe_math_optimizations
+ if (flag_reciprocal_math
&& TREE_CODE (arg1) == RDIV_EXPR)
return fold_build2 (MULT_EXPR, type,
fold_build2 (RDIV_EXPR, type, arg0,
TREE_OPERAND (arg1, 1));
/* Convert C1/(X*C2) into (C1/C2)/X. */
- if (flag_unsafe_math_optimizations
+ if (flag_reciprocal_math
&& TREE_CODE (arg1) == MULT_EXPR
&& TREE_CODE (arg0) == REAL_CST
&& TREE_CODE (TREE_OPERAND (arg1, 1)) == REAL_CST)
strict_overflow_p = false;
if (TREE_CODE (arg1) == LSHIFT_EXPR
&& (TYPE_UNSIGNED (type)
- || tree_expr_nonnegative_warnv_p (arg0, &strict_overflow_p)))
+ || tree_expr_nonnegative_warnv_p (op0, &strict_overflow_p)))
{
tree sval = TREE_OPERAND (arg1, 0);
if (integer_pow2p (sval) && tree_int_cst_sgn (sval) > 0)
fold_convert (type, arg0), sh_cnt);
}
}
+
+ /* For unsigned integral types, FLOOR_DIV_EXPR is the same as
+ TRUNC_DIV_EXPR. Rewrite into the latter in this case. */
+ if (INTEGRAL_TYPE_P (type)
+ && TYPE_UNSIGNED (type)
+ && code == FLOOR_DIV_EXPR)
+ return fold_build2 (TRUNC_DIV_EXPR, type, op0, op1);
+
/* Fall thru */
case ROUND_DIV_EXPR:
strict_overflow_p = false;
if ((code == TRUNC_MOD_EXPR || code == FLOOR_MOD_EXPR)
&& (TYPE_UNSIGNED (type)
- || tree_expr_nonnegative_warnv_p (arg0, &strict_overflow_p)))
+ || tree_expr_nonnegative_warnv_p (op0, &strict_overflow_p)))
{
tree c = arg1;
/* Also optimize A % (C << N) where C is a power of 2,
tree tem = build_int_cst (TREE_TYPE (arg1),
GET_MODE_BITSIZE (TYPE_MODE (type)));
tem = const_binop (MINUS_EXPR, tem, arg1, 0);
- return fold_build2 (RROTATE_EXPR, type, arg0, tem);
+ return fold_build2 (RROTATE_EXPR, type, op0, tem);
}
/* If we have a rotate of a bit operation with the rotate count and
== (unsigned int) GET_MODE_BITSIZE (TYPE_MODE (type))))
return TREE_OPERAND (arg0, 0);
+ /* Fold (X & C2) << C1 into (X << C1) & (C2 << C1)
+ (X & C2) >> C1 into (X >> C1) & (C2 >> C1)
+ if the latter can be further optimized. */
+ if ((code == LSHIFT_EXPR || code == RSHIFT_EXPR)
+ && TREE_CODE (arg0) == BIT_AND_EXPR
+ && TREE_CODE (arg1) == INTEGER_CST
+ && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
+ {
+ tree mask = fold_build2 (code, type,
+ fold_convert (type, TREE_OPERAND (arg0, 1)),
+ arg1);
+ tree shift = fold_build2 (code, type,
+ fold_convert (type, TREE_OPERAND (arg0, 0)),
+ arg1);
+ tem = fold_binary (BIT_AND_EXPR, type, shift, mask);
+ if (tem)
+ return tem;
+ }
+
return NULL_TREE;
case MIN_EXPR:
/* bool_var != 1 becomes !bool_var. */
if (TREE_CODE (TREE_TYPE (arg0)) == BOOLEAN_TYPE && integer_onep (arg1)
&& code == NE_EXPR)
- return fold_build1 (TRUTH_NOT_EXPR, type, arg0);
+ return fold_build1 (TRUTH_NOT_EXPR, type, fold_convert (type, arg0));
/* bool_var == 0 becomes !bool_var. */
if (TREE_CODE (TREE_TYPE (arg0)) == BOOLEAN_TYPE && integer_zerop (arg1)
&& code == EQ_EXPR)
- return fold_build1 (TRUTH_NOT_EXPR, type, arg0);
+ return fold_build1 (TRUTH_NOT_EXPR, type, fold_convert (type, arg0));
/* If this is an equality comparison of the address of two non-weak,
unaliased symbols neither of which are extern (since we do not
tree arg01 = TREE_OPERAND (arg0, 1);
if (TREE_CODE (arg00) == LSHIFT_EXPR
&& integer_onep (TREE_OPERAND (arg00, 0)))
- return
- fold_build2 (code, type,
- build2 (BIT_AND_EXPR, TREE_TYPE (arg0),
- build2 (RSHIFT_EXPR, TREE_TYPE (arg00),
- arg01, TREE_OPERAND (arg00, 1)),
- fold_convert (TREE_TYPE (arg0),
- integer_one_node)),
- arg1);
- else if (TREE_CODE (TREE_OPERAND (arg0, 1)) == LSHIFT_EXPR
- && integer_onep (TREE_OPERAND (TREE_OPERAND (arg0, 1), 0)))
- return
- fold_build2 (code, type,
- build2 (BIT_AND_EXPR, TREE_TYPE (arg0),
- build2 (RSHIFT_EXPR, TREE_TYPE (arg01),
- arg00, TREE_OPERAND (arg01, 1)),
- fold_convert (TREE_TYPE (arg0),
- integer_one_node)),
- arg1);
+ {
+ tree tem = fold_build2 (RSHIFT_EXPR, TREE_TYPE (arg00),
+ arg01, TREE_OPERAND (arg00, 1));
+ tem = fold_build2 (BIT_AND_EXPR, TREE_TYPE (arg0), tem,
+ build_int_cst (TREE_TYPE (arg0), 1));
+ return fold_build2 (code, type,
+ fold_convert (TREE_TYPE (arg1), tem), arg1);
+ }
+ else if (TREE_CODE (arg01) == LSHIFT_EXPR
+ && integer_onep (TREE_OPERAND (arg01, 0)))
+ {
+ tree tem = fold_build2 (RSHIFT_EXPR, TREE_TYPE (arg01),
+ arg00, TREE_OPERAND (arg01, 1));
+ tem = fold_build2 (BIT_AND_EXPR, TREE_TYPE (arg0), tem,
+ build_int_cst (TREE_TYPE (arg0), 1));
+ return fold_build2 (code, type,
+ fold_convert (TREE_TYPE (arg1), tem), arg1);
+ }
}
/* If this is an NE or EQ comparison of zero against the result of a
#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);
+static void fold_checksum_tree (const_tree, struct md5_ctx *, htab_t);
+static void fold_check_failed (const_tree, const_tree);
+void print_fold_checksum (const_tree);
/* When --enable-checking=fold, compute a digest of expr before
and after actual fold call to see if fold did not accidentally
}
void
-print_fold_checksum (tree expr)
+print_fold_checksum (const_tree expr)
{
struct md5_ctx ctx;
unsigned char checksum[16], cnt;
}
static void
-fold_check_failed (tree expr ATTRIBUTE_UNUSED, tree ret ATTRIBUTE_UNUSED)
+fold_check_failed (const_tree expr ATTRIBUTE_UNUSED, const_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)
+fold_checksum_tree (const_tree expr, struct md5_ctx *ctx, htab_t ht)
{
- void **slot;
+ const void **slot;
enum tree_code code;
struct tree_function_decl buf;
int i, len;
&& sizeof (struct tree_type) <= sizeof (struct tree_function_decl));
if (expr == NULL)
return;
- slot = htab_find_slot (ht, expr, INSERT);
+ slot = (const void **) htab_find_slot (ht, expr, INSERT);
if (*slot != NULL)
return;
*slot = expr;
{
/* Allow DECL_ASSEMBLER_NAME to be modified. */
memcpy ((char *) &buf, expr, tree_size (expr));
+ SET_DECL_ASSEMBLER_NAME ((tree)&buf, NULL);
expr = (tree) &buf;
- SET_DECL_ASSEMBLER_NAME (expr, NULL);
}
else if (TREE_CODE_CLASS (code) == tcc_type
&& (TYPE_POINTER_TO (expr) || TYPE_REFERENCE_TO (expr)
|| TYPE_CONTAINS_PLACEHOLDER_INTERNAL (expr)))
{
/* Allow these fields to be modified. */
+ tree tmp;
memcpy ((char *) &buf, expr, tree_size (expr));
- expr = (tree) &buf;
- TYPE_CONTAINS_PLACEHOLDER_INTERNAL (expr) = 0;
- TYPE_POINTER_TO (expr) = NULL;
- TYPE_REFERENCE_TO (expr) = NULL;
- if (TYPE_CACHED_VALUES_P (expr))
+ expr = tmp = (tree) &buf;
+ TYPE_CONTAINS_PLACEHOLDER_INTERNAL (tmp) = 0;
+ TYPE_POINTER_TO (tmp) = NULL;
+ TYPE_REFERENCE_TO (tmp) = NULL;
+ if (TYPE_CACHED_VALUES_P (tmp))
{
- TYPE_CACHED_VALUES_P (expr) = 0;
- TYPE_CACHED_VALUES (expr) = NULL;
+ TYPE_CACHED_VALUES_P (tmp) = 0;
+ TYPE_CACHED_VALUES (tmp) = NULL;
}
}
md5_process_bytes (expr, tree_size (expr), ctx);
outputs differ. */
void
-debug_fold_checksum (tree t)
+debug_fold_checksum (const_tree t)
{
int i;
unsigned char checksum[16];
transformed version). */
int
-multiple_of_p (tree type, tree top, tree bottom)
+multiple_of_p (tree type, const_tree top, const_tree bottom)
{
if (operand_equal_p (top, bottom, 0))
return 1;
case REAL_CST:
return ! REAL_VALUE_NEGATIVE (TREE_REAL_CST (t));
+ case FIXED_CST:
+ return ! FIXED_VALUE_NEGATIVE (TREE_FIXED_CST (t));
+
case POINTER_PLUS_EXPR:
case PLUS_EXPR:
if (FLOAT_TYPE_P (TREE_TYPE (t)))
}
/* Return the tree for neg (ARG0) when ARG0 is known to be either
- an integer constant or real constant.
+ an integer constant, real, or fixed-point constant.
TYPE is the type of the result. */
t = build_real (type, REAL_VALUE_NEGATE (TREE_REAL_CST (arg0)));
break;
+ case FIXED_CST:
+ {
+ FIXED_VALUE_TYPE f;
+ bool overflow_p = fixed_arithmetic (&f, NEGATE_EXPR,
+ &(TREE_FIXED_CST (arg0)), NULL,
+ TYPE_SATURATING (type));
+ t = build_fixed (type, f);
+ /* Propagate overflow flags. */
+ if (overflow_p | TREE_OVERFLOW (arg0))
+ {
+ TREE_OVERFLOW (t) = 1;
+ TREE_CONSTANT_OVERFLOW (t) = 1;
+ }
+ else if (TREE_CONSTANT_OVERFLOW (arg0))
+ TREE_CONSTANT_OVERFLOW (t) = 1;
+ break;
+ }
+
default:
gcc_unreachable ();
}
return constant_boolean_node (real_compare (code, c0, c1), type);
}
+ if (TREE_CODE (op0) == FIXED_CST && TREE_CODE (op1) == FIXED_CST)
+ {
+ const FIXED_VALUE_TYPE *c0 = TREE_FIXED_CST_PTR (op0);
+ const FIXED_VALUE_TYPE *c1 = TREE_FIXED_CST_PTR (op1);
+ return constant_boolean_node (fixed_compare (code, c0, c1), type);
+ }
+
/* Handle equality/inequality of complex constants. */
if (TREE_CODE (op0) == COMPLEX_CST && TREE_CODE (op1) == COMPLEX_CST)
{