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