https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116024

--- Comment #7 from Artemiy Volkov <artemiy at synopsys dot com> ---
(In reply to Richard Biener from comment #6)
> (In reply to Artemiy Volkov from comment #5)
> > Hi Andrew, thank you for the breakdown.  For i1() (the case applicable to
> > the initial bug report) something like this seems to fix the issue:
> > 
> > diff --git a/gcc/match.pd b/gcc/match.pd
> > index cf359b0ec0f..8ab6d47e278 100644
> > --- a/gcc/match.pd
> > +++ b/gcc/match.pd
> > @@ -8773,2 +8773,10 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
> >  
> > +/* Transform comparisons of the form C1 - X CMP C2 to X - C1 CMP -C2.  */
> > +(for cmp (lt le gt ge eq ne)
> > +     rcmp (gt ge lt le eq ne)
> > +  (simplify
> > +   (cmp (minus INTEGER_CST@0 @1) INTEGER_CST@2)
> > +   (if (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@1)))
> > +     (rcmp (minus @1 @0) (negate @2)))))
> > +
> >  /* Canonicalizations of BIT_FIELD_REFs.  */
> > 
> > Would it make sense for this ticket to be assigned to me so I could refine
> > and post the above patch as well as tackle i2() and i3() (should those be
> > extracted to a separate PR or is it fine to fix all three under this PR)?
> 
> I don't think this is correct for types with undefined behavior on overflow
> because you can't negate INT_MIN.

Fair enough.  How about something like:

diff --git a/gcc/match.pd b/gcc/match.pd
index cf359b0ec0f..897e01c39a3 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -8773,2 +8773,37 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)

+/* Transform comparisons of the form C1 - X CMP C2 to X CMP C1 - C2.  */
+(for cmp (lt le gt ge eq ne)
+     rcmp (gt ge lt le eq ne)
+  (simplify
+   (cmp (minus INTEGER_CST@0 @1) INTEGER_CST@2)
+   (if (!TREE_OVERFLOW (@0) && !TREE_OVERFLOW (@2)
+       && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@1)))
+     (with { tree res = int_const_binop (MINUS_EXPR, @0, @2); }
+      (if (TREE_OVERFLOW (res))
+       (with
+        {
+          fold_overflow_warning (("assuming signed overflow does not occur "
+                                  "when simplifying conditional to constant"),
+                                WARN_STRICT_OVERFLOW_CONDITIONAL);
+        }
+        (switch
+         (if (cmp == NE_EXPR)
+          { constant_boolean_node (true, type); })
+         (if (cmp == EQ_EXPR)
+          { constant_boolean_node (false, type); })
+         {
+           bool less = cmp == LE_EXPR || cmp == LT_EXPR;
+           bool ovf_high = wi::gt_p (wi::to_wide (@0), 0,
+                                     TYPE_SIGN (TREE_TYPE (@0)));
+           constant_boolean_node (less == ovf_high, type);
+         }))
+       (with
+        {
+          fold_overflow_warning (("assuming signed overflow does not occur "
+                                  "when changing C1 - X cmp C2 to "
+                                  "X cmp C1 - C2"),
+                                WARN_STRICT_OVERFLOW_COMPARISON);
+        }
+        (rcmp @1 { res; })))))))
+
 /* Canonicalizations of BIT_FIELD_REFs.  */

This passes a full dejagnu run plus a couple of newly crafted test cases around
INT_MIN and INT_MAX. (I made it mostly by analogy with the "X +- C1 CMP C2”
case directly above it.  I did not understand why that one is split into the
equality and relational parts with stricter pre-conditions for the former (the
old fold-const.c code that came before it didn't have this separation); so for
the new pattern I decided to keep them unified and just require
TYPE_OVERFLOW_UNDEFINED().)

Reply via email to