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