Message ID | 20210426141651.1657784-1-aldyh@redhat.com |
---|---|
State | New |
Headers | show |
Series | [1/2] Keep VR_UNDEFINED and VR_VARYING in sync (speeds up evrp by 8.47%). | expand |
On 4/26/21 10:16 AM, Aldy Hernandez wrote: > Currently multi-ranges calculate the undefined and varying bits on the > fly, whereas legacy uses the m_kind field. Since we will always have > space in the irange class for a kind field, might as well keep it in > sync as ranges are created, thus speeding up lookups. > > This patch, along with an upcoming ones for num_pairs(), speeds up EVRP > by 8.47%, VRP proper by 1.84% and overall compilation by 0.24%. > > FWIW, since evrp is such a fast pass, and is hard to measure clock-wise, > we've been using callgrind to estimate improvements. This has coincided > more or less with -ftime-report numbers (albeit having to run -ftime-report > half a dozen times and use the average). > > OK? Guess we should have done this earlier.. varying_p is very heavily used. I assume this also passes regressions and bootstrap :-)? > // Number of sub-ranges in a range. > @@ -271,17 +263,18 @@ irange::max () const > } > > inline bool > -irange::varying_p () const > +irange::irange_varying_p () const > { > - if (legacy_mode_p ()) > - return m_kind == VR_VARYING; > - > if (m_num_ranges != 1) > return false; > > tree l = m_base[0]; > tree u = m_base[1]; > tree t = TREE_TYPE (l); > + > + if (m_kind == VR_VARYING && t == error_mark_node) > + return true; > + > unsigned prec = TYPE_PRECISION (t); > signop sign = TYPE_SIGN (t); > if (INTEGRAL_TYPE_P (t)) > @@ -291,22 +284,17 @@ irange::varying_p () const > return (wi::to_wide (l) == 0 > && wi::to_wide (u) == wi::max_value (prec, sign)); > return true; > +} > I find the routine irange_varying_p() name to be a bit confusing... since varying_p is also an irange routine.. Maybe call it something like varying_p_compatible () or something along those lines? > > inline void > -irange::normalize_min_max () > -{ > - gcc_checking_assert (legacy_mode_p ()); > - gcc_checking_assert (!undefined_p ()); > - unsigned prec = TYPE_PRECISION (type ()); > - signop sign = TYPE_SIGN (type ()); > - if (wi::eq_p (wi::to_wide (min ()), wi::min_value (prec, sign)) > - && wi::eq_p (wi::to_wide (max ()), wi::max_value (prec, sign))) > +irange::normalize_kind () > +{ > + if (m_num_ranges == 0) > + m_kind = VR_UNDEFINED; > + else if (irange_varying_p ()) > { > if (m_kind == VR_RANGE) > - set_varying (type ()); > + m_kind = VR_VARYING; > else if (m_kind == VR_ANTI_RANGE) > set_undefined (); > else I see that normalize_kind will turn a varying ANTI_RANGE to UNDEFINED. If you go into irange::set (tree min, tree max, value_range_kind kind) I see: // Anti-ranges that can be represented as ranges should be so. 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. */ bool is_min = vrp_val_is_min (min); bool is_max = vrp_val_is_max (max); tree type = TREE_TYPE (min); if (is_min && is_max) { /* We cannot deal with empty ranges, drop to varying. ??? This could be VR_UNDEFINED instead. */ set_varying (type); return; } should that be set_undefined? or is that a different can of worms related to strict-enum? Assuming bootstrap and regression tests, OK Andrew
On 4/26/21 5:03 PM, Andrew MacLeod wrote: > On 4/26/21 10:16 AM, Aldy Hernandez wrote: >> Currently multi-ranges calculate the undefined and varying bits on the >> fly, whereas legacy uses the m_kind field. Since we will always have >> space in the irange class for a kind field, might as well keep it in >> sync as ranges are created, thus speeding up lookups. >> >> This patch, along with an upcoming ones for num_pairs(), speeds up EVRP >> by 8.47%, VRP proper by 1.84% and overall compilation by 0.24%. >> >> FWIW, since evrp is such a fast pass, and is hard to measure clock-wise, >> we've been using callgrind to estimate improvements. This has coincided >> more or less with -ftime-report numbers (albeit having to run >> -ftime-report >> half a dozen times and use the average). >> >> OK? > > Guess we should have done this earlier.. varying_p is very heavily > used. I assume this also passes regressions and bootstrap :-)? > > >> // Number of sub-ranges in a range. >> @@ -271,17 +263,18 @@ irange::max () const >> } >> inline bool >> -irange::varying_p () const >> +irange::irange_varying_p () const >> { >> - if (legacy_mode_p ()) >> - return m_kind == VR_VARYING; >> - >> if (m_num_ranges != 1) >> return false; >> tree l = m_base[0]; >> tree u = m_base[1]; >> tree t = TREE_TYPE (l); >> + >> + if (m_kind == VR_VARYING && t == error_mark_node) >> + return true; >> + >> unsigned prec = TYPE_PRECISION (t); >> signop sign = TYPE_SIGN (t); >> if (INTEGRAL_TYPE_P (t)) >> @@ -291,22 +284,17 @@ irange::varying_p () const >> return (wi::to_wide (l) == 0 >> && wi::to_wide (u) == wi::max_value (prec, sign)); >> return true; >> +} > I find the routine irange_varying_p() name to be a bit confusing... > since varying_p is also an irange routine.. Maybe call it something > like varying_p_compatible () or something along those lines? I've named it varying_compatible_p. >> inline void >> -irange::normalize_min_max () >> -{ >> - gcc_checking_assert (legacy_mode_p ()); >> - gcc_checking_assert (!undefined_p ()); >> - unsigned prec = TYPE_PRECISION (type ()); >> - signop sign = TYPE_SIGN (type ()); >> - if (wi::eq_p (wi::to_wide (min ()), wi::min_value (prec, sign)) >> - && wi::eq_p (wi::to_wide (max ()), wi::max_value (prec, sign))) >> +irange::normalize_kind () >> +{ >> + if (m_num_ranges == 0) >> + m_kind = VR_UNDEFINED; >> + else if (irange_varying_p ()) >> { >> if (m_kind == VR_RANGE) >> - set_varying (type ()); >> + m_kind = VR_VARYING; >> else if (m_kind == VR_ANTI_RANGE) >> set_undefined (); >> else > > I see that normalize_kind will turn a varying ANTI_RANGE to UNDEFINED. > If you go into irange::set (tree min, tree max, value_range_kind kind) I > see: > > // Anti-ranges that can be represented as ranges should be so. > 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. */ > bool is_min = vrp_val_is_min (min); > bool is_max = vrp_val_is_max (max); > tree type = TREE_TYPE (min); > > if (is_min && is_max) > { > /* We cannot deal with empty ranges, drop to varying. > ??? This could be VR_UNDEFINED instead. */ > set_varying (type); > return; > } > > should that be set_undefined? or is that a different can of worms > related to strict-enum? This is a very old comment that predates me. Let's address this as a follow-up. > > > Assuming bootstrap and regression tests, OK Oh, all my patches are tested on x86-64 Linux with no regressions. Pushed. Aldy
diff --git a/gcc/value-range.cc b/gcc/value-range.cc index f5ef4808530..369eeabd7d5 100644 --- a/gcc/value-range.cc +++ b/gcc/value-range.cc @@ -59,6 +59,7 @@ irange::operator= (const irange &src) m_base[x - 1] = src.m_base[src.m_num_ranges * 2 - 1]; m_num_ranges = lim; + m_kind = src.m_kind; return *this; } @@ -106,8 +107,8 @@ void irange::copy_to_legacy (const irange &src) { gcc_checking_assert (legacy_mode_p ()); - // Copy legacy to legacy. - if (src.legacy_mode_p ()) + // Handle legacy to legacy and other things that are easy to copy. + if (src.legacy_mode_p () || src.varying_p () || src.undefined_p ()) { m_num_ranges = src.m_num_ranges; m_base[0] = src.m_base[0]; @@ -116,11 +117,7 @@ irange::copy_to_legacy (const irange &src) return; } // Copy multi-range to legacy. - if (src.undefined_p ()) - set_undefined (); - else if (src.varying_p ()) - set_varying (src.type ()); - else if (src.maybe_anti_range ()) + if (src.maybe_anti_range ()) { int_range<3> r (src); r.invert (); @@ -180,6 +177,9 @@ irange::irange_set (tree min, tree max) m_base[0] = min; m_base[1] = max; m_num_ranges = 1; + m_kind = VR_RANGE; + normalize_kind (); + if (flag_checking) verify_range (); } @@ -247,6 +247,10 @@ irange::irange_set_anti_range (tree min, tree max) m_base[m_num_ranges * 2 + 1] = type_range.tree_upper_bound (0); ++m_num_ranges; } + + m_kind = VR_RANGE; + normalize_kind (); + if (flag_checking) verify_range (); } @@ -353,7 +357,7 @@ irange::set (tree min, tree max, value_range_kind kind) m_base[0] = min; m_base[1] = max; m_num_ranges = 1; - normalize_min_max (); + normalize_kind (); if (flag_checking) verify_range (); } @@ -363,9 +367,22 @@ irange::set (tree min, tree max, value_range_kind kind) void irange::verify_range () { + if (m_kind == VR_UNDEFINED) + { + gcc_assert (m_num_ranges == 0); + return; + } + gcc_assert (m_num_ranges != 0); + + if (m_kind == VR_VARYING) + { + gcc_assert (m_num_ranges == 1); + gcc_assert (irange_varying_p ()); + return; + } if (!legacy_mode_p ()) { - gcc_checking_assert (m_kind == VR_RANGE); + gcc_assert (!irange_varying_p ()); for (unsigned i = 0; i < m_num_ranges; ++i) { tree lb = tree_lower_bound (i); @@ -375,28 +392,11 @@ irange::verify_range () } return; } - - switch (m_kind) + if (m_kind == VR_RANGE || m_kind == VR_ANTI_RANGE) { - case VR_UNDEFINED: - gcc_assert (m_num_ranges == 0); - break; - - case VR_VARYING: gcc_assert (m_num_ranges == 1); - break; - - case VR_ANTI_RANGE: - case VR_RANGE: - { - gcc_assert (m_num_ranges == 1); - int cmp = compare_values (tree_lower_bound (0), tree_upper_bound (0)); - gcc_assert (cmp == 0 || cmp == -1 || cmp == -2); - return; - } - - default: - gcc_unreachable (); + int cmp = compare_values (tree_lower_bound (0), tree_upper_bound (0)); + gcc_assert (cmp == 0 || cmp == -1 || cmp == -2); } } @@ -1667,6 +1667,9 @@ irange::irange_union (const irange &r) m_base[j] = res [j]; m_num_ranges = i / 2; + m_kind = VR_RANGE; + normalize_kind (); + if (flag_checking) verify_range (); } @@ -1758,6 +1761,10 @@ irange::irange_intersect (const irange &r) // At the exit of this loop, it is one of 2 things: // ran out of r1, or r2, but either means we are done. m_num_ranges = bld_pair; + + m_kind = VR_RANGE; + normalize_kind (); + if (flag_checking) verify_range (); } @@ -1890,6 +1897,10 @@ irange::invert () } m_num_ranges = nitems / 2; + // We disallow undefined or varying coming in, so the result can + // only be a VR_RANGE. + gcc_checking_assert (m_kind == VR_RANGE); + if (flag_checking) verify_range (); } diff --git a/gcc/value-range.h b/gcc/value-range.h index bb27e706207..bfba1a3469e 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -111,7 +111,7 @@ protected: void irange_set (tree, tree); void irange_set_anti_range (tree, tree); - void normalize_min_max (); + void normalize_kind (); bool legacy_mode_p () const; bool legacy_equal_p (const irange &) const; @@ -128,6 +128,7 @@ protected: private: void irange_set_1bit_anti_range (tree, tree); + bool irange_varying_p () const; unsigned char m_num_ranges; unsigned char m_max_ranges; @@ -198,16 +199,7 @@ extern bool vrp_operand_equal_p (const_tree, const_tree); inline value_range_kind irange::kind () const { - if (legacy_mode_p ()) - return m_kind; - - if (undefined_p ()) - return VR_UNDEFINED; - - if (varying_p ()) - return VR_VARYING; - - return VR_RANGE; + return m_kind; } // Number of sub-ranges in a range. @@ -271,17 +263,18 @@ irange::max () const } inline bool -irange::varying_p () const +irange::irange_varying_p () const { - if (legacy_mode_p ()) - return m_kind == VR_VARYING; - if (m_num_ranges != 1) return false; tree l = m_base[0]; tree u = m_base[1]; tree t = TREE_TYPE (l); + + if (m_kind == VR_VARYING && t == error_mark_node) + return true; + unsigned prec = TYPE_PRECISION (t); signop sign = TYPE_SIGN (t); if (INTEGRAL_TYPE_P (t)) @@ -291,22 +284,17 @@ irange::varying_p () const return (wi::to_wide (l) == 0 && wi::to_wide (u) == wi::max_value (prec, sign)); return true; +} +inline bool +irange::varying_p () const +{ + return m_kind == VR_VARYING; } inline bool irange::undefined_p () const { - if (!legacy_mode_p ()) - return m_num_ranges == 0; - - if (CHECKING_P && legacy_mode_p ()) - { - if (m_kind == VR_UNDEFINED) - gcc_checking_assert (m_num_ranges == 0); - else - gcc_checking_assert (m_num_ranges != 0); - } return m_kind == VR_UNDEFINED; } @@ -389,10 +377,7 @@ irange::irange (tree *base, unsigned nranges) m_base = base; m_num_ranges = 0; m_max_ranges = nranges; - if (legacy_mode_p ()) - m_kind = VR_UNDEFINED; - else - m_kind = VR_RANGE; + m_kind = VR_UNDEFINED; } // Constructors for int_range<>. @@ -459,18 +444,16 @@ irange::set (tree val) inline void irange::set_undefined () { + m_kind = VR_UNDEFINED; m_num_ranges = 0; - if (legacy_mode_p ()) - m_kind = VR_UNDEFINED; } inline void irange::set_varying (tree type) { - if (legacy_mode_p ()) - m_kind = VR_VARYING; - + m_kind = VR_VARYING; m_num_ranges = 1; + if (INTEGRAL_TYPE_P (type)) { wide_int min = wi::min_value (TYPE_PRECISION (type), TYPE_SIGN (type)); @@ -574,17 +557,14 @@ irange::set_zero (tree type) // Normalize a range to VARYING or UNDEFINED if possible. inline void -irange::normalize_min_max () -{ - gcc_checking_assert (legacy_mode_p ()); - gcc_checking_assert (!undefined_p ()); - unsigned prec = TYPE_PRECISION (type ()); - signop sign = TYPE_SIGN (type ()); - if (wi::eq_p (wi::to_wide (min ()), wi::min_value (prec, sign)) - && wi::eq_p (wi::to_wide (max ()), wi::max_value (prec, sign))) +irange::normalize_kind () +{ + if (m_num_ranges == 0) + m_kind = VR_UNDEFINED; + else if (irange_varying_p ()) { if (m_kind == VR_RANGE) - set_varying (type ()); + m_kind = VR_VARYING; else if (m_kind == VR_ANTI_RANGE) set_undefined (); else