public inbox for gcc-help@gcc.gnu.org
 help / color / mirror / Atom feed
* question on alignment of anonymous unions inside structs
@ 2024-05-07  0:06 Henrik Holst
  2024-05-07 11:01 ` David Brown
  0 siblings, 1 reply; 3+ messages in thread
From: Henrik Holst @ 2024-05-07  0:06 UTC (permalink / raw)
  To: gcc-help

[-- Attachment #1: Type: text/plain, Size: 2078 bytes --]

Hi,

 I understand that unions inside structs have to be aligned in case they
are referenced by a pointer or someone creates an array of them but when
the union is completely anonymous and thus none of this is possible,
shouldn't the alignment rules be relaxed?

Case in point, here I'm using pahole to show the layout and padding of the
struct:

struct cb3_item {
        union {
                struct {
                        void *     ptr1;                 /*     0     8 */
                        void *     ptr2;                 /*     8     8 */
                };                                       /*     0    16 */
                uint8_t            raw[60];              /*     0    60 */
        };                                               /*     0    64 */
        /* --- cacheline 1 boundary (64 bytes) --- */
        unsigned int               _avail;               /*    64     4 */

        /* size: 72, cachelines: 2, members: 2 */
        /* padding: 4 */
        /* last cacheline: 8 bytes */
};

So my issue here is that IMHO since the union inside the struct is
anonymous there should be no need for the 4 byte padding between the union
and the _avail member. The _avail being a 32-bit integer is perfectly fine
on a 4 byte alignment so fits perfectly at position 60 which would make the
full struct 64 bytes in size and thus perfectly aligned for 64-bit
alignment.

But instead GCC (v13.2.0 in this case) aligns the union in case I would
make a pointer to it or an array of them but this cannot be done when
defined the way it is (I mean if I had done it as "union { } *p;" or
similar then I would fully understand that gcc would align it this way).

And yes I know that I can "fix" this with __attribute__((packed,aligned(1))
but that is a very broad hammer here since now one have to perform manual
alignment of each union member since alignment inside the union is ok here
but the issue is the alignment of the union as a whole.

Unless ofc if there are some other nifty solution to this that is not as
broad as using forced alignment?

/HH

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: question on alignment of anonymous unions inside structs
  2024-05-07  0:06 question on alignment of anonymous unions inside structs Henrik Holst
@ 2024-05-07 11:01 ` David Brown
  2024-05-07 16:33   ` Henrik Holst
  0 siblings, 1 reply; 3+ messages in thread
From: David Brown @ 2024-05-07 11:01 UTC (permalink / raw)
  To: Henrik Holst, gcc-help

On 07/05/2024 02:06, Henrik Holst via Gcc-help wrote:
> Hi,
> 
>   I understand that unions inside structs have to be aligned in case they
> are referenced by a pointer or someone creates an array of them but when
> the union is completely anonymous and thus none of this is possible,
> shouldn't the alignment rules be relaxed?
> 

Alignment rules are decided by the ABI for a given platform, along with 
the C standards.  They have to be consistent, so that you can have the 
same declaration in different bits of code, perhaps compiled with 
different tools, and the layout is the same.

So the alignment values, such as on your target, "void *" pointers have 
an alignment of 8, are determined by the target ABI.  On other 
platforms, such pointers might have alignment 8, 4, 2 or 1.  But the 
rules that say unions and structs take the alignment of their most 
aligned field, and that padding is added to the end of structs or 
between fields to maintain alignment, are determined by the C standards. 
  And these rules apply equally to anonymous unions and structs.


A compiler can't change these rules without being non-conforming. 
That's fine to do with explicit extensions, such as the "packed" 
attribute.  But it takes a very strong motivation, and usually an 
explicit compiler flag, to break conformity for code without using 
extensions.

I think your best bet is a slightly smaller hammer - put 
__attribute__((packed, aligned(4)) on the anonymous struct, and 
__attribute__((aligned(64))) on the outer struct :

struct __attribute__((aligned(64))) cb3_item  {
         union {
                 struct __attribute__((packed, aligned(4))) {
                         void *     ptr1;
                         void *     ptr2;
                 };
                 uint8_t            raw[60];
         };
         unsigned int               _avail;
};
_Static_assert(sizeof(struct cb3_item) == 64, "Check cb3_item struct");


This way you'll get your "packed" attribute only on the bit you need it, 
and an alignment of 4 is better than an alignment of 1.  And an outer 
alignment of 64 ensures that the structure is cache-friendly - you 
wouldn't want a big array of these things to just have an 8-byte alignment.

mvh.,

David






> Case in point, here I'm using pahole to show the layout and padding of the
> struct:
> 
> struct cb3_item {
>          union {
>                  struct {
>                          void *     ptr1;                 /*     0     8 */
>                          void *     ptr2;                 /*     8     8 */
>                  };                                       /*     0    16 */
>                  uint8_t            raw[60];              /*     0    60 */
>          };                                               /*     0    64 */
>          /* --- cacheline 1 boundary (64 bytes) --- */
>          unsigned int               _avail;               /*    64     4 */
> 
>          /* size: 72, cachelines: 2, members: 2 */
>          /* padding: 4 */
>          /* last cacheline: 8 bytes */
> };
> 
> So my issue here is that IMHO since the union inside the struct is
> anonymous there should be no need for the 4 byte padding between the union
> and the _avail member. The _avail being a 32-bit integer is perfectly fine
> on a 4 byte alignment so fits perfectly at position 60 which would make the
> full struct 64 bytes in size and thus perfectly aligned for 64-bit
> alignment.
> 
> But instead GCC (v13.2.0 in this case) aligns the union in case I would
> make a pointer to it or an array of them but this cannot be done when
> defined the way it is (I mean if I had done it as "union { } *p;" or
> similar then I would fully understand that gcc would align it this way).
> 
> And yes I know that I can "fix" this with __attribute__((packed,aligned(1))
> but that is a very broad hammer here since now one have to perform manual
> alignment of each union member since alignment inside the union is ok here
> but the issue is the alignment of the union as a whole.
> 
> Unless ofc if there are some other nifty solution to this that is not as
> broad as using forced alignment?
> 
> /HH
> 


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: question on alignment of anonymous unions inside structs
  2024-05-07 11:01 ` David Brown
@ 2024-05-07 16:33   ` Henrik Holst
  0 siblings, 0 replies; 3+ messages in thread
From: Henrik Holst @ 2024-05-07 16:33 UTC (permalink / raw)
  To: David Brown; +Cc: gcc-help

[-- Attachment #1: Type: text/plain, Size: 4439 bytes --]

thanks David!

/HH

Den tis 7 maj 2024 kl 13:01 skrev David Brown <david.brown@hesbynett.no>:

> On 07/05/2024 02:06, Henrik Holst via Gcc-help wrote:
> > Hi,
> >
> >   I understand that unions inside structs have to be aligned in case they
> > are referenced by a pointer or someone creates an array of them but when
> > the union is completely anonymous and thus none of this is possible,
> > shouldn't the alignment rules be relaxed?
> >
>
> Alignment rules are decided by the ABI for a given platform, along with
> the C standards.  They have to be consistent, so that you can have the
> same declaration in different bits of code, perhaps compiled with
> different tools, and the layout is the same.
>
> So the alignment values, such as on your target, "void *" pointers have
> an alignment of 8, are determined by the target ABI.  On other
> platforms, such pointers might have alignment 8, 4, 2 or 1.  But the
> rules that say unions and structs take the alignment of their most
> aligned field, and that padding is added to the end of structs or
> between fields to maintain alignment, are determined by the C standards.
>   And these rules apply equally to anonymous unions and structs.
>
>
> A compiler can't change these rules without being non-conforming.
> That's fine to do with explicit extensions, such as the "packed"
> attribute.  But it takes a very strong motivation, and usually an
> explicit compiler flag, to break conformity for code without using
> extensions.
>
> I think your best bet is a slightly smaller hammer - put
> __attribute__((packed, aligned(4)) on the anonymous struct, and
> __attribute__((aligned(64))) on the outer struct :
>
> struct __attribute__((aligned(64))) cb3_item  {
>          union {
>                  struct __attribute__((packed, aligned(4))) {
>                          void *     ptr1;
>                          void *     ptr2;
>                  };
>                  uint8_t            raw[60];
>          };
>          unsigned int               _avail;
> };
> _Static_assert(sizeof(struct cb3_item) == 64, "Check cb3_item struct");
>
>
> This way you'll get your "packed" attribute only on the bit you need it,
> and an alignment of 4 is better than an alignment of 1.  And an outer
> alignment of 64 ensures that the structure is cache-friendly - you
> wouldn't want a big array of these things to just have an 8-byte alignment.
>
> mvh.,
>
> David
>
>
>
>
>
>
> > Case in point, here I'm using pahole to show the layout and padding of
> the
> > struct:
> >
> > struct cb3_item {
> >          union {
> >                  struct {
> >                          void *     ptr1;                 /*     0     8
> */
> >                          void *     ptr2;                 /*     8     8
> */
> >                  };                                       /*     0    16
> */
> >                  uint8_t            raw[60];              /*     0    60
> */
> >          };                                               /*     0    64
> */
> >          /* --- cacheline 1 boundary (64 bytes) --- */
> >          unsigned int               _avail;               /*    64     4
> */
> >
> >          /* size: 72, cachelines: 2, members: 2 */
> >          /* padding: 4 */
> >          /* last cacheline: 8 bytes */
> > };
> >
> > So my issue here is that IMHO since the union inside the struct is
> > anonymous there should be no need for the 4 byte padding between the
> union
> > and the _avail member. The _avail being a 32-bit integer is perfectly
> fine
> > on a 4 byte alignment so fits perfectly at position 60 which would make
> the
> > full struct 64 bytes in size and thus perfectly aligned for 64-bit
> > alignment.
> >
> > But instead GCC (v13.2.0 in this case) aligns the union in case I would
> > make a pointer to it or an array of them but this cannot be done when
> > defined the way it is (I mean if I had done it as "union { } *p;" or
> > similar then I would fully understand that gcc would align it this way).
> >
> > And yes I know that I can "fix" this with
> __attribute__((packed,aligned(1))
> > but that is a very broad hammer here since now one have to perform manual
> > alignment of each union member since alignment inside the union is ok
> here
> > but the issue is the alignment of the union as a whole.
> >
> > Unless ofc if there are some other nifty solution to this that is not as
> > broad as using forced alignment?
> >
> > /HH
> >
>
>

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2024-05-07 16:33 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-05-07  0:06 question on alignment of anonymous unions inside structs Henrik Holst
2024-05-07 11:01 ` David Brown
2024-05-07 16:33   ` Henrik Holst

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).