]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/compile/internal/ssa/gen/RISCV64Ops.go
[dev.cmdgo] all: merge master (912f075) into dev.cmdgo
[gostls13.git] / src / cmd / compile / internal / ssa / gen / RISCV64Ops.go
1 // Copyright 2016 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 //go:build ignore
6 // +build ignore
7
8 package main
9
10 import (
11         "fmt"
12 )
13
14 // Notes:
15 //  - Boolean types occupy the entire register. 0=false, 1=true.
16
17 // Suffixes encode the bit width of various instructions:
18 //
19 // D (double word) = 64 bit int
20 // W (word)        = 32 bit int
21 // H (half word)   = 16 bit int
22 // B (byte)        = 8 bit int
23 // S (single)      = 32 bit float
24 // D (double)      = 64 bit float
25 // L               = 64 bit int, used when the opcode starts with F
26
27 const (
28         riscv64REG_G    = 27
29         riscv64REG_CTXT = 20
30         riscv64REG_LR   = 1
31         riscv64REG_SP   = 2
32         riscv64REG_TP   = 4
33         riscv64REG_TMP  = 31
34         riscv64REG_ZERO = 0
35 )
36
37 func riscv64RegName(r int) string {
38         switch {
39         case r == riscv64REG_G:
40                 return "g"
41         case r == riscv64REG_SP:
42                 return "SP"
43         case 0 <= r && r <= 31:
44                 return fmt.Sprintf("X%d", r)
45         case 32 <= r && r <= 63:
46                 return fmt.Sprintf("F%d", r-32)
47         default:
48                 panic(fmt.Sprintf("unknown register %d", r))
49         }
50 }
51
52 func init() {
53         var regNamesRISCV64 []string
54         var gpMask, fpMask, gpgMask, gpspMask, gpspsbMask, gpspsbgMask regMask
55         regNamed := make(map[string]regMask)
56
57         // Build the list of register names, creating an appropriately indexed
58         // regMask for the gp and fp registers as we go.
59         //
60         // If name is specified, use it rather than the riscv reg number.
61         addreg := func(r int, name string) regMask {
62                 mask := regMask(1) << uint(len(regNamesRISCV64))
63                 if name == "" {
64                         name = riscv64RegName(r)
65                 }
66                 regNamesRISCV64 = append(regNamesRISCV64, name)
67                 regNamed[name] = mask
68                 return mask
69         }
70
71         // General purpose registers.
72         for r := 0; r <= 31; r++ {
73                 if r == riscv64REG_LR {
74                         // LR is not used by regalloc, so we skip it to leave
75                         // room for pseudo-register SB.
76                         continue
77                 }
78
79                 mask := addreg(r, "")
80
81                 // Add general purpose registers to gpMask.
82                 switch r {
83                 // ZERO, TP and TMP are not in any gp mask.
84                 case riscv64REG_ZERO, riscv64REG_TP, riscv64REG_TMP:
85                 case riscv64REG_G:
86                         gpgMask |= mask
87                         gpspsbgMask |= mask
88                 case riscv64REG_SP:
89                         gpspMask |= mask
90                         gpspsbMask |= mask
91                         gpspsbgMask |= mask
92                 default:
93                         gpMask |= mask
94                         gpgMask |= mask
95                         gpspMask |= mask
96                         gpspsbMask |= mask
97                         gpspsbgMask |= mask
98                 }
99         }
100
101         // Floating pointer registers.
102         for r := 32; r <= 63; r++ {
103                 mask := addreg(r, "")
104                 fpMask |= mask
105         }
106
107         // Pseudo-register: SB
108         mask := addreg(-1, "SB")
109         gpspsbMask |= mask
110         gpspsbgMask |= mask
111
112         if len(regNamesRISCV64) > 64 {
113                 // regMask is only 64 bits.
114                 panic("Too many RISCV64 registers")
115         }
116
117         regCtxt := regNamed["X20"]
118         callerSave := gpMask | fpMask | regNamed["g"]
119
120         var (
121                 gpstore  = regInfo{inputs: []regMask{gpspsbMask, gpspMask, 0}} // SB in first input so we can load from a global, but not in second to avoid using SB as a temporary register
122                 gpstore0 = regInfo{inputs: []regMask{gpspsbMask}}
123                 gp01     = regInfo{outputs: []regMask{gpMask}}
124                 gp11     = regInfo{inputs: []regMask{gpMask}, outputs: []regMask{gpMask}}
125                 gp21     = regInfo{inputs: []regMask{gpMask, gpMask}, outputs: []regMask{gpMask}}
126                 gpload   = regInfo{inputs: []regMask{gpspsbMask, 0}, outputs: []regMask{gpMask}}
127                 gp11sb   = regInfo{inputs: []regMask{gpspsbMask}, outputs: []regMask{gpMask}}
128                 gpxchg   = regInfo{inputs: []regMask{gpspsbgMask, gpgMask}, outputs: []regMask{gpMask}}
129                 gpcas    = regInfo{inputs: []regMask{gpspsbgMask, gpgMask, gpgMask}, outputs: []regMask{gpMask}}
130                 gpatomic = regInfo{inputs: []regMask{gpspsbgMask, gpgMask}}
131
132                 fp11    = regInfo{inputs: []regMask{fpMask}, outputs: []regMask{fpMask}}
133                 fp21    = regInfo{inputs: []regMask{fpMask, fpMask}, outputs: []regMask{fpMask}}
134                 gpfp    = regInfo{inputs: []regMask{gpMask}, outputs: []regMask{fpMask}}
135                 fpgp    = regInfo{inputs: []regMask{fpMask}, outputs: []regMask{gpMask}}
136                 fpstore = regInfo{inputs: []regMask{gpspsbMask, fpMask, 0}}
137                 fpload  = regInfo{inputs: []regMask{gpspsbMask, 0}, outputs: []regMask{fpMask}}
138                 fp2gp   = regInfo{inputs: []regMask{fpMask, fpMask}, outputs: []regMask{gpMask}}
139
140                 call        = regInfo{clobbers: callerSave}
141                 callClosure = regInfo{inputs: []regMask{gpspMask, regCtxt, 0}, clobbers: callerSave}
142                 callInter   = regInfo{inputs: []regMask{gpMask}, clobbers: callerSave}
143         )
144
145         RISCV64ops := []opData{
146                 {name: "ADD", argLength: 2, reg: gp21, asm: "ADD", commutative: true}, // arg0 + arg1
147                 {name: "ADDI", argLength: 1, reg: gp11sb, asm: "ADDI", aux: "Int64"},  // arg0 + auxint
148                 {name: "ADDIW", argLength: 1, reg: gp11, asm: "ADDIW", aux: "Int64"},  // 32 low bits of arg0 + auxint, sign extended to 64 bits
149                 {name: "NEG", argLength: 1, reg: gp11, asm: "NEG"},                    // -arg0
150                 {name: "NEGW", argLength: 1, reg: gp11, asm: "NEGW"},                  // -arg0 of 32 bits, sign extended to 64 bits
151                 {name: "SUB", argLength: 2, reg: gp21, asm: "SUB"},                    // arg0 - arg1
152                 {name: "SUBW", argLength: 2, reg: gp21, asm: "SUBW"},                  // 32 low bits of arg 0 - 32 low bits of arg 1, sign extended to 64 bits
153
154                 // M extension. H means high (i.e., it returns the top bits of
155                 // the result). U means unsigned. W means word (i.e., 32-bit).
156                 {name: "MUL", argLength: 2, reg: gp21, asm: "MUL", commutative: true, typ: "Int64"}, // arg0 * arg1
157                 {name: "MULW", argLength: 2, reg: gp21, asm: "MULW", commutative: true, typ: "Int32"},
158                 {name: "MULH", argLength: 2, reg: gp21, asm: "MULH", commutative: true, typ: "Int64"},
159                 {name: "MULHU", argLength: 2, reg: gp21, asm: "MULHU", commutative: true, typ: "UInt64"},
160                 {name: "DIV", argLength: 2, reg: gp21, asm: "DIV", typ: "Int64"}, // arg0 / arg1
161                 {name: "DIVU", argLength: 2, reg: gp21, asm: "DIVU", typ: "UInt64"},
162                 {name: "DIVW", argLength: 2, reg: gp21, asm: "DIVW", typ: "Int32"},
163                 {name: "DIVUW", argLength: 2, reg: gp21, asm: "DIVUW", typ: "UInt32"},
164                 {name: "REM", argLength: 2, reg: gp21, asm: "REM", typ: "Int64"}, // arg0 % arg1
165                 {name: "REMU", argLength: 2, reg: gp21, asm: "REMU", typ: "UInt64"},
166                 {name: "REMW", argLength: 2, reg: gp21, asm: "REMW", typ: "Int32"},
167                 {name: "REMUW", argLength: 2, reg: gp21, asm: "REMUW", typ: "UInt32"},
168
169                 {name: "MOVaddr", argLength: 1, reg: gp11sb, asm: "MOV", aux: "SymOff", rematerializeable: true, symEffect: "RdWr"}, // arg0 + auxint + offset encoded in aux
170                 // auxint+aux == add auxint and the offset of the symbol in aux (if any) to the effective address
171
172                 {name: "MOVDconst", reg: gp01, asm: "MOV", typ: "UInt64", aux: "Int64", rematerializeable: true}, // auxint
173
174                 // Loads: load <size> bits from arg0+auxint+aux and extend to 64 bits; arg1=mem
175                 {name: "MOVBload", argLength: 2, reg: gpload, asm: "MOVB", aux: "SymOff", typ: "Int8", faultOnNilArg0: true, symEffect: "Read"},     //  8 bits, sign extend
176                 {name: "MOVHload", argLength: 2, reg: gpload, asm: "MOVH", aux: "SymOff", typ: "Int16", faultOnNilArg0: true, symEffect: "Read"},    // 16 bits, sign extend
177                 {name: "MOVWload", argLength: 2, reg: gpload, asm: "MOVW", aux: "SymOff", typ: "Int32", faultOnNilArg0: true, symEffect: "Read"},    // 32 bits, sign extend
178                 {name: "MOVDload", argLength: 2, reg: gpload, asm: "MOV", aux: "SymOff", typ: "Int64", faultOnNilArg0: true, symEffect: "Read"},     // 64 bits
179                 {name: "MOVBUload", argLength: 2, reg: gpload, asm: "MOVBU", aux: "SymOff", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read"},  //  8 bits, zero extend
180                 {name: "MOVHUload", argLength: 2, reg: gpload, asm: "MOVHU", aux: "SymOff", typ: "UInt16", faultOnNilArg0: true, symEffect: "Read"}, // 16 bits, zero extend
181                 {name: "MOVWUload", argLength: 2, reg: gpload, asm: "MOVWU", aux: "SymOff", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read"}, // 32 bits, zero extend
182
183                 // Stores: store <size> lowest bits in arg1 to arg0+auxint+aux; arg2=mem
184                 {name: "MOVBstore", argLength: 3, reg: gpstore, asm: "MOVB", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, //  8 bits
185                 {name: "MOVHstore", argLength: 3, reg: gpstore, asm: "MOVH", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // 16 bits
186                 {name: "MOVWstore", argLength: 3, reg: gpstore, asm: "MOVW", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // 32 bits
187                 {name: "MOVDstore", argLength: 3, reg: gpstore, asm: "MOV", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},  // 64 bits
188
189                 // Stores: store <size> of zero in arg0+auxint+aux; arg1=mem
190                 {name: "MOVBstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVB", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, //  8 bits
191                 {name: "MOVHstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVH", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // 16 bits
192                 {name: "MOVWstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVW", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // 32 bits
193                 {name: "MOVDstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOV", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},  // 64 bits
194
195                 // Conversions
196                 {name: "MOVBreg", argLength: 1, reg: gp11, asm: "MOVB"},   // move from arg0, sign-extended from byte
197                 {name: "MOVHreg", argLength: 1, reg: gp11, asm: "MOVH"},   // move from arg0, sign-extended from half
198                 {name: "MOVWreg", argLength: 1, reg: gp11, asm: "MOVW"},   // move from arg0, sign-extended from word
199                 {name: "MOVDreg", argLength: 1, reg: gp11, asm: "MOV"},    // move from arg0
200                 {name: "MOVBUreg", argLength: 1, reg: gp11, asm: "MOVBU"}, // move from arg0, unsign-extended from byte
201                 {name: "MOVHUreg", argLength: 1, reg: gp11, asm: "MOVHU"}, // move from arg0, unsign-extended from half
202                 {name: "MOVWUreg", argLength: 1, reg: gp11, asm: "MOVWU"}, // move from arg0, unsign-extended from word
203
204                 {name: "MOVDnop", argLength: 1, reg: regInfo{inputs: []regMask{gpMask}, outputs: []regMask{gpMask}}, resultInArg0: true}, // nop, return arg0 in same register
205
206                 // Shift ops
207                 {name: "SLL", argLength: 2, reg: gp21, asm: "SLL"},                 // arg0 << (aux1 & 63)
208                 {name: "SRA", argLength: 2, reg: gp21, asm: "SRA"},                 // arg0 >> (aux1 & 63), signed
209                 {name: "SRL", argLength: 2, reg: gp21, asm: "SRL"},                 // arg0 >> (aux1 & 63), unsigned
210                 {name: "SLLI", argLength: 1, reg: gp11, asm: "SLLI", aux: "Int64"}, // arg0 << auxint, shift amount 0-63
211                 {name: "SRAI", argLength: 1, reg: gp11, asm: "SRAI", aux: "Int64"}, // arg0 >> auxint, signed, shift amount 0-63
212                 {name: "SRLI", argLength: 1, reg: gp11, asm: "SRLI", aux: "Int64"}, // arg0 >> auxint, unsigned, shift amount 0-63
213
214                 // Bitwise ops
215                 {name: "XOR", argLength: 2, reg: gp21, asm: "XOR", commutative: true}, // arg0 ^ arg1
216                 {name: "XORI", argLength: 1, reg: gp11, asm: "XORI", aux: "Int64"},    // arg0 ^ auxint
217                 {name: "OR", argLength: 2, reg: gp21, asm: "OR", commutative: true},   // arg0 | arg1
218                 {name: "ORI", argLength: 1, reg: gp11, asm: "ORI", aux: "Int64"},      // arg0 | auxint
219                 {name: "AND", argLength: 2, reg: gp21, asm: "AND", commutative: true}, // arg0 & arg1
220                 {name: "ANDI", argLength: 1, reg: gp11, asm: "ANDI", aux: "Int64"},    // arg0 & auxint
221                 {name: "NOT", argLength: 1, reg: gp11, asm: "NOT"},                    // ^arg0
222
223                 // Generate boolean values
224                 {name: "SEQZ", argLength: 1, reg: gp11, asm: "SEQZ"},                 // arg0 == 0, result is 0 or 1
225                 {name: "SNEZ", argLength: 1, reg: gp11, asm: "SNEZ"},                 // arg0 != 0, result is 0 or 1
226                 {name: "SLT", argLength: 2, reg: gp21, asm: "SLT"},                   // arg0 < arg1, result is 0 or 1
227                 {name: "SLTI", argLength: 1, reg: gp11, asm: "SLTI", aux: "Int64"},   // arg0 < auxint, result is 0 or 1
228                 {name: "SLTU", argLength: 2, reg: gp21, asm: "SLTU"},                 // arg0 < arg1, unsigned, result is 0 or 1
229                 {name: "SLTIU", argLength: 1, reg: gp11, asm: "SLTIU", aux: "Int64"}, // arg0 < auxint, unsigned, result is 0 or 1
230
231                 // MOVconvert converts between pointers and integers.
232                 // We have a special op for this so as to not confuse GC
233                 // (particularly stack maps). It takes a memory arg so it
234                 // gets correctly ordered with respect to GC safepoints.
235                 {name: "MOVconvert", argLength: 2, reg: gp11, asm: "MOV"}, // arg0, but converted to int/ptr as appropriate; arg1=mem
236
237                 // Calls
238                 {name: "CALLstatic", argLength: 1, reg: call, aux: "CallOff", call: true},         // call static function aux.(*gc.Sym). arg0=mem, auxint=argsize, returns mem
239                 {name: "CALLclosure", argLength: 3, reg: callClosure, aux: "CallOff", call: true}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
240                 {name: "CALLinter", argLength: 2, reg: callInter, aux: "CallOff", call: true},     // call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem
241
242                 // duffzero
243                 // arg0 = address of memory to zero (in X10, changed as side effect)
244                 // arg1 = mem
245                 // auxint = offset into duffzero code to start executing
246                 // X1 (link register) changed because of function call
247                 // returns mem
248                 {
249                         name:      "DUFFZERO",
250                         aux:       "Int64",
251                         argLength: 2,
252                         reg: regInfo{
253                                 inputs:   []regMask{regNamed["X10"]},
254                                 clobbers: regNamed["X1"] | regNamed["X10"],
255                         },
256                         typ:            "Mem",
257                         faultOnNilArg0: true,
258                 },
259
260                 // duffcopy
261                 // arg0 = address of dst memory (in X11, changed as side effect)
262                 // arg1 = address of src memory (in X10, changed as side effect)
263                 // arg2 = mem
264                 // auxint = offset into duffcopy code to start executing
265                 // X1 (link register) changed because of function call
266                 // returns mem
267                 {
268                         name:      "DUFFCOPY",
269                         aux:       "Int64",
270                         argLength: 3,
271                         reg: regInfo{
272                                 inputs:   []regMask{regNamed["X11"], regNamed["X10"]},
273                                 clobbers: regNamed["X1"] | regNamed["X10"] | regNamed["X11"],
274                         },
275                         typ:            "Mem",
276                         faultOnNilArg0: true,
277                         faultOnNilArg1: true,
278                 },
279
280                 // Generic moves and zeros
281
282                 // general unaligned zeroing
283                 // arg0 = address of memory to zero (in X5, changed as side effect)
284                 // arg1 = address of the last element to zero (inclusive)
285                 // arg2 = mem
286                 // auxint = element size
287                 // returns mem
288                 //      mov     ZERO, (X5)
289                 //      ADD     $sz, X5
290                 //      BGEU    Rarg1, X5, -2(PC)
291                 {
292                         name:      "LoweredZero",
293                         aux:       "Int64",
294                         argLength: 3,
295                         reg: regInfo{
296                                 inputs:   []regMask{regNamed["X5"], gpMask},
297                                 clobbers: regNamed["X5"],
298                         },
299                         typ:            "Mem",
300                         faultOnNilArg0: true,
301                 },
302
303                 // general unaligned move
304                 // arg0 = address of dst memory (in X5, changed as side effect)
305                 // arg1 = address of src memory (in X6, changed as side effect)
306                 // arg2 = address of the last element of src (can't be X7 as we clobber it before using arg2)
307                 // arg3 = mem
308                 // auxint = alignment
309                 // clobbers X7 as a tmp register.
310                 // returns mem
311                 //      mov     (X6), X7
312                 //      mov     X7, (X5)
313                 //      ADD     $sz, X5
314                 //      ADD     $sz, X6
315                 //      BGEU    Rarg2, X5, -4(PC)
316                 {
317                         name:      "LoweredMove",
318                         aux:       "Int64",
319                         argLength: 4,
320                         reg: regInfo{
321                                 inputs:   []regMask{regNamed["X5"], regNamed["X6"], gpMask &^ regNamed["X7"]},
322                                 clobbers: regNamed["X5"] | regNamed["X6"] | regNamed["X7"],
323                         },
324                         typ:            "Mem",
325                         faultOnNilArg0: true,
326                         faultOnNilArg1: true,
327                 },
328
329                 // Atomic loads.
330                 // load from arg0. arg1=mem.
331                 // returns <value,memory> so they can be properly ordered with other loads.
332                 {name: "LoweredAtomicLoad8", argLength: 2, reg: gpload, faultOnNilArg0: true},
333                 {name: "LoweredAtomicLoad32", argLength: 2, reg: gpload, faultOnNilArg0: true},
334                 {name: "LoweredAtomicLoad64", argLength: 2, reg: gpload, faultOnNilArg0: true},
335
336                 // Atomic stores.
337                 // store arg1 to *arg0. arg2=mem. returns memory.
338                 {name: "LoweredAtomicStore8", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true},
339                 {name: "LoweredAtomicStore32", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true},
340                 {name: "LoweredAtomicStore64", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true},
341
342                 // Atomic exchange.
343                 // store arg1 to *arg0. arg2=mem. returns <old content of *arg0, memory>.
344                 {name: "LoweredAtomicExchange32", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true},
345                 {name: "LoweredAtomicExchange64", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true},
346
347                 // Atomic add.
348                 // *arg0 += arg1. arg2=mem. returns <new content of *arg0, memory>.
349                 {name: "LoweredAtomicAdd32", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
350                 {name: "LoweredAtomicAdd64", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
351
352                 // Atomic compare and swap.
353                 // arg0 = pointer, arg1 = old value, arg2 = new value, arg3 = memory.
354                 // if *arg0 == arg1 {
355                 //   *arg0 = arg2
356                 //   return (true, memory)
357                 // } else {
358                 //   return (false, memory)
359                 // }
360                 // MOV  $0, Rout
361                 // LR   (Rarg0), Rtmp
362                 // BNE  Rtmp, Rarg1, 3(PC)
363                 // SC   Rarg2, (Rarg0), Rtmp
364                 // BNE  Rtmp, ZERO, -3(PC)
365                 // MOV  $1, Rout
366                 {name: "LoweredAtomicCas32", argLength: 4, reg: gpcas, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
367                 {name: "LoweredAtomicCas64", argLength: 4, reg: gpcas, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
368
369                 // Atomic 32 bit AND/OR.
370                 // *arg0 &= (|=) arg1. arg2=mem. returns nil.
371                 {name: "LoweredAtomicAnd32", argLength: 3, reg: gpatomic, asm: "AMOANDW", faultOnNilArg0: true, hasSideEffects: true},
372                 {name: "LoweredAtomicOr32", argLength: 3, reg: gpatomic, asm: "AMOORW", faultOnNilArg0: true, hasSideEffects: true},
373
374                 // Lowering pass-throughs
375                 {name: "LoweredNilCheck", argLength: 2, faultOnNilArg0: true, nilCheck: true, reg: regInfo{inputs: []regMask{gpspMask}}}, // arg0=ptr,arg1=mem, returns void.  Faults if ptr is nil.
376                 {name: "LoweredGetClosurePtr", reg: regInfo{outputs: []regMask{regCtxt}}},                                                // scheduler ensures only at beginning of entry block
377
378                 // LoweredGetCallerSP returns the SP of the caller of the current function.
379                 {name: "LoweredGetCallerSP", reg: gp01, rematerializeable: true},
380
381                 // LoweredGetCallerPC evaluates to the PC to which its "caller" will return.
382                 // I.e., if f calls g "calls" getcallerpc,
383                 // the result should be the PC within f that g will return to.
384                 // See runtime/stubs.go for a more detailed discussion.
385                 {name: "LoweredGetCallerPC", reg: gp01, rematerializeable: true},
386
387                 // LoweredWB invokes runtime.gcWriteBarrier. arg0=destptr, arg1=srcptr, arg2=mem, aux=runtime.gcWriteBarrier
388                 // It saves all GP registers if necessary,
389                 // but clobbers RA (LR) because it's a call
390                 // and T6 (REG_TMP).
391                 {name: "LoweredWB", argLength: 3, reg: regInfo{inputs: []regMask{regNamed["X5"], regNamed["X6"]}, clobbers: (callerSave &^ (gpMask | regNamed["g"])) | regNamed["X1"]}, clobberFlags: true, aux: "Sym", symEffect: "None"},
392
393                 // There are three of these functions so that they can have three different register inputs.
394                 // When we check 0 <= c <= cap (A), then 0 <= b <= c (B), then 0 <= a <= b (C), we want the
395                 // default registers to match so we don't need to copy registers around unnecessarily.
396                 {name: "LoweredPanicBoundsA", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{regNamed["X7"], regNamed["X28"]}}, typ: "Mem", call: true}, // arg0=idx, arg1=len, arg2=mem, returns memory. AuxInt contains report code (see PanicBounds in genericOps.go).
397                 {name: "LoweredPanicBoundsB", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{regNamed["X6"], regNamed["X7"]}}, typ: "Mem", call: true},  // arg0=idx, arg1=len, arg2=mem, returns memory. AuxInt contains report code (see PanicBounds in genericOps.go).
398                 {name: "LoweredPanicBoundsC", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{regNamed["X5"], regNamed["X6"]}}, typ: "Mem", call: true},  // arg0=idx, arg1=len, arg2=mem, returns memory. AuxInt contains report code (see PanicBounds in genericOps.go).
399
400                 // F extension.
401                 {name: "FADDS", argLength: 2, reg: fp21, asm: "FADDS", commutative: true, typ: "Float32"},                                           // arg0 + arg1
402                 {name: "FSUBS", argLength: 2, reg: fp21, asm: "FSUBS", commutative: false, typ: "Float32"},                                          // arg0 - arg1
403                 {name: "FMULS", argLength: 2, reg: fp21, asm: "FMULS", commutative: true, typ: "Float32"},                                           // arg0 * arg1
404                 {name: "FDIVS", argLength: 2, reg: fp21, asm: "FDIVS", commutative: false, typ: "Float32"},                                          // arg0 / arg1
405                 {name: "FSQRTS", argLength: 1, reg: fp11, asm: "FSQRTS", typ: "Float32"},                                                            // sqrt(arg0)
406                 {name: "FNEGS", argLength: 1, reg: fp11, asm: "FNEGS", typ: "Float32"},                                                              // -arg0
407                 {name: "FMVSX", argLength: 1, reg: gpfp, asm: "FMVSX", typ: "Float32"},                                                              // reinterpret arg0 as float
408                 {name: "FCVTSW", argLength: 1, reg: gpfp, asm: "FCVTSW", typ: "Float32"},                                                            // float32(low 32 bits of arg0)
409                 {name: "FCVTSL", argLength: 1, reg: gpfp, asm: "FCVTSL", typ: "Float32"},                                                            // float32(arg0)
410                 {name: "FCVTWS", argLength: 1, reg: fpgp, asm: "FCVTWS", typ: "Int32"},                                                              // int32(arg0)
411                 {name: "FCVTLS", argLength: 1, reg: fpgp, asm: "FCVTLS", typ: "Int64"},                                                              // int64(arg0)
412                 {name: "FMOVWload", argLength: 2, reg: fpload, asm: "MOVF", aux: "SymOff", typ: "Float32", faultOnNilArg0: true, symEffect: "Read"}, // load float32 from arg0+auxint+aux
413                 {name: "FMOVWstore", argLength: 3, reg: fpstore, asm: "MOVF", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},  // store float32 to arg0+auxint+aux
414                 {name: "FEQS", argLength: 2, reg: fp2gp, asm: "FEQS", commutative: true},                                                            // arg0 == arg1
415                 {name: "FNES", argLength: 2, reg: fp2gp, asm: "FNES", commutative: true},                                                            // arg0 != arg1
416                 {name: "FLTS", argLength: 2, reg: fp2gp, asm: "FLTS"},                                                                               // arg0 < arg1
417                 {name: "FLES", argLength: 2, reg: fp2gp, asm: "FLES"},                                                                               // arg0 <= arg1
418
419                 // D extension.
420                 {name: "FADDD", argLength: 2, reg: fp21, asm: "FADDD", commutative: true, typ: "Float64"},                                           // arg0 + arg1
421                 {name: "FSUBD", argLength: 2, reg: fp21, asm: "FSUBD", commutative: false, typ: "Float64"},                                          // arg0 - arg1
422                 {name: "FMULD", argLength: 2, reg: fp21, asm: "FMULD", commutative: true, typ: "Float64"},                                           // arg0 * arg1
423                 {name: "FDIVD", argLength: 2, reg: fp21, asm: "FDIVD", commutative: false, typ: "Float64"},                                          // arg0 / arg1
424                 {name: "FSQRTD", argLength: 1, reg: fp11, asm: "FSQRTD", typ: "Float64"},                                                            // sqrt(arg0)
425                 {name: "FNEGD", argLength: 1, reg: fp11, asm: "FNEGD", typ: "Float64"},                                                              // -arg0
426                 {name: "FMVDX", argLength: 1, reg: gpfp, asm: "FMVDX", typ: "Float64"},                                                              // reinterpret arg0 as float
427                 {name: "FCVTDW", argLength: 1, reg: gpfp, asm: "FCVTDW", typ: "Float64"},                                                            // float64(low 32 bits of arg0)
428                 {name: "FCVTDL", argLength: 1, reg: gpfp, asm: "FCVTDL", typ: "Float64"},                                                            // float64(arg0)
429                 {name: "FCVTWD", argLength: 1, reg: fpgp, asm: "FCVTWD", typ: "Int32"},                                                              // int32(arg0)
430                 {name: "FCVTLD", argLength: 1, reg: fpgp, asm: "FCVTLD", typ: "Int64"},                                                              // int64(arg0)
431                 {name: "FCVTDS", argLength: 1, reg: fp11, asm: "FCVTDS", typ: "Float64"},                                                            // float64(arg0)
432                 {name: "FCVTSD", argLength: 1, reg: fp11, asm: "FCVTSD", typ: "Float32"},                                                            // float32(arg0)
433                 {name: "FMOVDload", argLength: 2, reg: fpload, asm: "MOVD", aux: "SymOff", typ: "Float64", faultOnNilArg0: true, symEffect: "Read"}, // load float64 from arg0+auxint+aux
434                 {name: "FMOVDstore", argLength: 3, reg: fpstore, asm: "MOVD", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"},  // store float6 to arg0+auxint+aux
435                 {name: "FEQD", argLength: 2, reg: fp2gp, asm: "FEQD", commutative: true},                                                            // arg0 == arg1
436                 {name: "FNED", argLength: 2, reg: fp2gp, asm: "FNED", commutative: true},                                                            // arg0 != arg1
437                 {name: "FLTD", argLength: 2, reg: fp2gp, asm: "FLTD"},                                                                               // arg0 < arg1
438                 {name: "FLED", argLength: 2, reg: fp2gp, asm: "FLED"},                                                                               // arg0 <= arg1
439         }
440
441         RISCV64blocks := []blockData{
442                 {name: "BEQ", controls: 2},
443                 {name: "BNE", controls: 2},
444                 {name: "BLT", controls: 2},
445                 {name: "BGE", controls: 2},
446                 {name: "BLTU", controls: 2},
447                 {name: "BGEU", controls: 2},
448
449                 {name: "BEQZ", controls: 1},
450                 {name: "BNEZ", controls: 1},
451                 {name: "BLEZ", controls: 1},
452                 {name: "BGEZ", controls: 1},
453                 {name: "BLTZ", controls: 1},
454                 {name: "BGTZ", controls: 1},
455         }
456
457         archs = append(archs, arch{
458                 name:            "RISCV64",
459                 pkg:             "cmd/internal/obj/riscv",
460                 genfile:         "../../riscv64/ssa.go",
461                 ops:             RISCV64ops,
462                 blocks:          RISCV64blocks,
463                 regnames:        regNamesRISCV64,
464                 gpregmask:       gpMask,
465                 fpregmask:       fpMask,
466                 framepointerreg: -1, // not used
467         })
468 }