public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
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


  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).