https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69097
Jakub Jelinek <jakub at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |jakub at gcc dot gnu.org --- Comment #2 from Jakub Jelinek <jakub at gcc dot gnu.org> --- Seems like a bogus fold-const.c transformation has been moved into match.pd and so now it hits even more often. Another testcase: __attribute__((noinline, noclone)) int f1 (int x, int y) { return x % y; } __attribute__((noinline, noclone)) int f2 (int x, int y) { return x % -y; } __attribute__((noinline, noclone)) int f3 (int x, int y) { int z = -y; return x % z; } int main () { if (f1 (-__INT_MAX__ - 1, 1) != 0 || f2 (-__INT_MAX__ - 1, -1) != 0 || f3 (-__INT_MAX__ - 1, -1) != 0) __builtin_abort (); return 0; } The bad optimization has been introduced with https://gcc.gnu.org/ml/gcc-patches/2004-07/msg00358.html in 2004. For constant last operand we already do the right thing: /* X % -C is the same as X % C. */ (simplify (trunc_mod @0 INTEGER_CST@1) (if (TYPE_SIGN (type) == SIGNED && !TREE_OVERFLOW (@1) && wi::neg_p (@1) && !TYPE_OVERFLOW_TRAPS (type) /* Avoid this transformation if C is INT_MIN, i.e. C == -C. */ && !sign_bit_p (@1, @1)) (trunc_mod @0 (negate @1)))) because we only do the transformation for negative constants. But for variable last operand: /* X % -Y is the same as X % Y. */ (simplify (trunc_mod @0 (convert? (negate @1))) (if (!TYPE_UNSIGNED (type) && !TYPE_OVERFLOW_TRAPS (type) && tree_nop_conversion_p (type, TREE_TYPE (@1))) (trunc_mod @0 (convert @1)))) we can turn a valid INT_MIN % -(-1) which yields 0 into invalid INT_MIN % -1 which raises division by zero. So, if we really want to perform this X % -Y transformation to X % Y, we can do that only if VRP info tells us that the first operand can't be the signed minimum, or the operand of the negation can't be -1.