Hi! As the testcase shows, for 32-bit word size we can end up with op1 up to 0xffffffff (0x100000000 % 0xffffffff == 1 and so we use bit == 32 for that), but the CONST_INT we got from caller is for DImode in that case and not valid for SImode operations.
The following patch canonicalizes the two spots where the constant needs canonicalization. Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2020-12-11 Jakub Jelinek <ja...@redhat.com> PR rtl-optimization/98229 * optabs.c (expand_doubleword_mod): Canonicalize op1 and 1 - INTVAL (op1) as word_mode constants when used in word_mode arithmetics. * gcc.c-torture/compile/pr98229.c: New test. --- gcc/optabs.c.jj 2020-12-02 11:40:47.574338088 +0100 +++ gcc/optabs.c 2020-12-10 19:00:46.151434474 +0100 @@ -1081,7 +1081,8 @@ expand_doubleword_mod (machine_mode mode return NULL_RTX; } } - rtx remainder = expand_divmod (1, TRUNC_MOD_EXPR, word_mode, sum, op1, + rtx op1w = GEN_INT (trunc_int_for_mode (INTVAL (op1), word_mode)); + rtx remainder = expand_divmod (1, TRUNC_MOD_EXPR, word_mode, sum, op1w, NULL_RTX, 1, OPTAB_DIRECT); if (remainder == NULL_RTX) return NULL_RTX; @@ -1098,8 +1099,9 @@ expand_doubleword_mod (machine_mode mode if (mask == NULL_RTX) return NULL_RTX; } - mask = expand_simple_binop (word_mode, AND, mask, - GEN_INT (1 - INTVAL (op1)), + rtx oneminusop1 + = GEN_INT (trunc_int_for_mode (1 - INTVAL (op1), word_mode)); + mask = expand_simple_binop (word_mode, AND, mask, oneminusop1, NULL_RTX, 1, OPTAB_DIRECT); if (mask == NULL_RTX) return NULL_RTX; --- gcc/testsuite/gcc.c-torture/compile/pr98229.c.jj 2020-12-10 19:08:25.502328354 +0100 +++ gcc/testsuite/gcc.c-torture/compile/pr98229.c 2020-12-10 19:08:10.062499943 +0100 @@ -0,0 +1,7 @@ +/* PR rtl-optimization/98229 */ + +unsigned long long +foo (unsigned long long x) +{ + return x % ~0U; +} Jakub