From patchwork Fri Jun 21 11:41:26 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aldy Hernandez X-Patchwork-Id: 1120179 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-503425-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 45VcGk6nT8z9s4V for ; Fri, 21 Jun 2019 21:41:49 +1000 (AEST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:to:cc :from:subject:message-id:date:mime-version:content-type; q=dns; s=default; b=RDQxzWkIAnsz5hD4IOBdeXuuGe39dO2ZsbQB14Qy03obb6xkIm K5EMk9czC1IY/T6g+ZBrsCuigBEAlAQT+dNaocd/cy0VDy8sQDQWCR+to6v6x6jk /PrUnyv0H1aU+/7EGDOWtw2So3H4PTYh28r5hawVA2/tPBtAsS1/P+PBo= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:to:cc :from:subject:message-id:date:mime-version:content-type; s= default; bh=Kc87O4BcysgFLPgb74DSe//YNew=; b=SSYPGv6XXHAoFiha8SDr 4NWS2VbciSNj2K9wAs5xNw+0moqMagqqU+idX64Bh7uUllnbtYkAWWg+Wz6zlet1 ou3iy/ANgWRe1LFV+7L5UfvTU3OgdbILjh6Oj0R2Kwgor+HR/WU+4Ruy4/5LmoQi jjuuR2axlWmz1yEpQDX2UDw= Received: (qmail 116770 invoked by alias); 21 Jun 2019 11:41:38 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 116762 invoked by uid 89); 21 Jun 2019 11:41:38 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-19.4 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_ASCII_DIVIDERS, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 spammy=traversal, virtually, 6627 X-HELO: mail-wm1-f51.google.com Received: from mail-wm1-f51.google.com (HELO mail-wm1-f51.google.com) (209.85.128.51) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 21 Jun 2019 11:41:31 +0000 Received: by mail-wm1-f51.google.com with SMTP id u8so6267428wmm.1 for ; Fri, 21 Jun 2019 04:41:30 -0700 (PDT) Received: from abulafia.quesejoda.com (96.red-79-147-188.dynamicip.rima-tde.net. [79.147.188.96]) by smtp.gmail.com with ESMTPSA id y2sm1791824wrl.4.2019.06.21.04.41.27 (version=TLS1_3 cipher=AEAD-AES128-GCM-SHA256 bits=128/128); Fri, 21 Jun 2019 04:41:27 -0700 (PDT) To: Richard Biener , gcc-patches Cc: Andrew MacLeod From: Aldy Hernandez Subject: value_range and irange unification Message-ID: <684d495e-d931-ab7f-672e-1ccd13f1bc00@redhat.com> Date: Fri, 21 Jun 2019 07:41:26 -0400 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.6.1 MIME-Version: 1.0 X-IsSubscribed: yes Hi Richard. Hi folks. In order to unify the APIs for value_range and irange, we'd like to make some minor changes to value_range. We believe most of these changes could go in now, and would prefer so, to get broader testing and minimize the plethora of changes we drag around on our branch. First, introduce a type for VR_VARYING and VR_UNDEFINED. -------------------------------------------------------- irange utilizes 0 or more sub-ranges to represent a range, and VARYING is simply one subrange [MIN, MAX]. value_range represents this with VR_VARYING, and since there is no type associated with it, we cannot calculate the lower and upper bounds for the range. There is also a lack of canonicalness in value range in that VR_VARYING and [MIN, MAX] are two different representations of the same value. We tried to adjust irange to not associate a type with the empty range [] (representing undefined), but found we were unable to perform all operations properly. In particular, we cannot invert an empty range. i.e. invert ( [] ) should produce [MIN, MAX]. Again, we need to have a type associated with this empty range. We'd like to tweak value_range so that set_varying() and set_undefined() both take a type, and then always set the min/max fields based on that type. This takes no additional memory in the structure, and is virtually transparent to all the existing uses of value_range. This allows: 1) invert to be implemented properly for both VARYING and UNDEFINED by simply changing one to the other. 2) the type() method to always work without any special casing by simply returning TREE_TYPE(min) 3) the new incoming bounds() routines to work trivially for these cases as well (lbound/ubound, num_pairs(), etc). This functionality is provided in the first attached patch. Note, the current implementation sets min/max to TREE_TYPE, not to TYPE_MIN/MAX_VALUE. We can fix this if preferred. Second, enforce canonicalization at value_range build time. ----------------------------------------------------------- As discussed above, value_range has multiple representations for the same range. For instance, ~[0,0] is the same as [1,MAX] in unsigned and [MIN, MAX] is really varying, among others. We found it quite difficult to make things work, with multiple representations for a given range. Canonicalizing at build time solves this, as well as removing explicit set_and_canonicalize() calls throughout. Furthermore, it avoids some special casing in VRP. Along with canonicalizing, we also enforce the existing value_range API more strongly. For instance, we don't allow setting equivalences for either VR_VARYING or VR_UNDEFINED. This functionality is provided in the second patch. Third, irange on value_range implementation. --------------------------------------------- The third attached patch shows how we use the above two to implement irange using value_ranges. value_range would be a drop-in replacement for irange, by just doing the following in range.h: +// Enable this to implement irange piggybacking on value_range. +#define IRANGE_WITH_VALUE_RANGE 1 + +#if IRANGE_WITH_VALUE_RANGE +#include "tree-vrp.h" +typedef value_range_base irange; +typedef value_range_storage irange_storage; +#define IRANGE_PLAIN VR_RANGE +#define IRANGE_INVERSE VR_ANTI_RANGE +#else ... The additions to the value_range API would be mostly the following (full details in the third attached patch): + value_range_base (tree, tree); + value_range_base (value_range_kind, + tree type, const wide_int &, const wide_int &); + value_range_base (tree type, const wide_int &, const wide_int &); + value_range_base (tree type, const value_range_storage *); + value_range_base (tree type); void set (value_range_kind, tree, tree); void set (tree); @@ -77,7 +86,25 @@ public: bool singleton_p (tree *result = NULL) const; void dump (FILE *) 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 { dump (stderr); } + // FIXME: Perhaps rewrite the irange versions to use pointers instead. + void union_ (const value_range_base &); + void intersect (const value_range_base &); + protected: + value_range_base normalize_symbolics () const; There are no regressions from mainline, and we are catching every one of our internal ranger tests, with the exception of two that require more than 2 sub-ranges to work. i.e. Not a regression from mainline-- just new functionality we can't get with the limited sub-ranges in value_range. Note: Please ignore the value_range_base::normalize_symbolics stuff. It's likely to go through multiple revisions as Andrew gets the ranger to deal with symbolics. Finally ------- All these patches are already in our branch, and irange with value_range can be enabled by #define IRANGE_WITH_VALUE_RANGE 1. With these changes, we can successfully build and run the ranger branch using value_range in place of irange, which indicates a successful API merge. After some minor cleanups, I would like to contribute at least the first two patches to trunk (VARYING types and the enforced canonicalization). This will enable us to move forward with trying to integrate the range-ops code which makes heavy use of the subrange interface, and allows for broader testing instead of dropping everything in one-go. These two patches stand on their own independently, and IMO provide useful functionality right now. I would ideally like to contribute the third patch to mainline, but I do understand that it currently has no users... although I could rewrite bits of tree-vrp to use these new functions (lower_bound, upper_bound, etc), thus providing a use case ??. However, I do understand if you'd prefer to keep this last patch on the branch. Thoughts? Aldy (and Andrew) commit 1d7d379b3f8b23e5b378488f5dc1e8cc3225d350 Author: aldyh Date: Tue Jun 18 22:44:57 2019 +0000 irange on value_range implementation. diff --git a/gcc/tree-vrp.h b/gcc/tree-vrp.h index 4af1bc99da9..80fcc4aee26 100644 --- a/gcc/tree-vrp.h +++ b/gcc/tree-vrp.h @@ -35,14 +35,23 @@ enum value_range_kind VR_LAST }; +class value_range_storage; /* Range of values that can be associated with an SSA_NAME after VRP has executed. */ class GTY((for_user)) value_range_base { + friend value_range_storage; + friend void irange_tests (); public: value_range_base (); value_range_base (value_range_kind, tree, tree); + value_range_base (tree, tree); + value_range_base (value_range_kind, + tree type, const wide_int &, const wide_int &); + value_range_base (tree type, const wide_int &, const wide_int &); + value_range_base (tree type, const value_range_storage *); + value_range_base (tree type); void set (value_range_kind, tree, tree); void set (tree); @@ -77,7 +86,25 @@ public: bool singleton_p (tree *result = NULL) const; void dump (FILE *) 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 { dump (stderr); } + // FIXME: Perhaps rewrite the irange versions to use pointers instead. + void union_ (const value_range_base &); + void intersect (const value_range_base &); + protected: + value_range_base normalize_symbolics () const; void check (); static value_range_base union_helper (const value_range_base *, const value_range_base *); @@ -156,6 +183,29 @@ class GTY((user)) value_range : public value_range_base bitmap m_equiv; }; +class value_range_storage +{ + friend class value_range_base; +public: + static value_range_storage *alloc (const value_range_base &r) + { + value_range_storage *p = ggc_alloc (); + p->set (r); + return p; + } + bool update (const value_range_base &r) + { + set (r); + return true; + } +private: + void set (const value_range_base &r) + { + m_vr = r; + } + value_range_base m_vr; +}; + inline value_range_base::value_range_base () { @@ -267,11 +317,11 @@ extern bool range_int_cst_singleton_p (const value_range_base *); extern int compare_values (tree, tree); extern int compare_values_warnv (tree, tree, bool *); extern int operand_less_p (tree, tree); -extern bool vrp_val_is_min (const_tree); -extern bool vrp_val_is_max (const_tree); +extern bool vrp_val_is_min (const_tree, bool handle_pointers = false); +extern bool vrp_val_is_max (const_tree, bool handle_pointers = false); -extern tree vrp_val_min (const_tree); -extern tree vrp_val_max (const_tree); +extern tree vrp_val_min (const_tree, bool handle_pointers = false); +extern tree vrp_val_max (const_tree, bool handle_pointers = false); extern void extract_range_from_unary_expr (value_range_base *vr, enum tree_code code, diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index 8a3bd2599a5..b4d5698823e 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -71,6 +71,11 @@ along with GCC; see the file COPYING3. If not see #include "wide-int-range.h" #include "grange.h" +static bool +ranges_from_anti_range (const value_range_base *ar, + value_range_base *vr0, value_range_base *vr1, + bool handle_pointers = false); + /* Set of SSA names found live during the RPO traversal of the function for still active basic-blocks. */ static sbitmap *live; @@ -136,6 +141,42 @@ value_range::value_range (const value_range_base &other) set (other.kind (), other.min(), other.max (), NULL); } +value_range_base::value_range_base (tree type) +{ + set_varying (type); +} + +value_range_base::value_range_base (enum value_range_kind kind, + tree type, + const wide_int &wmin, + const wide_int &wmax) +{ + tree min = wide_int_to_tree (type, wmin); + tree max = wide_int_to_tree (type, wmax); + gcc_assert (kind == VR_RANGE || kind == VR_ANTI_RANGE); + set_and_canonicalize (kind, min, max); +} + +value_range_base::value_range_base (tree type, + const wide_int &wmin, + const wide_int &wmax) +{ + tree min = wide_int_to_tree (type, wmin); + tree max = wide_int_to_tree (type, wmax); + set_and_canonicalize (VR_RANGE, min, max); +} + +value_range_base::value_range_base (tree min, tree max) +{ + set (VR_RANGE, min, max); +} + +value_range_base::value_range_base (tree type ATTRIBUTE_UNUSED, + const value_range_storage *stow) +{ + *this = stow->m_vr; +} + /* Like set, but keep the equivalences in place. */ void @@ -334,6 +375,13 @@ value_range::equiv_add (const_tree var, bool value_range_base::singleton_p (tree *result) const { + if (m_kind == VR_ANTI_RANGE) + { + value_range_base vr0, vr1; + return (ranges_from_anti_range (this, &vr0, &vr1, true) + && vr1.undefined_p () + && vr0.singleton_p (result)); + } if (m_kind == VR_RANGE && vrp_operand_equal_p (min (), max ()) && is_gimple_min_invariant (min ())) @@ -520,10 +568,18 @@ static assert_locus **asserts_for; /* Return the maximum value for TYPE. */ tree -vrp_val_max (const_tree type) +vrp_val_max (const_tree type, bool handle_pointers) { if (!INTEGRAL_TYPE_P (type)) - return NULL_TREE; + { + if (POINTER_TYPE_P (type) && handle_pointers) + { + wide_int max = wi::max_value (TYPE_PRECISION (type), + TYPE_SIGN (type)); + return wide_int_to_tree (const_cast (type), max); + } + return NULL_TREE; + } return TYPE_MAX_VALUE (type); } @@ -531,10 +587,14 @@ vrp_val_max (const_tree type) /* Return the minimum value for TYPE. */ tree -vrp_val_min (const_tree type) +vrp_val_min (const_tree type, bool handle_pointers) { if (!INTEGRAL_TYPE_P (type)) - return NULL_TREE; + { + if (POINTER_TYPE_P (type) && handle_pointers) + return build_zero_cst (const_cast (type)); + return NULL_TREE; + } return TYPE_MIN_VALUE (type); } @@ -545,9 +605,9 @@ vrp_val_min (const_tree type) is not == to the integer constant with the same value in the type. */ bool -vrp_val_is_max (const_tree val) +vrp_val_is_max (const_tree val, bool handle_pointers) { - tree type_max = vrp_val_max (TREE_TYPE (val)); + tree type_max = vrp_val_max (TREE_TYPE (val), handle_pointers); return (val == type_max || (type_max != NULL_TREE && operand_equal_p (val, type_max, 0))); @@ -556,9 +616,9 @@ vrp_val_is_max (const_tree val) /* Return whether VAL is equal to the minimum value of its type. */ bool -vrp_val_is_min (const_tree val) +vrp_val_is_min (const_tree val, bool handle_pointers) { - tree type_min = vrp_val_min (TREE_TYPE (val)); + tree type_min = vrp_val_min (TREE_TYPE (val), handle_pointers); return (val == type_min || (type_min != NULL_TREE && operand_equal_p (val, type_min, 0))); @@ -652,7 +712,7 @@ value_range_base::set_and_canonicalize (enum value_range_kind kind, { if (kind == VR_UNDEFINED) { - gcc_assert (TYPE_P (min)); + gcc_assert (!min || TYPE_P (min)); set_undefined (min); return; } @@ -704,11 +764,11 @@ value_range_base::set_and_canonicalize (enum value_range_kind kind, } /* Anti-ranges that can be represented as ranges should be so. */ + tree type = TREE_TYPE (min); if (kind == VR_ANTI_RANGE) { /* For -fstrict-enums we may receive out-of-range ranges so consider values < -INF and values > INF as -INF/INF as well. */ - tree type = TREE_TYPE (min); bool is_min = (INTEGRAL_TYPE_P (type) && tree_int_cst_compare (min, TYPE_MIN_VALUE (type)) <= 0); bool is_max = (INTEGRAL_TYPE_P (type) @@ -754,7 +814,6 @@ value_range_base::set_and_canonicalize (enum value_range_kind kind, /* FIXME: The ranger chops off out-of-bound ranges for -fstrict-enums. Do the same here. This is only here to make sure the ranger and VRP compare correctly. */ - tree type = TREE_TYPE (min); if (TREE_CODE (type) == ENUMERAL_TYPE && kind == VR_RANGE) { @@ -1209,8 +1279,14 @@ vrp_set_zero_nonzero_bits (const tree expr_type, static bool ranges_from_anti_range (const value_range_base *ar, - value_range_base *vr0, value_range_base *vr1) + value_range_base *vr0, value_range_base *vr1, + bool handle_pointers) { + /* ?? This function is called multiple times from num_pairs, + lower_bound, and upper_bound. We should either memoize this, or + rewrite the callers in such a way that we're not re-calculating + this constantly. */ + tree type = ar->type (); vr0->set_undefined (type); @@ -1222,18 +1298,18 @@ ranges_from_anti_range (const value_range_base *ar, if (ar->kind () != VR_ANTI_RANGE || TREE_CODE (ar->min ()) != INTEGER_CST || TREE_CODE (ar->max ()) != INTEGER_CST - || !vrp_val_min (type) - || !vrp_val_max (type)) + || !vrp_val_min (type, handle_pointers) + || !vrp_val_max (type, handle_pointers)) return false; - if (tree_int_cst_lt (vrp_val_min (type), ar->min ())) + if (tree_int_cst_lt (vrp_val_min (type, handle_pointers), ar->min ())) vr0->set (VR_RANGE, - vrp_val_min (type), + vrp_val_min (type, handle_pointers), wide_int_to_tree (type, wi::to_wide (ar->min ()) - 1)); - if (tree_int_cst_lt (ar->max (), vrp_val_max (type))) + if (tree_int_cst_lt (ar->max (), vrp_val_max (type, handle_pointers))) vr1->set (VR_RANGE, wide_int_to_tree (type, wi::to_wide (ar->max ()) + 1), - vrp_val_max (type)); + vrp_val_max (type, handle_pointers)); if (vr0->undefined_p ()) { *vr0 = *vr1; @@ -6547,6 +6623,197 @@ value_range::union_ (const value_range *other) } } +value_range_base +value_range_base::normalize_symbolics () const +{ + tree ttype = type (); + bool min_symbolic = is_gimple_min_invariant (min ()); + bool max_symbolic = is_gimple_min_invariant (max ()); + if (varying_p () || undefined_p () || (!min_symbolic && !max_symbolic)) + return *this; + + // [SYM, SYM] -> VARYING + if (min_symbolic && max_symbolic) + goto varying; + if (kind () == VR_RANGE) + { + // [SYM, NUM] -> [-MIN, NUM] + if (min_symbolic) + return value_range_base (VR_RANGE, vrp_val_min (ttype), max ()); + // [NUM, SYM] -> [NUM, +MAX] + return value_range_base (VR_RANGE, min (), vrp_val_max (ttype)); + } + gcc_assert (kind () == VR_ANTI_RANGE); + // ~[SYM, NUM] -> [NUM + 1, +MAX] + if (min_symbolic) + { + if (!vrp_val_is_max (max ())) + { + tree n = wide_int_to_tree (ttype, wi::to_wide (max ()) + 1); + return value_range_base (VR_RANGE, n, vrp_val_max (ttype)); + } + goto varying; + } + // ~[NUM, SYM] -> [-MIN, NUM - 1] + if (!vrp_val_is_min (min ())) + { + tree n = wide_int_to_tree (ttype, wi::to_wide (min ()) - 1); + return value_range_base (VR_RANGE, vrp_val_min (ttype), n); + } + varying: + value_range_base tmp; + tmp.set_varying (ttype); + return tmp; +} + +unsigned +value_range_base::num_pairs () const +{ + if (undefined_p ()) + return 0; + if (varying_p ()) + return 1; + if (symbolic_p ()) + return normalize_symbolics ().num_pairs (); + if (m_kind == VR_ANTI_RANGE) + { + value_range_base vr0, vr1; + gcc_assert (ranges_from_anti_range (this, &vr0, &vr1, true)); + if (vr1.undefined_p ()) + return 1; + return 2; + } + return 1; +} + +wide_int +value_range_base::lower_bound (unsigned pair) const +{ + if (symbolic_p ()) + return normalize_symbolics ().lower_bound (pair); + + gcc_assert (!undefined_p ()); + gcc_assert (pair + 1 <= num_pairs ()); + tree t = NULL; + if (varying_p ()) + t = vrp_val_min (type (), true); + else if (m_kind == VR_RANGE) + t = m_min; + else if (m_kind == VR_ANTI_RANGE) + { + value_range_base vr0, vr1; + gcc_assert (ranges_from_anti_range (this, &vr0, &vr1, true)); + if (pair == 0) + t = vr0.min (); + else if (pair == 1) + t = vr1.min (); + else + gcc_unreachable (); + } + return wi::to_wide (t); +} + +wide_int +value_range_base::upper_bound (unsigned pair) const +{ + if (symbolic_p ()) + return normalize_symbolics ().upper_bound (pair); + + gcc_assert (!undefined_p ()); + gcc_assert (pair + 1 <= num_pairs ()); + tree t = NULL; + if (varying_p ()) + t = vrp_val_max (type (), true); + else if (m_kind == VR_RANGE) + t = m_max; + else if (m_kind == VR_ANTI_RANGE) + { + value_range_base vr0, vr1; + gcc_assert (ranges_from_anti_range (this, &vr0, &vr1, true)); + if (pair == 0) + t = vr0.max (); + else if (pair == 1) + t = vr1.max (); + else + gcc_unreachable (); + } + return wi::to_wide (t); +} + +wide_int +value_range_base::upper_bound () const +{ + unsigned pairs = num_pairs (); + gcc_assert (pairs > 0); + return upper_bound (pairs - 1); +} + +void +value_range_base::cast (tree typ) +{ + value_range_base tem; + enum ranges_mode save = flag_ranges_mode; + /* Avoid infinite recursion in the ranger vs vrp checking code. */ + flag_ranges_mode = RANGES_VRP; + /* At some point we should inline all of the CONVERT_EXPR code from + extract_range_from_unary_expr here. */ + extract_range_from_unary_expr (&tem, CONVERT_EXPR, typ, this, type ()); + flag_ranges_mode = save; + *this = tem; +} + +/* Return TRUE if range contains INTEGER_CST. */ + +bool +value_range_base::contains_p (tree cst) const +{ + gcc_assert (TREE_CODE (cst) == INTEGER_CST); + if (symbolic_p ()) + return normalize_symbolics ().contains_p (cst); + return value_inside_range (cst) == 1; +} + +void +value_range_base::invert () +{ + if (undefined_p ()) + set_varying (type ()); + else if (varying_p ()) + set_undefined (type ()); + else if (m_kind == VR_RANGE) + m_kind = VR_ANTI_RANGE; + else if (m_kind == VR_ANTI_RANGE) + m_kind = VR_RANGE; + else + gcc_unreachable (); +} + +void +value_range_base::union_ (const value_range_base &r) +{ + /* Disable details for now, because it makes the ranger dump + unnecessarily verbose. */ + bool details = dump_flags & TDF_DETAILS; + if (details) + dump_flags &= ~TDF_DETAILS; + union_ (&r); + if (details) + dump_flags |= TDF_DETAILS; +} + +void +value_range_base::intersect (const value_range_base &r) +{ + /* Disable details for now, because it makes the ranger dump + unnecessarily verbose. */ + bool details = dump_flags & TDF_DETAILS; + if (details) + dump_flags &= ~TDF_DETAILS; + intersect (&r); + if (details) + dump_flags |= TDF_DETAILS; +} + /* Visit all arguments for PHI node PHI that flow through executable edges. If a valid value range can be derived from all the incoming value ranges, set a new range for the LHS of PHI. */ @@ -7241,3 +7512,24 @@ determine_value_range (tree expr, wide_int *min, wide_int *max) return VR_VARYING; } + +#if IRANGE_WITH_VALUE_RANGE +irange +value_range_to_irange (tree type ATTRIBUTE_UNUSED, const value_range_base &vr) +{ + return vr; +} + +irange +value_range_to_irange (tree type, enum value_range_kind kind, + const wide_int &min, const wide_int &max) +{ + return irange (kind, type, min, max); +} + +value_range_base +irange_to_value_range (const irange &ir) +{ + return ir; +} +#endif // IRANGE_TO_VALUE_RANGE diff --git a/gcc/vr-values.c b/gcc/vr-values.c index 6bc62f46d2a..def5a163e90 100644 --- a/gcc/vr-values.c +++ b/gcc/vr-values.c @@ -105,7 +105,7 @@ set_value_range_to_truthvalue (value_range *vr, tree type) value_range * vr_values::get_value_range (const_tree var) { - static const value_range vr_const_varying (VR_VARYING, NULL, NULL); + tree type = TREE_TYPE (var); value_range *vr; tree sym; unsigned ver = SSA_NAME_VERSION (var); @@ -118,7 +118,13 @@ vr_values::get_value_range (const_tree var) We should get here at most from the substitute-and-fold stage which will never try to change values. */ if (ver >= num_vr_values) - return CONST_CAST (value_range *, &vr_const_varying); + { + /* ?? At some point we should find a way to cache varying ranges + by type. In the tree type itself? */ + vr = vrp_value_range_pool.allocate (); + vr->set_varying (type); + return vr; + } vr = vr_value[ver]; if (vr) @@ -126,11 +132,16 @@ vr_values::get_value_range (const_tree var) /* After propagation finished do not allocate new value-ranges. */ if (values_propagated) - return CONST_CAST (value_range *, &vr_const_varying); + { + /* See note about caching varying above. */ + vr = vrp_value_range_pool.allocate (); + vr->set_varying (type); + return vr; + } /* Create a default value range. */ vr_value[ver] = vr = vrp_value_range_pool.allocate (); - vr->set_undefined (); + vr->set_undefined (type); /* If VAR is a default definition of a parameter, the variable can take any value in VAR's type. */ @@ -179,9 +190,7 @@ vr_values::set_defs_to_varying (gimple *stmt) FOR_EACH_SSA_TREE_OPERAND (def, stmt, i, SSA_OP_DEF) { value_range *vr = get_value_range (def); - /* Avoid writing to vr_const_varying get_value_range may return. */ - if (!vr->varying_p ()) - vr->set_varying (TREE_TYPE (def)); + vr->set_varying (TREE_TYPE (def)); } } @@ -995,6 +1004,9 @@ check_for_binary_op_overflow (enum tree_code subcode, tree type, tree op1, irange &ir1, bool *ovf) { + if (ir0.undefined_p () || ir1.undefined_p ()) + return false; + tree vr0min = wide_int_to_tree (TREE_TYPE (op0), ir0.lower_bound ()); tree vr0max = wide_int_to_tree (TREE_TYPE (op0), ir0.upper_bound ()); tree vr1min = wide_int_to_tree (TREE_TYPE (op1), ir1.lower_bound ()); @@ -3948,6 +3960,12 @@ range_misc::simplify_float_conversion_using_ranges (gimple_stmt_iterator *gsi, tree tem; gassign *conv; + /* An undefined means this statement is unreachable. Bail to avoid + calculating anything in range_fits_type_p below. Perhaps we + should generically bail from simplify_stmt_using_ranges. */ + if (ir.undefined_p ()) + return false; + /* First check if we can use a signed type in place of an unsigned. */ scalar_int_mode rhs_mode = SCALAR_INT_TYPE_MODE (TREE_TYPE (rhs1)); if (TYPE_UNSIGNED (TREE_TYPE (rhs1))