aboutsummaryrefslogtreecommitdiff
path: root/gcc/fold-const.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/fold-const.c')
-rw-r--r--gcc/fold-const.c270
1 files changed, 104 insertions, 166 deletions
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index a7556f438e5..308d60e6bbe 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -102,6 +102,7 @@ static tree unextend PARAMS ((tree, int, int, tree));
static tree fold_truthop PARAMS ((enum tree_code, tree, tree, tree));
static tree optimize_minmax_comparison PARAMS ((tree));
static tree extract_muldiv PARAMS ((tree, tree, enum tree_code, tree));
+static tree extract_muldiv_1 PARAMS ((tree, tree, enum tree_code, tree));
static tree strip_compound_expr PARAMS ((tree, tree));
static int multiple_of_p PARAMS ((tree, tree, tree));
static tree constant_boolean_node PARAMS ((int, tree));
@@ -4044,6 +4045,31 @@ extract_muldiv (t, c, code, wide_type)
enum tree_code code;
tree wide_type;
{
+ /* To avoid exponential search depth, refuse to allow recursion past
+ three levels. Beyond that (1) it's highly unlikely that we'll find
+ something interesting and (2) we've probably processed it before
+ when we built the inner expression. */
+
+ static int depth;
+ tree ret;
+
+ if (depth > 3)
+ return NULL;
+
+ depth++;
+ ret = extract_muldiv_1 (t, c, code, wide_type);
+ depth--;
+
+ return ret;
+}
+
+static tree
+extract_muldiv_1 (t, c, code, wide_type)
+ tree t;
+ tree c;
+ enum tree_code code;
+ tree wide_type;
+{
tree type = TREE_TYPE (t);
enum tree_code tcode = TREE_CODE (t);
tree ctype = (wide_type != 0 && (GET_MODE_SIZE (TYPE_MODE (wide_type))
@@ -4088,10 +4114,15 @@ extract_muldiv (t, c, code, wide_type)
&& TYPE_IS_SIZETYPE (TREE_TYPE (op0)))
&& (GET_MODE_SIZE (TYPE_MODE (ctype))
> GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op0)))))
- /* ... or its type is larger than ctype,
- then we cannot pass through this truncation. */
- || (GET_MODE_SIZE (TYPE_MODE (ctype))
- < GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op0))))))
+ /* ... or this is a truncation (t is narrower than op0),
+ then we cannot pass through this narrowing. */
+ || (GET_MODE_SIZE (TYPE_MODE (type))
+ < GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op0))))
+ /* ... or signedness changes for division or modulus,
+ then we cannot pass through this conversion. */
+ || (code != MULT_EXPR
+ && (TREE_UNSIGNED (ctype)
+ != TREE_UNSIGNED (TREE_TYPE (op0))))))
break;
/* Pass the constant down and see if we can make a simplification. If
@@ -4131,25 +4162,6 @@ extract_muldiv (t, c, code, wide_type)
TREE_OPERAND (t, 1));
break;
- case SAVE_EXPR:
- /* If this has not been evaluated and the operand has no side effects,
- we can see if we can do something inside it and make a new one.
- Note that this test is overly conservative since we can do this
- if the only reason it had side effects is that it was another
- similar SAVE_EXPR, but that isn't worth bothering with. */
- if (SAVE_EXPR_RTL (t) == 0 && ! TREE_SIDE_EFFECTS (TREE_OPERAND (t, 0))
- && 0 != (t1 = extract_muldiv (TREE_OPERAND (t, 0), c, code,
- wide_type)))
- {
- t1 = save_expr (t1);
- if (SAVE_EXPR_PERSISTENT_P (t) && TREE_CODE (t1) == SAVE_EXPR)
- SAVE_EXPR_PERSISTENT_P (t1) = 1;
- if (is_pending_size (t))
- put_pending_size (t1);
- return t1;
- }
- break;
-
case LSHIFT_EXPR: case RSHIFT_EXPR:
/* If the second operand is constant, this is a multiplication
or floor division, by a power of two, so we can treat it that
@@ -6001,150 +6013,68 @@ fold (expr)
return fold (build (code, type, TREE_OPERAND (arg0, 0), tem));
}
- /* Convert foo++ == CONST into ++foo == CONST + INCR.
- First, see if one arg is constant; find the constant arg
- and the other one. */
- {
- tree constop = 0, varop = NULL_TREE;
- int constopnum = -1;
- if (TREE_CONSTANT (arg1))
- constopnum = 1, constop = arg1, varop = arg0;
- if (TREE_CONSTANT (arg0))
- constopnum = 0, constop = arg0, varop = arg1;
+ /* Convert foo++ == CONST into ++foo == CONST + INCR. */
+ if (TREE_CONSTANT (arg1)
+ && (TREE_CODE (arg0) == POSTINCREMENT_EXPR
+ || TREE_CODE (arg0) == POSTDECREMENT_EXPR)
+ /* This optimization is invalid for ordered comparisons
+ if CONST+INCR overflows or if foo+incr might overflow.
+ This optimization is invalid for floating point due to rounding.
+ For pointer types we assume overflow doesn't happen. */
+ && (POINTER_TYPE_P (TREE_TYPE (arg0))
+ || (INTEGRAL_TYPE_P (TREE_TYPE (arg0))
+ && (code == EQ_EXPR || code == NE_EXPR))))
+ {
+ tree varop, newconst;
- if (constop && TREE_CODE (varop) == POSTINCREMENT_EXPR)
- {
- /* This optimization is invalid for ordered comparisons
- if CONST+INCR overflows or if foo+incr might overflow.
- This optimization is invalid for floating point due to rounding.
- For pointer types we assume overflow doesn't happen. */
- if (POINTER_TYPE_P (TREE_TYPE (varop))
- || (! FLOAT_TYPE_P (TREE_TYPE (varop))
- && (code == EQ_EXPR || code == NE_EXPR)))
- {
- tree newconst
- = fold (build (PLUS_EXPR, TREE_TYPE (varop),
- constop, TREE_OPERAND (varop, 1)));
-
- /* Do not overwrite the current varop to be a preincrement,
- create a new node so that we won't confuse our caller who
- might create trees and throw them away, reusing the
- arguments that they passed to build. This shows up in
- the THEN or ELSE parts of ?: being postincrements. */
- varop = build (PREINCREMENT_EXPR, TREE_TYPE (varop),
- TREE_OPERAND (varop, 0),
- TREE_OPERAND (varop, 1));
-
- /* If VAROP is a reference to a bitfield, we must mask
- the constant by the width of the field. */
- if (TREE_CODE (TREE_OPERAND (varop, 0)) == COMPONENT_REF
- && DECL_BIT_FIELD(TREE_OPERAND
- (TREE_OPERAND (varop, 0), 1)))
- {
- int size
- = TREE_INT_CST_LOW (DECL_SIZE
- (TREE_OPERAND
- (TREE_OPERAND (varop, 0), 1)));
- tree mask, unsigned_type;
- unsigned int precision;
- tree folded_compare;
-
- /* First check whether the comparison would come out
- always the same. If we don't do that we would
- change the meaning with the masking. */
- if (constopnum == 0)
- folded_compare = fold (build (code, type, constop,
- TREE_OPERAND (varop, 0)));
- else
- folded_compare = fold (build (code, type,
- TREE_OPERAND (varop, 0),
- constop));
- if (integer_zerop (folded_compare)
- || integer_onep (folded_compare))
- return omit_one_operand (type, folded_compare, varop);
-
- unsigned_type = (*lang_hooks.types.type_for_size)(size, 1);
- precision = TYPE_PRECISION (unsigned_type);
- mask = build_int_2 (~0, ~0);
- TREE_TYPE (mask) = unsigned_type;
- force_fit_type (mask, 0);
- mask = const_binop (RSHIFT_EXPR, mask,
- size_int (precision - size), 0);
- newconst = fold (build (BIT_AND_EXPR,
- TREE_TYPE (varop), newconst,
- convert (TREE_TYPE (varop),
- mask)));
- }
+ if (TREE_CODE (arg0) == POSTINCREMENT_EXPR)
+ {
+ newconst = fold (build (PLUS_EXPR, TREE_TYPE (arg0),
+ arg1, TREE_OPERAND (arg0, 1)));
+ varop = build (PREINCREMENT_EXPR, TREE_TYPE (arg0),
+ TREE_OPERAND (arg0, 0),
+ TREE_OPERAND (arg0, 1));
+ }
+ else
+ {
+ newconst = fold (build (MINUS_EXPR, TREE_TYPE (arg0),
+ arg1, TREE_OPERAND (arg0, 1)));
+ varop = build (PREDECREMENT_EXPR, TREE_TYPE (arg0),
+ TREE_OPERAND (arg0, 0),
+ TREE_OPERAND (arg0, 1));
+ }
- t = build (code, type,
- (constopnum == 0) ? newconst : varop,
- (constopnum == 1) ? newconst : varop);
- return t;
- }
- }
- else if (constop && TREE_CODE (varop) == POSTDECREMENT_EXPR)
- {
- if (POINTER_TYPE_P (TREE_TYPE (varop))
- || (! FLOAT_TYPE_P (TREE_TYPE (varop))
- && (code == EQ_EXPR || code == NE_EXPR)))
- {
- tree newconst
- = fold (build (MINUS_EXPR, TREE_TYPE (varop),
- constop, TREE_OPERAND (varop, 1)));
-
- /* Do not overwrite the current varop to be a predecrement,
- create a new node so that we won't confuse our caller who
- might create trees and throw them away, reusing the
- arguments that they passed to build. This shows up in
- the THEN or ELSE parts of ?: being postdecrements. */
- varop = build (PREDECREMENT_EXPR, TREE_TYPE (varop),
- TREE_OPERAND (varop, 0),
- TREE_OPERAND (varop, 1));
-
- if (TREE_CODE (TREE_OPERAND (varop, 0)) == COMPONENT_REF
- && DECL_BIT_FIELD(TREE_OPERAND
- (TREE_OPERAND (varop, 0), 1)))
- {
- int size
- = TREE_INT_CST_LOW (DECL_SIZE
- (TREE_OPERAND
- (TREE_OPERAND (varop, 0), 1)));
- tree mask, unsigned_type;
- unsigned int precision;
- tree folded_compare;
-
- if (constopnum == 0)
- folded_compare = fold (build (code, type, constop,
- TREE_OPERAND (varop, 0)));
- else
- folded_compare = fold (build (code, type,
- TREE_OPERAND (varop, 0),
- constop));
- if (integer_zerop (folded_compare)
- || integer_onep (folded_compare))
- return omit_one_operand (type, folded_compare, varop);
-
- unsigned_type = (*lang_hooks.types.type_for_size)(size, 1);
- precision = TYPE_PRECISION (unsigned_type);
- mask = build_int_2 (~0, ~0);
- TREE_TYPE (mask) = TREE_TYPE (varop);
- force_fit_type (mask, 0);
- mask = const_binop (RSHIFT_EXPR, mask,
- size_int (precision - size), 0);
- newconst = fold (build (BIT_AND_EXPR,
- TREE_TYPE (varop), newconst,
- convert (TREE_TYPE (varop),
- mask)));
- }
- t = build (code, type,
- (constopnum == 0) ? newconst : varop,
- (constopnum == 1) ? newconst : varop);
- return t;
- }
- }
- }
+ /* If VAROP is a reference to a bitfield, we must mask
+ the constant by the width of the field. */
+ if (TREE_CODE (TREE_OPERAND (varop, 0)) == COMPONENT_REF
+ && DECL_BIT_FIELD (TREE_OPERAND (TREE_OPERAND (varop, 0), 1)))
+ {
+ tree fielddecl = TREE_OPERAND (TREE_OPERAND (varop, 0), 1);
+ int size = TREE_INT_CST_LOW (DECL_SIZE (fielddecl));
+ tree folded_compare, shift;
+
+ /* First check whether the comparison would come out
+ always the same. If we don't do that we would
+ change the meaning with the masking. */
+ folded_compare = fold (build (code, type,
+ TREE_OPERAND (varop, 0),
+ arg1));
+ if (integer_zerop (folded_compare)
+ || integer_onep (folded_compare))
+ return omit_one_operand (type, folded_compare, varop);
+
+ shift = build_int_2 (TYPE_PRECISION (TREE_TYPE (varop)) - size,
+ 0);
+ newconst = fold (build (LSHIFT_EXPR, TREE_TYPE (varop),
+ newconst, shift));
+ newconst = fold (build (RSHIFT_EXPR, TREE_TYPE (varop),
+ newconst, shift));
+ }
+
+ return fold (build (code, type, varop, newconst));
+ }
/* Change X >= C to X > (C - 1) and X < C to X <= (C - 1) if C > 0.
This transformation affects the cases which are handled in later
@@ -6773,9 +6703,17 @@ fold (expr)
/* Pedantic ANSI C says that a conditional expression is never an lvalue,
so all simple results must be passed through pedantic_non_lvalue. */
if (TREE_CODE (arg0) == INTEGER_CST)
- return pedantic_non_lvalue
- (TREE_OPERAND (t, (integer_zerop (arg0) ? 2 : 1)));
- else if (operand_equal_p (arg1, TREE_OPERAND (expr, 2), 0))
+ {
+ tem = TREE_OPERAND (t, (integer_zerop (arg0) ? 2 : 1));
+ /* Only optimize constant conditions when the selected branch
+ has the same type as the COND_EXPR. This avoids optimizing
+ away "c ? x : throw", where the throw has a void type. */
+ if (! VOID_TYPE_P (TREE_TYPE (tem))
+ || VOID_TYPE_P (TREE_TYPE (t)))
+ return pedantic_non_lvalue (tem);
+ return t;
+ }
+ if (operand_equal_p (arg1, TREE_OPERAND (expr, 2), 0))
return pedantic_omit_one_operand (type, arg1, arg0);
/* If the second operand is zero, invert the comparison and swap