On Tue, Feb 1, 2022 at 4:21 PM Arjun Shankar <ar...@redhat.com> wrote:
>
> > +/* As a special case, X + C < Y + C is the same as X < Y even with wrapping
> > +   overflow if X and Y are signed integers of the same size, and C is an
> > +   unsigned constant with all bits except MSB set to 0 and size >= that of
> > +   X/Y.  */
> > +(for op (lt le ge gt)
> > + (simplify
> > +  (op (plus:c (convert@0 @1) @4) (plus:c (convert@2 @3) @4))
> > +  (if (CONSTANT_CLASS_P (@4)
> > +       && TYPE_UNSIGNED (TREE_TYPE (@4))
> >
> > why include (convert ..) here?  It looks like you could do without,
> > merging the special case with the preceding pattern and let a followup
> > pattern simplify (lt (convert @1) (convert @2)) instead?
>
> Thanks for taking a look at this patch.
>
> It looks like the convert and plus need to be taken into account
> together when applying this simplification.
>
> 1. 0x80000000 is *just* large enough to be interpreted as an unsigned.
>
> 2. So, an expression like...
>
> x + 0x80000000 < y + 0x80000000;
>
> ...where x and y are signed actually gets interpreted as:
>
> (unsigned) x + 0x80000000 < (unsigned) y + 0x80000000
>
> 3. Now, adding 0x80000000 to (unsigned) INT_MIN gives us 0,
> and adding it to (unsigned) INT_MAX gives us UINT_MAX.
>
> 4. So, if x < y is true when they are compared as signed integers, then...
> (unsigned) x + 0x80000000 < (unsigned) y + 0x80000000
> ...will also be true.
>
> 5. i.e. the unsigned comparison must be replaced by a signed
> comparison when we remove the constant, and so the constant and
> convert need to be matched and removed together.

Oh, I see - that's very special then and the pattern in the comment
does not include this conversion.  I think you can simplify the checking
done by requiring types_match (TREE_TYPE (@1), TREE_TYPE (@3))
and by noting that the types of @0, @2 and @4 are the same
(you don't seem to use @2).

I wonder how relevant these kind of patterns are?  Probably clang
catches this simplification while we don't?

Btw, you fail to check for INTEGRAL_TYPE_P, the whole thing
would also match floats as-is, I think the easiest thing would be to
change the match to

+  (op (plus:c (convert@0 @1) INTEGER_CST@4) (plus:c (convert@2 @3)
INTEGER_CST@4))

where you then also can elide the CONSTANT_CLASS_P (@4) check.

Btw, for

  unsigned x, y;
  if (x + 0x80000000 < y + 0x80000000)

it would be valid to transform this into

  if ((int)x < (int)y)

which is a simplification that's worthwhile as well I think?  So we
might not actually
need the (convert ...) but rely on (convert (convert @0)) being
simplfiied?  You'd
then use

 (with { stype = signed_type_for (TREE_TYPE (@1)); }
  (op (convert:stype @1) (convert:stype @3)))

as transform.

Thanks,
Richard.

Reply via email to