/* Fold a constant sub-tree into a single node for C-compiler
- Copyright (C) 1987-2016 Free Software Foundation, Inc.
+ Copyright (C) 1987-2017 Free Software Foundation, Inc.
This file is part of GCC.
#include "tree.h"
#include "gimple.h"
#include "predict.h"
+#include "memmodel.h"
#include "tm_p.h"
#include "tree-ssa-operands.h"
#include "optabs-query.h"
#include "md5.h"
#include "case-cfn-macros.h"
#include "stringpool.h"
+#include "tree-vrp.h"
#include "tree-ssanames.h"
#include "selftest.h"
-#ifndef LOAD_EXTEND_OP
-#define LOAD_EXTEND_OP(M) UNKNOWN
-#endif
-
/* Nonzero if we are folding constants inside an initializer; zero
otherwise. */
int folding_initializer = 0;
tree, tree,
tree, tree, int);
static tree fold_div_compare (location_t, enum tree_code, tree, tree, tree);
-static bool reorder_operands_p (const_tree, const_tree);
static tree fold_negate_const (tree, tree);
static tree fold_not_const (const_tree, tree);
static tree fold_relational_const (enum tree_code, tree, tree, tree);
static tree fold_convert_const (enum tree_code, tree, tree);
static tree fold_view_convert_expr (tree, tree);
static bool vec_cst_ctor_to_array (tree, tree *);
+static tree fold_negate_expr (location_t, tree);
/* Return EXPR_LOCATION of T if it is not UNKNOWN_LOCATION.
&& ! TYPE_OVERFLOW_WRAPS (type)))
return false;
/* -(A + B) -> (-B) - A. */
- if (negate_expr_p (TREE_OPERAND (t, 1))
- && reorder_operands_p (TREE_OPERAND (t, 0),
- TREE_OPERAND (t, 1)))
+ if (negate_expr_p (TREE_OPERAND (t, 1)))
return true;
/* -(A + B) -> (-A) - B. */
return negate_expr_p (TREE_OPERAND (t, 0));
return !HONOR_SIGN_DEPENDENT_ROUNDING (element_mode (type))
&& !HONOR_SIGNED_ZEROS (element_mode (type))
&& (! INTEGRAL_TYPE_P (type)
- || TYPE_OVERFLOW_WRAPS (type))
- && reorder_operands_p (TREE_OPERAND (t, 0),
- TREE_OPERAND (t, 1));
+ || TYPE_OVERFLOW_WRAPS (type));
case MULT_EXPR:
if (TYPE_UNSIGNED (type))
break;
/* INT_MIN/n * n doesn't overflow while negating one operand it does
- if n is a power of two. */
+ if n is a (negative) power of two. */
if (INTEGRAL_TYPE_P (TREE_TYPE (t))
&& ! TYPE_OVERFLOW_WRAPS (TREE_TYPE (t))
&& ! ((TREE_CODE (TREE_OPERAND (t, 0)) == INTEGER_CST
- && ! integer_pow2p (TREE_OPERAND (t, 0)))
+ && wi::popcount (wi::abs (TREE_OPERAND (t, 0))) != 1)
|| (TREE_CODE (TREE_OPERAND (t, 1)) == INTEGER_CST
- && ! integer_pow2p (TREE_OPERAND (t, 1)))))
+ && wi::popcount (wi::abs (TREE_OPERAND (t, 1))) != 1)))
break;
/* Fall through. */
returned. */
static tree
-fold_negate_expr (location_t loc, tree t)
+fold_negate_expr_1 (location_t loc, tree t)
{
tree type = TREE_TYPE (t);
tree tem;
case BIT_NOT_EXPR:
if (INTEGRAL_TYPE_P (type))
return fold_build2_loc (loc, PLUS_EXPR, type, TREE_OPERAND (t, 0),
- build_one_cst (type));
+ build_one_cst (type));
break;
case INTEGER_CST:
case COMPLEX_EXPR:
if (negate_expr_p (t))
return fold_build2_loc (loc, COMPLEX_EXPR, type,
- fold_negate_expr (loc, TREE_OPERAND (t, 0)),
- fold_negate_expr (loc, TREE_OPERAND (t, 1)));
+ fold_negate_expr (loc, TREE_OPERAND (t, 0)),
+ fold_negate_expr (loc, TREE_OPERAND (t, 1)));
break;
case CONJ_EXPR:
if (negate_expr_p (t))
return fold_build1_loc (loc, CONJ_EXPR, type,
- fold_negate_expr (loc, TREE_OPERAND (t, 0)));
+ fold_negate_expr (loc, TREE_OPERAND (t, 0)));
break;
case NEGATE_EXPR:
&& !HONOR_SIGNED_ZEROS (element_mode (type)))
{
/* -(A + B) -> (-B) - A. */
- if (negate_expr_p (TREE_OPERAND (t, 1))
- && reorder_operands_p (TREE_OPERAND (t, 0),
- TREE_OPERAND (t, 1)))
+ if (negate_expr_p (TREE_OPERAND (t, 1)))
{
tem = negate_expr (TREE_OPERAND (t, 1));
return fold_build2_loc (loc, MINUS_EXPR, type,
- tem, TREE_OPERAND (t, 0));
+ tem, TREE_OPERAND (t, 0));
}
/* -(A + B) -> (-A) - B. */
{
tem = negate_expr (TREE_OPERAND (t, 0));
return fold_build2_loc (loc, MINUS_EXPR, type,
- tem, TREE_OPERAND (t, 1));
+ tem, TREE_OPERAND (t, 1));
}
}
break;
case MINUS_EXPR:
/* - (A - B) -> B - A */
if (!HONOR_SIGN_DEPENDENT_ROUNDING (element_mode (type))
- && !HONOR_SIGNED_ZEROS (element_mode (type))
- && reorder_operands_p (TREE_OPERAND (t, 0), TREE_OPERAND (t, 1)))
+ && !HONOR_SIGNED_ZEROS (element_mode (type)))
return fold_build2_loc (loc, MINUS_EXPR, type,
- TREE_OPERAND (t, 1), TREE_OPERAND (t, 0));
+ TREE_OPERAND (t, 1), TREE_OPERAND (t, 0));
break;
case MULT_EXPR:
tem = TREE_OPERAND (t, 1);
if (negate_expr_p (tem))
return fold_build2_loc (loc, TREE_CODE (t), type,
- TREE_OPERAND (t, 0), negate_expr (tem));
+ TREE_OPERAND (t, 0), negate_expr (tem));
tem = TREE_OPERAND (t, 0);
if (negate_expr_p (tem))
return fold_build2_loc (loc, TREE_CODE (t), type,
- negate_expr (tem), TREE_OPERAND (t, 1));
+ negate_expr (tem), TREE_OPERAND (t, 1));
}
break;
return NULL_TREE;
}
+/* A wrapper for fold_negate_expr_1. */
+
+static tree
+fold_negate_expr (location_t loc, tree t)
+{
+ tree type = TREE_TYPE (t);
+ STRIP_SIGN_NOPS (t);
+ tree tem = fold_negate_expr_1 (loc, t);
+ if (tem == NULL_TREE)
+ return NULL_TREE;
+ return fold_convert_loc (loc, type, tem);
+}
+
/* Like fold_negate_expr, but return a NEGATE_EXPR tree, if T can not be
negated in a simpler way. Also allow for T to be NULL_TREE, in which case
return NULL_TREE. */
though the C standard doesn't say so) for integers because
the value is not affected. For reals, the value might be
affected, so we can't. */
- && ((code == PLUS_EXPR && TREE_CODE (in) == MINUS_EXPR)
- || (code == MINUS_EXPR && TREE_CODE (in) == PLUS_EXPR))))
+ && ((code == PLUS_EXPR && TREE_CODE (in) == POINTER_PLUS_EXPR)
+ || (code == PLUS_EXPR && TREE_CODE (in) == MINUS_EXPR)
+ || (code == MINUS_EXPR
+ && (TREE_CODE (in) == PLUS_EXPR
+ || TREE_CODE (in) == POINTER_PLUS_EXPR)))))
{
tree op0 = TREE_OPERAND (in, 0);
tree op1 = TREE_OPERAND (in, 1);
/* Now do any needed negations. */
if (neg_litp_p)
*minus_litp = *litp, *litp = 0;
- if (neg_conp_p)
- *conp = negate_expr (*conp);
+ if (neg_conp_p && *conp)
+ {
+ /* Convert to TYPE before negating. */
+ *conp = fold_convert_loc (loc, type, *conp);
+ *conp = negate_expr (*conp);
+ }
if (neg_var_p && var)
{
/* Convert to TYPE before negating. */
var = negate_expr (var);
}
}
+ else if (TREE_CONSTANT (in))
+ *conp = in;
else if (TREE_CODE (in) == BIT_NOT_EXPR
&& code == PLUS_EXPR)
{
- /* -X - 1 is folded to ~X, undo that here. */
+ /* -X - 1 is folded to ~X, undo that here. Do _not_ do this
+ when IN is constant. */
*minus_litp = build_one_cst (TREE_TYPE (in));
var = negate_expr (TREE_OPERAND (in, 0));
}
- else if (TREE_CONSTANT (in))
- *conp = in;
else
var = in;
*minus_litp = *litp, *litp = 0;
else if (*minus_litp)
*litp = *minus_litp, *minus_litp = 0;
- *conp = negate_expr (*conp);
+ if (*conp)
+ {
+ /* Convert to TYPE before negating. */
+ *conp = fold_convert_loc (loc, type, *conp);
+ *conp = negate_expr (*conp);
+ }
if (var)
{
/* Convert to TYPE before negating. */
return NULL_TREE;
wide_int w2 = arg2;
f2.data.high = w2.elt (1);
- f2.data.low = w2.elt (0);
+ f2.data.low = w2.ulow ();
f2.mode = SImode;
}
break;
return do_mpc_arg2 (arg1, arg2, type,
/* do_nonfinite= */ folding_initializer,
mpc_div);
- /* Fallthru ... */
+ /* Fallthru. */
case TRUNC_DIV_EXPR:
case CEIL_DIV_EXPR:
case FLOOR_DIV_EXPR:
If OEP_ADDRESS_OF is set, we are actually comparing addresses of objects,
not values of expressions.
+ If OEP_LEXICOGRAPHIC is set, then also handle expressions with side-effects
+ such as MODIFY_EXPR, RETURN_EXPR, as well as STATEMENT_LISTs.
+
Unless OEP_MATCH_SIDE_EFFECTS is set, the function returns false on
any operand with side effect. This is unnecesarily conservative in the
case we know that arg0 and arg1 are in disjoint code paths (such as in
case CONSTRUCTOR:
/* In GIMPLE empty constructors are allowed in initializers of
aggregates. */
- return (!vec_safe_length (CONSTRUCTOR_ELTS (arg0))
- && !vec_safe_length (CONSTRUCTOR_ELTS (arg1)));
+ return !CONSTRUCTOR_NELTS (arg0) && !CONSTRUCTOR_NELTS (arg1);
default:
break;
}
TREE_OPERAND (arg1, 0), flags));
case COND_EXPR:
- if (! OP_SAME (1) || ! OP_SAME (2))
+ if (! OP_SAME (1) || ! OP_SAME_WITH_NULL (2))
return 0;
flags &= ~OEP_ADDRESS_OF;
return OP_SAME (0);
case BIT_INSERT_EXPR:
return OP_SAME (0) && OP_SAME (1) && OP_SAME (2);
+ case MODIFY_EXPR:
+ case INIT_EXPR:
+ case COMPOUND_EXPR:
+ case PREDECREMENT_EXPR:
+ case PREINCREMENT_EXPR:
+ case POSTDECREMENT_EXPR:
+ case POSTINCREMENT_EXPR:
+ if (flags & OEP_LEXICOGRAPHIC)
+ return OP_SAME (0) && OP_SAME (1);
+ return 0;
+
+ case CLEANUP_POINT_EXPR:
+ case EXPR_STMT:
+ if (flags & OEP_LEXICOGRAPHIC)
+ return OP_SAME (0);
+ return 0;
+
default:
return 0;
}
cef &= ECF_CONST | ECF_PURE;
else
cef &= ECF_CONST;
- if (!cef)
+ if (!cef && !(flags & OEP_LEXICOGRAPHIC))
return 0;
}
}
return 1;
}
+ else if (TREE_CODE (arg0) == STATEMENT_LIST
+ && (flags & OEP_LEXICOGRAPHIC))
+ {
+ /* Compare the STATEMENT_LISTs. */
+ tree_stmt_iterator tsi1, tsi2;
+ tree body1 = CONST_CAST_TREE (arg0);
+ tree body2 = CONST_CAST_TREE (arg1);
+ for (tsi1 = tsi_start (body1), tsi2 = tsi_start (body2); ;
+ tsi_next (&tsi1), tsi_next (&tsi2))
+ {
+ /* The lists don't have the same number of statements. */
+ if (tsi_end_p (tsi1) ^ tsi_end_p (tsi2))
+ return 0;
+ if (tsi_end_p (tsi1) && tsi_end_p (tsi2))
+ return 1;
+ if (!operand_equal_p (tsi_stmt (tsi1), tsi_stmt (tsi2),
+ OEP_LEXICOGRAPHIC))
+ return 0;
+ }
+ }
return 0;
+ case tcc_statement:
+ switch (TREE_CODE (arg0))
+ {
+ case RETURN_EXPR:
+ if (flags & OEP_LEXICOGRAPHIC)
+ return OP_SAME_WITH_NULL (0);
+ return 0;
+ default:
+ return 0;
+ }
+
default:
return 0;
}
if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE)
return build1_loc (loc, TRUTH_NOT_EXPR, type, arg);
- /* ... fall through ... */
+ /* fall through */
case FLOAT_EXPR:
loc1 = expr_location_or (TREE_OPERAND (arg, 0), loc);
{
tree result, bftype;
- if (get_alias_set (inner) != get_alias_set (orig_inner))
+ /* Attempt not to lose the access path if possible. */
+ if (TREE_CODE (orig_inner) == COMPONENT_REF)
+ {
+ tree ninner = TREE_OPERAND (orig_inner, 0);
+ machine_mode nmode;
+ HOST_WIDE_INT nbitsize, nbitpos;
+ tree noffset;
+ int nunsignedp, nreversep, nvolatilep = 0;
+ tree base = get_inner_reference (ninner, &nbitsize, &nbitpos,
+ &noffset, &nmode, &nunsignedp,
+ &nreversep, &nvolatilep);
+ if (base == inner
+ && noffset == NULL_TREE
+ && nbitsize >= bitsize
+ && nbitpos <= bitpos
+ && bitpos + bitsize <= nbitpos + nbitsize
+ && !reversep
+ && !nreversep
+ && !nvolatilep)
+ {
+ inner = ninner;
+ bitpos -= nbitpos;
+ }
+ }
+
+ alias_set_type iset = get_alias_set (orig_inner);
+ if (iset == 0 && get_alias_set (inner) != iset)
inner = fold_build2 (MEM_REF, TREE_TYPE (inner),
build_fold_addr_expr (inner),
- build_int_cst
- (reference_alias_ptr_type (orig_inner), 0));
+ build_int_cst (ptr_type_node, 0));
if (bitpos == 0 && !reversep)
{
punsignedp, preversep, pvolatilep);
if ((inner == exp && and_mask == 0)
|| *pbitsize < 0 || offset != 0
- || TREE_CODE (inner) == PLACEHOLDER_EXPR)
+ || TREE_CODE (inner) == PLACEHOLDER_EXPR
+ /* Reject out-of-bound accesses (PR79731). */
+ || (! AGGREGATE_TYPE_P (TREE_TYPE (inner))
+ && compare_tree_int (TYPE_SIZE (TREE_TYPE (inner)),
+ *pbitpos + *pbitsize) < 0))
return 0;
*exp_ = exp;
*pin_p = in_p, *plow = low, *phigh = high;
return exp;
}
+
+/* Returns TRUE if [LOW, HIGH] range check can be optimized to
+ a bitwise check i.e. when
+ LOW == 0xXX...X00...0
+ HIGH == 0xXX...X11...1
+ Return corresponding mask in MASK and stem in VALUE. */
+
+static bool
+maskable_range_p (const_tree low, const_tree high, tree type, tree *mask,
+ tree *value)
+{
+ if (TREE_CODE (low) != INTEGER_CST
+ || TREE_CODE (high) != INTEGER_CST)
+ return false;
+
+ unsigned prec = TYPE_PRECISION (type);
+ wide_int lo = wi::to_wide (low, prec);
+ wide_int hi = wi::to_wide (high, prec);
+
+ wide_int end_mask = lo ^ hi;
+ if ((end_mask & (end_mask + 1)) != 0
+ || (lo & end_mask) != 0)
+ return false;
+
+ wide_int stem_mask = ~end_mask;
+ wide_int stem = lo & stem_mask;
+ if (stem != (hi & stem_mask))
+ return false;
+
+ *mask = wide_int_to_tree (type, stem_mask);
+ *value = wide_int_to_tree (type, stem);
+
+ return true;
+}
\f
/* Given a range, LOW, HIGH, and IN_P, an expression, EXP, and a result
type, TYPE, return an expression to test if EXP is in (or out of, depending
build_range_check (location_t loc, tree type, tree exp, int in_p,
tree low, tree high)
{
- tree etype = TREE_TYPE (exp), value;
+ tree etype = TREE_TYPE (exp), mask, value;
/* Disable this optimization for function pointer expressions
on targets that require function pointer canonicalization. */
return fold_build2_loc (loc, EQ_EXPR, type, exp,
fold_convert_loc (loc, etype, low));
+ if (TREE_CODE (exp) == BIT_AND_EXPR
+ && maskable_range_p (low, high, etype, &mask, &value))
+ return fold_build2_loc (loc, EQ_EXPR, type,
+ fold_build2_loc (loc, BIT_AND_EXPR, etype,
+ exp, mask),
+ value);
+
if (integer_zerop (low))
{
if (! TYPE_UNSIGNED (etype))
case EQ_EXPR:
case UNEQ_EXPR:
tem = fold_convert_loc (loc, arg1_type, arg1);
- return pedantic_non_lvalue_loc (loc,
- fold_convert_loc (loc, type,
- negate_expr (tem)));
+ return fold_convert_loc (loc, type, negate_expr (tem));
case NE_EXPR:
case LTGT_EXPR:
- return pedantic_non_lvalue_loc (loc, fold_convert_loc (loc, type, arg1));
+ return fold_convert_loc (loc, type, arg1);
case UNGE_EXPR:
case UNGT_EXPR:
if (flag_trapping_math)
if (TYPE_UNSIGNED (TREE_TYPE (arg1)))
break;
tem = fold_build1_loc (loc, ABS_EXPR, TREE_TYPE (arg1), arg1);
- return pedantic_non_lvalue_loc (loc, fold_convert_loc (loc, type, tem));
+ return fold_convert_loc (loc, type, tem);
case UNLE_EXPR:
case UNLT_EXPR:
if (flag_trapping_math)
break;
+ /* FALLTHRU */
case LE_EXPR:
case LT_EXPR:
if (TYPE_UNSIGNED (TREE_TYPE (arg1)))
&& integer_zerop (arg01) && integer_zerop (arg2))
{
if (comp_code == NE_EXPR)
- return pedantic_non_lvalue_loc (loc, fold_convert_loc (loc, type, arg1));
+ return fold_convert_loc (loc, type, arg1);
else if (comp_code == EQ_EXPR)
return build_zero_cst (type);
}
tree comp_op1 = arg01;
tree comp_type = TREE_TYPE (comp_op0);
- /* Avoid adding NOP_EXPRs in case this is an lvalue. */
- if (TYPE_MAIN_VARIANT (comp_type) == TYPE_MAIN_VARIANT (type))
- {
- comp_type = type;
- comp_op0 = arg1;
- comp_op1 = arg2;
- }
-
switch (comp_code)
{
case EQ_EXPR:
- return pedantic_non_lvalue_loc (loc, fold_convert_loc (loc, type, arg2));
+ return fold_convert_loc (loc, type, arg2);
case NE_EXPR:
- return pedantic_non_lvalue_loc (loc, fold_convert_loc (loc, type, arg1));
+ return fold_convert_loc (loc, type, arg1);
case LE_EXPR:
case LT_EXPR:
case UNLE_EXPR:
? fold_build2_loc (loc, MIN_EXPR, comp_type, comp_op0, comp_op1)
: fold_build2_loc (loc, MIN_EXPR, comp_type,
comp_op1, comp_op0);
- return pedantic_non_lvalue_loc (loc,
- fold_convert_loc (loc, type, tem));
+ return fold_convert_loc (loc, type, tem);
}
break;
case GE_EXPR:
? fold_build2_loc (loc, MAX_EXPR, comp_type, comp_op0, comp_op1)
: fold_build2_loc (loc, MAX_EXPR, comp_type,
comp_op1, comp_op0);
- return pedantic_non_lvalue_loc (loc,
- fold_convert_loc (loc, type, tem));
+ return fold_convert_loc (loc, type, tem);
}
break;
case UNEQ_EXPR:
if (!HONOR_NANS (arg1))
- return pedantic_non_lvalue_loc (loc,
- fold_convert_loc (loc, type, arg2));
+ return fold_convert_loc (loc, type, arg2);
break;
case LTGT_EXPR:
if (!HONOR_NANS (arg1))
- return pedantic_non_lvalue_loc (loc,
- fold_convert_loc (loc, type, arg1));
+ return fold_convert_loc (loc, type, arg1);
break;
default:
gcc_assert (TREE_CODE_CLASS (comp_code) == tcc_comparison);
}
}
- /* If this is A op C1 ? A : C2 with C1 and C2 constant integers,
- we might still be able to simplify this. For example,
- if C1 is one less or one more than C2, this might have started
- out as a MIN or MAX and been transformed by this function.
- Only good for INTEGER_TYPEs, because we need TYPE_MAX_VALUE. */
-
- if (INTEGRAL_TYPE_P (type)
- && TREE_CODE (arg01) == INTEGER_CST
- && TREE_CODE (arg2) == INTEGER_CST)
- switch (comp_code)
- {
- case EQ_EXPR:
- if (TREE_CODE (arg1) == INTEGER_CST)
- break;
- /* We can replace A with C1 in this case. */
- arg1 = fold_convert_loc (loc, type, arg01);
- return fold_build3_loc (loc, COND_EXPR, type, arg0, arg1, arg2);
-
- case LT_EXPR:
- /* If C1 is C2 + 1, this is min(A, C2), but use ARG00's type for
- MIN_EXPR, to preserve the signedness of the comparison. */
- if (! operand_equal_p (arg2, TYPE_MAX_VALUE (type),
- OEP_ONLY_CONST)
- && operand_equal_p (arg01,
- const_binop (PLUS_EXPR, arg2,
- build_int_cst (type, 1)),
- OEP_ONLY_CONST))
- {
- tem = fold_build2_loc (loc, MIN_EXPR, TREE_TYPE (arg00), arg00,
- fold_convert_loc (loc, TREE_TYPE (arg00),
- arg2));
- return pedantic_non_lvalue_loc (loc,
- fold_convert_loc (loc, type, tem));
- }
- break;
-
- case LE_EXPR:
- /* If C1 is C2 - 1, this is min(A, C2), with the same care
- as above. */
- if (! operand_equal_p (arg2, TYPE_MIN_VALUE (type),
- OEP_ONLY_CONST)
- && operand_equal_p (arg01,
- const_binop (MINUS_EXPR, arg2,
- build_int_cst (type, 1)),
- OEP_ONLY_CONST))
- {
- tem = fold_build2_loc (loc, MIN_EXPR, TREE_TYPE (arg00), arg00,
- fold_convert_loc (loc, TREE_TYPE (arg00),
- arg2));
- return pedantic_non_lvalue_loc (loc,
- fold_convert_loc (loc, type, tem));
- }
- break;
-
- case GT_EXPR:
- /* If C1 is C2 - 1, this is max(A, C2), but use ARG00's type for
- MAX_EXPR, to preserve the signedness of the comparison. */
- if (! operand_equal_p (arg2, TYPE_MIN_VALUE (type),
- OEP_ONLY_CONST)
- && operand_equal_p (arg01,
- const_binop (MINUS_EXPR, arg2,
- build_int_cst (type, 1)),
- OEP_ONLY_CONST))
- {
- tem = fold_build2_loc (loc, MAX_EXPR, TREE_TYPE (arg00), arg00,
- fold_convert_loc (loc, TREE_TYPE (arg00),
- arg2));
- return pedantic_non_lvalue_loc (loc, fold_convert_loc (loc, type, tem));
- }
- break;
-
- case GE_EXPR:
- /* If C1 is C2 + 1, this is max(A, C2), with the same care as above. */
- if (! operand_equal_p (arg2, TYPE_MAX_VALUE (type),
- OEP_ONLY_CONST)
- && operand_equal_p (arg01,
- const_binop (PLUS_EXPR, arg2,
- build_int_cst (type, 1)),
- OEP_ONLY_CONST))
- {
- tem = fold_build2_loc (loc, MAX_EXPR, TREE_TYPE (arg00), arg00,
- fold_convert_loc (loc, TREE_TYPE (arg00),
- arg2));
- return pedantic_non_lvalue_loc (loc, fold_convert_loc (loc, type, tem));
- }
- break;
- case NE_EXPR:
- break;
- default:
- gcc_unreachable ();
- }
-
return NULL_TREE;
}
t1 = extract_muldiv (op0, c, code, wide_type, &sub_strict_overflow_p);
t2 = extract_muldiv (op1, c, code, wide_type, &sub_strict_overflow_p);
if (t1 != 0 && t2 != 0
+ && TYPE_OVERFLOW_WRAPS (ctype)
&& (code == MULT_EXPR
/* If not multiplication, we can only do this if both operands
are divisible by c. */
if (TYPE_UNSIGNED (ctype) && ctype != type)
break;
- /* If we were able to eliminate our operation from the first side,
- apply our operation to the second side and reform the PLUS. */
- if (t1 != 0 && (TREE_CODE (t1) != code || code == MULT_EXPR))
- return fold_build2 (tcode, ctype, fold_convert (ctype, t1), op1);
-
/* The last case is if we are a multiply. In that case, we can
apply the distributive law to commute the multiply and addition
if the multiplication of the constants doesn't overflow
new operation. Likewise for the RHS from a MULT_EXPR. Otherwise,
do something only if the second operand is a constant. */
if (same_p
+ && TYPE_OVERFLOW_WRAPS (ctype)
&& (t1 = extract_muldiv (op0, c, code, wide_type,
strict_overflow_p)) != 0)
return fold_build2 (tcode, ctype, fold_convert (ctype, t1),
fold_convert (ctype, op1));
else if (tcode == MULT_EXPR && code == MULT_EXPR
+ && TYPE_OVERFLOW_WRAPS (ctype)
&& (t1 = extract_muldiv (op1, c, code, wide_type,
strict_overflow_p)) != 0)
return fold_build2 (tcode, ctype, fold_convert (ctype, op0),
/* If we are going to be able to omit the AND below, we must do our
operations as unsigned. If we must use the AND, we have a choice.
Normally unsigned is faster, but for some machines signed is. */
- ops_unsigned = (LOAD_EXTEND_OP (operand_mode) == SIGN_EXTEND
+ ops_unsigned = (load_extend_op (operand_mode) == SIGN_EXTEND
&& !flag_syntax_only) ? 0 : 1;
signed_type = lang_hooks.types.type_for_mode (operand_mode, 0);
return NULL_TREE;
}
-/* Check whether we are allowed to reorder operands arg0 and arg1,
- such that the evaluation of arg1 occurs before arg0. */
-
-static bool
-reorder_operands_p (const_tree arg0, const_tree arg1)
-{
- if (! flag_evaluation_order)
- return true;
- if (TREE_CONSTANT (arg0) || TREE_CONSTANT (arg1))
- return true;
- return ! TREE_SIDE_EFFECTS (arg0)
- && ! TREE_SIDE_EFFECTS (arg1);
-}
-
/* Test whether it is preferable two swap two operands, ARG0 and
ARG1, for example because ARG0 is an integer constant and ARG1
- isn't. If REORDER is true, only recommend swapping if we can
- evaluate the operands in reverse order. */
+ isn't. */
bool
-tree_swap_operands_p (const_tree arg0, const_tree arg1, bool reorder)
+tree_swap_operands_p (const_tree arg0, const_tree arg1)
{
if (CONSTANT_CLASS_P (arg1))
return 0;
if (TREE_CONSTANT (arg0))
return 1;
- if (reorder && flag_evaluation_order
- && (TREE_SIDE_EFFECTS (arg0) || TREE_SIDE_EFFECTS (arg1)))
- return 0;
-
/* 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
}
same = NULL_TREE;
- if (operand_equal_p (arg01, arg11, 0))
- same = arg01, alt0 = arg00, alt1 = arg10;
- else if (operand_equal_p (arg00, arg10, 0))
+ /* Prefer factoring a common non-constant. */
+ if (operand_equal_p (arg00, arg10, 0))
same = arg00, alt0 = arg01, alt1 = arg11;
+ else if (operand_equal_p (arg01, arg11, 0))
+ same = arg01, alt0 = arg00, alt1 = arg10;
else if (operand_equal_p (arg00, arg11, 0))
same = arg00, alt0 = arg01, alt1 = arg10;
else if (operand_equal_p (arg01, arg10, 0))
}
}
- if (same)
+ if (!same)
+ return NULL_TREE;
+
+ if (! INTEGRAL_TYPE_P (type)
+ || TYPE_OVERFLOW_WRAPS (type)
+ /* We are neither factoring zero nor minus one. */
+ || TREE_CODE (same) == INTEGER_CST)
return fold_build2_loc (loc, MULT_EXPR, type,
fold_build2_loc (loc, code, type,
fold_convert_loc (loc, type, alt0),
fold_convert_loc (loc, type, alt1)),
fold_convert_loc (loc, type, same));
- return NULL_TREE;
+ /* Same may be zero and thus the operation 'code' may overflow. Likewise
+ same may be minus one and thus the multiplication may overflow. Perform
+ the operations in an unsigned type. */
+ tree utype = unsigned_type_for (type);
+ tree tem = fold_build2_loc (loc, code, utype,
+ fold_convert_loc (loc, utype, alt0),
+ fold_convert_loc (loc, utype, alt1));
+ /* If the sum evaluated to a constant that is not -INF the multiplication
+ cannot overflow. */
+ if (TREE_CODE (tem) == INTEGER_CST
+ && ! wi::eq_p (tem, wi::min_value (TYPE_PRECISION (utype), SIGNED)))
+ return fold_build2_loc (loc, MULT_EXPR, type,
+ fold_convert (type, tem), same);
+
+ return fold_convert_loc (loc, type,
+ fold_build2_loc (loc, MULT_EXPR, utype, tem,
+ fold_convert_loc (loc, utype, same)));
}
/* Subroutine of native_encode_expr. Encode the INTEGER_CST
offset += byte % UNITS_PER_WORD;
}
else
- offset = BYTES_BIG_ENDIAN ? 3 - byte : byte;
+ {
+ offset = byte;
+ if (BYTES_BIG_ENDIAN)
+ {
+ /* Reverse bytes within each long, or within the entire float
+ if it's smaller than a long (for HFmode). */
+ offset = MIN (3, total_bytes - 1) - offset;
+ gcc_assert (offset >= 0);
+ }
+ }
offset = offset + ((bitpos / BITS_PER_UNIT) & ~3);
if (offset >= off
&& offset - off < len)
}
}
+/* Return true iff a constant of type TYPE is accepted by
+ native_encode_expr. */
+
+bool
+can_native_encode_type_p (tree type)
+{
+ switch (TREE_CODE (type))
+ {
+ case INTEGER_TYPE:
+ case REAL_TYPE:
+ case FIXED_POINT_TYPE:
+ case COMPLEX_TYPE:
+ case VECTOR_TYPE:
+ case POINTER_TYPE:
+ return true;
+ default:
+ return false;
+ }
+}
+
/* Fold a VIEW_CONVERT_EXPR of a constant expression EXPR to type
TYPE at compile-time. If we're unable to perform the conversion
return NULL_TREE. */
change = (cst == 0);
if (change
&& !flag_syntax_only
- && (LOAD_EXTEND_OP (TYPE_MODE (TREE_TYPE (and0)))
+ && (load_extend_op (TYPE_MODE (TREE_TYPE (and0)))
== ZERO_EXTEND))
{
tree uns = unsigned_type_for (TREE_TYPE (and0));
if (TREE_CODE (op0) == ADDR_EXPR)
{
tree op00 = TREE_OPERAND (op0, 0);
- if ((TREE_CODE (op00) == VAR_DECL
+ if ((VAR_P (op00)
|| TREE_CODE (op00) == PARM_DECL
|| TREE_CODE (op00) == RESULT_DECL)
&& !TREE_READONLY (op00))
return fold_build2_loc (loc, icode, type, TREE_OPERAND (arg0, 0),
tem);
}
- /* Same as abouve but for (A AND[-IF] (B AND-IF C)) -> ((A AND B) AND-IF C),
+ /* Same as above but for (A AND[-IF] (B AND-IF C)) -> ((A AND B) AND-IF C),
or (A OR[-IF] (B OR-IF C) -> ((A OR B) OR-IF C). */
else if (TREE_CODE (arg1) == icode
&& simple_operand_p_2 (arg0)
/* Return a positive integer when the symbol DECL is known to have
a nonzero address, zero when it's known not to (e.g., it's a weak
symbol), and a negative integer when the symbol is not yet in the
- symbol table and so whether or not its address is zero is unknown. */
+ symbol table and so whether or not its address is zero is unknown.
+ For function local objects always return positive integer. */
static int
maybe_nonzero_address (tree decl)
{
if (struct symtab_node *symbol = symtab_node::get_create (decl))
return symbol->nonzero_address ();
+ /* Function local objects are never NULL. */
+ if (DECL_P (decl)
+ && (DECL_CONTEXT (decl)
+ && TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL
+ && auto_var_in_fn_p (decl, DECL_CONTEXT (decl))))
+ return 1;
+
return -1;
}
below follow the C++ rules with the additional property that
every object pointer compares greater than a null pointer.
*/
- else if (DECL_P (base0)
- && maybe_nonzero_address (base0) > 0
- /* Avoid folding references to struct members at offset 0 to
- prevent tests like '&ptr->firstmember == 0' from getting
- eliminated. When ptr is null, although the -> expression
- is strictly speaking invalid, GCC retains it as a matter
- of QoI. See PR c/44555. */
- && (offset0 == NULL_TREE && bitpos0 != 0)
+ else if (((DECL_P (base0)
+ && maybe_nonzero_address (base0) > 0
+ /* Avoid folding references to struct members at offset 0 to
+ prevent tests like '&ptr->firstmember == 0' from getting
+ eliminated. When ptr is null, although the -> expression
+ is strictly speaking invalid, GCC retains it as a matter
+ of QoI. See PR c/44555. */
+ && (offset0 == NULL_TREE && bitpos0 != 0))
+ || CONSTANT_CLASS_P (base0))
+ && indirect_base0
/* The caller guarantees that when one of the arguments is
constant (i.e., null in this case) it is second. */
&& integer_zerop (arg1))
if (save_p)
{
tem = save_expr (build2 (code, type, cval1, cval2));
- SET_EXPR_LOCATION (tem, loc);
+ protected_set_expr_location (tem, loc);
return tem;
}
return fold_build2_loc (loc, code, type, cval1, cval2);
/* We can fold X/C1 op C2 where C1 and C2 are integer constants
into a single range test. */
- if ((TREE_CODE (arg0) == TRUNC_DIV_EXPR
- || TREE_CODE (arg0) == EXACT_DIV_EXPR)
+ if (TREE_CODE (arg0) == TRUNC_DIV_EXPR
&& TREE_CODE (arg1) == INTEGER_CST
&& TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
&& !integer_zerop (TREE_OPERAND (arg0, 1))
tree op0 = fold_convert_loc (loc, type, TREE_OPERAND (aref0, 1));
tree op1 = fold_convert_loc (loc, type, TREE_OPERAND (aref1, 1));
tree esz = fold_convert_loc (loc, type, array_ref_element_size (aref0));
- tree diff = build2 (MINUS_EXPR, type, op0, op1);
+ tree diff = fold_build2_loc (loc, MINUS_EXPR, type, op0, op1);
return fold_build2_loc (loc, PLUS_EXPR, type,
base_offset,
fold_build2_loc (loc, MULT_EXPR, type,
/* Return true when T is an address and is known to be nonzero.
Handle warnings about undefined signed overflow. */
-static bool
+bool
tree_expr_nonzero_p (tree t)
{
bool ret, strict_overflow_p;
/* If this is a commutative operation, and ARG0 is a constant, move it
to ARG1 to reduce the number of tests below. */
if (commutative_tree_code (code)
- && tree_swap_operands_p (arg0, arg1, true))
+ && tree_swap_operands_p (arg0, arg1))
return fold_build2_loc (loc, code, type, op1, op0);
/* Likewise if this is a comparison, and ARG0 is a constant, move it
to ARG1 to reduce the number of tests below. */
if (kind == tcc_comparison
- && tree_swap_operands_p (arg0, arg1, true))
+ && tree_swap_operands_p (arg0, arg1))
return fold_build2_loc (loc, swap_tree_comparison (code), type, op1, op0);
tem = generic_simplify (loc, code, type, op0, op1);
return build2_loc (loc, COMPOUND_EXPR, type, TREE_OPERAND (arg0, 0),
tem);
}
- if (TREE_CODE (arg1) == COMPOUND_EXPR
- && reorder_operands_p (arg0, TREE_OPERAND (arg1, 0)))
+ if (TREE_CODE (arg1) == COMPOUND_EXPR)
{
tem = fold_build2_loc (loc, code, type, op0,
fold_convert_loc (loc, TREE_TYPE (op1),
case MINUS_EXPR:
/* (-A) - B -> (-B) - A where B is easily negated and we can swap. */
if (TREE_CODE (arg0) == NEGATE_EXPR
- && negate_expr_p (op1)
- && reorder_operands_p (arg0, arg1))
+ && negate_expr_p (op1))
return fold_build2_loc (loc, MINUS_EXPR, type,
negate_expr (op1),
fold_convert_loc (loc, type,
if (TREE_CODE (op1) == INTEGER_CST
&& tree_int_cst_sgn (op1) == -1
&& negate_expr_p (op0)
+ && negate_expr_p (op1)
&& (tem = negate_expr (op1)) != op1
&& ! TREE_OVERFLOW (tem))
return fold_build2_loc (loc, MULT_EXPR, type,
/* If (C1|C2) == ~0 then (X&C1)|C2 becomes X|C2. */
if (msk.and_not (c1 | c2) == 0)
- return fold_build2_loc (loc, BIT_IOR_EXPR, type,
- TREE_OPERAND (arg0, 0), arg1);
+ {
+ tem = fold_convert_loc (loc, type, TREE_OPERAND (arg0, 0));
+ return fold_build2_loc (loc, BIT_IOR_EXPR, type, tem, arg1);
+ }
/* 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
}
if (c3 != c1)
- return fold_build2_loc (loc, BIT_IOR_EXPR, type,
- fold_build2_loc (loc, BIT_AND_EXPR, type,
- TREE_OPERAND (arg0, 0),
- wide_int_to_tree (type,
- c3)),
- arg1);
+ {
+ tem = fold_convert_loc (loc, type, TREE_OPERAND (arg0, 0));
+ tem = fold_build2_loc (loc, BIT_AND_EXPR, type, tem,
+ wide_int_to_tree (type, c3));
+ return fold_build2_loc (loc, BIT_IOR_EXPR, type, tem, arg1);
+ }
}
/* See if this can be simplified into a rotate first. If that
mode which allows further optimizations. */
int pop = wi::popcount (warg1);
if (!(pop >= BITS_PER_UNIT
- && exact_log2 (pop) != -1
+ && pow2p_hwi (pop)
&& wi::mask (pop, false, warg1.get_precision ()) == warg1))
return fold_build2_loc (loc, code, type, op0,
wide_int_to_tree (type, masked));
/* Convert -A / -B to A / B when the type is signed and overflow is
undefined. */
if ((!INTEGRAL_TYPE_P (type) || TYPE_OVERFLOW_UNDEFINED (type))
- && TREE_CODE (arg0) == NEGATE_EXPR
+ && TREE_CODE (op0) == NEGATE_EXPR
&& negate_expr_p (op1))
{
if (INTEGRAL_TYPE_P (type))
/* If first arg is constant zero, return it. */
if (integer_zerop (arg0))
return fold_convert_loc (loc, type, arg0);
+ /* FALLTHRU */
case TRUTH_AND_EXPR:
/* If either arg is constant true, drop it. */
if (TREE_CODE (arg0) == INTEGER_CST && ! integer_zerop (arg0))
/* If first arg is constant true, return it. */
if (TREE_CODE (arg0) == INTEGER_CST && ! integer_zerop (arg0))
return fold_convert_loc (loc, type, arg0);
+ /* FALLTHRU */
case TRUTH_OR_EXPR:
/* If either arg is constant zero, drop it. */
if (TREE_CODE (arg0) == INTEGER_CST && integer_zerop (arg0))
TREE_OPERAND (arg1, 0), arg0);
}
- /* Transform comparisons of the form C - X CMP X if C % 2 == 1. */
- if (TREE_CODE (arg0) == MINUS_EXPR
- && TREE_CODE (TREE_OPERAND (arg0, 0)) == INTEGER_CST
- && operand_equal_p (tree_strip_nop_conversions (TREE_OPERAND (arg0,
- 1)),
- arg1, 0)
- && wi::extract_uhwi (TREE_OPERAND (arg0, 0), 0, 1) == 1)
- return omit_two_operands_loc (loc, type,
- code == NE_EXPR
- ? boolean_true_node : boolean_false_node,
- TREE_OPERAND (arg0, 1), arg1);
-
- /* Transform comparisons of the form X CMP C - X if C % 2 == 1. */
- if (TREE_CODE (arg1) == MINUS_EXPR
- && TREE_CODE (TREE_OPERAND (arg1, 0)) == INTEGER_CST
- && operand_equal_p (tree_strip_nop_conversions (TREE_OPERAND (arg1,
- 1)),
- arg0, 0)
- && wi::extract_uhwi (TREE_OPERAND (arg1, 0), 0, 1) == 1)
- return omit_two_operands_loc (loc, type,
- code == NE_EXPR
- ? boolean_true_node : boolean_false_node,
- TREE_OPERAND (arg1, 1), arg0);
-
/* If this is an EQ or NE comparison with zero and ARG0 is
(1 << foo) & bar, convert it to (bar >> foo) & 1. Both require
two operations, but the latter can be done in one less insn
}
}
- /* If we have (A & C) == D where D & ~C != 0, convert this into 0.
- Similarly for NE_EXPR. */
- if (TREE_CODE (arg0) == BIT_AND_EXPR
- && TREE_CODE (arg1) == INTEGER_CST
- && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
- {
- tree notc = fold_build1_loc (loc, BIT_NOT_EXPR,
- TREE_TYPE (TREE_OPERAND (arg0, 1)),
- TREE_OPERAND (arg0, 1));
- tree dandnotc
- = fold_build2_loc (loc, BIT_AND_EXPR, TREE_TYPE (arg0),
- fold_convert_loc (loc, TREE_TYPE (arg0), arg1),
- notc);
- tree rslt = code == EQ_EXPR ? integer_zero_node : integer_one_node;
- if (integer_nonzerop (dandnotc))
- return omit_one_operand_loc (loc, type, rslt, arg0);
- }
-
/* If this is a comparison of a field, we may be able to simplify it. */
if ((TREE_CODE (arg0) == COMPONENT_REF
|| TREE_CODE (arg0) == BIT_FIELD_REF)
tree itype = TREE_TYPE (arg0);
if (operand_equal_p (arg01, arg11, 0))
- return fold_build2_loc (loc, code, type,
- fold_build2_loc (loc, BIT_AND_EXPR, itype,
- fold_build2_loc (loc,
- BIT_XOR_EXPR, itype,
- arg00, arg10),
- arg01),
- build_zero_cst (itype));
-
+ {
+ tem = fold_convert_loc (loc, itype, arg10);
+ tem = fold_build2_loc (loc, BIT_XOR_EXPR, itype, arg00, tem);
+ tem = fold_build2_loc (loc, BIT_AND_EXPR, itype, tem, arg01);
+ return fold_build2_loc (loc, code, type, tem,
+ build_zero_cst (itype));
+ }
if (operand_equal_p (arg01, arg10, 0))
- return fold_build2_loc (loc, code, type,
- fold_build2_loc (loc, BIT_AND_EXPR, itype,
- fold_build2_loc (loc,
- BIT_XOR_EXPR, itype,
- arg00, arg11),
- arg01),
- build_zero_cst (itype));
-
+ {
+ tem = fold_convert_loc (loc, itype, arg11);
+ tem = fold_build2_loc (loc, BIT_XOR_EXPR, itype, arg00, tem);
+ tem = fold_build2_loc (loc, BIT_AND_EXPR, itype, tem, arg01);
+ return fold_build2_loc (loc, code, type, tem,
+ build_zero_cst (itype));
+ }
if (operand_equal_p (arg00, arg11, 0))
- return fold_build2_loc (loc, code, type,
- fold_build2_loc (loc, BIT_AND_EXPR, itype,
- fold_build2_loc (loc,
- BIT_XOR_EXPR, itype,
- arg01, arg10),
- arg00),
- build_zero_cst (itype));
-
+ {
+ tem = fold_convert_loc (loc, itype, arg10);
+ tem = fold_build2_loc (loc, BIT_XOR_EXPR, itype, arg01, tem);
+ tem = fold_build2_loc (loc, BIT_AND_EXPR, itype, tem, arg00);
+ return fold_build2_loc (loc, code, type, tem,
+ build_zero_cst (itype));
+ }
if (operand_equal_p (arg00, arg10, 0))
- return fold_build2_loc (loc, code, type,
- fold_build2_loc (loc, BIT_AND_EXPR, itype,
- fold_build2_loc (loc,
- BIT_XOR_EXPR, itype,
- arg01, arg11),
- arg00),
- build_zero_cst (itype));
+ {
+ tem = fold_convert_loc (loc, itype, arg11);
+ tem = fold_build2_loc (loc, BIT_XOR_EXPR, itype, arg01, tem);
+ tem = fold_build2_loc (loc, BIT_AND_EXPR, itype, tem, arg00);
+ return fold_build2_loc (loc, code, type, tem,
+ build_zero_cst (itype));
+ }
}
if (TREE_CODE (arg0) == BIT_XOR_EXPR
case GOTO_EXPR:
*walk_subtrees = 0;
- /* ... fall through ... */
+ /* fall through */
default:
return NULL_TREE;
/* If this is a commutative operation, and OP0 is a constant, move it
to OP1 to reduce the number of tests below. */
if (commutative_ternary_tree_code (code)
- && tree_swap_operands_p (op0, op1, true))
+ && tree_swap_operands_p (op0, op1))
return fold_build3_loc (loc, code, type, op1, op0, op2);
tem = generic_simplify (loc, code, type, op0, op1, op2);
/* If the second operand is simpler than the third, swap them
since that produces better jump optimization results. */
if (truth_value_p (TREE_CODE (arg0))
- && tree_swap_operands_p (op1, op2, false))
+ && tree_swap_operands_p (op1, op2))
{
location_t loc0 = expr_location_or (arg0, loc);
/* See if this can be inverted. If it can't, possibly because
STRIP_NOPS (tem);
if (TREE_CODE (tem) == RSHIFT_EXPR
&& tree_fits_uhwi_p (TREE_OPERAND (tem, 1))
- && (unsigned HOST_WIDE_INT) tree_log2 (arg1) ==
- tree_to_uhwi (TREE_OPERAND (tem, 1)))
+ && (unsigned HOST_WIDE_INT) tree_log2 (arg1)
+ == tree_to_uhwi (TREE_OPERAND (tem, 1)))
return fold_build2_loc (loc, BIT_AND_EXPR, type,
- TREE_OPERAND (tem, 0), arg1);
+ fold_convert_loc (loc, type,
+ TREE_OPERAND (tem, 0)),
+ op1);
}
/* A & N ? N : 0 is simply A & N if N is a power of two. This
&& (code == VEC_COND_EXPR || !VECTOR_TYPE_P (type)))
return fold_build2_loc (loc, code == VEC_COND_EXPR ? BIT_AND_EXPR
: TRUTH_ANDIF_EXPR,
- type, fold_convert_loc (loc, type, arg0), arg1);
+ type, fold_convert_loc (loc, type, arg0), op1);
/* Convert A ? B : 1 into !A || B if A and B are truth values. */
if (code == VEC_COND_EXPR ? integer_all_onesp (op2) : integer_onep (op2)
? BIT_IOR_EXPR
: TRUTH_ORIF_EXPR,
type, fold_convert_loc (loc, type, tem),
- arg1);
+ op1);
}
/* Convert A ? 0 : B into !A && B if A and B are truth values. */
int
multiple_of_p (tree type, const_tree top, const_tree bottom)
{
+ gimple *stmt;
+ tree t1, op1, op2;
+
if (operand_equal_p (top, bottom, 0))
return 1;
/* FALLTHRU */
case MULT_EXPR:
- return (multiple_of_p (type, TREE_OPERAND (top, 0), bottom)
- || multiple_of_p (type, TREE_OPERAND (top, 1), bottom));
+ return (multiple_of_p (type, TREE_OPERAND (top, 1), bottom)
+ || multiple_of_p (type, TREE_OPERAND (top, 0), bottom));
- case PLUS_EXPR:
case MINUS_EXPR:
- return (multiple_of_p (type, TREE_OPERAND (top, 0), bottom)
- && multiple_of_p (type, TREE_OPERAND (top, 1), bottom));
+ /* It is impossible to prove if op0 - op1 is multiple of bottom
+ precisely, so be conservative here checking if both op0 and op1
+ are multiple of bottom. Note we check the second operand first
+ since it's usually simpler. */
+ return (multiple_of_p (type, TREE_OPERAND (top, 1), bottom)
+ && multiple_of_p (type, TREE_OPERAND (top, 0), bottom));
+
+ case PLUS_EXPR:
+ /* The same as MINUS_EXPR, but handle cases like op0 + 0xfffffffd
+ as op0 - 3 if the expression has unsigned type. For example,
+ (X / 3) + 0xfffffffd is multiple of 3, but 0xfffffffd is not. */
+ op1 = TREE_OPERAND (top, 1);
+ if (TYPE_UNSIGNED (type)
+ && TREE_CODE (op1) == INTEGER_CST && tree_int_cst_sign_bit (op1))
+ op1 = fold_build1 (NEGATE_EXPR, type, op1);
+ return (multiple_of_p (type, op1, bottom)
+ && multiple_of_p (type, TREE_OPERAND (top, 0), bottom));
case LSHIFT_EXPR:
if (TREE_CODE (TREE_OPERAND (top, 1)) == INTEGER_CST)
{
- tree op1, t1;
-
op1 = TREE_OPERAND (top, 1);
/* const_binop may not detect overflow correctly,
so check for it explicitly here. */
< TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (top, 0)))))
return 0;
- /* .. fall through ... */
+ /* fall through */
case SAVE_EXPR:
return multiple_of_p (type, TREE_OPERAND (top, 0), bottom);
return wi::multiple_of_p (wi::to_widest (top), wi::to_widest (bottom),
SIGNED);
+ case SSA_NAME:
+ if (TREE_CODE (bottom) == INTEGER_CST
+ && (stmt = SSA_NAME_DEF_STMT (top)) != NULL
+ && gimple_code (stmt) == GIMPLE_ASSIGN)
+ {
+ enum tree_code code = gimple_assign_rhs_code (stmt);
+
+ /* Check for special cases to see if top is defined as multiple
+ of bottom:
+
+ top = (X & ~(bottom - 1) ; bottom is power of 2
+
+ or
+
+ Y = X % bottom
+ top = X - Y. */
+ if (code == BIT_AND_EXPR
+ && (op2 = gimple_assign_rhs2 (stmt)) != NULL_TREE
+ && TREE_CODE (op2) == INTEGER_CST
+ && integer_pow2p (bottom)
+ && wi::multiple_of_p (wi::to_widest (op2),
+ wi::to_widest (bottom), UNSIGNED))
+ return 1;
+
+ op1 = gimple_assign_rhs1 (stmt);
+ if (code == MINUS_EXPR
+ && (op2 = gimple_assign_rhs2 (stmt)) != NULL_TREE
+ && TREE_CODE (op2) == SSA_NAME
+ && (stmt = SSA_NAME_DEF_STMT (op2)) != NULL
+ && gimple_code (stmt) == GIMPLE_ASSIGN
+ && (code = gimple_assign_rhs_code (stmt)) == TRUNC_MOD_EXPR
+ && operand_equal_p (op1, gimple_assign_rhs1 (stmt), 0)
+ && operand_equal_p (bottom, gimple_assign_rhs2 (stmt), 0))
+ return 1;
+ }
+
+ /* fall through */
+
default:
return 0;
}
if (nonzero_addr >= 0)
return nonzero_addr;
- /* Function local objects are never NULL. */
- if (DECL_P (base)
- && (DECL_CONTEXT (base)
- && TREE_CODE (DECL_CONTEXT (base)) == FUNCTION_DECL
- && auto_var_in_fn_p (base, DECL_CONTEXT (base))))
- return true;
-
/* Constants are never weak. */
if (CONSTANT_CLASS_P (base))
return true;
}
break;
+ case SSA_NAME:
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (t)))
+ break;
+ return expr_not_equal_to (t, wi::zero (TYPE_PRECISION (TREE_TYPE (t))));
+
default:
break;
}
if (!VECTOR_TYPE_P (type))
{
/* Have vector comparison with scalar boolean result. */
- bool result = true;
gcc_assert ((code == EQ_EXPR || code == NE_EXPR)
&& VECTOR_CST_NELTS (op0) == VECTOR_CST_NELTS (op1));
for (unsigned i = 0; i < VECTOR_CST_NELTS (op0); i++)
tree elem0 = VECTOR_CST_ELT (op0, i);
tree elem1 = VECTOR_CST_ELT (op1, i);
tree tmp = fold_relational_const (code, type, elem0, elem1);
- result &= integer_onep (tmp);
+ if (tmp == NULL_TREE)
+ return NULL_TREE;
+ if (integer_zerop (tmp))
+ return constant_boolean_node (false, type);
}
- if (code == NE_EXPR)
- result = !result;
- return constant_boolean_node (result, type);
+ return constant_boolean_node (true, type);
}
unsigned count = VECTOR_CST_NELTS (op0);
tree *elts = XALLOCAVEC (tree, count);
return expr;
}
- return build1 (CLEANUP_POINT_EXPR, type, expr);
+ return build1_loc (EXPR_LOCATION (expr), CLEANUP_POINT_EXPR, type, expr);
}
/* Given a pointer value OP0 and a type TYPE, return a simplified version
STRIP_NOPS (sub);
subtype = TREE_TYPE (sub);
- if (!POINTER_TYPE_P (subtype))
+ if (!POINTER_TYPE_P (subtype)
+ || TYPE_REF_CAN_ALIAS_ALL (TREE_TYPE (op0)))
return NULL_TREE;
if (TREE_CODE (sub) == ADDR_EXPR)
}
/* If divisor is a power of two, simplify this to bit manipulation. */
- if (divisor == (divisor & -divisor))
+ if (pow2_or_zerop (divisor))
{
if (TREE_CODE (value) == INTEGER_CST)
{
overflow_p = TREE_OVERFLOW (value);
val += divisor - 1;
- val &= - (int) divisor;
+ val &= (int) -divisor;
if (val == 0)
overflow_p = true;
}
/* If divisor is a power of two, simplify this to bit manipulation. */
- if (divisor == (divisor & -divisor))
+ if (pow2_or_zerop (divisor))
{
tree t;
&volatilep);
core = build_fold_addr_expr_loc (loc, core);
}
+ else if (TREE_CODE (exp) == POINTER_PLUS_EXPR)
+ {
+ core = TREE_OPERAND (exp, 0);
+ STRIP_NOPS (core);
+ *pbitpos = 0;
+ *poffset = TREE_OPERAND (exp, 1);
+ if (TREE_CODE (*poffset) == INTEGER_CST)
+ {
+ offset_int tem = wi::sext (wi::to_offset (*poffset),
+ TYPE_PRECISION (TREE_TYPE (*poffset)));
+ tem <<= LOG2_BITS_PER_UNIT;
+ if (wi::fits_shwi_p (tem))
+ {
+ *pbitpos = tem.to_shwi ();
+ *poffset = NULL_TREE;
+ }
+ }
+ }
else
{
core = exp;
}
/* Return a char pointer for a C string if it is a string constant
- or sum of string constant and integer constant. */
+ or sum of string constant and integer constant. We only support
+ string constants properly terminated with '\0' character.
+ If STRLEN is a valid pointer, length (including terminating character)
+ of returned string is stored to the argument. */
const char *
-c_getstr (tree src)
+c_getstr (tree src, unsigned HOST_WIDE_INT *strlen)
{
tree offset_node;
+ if (strlen)
+ *strlen = 0;
+
src = string_constant (src, &offset_node);
if (src == 0)
- return 0;
+ return NULL;
- if (offset_node == 0)
- return TREE_STRING_POINTER (src);
- else if (!tree_fits_uhwi_p (offset_node)
- || compare_tree_int (offset_node, TREE_STRING_LENGTH (src) - 1) > 0)
- return 0;
+ unsigned HOST_WIDE_INT offset = 0;
+ if (offset_node != NULL_TREE)
+ {
+ if (!tree_fits_uhwi_p (offset_node))
+ return NULL;
+ else
+ offset = tree_to_uhwi (offset_node);
+ }
- return TREE_STRING_POINTER (src) + tree_to_uhwi (offset_node);
+ unsigned HOST_WIDE_INT string_length = TREE_STRING_LENGTH (src);
+ const char *string = TREE_STRING_POINTER (src);
+
+ /* Support only properly null-terminated strings. */
+ if (string_length == 0
+ || string[string_length - 1] != '\0'
+ || offset >= string_length)
+ return NULL;
+
+ if (strlen)
+ *strlen = string_length - offset;
+ return string + offset;
}
#if CHECKING_P
x);
}
+/* Verify that various binary operations on vectors are folded
+ correctly. */
+
+static void
+test_vector_folding ()
+{
+ tree inner_type = integer_type_node;
+ tree type = build_vector_type (inner_type, 4);
+ tree zero = build_zero_cst (type);
+ tree one = build_one_cst (type);
+
+ /* Verify equality tests that return a scalar boolean result. */
+ tree res_type = boolean_type_node;
+ ASSERT_FALSE (integer_nonzerop (fold_build2 (EQ_EXPR, res_type, zero, one)));
+ ASSERT_TRUE (integer_nonzerop (fold_build2 (EQ_EXPR, res_type, zero, zero)));
+ ASSERT_TRUE (integer_nonzerop (fold_build2 (NE_EXPR, res_type, zero, one)));
+ ASSERT_FALSE (integer_nonzerop (fold_build2 (NE_EXPR, res_type, one, one)));
+}
+
/* Run all of the selftests within this file. */
void
fold_const_c_tests ()
{
test_arithmetic_folding ();
+ test_vector_folding ();
}
} // namespace selftest