Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Codify Save/Restore Frame Layout #70

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 37 additions & 3 deletions src/toolchain-conventions.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -193,9 +193,12 @@ have the following signatures:
- `void` `+__riscv_restore_<N>(void)+`
- `void` `+__riscv_restore_tailcall_<N>+` `(void * tail /* passed in t1 */)` (LLVM/compiler-rt only)

`<N>` is a value between 0 and 12 and corresponds to the number of
registers between `s0` and `s11` that are saved/restored. The return
address register `ra` is always included in the registers saved and restored.
`<N>` is a value between 0 and 12 and corresponds to the number of registers
between `s0` and `s11` that are saved/restored. When using the `ILP32E` ABI,
`<N>` can be at most 2, as `s3` to `s12` are temporary registers in this ABI.

The return address register `ra` is always included in the registers saved and
restored.

The `+__riscv_save_<N>+` functions are called from the prologue, using `t0` as
the link register to avoid clobbering `ra`. They allocate stack space for the
Expand All @@ -216,6 +219,37 @@ As of November 2021 the additional tail-call entry points are only
implemented in compiler-rt, and calls will only be generated by LLVM
when the option `-mllvm -save-restore-tailcall` is specified.

=== Save Restore Routine Stack Frame Layouts

While the implementation of the save restore routines are in the library, it is
the compiler's responsibility to emit the unwind information (CFI) for the
registers that are saved and restored by these routines, so the compilers and
the libraries must agree on the stack layouts used by these routines.
kito-cheng marked this conversation as resolved.
Show resolved Hide resolved

As the stack pointer must be correctly aligned at all times, the save restore
routines are expected to allocate more stack than they require to spill all
registers in many cases. Additional Callee-saved registers, beyond those
requested, may be saved and restored by these routines, in line with the
existing practice of saving and restoring registers in batches to match the
stack alignment (which saves on code size).

For the `LP64`, `LP64F`, `LP64D`, and `LP64Q` ABIs, the save restore routines
use `roundup(N+1, 2) * 8` bytes of stack space (where `roundup(val, multiple)`
rounds `value` up to a multiple of `multiple`).

For the `ILP32`, `ILP32F`, and `ILP32D` ABIs, the save restore routines use
`roundup(N+1, 4) * 4` bytes of stack space.

For the `ILP32E` ABI, the save restore routines use `(N+1) * 4` bytes of stack
space (which reflects the lower stack alignment used by this ABI).

In all the save restore routines, across all ABIs, `ra` is stored adjacent to
the incoming stack pointer (highest address), then the Callee-Saved registers in
register order from `s0` to `s11`. This follows the [Frame Pointer
Convention](https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc#frame-pointer-convention),
whether or not a frame pointer is actually being used, and contradicts with the
order used by Zcmp push/pop instructions.

== Conventions for vendor extensions

Support for custom instruction set extensions are an important part of RISC-V,
Expand Down
Loading