RISC-V ABI: Integer Calling Convention & Passing Large Aggregates

59 views
Skip to first unread message

Heiko Falk

unread,
Feb 14, 2024, 11:03:16 AMFeb 14
to RISC-V SW Dev
Dear all,


I am a C compiler writer and have a question regarding the integer calling convention described in section 2.1 of the ABI v1.0 from Nov 2022 [1].

The ABI states that "Aggregates larger than 2×XLEN bits are passed by reference and are replaced in the argument list with the address" and "Arguments passed by reference may be modified by the callee."

In the attached C test program, a struct bar with 3 ints is passed from main to foo. This struct is passed via the memory, and in order to protect struct bar from being modified within foo, a copy of bar needs to be made.

Compiling this little test program with

riscv32-unknown-elf-gcc -march=rv32imc -std=c99 -pedantic -O0 -S test.c

produces the attached RISC-V assembly code. The above mentioned copying of struct bar can be found in lines 41-46, i.e., the copy is made by the caller main, and not by the callee foo.

My question -- where I would appreciate any kind of helpful feedback or citations of relevant specs -- now is: Where and how is specified who has to make such a copy?

A student of mine has just added basic support for C-structs to the RISC-V port of our research compiler WCC. And it turns out that he decided to have the callee make such a copy within WCC. This works, our generated code behaves correctly.

But obviously, our WCC code follows a different style compared to GCC code so that interoperability when linking together GCC+WCC assembly code no longer is given.

Who is right?     🙂

Thanks in advance for your insights, all the best,

  Heiko


[1] https://drive.google.com/file/d/1Ja_Tpp_5Me583CGVD-BIZMlgGBnlKU4R/view?usp=drive_link

-- 

_______________________________________________________________________

Prof. Dr. Heiko Falk

Institute of Embedded Systems
Hamburg University of Technology (TUHH)

D-21071 Hamburg
Germany


Phone:  +49 40 42878 3055
Mail:   Heiko...@tuhh.de
WWW:    http://www.tuhh.de/es
PGP:    http://www.tuhh.de/es/esd/people/hfalk/pgp
_______________________________________________________________________
test.s
test.c

Heiko Falk

unread,
Mar 6, 2024, 8:38:40 AMMar 6
to RISC-V SW Dev, Heiko Falk
Dear all,

does someone of you know how to contact the RISC-V ABI Specs team? It seems that noone from the sw-dev community here can help so that I would like to reach out to the people maintaining the official specifications.

Thanks and best wishes,

  Heiko

David Abdurachmanov

unread,
Mar 6, 2024, 8:46:21 AMMar 6
to Heiko Falk, RISC-V SW Dev
On Wed, Mar 6, 2024 at 3:38 PM Heiko Falk <Heiko...@tuhh.de> wrote:
>
> Dear all,
>
> does someone of you know how to contact the RISC-V ABI Specs team? It seems that noone from the sw-dev community here can help so that I would like to reach out to the people maintaining the official specifications.

Hi,

psABI is maintained as a GitHub repository:
https://github.com/riscv-non-isa/riscv-elf-psabi-doc

david
> --
> You received this message because you are subscribed to the Google Groups "RISC-V SW Dev" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to sw-dev+un...@groups.riscv.org.
> To view this discussion on the web visit https://groups.google.com/a/groups.riscv.org/d/msgid/sw-dev/dc6fb0dc-02da-4c72-a334-f8419ebbff1en%40groups.riscv.org.

Tommy Murphy

unread,
Mar 6, 2024, 8:55:30 AMMar 6
to David Abdurachmanov, Heiko Falk, RISC-V SW Dev

Christoph Müllner

unread,
Mar 6, 2024, 10:34:03 AMMar 6
to Heiko Falk, RISC-V SW Dev, Kito Cheng, Jessica Clarke, David Abdurachmanov, Tommy Murphy

Hi Heiko,

On Wed, Feb 14, 2024 at 5:03 PM Heiko Falk <Heiko...@tuhh.de> wrote:
Dear all,


I am a C compiler writer and have a question regarding the integer calling convention described in section 2.1 of the ABI v1.0 from Nov 2022 [1].

The ABI states that "Aggregates larger than 2×XLEN bits are passed by reference and are replaced in the argument list with the address" and "Arguments passed by reference may be modified by the callee."

In the attached C test program, a struct bar with 3 ints is passed from main to foo. This struct is passed via the memory, and in order to protect struct bar from being modified within foo, a copy of bar needs to be made.

Compiling this little test program with

riscv32-unknown-elf-gcc -march=rv32imc -std=c99 -pedantic -O0 -S test.c

produces the attached RISC-V assembly code. The above mentioned copying of struct bar can be found in lines 41-46, i.e., the copy is made by the caller main, and not by the callee foo.

My question -- where I would appreciate any kind of helpful feedback or citations of relevant specs -- now is: Where and how is specified who has to make such a copy?

The CC clearly states, as you already found out, that "arguments passed by reference may be modified by the callee".
This means that the aggregate's values are not preserved across calls.
I.e., the caller has no guarantee that the values of the referenced aggregate won't be modified, so it must assume that the aggregate will be modified.
 
A student of mine has just added basic support for C-structs to the RISC-V port of our research compiler WCC. And it turns out that he decided to have the callee make such a copy within WCC. This works, our generated code behaves correctly.

That's an incompatible change of the calling convention: the caller does not pass a copy of the aggregate by reference.
The fact that the callee creates a copy is irrelevant in this context (it is a performance issue, but not a correctness issue).
E.g., when linking against shared libraries that won't do the (not required) copy of the aggregate in the callee.

Regarding your example:
Since the instance bar is dead after the call to foo in main, there is no need to create a copy anyway.
The specification defines if values are preserved, not if either side must make a copy (or not).
An example that highlights the overhead implied in the caller (even with -O3) could look like this:

BR
Christoph


 


But obviously, our WCC code follows a different style compared to GCC code so that interoperability when linking together GCC+WCC assembly code no longer is given.

Who is right?     🙂

Thanks in advance for your insights, all the best,

  Heiko


[1] https://drive.google.com/file/d/1Ja_Tpp_5Me583CGVD-BIZMlgGBnlKU4R/view?usp=drive_link

-- 

_______________________________________________________________________

Prof. Dr. Heiko Falk

Institute of Embedded Systems
Hamburg University of Technology (TUHH)

D-21071 Hamburg
Germany


Phone:  +49 40 42878 3055
Mail:   Heiko...@tuhh.de
WWW:    http://www.tuhh.de/es
PGP:    http://www.tuhh.de/es/esd/people/hfalk/pgp
_______________________________________________________________________

--
You received this message because you are subscribed to the Google Groups "RISC-V SW Dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to sw-dev+un...@groups.riscv.org.

Bruce Hoult

unread,
Mar 7, 2024, 4:25:48 AMMar 7
to Heiko Falk, RISC-V SW Dev
> The ABI states that "Aggregates larger than 2×XLEN bits are passed by reference and are replaced in the argument list with the address" and "Arguments passed by reference may be modified by the callee."
>
>In the attached C test program, a struct bar with 3 ints is passed from main to foo. This struct is passed via the memory, and in order to protect struct bar from being modified within foo, a copy of bar needs to be made.

This is exactly the same for both small values and large ones.

The callee is free to modify registers used to pass arguments to it.
If the caller wants to preserve their original value then they need to
make a copy somewhere else. For optimised code this is usually in S
registers, but it can also be in memory i.e. on the stack.

It is exactly the same for large aggregates, except they can't fit in
to a register (or pair of registers). In memory is the only choice. If
the caller wants to use the original value of the aggregate again
after the call then it needs to make a copy, and pass the address of
either the copy or the original. If the caller doesn't need the
original value again after the call (which the callee can't possibly
know) then the caller can just pass the address of the original value.

Your student's compiler is wrong. If a standard function calls a
function compiled by them , the aggregate will be (harmlessly) copied
twice. But if the student's compiler calls a standard RISC-V function
... e.g. in the standard library ... then no one will copy the
aggregate, and disaster may follow. (If any such function exists ...
as far as I recall, all large structures are passed to the standard
library explicitly by reference anyway)
> --
> You received this message because you are subscribed to the Google Groups "RISC-V SW Dev" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to sw-dev+un...@groups.riscv.org.
> To view this discussion on the web visit https://groups.google.com/a/groups.riscv.org/d/msgid/sw-dev/dc6fb0dc-02da-4c72-a334-f8419ebbff1en%40groups.riscv.org.
Reply all
Reply to author
Forward
0 new messages