aboutsummaryrefslogtreecommitdiff
path: root/src/calling.tex
diff options
context:
space:
mode:
Diffstat (limited to 'src/calling.tex')
-rw-r--r--src/calling.tex198
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.