diff options
Diffstat (limited to 'gcc/fold-const.c')
-rw-r--r-- | gcc/fold-const.c | 270 |
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 |