Improve clarity of the LI and LA pseudo instructions

This commit is contained in:
John Winans 2022-04-18 10:28:47 -05:00
parent cec208933c
commit 9de91452f2

View File

@ -364,26 +364,27 @@ Introduce and present subroutines but not nesting until introduce stack operatio
{\small {\small
\begin{verbatim} \begin{verbatim}
li rd,constant lui rd,(constant >>U 12)+(constant & 0x00000800 ? 1 : 0) li rd,constant
lui rd,(constant + 0x00000800) >> 12
addi rd,rd,(constant & 0x00000fff) addi rd,rd,(constant & 0x00000fff)
la rd,label la rd,label
auipc rd,((label-.) >>U 12) + ((label-.) & 0x00000800 ? 1 : 0) auipc rd,((label-.) + 0x00000800) >> 12
addi rd,rd,((label-(.-4)) & 0x00000fff) addi rd,rd,((label-(.-4)) & 0x00000fff)
l{b|h|w} rd,label l{b|h|w} rd,label
auipc rd,((label-.) >>U 12) + ((label-.) & 0x00000800 ? 1 : 0) auipc rd,((label-.) + 0x00000800) >> 12
l{b|h|w} rd,((label-(.-4)) & 0x00000fff)(rd) l{b|h|w} rd,((label-(.-4)) & 0x00000fff)(rd)
s{b|h|w} rd,label,rt # rt used as a temp reg for the operation (default=x6) s{b|h|w} rd,label,rt # rt used as a temp reg for the operation (default=x6)
auipc rt,((label-.) >>U 12) + ((label-.) & 0x00000800 ? 1 : 0) auipc rt,((label-.) + 0x00000800) >> 12
s{b|h|w} rd,((label-(.-4)) & 0x00000fff)(rt) s{b|h|w} rd,((label-(.-4)) & 0x00000fff)(rt)
call label auipc x1,((label-.) >>U 12) + ((label-.) & 0x00000800 ? 1 : 0) call label auipc x1,((label-.) + 0x00000800) >> 12
jalr x1,((label-(.-4)) & 0x00000fff)(x1) jalr x1,((label-(.-4)) & 0x00000fff)(x1)
tail label,rt # rt used as a temp reg for the operation (default=x6) tail label,rt # rt used as a temp reg for the operation (default=x6)
auipc rt,((label-.) >>U 12) + ((label-.) & 0x00000800 ? 1 : 0) auipc rt,((label-.) + 0x00000800) >> 12
jalr x0,((label-(.-4)) & 0x00000fff)(rt) jalr x0,((label-(.-4)) & 0x00000fff)(rt)
mv rd,rs addi rd,rs,0 mv rd,rs addi rd,rs,0
@ -398,7 +399,8 @@ Introduce and present subroutines but not nesting until introduce stack operatio
\subsection{The {\tt li} Pseudoinstruction} \subsection{The {\tt li} Pseudoinstruction}
Note that the {\tt li} pseudoinstruction includes a conditional addition of 1 to the operand Note that the {\tt li} pseudoinstruction includes an (effectively) conditional addition
of 1 to the immediate operand
in the {\tt lui} instruction. This is because the immediate operand in the in the {\tt lui} instruction. This is because the immediate operand in the
{\tt addi} instruction is sign-extended before it is added to \verb@rd@. {\tt addi} instruction is sign-extended before it is added to \verb@rd@.
If the immediate operand to the {\tt addi} has its most-significant-bit set to 1 then If the immediate operand to the {\tt addi} has its most-significant-bit set to 1 then
@ -422,32 +424,56 @@ A naive (incorrect) solution might be:
The result of the above code is that an incorrect value has been placed into x5. The result of the above code is that an incorrect value has been placed into x5.
} }
To remedy this problem, the value used in the {\tt lui} instruction can altered To remedy this problem, the value used in the {\tt lui} instruction can be altered
(by adding 1 to its operand) to compensate for the sign-extention in the {\tt addi} (by adding 1 to its operand) to compensate for the sign-extention in the {\tt addi}
instruction: instruction:
{\small {\small
\begin{verbatim} \begin{verbatim}
lui x5,0x12346 // x5 = 0x12346000 (note: this is 0x12345000 + 0x1000) lui x5,0x12346 // x5 = 0x12346000 (note: this is 0x12345800 + 0x0800)
addi x5,x5,0x800 // x5 = 0x12346000 + sx(0x800) = 0x12346000 + 0xfffff800 = 0x12345800 addi x5,x5,0x800 // x5 = 0x12346000 + sx(0x800) = 0x12346000 + 0xfffff800 = 0x12345800
\end{verbatim} \end{verbatim}
} }
Keep in mind that the {\em only} time that this altering of the operand in the {\tt lui}
instruction should take place is when the most-significant-bit of the operand in the Keep in mind that the {\tt li} pseudoinstruction must {\em only} increment the operand
{\tt addi} is set to one. of the {\tt lui} instruction when it is known that the operand of the subsequent
{\tt addi} instruction will be a negative number.
\enote{Add a ribbon diagram of this?}%
By adding {\tt 0x00000800} to the immediate operand of the {\tt lui} instruction in
this example, a carry-bit into bit-12 will be set to {\tt 1} iff the value in
bits 11-0 will be treated as a negative value in the subsequent {\tt addi} instruction.
In other words, when bit-11 is set to {\tt 1} in the immediate operand of the {\tt li}
pseudoinstruction, the immediate operand of the {\tt lui} instruction will be
incremented by {\tt 1}.
Consider the case where we wish to put the value {\tt 0x12345700} into register {\tt x5}: Consider the case where we wish to put the value {\tt 0x12345700} into register {\tt x5}:
{\small {\small
\begin{verbatim} \begin{verbatim}
lui x5,0x12345 // x5 = 0x12345000 (note this is 0x12345 + 0) lui x5,0x12345 // x5 = 0x12345000 (note that 0x12345700 + 0x0800 = 0x12345f00)
addi x5,x5,0x700 // x5 = 0x12345000 + sx(0x700) = 0x12345000 + 0x00000700 = 0x12345700 addi x5,x5,0x700 // x5 = 0x12345000 + sx(0x700) = 0x12345000 + 0x00000700 = 0x12345700
\end{verbatim} \end{verbatim}
} }
The sign-extension in this example performed by the {\tt addi} instruction will convert the The sign-extension in this example performed by the {\tt addi} instruction will convert the
{\tt 0x700} to {\tt 0x00000700} before the addition. {\tt 0x700} to {\tt 0x00000700} before the addition.
Therefore, the {\tt li} pseudoinstruction must {\em only} increment the operand of the Observe that {\tt 0x12345700+0x0800 = 0x12345f00} and therefore, after shifting
{\tt lui} instruction when it is known that the operand of the subsequent {\tt addi} to the right, the least significant {\tt 0xf00} is truncated, leaving {\tt 0x12345} as
instruction will be a negative number. the immediate operand of the {\tt lui} instruction. The addition of
{\tt 0x0800} in this example has no effect on the immediate operand of the {\tt lui}
instruction because bit-11 in the original value {\tt 0x12345700} is zero.
A general algorithm for implementing the {\tt li rd,constant} pseudoinstruction is:
{\small
\begin{verbatim}
lui rd,(constant + 0x00000800) >> 12
addi rd,rd,(constant & 0x00000fff) // the 12-bit immediate is sign extended
\end{verbatim}
}
\enote{Find a proper citation for this.}%
Note that on RV64 and RV128 systems, the {\tt lui} places the immediate operand into
bits 31-12 and then sign-extends the result to {\tt XLEN} bits.
@ -477,10 +503,10 @@ into register x10:
00010900 .word 999 # a 32-bit integer constant stored in memory at address var1 00010900 .word 999 # a 32-bit integer constant stored in memory at address var1
\end{verbatim} \end{verbatim}
} }
The \verb@la@ instruction here will expand into: The \verb@la@ instruction in this example will expand into:
{\small {\small
\begin{verbatim} \begin{verbatim}
00010040 auipc x10,((var1-.) >>U 12) + ((var1-.) & 0x00000800 ? 1 : 0) 00010040 auipc x10,((var1-.) + 0x00000800) >> 12
00010044 addi x10,x10,((var1-(.-4)) & 0x00000fff) 00010044 addi x10,x10,((var1-(.-4)) & 0x00000fff)
\end{verbatim} \end{verbatim}
} }
@ -494,43 +520,39 @@ represented by the label \verb@var1@ from the address of the current instruction
to the target label\ldots{} which is \verb@0x000008c0@. to the target label\ldots{} which is \verb@0x000008c0@.
Therefore the expanded pseudoinstruction example will become: Therefore the expanded pseudoinstruction example will become:
{\small {\small
\begin{verbatim} \begin{verbatim}
00010040 auipc x10,((0x00010900-0x00010040) >>U 12) + ((0x00010900-0x00010040) & 0x00000800 ? 1 : 0) 00010040 auipc x10,((0x00010900 - 0x00010040) + 0x00000800) >> 12
00010044 addi x10,x10,((0x00010900 - (0x00010044 - 4)) & 0x00000fff) # note the extra -4 here! 00010044 addi x10,x10,((0x00010900 - (0x00010044 - 4)) & 0x00000fff) # note the extra -4 here!
\end{verbatim} \end{verbatim}
} }
After performing the subtractions, it will reduce to this: After performing the subtractions, it will reduce to this:
{\small {\small
\begin{verbatim} \begin{verbatim}
00010040 auipc x10,(0x000008c0 >>U 12) + ((0x000008c0) & 0x00000800 ? 1 : 0) 00010040 auipc x10,(0x000008c0 + 0x00000800) >> 12
00010044 addi x10,x10,(0x000008c0 & 0x00000fff) 00010044 addi x10,x10,(0x000008c0 & 0x00000fff)
\end{verbatim} \end{verbatim}
} }
Continuing to reduce the math operations we get: Continuing to reduce the math operations we get:
{\small {\small
\begin{verbatim} \begin{verbatim}
00010040 auipc x10,0x00000 + 1 # add 1 here because 0x8c0 below has MSB = 1 00010040 auipc x10,0x00001 # 0x000008c0 + 0x00000800 = 0x000010c0
00010044 addi x10,x10,0x8c0 00010044 addi x10,x10,0x8c0
\end{verbatim} \end{verbatim}
} }
\ldots and\ldots Note that the \verb@la@ pseudoinstruction exhibits the same sort of technique as
the \verb@li@ in that
{\small
\begin{verbatim}
00010040 auipc x10,0x00001
00010044 addi x10,x10,0x8c0
\end{verbatim}
}
Note that the the \verb@la@ exhibits the same sort of technique as the \verb@li@ in that
if/when the immediate operand of the \verb@addi@ instruction has its most significant if/when the immediate operand of the \verb@addi@ instruction has its most significant
bit set then the operand in the \verb@auipc@ has to be incremented by 1 to compensate. bit set then the operand in the \verb@auipc@ has to be incremented by 1 to compensate.
\section{Relocation} \section{Relocation}
Because expressions that refer to constants and address labels are common in Because expressions that refer to constants and address labels are common in
@ -545,12 +567,12 @@ that appears in instructions like \verb@addi@ and \verb@jalr@.)
To refer to an absolute value, the following operators can be used: To refer to an absolute value, the following operators can be used:
{\small {\small
\begin{verbatim} \begin{verbatim}
%hi(constant) // becomes: (constant >>U 12)+(constant & 0x00000800 ? 1 : 0) %hi(constant) // becomes: (constant + 0x00000800) >> 12
%lo(constant) // becomes: (constant & 0x00000fff) %lo(constant) // becomes: (constant & 0x00000fff)
\end{verbatim} \end{verbatim}
} }
Thus, the \verb@li@ pseudoinstruction can be expressed like this: Thus, the \verb@li@ pseudoinstruction can, therefore, be expressed like this:
{\small {\small
\begin{verbatim} \begin{verbatim}
@ -566,7 +588,7 @@ Thus, the \verb@li@ pseudoinstruction can be expressed like this:
The following can be used for PC-relative addresses: The following can be used for PC-relative addresses:
{\small {\small
\begin{verbatim} \begin{verbatim}
%pcrel_hi(symbol) // becomes: ((symbol-.) >>U 12) + ((symbol-.) & 0x00000800 ? 1 : 0) %pcrel_hi(symbol) // becomes: ((symbol-.) + 0x0800) >> 12
%pcrel_lo(lab) // becomes: ((symbol-lab) & 0x00000fff) %pcrel_lo(lab) // becomes: ((symbol-lab) & 0x00000fff)
\end{verbatim} \end{verbatim}
} }
@ -589,7 +611,7 @@ Examples of using the \verb@auipc@ \& \verb@addi@ together with \verb@%pcrel_hi(
{\small {\small
\begin{verbatim} \begin{verbatim}
xxx: auipc t1,%pcrel_hi(yyy) // (yyy-.) >>U 12) + ((yyy-.) & 0x00000800 ? 1 : 0) xxx: auipc t1,%pcrel_hi(yyy) // ((yyy-.) + 0x0800) >> 12
addi t1,t1,%pcrel_lo(xxx) // ((yyy-xxx) & 0x00000fff) addi t1,t1,%pcrel_lo(xxx) // ((yyy-xxx) & 0x00000fff)
... ...
yyy: // the address: yyy is saved into t1 above yyy: // the address: yyy is saved into t1 above
@ -610,9 +632,13 @@ label: auipc t1,%pcrel_hi(symbol)
\end{verbatim} \end{verbatim}
} }
\section{Relaxation} \section{Relaxation}
\enote{I'm not sure I want to get into the details of how this is done. Just assume it works.}% %\enote{I'm not sure I want to get into the details of how this is done. Just assume it works.}%
In the simplest of terms, {\em Relaxation} refers to the ability of the In the simplest of terms, {\em Relaxation} refers to the ability of the
linker (not the compiler!) to determine if/when the instructions that linker (not the compiler!) to determine if/when the instructions that
were generated with the \verb@xxx_hi@ and \verb@xxx_lo@ operators are were generated with the \verb@xxx_hi@ and \verb@xxx_lo@ operators are