Hi! For SUBREGs, make_compound_operation* recurses on the SUBREG_REG. If the original in_code is EQ (i.e. equality comparison against 0) or SET, we handle it correctly, but as the following testcase shows, for COMPARE (some other comparison against 0) we in some cases don't.
The problem is that the recursive call can encounter: /* If we are in a comparison and this is an AND with a power of two, convert this into the appropriate bit extract. */ else if (in_code == COMPARE && (i = exact_log2 (UINTVAL (XEXP (x, 1)))) >= 0 && (equality_comparison || i < GET_MODE_PRECISION (mode) - 1)) new_rtx = make_extraction (mode, make_compound_operation (XEXP (x, 0), next_code), i, NULL_RTX, 1, 1, 0, 1); and mode in that case is the mode of the SUBREG_REG, so on the following testcase SImode, while SUBREG's mode is QImode, and inner is AND with 0x80 constant. For COMPARE (i.e. non-equality_comparison), we can do that only if the AND is with a mask smaller than the sign bit and we can then just extract the corresponding bits in lower positions. But with SUBREGs, we actually need to make sure that we only consider masks smaller than the sign bit of the outer SUBREG's mode. Apparently the caller already has a spot where I've fixed similar issues already, but only if the mask was completely outside of the bits of the inner mode, the following patch just extends it also to the sign bit of the SUBREG's mode. Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk/7.1? 2017-04-24 Jakub Jelinek <ja...@redhat.com> PR rtl-optimization/80501 * combine.c (make_compound_operation_int): Set subreg_code to SET even for AND with mask of the sign bit of mode. * gcc.c-torture/execute/pr80501.c: New test. --- gcc/combine.c.jj 2017-03-30 15:24:24.000000000 +0200 +++ gcc/combine.c 2017-04-24 13:05:49.264713210 +0200 @@ -8170,12 +8170,15 @@ make_compound_operation_int (machine_mod || GET_CODE (inner) == SUBREG /* (subreg:SI (and:DI (reg:DI) (const_int 0x800000000)) 0) is (const_int 0), rather than - (subreg:SI (lshiftrt:DI (reg:DI) (const_int 35)) 0). */ + (subreg:SI (lshiftrt:DI (reg:DI) (const_int 35)) 0). + Similarly (subreg:QI (and:SI (reg:SI) (const_int 0x80)) 0) + for non-equality comparisons against 0 is not equivalent + to (subreg:QI (lshiftrt:SI (reg:SI) (const_int 7)) 0). */ || (GET_CODE (inner) == AND && CONST_INT_P (XEXP (inner, 1)) && GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (inner)) && exact_log2 (UINTVAL (XEXP (inner, 1))) - >= GET_MODE_BITSIZE (mode)))) + >= GET_MODE_BITSIZE (mode) - 1))) subreg_code = SET; tem = make_compound_operation (inner, subreg_code); --- gcc/testsuite/gcc.c-torture/execute/pr80501.c.jj 2017-04-24 13:20:19.681024137 +0200 +++ gcc/testsuite/gcc.c-torture/execute/pr80501.c 2017-04-24 13:20:08.000000000 +0200 @@ -0,0 +1,23 @@ +/* PR rtl-optimization/80501 */ + +signed char v = 0; + +static signed char +foo (int x, int y) +{ + return x << y; +} + +__attribute__((noinline, noclone)) int +bar (void) +{ + return foo (v >= 0, __CHAR_BIT__ - 1) >= 1; +} + +int +main () +{ + if (sizeof (int) > sizeof (char) && bar () != 0) + __builtin_abort (); + return 0; +} Jakub