simplify_shift_const_1 has code to convert: (ashift (trunc (plus X C1)) C2)
into: (plus (ashift (trunc X) C2) C1<<C2) The bug in the testcase was that it was calculating C1<<C2 in the mode of the result rather than in the mode of X, but it wasn't truncating C1 to that mode first. Generating temporary rtxes for this kind of thing is less than ideal, but we're already doing that for the C2 argument and result, even though we only want a HOST_WIDE_INT in the end. Cleaning things up so that operations can be done directly on wide_ints is future work. E.g. using wi::lshift directly here would avoid the checks for things like SHIFT_COUNT_TRUNCATED. Tested on x86_64-linux-gnu. OK to install? Thanks, Richard gcc/ PR rtl-optimization/61222 * combine.c (simplify_shift_const_1): Fix modes used when handling PLUS. gcc/testsuite/ PR rtl-optimization/61222 * gcc.c-torture/compile/pr61222-1.c: New test. * gcc.c-torture/compile/pr61222-2.c: Likewise. Index: gcc/combine.c =================================================================== --- gcc/combine.c 2014-05-21 12:05:45.273722308 +0100 +++ gcc/combine.c 2014-05-22 10:34:54.852807517 +0100 @@ -10349,9 +10349,10 @@ simplify_shift_const_1 (enum rtx_code co /* (ashift (plus foo C) N) is (plus (ashift foo N) C'). */ if (code == ASHIFT && CONST_INT_P (XEXP (varop, 1)) - && (new_rtx = simplify_const_binary_operation (ASHIFT, result_mode, - XEXP (varop, 1), - GEN_INT (count))) != 0 + && (new_rtx = simplify_const_binary_operation + (ASHIFT, result_mode, + gen_int_mode (INTVAL (XEXP (varop, 1)), result_mode), + GEN_INT (count))) != 0 && CONST_INT_P (new_rtx) && merge_outer_ops (&outer_op, &outer_const, PLUS, INTVAL (new_rtx), result_mode, &complement_p)) @@ -10368,9 +10369,10 @@ simplify_shift_const_1 (enum rtx_code co if (code == LSHIFTRT && CONST_INT_P (XEXP (varop, 1)) && mode_signbit_p (result_mode, XEXP (varop, 1)) - && (new_rtx = simplify_const_binary_operation (code, result_mode, - XEXP (varop, 1), - GEN_INT (count))) != 0 + && (new_rtx = simplify_const_binary_operation + (code, result_mode, + gen_int_mode (INTVAL (XEXP (varop, 1)), result_mode), + GEN_INT (count))) != 0 && CONST_INT_P (new_rtx) && merge_outer_ops (&outer_op, &outer_const, XOR, INTVAL (new_rtx), result_mode, &complement_p)) Index: gcc/testsuite/gcc.c-torture/compile/pr61222-1.c =================================================================== --- /dev/null 2014-05-18 17:42:44.871287828 +0100 +++ gcc/testsuite/gcc.c-torture/compile/pr61222-1.c 2014-05-22 10:33:39.458121563 +0100 @@ -0,0 +1,23 @@ +int a, b, d, e; +char c; + +void +foo () +{ + for (; a; a++) + { + d = ((b == 0) ^ (129 + a)); + c = d * 9; + e = c < 1; + if (e) + for (;;) + ; + } +} + +int +main () +{ + foo (); + return 0; +} Index: gcc/testsuite/gcc.c-torture/compile/pr61222-2.c =================================================================== --- /dev/null 2014-05-18 17:42:44.871287828 +0100 +++ gcc/testsuite/gcc.c-torture/compile/pr61222-2.c 2014-05-22 10:33:39.458121563 +0100 @@ -0,0 +1,7 @@ +int a, b, d; +int main (void) +{ + int c = a && 1; + d = 1 << (((c | (b - 842)) << 1) + 1); + return 0; +}