https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109495
--- Comment #4 from Richard Biener <rguenth at gcc dot gnu.org> ---
In store_field we run into
/* If the structure is in a register or if the component
is a bit field, we cannot use addressing to access it.
Use bit-field techniques or SUBREG to store in it. */
because
/* If the RHS and field are a constant size and the size of the
RHS isn't the same size as the bitfield, we must use bitfield
operations. */
|| (known_size_p (bitsize)
&& poly_int_tree_p (TYPE_SIZE (TREE_TYPE (exp)))
&& maybe_ne (wi::to_poly_offset (TYPE_SIZE (TREE_TYPE (exp))),
bitsize)
as bitsize == 524312 and TYPE_SIZE == 524320 (we have a COMPONENT_REF
here and the size of the FIELD_DECL is 524312!)
and since !TREE_ADDRESSABLE we're happily oblieging here.
And then we proceed with
temp = expand_normal (exp);
which results in a copy on the stack.
I wonder why we should ever, for smaller bitsize, use a copy here, when
bitsize/bitpos is a multiple of BITS_PER_UNIT? In particular I don't
understand why we need TREE_ADDRESSABLE to let a proper COMPONENT_REF
through?
/* And except for bitwise copying of TREE_ADDRESSABLE types,
where the FIELD_DECL has the right bitsize, but TREE_TYPE (exp)
includes some extra padding. store_expr / expand_expr will in
that case call get_inner_reference that will have the bitsize
we check here and thus the block move will not clobber the
padding that shouldn't be clobbered. In the future we could
replace the TREE_ADDRESSABLE check with a check that
get_base_address needs to live in memory. */
&& (!TREE_ADDRESSABLE (TREE_TYPE (exp))
|| TREE_CODE (exp) != COMPONENT_REF
|| !multiple_p (bitsize, BITS_PER_UNIT)
|| !multiple_p (bitpos, BITS_PER_UNIT)
|| !poly_int_tree_p (DECL_SIZE (TREE_OPERAND (exp, 1)),
&decl_bitsize)
|| maybe_ne (decl_bitsize, bitsize))
removing the !TREE_ADDRESSABLE check fixes the testcase.