diff options
Diffstat (limited to 'gcc/fold-const.c')
-rw-r--r-- | gcc/fold-const.c | 251 |
1 files changed, 144 insertions, 107 deletions
diff --git a/gcc/fold-const.c b/gcc/fold-const.c index d702de2f97f..5a118ca50a1 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -79,6 +79,8 @@ along with GCC; see the file COPYING3. If not see #include "tree-vrp.h" #include "tree-ssanames.h" #include "selftest.h" +#include "stringpool.h" +#include "attribs.h" /* Nonzero if we are folding constants inside an initializer; zero otherwise. */ @@ -108,8 +110,6 @@ enum comparison_code { static bool negate_expr_p (tree); static tree negate_expr (tree); -static tree split_tree (location_t, tree, tree, enum tree_code, - tree *, tree *, tree *, int); static tree associate_trees (location_t, tree, tree, enum tree_code, tree); static enum comparison_code comparison_to_compcode (enum tree_code); static enum tree_code compcode_to_comparison (enum comparison_code); @@ -775,12 +775,14 @@ negate_expr (tree t) same type as IN, but they will have the same signedness and mode. */ static tree -split_tree (location_t loc, tree in, tree type, enum tree_code code, - tree *conp, tree *litp, tree *minus_litp, int negate_p) +split_tree (tree in, tree type, enum tree_code code, + tree *minus_varp, tree *conp, tree *minus_conp, + tree *litp, tree *minus_litp, int negate_p) { tree var = 0; - + *minus_varp = 0; *conp = 0; + *minus_conp = 0; *litp = 0; *minus_litp = 0; @@ -834,27 +836,19 @@ split_tree (location_t loc, tree in, tree type, enum tree_code code, if (neg_litp_p) *minus_litp = *litp, *litp = 0; if (neg_conp_p && *conp) - { - /* Convert to TYPE before negating. */ - *conp = fold_convert_loc (loc, type, *conp); - *conp = negate_expr (*conp); - } + *minus_conp = *conp, *conp = 0; if (neg_var_p && var) - { - /* Convert to TYPE before negating. */ - var = fold_convert_loc (loc, type, var); - var = negate_expr (var); - } + *minus_varp = var, var = 0; } 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. Do _not_ do this - when IN is constant. Convert to TYPE before negating. */ - *minus_litp = build_one_cst (type); - var = negate_expr (fold_convert_loc (loc, type, TREE_OPERAND (in, 0))); + /* -1 - X is folded to ~X, undo that here. Do _not_ do this + when IN is constant. */ + *litp = build_minus_one_cst (type); + *minus_varp = TREE_OPERAND (in, 0); } else var = in; @@ -866,17 +860,13 @@ split_tree (location_t loc, tree in, tree type, enum tree_code code, else if (*minus_litp) *litp = *minus_litp, *minus_litp = 0; if (*conp) - { - /* Convert to TYPE before negating. */ - *conp = fold_convert_loc (loc, type, *conp); - *conp = negate_expr (*conp); - } + *minus_conp = *conp, *conp = 0; + else if (*minus_conp) + *conp = *minus_conp, *minus_conp = 0; if (var) - { - /* Convert to TYPE before negating. */ - var = fold_convert_loc (loc, type, var); - var = negate_expr (var); - } + *minus_varp = var, var = 0; + else if (*minus_varp) + var = *minus_varp, *minus_varp = 0; } if (*litp @@ -898,7 +888,10 @@ static tree associate_trees (location_t loc, tree t1, tree t2, enum tree_code code, tree type) { if (t1 == 0) - return t2; + { + gcc_assert (t2 == 0 || code != MINUS_EXPR); + return t2; + } else if (t2 == 0) return t1; @@ -906,6 +899,7 @@ associate_trees (location_t loc, tree t1, tree t2, enum tree_code code, tree typ try to fold this since we will have infinite recursion. But do deal with any NEGATE_EXPRs. */ if (TREE_CODE (t1) == code || TREE_CODE (t2) == code + || TREE_CODE (t1) == PLUS_EXPR || TREE_CODE (t2) == PLUS_EXPR || TREE_CODE (t1) == MINUS_EXPR || TREE_CODE (t2) == MINUS_EXPR) { if (code == PLUS_EXPR) @@ -3184,9 +3178,18 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags) flags &= ~OEP_ADDRESS_OF; return OP_SAME (0); + case BIT_INSERT_EXPR: + /* BIT_INSERT_EXPR has an implict operand as the type precision + of op1. Need to check to make sure they are the same. */ + if (TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST + && TREE_CODE (TREE_OPERAND (arg1, 1)) == INTEGER_CST + && TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg0, 1))) + != TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg1, 1)))) + return false; + /* FALLTHRU */ + case VEC_COND_EXPR: case DOT_PROD_EXPR: - case BIT_INSERT_EXPR: return OP_SAME (0) && OP_SAME (1) && OP_SAME (2); case MODIFY_EXPR: @@ -3927,7 +3930,7 @@ make_bit_field_ref (location_t loc, tree inner, tree orig_inner, tree type, bftype = build_nonstandard_integer_type (bitsize, 0); result = build3_loc (loc, BIT_FIELD_REF, bftype, inner, - size_int (bitsize), bitsize_int (bitpos)); + bitsize_int (bitsize), bitsize_int (bitpos)); REF_REVERSE_STORAGE_ORDER (result) = reversep; if (bftype != type) @@ -4850,21 +4853,21 @@ build_range_check (location_t loc, tree type, tree exp, int in_p, if (low == 0) return fold_build2_loc (loc, LE_EXPR, type, exp, - fold_convert_loc (loc, etype, high)); + fold_convert_loc (loc, etype, high)); if (high == 0) return fold_build2_loc (loc, GE_EXPR, type, exp, - fold_convert_loc (loc, etype, low)); + fold_convert_loc (loc, etype, low)); if (operand_equal_p (low, high, 0)) return fold_build2_loc (loc, EQ_EXPR, type, exp, - fold_convert_loc (loc, etype, low)); + 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), + exp, mask), value); if (integer_zerop (low)) @@ -4896,7 +4899,7 @@ build_range_check (location_t loc, tree type, tree exp, int in_p, exp = fold_convert_loc (loc, etype, exp); } return fold_build2_loc (loc, GT_EXPR, type, exp, - build_int_cst (etype, 0)); + build_int_cst (etype, 0)); } } @@ -4906,25 +4909,15 @@ build_range_check (location_t loc, tree type, tree exp, int in_p, if (etype == NULL_TREE) return NULL_TREE; + if (POINTER_TYPE_P (etype)) + etype = unsigned_type_for (etype); + high = fold_convert_loc (loc, etype, high); low = fold_convert_loc (loc, etype, low); exp = fold_convert_loc (loc, etype, exp); value = const_binop (MINUS_EXPR, high, low); - - if (POINTER_TYPE_P (etype)) - { - if (value != 0 && !TREE_OVERFLOW (value)) - { - low = fold_build1_loc (loc, NEGATE_EXPR, TREE_TYPE (low), low); - return build_range_check (loc, type, - fold_build_pointer_plus_loc (loc, exp, low), - 1, build_int_cst (etype, 0), value); - } - return 0; - } - if (value != 0 && !TREE_OVERFLOW (value)) return build_range_check (loc, type, fold_build2_loc (loc, MINUS_EXPR, etype, exp, low), @@ -8459,14 +8452,9 @@ fold_comparison (location_t loc, enum tree_code code, tree type, { /* We can fold this expression to a constant if the non-constant offset parts are equal. */ - if ((offset0 == offset1 - || (offset0 && offset1 - && operand_equal_p (offset0, offset1, 0))) - && (equality_code - || (indirect_base0 - && (DECL_P (base0) || CONSTANT_CLASS_P (base0))) - || POINTER_TYPE_OVERFLOW_UNDEFINED)) - + if (offset0 == offset1 + || (offset0 && offset1 + && operand_equal_p (offset0, offset1, 0))) { if (!equality_code && bitpos0 != bitpos1 @@ -8501,11 +8489,7 @@ fold_comparison (location_t loc, enum tree_code code, tree type, 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. */ - else if (bitpos0 == bitpos1 - && (equality_code - || (indirect_base0 - && (DECL_P (base0) || CONSTANT_CLASS_P (base0))) - || POINTER_TYPE_OVERFLOW_UNDEFINED)) + else if (bitpos0 == bitpos1) { /* By converting to signed sizetype we cover middle-end pointer arithmetic which operates on unsigned pointer types of size @@ -9570,8 +9554,8 @@ fold_binary_loc (location_t loc, if ((! FLOAT_TYPE_P (type) || flag_associative_math) && !TYPE_SATURATING (type)) { - tree var0, con0, lit0, minus_lit0; - tree var1, con1, lit1, minus_lit1; + tree var0, minus_var0, con0, minus_con0, lit0, minus_lit0; + tree var1, minus_var1, con1, minus_con1, lit1, minus_lit1; tree atype = type; bool ok = true; @@ -9580,10 +9564,12 @@ fold_binary_loc (location_t loc, then the result with variables. This increases the chances of literals being recombined later and of generating relocatable expressions for the sum of a constant and literal. */ - var0 = split_tree (loc, arg0, type, code, - &con0, &lit0, &minus_lit0, 0); - var1 = split_tree (loc, arg1, type, code, - &con1, &lit1, &minus_lit1, code == MINUS_EXPR); + var0 = split_tree (arg0, type, code, + &minus_var0, &con0, &minus_con0, + &lit0, &minus_lit0, 0); + var1 = split_tree (arg1, type, code, + &minus_var1, &con1, &minus_con1, + &lit1, &minus_lit1, code == MINUS_EXPR); /* Recombine MINUS_EXPR operands by using PLUS_EXPR. */ if (code == MINUS_EXPR) @@ -9591,7 +9577,7 @@ fold_binary_loc (location_t loc, /* With undefined overflow prefer doing association in a type which wraps on overflow, if that is one of the operand types. */ - if ((POINTER_TYPE_P (type) && POINTER_TYPE_OVERFLOW_UNDEFINED) + if (POINTER_TYPE_P (type) || (INTEGRAL_TYPE_P (type) && !TYPE_OVERFLOW_WRAPS (type))) { if (INTEGRAL_TYPE_P (TREE_TYPE (arg0)) @@ -9605,13 +9591,16 @@ fold_binary_loc (location_t loc, /* With undefined overflow we can only associate constants with one variable, and constants whose association doesn't overflow. */ - if ((POINTER_TYPE_P (atype) && POINTER_TYPE_OVERFLOW_UNDEFINED) + if (POINTER_TYPE_P (atype) || (INTEGRAL_TYPE_P (atype) && !TYPE_OVERFLOW_WRAPS (atype))) { - if (var0 && var1) + if ((var0 && var1) || (minus_var0 && minus_var1)) { - tree tmp0 = var0; - tree tmp1 = var1; + /* ??? If split_tree would handle NEGATE_EXPR we could + simply reject these cases and the allowed cases would + be the var0/minus_var1 ones. */ + tree tmp0 = var0 ? var0 : minus_var0; + tree tmp1 = var1 ? var1 : minus_var1; bool one_neg = false; if (TREE_CODE (tmp0) == NEGATE_EXPR) @@ -9640,22 +9629,46 @@ fold_binary_loc (location_t loc, || !operand_equal_p (tmp0, tmp1, 0)) ok = false; } + else if ((var0 && minus_var1 + && ! operand_equal_p (var0, minus_var1, 0)) + || (minus_var0 && var1 + && ! operand_equal_p (minus_var0, var1, 0))) + ok = false; } /* Only do something if we found more than two objects. Otherwise, nothing has changed and we risk infinite recursion. */ if (ok && (2 < ((var0 != 0) + (var1 != 0) + + (minus_var0 != 0) + (minus_var1 != 0) + (con0 != 0) + (con1 != 0) + + (minus_con0 != 0) + (minus_con1 != 0) + (lit0 != 0) + (lit1 != 0) + (minus_lit0 != 0) + (minus_lit1 != 0)))) { var0 = associate_trees (loc, var0, var1, code, atype); + minus_var0 = associate_trees (loc, minus_var0, minus_var1, + code, atype); con0 = associate_trees (loc, con0, con1, code, atype); + minus_con0 = associate_trees (loc, minus_con0, minus_con1, + code, atype); lit0 = associate_trees (loc, lit0, lit1, code, atype); minus_lit0 = associate_trees (loc, minus_lit0, minus_lit1, code, atype); + if (minus_var0 && var0) + { + var0 = associate_trees (loc, var0, minus_var0, + MINUS_EXPR, atype); + minus_var0 = 0; + } + if (minus_con0 && con0) + { + con0 = associate_trees (loc, con0, minus_con0, + MINUS_EXPR, atype); + minus_con0 = 0; + } + /* Preserve the MINUS_EXPR if the negative part of the literal is greater than the positive part. Otherwise, the multiplicative folding code (i.e extract_muldiv) may be fooled in case @@ -9665,7 +9678,9 @@ fold_binary_loc (location_t loc, { if (TREE_CODE (lit0) == INTEGER_CST && TREE_CODE (minus_lit0) == INTEGER_CST - && tree_int_cst_lt (lit0, minus_lit0)) + && tree_int_cst_lt (lit0, minus_lit0) + /* But avoid ending up with only negated parts. */ + && (var0 || con0)) { minus_lit0 = associate_trees (loc, minus_lit0, lit0, MINUS_EXPR, atype); @@ -9684,25 +9699,38 @@ fold_binary_loc (location_t loc, || (minus_lit0 && TREE_OVERFLOW_P (minus_lit0))) return NULL_TREE; - if (minus_lit0) + /* Eliminate lit0 and minus_lit0 to con0 and minus_con0. */ + con0 = associate_trees (loc, con0, lit0, code, atype); + lit0 = 0; + minus_con0 = associate_trees (loc, minus_con0, minus_lit0, + code, atype); + minus_lit0 = 0; + + /* Eliminate minus_con0. */ + if (minus_con0) { - if (con0 == 0) - return - fold_convert_loc (loc, type, - associate_trees (loc, var0, minus_lit0, - MINUS_EXPR, atype)); + if (con0) + con0 = associate_trees (loc, con0, minus_con0, + MINUS_EXPR, atype); + else if (var0) + var0 = associate_trees (loc, var0, minus_con0, + MINUS_EXPR, atype); else - { - con0 = associate_trees (loc, con0, minus_lit0, - MINUS_EXPR, atype); - return - fold_convert_loc (loc, type, - associate_trees (loc, var0, con0, - PLUS_EXPR, atype)); - } + gcc_unreachable (); + minus_con0 = 0; + } + + /* Eliminate minus_var0. */ + if (minus_var0) + { + if (con0) + con0 = associate_trees (loc, con0, minus_var0, + MINUS_EXPR, atype); + else + gcc_unreachable (); + minus_var0 = 0; } - con0 = associate_trees (loc, con0, lit0, code, atype); return fold_convert_loc (loc, type, associate_trees (loc, var0, con0, code, atype)); @@ -12196,8 +12224,8 @@ debug_fold_checksum (const_tree t) expression with code CODE of type TYPE with an operand OP0. */ tree -fold_build1_stat_loc (location_t loc, - enum tree_code code, tree type, tree op0 MEM_STAT_DECL) +fold_build1_loc (location_t loc, + enum tree_code code, tree type, tree op0 MEM_STAT_DECL) { tree tem; #ifdef ENABLE_FOLD_CHECKING @@ -12213,7 +12241,7 @@ fold_build1_stat_loc (location_t loc, tem = fold_unary_loc (loc, code, type, op0); if (!tem) - tem = build1_stat_loc (loc, code, type, op0 PASS_MEM_STAT); + tem = build1_loc (loc, code, type, op0 PASS_MEM_STAT); #ifdef ENABLE_FOLD_CHECKING md5_init_ctx (&ctx); @@ -12233,7 +12261,7 @@ fold_build1_stat_loc (location_t loc, OP0 and OP1. */ tree -fold_build2_stat_loc (location_t loc, +fold_build2_loc (location_t loc, enum tree_code code, tree type, tree op0, tree op1 MEM_STAT_DECL) { @@ -12259,7 +12287,7 @@ fold_build2_stat_loc (location_t loc, tem = fold_binary_loc (loc, code, type, op0, op1); if (!tem) - tem = build2_stat_loc (loc, code, type, op0, op1 PASS_MEM_STAT); + tem = build2_loc (loc, code, type, op0, op1 PASS_MEM_STAT); #ifdef ENABLE_FOLD_CHECKING md5_init_ctx (&ctx); @@ -12286,7 +12314,7 @@ fold_build2_stat_loc (location_t loc, type TYPE with operands OP0, OP1, and OP2. */ tree -fold_build3_stat_loc (location_t loc, enum tree_code code, tree type, +fold_build3_loc (location_t loc, enum tree_code code, tree type, tree op0, tree op1, tree op2 MEM_STAT_DECL) { tree tem; @@ -12319,7 +12347,7 @@ fold_build3_stat_loc (location_t loc, enum tree_code code, tree type, gcc_assert (TREE_CODE_CLASS (code) != tcc_vl_exp); tem = fold_ternary_loc (loc, code, type, op0, op1, op2); if (!tem) - tem = build3_stat_loc (loc, code, type, op0, op1, op2 PASS_MEM_STAT); + tem = build3_loc (loc, code, type, op0, op1, op2 PASS_MEM_STAT); #ifdef ENABLE_FOLD_CHECKING md5_init_ctx (&ctx); @@ -13693,8 +13721,8 @@ fold_negate_const (tree arg0, tree type) bool overflow; wide_int val = wi::neg (arg0, &overflow); t = force_fit_type (type, val, 1, - (overflow | TREE_OVERFLOW (arg0)) - && !TYPE_UNSIGNED (type)); + (overflow && ! TYPE_UNSIGNED (type)) + || TREE_OVERFLOW (arg0)); break; } @@ -14081,14 +14109,23 @@ fold_indirect_ref_1 (location_t loc, tree type, tree op0) && type == TREE_TYPE (op00type)) { tree type_domain = TYPE_DOMAIN (op00type); - tree min_val = size_zero_node; - if (type_domain && TYPE_MIN_VALUE (type_domain)) - min_val = TYPE_MIN_VALUE (type_domain); - op01 = size_binop_loc (loc, EXACT_DIV_EXPR, op01, - TYPE_SIZE_UNIT (type)); - op01 = size_binop_loc (loc, PLUS_EXPR, op01, min_val); - return build4_loc (loc, ARRAY_REF, type, op00, op01, - NULL_TREE, NULL_TREE); + tree min; + if (type_domain != NULL_TREE + && (min = TYPE_MIN_VALUE (type_domain)) + && TREE_CODE (min) == INTEGER_CST) + { + offset_int off = wi::to_offset (op01); + offset_int el_sz = wi::to_offset (TYPE_SIZE_UNIT (type)); + offset_int remainder; + off = wi::divmod_trunc (off, el_sz, SIGNED, &remainder); + if (remainder == 0) + { + off = off + wi::to_offset (min); + op01 = wide_int_to_tree (sizetype, off); + return build4_loc (loc, ARRAY_REF, type, op00, op01, + NULL_TREE, NULL_TREE); + } + } } } } |