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.

Reply via email to