http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60466
Bug ID: 60466 Summary: Support for HARD_REGNO_NREGS_HAS_PADDING and HARD_REGNO_NREGS_WITH_PADDING broken Product: gcc Version: unknown Status: UNCONFIRMED Severity: normal Priority: P3 Component: rtl-optimization Assignee: unassigned at gcc dot gnu.org Reporter: rsandifo at gcc dot gnu.org It looks like HARD_REGNO_NREGS_HAS_PADDING and HARD_REGNO_NREGS_WITH_PADDING no longer work correctly, possibly since subreg_get_info was introduced. I doubt anyone cares since it's only used for long double on -m32 with -m128bit-long-double, but just recording it anyway. Test case: void foo (void) { _Complex long double x; asm volatile ("" : "=r" (x)); asm volatile ("" :: "r" (__imag__ x), "r" (__real__ x)); } When compiled on x86_64-linux-gnu with -m32 -m128bit-long-double -O2 it fails the second of these asserts in subreg_get_info: /* This should always pass, otherwise we don't know how to verify the constraint. These conditions may be relaxed but subreg_regno_offset would need to be redesigned. */ gcc_assert ((GET_MODE_SIZE (xmode) % GET_MODE_SIZE (ymode)) == 0); gcc_assert ((nregs_xmode % nregs_ymode) == 0); nregs_xmode is set to the number of registers that there would be if no padding were present: nregs_xmode = HARD_REGNO_NREGS_WITH_PADDING (xregno, xmode); But nregs_ymode is always set to the "real" number (without padding): nregs_ymode = hard_regno_nregs[xregno][ymode]; nregs_xmode is used here: offset_adj -= subreg_lowpart_offset (ymode, mode_for_size (GET_MODE_BITSIZE (xmode) / nregs_xmode, MODE_INT, 0)); where using the padded value looks correct. The division will give a 16-byte mode, matching ymode's size, and the lowpart offset will be 0. But later we have: mode_multiple = GET_MODE_SIZE (xmode) / GET_MODE_SIZE (ymode); ... nregs_multiple = nregs_xmode / nregs_ymode; ... info->offset = (y_offset / (mode_multiple / nregs_multiple)) * nregs_ymode; where it doesn't look correct to mix padded and unpadded register counts.