https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84071
Bug ID: 84071 Summary: [7/8 regression] nonzero_bits1 of subreg incorrect Product: gcc Version: 7.0 Status: UNCONFIRMED Severity: major Priority: P3 Component: middle-end Assignee: unassigned at gcc dot gnu.org Reporter: wilco at gcc dot gnu.org Target Milestone: --- PR59461 changed nonzero_bits1 incorrectly for subregs: /* On many CISC machines, accessing an object in a wider mode causes the high-order bits to become undefined. So they are not known to be zero. */ rtx_code extend_op; if ((!WORD_REGISTER_OPERATIONS /* If this is a typical RISC machine, we only have to worry about the way loads are extended. */ || ((extend_op = load_extend_op (inner_mode)) == SIGN_EXTEND ? val_signbit_known_set_p (inner_mode, nonzero) : extend_op != ZERO_EXTEND) || (!MEM_P (SUBREG_REG (x)) && !REG_P (SUBREG_REG (x)))) && xmode_width > inner_width) nonzero |= (GET_MODE_MASK (GET_MODE (x)) & ~GET_MODE_MASK (inner_mode)); If WORD_REGISTER_OPERATIONS is set and load_extend_op is ZERO_EXTEND, rtl like (subreg:SI (reg:HI 125) 0) is assumed to be always zero-extended. This is incorrect since modes that are smaller than WORD_MODE may contain random top bits. This is equally true for RISC and CISC ISAs and independent of WORD_REGISTER_OPERATIONS, so it's unclear why the !REG_P check was added. On ARM this causes the following bug: arm-none-eabi-gcc -march=armv7-a -marm -O2 -S -o- -mbig-endian typedef union { signed short ss; unsigned short us; int x; } U; int f(int x, int y, int z, int a, U u) { return (u.ss <= 0) + u.us; } ldrsh r3, [sp] sxth r0, r3 cmp r0, #0 // correctly uses sign-extended value movgt r0, r3 // wrong - must be zero-extended!!! addle r0, r3, #1 bx lr