Skip to content

Commit b24aec5

Browse files
markdryangopherbot
authored andcommitted
doc, cmd/internal/obj/riscv: document the riscv64 assembler
Add documentation for the riscv64 assembler with a link to the documentation from asm.html. Architecture specific assembler documentation is provided for the other architectures but has been missing for riscv64 until now. Change-Id: I62ed7e6a2a4b52e0720d869e964b29e2a980223a Reviewed-on: https://go-review.googlesource.com/c/go/+/652717 Reviewed-by: Joel Sing <[email protected]> Reviewed-by: Michael Pratt <[email protected]> Reviewed-by: Meng Zhuo <[email protected]> Auto-Submit: Joel Sing <[email protected]> Reviewed-by: Junyang Shao <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
1 parent a0e738c commit b24aec5

File tree

2 files changed

+303
-0
lines changed

2 files changed

+303
-0
lines changed

doc/asm.html

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1039,6 +1039,12 @@ <h3 id="mips">MIPS, MIPS64</h3>
10391039
<code>GOMIPS64_hardfloat</code> or <code>GOMIPS64_softfloat</code>.
10401040
</p>
10411041

1042+
<h3 id="riscv64">RISCV64</h3>
1043+
1044+
<p>
1045+
Reference: <a href="/pkg/cmd/internal/obj/riscv">Go RISCV64 Assembly Instructions Reference Manual</a>
1046+
</p>
1047+
10421048
<h3 id="unsupported_opcodes">Unsupported opcodes</h3>
10431049

10441050
<p>

src/cmd/internal/obj/riscv/doc.go

Lines changed: 297 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,297 @@
1+
// Copyright 2025 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
/*
6+
Package riscv implements the riscv64 assembler.
7+
8+
# Register naming
9+
10+
The integer registers are named X0 through to X31, however X4 must be accessed
11+
through its RISC-V ABI name, TP, and X27, which holds a pointer to the Go
12+
routine structure, must be referred to as g. Additionally, when building in
13+
shared mode, X3 is unavailable and must be accessed via its RISC-V ABI name,
14+
GP.
15+
16+
The floating-point registers are named F0 through to F31.
17+
18+
The vector registers are named V0 through to V31.
19+
20+
Both integer and floating-point registers can be referred to by their RISC-V
21+
ABI names, e.g., A0 or FT0, with the exception that X27 cannot be referred to
22+
by its RISC-V ABI name, S11. It must be referred to as g.
23+
24+
Some of the integer registers are used by the Go runtime and assembler - X26 is
25+
the closure pointer, X27 points to the Go routine structure and X31 is a
26+
temporary register used by the Go assembler. Use of X31 should be avoided in
27+
hand written assembly code as its value could be altered by the instruction
28+
sequences emitted by the assembler.
29+
30+
# Instruction naming
31+
32+
Many RISC-V instructions contain one or more suffixes in their names. In the
33+
[RISC-V ISA Manual] these suffixes are separated from themselves and the
34+
name of the instruction mnemonic with a dot ('.'). In the Go assembler, the
35+
separators are omitted and the suffixes are written in upper case.
36+
37+
Example:
38+
39+
FMVWX <=> fmv.w.x
40+
41+
# Rounding modes
42+
43+
The Go toolchain does not set the FCSR register and requires the desired
44+
rounding mode to be explicitly encoded within floating-point instructions.
45+
The syntax the Go assembler uses to specify the rounding modes differs
46+
from the syntax in the RISC-V specifications. In the [RISC-V ISA Manual]
47+
the rounding mode is given as an extra operand at the end of an
48+
assembly language instruction. In the Go assembler, the rounding modes are
49+
converted to uppercase and follow the instruction mnemonic from which they
50+
are separated with a dot ('.').
51+
52+
Example:
53+
54+
FCVTLUS.RNE F0, X5 <=> fcvt.lu.s x5, f0, rne
55+
56+
RTZ is assumed if the rounding mode is omitted.
57+
58+
# RISC-V extensions
59+
60+
By default the Go compiler targets the [rva20u64] profile. This profile mandates
61+
all the general RISC-V instructions, allowing Go to use integer, multiplication,
62+
division, floating-point and atomic instructions without having to
63+
perform compile time or runtime checks to verify that their use is appropriate
64+
for the target hardware. All widely available riscv64 devices support at least
65+
[rva20u64]. The Go toolchain can be instructed to target later RISC-V profiles,
66+
including, [rva22u64] and [rva23u64], via the GORISCV64 environment variable.
67+
Instructions that are provided by newer profiles cannot typically be used in
68+
handwritten assembly code without compile time guards (or runtime checks)
69+
that ensure they are hardware supported.
70+
71+
The file asm_riscv64.h defines macros for each RISC-V extension that is enabled
72+
by setting the GORISCV64 environment variable to a value other than [rva20u64].
73+
For example, if GORISCV64=rva22u64 the macros hasZba, hasZbb and hasZbs will be
74+
defined. If GORISCV64=rva23u64 hasV will be defined in addition to hasZba,
75+
hasZbb and hasZbs. These macros can be used to determine whether it's safe
76+
to use an instruction in hand-written assembly.
77+
78+
It is not always necessary to include asm_riscv64.h and use #ifdefs in your
79+
code to safely take advantage of instructions present in the [rva22u64]
80+
profile. In some cases the assembler can generate [rva20u64] compatible code
81+
even when an [rva22u64] instruction is used in an assembly source file. When
82+
GORISCV64=rva20u64 the assembler will synthesize certain [rva22u64]
83+
instructions, e.g., ANDN, using multiple [rva20u64] instructions. Instructions
84+
such as ANDN can then be freely used in assembly code without checking to see
85+
whether the instruction is supported by the target profile. When building a
86+
source file containing the ANDN instruction with GORISCV64=rva22u64 the
87+
assembler will emit the Zbb ANDN instruction directly. When building the same
88+
source file with GORISCV64=rva20u64 the assembler will emit multiple [rva20u64]
89+
instructions to synthesize ANDN.
90+
91+
The assembler will also use [rva22u64] instructions to implement the zero and
92+
sign extension instructions, e.g., MOVB and MOVHU, when GORISCV64=rva22u64 or
93+
greater.
94+
95+
The instructions not implemented in the default profile ([rva20u64]) that can
96+
be safely used in assembly code without compile time checks are:
97+
98+
- ANDN
99+
- MAX
100+
- MAXU
101+
- MIN
102+
- MINU
103+
- MOVB
104+
- MOVH
105+
- MOVHU
106+
- MOVWU
107+
- ORN
108+
- ROL
109+
- ROLW
110+
- ROR
111+
- RORI
112+
- RORIW
113+
- RORW
114+
- XNOR
115+
116+
# Operand ordering
117+
118+
The ordering used for instruction operands in the Go assembler differs from the
119+
ordering defined in the [RISC-V ISA Manual].
120+
121+
1. R-Type instructions
122+
123+
R-Type instructions are written in the reverse order to that given in the
124+
[RISC-V ISA Manual], with the register order being rs2, rs1, rd.
125+
126+
Examples:
127+
128+
ADD X10, X11, X12 <=> add x12, x11, x10
129+
FADDD F10, F11, F12 <=> fadd.d f12, f11, f10
130+
131+
2. I-Type arithmetic instructions
132+
133+
I-Type arithmetic instructions (not loads, fences, ebreak, ecall) use the same
134+
ordering as the R-Type instructions, typically, imm12, rs1, rd.
135+
136+
Examples:
137+
138+
ADDI $1, X11, X12 <=> add x12, x11, 1
139+
SLTI $1, X11, X12 <=> slti x12, x11, 1
140+
141+
3. Loads and Stores
142+
143+
Load instructions are written with the source operand (whether it be a register
144+
or a memory address), first followed by the destination operand.
145+
146+
Examples:
147+
148+
MOV 16(X2), X10 <=> ld x10, 16(x2)
149+
MOV X10, (X2) <=> sd x10, 0(x2)
150+
151+
4. Branch instructions
152+
153+
The branch instructions use the same operand ordering as is given in the
154+
[RISC-V ISA Manual], e.g., rs1, rs2, label.
155+
156+
Example:
157+
158+
BLT X12, X23, loop1 <=> blt x12, x23, loop1
159+
160+
BLT X12, X23, label will jump to label if X12 < X23. Note this is not the
161+
same ordering as is used for the SLT instructions.
162+
163+
5. FMA instructions
164+
165+
The Go assembler uses a different ordering for the RISC-V FMA operands to
166+
the ordering given in the [RISC-V ISA Manual]. The operands are rotated one
167+
place to the left, so that the destination operand comes last.
168+
169+
Example:
170+
171+
FMADDS F1, F2, F3, F4 <=> fmadd.s f4, f1, f2, f3
172+
173+
6. AMO instructions
174+
175+
The ordering used for the AMO operations is rs2, rs1, rd, i.e., the operands
176+
as specified in the [RISC-V ISA Manual] are rotated one place to the left.
177+
178+
Example:
179+
180+
AMOSWAPW X5, (X6), X7 <=> amoswap.w x7, x5, (x6)
181+
182+
7. Vector instructions
183+
184+
The VSETVLI instruction uses the same symbolic names as the [RISC-V ISA Manual]
185+
to represent the components of vtype, with the exception
186+
that they are written in upper case. The ordering of the operands in the Go
187+
assembler differs from the [RISC-V ISA Manual] in that the operands are
188+
rotated one place to the left so that the destination register, the register
189+
that holds the new vl, is the last operand.
190+
191+
Example:
192+
193+
VSETVLI X10, E8, M1, TU, MU, X12 <=> vsetvli x12, x10, e8, m1, tu, mu
194+
195+
Vector load and store instructions follow the pattern set by scalar loads and
196+
stores, i.e., the source is always the first operand and the destination the
197+
last. However, the ordering of the operands of these instructions is
198+
complicated by the optional mask register and, in some cases, the use of an
199+
additional stride or index register. In the Go assembler the index and stride
200+
registers appear as the second operand in indexed or strided loads and stores,
201+
while the mask register, if present, is always the penultimate operand.
202+
203+
Examples:
204+
205+
VLE8V (X10), V3 <=> vle8.v v3, (x10)
206+
VSE8V V3, (X10) <=> vse8.v v3, (x10)
207+
VLE8V (X10), V0, V3 <=> vle8.v v3, (x10), v0.t
208+
VSE8V V3, V0, (X10) <=> vse8.v v3, (x10), v0.t
209+
VLSE8V (X10), X11, V3 <=> vlse8.v v3, (x10), x11
210+
VSSE8V V3, X11, (X10) <=> vsse8.v v3, (x10), x11
211+
VLSE8V (X10), X11, V0, V3 <=> vlse8.v v3, (x10), x11, v0.t
212+
VSSE8V V3, X11, V0, (X10) <=> vsse8.v v3, (x10), x11, v0.t
213+
VLUXEI8V (X10), V2, V3 <=> vluxei8.v v3, (x10), v2
214+
VSUXEI8V V3, V2, (X10) <=> vsuxei8.v v3, (x10), v2
215+
VLUXEI8V (X10), V2, V0, V3 <=> vluxei8.v v3, (x10), v2, v0.t
216+
VSUXEI8V V3, V2, V0, (X10) <=> vsuxei8.v v3, (x10), v2, v0.t
217+
VL1RE8V (X10), V3 <=> vl1re8.v v3, (x10)
218+
VS1RV V3, (X11) <=> vs1r.v v3, (x11)
219+
220+
The ordering of operands for two and three argument vector arithmetic instructions is
221+
reversed in the Go assembler.
222+
223+
Examples:
224+
225+
VMVVV V2, V3 <=> vmv.v.v v3, v2
226+
VADDVV V1, V2, V3 <=> vadd.vv v3, v2, v1
227+
VADDVX X10, V2, V3 <=> vadd.vx v3, v2, x10
228+
VMADCVI $15, V2, V3 <=> vmadc.vi v3, v2, 15
229+
230+
The mask register, when specified, is always the penultimate operand in a vector
231+
arithmetic instruction, appearing before the destination register.
232+
233+
Examples:
234+
235+
VANDVV V1, V2, V0, V3 <=> vand.vv v3, v2, v1, v0.t
236+
237+
# Ternary instructions
238+
239+
The Go assembler allows the second operand to be omitted from most ternary
240+
instructions if it matches the third (destination) operand.
241+
242+
Examples:
243+
244+
ADD X10, X12, X12 <=> ADD X10, X12
245+
ANDI $3, X12, X12 <=> ANDI $3, X12
246+
247+
The use of this abbreviated syntax is encouraged.
248+
249+
# Ordering of atomic instructions
250+
251+
It is not possible to specify the ordering bits in the FENCE, LR, SC or AMO
252+
instructions. The FENCE instruction is always emitted as a full fence, the
253+
acquire and release bits are always set for the AMO instructions, the acquire
254+
bit is always set for the LR instructions while the release bit is set for
255+
the SC instructions.
256+
257+
# Immediate operands
258+
259+
In many cases, where an R-Type instruction has a corresponding I-Type
260+
instruction, the R-Type mnemonic can be used in place of the I-Type mnemonic.
261+
The assembler assumes that the immediate form of the instruction was intended
262+
when the first operand is given as an immediate value rather than a register.
263+
264+
Example:
265+
266+
AND $3, X12, X13 <=> ANDI $3, X12, X13
267+
268+
# Integer constant materialization
269+
270+
The MOV instruction can be used to set a register to the value of any 64 bit
271+
constant literal. The way this is achieved by the assembler varies depending
272+
on the value of the constant. Where possible the assembler will synthesize the
273+
constant using one or more RISC-V arithmetic instructions. If it is unable
274+
to easily materialize the constant it will load the 64 bit literal from memory.
275+
276+
A 32 bit constant literal can be specified as an argument to ADDI, ANDI, ORI and
277+
XORI. If the specified literal does not fit into 12 bits the assembler will
278+
generate extra instructions to synthesize it.
279+
280+
Integer constants provided as operands to all other instructions must fit into
281+
the number of bits allowed by the instructions' encodings for immediate values.
282+
Otherwise, an error will be generated.
283+
284+
# Floating point constant materialization
285+
286+
The MOVF and MOVD instructions can be used to set a register to the value
287+
of any 32 bit or 64 bit floating point constant literal, respectively. Unless
288+
the constant literal is 0.0, MOVF and MOVD will be encoded as FLW and FLD
289+
instructions that load the constant from a location within the program's
290+
binary.
291+
292+
[RISC-V ISA Manual]: https://github.com/riscv/riscv-isa-manual
293+
[rva20u64]: https://github.com/riscv/riscv-profiles/blob/main/src/profiles.adoc#51-rva20u64-profile
294+
[rva22u64]: https://github.com/riscv/riscv-profiles/blob/main/src/profiles.adoc#rva22u64-profile
295+
[rva23u64]: https://github.com/riscv/riscv-profiles/blob/main/src/rva23-profile.adoc#rva23u64-profile
296+
*/
297+
package riscv

0 commit comments

Comments
 (0)