From: Jiufu Guo <guojiufu@linux.ibm.com>
To: Andrew MacLeod <amacleod@redhat.com>
Cc: Richard Biener <rguenther@suse.de>,
Aldy Hernandez <aldyh@redhat.com>,
gcc-patches@gcc.gnu.org, jeffreyalaw@gmail.com,
richard.sandiford@arm.com, segher@kernel.crashing.org,
dje.gcc@gmail.com, linkw@gcc.gnu.org, bergner@linux.ibm.com
Subject: Re: [PATCH V4] Optimize '(X - N * M) / N' to 'X / N - M' if valid
Date: Mon, 17 Jul 2023 14:27:01 +0800 [thread overview]
Message-ID: <7n5y6j12a2.fsf@ltcden2-lp1.aus.stglabs.ibm.com> (raw)
In-Reply-To: <a5709138-726b-b685-8c2f-e861b6464200@redhat.com> (Andrew MacLeod's message of "Fri, 14 Jul 2023 17:00:29 -0400")
Hi Andrew, Aldy and Richard,
Thanks a lot for all your very helpful comments!
Andrew MacLeod <amacleod@redhat.com> writes:
> On 7/14/23 09:37, Richard Biener wrote:
>> On Fri, 14 Jul 2023, Aldy Hernandez wrote:
>>
>>> I don't know what you're trying to accomplish here, as I haven't been
>>> following the PR, but adding all these helper functions to the ranger header
>>> file seems wrong, especially since there's only one use of them. I see you're
>>> tweaking the irange API, adding helper functions to range-op (which is only
>>> for code dealing with implementing range operators for tree codes), etc etc.
>>>
>>> If you need these helper functions, I suggest you put them closer to their
>>> uses (i.e. wherever the match.pd support machinery goes).
>> Note I suggested the opposite beacuse I thought these kind of helpers
>> are closer to value-range support than to match.pd.
>
>
> probably vr-values.{cc.h} and the simply_using_ranges paradigm would
> be the most sensible place to put these kinds of auxiliary routines?
Thanks! Richard also mentioned this as an example of using VR APIs.
I did not use vr-values.h/cc just because it seems vr-values are not
used/included in match.pd directly yet.
>
>
>>
>> But I take away from your answer that there's nothing close in the
>> value-range machinery that answers the question whether A op B may
>> overflow?
>
> we dont track it in ranges themselves. During calculation of a range
> we obviously know, but propagating that generally when we rarely care
> doesn't seem worthwhile. The very first generation of irange 6 years
> ago had an overflow_p() flag, but it was removed as not being worth
> keeping. easier to simply ask the question when it matters
Right, agree!
>
> As the routines show, it pretty easy to figure out when the need arises so I think that should suffice. At least for now,
>
> Should we decide we would like it in general, it wouldnt be hard to
> add to irange. wi_fold() cuurently returns null, it could easily
> return a bool indicating if an overflow happened, and wi_fold_in_parts
> and fold_range would simply OR the results all together of the
> compoent wi_fold() calls. It would require updating/audfiting a
> number of range-op entries and adding an overflowed_p() query to
> irange.
I also tried to add a 'm_ovf' field to irange and record the
overflow info during 'wi_fold' in range-op(e.g. plus/minus/mult).
But, as you said, overflow info is not widely used (it seems that
match.pd covers most of the cases which are using overflow info).
It may not be worth adding a field to every instance of VR, and
additional cost may not be profitable to maintain it during VR
assign/union_/intersect.
I've attached a patch for this idea, just for reference.
Currently, what I'm trying to do is find a better place to add
APIs to check the overflow info for match.pd.
vr-range.h/cc would be one choice :)
I noticed Aldy mentioned 'may_overflow_p' in a comment of PR100499,
where this API was trying to add? This may be another choice.
Thanks a gain for your great comments!
BR,
Jeff (Jiufu Guo)
>
> Andrew
gcc/ChangeLog:
* range-op.cc (value_range_with_overflow): Call set_overflow.
(operator_mult::wi_fold): Call set_overflow.
* value-query.h (get_range): New function.
* value-range-storage.cc (irange_storage::set_irange): Set
ovf info.
(irange_storage::get_irange): Call set_overflow.
* value-range-storage.h (irange_storage): Add m_ovf field.
* value-range.cc (irange::nonnegative_p): New function.
(irange::nonpositive_p): New function.
(irange::operator=): Maintain ovf info.
(irange::union_): Maintain ovf info.
(irange::intersect): Maintain ovf info.
* value-range.h (irange::irange): Initialize m_ovf.
---
gcc/range-op.cc | 17 +++++++++++++----
gcc/value-query.h | 10 ++++++++++
gcc/value-range-storage.cc | 2 ++
gcc/value-range-storage.h | 1 +
gcc/value-range.cc | 29 ++++++++++++++++++++++++++---
gcc/value-range.h | 6 ++++++
6 files changed, 58 insertions(+), 7 deletions(-)
diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index 3ab2c665901..02971e8a16a 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -433,6 +433,10 @@ value_range_with_overflow (irange &r, tree type,
const unsigned int prec = TYPE_PRECISION (type);
const bool overflow_wraps = TYPE_OVERFLOW_WRAPS (type);
+ bool ovf = !TYPE_OVERFLOW_UNDEFINED (type)
+ && (min_ovf != wi::OVF_NONE || max_ovf != wi::OVF_NONE);
+ r.set_overflow (ovf ? wi::OVF_UNKNOWN : wi::OVF_NONE);
+
// For one bit precision if max != min, then the range covers all
// values.
if (prec == 1 && wi::ne_p (wmax, wmin))
@@ -2050,10 +2054,15 @@ operator_mult::wi_fold (irange &r, tree type,
// Sort the 4 products so that min is in prod0 and max is in
// prod3.
- widest2_int prod0 = min0 * min1;
- widest2_int prod1 = min0 * max1;
- widest2_int prod2 = max0 * min1;
- widest2_int prod3 = max0 * max1;
+ wi::overflow_type ovf1, ovf2, ovf3, ovf4;
+ widest2_int prod0 = wi::mul (min0, min1, sign, &ovf1);
+ widest2_int prod1 = wi::mul (min0, max1, sign, &ovf2);
+ widest2_int prod2 = wi::mul (max0, min1, sign, &ovf3);
+ widest2_int prod3 = wi::mul (max0, max1, sign, &ovf4);
+ bool ovf = !TYPE_OVERFLOW_UNDEFINED (type)
+ && (ovf1 != wi::OVF_NONE || ovf2 != wi::OVF_NONE
+ || ovf3 != wi::OVF_NONE || ovf3 != wi::OVF_NONE);
+ r.set_overflow (ovf ? wi::OVF_UNKNOWN : wi::OVF_NONE);
// min0min1 > max0max1
if (prod0 > prod3)
diff --git a/gcc/value-query.h b/gcc/value-query.h
index d10c3eac1e2..cf488c7ea9b 100644
--- a/gcc/value-query.h
+++ b/gcc/value-query.h
@@ -137,6 +137,16 @@ get_range_query (const struct function *fun)
return (fun && fun->x_range_query) ? fun->x_range_query : &global_ranges;
}
+/* Return true if there is range for "X" expression at "S" statement,
+ and the range is not varying and not undefined. */
+
+inline bool
+get_range (vrange &r, tree x, gimple *s = NULL)
+{
+ return get_range_query (cfun)->range_of_expr (r, x, s) && !r.varying_p ()
+ && !r.undefined_p ();
+}
+
// Query the global range of NAME in function F. Default to cfun.
extern void gimple_range_global (vrange &v, tree name,
struct function *f = cfun);
diff --git a/gcc/value-range-storage.cc b/gcc/value-range-storage.cc
index 2f82739680c..93bbae3c465 100644
--- a/gcc/value-range-storage.cc
+++ b/gcc/value-range-storage.cc
@@ -277,6 +277,7 @@ void
irange_storage::set_irange (const irange &r)
{
gcc_checking_assert (fits_p (r));
+ m_ovf = r.m_ovf;
if (r.undefined_p ())
{
@@ -325,6 +326,7 @@ read_wide_int (wide_int &w,
void
irange_storage::get_irange (irange &r, tree type) const
{
+ r.set_overflow (m_ovf);
if (m_kind == VR_UNDEFINED)
{
r.set_undefined ();
diff --git a/gcc/value-range-storage.h b/gcc/value-range-storage.h
index 99fb815cdc2..62a17d73e9f 100644
--- a/gcc/value-range-storage.h
+++ b/gcc/value-range-storage.h
@@ -90,6 +90,7 @@ private:
unsigned char m_num_ranges;
enum value_range_kind m_kind : 3;
+ wi::overflow_type m_ovf;
// The length of this is m_num_ranges * 2 + 1 to accomodate the nonzero bits.
HOST_WIDE_INT m_val[1];
diff --git a/gcc/value-range.cc b/gcc/value-range.cc
index 707b1f15fd4..58aed715658 100644
--- a/gcc/value-range.cc
+++ b/gcc/value-range.cc
@@ -287,6 +287,18 @@ add_vrange (const vrange &v, inchash::hash &hstate,
} //namespace inchash
+bool
+irange::nonnegative_p () const
+{
+ return wi::ge_p (lower_bound (), 0, TYPE_SIGN (type ()));
+}
+
+bool
+irange::nonpositive_p () const
+{
+ return wi::le_p (upper_bound (), 0, TYPE_SIGN (type ()));
+}
+
bool
irange::supports_type_p (const_tree type) const
{
@@ -916,6 +928,7 @@ irange::operator= (const irange &src)
m_type = src.m_type;
m_kind = src.m_kind;
m_nonzero_mask = src.m_nonzero_mask;
+ m_ovf = src.m_ovf;
if (m_max_ranges == 1)
normalize_kind ();
if (flag_checking)
@@ -1244,7 +1257,15 @@ irange::union_ (const vrange &v)
}
if (varying_p ())
- return false;
+ {
+ if (m_ovf == r.m_ovf || m_ovf == wi::OVF_UNKNOWN)
+ return false;
+ m_ovf = wi::OVF_UNKNOWN;
+ return true;
+ }
+
+ if (m_ovf != r.m_ovf)
+ m_ovf = wi::OVF_UNKNOWN;
if (r.varying_p ())
{
@@ -1417,14 +1438,16 @@ irange::intersect (const vrange &v)
set_undefined ();
return true;
}
- if (r.varying_p ())
- return false;
+
if (varying_p ())
{
operator= (r);
return true;
}
+ if (r.varying_p ())
+ return false;
+
if (r.num_pairs () == 1)
{
bool res = intersect (r.lower_bound (), r.upper_bound ());
diff --git a/gcc/value-range.h b/gcc/value-range.h
index 2b4ebabe7c8..ae35f6fbcf7 100644
--- a/gcc/value-range.h
+++ b/gcc/value-range.h
@@ -145,6 +145,10 @@ public:
virtual bool singleton_p (tree *result = NULL) const override;
bool singleton_p (wide_int &) const;
bool contains_p (const wide_int &) const;
+ bool nonnegative_p () const;
+ bool nonpositive_p () const;
+ bool no_overflow () const { return m_ovf == wi::OVF_NONE; }
+ void set_overflow (wi::overflow_type ovf) { m_ovf = ovf;}
// In-place operators.
virtual bool union_ (const vrange &) override;
@@ -197,6 +201,7 @@ private:
unsigned char m_max_ranges;
tree m_type;
wide_int m_nonzero_mask;
+ wi::overflow_type m_ovf;
protected:
wide_int *m_base;
};
@@ -839,6 +844,7 @@ irange::irange (wide_int *base, unsigned nranges, bool resizable)
m_max_ranges (nranges)
{
m_base = base;
+ m_ovf = wi::OVF_UNKNOWN;
set_undefined ();
}
--
2.39.3
next prev parent reply other threads:[~2023-07-17 6:27 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-07-11 9:04 Jiufu Guo
2023-07-14 11:27 ` Aldy Hernandez
2023-07-14 13:37 ` Richard Biener
2023-07-14 14:12 ` Aldy Hernandez
2023-07-14 21:00 ` Andrew MacLeod
2023-07-17 6:27 ` Jiufu Guo [this message]
2023-07-17 9:24 ` Richard Biener
2023-07-17 13:45 ` Jiufu Guo
2023-07-17 17:24 ` Andrew MacLeod
2023-07-18 9:44 ` Jiufu Guo
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=7n5y6j12a2.fsf@ltcden2-lp1.aus.stglabs.ibm.com \
--to=guojiufu@linux.ibm.com \
--cc=aldyh@redhat.com \
--cc=amacleod@redhat.com \
--cc=bergner@linux.ibm.com \
--cc=dje.gcc@gmail.com \
--cc=gcc-patches@gcc.gnu.org \
--cc=jeffreyalaw@gmail.com \
--cc=linkw@gcc.gnu.org \
--cc=rguenther@suse.de \
--cc=richard.sandiford@arm.com \
--cc=segher@kernel.crashing.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).