https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70222
--- Comment #5 from Jakub Jelinek <jakub at gcc dot gnu.org> --- So, the bug is apparently in simplify_shift_const_1 (code=LSHIFTRT, result_mode=SImode, varop=0x7ffff184de70, orig_count=31) where varop is: (subreg:SI (lshiftrt:DI (const_int -1 [0xffffffffffffffff]) (subreg:QI (reg:SI 100) 0)) 0) We optimize the inner shift (mode == DImode) into (lshiftrt:DI (const_int 8589934591 [0x1ffffffff]) (subreg:QI (reg:SI 100) 0)) 0) which is fine (assuming we do the final masking), and turn shift count into 0. shift_mode is still SImode, because nonzero_bits doesn't say the upper bits are 0, and we don't have OUTER_OP. For this to really work, we need to mask off the bits though. We have: /* If we were doing an LSHIFTRT in a wider mode than it was originally, turn off all the bits that the shift would have turned off. */ if (orig_code == LSHIFTRT && result_mode != shift_mode) x = simplify_and_const_int (NULL_RTX, shift_mode, x, GET_MODE_MASK (result_mode) >> orig_count); that does this, unfortunately it doesn't trigger here, because shift_mode == result_mode == SImode. So, one possibility is to do if (orig_code == LSHIFTRT && (result_mode != shift_mode || (result_mode != mode && count == 0))) (and maybe "&& orig_count != 0" too?), to say that we need to mask even if the shift in shift_mode actually isn't performed at all (or shall it be orig_count != count ?). Or we'd need to force outer_op in this case somewhere, but not sure what all cases would need to do that.