From: Richard Biener <rguenther@suse.de>
To: Richard Sandiford <richard.sandiford@arm.com>
Cc: Richard Biener via Gcc-patches <gcc-patches@gcc.gnu.org>,
bin.cheng@linux.alibaba.com
Subject: Re: [PATCH] tree-optimization/100499 - niter analysis and multiple_of_p
Date: Fri, 4 Feb 2022 12:01:24 +0100 (CET) [thread overview]
Message-ID: <11q58414-qs1s-55pq-rp8-sqn9p90p67r@fhfr.qr> (raw)
In-Reply-To: <mptmtj6aogp.fsf@arm.com>
On Fri, 4 Feb 2022, Richard Sandiford wrote:
> Richard Biener <rguenther@suse.de> writes:
> > On Fri, 4 Feb 2022, Richard Sandiford wrote:
> >> Richard Biener via Gcc-patches <gcc-patches@gcc.gnu.org> writes:
> >> > niter analysis uses multiple_of_p which currently assumes
> >> > operations like MULT_EXPR do not wrap. We've got to rely on this
> >> > for optimizing size expressions like those in DECL_SIZE and those
> >> > generally use unsigned arithmetic with no indication that they
> >> > are not expected to wrap. To preserve that the following adds
> >> > a parameter to multiple_of_p, defaulted to true, indicating that
> >> > the TOP expression is not expected to wrap for outer computations
> >> > in TYPE. This mostly follows a patch proposed by Bin last year
> >> > with the conversion behavior added.
> >> >
> >> > Applying to all users the new effect is that upon type conversions
> >> > in the TOP expression the behavior will switch to honor
> >> > TYPE_OVERFLOW_UNDEFINED for the converted sub-expressions.
> >> >
> >> > The patch also changes the occurance in niter analysis that we
> >> > know is problematic and we have testcases for to pass false
> >> > to multiple_of_p. The patch also contains a change to the
> >> > PR72817 fix from Bin to avoid regressing gcc.dg/tree-ssa/loop-42.c.
> >> >
> >> > The intent for stage1 is to introduce a size_multiple_of_p and
> >> > internalize the added parameter so all multiple_of_p users will
> >> > honor TYPE_OVERFLOW_UNDEFINED and users dealing with size expressions
> >> > need to be switched to size_multiple_of_p.
> >> >
> >> > Bootstrapped and tested on x86_64-unknown-linux-gnu with all languages
> >> > and {,-m32} testing.
> >> >
> >> > The patch applies ontop of the three earlier posted ones that touch
> >> > multiple_of_p but have not yet been reviewed/pushed.
> >> >
> >> > OK?
> >> >
> >> > Thanks,
> >> > Richard.
> >> >
> >> > 2022-01-26 Richard Biener <rguenther@suse.de>
> >> >
> >> > PR tree-optimization/100499
> >> > * fold-const.h (multiple_of_p): Add nowrap parameter, defaulted
> >> > to true.
> >> > * fold-const.cc (multiple_of_p): Likewise. Honor it for
> >> > MULT_EXPR, PLUS_EXPR and MINUS_EXPR and pass it along,
> >> > switching to false for conversions.
> >> > * tree-ssa-loop-niter.cc (number_of_iterations_ne): Do not
> >> > claim the outermost expression does not wrap when calling
> >> > multiple_of_p. Refactor the check done to check the
> >> > original IV, avoiding a bias that might wrap.
> >> >
> >> > * gcc.dg/torture/pr100499-1.c: New testcase.
> >> > * gcc.dg/torture/pr100499-2.c: Likewise.
> >> > * gcc.dg/torture/pr100499-3.c: Likewise.
> >> >
> >> > Co-authored-by: Bin Cheng <bin.cheng@linux.alibaba.com>
> >> > ---
> >> > gcc/fold-const.cc | 81 +++++++++++++++--------
> >> > gcc/fold-const.h | 2 +-
> >> > gcc/testsuite/gcc.dg/torture/pr100499-1.c | 27 ++++++++
> >> > gcc/testsuite/gcc.dg/torture/pr100499-2.c | 16 +++++
> >> > gcc/testsuite/gcc.dg/torture/pr100499-3.c | 14 ++++
> >> > gcc/tree-ssa-loop-niter.cc | 52 ++++++---------
> >> > 6 files changed, 131 insertions(+), 61 deletions(-)
> >> > create mode 100644 gcc/testsuite/gcc.dg/torture/pr100499-1.c
> >> > create mode 100644 gcc/testsuite/gcc.dg/torture/pr100499-2.c
> >> > create mode 100644 gcc/testsuite/gcc.dg/torture/pr100499-3.c
> >> >
> >> > diff --git a/gcc/fold-const.cc b/gcc/fold-const.cc
> >> > index a0a4913c45e..7c204fb6265 100644
> >> > --- a/gcc/fold-const.cc
> >> > +++ b/gcc/fold-const.cc
> >> > @@ -14062,10 +14062,16 @@ fold_binary_initializer_loc (location_t loc, tree_code code, tree type,
> >> > SAVE_EXPR (I) * SAVE_EXPR (J)
> >> >
> >> > (where the same SAVE_EXPR (J) is used in the original and the
> >> > - transformed version). */
> >> > + transformed version).
> >> > +
> >> > + NOWRAP specifies whether all outer operations in TYPE should
> >> > + be considered not wrapping. Any type conversion within TOP acts
> >> > + as a barrier and we will fall back to NOWRAP being false.
> >> > + NOWRAP is mostly used to treat expressions in TYPE_SIZE and friends
> >> > + as not wrapping even though they are generally using unsigned arithmetic. */
> >> >
> >> > int
> >> > -multiple_of_p (tree type, const_tree top, const_tree bottom)
> >> > +multiple_of_p (tree type, const_tree top, const_tree bottom, bool nowrap)
> >> > {
> >> > gimple *stmt;
> >> > tree op1, op2;
> >> > @@ -14083,10 +14089,17 @@ multiple_of_p (tree type, const_tree top, const_tree bottom)
> >> > a multiple of BOTTOM then TOP is a multiple of BOTTOM. */
> >> > if (!integer_pow2p (bottom))
> >> > return 0;
> >> > - return (multiple_of_p (type, TREE_OPERAND (top, 1), bottom)
> >> > - || multiple_of_p (type, TREE_OPERAND (top, 0), bottom));
> >> > + return (multiple_of_p (type, TREE_OPERAND (top, 1), bottom, nowrap)
> >> > + || multiple_of_p (type, TREE_OPERAND (top, 0), bottom, nowrap));
> >> >
> >> > case MULT_EXPR:
> >> > + /* If the multiplication can wrap we cannot recurse further unless
> >> > + the second operand is a power of two which is where wrapping
> >> > + does not matter. */
> >> > + if (!nowrap
> >> > + && !TYPE_OVERFLOW_UNDEFINED (type)
> >> > + && !integer_pow2p (TREE_OPERAND (top, 1)))
> >> > + return 0;
> >>
> >> I think I'm missing something, but isn't the key thing whether bottom
> >> is a power of 2? E.g. as it stands it looks like we'd still say that a
> >> wrapping x * 2 is a multiple of 3 based purely on x being a multiple of 3,
> >> thanks to…
> >
> > I had to think about this as well but the logic is that (as you noted),
> > we below test ...
> >
> >> > if (TREE_CODE (bottom) == INTEGER_CST)
> >> > {
> >> > op1 = TREE_OPERAND (top, 0);
> >> > @@ -14095,24 +14108,24 @@ multiple_of_p (tree type, const_tree top, const_tree bottom)
> >> > std::swap (op1, op2);
> >> > if (TREE_CODE (op2) == INTEGER_CST)
> >> > {
> >> > - if (multiple_of_p (type, op2, bottom))
> >> > + if (multiple_of_p (type, op2, bottom, nowrap))
> >> > return 1;
> >> > /* Handle multiple_of_p ((x * 2 + 2) * 4, 8). */
> >> > - if (multiple_of_p (type, bottom, op2))
> >> > + if (multiple_of_p (type, bottom, op2, nowrap))
> >> > {
> >> > widest_int w = wi::sdiv_trunc (wi::to_widest (bottom),
> >> > wi::to_widest (op2));
> >> > if (wi::fits_to_tree_p (w, TREE_TYPE (bottom)))
> >> > {
> >> > op2 = wide_int_to_tree (TREE_TYPE (bottom), w);
> >> > - return multiple_of_p (type, op1, op2);
> >> > + return multiple_of_p (type, op1, op2, nowrap);
> >> > }
> >> > }
> >> > - return multiple_of_p (type, op1, bottom);
> >> > + return multiple_of_p (type, op1, bottom, nowrap);
> >> > }
> >> > }
> >> > - return (multiple_of_p (type, TREE_OPERAND (top, 1), bottom)
> >> > - || multiple_of_p (type, TREE_OPERAND (top, 0), bottom));
> >> > + return (multiple_of_p (type, TREE_OPERAND (top, 1), bottom, nowrap)
> >> > + || multiple_of_p (type, TREE_OPERAND (top, 0), bottom, nowrap));
> >>
> >> …the second arm of the || here.
> >
> > .. oh, we use ||, I thought about this again for the plus case
> > and there we use && which means we'll have bottom a power of two.
> >
> > I think back last year when we discussed this Bin said having
> > bottom a power of two is unnecessarily restrictive.
> >
> >> On the other hand, a wrapping x * 6 is a multiple of 2 even though 6
> >> isn't a power of 2.
> >
> > Yes, for bottom being a power of two the logic would definitely apply.
> >
> > So, changing it to
> >
> > if (!nowrap
> > && !TYPE_OVERFLOW_UNDEFINED (type)
> > && !integer_pow2p (bottom))
> > return 0;
> >
> > would work.
> >
> > I suppose for consistency we should change the condition on the
> > plus/minus case in the same way.
>
> Yeah, agreed.
>
> Like you were discussing in the PR trail, it would be great if ranger
> could help to cut down the false negatives here…
Yes. Note that the patch leaves nowrap = true on all but one caller
so we have something to backport to fix the case we have a testcase for.
For GCC 13 I plan to drop the defaulting as indicated and then we
can also look to either just honor global ranges or do even more
fancy things. I intentionally tried to come up with the most
simplistic and obviously correct patch at this point.
I'm re-testing currently and will post the updated patch.
Richard.
prev parent reply other threads:[~2022-02-04 11:01 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-01-26 13:04 Richard Biener
2022-02-04 10:29 ` Richard Sandiford
2022-02-04 10:42 ` Richard Biener
2022-02-04 10:57 ` Richard Sandiford
2022-02-04 11:01 ` Richard Biener [this message]
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=11q58414-qs1s-55pq-rp8-sqn9p90p67r@fhfr.qr \
--to=rguenther@suse.de \
--cc=bin.cheng@linux.alibaba.com \
--cc=gcc-patches@gcc.gnu.org \
--cc=richard.sandiford@arm.com \
/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).