I am testing the following patch which fixes PR69771 where the code doesn't match the comment before it. We get to expand a QImode << QImode shift but the shift amount was of type int and thus it was expanded as SImode constant. Then
/* In case the insn wants input operands in modes different from those of the actual operands, convert the operands. It would seem that we don't need to convert CONST_INTs, but we do, so that they're properly zero-extended, sign-extended or truncated for their mode. */ has to apply as we need to re-extend the VOIDmode CONST_INT for QImode. But then mode1 is computed as 'mode' (QImode) which happens to match what is expected even though the constant isn't valid. The fix is IMHO to always call convert_modes for VOIDmode ops (if the target doesn't expect VOIDmode itself). Bootstrap and regtest running on x86_64-unknown-linux-gnu, ok for trunk? Thanks, Richard. 2016-02-12 Richard Biener <rguent...@suse.de> PR rtl-optimization/69771 * optabs.c (expand_binop_directly): Properly zero-/sign-extend VOIDmode operands. * gcc.dg/torture/pr69771.c: New testcase. Index: gcc/optabs.c =================================================================== --- gcc/optabs.c (revision 233369) +++ gcc/optabs.c (working copy) @@ -1013,15 +1013,15 @@ expand_binop_directly (machine_mode mode that they're properly zero-extended, sign-extended or truncated for their mode. */ - mode0 = GET_MODE (xop0) != VOIDmode ? GET_MODE (xop0) : mode; - if (xmode0 != VOIDmode && xmode0 != mode0) + mode0 = GET_MODE (xop0); + if (xmode0 != mode0) { xop0 = convert_modes (xmode0, mode0, xop0, unsignedp); mode0 = xmode0; } - mode1 = GET_MODE (xop1) != VOIDmode ? GET_MODE (xop1) : mode; - if (xmode1 != VOIDmode && xmode1 != mode1) + mode1 = GET_MODE (xop1); + if (xmode1 != mode1) { xop1 = convert_modes (xmode1, mode1, xop1, unsignedp); mode1 = xmode1; Index: gcc/testsuite/gcc.dg/torture/pr69771.c =================================================================== --- gcc/testsuite/gcc.dg/torture/pr69771.c (revision 0) +++ gcc/testsuite/gcc.dg/torture/pr69771.c (working copy) @@ -0,0 +1,15 @@ +/* { dg-do compile } */ + +unsigned char a = 5, c; +unsigned short b = 0; +unsigned d = 0x76543210; +void __attribute__((noinline)) +fn1() { c = d >> ~(a || ~b); } /* { dg-warning "shift count is negative" } */ + +int main() +{ + fn1(); + if (c != 1) + __builtin_abort (); + return 0; +}