Author Topic: GCC's __BIGGEST_ALIGNMENT__ macro on RISC-V architectures  (Read 784 times)

0 Members and 2 Guests are viewing this topic.

Offline HwAoRrDkTopic starter

  • Super Contributor
  • ***
  • Posts: 1637
  • Country: gb
GCC's __BIGGEST_ALIGNMENT__ macro on RISC-V architectures
« on: December 24, 2024, 09:47:56 am »
GCC documents the __BIGGEST_ALIGNMENT__ macro as:

Quote
GCC also provides a target specific macro __BIGGEST_ALIGNMENT__, which is the largest alignment ever used for any data type on the target machine you are compiling for. For example, you could write:

Code: [Select]
short array[3] __attribute__ ((aligned (__BIGGEST_ALIGNMENT__)));

However, I have found that in code compiled for 32-bit RISC-V microcontrollers, this macro's value is 16. ??? I would have expected it to be 4. That is, I would expect it to reflect the architecture's (as specified by -march) native word/register size - 4 bytes for RV32, 8 bytes for RV64, etc.

Where does 16 come from? Are they just blanket defining it as 16 because RV128 is a thing, and so therefore it obviously must be that when the target machine is any RISC-V architecture? ::) Surely it should be more nuanced than that...
 

Offline xvr

  • Frequent Contributor
  • **
  • Posts: 602
  • Country: ie
    • LinkedIn
Re: GCC's __BIGGEST_ALIGNMENT__ macro on RISC-V architectures
« Reply #1 on: December 24, 2024, 01:34:55 pm »
Stack alignment is 16. But I not sure how it connected to __BIGGEST_ALIGNMENT__ :)
May be something penetrated from Vector Extension  :-//
 

Offline I wanted a rude username

  • Frequent Contributor
  • **
  • Posts: 669
  • Country: au
  • ... but this username is also acceptable.
Re: GCC's __BIGGEST_ALIGNMENT__ macro on RISC-V architectures
« Reply #2 on: December 24, 2024, 03:51:40 pm »
Since you're targeting RV32, more likely this is because of the Q extension (128 b float).

This is also how the compiler will align if you don't specify a size:

Code: [Select]
int16_t array[3] __attribute__ ((aligned)); // Aligns to at least 16 B on most architectures
Usually we use compiler hints of this type to tell the compiler something that we know and it doesn't. So in practice you'll find people specifying the desired alignment explicitly (e.g. 8 B in this case).
 

Offline HwAoRrDkTopic starter

  • Super Contributor
  • ***
  • Posts: 1637
  • Country: gb
Re: GCC's __BIGGEST_ALIGNMENT__ macro on RISC-V architectures
« Reply #3 on: December 24, 2024, 04:45:22 pm »
The thing is I understand that there are architecture variations (e.g. RV128) or extensions that give a data type with 128-bit width, but if I'm specifying, for example, -march=rv32ec where no instruction can work with anything larger than 4 bytes, then surely that shouldn't apply?

I picked up on __BIGGEST_ALIGNMENT__ because I was using __attribute__((aligned(n))) to specify that something needed to be word-aligned, and I thought that rather than specifying a fixed value, the macro would give me whatever the native word size was for the architecture being compiled for. But it seems it doesn't work like that, and just gives you the same value that __attribute__((aligned)) uses when not specifying a size. So what's even the point of the existence of the macro? Maybe it's different for different platforms... :-//
 

Offline I wanted a rude username

  • Frequent Contributor
  • **
  • Posts: 669
  • Country: au
  • ... but this username is also acceptable.
Re: GCC's __BIGGEST_ALIGNMENT__ macro on RISC-V architectures
« Reply #4 on: December 24, 2024, 06:00:22 pm »
If you want to align on native word size ... why don't you just use __UNITS_PER_WORD__?
 

Online ejeffrey

  • Super Contributor
  • ***
  • Posts: 4072
  • Country: us
Re: GCC's __BIGGEST_ALIGNMENT__ macro on RISC-V architectures
« Reply #5 on: December 24, 2024, 06:40:37 pm »
BIGGEST_ALIGNMENT is the maximum alignment required by the ABI, not the architecture.  So architectural flags aren't going to affect it unless it corresponds to a different ABI (riscv32 vs 64).  That's going to be at least 8 bytes on most platforms that require double to be naturally aligned, and 16 bytes if it has a long double or long long type that requires it.  This is independent of whether the architecture has hardware support for floating point or whether you actually link the soft math libraries.

If you want the machine native word size, use sizeof(void *).
 

Online Nominal Animal

  • Super Contributor
  • ***
  • Posts: 7433
  • Country: fi
    • My home page and email address
Re: GCC's __BIGGEST_ALIGNMENT__ macro on RISC-V architectures
« Reply #6 on: December 24, 2024, 06:57:04 pm »
This can sound like a nitpick, but I warmly recommend writing that as sizeof (void *), with a space after the sizeof keyword, simply to remind us humans that it is not a function call and does not work like a function call; the expression is only evaluated for the type, without any side effects like memory accesses (or even pre- or post-increment and -decrement operations being applied).

The C language itself does not care either way, it's just for us humans.
 
The following users thanked this post: Siwastaja

Online SiliconWizard

  • Super Contributor
  • ***
  • Posts: 16097
  • Country: fr
Re: GCC's __BIGGEST_ALIGNMENT__ macro on RISC-V architectures
« Reply #7 on: December 24, 2024, 09:38:32 pm »
If you want the machine native word size, use sizeof(void *).

If we're gonna nitpick further, problem is, whatever is meant by "native word size". Granted the OP was talking about RISC-V, in in this case, pointers will have the same size as all general-purpose registers, which I guess is what we could call "native word size" (backed by the numbering in RVxx). For other architectures, you can have different register sizes for different things, in particular address registers may have a different size than "data" registers. So 'sizeof (void *)' is not exactly a portable way of finding this out, and "native word size" isn't really a portable concept either.

If this is targetted at RISC-V specifically, rather than 'sizeof (void *)', I prefer using GCC's predefined macros (similarly available with Clang): __riscv_xlen, which give the XLEN value for the RISC-V target the code is compiled for (in bits! so, if you want the value in bytes, obviously just divide it by 8, it will be done at compile time for sure.)

Similarly, you have __riscv_flen for the width of the FP registers.

Just my 2 cents.

Of course, if you specifically want the size of *pointers* in a portable way, sizeof (void *) would do. Be again careful (although this is only found in niche architectures) that pointers to data and pointers to functions may have a different size.

As to the __BIGGEST_ALIGNMENT__ predefined macro, see: 'https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html
As the name implies, it's the "largest alignment ever used for any data type on the target machine".
« Last Edit: December 24, 2024, 09:45:01 pm by SiliconWizard »
 

Offline TheCalligrapher

  • Regular Contributor
  • *
  • Posts: 161
  • Country: us
Re: GCC's __BIGGEST_ALIGNMENT__ macro on RISC-V architectures
« Reply #8 on: December 26, 2024, 06:53:47 pm »
However, I have found that in code compiled for 32-bit RISC-V microcontrollers, this macro's value is 16. ??? I would have expected it to be 4. That is, I would expect it to reflect the architecture's (as specified by -march) native word/register size - 4 bytes for RV32, 8 bytes for RV64, etc.

That's unfounded, since the alignment requirements (including hardware-dicatated ones) are not generally tied to native word size. On x64, for one example, GCC's alignment requirement for `long double` values is 16, despite the native word size of 8. And there are x86 CPU instructions that will generate a bus error if fed with an unaligned `long double`.

Does 32-bit RISC-V GCC support any "over-aligned" types like that? BTW, as a wild guess, what is `long double` in 32-bit RISC-V GCC?

---

Just noticed that Godbolt offers 32-bit RISC-V GCC. So, let's try

Code: [Select]
int x = alignof(long double);
int main() {}

compiles to

Code: [Select]
main:
        li      a0,0
        ret
x:
        .word   16

So, here's your 16. It is indeed `long double` (at least). Not surprisingly, `alignof(std::max_align_t)` is also 16.
« Last Edit: December 28, 2024, 06:45:42 am by TheCalligrapher »
 

Offline HwAoRrDkTopic starter

  • Super Contributor
  • ***
  • Posts: 1637
  • Country: gb
Re: GCC's __BIGGEST_ALIGNMENT__ macro on RISC-V architectures
« Reply #9 on: December 30, 2024, 06:37:42 pm »
Oh, so it's an ABI thing, not something related to the specific -march being compiled for.

It'd probably help if they described it as such in the documentation, rather than the slightly ambiguous "target machine". Unless "target machine" has a more precise meaning that I'm not aware of within the lexicon of GCC...
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf