Hi! r17-126 has changed the simplification in a way where it can now introduce signed integer overflow into a program which didn't have it before, e.g. x != (INT_MAX - 3) ? x + 5 : (INT_MIN + 1) when x is int doesn't invoke signed integer overflow for x equal to INT_MAX - 3 (it does for various other values and for many doesn't), while the simplified x + 5 invokes it even for that value.
The following patch fixes it by checking for overflow on the CST1 + CST2 addition, if TYPE_OVERFLOW_WRAPS or if CST1 + CST2 doesn't overflow, it does what it previously did, otherwise rewrites x + CST2 into unsigned. Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2026-10-07 Jakub Jelinek <[email protected]> PR tree-optimization/126459 * match.pd (x != CST1 ? x + CST2 : CST3 -> x + CST2): If CST1 + CST2 overflows and type overflow doesn't wrap, simplify into corresponding unsigned addition. * gcc.dg/torture/pr126459.c: New test. --- a/gcc/match.pd 2026-10-03 21:28:13.092320517 +0200 +++ b/gcc/match.pd 2026-10-06 21:51:21.966900769 +0200 @@ -5369,9 +5369,16 @@ (define_operator_list SYNC_FETCH_AND_AND tree cst1 = uniform_integer_cst_p (@1); tree cst2 = uniform_integer_cst_p (@3); tree cst3 = uniform_integer_cst_p (@4); - } - (if (wi::to_wide (cst1) + wi::to_wide (cst2) == wi::to_wide (cst3)) - @2)))) + wi::overflow_type ovf; + } + (if (wi::add (wi::to_wide (cst1), wi::to_wide (cst2), + TYPE_SIGN (TREE_TYPE (cst1)), &ovf) == wi::to_wide (cst3)) + (if (!ovf || TYPE_OVERFLOW_WRAPS (TREE_TYPE (cst1))) + @2 + (with { + tree utype = unsigned_type_for (type); + } + (convert (plus (convert:utype @0) (convert:utype @3))))))))) /* Simplifications of shift and rotates. */ --- a/gcc/testsuite/gcc.dg/torture/pr126459.c 2026-10-06 22:05:01.595899608 +0200 +++ b/gcc/testsuite/gcc.dg/torture/pr126459.c 2026-10-06 22:04:43.130147484 +0200 @@ -0,0 +1,34 @@ +/* PR tree-optimization/126459 */ +/* { dg-do run } */ + +#define INT_MAX __INT_MAX__ +#define INT_MIN (-(INT_MAX) - 1) + +__attribute__((noipa)) int +foo (int x) +{ + return (x != INT_MAX ? x + 1 : INT_MIN) > x; +} + +__attribute__((noipa)) int +bar (int x) +{ + return (x != INT_MIN ? x - 1 : INT_MAX) < x; +} + +__attribute__((noipa)) int +baz (int x) +{ + return (x != INT_MIN ? x + INT_MIN : 0) < 0; +} + +int +main () +{ + if (foo (INT_MAX) != 0 || foo (1) != 1) + __builtin_abort (); + if (bar (INT_MIN) != 0 || bar (2) != 1) + __builtin_abort (); + if (baz (INT_MIN) != 0 || baz (3) != 1) + __builtin_abort (); +} Jakub
