diff options
Diffstat (limited to 'src/calling.tex')
-rw-r--r-- | src/calling.tex | 198 |
1 files changed, 198 insertions, 0 deletions
diff --git a/src/calling.tex b/src/calling.tex new file mode 100644 index 0000000..55c55e1 --- /dev/null +++ b/src/calling.tex @@ -0,0 +1,198 @@ +\chapter{Calling Convention} +\label{sec:calling} + +This chapter describes the C compiler standards for RV32 and RV64 programs +and two calling conventions: the convention for the base ISA +plus standard general extensions (RV32G/RV64G), and the soft-float +convention for implementations lacking floating-point units (e.g., RV32I/RV64I). + +\begin{commentary} +Implementations with ISA extensions might require extended calling +conventions. +\end{commentary} + +\section{C Datatypes and Alignment} + +Table~\ref{datatypes} summarizes the datatypes natively supported by +RISC-V C programs. In both RV32 and RV64 C compilers, the C type {\tt + int} is 32 bits wide. {\tt long}s and pointers, on the other hand, +are both as wide as a integer register, so in RV32, both are 32 bits +wide, while in RV64, both are 64 bits wide. Equivalently, RV32 +employs an ILP32 integer model, while RV64 is LP64. In both RV32 and +RV64, the C type {\tt long long} is a 64-bit integer, {\tt float} is a +32-bit IEEE 754-2008 floating-point number, {\tt double} is a 64-bit +IEEE 754-2008 floating-point number, and {\tt long double} is a +128-bit IEEE floating-point number. + +The C types {\tt char} and {\tt unsigned char} are 8-bit unsigned integers and +are zero-extended when stored in a RISC-V integer register. {\tt unsigned +short} is a 16-bit unsigned integer and is zero-extended when stored in +a RISC-V integer register. {\tt signed char} is an 8-bit signed integer and +is sign-extended when stored in a RISC-V integer register, i.e. bits +(XLEN-1)..7 are all equal. {\tt short} is a 16-bit signed integer and is +sign-extended when stored in a register. + +In RV64, 32-bit types, such as {\tt int}, are stored in integer registers +as proper sign extensions of their 32-bit values; that is, bits 63..31 are all +equal. This restriction holds even for unsigned 32-bit types. + +The RV32 and RV64 C compiler and compliant software keep all of the +above datatypes naturally aligned when stored in memory. + +\vspace{0.2in} +\begin{table*}[htbp] +\begin{center} +\begin{tabular}{|l|l|r|r|} + + \hline + C type & Description & Bytes in RV32 & Bytes in RV64 \\ \hline + \tt char & Character value/byte & 1 & 1 \\ + \tt short & Short integer & 2 & 2 \\ + \tt int & Integer & 4 & 4 \\ + \tt long & Long integer & 4 & 8 \\ + \tt long long & Long long integer & 8 & 8 \\ + \tt void* & Pointer & 4 & 8 \\ + \tt float & Single-precision float & 4 & 4 \\ + \tt double & Double-precision float & 8 & 8 \\ + \tt long double & Extended-precision float & 16 & 16 \\ + \hline + + \end{tabular} +\end{center} +\caption{C compiler datatypes for base RISC-V ISA.} +\label{datatypes} +\end{table*} + + +\section{RVG Calling Convention} + +The RISC-V calling convention passes arguments in registers when +possible. Up to eight integer registers, {\tt a0}--{\tt a7}, +and up to eight floating-point registers, {\tt fa0}--{\tt fa7}, +are used for this purpose. + +If the arguments to a function are conceptualized as fields of a C +{\tt struct}, each with pointer alignment, the argument registers are +a shadow of the first eight pointer-words of that {\tt struct}. If +argument $i<8$ is a floating-point type, it is passed in +floating-point register {\tt fa}$i$; otherwise, it is passed in +integer register {\tt a}$i$. However, floating-point arguments +that are part of {\tt union}s or array fields of structures are passed +in integer registers. Additionally, floating-point arguments to +variadic functions (except those that are explicitly named in the +parameter list) are passed in integer registers. + +Arguments smaller than a pointer-word are passed in the least-significant bits +of argument registers. Correspondingly, sub-pointer-word arguments passed on +the stack appear in the lower addresses of a pointer-word, since RISC-V +has a little-endian memory system. + +When primitive arguments twice the size of a pointer-word are passed on the +stack, they are naturally aligned. When they are passed in the integer +registers, they reside in an aligned even-odd register pair, with the even +register holding the least-significant bits. In RV32, for example, the function +{\tt void foo(int, long long)} is passed its first argument in +{\tt a0} and its second in {\tt a2} and {\tt a3}. Nothing is passed +in {\tt a1}. + +Arguments more than twice the size of a pointer-word are passed by reference. + +The portion of the conceptual {\tt struct} that is not passed in argument +registers is passed on the stack. The stack pointer {\tt sp} points to the +first argument not passed in a register. + +Values are returned from functions in integer registers {\tt a0} and {\tt +a1} and floating-point registers {\tt fa0} and {\tt fa1}. Floating-point +values are returned in floating-point registers only if they are primitives or +members of a {\tt struct} consisting of only one or two floating-point values. +Other return values that fit into two pointer-words are returned in {\tt a0} +and {\tt a1}. Larger return values are passed entirely in memory; the caller +allocates this memory region and passes a pointer to it as an implicit first +parameter to the callee. + +In the standard RISC-V calling convention, the stack grows downward and the +stack pointer is always kept 16-byte aligned. + +In addition to the argument and return value registers, +seven integer registers {\tt t0}--{\tt t6} and twelve floating-point registers +{\tt ft0}--{\tt ft11} are temporary registers that are volatile across +calls and must be saved by the caller if later used. +Twelve integer registers {\tt s0}--{\tt s11} and twelve floating-point +registers {\tt fs0}--{\tt fs11} are preserved across calls and must be saved +by the callee if used. Table~\ref{regmap} indicates the role of each +integer and floating-point register in the calling convention. + +\vspace{0.2in} +\begin{table*}[htbp] +\begin{center} +\begin{tabular}{|l|l|l|l|} + + \hline + Register & ABI Name & Description & Saver \\ \hline + \tt x0 & \tt zero & Hard-wired zero & --- \\ + \tt x1 & \tt ra & Return address & Caller \\ + \tt x2 & \tt sp & Stack pointer & Callee \\ + \tt x3 & \tt gp & Global pointer & --- \\ + \tt x4 & \tt tp & Thread pointer & --- \\ + {\tt x5}--{\tt 7} & {\tt t0}--{\tt 2} & Temporaries & Caller \\ + \tt x8 & {\tt s0}/\tt fp & Saved register/frame pointer & Callee \\ + \tt x9 & {\tt s1} & Saved register & Callee \\ + {\tt x10}--{\tt 11} & {\tt a0}--{\tt 1} & Function arguments/return values & Caller \\ + {\tt x12}--{\tt 17} & {\tt a2}--{\tt 7} & Function arguments & Caller \\ + {\tt x18}--{\tt 27} & {\tt s2}--{\tt 11} & Saved registers & Callee \\ + {\tt x28}--{\tt 31} & {\tt t3}--{\tt 6} & Temporaries & Caller \\ + \hline + {\tt f0}--{\tt 7} & {\tt ft0}--{\tt 7} & FP temporaries & Caller \\ + {\tt f8}--{\tt 9} & {\tt fs0}--{\tt 1} & FP saved registers & Callee \\ + {\tt f10}--{\tt 11} & {\tt fa0}--{\tt 1} & FP arguments/return values & Caller \\ + {\tt f12}--{\tt 17} & {\tt fa2}--{\tt 7} & FP arguments & Caller \\ + {\tt f18}--{\tt 27} & {\tt fs2}--{\tt 11} & FP saved registers & Callee \\ + {\tt f28}--{\tt 31} & {\tt ft8}--{\tt 11} & FP temporaries & Caller \\ + \hline + + \end{tabular} +\end{center} +\caption{RISC-V calling convention register usage.} +\label{regmap} +\end{table*} + +\section{Soft-Float Calling Convention} + +The soft-float calling convention is intended for use on RV32 and RV64 +implementations that lack floating-point hardware. It avoids all use +of instructions in the F, D, and Q standard extensions, and hence the +{\tt f} registers. + +Integral arguments are passed and returned in the same manner as the +RVG convention, and the stack discipline is the same except that the +stack is only kept aligned to XLEN/8-byte boundaries (e.g., four-byte +alignment for RV32I). + +\begin{commentary} + As floating-point data on the stack will be accessed using integer + load and store instructions, there is no incentive to maintain stack + alignment at a coarse granularity in the soft-float calling + convention. The reduced stack alignment saves space in the + memory-constrained systems that might commonly use soft + floating-point. +\end{commentary} + +Floating-point arguments are passed and returned in integer registers, +using the rules for integer arguments of the same size. In RV32, for +example, the function {\tt double foo(int, double, long double)} is +passed its first argument in {\tt a0}, its second argument in {\tt a2} +and {\tt a3}, and its third argument by reference via {\tt a4}; its +result is returned in {\tt a0} and {\tt a1}. In RV64, the arguments +are passed in {\tt a0}, {\tt a1}, and the {\tt a2}-{\tt a3} pair, and +the result is returned in {\tt a0}. + +The dynamic rounding mode and accrued exception flags are accessed through +the routines provided by the C99 header {\tt fenv.h}. + +\section{RV32E Calling Convention} + +RV32E uses a subset of the Soft-Float calling convention. As only 16 +integer registers {\tt x0}--{\tt x15} are present, there are only six +argument registers ({\tt x10}--{\tt x15}), two saved registers ({\tt + x8}--{\tt x9}), and three temporary registers ({\tt x5}--{\tt x7}). +The stack is kept aligned on a four-byte boundary. |