Public review for RISC-V psABI v1.0-rc1

Hi all:

It’s Kito Cheng from the RISC-V community, Jessica Clarke and I are
working on releasing a stable version of the psABI, and are seeking
feedback from the open source community.

The goal of this stable release is having a stable version to let
people use as a reference point. We are trying to describe what we did
and what we have, and with as little new stuff as necessary for the
new and upcoming extensions.

But that does NOT mean we won’t accept any new stuff in the future,
the RISC-V psABI will still accept new backwards-compatible changes
and release periodically going forwards.

Feel free to give feedback or ask any question by replying to this
mail or creating an issue on GitHub!

Document: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/releases/tag/v1.0-rc1
Create issues here: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/issues

My 2c:

  1. XLEN should be defined somewhere for the sake of completeness. The first occurrence of this word happens in “Integer Calling Convention” and the reader has no clue of what it means. If the reader is supposed to read some other manual (e.g. ISA manual) then it should be mentioned in a new prerequisites section.

  2. I feel the allocation of aggregates to registers/stack needs to be explained in detail in “Integer Register Convention”. Specifically,

“if only one register is available, the first half is passed in a register and the second half is passed on the stack.”
a. How is the first “half” supposed to be calculated? Size of an aggregate need not be an even value.

b. As one iterates over the fields of the aggregate, the fields will get allocated to the bits in the available register. What if at a given field there is no space in the current register? Would ABI allocate the field to the next register?

  1. Isn’t there a need to standardize stack frame layout?

Hi Madhur:

Thanks for your review comment.

1. XLEN should be defined somewhere for the sake of completeness. The first occurrence of this word happens in "Integer Calling Convention" and the reader has no clue of what it means. If the reader is supposed to read some other manual (e.g. ISA manual) then it should be mentioned in a new prerequisites section.

That's a good catch, although that's a common term used in the RISC-V
world, but it definitely worth defining that clearly before use!

2. I feel the allocation of aggregates to registers/stack needs to be explained in detail in "Integer Register Convention". Specifically,
"if only one register is available, the first half is passed in a register and the second half is passed on the stack."
a. How is the first "half" supposed to be calculated? Size of an aggregate need not be an even value.

The size might not be even, and the first half might be imprecise
here, that should be first XLEN bits, given following (weird) case:

$ clang -target riscv64-elf x.c -O3 -o - -S -march=rv32gc -mabi=ilp32

struct X {
   short x;
   int y;
} __attribute__ ((packed));

int foo(int a0, int a1, int a2, int a3, int a4, int a5, int a6, struct X a7)
{
   return a7.y;
}

First 32 bits of struct X will hold in a7 registre and the remaining
16 bits will be put on stack.

I guess the wording should be revised to prevent confusion, thanks for
pointing out this!

b. As one iterates over the fields of the aggregate, the fields will get allocated to the bits in the available register. What if at a given field there is no space in the current register? Would ABI > allocate the field to the next register?

Yes, the value will splitted into two registers, give an example to demo that:

$ clang -target riscv64-elf x.c -O3 -o - -S -march=rv32gc -mabi=ilp32

struct X {
   short x;
   int y;
} __attribute__ ((packed));

int bar(struct X a7)
{
   return a7.y;
}

The first argument register will hold `x` and the first half of `y`,
and the remaining half will hold in the second argument register.

3. Isn't there a need to standardize stack frame layout?

The ABI/calling convention only cares about the interface between
different functions, e.g. how to pass/return value, the stack point
must be aligned to N-bits, and the stack argument put in where.

So how stack frame layout isn't effect the interface except the stack
argument, we are trying to don't put too much strong rule here, that
give more freedom on hand-written assembly code to layout their own
stack, otherwise it would be easy to violate :stuck_out_tongue:

Thanks again for giving that feedback!