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.