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