From: Aldy Hernandez Date: Sun, 18 Aug 2019 17:21:23 +0000 (+0000) Subject: Merge branch 'trunk-at-merge' into ranger-merge X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2e6949761d8508d665e42778690aeeb7281b5f18;p=thirdparty%2Fgcc.git Merge branch 'trunk-at-merge' into ranger-merge From-SVN: r274621 --- 2e6949761d8508d665e42778690aeeb7281b5f18 diff --cc gcc/gimple-ssa-warn-alloca.c index 469b0990bce9,af39ff415e1b..58df6b1d0a0a --- a/gcc/gimple-ssa-warn-alloca.c +++ b/gcc/gimple-ssa-warn-alloca.c @@@ -177,12 -294,48 +178,12 @@@ alloca_call_type_by_arg (unsigned HOST_ // Analyze the alloca call in STMT and return the alloca type with its // corresponding limit (if applicable). IS_VLA is set if the alloca // call was created by the gimplifier for a VLA. -// -// If the alloca call may be too large because of a cast from a signed -// type to an unsigned type, set *INVALID_CASTED_TYPE to the -// problematic signed type. - static struct alloca_type_and_limit + static class alloca_type_and_limit -alloca_call_type (gimple *stmt, bool is_vla, tree *invalid_casted_type) +alloca_call_type (global_ranger &ranger, gimple *stmt, bool is_vla) { gcc_assert (gimple_alloca_call_p (stmt)); - bool tentative_cast_from_signed = false; tree len = gimple_call_arg (stmt, 0); - tree len_casted = NULL; - wide_int min, max; - edge_iterator ei; - edge e; gcc_assert (!is_vla || warn_vla_limit >= 0); gcc_assert (is_vla || warn_alloca_limit >= 0); @@@ -294,8 -535,9 +295,8 @@@ pass_walloca::execute (function *fun else if (warn_alloca_limit < 0) continue; - struct alloca_type_and_limit t - tree invalid_casted_type = NULL; + class alloca_type_and_limit t - = alloca_call_type (stmt, is_vla, &invalid_casted_type); + = alloca_call_type (ranger, stmt, is_vla); unsigned HOST_WIDE_INT adjusted_alloca_limit = adjusted_warn_limit (false); diff --cc gcc/passes.def index 8f12acf67189,1a7fd144f87d..39410ba05f62 --- a/gcc/passes.def +++ b/gcc/passes.def @@@ -83,8 -83,7 +83,8 @@@ along with GCC; see the file COPYING3 /* pass_build_ealias is a dummy pass that ensures that we execute TODO_rebuild_alias at this point. */ NEXT_PASS (pass_build_ealias); - NEXT_PASS (pass_fre); + NEXT_PASS (pass_fre, true /* may_iterate */); + NEXT_PASS (pass_ranger_vrp); NEXT_PASS (pass_early_vrp); NEXT_PASS (pass_merge_phi); NEXT_PASS (pass_dse); diff --cc gcc/tree-ssa-sccvn.c index fc8d6bc07ea7,eb7e4be09e69..f06f57269cbd --- a/gcc/tree-ssa-sccvn.c +++ b/gcc/tree-ssa-sccvn.c @@@ -69,8 -70,8 +70,9 @@@ along with GCC; see the file COPYING3 #include "tree-ssa-loop.h" #include "tree-scalar-evolution.h" #include "tree-ssa-loop-niter.h" + #include "builtins.h" #include "tree-ssa-sccvn.h" +#include "tree-ssa-propagate.h" /* This algorithm is based on the SCC algorithm presented by Keith Cooper and L. Taylor Simpson in "SCC-Based Value numbering" @@@ -1904,8 -2136,8 +2136,8 @@@ class rpo_elim : public eliminate_dom_w { public: rpo_elim(basic_block entry_) - : eliminate_dom_walker (CDI_DOMINATORS, NULL, NULL), entry (entry_) {} - ~rpo_elim(); - : eliminate_dom_walker (CDI_DOMINATORS, NULL), entry (entry_), ++ : eliminate_dom_walker (CDI_DOMINATORS, NULL, NULL), entry (entry_), + m_avail_freelist (NULL) {} virtual tree eliminate_avail (basic_block, tree op); diff --cc gcc/tree-vrp.c index d56fad9dfc3e,8067f8560cd1..01bffa0e8585 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@@ -1507,196 -1448,112 +1514,49 @@@ combine_bound (enum tree_code code, wid wi = wi::shwi (0, prec); } -/* Given a range in [WMIN, WMAX], adjust it for possible overflow and - put the result in VR. - - TYPE is the type of the range. - - MIN_OVF and MAX_OVF indicate what type of overflow, if any, - occurred while originally calculating WMIN or WMAX. -1 indicates - underflow. +1 indicates overflow. 0 indicates neither. */ +/* Fold two value range's of a POINTER_PLUS_EXPR into VR. Return TRUE + if successful. */ -static void -set_value_range_with_overflow (value_range_kind &kind, tree &min, tree &max, - tree type, - const wide_int &wmin, const wide_int &wmax, - wi::overflow_type min_ovf, - wi::overflow_type max_ovf) +static bool - handle_symbolics_in_pointer_plus_expr (value_range_base *vr, - enum tree_code code, - tree expr_type, - const value_range_base *vr0, - const value_range_base *vr1) ++extract_range_from_pointer_plus_expr (value_range_base *vr, ++ enum tree_code code, ++ tree expr_type, ++ const value_range_base *vr0, ++ const value_range_base *vr1) { - const signop sgn = TYPE_SIGN (type); - const unsigned int prec = TYPE_PRECISION (type); - - /* For one bit precision if max < min, then the swapped - range covers all values. */ - if (prec == 1 && wi::lt_p (wmax, wmin, sgn)) - { - kind = VR_VARYING; - return; - } - - if (TYPE_OVERFLOW_WRAPS (type)) - { - /* If overflow wraps, truncate the values and adjust the - range kind and bounds appropriately. */ - wide_int tmin = wide_int::from (wmin, prec, sgn); - wide_int tmax = wide_int::from (wmax, prec, sgn); - if ((min_ovf != wi::OVF_NONE) == (max_ovf != wi::OVF_NONE)) - { - /* If the limits are swapped, we wrapped around and cover - the entire range. We have a similar check at the end of - extract_range_from_binary_expr. */ - if (wi::gt_p (tmin, tmax, sgn)) - kind = VR_VARYING; - else - { - kind = VR_RANGE; - /* No overflow or both overflow or underflow. The - range kind stays VR_RANGE. */ - min = wide_int_to_tree (type, tmin); - max = wide_int_to_tree (type, tmax); - } - return; - } - else if ((min_ovf == wi::OVF_UNDERFLOW && max_ovf == wi::OVF_NONE) - || (max_ovf == wi::OVF_OVERFLOW && min_ovf == wi::OVF_NONE)) - { - /* Min underflow or max overflow. The range kind - changes to VR_ANTI_RANGE. */ - bool covers = false; - wide_int tem = tmin; - tmin = tmax + 1; - if (wi::cmp (tmin, tmax, sgn) < 0) - covers = true; - tmax = tem - 1; - if (wi::cmp (tmax, tem, sgn) > 0) - covers = true; - /* If the anti-range would cover nothing, drop to varying. - Likewise if the anti-range bounds are outside of the - types values. */ - if (covers || wi::cmp (tmin, tmax, sgn) > 0) - { - kind = VR_VARYING; - return; - } - kind = VR_ANTI_RANGE; - min = wide_int_to_tree (type, tmin); - max = wide_int_to_tree (type, tmax); - return; - } + if (POINTER_TYPE_P (expr_type) && code == POINTER_PLUS_EXPR) + { + /* For pointer types, we are really only interested in asserting + whether the expression evaluates to non-NULL. + With -fno-delete-null-pointer-checks we need to be more + conservative. As some object might reside at address 0, + then some offset could be added to it and the same offset + subtracted again and the result would be NULL. + E.g. + static int a[12]; where &a[0] is NULL and + ptr = &a[6]; + ptr -= 6; + ptr will be NULL here, even when there is POINTER_PLUS_EXPR + where the first range doesn't include zero and the second one + doesn't either. As the second operand is sizetype (unsigned), + consider all ranges where the MSB could be set as possible + subtractions where the result might be NULL. */ + if ((!range_includes_zero_p (vr0) + || !range_includes_zero_p (vr1)) + && !TYPE_OVERFLOW_WRAPS (expr_type) + && (flag_delete_null_pointer_checks + || (range_int_cst_p (vr1) + && !tree_int_cst_sign_bit (vr1->max ())))) + vr->set_nonzero (expr_type); + else if (vr0->zero_p () && vr1->zero_p ()) + vr->set_zero (expr_type); else - { - /* Other underflow and/or overflow, drop to VR_VARYING. */ - kind = VR_VARYING; - return; - } - } - else - { - /* If overflow does not wrap, saturate to the types min/max - value. */ - wide_int type_min = wi::min_value (prec, sgn); - wide_int type_max = wi::max_value (prec, sgn); - kind = VR_RANGE; - if (min_ovf == wi::OVF_UNDERFLOW) - min = wide_int_to_tree (type, type_min); - else if (min_ovf == wi::OVF_OVERFLOW) - min = wide_int_to_tree (type, type_max); - else - min = wide_int_to_tree (type, wmin); - - if (max_ovf == wi::OVF_UNDERFLOW) - max = wide_int_to_tree (type, type_min); - else if (max_ovf == wi::OVF_OVERFLOW) - max = wide_int_to_tree (type, type_max); - else - max = wide_int_to_tree (type, wmax); + vr->set_varying (expr_type); + return true; } + return false; } - /* Extract range information from a PLUS_EXPR or MINUS_EXPR based on - the ranges of each of its operands *VR0 and *VR1 with resulting - type EXPR_TYPE. The resulting range is stored in *VR. */ - - static void - extract_range_from_plus_expr (value_range_base *vr, - enum tree_code code, tree expr_type, - const value_range_base *vr0, - const value_range_base *vr1) - { - gcc_assert (code == PLUS_EXPR || code == MINUS_EXPR); - enum value_range_kind type; - tree min = NULL, max = NULL; - value_range_kind vr0_kind = vr0->kind (), vr1_kind = vr1->kind (); - tree vr0_min = vr0->min (), vr0_max = vr0->max (); - tree vr1_min = vr1->min (), vr1_max = vr1->max (); - /* This will normalize things such that calculating - [0,0] - VR_VARYING is not dropped to varying, but is - calculated as [MIN+1, MAX]. */ - if (vr0->varying_p ()) - { - vr0_kind = VR_RANGE; - vr0_min = vrp_val_min (expr_type); - vr0_max = vrp_val_max (expr_type); - } - if (vr1->varying_p ()) - { - vr1_kind = VR_RANGE; - vr1_min = vrp_val_min (expr_type); - vr1_max = vrp_val_max (expr_type); - } - const bool minus_p = (code == MINUS_EXPR); - tree min_op0 = vr0_min; - tree min_op1 = minus_p ? vr1_max : vr1_min; - tree max_op0 = vr0_max; - tree max_op1 = minus_p ? vr1_min : vr1_max; - tree sym_min_op0 = NULL_TREE; - tree sym_min_op1 = NULL_TREE; - tree sym_max_op0 = NULL_TREE; - tree sym_max_op1 = NULL_TREE; - bool neg_min_op0, neg_min_op1, neg_max_op0, neg_max_op1; - - neg_min_op0 = neg_min_op1 = neg_max_op0 = neg_max_op1 = false; - - /* If we have a PLUS or MINUS with two VR_RANGEs, either constant or - single-symbolic ranges, try to compute the precise resulting range, - but only if we know that this resulting range will also be constant - or single-symbolic. */ - if (vr0_kind == VR_RANGE && vr1_kind == VR_RANGE - && (TREE_CODE (min_op0) == INTEGER_CST - || (sym_min_op0 - = get_single_symbol (min_op0, &neg_min_op0, &min_op0))) - && (TREE_CODE (min_op1) == INTEGER_CST - || (sym_min_op1 - = get_single_symbol (min_op1, &neg_min_op1, &min_op1))) - && (!(sym_min_op0 && sym_min_op1) - || (sym_min_op0 == sym_min_op1 - && neg_min_op0 == (minus_p ? neg_min_op1 : !neg_min_op1))) - && (TREE_CODE (max_op0) == INTEGER_CST - || (sym_max_op0 - = get_single_symbol (max_op0, &neg_max_op0, &max_op0))) - && (TREE_CODE (max_op1) == INTEGER_CST - || (sym_max_op1 - = get_single_symbol (max_op1, &neg_max_op1, &max_op1))) - && (!(sym_max_op0 && sym_max_op1) - || (sym_max_op0 == sym_max_op1 - && neg_max_op0 == (minus_p ? neg_max_op1 : !neg_max_op1)))) - { - wide_int wmin, wmax; - wi::overflow_type min_ovf = wi::OVF_NONE; - wi::overflow_type max_ovf = wi::OVF_NONE; - - /* Build the bounds. */ - combine_bound (code, wmin, min_ovf, expr_type, min_op0, min_op1); - combine_bound (code, wmax, max_ovf, expr_type, max_op0, max_op1); - - /* If we have overflow for the constant part and the resulting - range will be symbolic, drop to VR_VARYING. */ - if (((bool)min_ovf && sym_min_op0 != sym_min_op1) - || ((bool)max_ovf && sym_max_op0 != sym_max_op1)) - { - vr->set_varying (expr_type); - return; - } - - adjust_range_for_overflow (type, wmin, wmax, expr_type, - min_ovf, max_ovf, - TYPE_OVERFLOW_WRAPS (expr_type)); - if (type == VR_VARYING) - { - vr->set_varying (expr_type); - return; - } - gcc_assert (type != VR_UNDEFINED); - min = wide_int_to_tree (expr_type, wmin); - max = wide_int_to_tree (expr_type, wmax); - - /* Build the symbolic bounds if needed. */ - adjust_symbolic_bound (min, code, expr_type, - sym_min_op0, sym_min_op1, - neg_min_op0, neg_min_op1); - adjust_symbolic_bound (max, code, expr_type, - sym_max_op0, sym_max_op1, - neg_max_op0, neg_max_op1); - - /* If either MIN or MAX overflowed, then set the resulting range to - VARYING. */ - if (min == NULL_TREE - || TREE_OVERFLOW_P (min) - || max == NULL_TREE - || TREE_OVERFLOW_P (max)) - { - vr->set_varying (expr_type); - return; - } - - int cmp = compare_values (min, max); - if (cmp == -2 || cmp == 1) - { - /* If the new range has its limits swapped around (MIN > MAX), - then the operation caused one of them to wrap around, mark - the new range VARYING. */ - vr->set_varying (expr_type); - } - else - vr->set (type, min, max); - return; - } - else - { - /* For other cases, for example if we have a PLUS_EXPR with two - VR_ANTI_RANGEs, drop to VR_VARYING. It would take more effort - to compute a precise range for such a case. - ??? General even mixed range kind operations can be expressed - by for example transforming ~[3, 5] + [1, 2] to range-only - operations and a union primitive: - [-INF, 2] + [1, 2] U [5, +INF] + [1, 2] - [-INF+1, 4] U [6, +INF(OVF)] - though usually the union is not exactly representable with - a single range or anti-range as the above is - [-INF+1, +INF(OVF)] intersected with ~[5, 5] - but one could use a scheme similar to equivalences for this. */ - vr->set_varying (expr_type); - } - } - - /* Extract range information from a binary operation CODE based on the ranges of each of its operands *VR0 and *VR1 with resulting type EXPR_TYPE. The resulting range is stored in *VR. */ @@@ -1867,7 -1709,34 +1727,7 @@@ extract_range_from_binary_expr (value_r vr->set_varying (expr_type); } else if (code == POINTER_PLUS_EXPR) - handle_symbolics_in_pointer_plus_expr (vr, code, expr_type, &vr0, &vr1); - { - /* For pointer types, we are really only interested in asserting - whether the expression evaluates to non-NULL. - With -fno-delete-null-pointer-checks we need to be more - conservative. As some object might reside at address 0, - then some offset could be added to it and the same offset - subtracted again and the result would be NULL. - E.g. - static int a[12]; where &a[0] is NULL and - ptr = &a[6]; - ptr -= 6; - ptr will be NULL here, even when there is POINTER_PLUS_EXPR - where the first range doesn't include zero and the second one - doesn't either. As the second operand is sizetype (unsigned), - consider all ranges where the MSB could be set as possible - subtractions where the result might be NULL. */ - if ((!range_includes_zero_p (&vr0) - || !range_includes_zero_p (&vr1)) - && !TYPE_OVERFLOW_WRAPS (expr_type) - && (flag_delete_null_pointer_checks - || (range_int_cst_p (&vr1) - && !tree_int_cst_sign_bit (vr1.max ())))) - vr->set_nonzero (expr_type); - else if (vr0.zero_p () && vr1.zero_p ()) - vr->set_zero (expr_type); - else - vr->set_varying (expr_type); - } ++ extract_range_from_pointer_plus_expr (vr, code, expr_type, &vr0, &vr1); else if (code == BIT_AND_EXPR) { /* For pointer types, we are really only interested in asserting @@@ -1889,8 -1758,115 +1749,116 @@@ range and see what we end up with. */ if (code == PLUS_EXPR || code == MINUS_EXPR) { - extract_range_from_plus_expr (vr, code, expr_type, &vr0, &vr1); - return; + value_range_kind vr0_kind = vr0.kind (), vr1_kind = vr1.kind (); + tree vr0_min = vr0.min (), vr0_max = vr0.max (); + tree vr1_min = vr1.min (), vr1_max = vr1.max (); + /* This will normalize things such that calculating + [0,0] - VR_VARYING is not dropped to varying, but is + calculated as [MIN+1, MAX]. */ + if (vr0.varying_p ()) + { + vr0_kind = VR_RANGE; + vr0_min = vrp_val_min (expr_type); + vr0_max = vrp_val_max (expr_type); + } + if (vr1.varying_p ()) + { + vr1_kind = VR_RANGE; + vr1_min = vrp_val_min (expr_type); + vr1_max = vrp_val_max (expr_type); + } + + const bool minus_p = (code == MINUS_EXPR); + tree min_op0 = vr0_min; + tree min_op1 = minus_p ? vr1_max : vr1_min; + tree max_op0 = vr0_max; + tree max_op1 = minus_p ? vr1_min : vr1_max; + tree sym_min_op0 = NULL_TREE; + tree sym_min_op1 = NULL_TREE; + tree sym_max_op0 = NULL_TREE; + tree sym_max_op1 = NULL_TREE; + bool neg_min_op0, neg_min_op1, neg_max_op0, neg_max_op1; + + neg_min_op0 = neg_min_op1 = neg_max_op0 = neg_max_op1 = false; + + /* If we have a PLUS or MINUS with two VR_RANGEs, either constant or + single-symbolic ranges, try to compute the precise resulting range, + but only if we know that this resulting range will also be constant + or single-symbolic. */ + if (vr0_kind == VR_RANGE && vr1_kind == VR_RANGE + && (TREE_CODE (min_op0) == INTEGER_CST + || (sym_min_op0 + = get_single_symbol (min_op0, &neg_min_op0, &min_op0))) + && (TREE_CODE (min_op1) == INTEGER_CST + || (sym_min_op1 + = get_single_symbol (min_op1, &neg_min_op1, &min_op1))) + && (!(sym_min_op0 && sym_min_op1) + || (sym_min_op0 == sym_min_op1 + && neg_min_op0 == (minus_p ? neg_min_op1 : !neg_min_op1))) + && (TREE_CODE (max_op0) == INTEGER_CST + || (sym_max_op0 + = get_single_symbol (max_op0, &neg_max_op0, &max_op0))) + && (TREE_CODE (max_op1) == INTEGER_CST + || (sym_max_op1 + = get_single_symbol (max_op1, &neg_max_op1, &max_op1))) + && (!(sym_max_op0 && sym_max_op1) + || (sym_max_op0 == sym_max_op1 + && neg_max_op0 == (minus_p ? neg_max_op1 : !neg_max_op1)))) + { + wide_int wmin, wmax; + wi::overflow_type min_ovf = wi::OVF_NONE; + wi::overflow_type max_ovf = wi::OVF_NONE; + + /* Build the bounds. */ + combine_bound (code, wmin, min_ovf, expr_type, min_op0, min_op1); + combine_bound (code, wmax, max_ovf, expr_type, max_op0, max_op1); + + /* If we have overflow for the constant part and the resulting + range will be symbolic, drop to VR_VARYING. */ + if (((bool)min_ovf && sym_min_op0 != sym_min_op1) + || ((bool)max_ovf && sym_max_op0 != sym_max_op1)) + { + vr->set_varying (expr_type); + return; + } + - /* Adjust the range for possible overflow. */ - min = NULL_TREE; - max = NULL_TREE; - set_value_range_with_overflow (type, min, max, expr_type, - wmin, wmax, min_ovf, max_ovf); ++ adjust_range_for_overflow (type, wmin, wmax, expr_type, ++ min_ovf, max_ovf, ++ TYPE_OVERFLOW_WRAPS (expr_type)); + if (type == VR_VARYING) + { + vr->set_varying (expr_type); + return; + } ++ gcc_assert (type != VR_UNDEFINED); ++ min = wide_int_to_tree (expr_type, wmin); ++ max = wide_int_to_tree (expr_type, wmax); + + /* Build the symbolic bounds if needed. */ + adjust_symbolic_bound (min, code, expr_type, + sym_min_op0, sym_min_op1, + neg_min_op0, neg_min_op1); + adjust_symbolic_bound (max, code, expr_type, + sym_max_op0, sym_max_op1, + neg_max_op0, neg_max_op1); + } + else + { + /* For other cases, for example if we have a PLUS_EXPR with two + VR_ANTI_RANGEs, drop to VR_VARYING. It would take more effort + to compute a precise range for such a case. + ??? General even mixed range kind operations can be expressed + by for example transforming ~[3, 5] + [1, 2] to range-only + operations and a union primitive: + [-INF, 2] + [1, 2] U [5, +INF] + [1, 2] + [-INF+1, 4] U [6, +INF(OVF)] + though usually the union is not exactly representable with + a single range or anti-range as the above is + [-INF+1, +INF(OVF)] intersected with ~[5, 5] + but one could use a scheme similar to equivalences for this. */ + vr->set_varying (expr_type); + return; + } } else if (code == MIN_EXPR || code == MAX_EXPR) @@@ -2281,353 -2257,6 +2249,353 @@@ extract_range_from_unary_expr (value_ra return; } +/* Given two ranges (OLD_VR and NEW_VR) that are the result of + VR0 .OPCODE. VR1, abort if they are not equivalent. */ + +void +assert_compare_value_ranges (const value_range_base *old_vr, + const value_range_base *new_vr, + tree_code code, + const value_range_base *vr0, + const value_range_base *vr1) +{ + if (old_vr->equal_p (*new_vr)) + return; + + /* Now account for any known differences between range-ops and + extract_range_from_*expr. If we can't account for the difference + between the ranges, fail vewwy woughly. */ + + /* Ideally, unsigned [1, MAX] should've been canonicalized as + ~[0, 0], but this causes issues with ranges_from_anti_range. + Special case this for now, and avoid batting the beehive. */ + if (TYPE_UNSIGNED (old_vr->type ()) + && integer_onep (old_vr->min ()) + && vrp_val_is_max (old_vr->max ()) + && new_vr->nonzero_p ()) + return; + + /* extract_range_from_binary_expr special cases this scenario, and + gives up. Since range-ops can do better, avoid a false + positive. */ + if (code == EXACT_DIV_EXPR && vr0->nonzero_p ()) + return; + + /* The ordering in which range-ops and + extract_range_from_binary_expr split up and handle sub-ranges + matters, and this can yield slightly worse results for VRP at + times. This is because the union of intermediate ranges, + depending on which order they are done in, can yield + unrepresentable ranges that ultimately generate a VARYING. + + This is imprecise at best, so avoid comparing pairs of + VR_ANTI_RANGES inputs, for which VRP produces VARYING and + range-ops does better. + + For example, extract_range_from_binary_expr, with its recursive + ranges_from_anti_range approach, will handle ~[5,10] OP [20,30] + in this order: + + [0,4][11,MAX] OP [0,19][31,MAX] + + t1 = [0,4] OP [0,19] + t2 = [0,4] OP [31,MAX] + t3 = union(t1, t2) + + t4 = [11,MAX] OP [0,19] + t5 = [11,MAX] OP [31,MAX] + t6 = union(t4, t5) + + t = union(t3, t6) + + Whereas, range-ops will do: + + t = union([0,4] OP [0,19]) + t = union(t, union([0,4] OP [31,MAX])) + t = union(t, union([11,MAX] OP [0,19])) + t = union(t, union([11,MAX] OP [31,MAX])) + + Ugh. In the amount of time it took to explain this, I could've + rewritten VRP to match range-ops, but let's avoid touching too + much of existing code. + + Triggered by: gcc.target/i386/sse4_2-crc32b.c. */ + if (vr0->kind () == VR_ANTI_RANGE && vr1->kind () == VR_ANTI_RANGE + && old_vr->varying_p ()) + return; + + /* MAX/MIN of pointers in VRP dumbs everything down to + NULL/NON_NULL/VARYING. When running range-ops with multiple + sub-ranges, we may get slightly better ranges. In this case, + pretend we're varying and see if we matched VRP. */ + if ((code == MAX_EXPR || code == MIN_EXPR) + && POINTER_TYPE_P (new_vr->type ()) + && !new_vr->zero_p () + && !new_vr->nonzero_p () + && old_vr->varying_p ()) + return; + + /* Sigh. extract_range_from_binary_expr may refuse to work on + varying ranges for some codes, but range-ops can sometimes derive + useful information. This is the same check we have in + extract_range_from_binary_expr. */ + if (code != BIT_AND_EXPR + && code != BIT_IOR_EXPR + && code != TRUNC_DIV_EXPR + && code != FLOOR_DIV_EXPR + && code != CEIL_DIV_EXPR + && code != EXACT_DIV_EXPR + && code != ROUND_DIV_EXPR + && code != TRUNC_MOD_EXPR + && code != MIN_EXPR + && code != MAX_EXPR + && code != PLUS_EXPR + && code != MINUS_EXPR + && code != RSHIFT_EXPR + && code != POINTER_PLUS_EXPR + && (vr0->varying_p () + || vr1->varying_p () + || vr0->symbolic_p () + || vr1->symbolic_p ())) + { + /* If VRP was varying, we know we did better. */ + if (old_vr->varying_p ()) + return; + } + + /* There's an unaccounted difference. This may be a real bug. */ + + tree expr_type = old_vr->type (); + fprintf (stderr, "------------\n"); + fprintf (stderr, "Ranges from VRP and range-ops do not agree!\n"); + fprintf (stderr, "CODE: %s\n", get_tree_code_name (code)); + fprintf (stderr, "TYPE = "); + debug_generic_stmt (expr_type); + if (CONVERT_EXPR_CODE_P (code)) + { + fprintf (stderr, "\tFROM TYPE = "); + debug_generic_stmt (vr0->type ()); + } + fprintf (stderr, "vr0: "); + vr0->dump (stderr); + fputc ('\n', stderr); + if (TREE_CODE_CLASS (code) != tcc_unary) + { + fprintf (stderr, "vr1: "); + vr1->dump (stderr); + fputc ('\n', stderr); + } + fprintf (stderr, "VRP returned: "); + old_vr->dump (stderr); + fprintf (stderr, "\nrange-ops returned: "); + new_vr->dump (stderr); + fputc ('\n', stderr); + gcc_unreachable(); +} + +/* Normalize a value_range for use in range_ops and return it. + Eventually, range-ops should do this for us. */ + +static value_range_base +normalize_for_range_ops (const value_range_base &vr) +{ + tree type = vr.type (); + + /* This will return ~[0,0] for [&var, &var]. */ + if (POINTER_TYPE_P (type) && !range_includes_zero_p (&vr)) + { + value_range_base temp; + temp.set_nonzero (type); + return temp; + } + if (vr.symbolic_p ()) + return normalize_for_range_ops (vr.normalize_symbolics ()); + if (TREE_CODE (vr.min ()) == INTEGER_CST + && TREE_CODE (vr.max ()) == INTEGER_CST) + return vr; + /* Anything not strictly numeric at this point becomes varying. */ + return value_range_base (vr.type ()); +} + +/* Fold a binary expression of two value_range's with range-ops. */ + +static void +range_ops_fold_binary_expr (value_range_base *vr, + enum tree_code code, + tree expr_type, + const value_range_base *vr0_, + const value_range_base *vr1_) +{ + /* Mimic any behavior users of extract_range_from_unary_expr may + expect. */ + range_operator *op = range_op_handler (code); + if (!op) + { + vr->set_varying (expr_type); + return; + } + value_range_base vr0 = *vr0_, vr1 = *vr1_; + if (vr0.undefined_p () && vr1.undefined_p ()) + { + vr->set_undefined (expr_type); + return; + } + if (vr0.undefined_p ()) + vr0.set_varying (expr_type); + else if (vr1.undefined_p ()) + vr1.set_varying (expr_type); + + /* Handle symbolics. Worth moving into range-ops?? */ + if ((code == PLUS_EXPR || code == MINUS_EXPR) + && (vr0.symbolic_p () || vr1.symbolic_p ())) + { + /* Pass on down until we handle anti-ranges in + extract_range_from_plus_expr. */ + extract_range_from_binary_expr (vr, code, expr_type, &vr0, &vr1); + return; + } - if (handle_symbolics_in_pointer_plus_expr (vr, code, expr_type, &vr0, &vr1)) ++ if (extract_range_from_pointer_plus_expr (vr, code, expr_type, &vr0, &vr1)) + return; + + /* Do the range-ops dance. */ + value_range_base n0 = normalize_for_range_ops (vr0); + value_range_base n1 = normalize_for_range_ops (vr1); +#if USE_IRANGE + irange ir; + op->fold_range (ir, n0, n1); + *vr = ir; +#else + op->fold_range (*vr, n0, n1); +#endif +} + +/* Fold a unary expression of a value_range with range-ops. */ + +static void +range_ops_fold_unary_expr (value_range_base *vr, + enum tree_code code, tree expr_type, + const value_range_base *vr0) +{ + /* Mimic any behavior users of extract_range_from_unary_expr may + expect. */ + range_operator *op = range_op_handler (code); + if (!op) + { + vr->set_varying (expr_type); + return; + } + if (vr0->undefined_p ()) + { + vr->set_undefined (expr_type); + return; + } + + /* Handle symbolics. Worth moving into range-ops?? */ + if (code == NEGATE_EXPR && vr0->symbolic_p ()) + { + /* -X is simply 0 - X. */ + value_range_base zero; + zero.set_zero (vr0->type ()); + range_ops_fold_binary_expr (vr, MINUS_EXPR, expr_type, &zero, vr0); + return; + } + if (code == BIT_NOT_EXPR && vr0->symbolic_p ()) + { + /* ~X is simply -1 - X. */ + value_range_base minusone; + minusone.set (build_int_cst (vr0->type (), -1)); + range_ops_fold_binary_expr (vr, MINUS_EXPR, expr_type, &minusone, vr0); + return; + } + if (CONVERT_EXPR_CODE_P (code) && (POINTER_TYPE_P (expr_type) + || POINTER_TYPE_P (vr0->type ()))) + { + /* This handles symbolic conversions such such as [25, x_4]. */ + if (!range_includes_zero_p (vr0)) + vr->set_nonzero (expr_type); + else if (vr0->zero_p ()) + vr->set_zero (expr_type); + else + vr->set_varying (expr_type); + return; + } + + + /* Do the range-ops dance. */ + value_range_base n0 = normalize_for_range_ops (*vr0); + value_range_base n1 (expr_type); +#if USE_IRANGE + irange ir; + op->fold_range (ir, n0, n1); + *vr = ir; +#else + op->fold_range (*vr, n0, n1); +#endif +} + +/* Generic folding of a binary expression between two value_ranges. + Uses range-ops and extract_range_from_binary_expr, and verifies + that the results match. */ + +void +range_fold_binary_expr (value_range_base *vr, + enum tree_code code, + tree expr_type, + const value_range_base *vr0, + const value_range_base *vr1) +{ + if (!value_range_base::supports_type_p (expr_type) + || !value_range_base::supports_type_p (vr0->type ()) + || !value_range_base::supports_type_p (vr1->type ())) + { + *vr = value_range (expr_type); + return; + } + if (flag_ranges_mode & RANGES_RANGE_OPS) + range_ops_fold_binary_expr (vr, code, expr_type, vr0, vr1); + if (flag_ranges_mode & RANGES_VRP) + { + value_range_base old; + extract_range_from_binary_expr (&old, code, expr_type, vr0, vr1); + if (flag_ranges_mode & RANGES_CHECKING) + assert_compare_value_ranges (&old, vr, code, vr0, vr1); + else + *vr = old; + } +} + +/* Generic folding of a unary expression of a value_range. Uses + range-ops and extract_range_from_unary_expr, and verifies that the + results match. */ + +void +range_fold_unary_expr (value_range_base *vr, + enum tree_code code, + tree expr_type, + const value_range_base *vr0) +{ + if (!value_range_base::supports_type_p (expr_type) + || !value_range_base::supports_type_p (vr0->type ())) + { + *vr = value_range (expr_type); + return; + } + if (flag_ranges_mode & RANGES_RANGE_OPS) + range_ops_fold_unary_expr (vr, code, expr_type, vr0); + if (flag_ranges_mode & RANGES_VRP) + { + value_range_base old; + extract_range_from_unary_expr (&old, code, expr_type, vr0, vr0->type ()); + if (flag_ranges_mode & RANGES_CHECKING) + { + value_range_base vr1 (expr_type); + assert_compare_value_ranges (&old, vr, code, vr0, &vr1); + } + else + *vr = old; + } +} + /* Given a COND_EXPR COND of the form 'V OP W', and an SSA name V, create a new SSA name N and return the assertion assignment 'N = ASSERT_EXPR '. */ @@@ -6614,9 -6245,9 +6584,9 @@@ value_range_base::union_helper (const v /* Work on a temporary so we can still use vr0 when union returns varying. */ value_range_base tem; if (vr0type == VR_UNDEFINED) - tem.set_undefined (); + tem.set_undefined (TREE_TYPE (vr0->min ())); else if (vr0type == VR_VARYING) - tem.set_varying (TREE_TYPE (vr0->min ())); + tem.set_varying (vr0->type ()); else tem.set (vr0type, vr0min, vr0max); diff --cc gcc/tree-vrp.h index 32eb856e7faa,c879a8c6df87..ba60f47ef0a8 --- a/gcc/tree-vrp.h +++ b/gcc/tree-vrp.h @@@ -56,8 -58,8 +56,8 @@@ public bool constant_p () const; bool undefined_p () const; bool varying_p () const; - void set_varying (tree); + void set_varying (tree type); - void set_undefined (); + void set_undefined (tree = NULL); void union_ (const value_range_base *); void intersect (const value_range_base *); @@@ -73,24 -75,11 +73,25 @@@ bool nonzero_p () const; bool singleton_p (tree *result = NULL) const; void dump (FILE *) const; + void dump () const; + + static bool supports_type_p (tree); + value_range_base normalize_symbolics () const; + /* Support machinery for irange. */ + static const unsigned int m_max_pairs = 2; - static bool supports_type_p (tree type); + static bool supports_ssa_p (tree ssa); + static bool supports_p (tree expr); + void cast (tree); + bool contains_p (tree) const; + unsigned num_pairs () const; + wide_int lower_bound (unsigned = 0) const; + wide_int upper_bound (unsigned) const; + wide_int upper_bound () const; + void invert (); - void dump () const; - value_range_base normalize_symbolics () const; + void union_ (const value_range_base &); + void intersect (const value_range_base &); + protected: void check (); static value_range_base union_helper (const value_range_base *, diff --cc gcc/vr-values.c index 21c1f930c33c,6f9a3612931c..7a9639f476ec --- a/gcc/vr-values.c +++ b/gcc/vr-values.c @@@ -46,96 -46,8 +46,96 @@@ along with GCC; see the file COPYING3 #include "case-cfn-macros.h" #include "alloc-pool.h" #include "attribs.h" +#include "range.h" #include "vr-values.h" #include "cfghooks.h" +#include "range-op.h" +#include "wide-int-range.h" + + +/* Cache VARYING value_ranges indexed by type. */ +class type_range_cache +{ +public: + type_range_cache (); + ~type_range_cache (); + value_range *varying_range (tree type); +private: + value_range *new_varying (tree type); + hash_map *m_type_table; + obstack m_range_obj; +}; + +/* Delete type cache. */ +type_range_cache::~type_range_cache () +{ + delete m_type_table; + obstack_free (&m_range_obj, NULL); +} + +/* Create a new type cache. */ +type_range_cache::type_range_cache () +{ + /* Allocate a map and a local obstack. */ + m_type_table = new hash_map; + gcc_obstack_init (&m_range_obj); +} + +/* Allocate a new range from the obstack and set it to VARYING for TYPE. */ +inline value_range * +type_range_cache::new_varying (tree type) +{ + /* Allocate memory. */ + void *p = XOBNEW (&m_range_obj, value_range); + /* Invoke the constructors on the memory using placement new. */ + value_range *new_p = new (p) value_range (); + /* Initialize it to varying. */ + new_p->set_varying (type); + return new_p; +} + +/* Return a varying object for TYPE. If it already exists, return it. + Otherwise allocate a new one and register it in the table. */ +value_range * +type_range_cache::varying_range (tree type) +{ + bool existed; + value_range *&slot = m_type_table->get_or_insert (type, &existed); + if (!existed) + slot = new_varying (type); + else + { + /* Sanity check to ensure this varying hasn't been modified. */ + value_range v; + v.set_varying (type); + gcc_checking_assert (v.equal_p (*slot, true)); + } + return slot; +} + +/* Convert the value_range in this object to an irange. This function + will normalize non-constant ranges into constant ranges by + degrading them to VARYING. */ + +irange +vr_values::get_irange (tree op, gimple *stmt ATTRIBUTE_UNUSED) +{ + if (TREE_CODE (op) == INTEGER_CST) + return irange (op, op); + + if (TREE_CODE (op) != SSA_NAME) + return irange (TREE_TYPE (op)); + - value_range *vr = get_value_range (op); ++ const value_range *vr = get_value_range (op); + /* Degrade all symbolics and non-constants into VARYING. This will + downgrade things like [0, "a"], etc. */ + if (vr->symbolic_p () + || ((vr->kind () == VR_RANGE || vr->kind () == VR_ANTI_RANGE) + && !vr->constant_p ())) + return irange (TREE_TYPE (op)); + + return *vr; +} /* Set value range VR to a non-negative range of type TYPE. */ @@@ -1799,8 -1743,8 +1827,8 @@@ compare_range_with_value (enum tree_cod for VAR. If so, update VR with the new limits. */ void - range_misc::adjust_range_with_loop (irange &ir, struct loop *loop, -vr_values::adjust_range_with_scev (value_range *vr, class loop *loop, -- gimple *stmt, tree var) ++range_misc::adjust_range_with_loop (irange &ir, class loop *loop, ++ gimple *stmt, tree var) { tree init, step, chrec, tmin, tmax, min, max, type, tem; enum ev_direction dir; @@@ -2718,7 -2638,7 +2747,8 @@@ vr_values::vrp_visit_cond_stmt (gcond * Returns true if the default label is not needed. */ static bool - find_case_label_ranges (gswitch *stmt, value_range_base *vr, size_t *min_idx1, -find_case_label_ranges (gswitch *stmt, const value_range *vr, size_t *min_idx1, ++find_case_label_ranges (gswitch *stmt, const value_range_base *vr, ++ size_t *min_idx1, size_t *max_idx1, size_t *min_idx2, size_t *max_idx2) { @@@ -3683,14 -3660,10 +3713,14 @@@ vr_values::simplify_cond_using_ranges_ && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (innerop) && desired_pro_or_demotion_p (TREE_TYPE (innerop), TREE_TYPE (op0))) { - value_range *vr = get_value_range (innerop); + const value_range *vr = get_value_range (innerop); + irange ir; + + if (range_int_cst_p (vr)) + ir = *vr; - if (range_int_cst_p (vr) - && range_fits_type_p (vr, + if (!ir.undefined_p () + && range_fits_type_p (ir, TYPE_PRECISION (TREE_TYPE (op0)), TYPE_SIGN (TREE_TYPE (op0))) && int_fits_type_p (op1, TREE_TYPE (innerop))) @@@ -3717,8 -3690,7 +3747,8 @@@ boo vr_values::simplify_switch_using_ranges (gswitch *stmt) { tree op = gimple_switch_index (stmt); - const value_range *vr = NULL; + value_range_base vr_obj; - value_range_base *vr = NULL; ++ const value_range_base *vr = NULL; bool take_default; edge e; edge_iterator ei; diff --cc gcc/vr-values.h index 29b35d0f2ea7,ec65de3dab73..ea4c6b6e3baa --- a/gcc/vr-values.h +++ b/gcc/vr-values.h @@@ -76,14 -40,15 +76,16 @@@ class vr_values : public range_mis vr_values (void); ~vr_values (void); - value_range *get_value_range (const_tree); - + const value_range *get_value_range (const_tree); void set_vr_value (tree, value_range *); + value_range *swap_vr_value (tree, value_range *); + + void set_def_to_varying (const_tree); void set_defs_to_varying (gimple *); bool update_value_range (const_tree, value_range *); - tree op_with_constant_singleton_value_range (tree); - void adjust_range_with_scev (value_range *, class loop *, gimple *, tree); + tree singleton (tree, gimple *); - void adjust_range_with_scev (value_range_base *, struct loop *, gimple *, ++ void adjust_range_with_scev (value_range_base *, class loop *, gimple *, + tree); tree vrp_evaluate_conditional (tree_code, tree, tree, gimple *); void dump_all_value_ranges (FILE *); @@@ -108,13 -76,17 +112,13 @@@ void cleanup_edges_and_switches (void); private: + irange get_irange (tree, gimple *); - + value_range *get_lattice_entry (const_tree); bool vrp_stmt_computes_nonzero (gimple *); bool op_with_boolean_value_range_p (tree); - value_range *get_vr_for_comparison (int, value_range *); - bool check_for_binary_op_overflow (enum tree_code, tree, tree, tree, bool *); + const value_range *get_vr_for_comparison (int, value_range *); tree compare_name_with_value (enum tree_code, tree, tree, bool *, bool); tree compare_names (enum tree_code, tree, tree, bool *); - bool two_valued_val_range_p (tree, tree *, tree *); - tree vrp_evaluate_conditional_warnv_with_ops_using_ranges (enum tree_code, - tree, tree, - bool *); tree vrp_evaluate_conditional_warnv_with_ops (enum tree_code, tree, tree, bool, bool *, bool *);