|
| 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