]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/compile/internal/ssa/gen/MIPS64Ops.go
[dev.cmdgo] codereview.cfg: add config for dev.cmdgo
[gostls13.git] / src / cmd / compile / internal / ssa / gen / MIPS64Ops.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 // +build ignore
6
7 package main
8
9 import "strings"
10
11 // Notes:
12 //  - Integer types live in the low portion of registers. Upper portions are junk.
13 //  - Boolean types use the low-order byte of a register. 0=false, 1=true.
14 //    Upper bytes are junk.
15 //  - *const instructions may use a constant larger than the instruction can encode.
16 //    In this case the assembler expands to multiple instructions and uses tmp
17 //    register (R23).
18
19 // Suffixes encode the bit width of various instructions.
20 // V (vlong)     = 64 bit
21 // WU (word)     = 32 bit unsigned
22 // W (word)      = 32 bit
23 // H (half word) = 16 bit
24 // HU            = 16 bit unsigned
25 // B (byte)      = 8 bit
26 // BU            = 8 bit unsigned
27 // F (float)     = 32 bit float
28 // D (double)    = 64 bit float
29
30 // Note: registers not used in regalloc are not included in this list,
31 // so that regmask stays within int64
32 // Be careful when hand coding regmasks.
33 var regNamesMIPS64 = []string{
34         "R0", // constant 0
35         "R1",
36         "R2",
37         "R3",
38         "R4",
39         "R5",
40         "R6",
41         "R7",
42         "R8",
43         "R9",
44         "R10",
45         "R11",
46         "R12",
47         "R13",
48         "R14",
49         "R15",
50         "R16",
51         "R17",
52         "R18",
53         "R19",
54         "R20",
55         "R21",
56         "R22",
57         // R23 = REGTMP not used in regalloc
58         "R24",
59         "R25",
60         // R26 reserved by kernel
61         // R27 reserved by kernel
62         // R28 = REGSB not used in regalloc
63         "SP",  // aka R29
64         "g",   // aka R30
65         "R31", // aka REGLINK
66
67         "F0",
68         "F1",
69         "F2",
70         "F3",
71         "F4",
72         "F5",
73         "F6",
74         "F7",
75         "F8",
76         "F9",
77         "F10",
78         "F11",
79         "F12",
80         "F13",
81         "F14",
82         "F15",
83         "F16",
84         "F17",
85         "F18",
86         "F19",
87         "F20",
88         "F21",
89         "F22",
90         "F23",
91         "F24",
92         "F25",
93         "F26",
94         "F27",
95         "F28",
96         "F29",
97         "F30",
98         "F31",
99
100         "HI", // high bits of multiplication
101         "LO", // low bits of multiplication
102
103         // If you add registers, update asyncPreempt in runtime.
104
105         // pseudo-registers
106         "SB",
107 }
108
109 func init() {
110         // Make map from reg names to reg integers.
111         if len(regNamesMIPS64) > 64 {
112                 panic("too many registers")
113         }
114         num := map[string]int{}
115         for i, name := range regNamesMIPS64 {
116                 num[name] = i
117         }
118         buildReg := func(s string) regMask {
119                 m := regMask(0)
120                 for _, r := range strings.Split(s, " ") {
121                         if n, ok := num[r]; ok {
122                                 m |= regMask(1) << uint(n)
123                                 continue
124                         }
125                         panic("register " + r + " not found")
126                 }
127                 return m
128         }
129
130         // Common individual register masks
131         var (
132                 gp         = buildReg("R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31")
133                 gpg        = gp | buildReg("g")
134                 gpsp       = gp | buildReg("SP")
135                 gpspg      = gpg | buildReg("SP")
136                 gpspsbg    = gpspg | buildReg("SB")
137                 fp         = buildReg("F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31")
138                 lo         = buildReg("LO")
139                 hi         = buildReg("HI")
140                 callerSave = gp | fp | lo | hi | buildReg("g") // runtime.setg (and anything calling it) may clobber g
141                 r1         = buildReg("R1")
142                 r2         = buildReg("R2")
143                 r3         = buildReg("R3")
144                 r4         = buildReg("R4")
145         )
146         // Common regInfo
147         var (
148                 gp01     = regInfo{inputs: nil, outputs: []regMask{gp}}
149                 gp11     = regInfo{inputs: []regMask{gpg}, outputs: []regMask{gp}}
150                 gp11sp   = regInfo{inputs: []regMask{gpspg}, outputs: []regMask{gp}}
151                 gp21     = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{gp}}
152                 gp2hilo  = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{hi, lo}}
153                 gpload   = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}}
154                 gpstore  = regInfo{inputs: []regMask{gpspsbg, gpg}}
155                 gpstore0 = regInfo{inputs: []regMask{gpspsbg}}
156                 gpxchg   = regInfo{inputs: []regMask{gpspsbg, gpg}, outputs: []regMask{gp}}
157                 gpcas    = regInfo{inputs: []regMask{gpspsbg, gpg, gpg}, outputs: []regMask{gp}}
158                 fp01     = regInfo{inputs: nil, outputs: []regMask{fp}}
159                 fp11     = regInfo{inputs: []regMask{fp}, outputs: []regMask{fp}}
160                 //fp1flags  = regInfo{inputs: []regMask{fp}}
161                 //fpgp      = regInfo{inputs: []regMask{fp}, outputs: []regMask{gp}}
162                 //gpfp      = regInfo{inputs: []regMask{gp}, outputs: []regMask{fp}}
163                 fp21      = regInfo{inputs: []regMask{fp, fp}, outputs: []regMask{fp}}
164                 fp2flags  = regInfo{inputs: []regMask{fp, fp}}
165                 fpload    = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{fp}}
166                 fpstore   = regInfo{inputs: []regMask{gpspsbg, fp}}
167                 readflags = regInfo{inputs: nil, outputs: []regMask{gp}}
168         )
169         ops := []opData{
170                 // binary ops
171                 {name: "ADDV", argLength: 2, reg: gp21, asm: "ADDVU", commutative: true},                             // arg0 + arg1
172                 {name: "ADDVconst", argLength: 1, reg: gp11sp, asm: "ADDVU", aux: "Int64"},                           // arg0 + auxInt. auxInt is 32-bit, also in other *const ops.
173                 {name: "SUBV", argLength: 2, reg: gp21, asm: "SUBVU"},                                                // arg0 - arg1
174                 {name: "SUBVconst", argLength: 1, reg: gp11, asm: "SUBVU", aux: "Int64"},                             // arg0 - auxInt
175                 {name: "MULV", argLength: 2, reg: gp2hilo, asm: "MULV", commutative: true, typ: "(Int64,Int64)"},     // arg0 * arg1, signed, results hi,lo
176                 {name: "MULVU", argLength: 2, reg: gp2hilo, asm: "MULVU", commutative: true, typ: "(UInt64,UInt64)"}, // arg0 * arg1, unsigned, results hi,lo
177                 {name: "DIVV", argLength: 2, reg: gp2hilo, asm: "DIVV", typ: "(Int64,Int64)"},                        // arg0 / arg1, signed, results hi=arg0%arg1,lo=arg0/arg1
178                 {name: "DIVVU", argLength: 2, reg: gp2hilo, asm: "DIVVU", typ: "(UInt64,UInt64)"},                    // arg0 / arg1, signed, results hi=arg0%arg1,lo=arg0/arg1
179
180                 {name: "ADDF", argLength: 2, reg: fp21, asm: "ADDF", commutative: true}, // arg0 + arg1
181                 {name: "ADDD", argLength: 2, reg: fp21, asm: "ADDD", commutative: true}, // arg0 + arg1
182                 {name: "SUBF", argLength: 2, reg: fp21, asm: "SUBF"},                    // arg0 - arg1
183                 {name: "SUBD", argLength: 2, reg: fp21, asm: "SUBD"},                    // arg0 - arg1
184                 {name: "MULF", argLength: 2, reg: fp21, asm: "MULF", commutative: true}, // arg0 * arg1
185                 {name: "MULD", argLength: 2, reg: fp21, asm: "MULD", commutative: true}, // arg0 * arg1
186                 {name: "DIVF", argLength: 2, reg: fp21, asm: "DIVF"},                    // arg0 / arg1
187                 {name: "DIVD", argLength: 2, reg: fp21, asm: "DIVD"},                    // arg0 / arg1
188
189                 {name: "AND", argLength: 2, reg: gp21, asm: "AND", commutative: true},                // arg0 & arg1
190                 {name: "ANDconst", argLength: 1, reg: gp11, asm: "AND", aux: "Int64"},                // arg0 & auxInt
191                 {name: "OR", argLength: 2, reg: gp21, asm: "OR", commutative: true},                  // arg0 | arg1
192                 {name: "ORconst", argLength: 1, reg: gp11, asm: "OR", aux: "Int64"},                  // arg0 | auxInt
193                 {name: "XOR", argLength: 2, reg: gp21, asm: "XOR", commutative: true, typ: "UInt64"}, // arg0 ^ arg1
194                 {name: "XORconst", argLength: 1, reg: gp11, asm: "XOR", aux: "Int64", typ: "UInt64"}, // arg0 ^ auxInt
195                 {name: "NOR", argLength: 2, reg: gp21, asm: "NOR", commutative: true},                // ^(arg0 | arg1)
196                 {name: "NORconst", argLength: 1, reg: gp11, asm: "NOR", aux: "Int64"},                // ^(arg0 | auxInt)
197
198                 {name: "NEGV", argLength: 1, reg: gp11},                // -arg0
199                 {name: "NEGF", argLength: 1, reg: fp11, asm: "NEGF"},   // -arg0, float32
200                 {name: "NEGD", argLength: 1, reg: fp11, asm: "NEGD"},   // -arg0, float64
201                 {name: "SQRTD", argLength: 1, reg: fp11, asm: "SQRTD"}, // sqrt(arg0), float64
202
203                 // shifts
204                 {name: "SLLV", argLength: 2, reg: gp21, asm: "SLLV"},                    // arg0 << arg1, shift amount is mod 64
205                 {name: "SLLVconst", argLength: 1, reg: gp11, asm: "SLLV", aux: "Int64"}, // arg0 << auxInt
206                 {name: "SRLV", argLength: 2, reg: gp21, asm: "SRLV"},                    // arg0 >> arg1, unsigned, shift amount is mod 64
207                 {name: "SRLVconst", argLength: 1, reg: gp11, asm: "SRLV", aux: "Int64"}, // arg0 >> auxInt, unsigned
208                 {name: "SRAV", argLength: 2, reg: gp21, asm: "SRAV"},                    // arg0 >> arg1, signed, shift amount is mod 64
209                 {name: "SRAVconst", argLength: 1, reg: gp11, asm: "SRAV", aux: "Int64"}, // arg0 >> auxInt, signed
210
211                 // comparisons
212                 {name: "SGT", argLength: 2, reg: gp21, asm: "SGT", typ: "Bool"},                      // 1 if arg0 > arg1 (signed), 0 otherwise
213                 {name: "SGTconst", argLength: 1, reg: gp11, asm: "SGT", aux: "Int64", typ: "Bool"},   // 1 if auxInt > arg0 (signed), 0 otherwise
214                 {name: "SGTU", argLength: 2, reg: gp21, asm: "SGTU", typ: "Bool"},                    // 1 if arg0 > arg1 (unsigned), 0 otherwise
215                 {name: "SGTUconst", argLength: 1, reg: gp11, asm: "SGTU", aux: "Int64", typ: "Bool"}, // 1 if auxInt > arg0 (unsigned), 0 otherwise
216
217                 {name: "CMPEQF", argLength: 2, reg: fp2flags, asm: "CMPEQF", typ: "Flags"}, // flags=true if arg0 = arg1, float32
218                 {name: "CMPEQD", argLength: 2, reg: fp2flags, asm: "CMPEQD", typ: "Flags"}, // flags=true if arg0 = arg1, float64
219                 {name: "CMPGEF", argLength: 2, reg: fp2flags, asm: "CMPGEF", typ: "Flags"}, // flags=true if arg0 >= arg1, float32
220                 {name: "CMPGED", argLength: 2, reg: fp2flags, asm: "CMPGED", typ: "Flags"}, // flags=true if arg0 >= arg1, float64
221                 {name: "CMPGTF", argLength: 2, reg: fp2flags, asm: "CMPGTF", typ: "Flags"}, // flags=true if arg0 > arg1, float32
222                 {name: "CMPGTD", argLength: 2, reg: fp2flags, asm: "CMPGTD", typ: "Flags"}, // flags=true if arg0 > arg1, float64
223
224                 // moves
225                 {name: "MOVVconst", argLength: 0, reg: gp01, aux: "Int64", asm: "MOVV", typ: "UInt64", rematerializeable: true},    // auxint
226                 {name: "MOVFconst", argLength: 0, reg: fp01, aux: "Float64", asm: "MOVF", typ: "Float32", rematerializeable: true}, // auxint as 64-bit float, convert to 32-bit float
227                 {name: "MOVDconst", argLength: 0, reg: fp01, aux: "Float64", asm: "MOVD", typ: "Float64", rematerializeable: true}, // auxint as 64-bit float
228
229                 {name: "MOVVaddr", argLength: 1, reg: regInfo{inputs: []regMask{buildReg("SP") | buildReg("SB")}, outputs: []regMask{gp}}, aux: "SymOff", asm: "MOVV", rematerializeable: true, symEffect: "Addr"}, // arg0 + auxInt + aux.(*gc.Sym), arg0=SP/SB
230
231                 {name: "MOVBload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVB", typ: "Int8", faultOnNilArg0: true, symEffect: "Read"},     // load from arg0 + auxInt + aux.  arg1=mem.
232                 {name: "MOVBUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVBU", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read"},  // load from arg0 + auxInt + aux.  arg1=mem.
233                 {name: "MOVHload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVH", typ: "Int16", faultOnNilArg0: true, symEffect: "Read"},    // load from arg0 + auxInt + aux.  arg1=mem.
234                 {name: "MOVHUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVHU", typ: "UInt16", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux.  arg1=mem.
235                 {name: "MOVWload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVW", typ: "Int32", faultOnNilArg0: true, symEffect: "Read"},    // load from arg0 + auxInt + aux.  arg1=mem.
236                 {name: "MOVWUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVWU", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux.  arg1=mem.
237                 {name: "MOVVload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVV", typ: "UInt64", faultOnNilArg0: true, symEffect: "Read"},   // load from arg0 + auxInt + aux.  arg1=mem.
238                 {name: "MOVFload", argLength: 2, reg: fpload, aux: "SymOff", asm: "MOVF", typ: "Float32", faultOnNilArg0: true, symEffect: "Read"},  // load from arg0 + auxInt + aux.  arg1=mem.
239                 {name: "MOVDload", argLength: 2, reg: fpload, aux: "SymOff", asm: "MOVD", typ: "Float64", faultOnNilArg0: true, symEffect: "Read"},  // load from arg0 + auxInt + aux.  arg1=mem.
240
241                 {name: "MOVBstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVB", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 1 byte of arg1 to arg0 + auxInt + aux.  arg2=mem.
242                 {name: "MOVHstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVH", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 2 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
243                 {name: "MOVWstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVW", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 4 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
244                 {name: "MOVVstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVV", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 8 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
245                 {name: "MOVFstore", argLength: 3, reg: fpstore, aux: "SymOff", asm: "MOVF", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 4 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
246                 {name: "MOVDstore", argLength: 3, reg: fpstore, aux: "SymOff", asm: "MOVD", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 8 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
247
248                 {name: "MOVBstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVB", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 1 byte of zero to arg0 + auxInt + aux.  arg1=mem.
249                 {name: "MOVHstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVH", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 2 bytes of zero to arg0 + auxInt + aux.  arg1=mem.
250                 {name: "MOVWstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVW", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 4 bytes of zero to arg0 + auxInt + aux.  arg1=mem.
251                 {name: "MOVVstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVV", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 8 bytes of zero to arg0 + auxInt + aux.  ar12=mem.
252
253                 // conversions
254                 {name: "MOVBreg", argLength: 1, reg: gp11, asm: "MOVB"},   // move from arg0, sign-extended from byte
255                 {name: "MOVBUreg", argLength: 1, reg: gp11, asm: "MOVBU"}, // move from arg0, unsign-extended from byte
256                 {name: "MOVHreg", argLength: 1, reg: gp11, asm: "MOVH"},   // move from arg0, sign-extended from half
257                 {name: "MOVHUreg", argLength: 1, reg: gp11, asm: "MOVHU"}, // move from arg0, unsign-extended from half
258                 {name: "MOVWreg", argLength: 1, reg: gp11, asm: "MOVW"},   // move from arg0, sign-extended from word
259                 {name: "MOVWUreg", argLength: 1, reg: gp11, asm: "MOVWU"}, // move from arg0, unsign-extended from word
260                 {name: "MOVVreg", argLength: 1, reg: gp11, asm: "MOVV"},   // move from arg0
261
262                 {name: "MOVVnop", argLength: 1, reg: regInfo{inputs: []regMask{gp}, outputs: []regMask{gp}}, resultInArg0: true}, // nop, return arg0 in same register
263
264                 {name: "MOVWF", argLength: 1, reg: fp11, asm: "MOVWF"},     // int32 -> float32
265                 {name: "MOVWD", argLength: 1, reg: fp11, asm: "MOVWD"},     // int32 -> float64
266                 {name: "MOVVF", argLength: 1, reg: fp11, asm: "MOVVF"},     // int64 -> float32
267                 {name: "MOVVD", argLength: 1, reg: fp11, asm: "MOVVD"},     // int64 -> float64
268                 {name: "TRUNCFW", argLength: 1, reg: fp11, asm: "TRUNCFW"}, // float32 -> int32
269                 {name: "TRUNCDW", argLength: 1, reg: fp11, asm: "TRUNCDW"}, // float64 -> int32
270                 {name: "TRUNCFV", argLength: 1, reg: fp11, asm: "TRUNCFV"}, // float32 -> int64
271                 {name: "TRUNCDV", argLength: 1, reg: fp11, asm: "TRUNCDV"}, // float64 -> int64
272                 {name: "MOVFD", argLength: 1, reg: fp11, asm: "MOVFD"},     // float32 -> float64
273                 {name: "MOVDF", argLength: 1, reg: fp11, asm: "MOVDF"},     // float64 -> float32
274
275                 // function calls
276                 {name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true},                                               // call static function aux.(*obj.LSym).  arg0=mem, auxint=argsize, returns mem
277                 {name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{gpsp, buildReg("R22"), 0}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call function via closure.  arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
278                 {name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true},                         // call fn by pointer.  arg0=codeptr, arg1=mem, auxint=argsize, returns mem
279
280                 // duffzero
281                 // arg0 = address of memory to zero
282                 // arg1 = mem
283                 // auxint = offset into duffzero code to start executing
284                 // returns mem
285                 // R1 aka mips.REGRT1 changed as side effect
286                 {
287                         name:      "DUFFZERO",
288                         aux:       "Int64",
289                         argLength: 2,
290                         reg: regInfo{
291                                 inputs:   []regMask{gp},
292                                 clobbers: buildReg("R1 R31"),
293                         },
294                         faultOnNilArg0: true,
295                 },
296
297                 // duffcopy
298                 // arg0 = address of dst memory (in R2, changed as side effect)
299                 // arg1 = address of src memory (in R1, changed as side effect)
300                 // arg2 = mem
301                 // auxint = offset into duffcopy code to start executing
302                 // returns mem
303                 {
304                         name:      "DUFFCOPY",
305                         aux:       "Int64",
306                         argLength: 3,
307                         reg: regInfo{
308                                 inputs:   []regMask{buildReg("R2"), buildReg("R1")},
309                                 clobbers: buildReg("R1 R2 R31"),
310                         },
311                         faultOnNilArg0: true,
312                         faultOnNilArg1: true,
313                 },
314
315                 // large or unaligned zeroing
316                 // arg0 = address of memory to zero (in R1, changed as side effect)
317                 // arg1 = address of the last element to zero
318                 // arg2 = mem
319                 // auxint = alignment
320                 // returns mem
321                 //      SUBV    $8, R1
322                 //      MOVV    R0, 8(R1)
323                 //      ADDV    $8, R1
324                 //      BNE     Rarg1, R1, -2(PC)
325                 {
326                         name:      "LoweredZero",
327                         aux:       "Int64",
328                         argLength: 3,
329                         reg: regInfo{
330                                 inputs:   []regMask{buildReg("R1"), gp},
331                                 clobbers: buildReg("R1"),
332                         },
333                         clobberFlags:   true,
334                         faultOnNilArg0: true,
335                 },
336
337                 // large or unaligned move
338                 // arg0 = address of dst memory (in R2, changed as side effect)
339                 // arg1 = address of src memory (in R1, changed as side effect)
340                 // arg2 = address of the last element of src
341                 // arg3 = mem
342                 // auxint = alignment
343                 // returns mem
344                 //      SUBV    $8, R1
345                 //      MOVV    8(R1), Rtmp
346                 //      MOVV    Rtmp, (R2)
347                 //      ADDV    $8, R1
348                 //      ADDV    $8, R2
349                 //      BNE     Rarg2, R1, -4(PC)
350                 {
351                         name:      "LoweredMove",
352                         aux:       "Int64",
353                         argLength: 4,
354                         reg: regInfo{
355                                 inputs:   []regMask{buildReg("R2"), buildReg("R1"), gp},
356                                 clobbers: buildReg("R1 R2"),
357                         },
358                         clobberFlags:   true,
359                         faultOnNilArg0: true,
360                         faultOnNilArg1: true,
361                 },
362
363                 // atomic loads.
364                 // load from arg0. arg1=mem.
365                 // returns <value,memory> so they can be properly ordered with other loads.
366                 {name: "LoweredAtomicLoad8", argLength: 2, reg: gpload, faultOnNilArg0: true},
367                 {name: "LoweredAtomicLoad32", argLength: 2, reg: gpload, faultOnNilArg0: true},
368                 {name: "LoweredAtomicLoad64", argLength: 2, reg: gpload, faultOnNilArg0: true},
369
370                 // atomic stores.
371                 // store arg1 to arg0. arg2=mem. returns memory.
372                 {name: "LoweredAtomicStore8", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true},
373                 {name: "LoweredAtomicStore32", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true},
374                 {name: "LoweredAtomicStore64", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true},
375                 // store zero to arg0. arg1=mem. returns memory.
376                 {name: "LoweredAtomicStorezero32", argLength: 2, reg: gpstore0, faultOnNilArg0: true, hasSideEffects: true},
377                 {name: "LoweredAtomicStorezero64", argLength: 2, reg: gpstore0, faultOnNilArg0: true, hasSideEffects: true},
378
379                 // atomic exchange.
380                 // store arg1 to arg0. arg2=mem. returns <old content of *arg0, memory>.
381                 // SYNC
382                 // LL   (Rarg0), Rout
383                 // MOVV Rarg1, Rtmp
384                 // SC   Rtmp, (Rarg0)
385                 // BEQ  Rtmp, -3(PC)
386                 // SYNC
387                 {name: "LoweredAtomicExchange32", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
388                 {name: "LoweredAtomicExchange64", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
389
390                 // atomic add.
391                 // *arg0 += arg1. arg2=mem. returns <new content of *arg0, memory>.
392                 // SYNC
393                 // LL   (Rarg0), Rout
394                 // ADDV Rarg1, Rout, Rtmp
395                 // SC   Rtmp, (Rarg0)
396                 // BEQ  Rtmp, -3(PC)
397                 // SYNC
398                 // ADDV Rarg1, Rout
399                 {name: "LoweredAtomicAdd32", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
400                 {name: "LoweredAtomicAdd64", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
401                 // *arg0 += auxint. arg1=mem. returns <new content of *arg0, memory>. auxint is 32-bit.
402                 {name: "LoweredAtomicAddconst32", argLength: 2, reg: regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}}, aux: "Int32", resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
403                 {name: "LoweredAtomicAddconst64", argLength: 2, reg: regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}}, aux: "Int64", resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
404
405                 // atomic compare and swap.
406                 // arg0 = pointer, arg1 = old value, arg2 = new value, arg3 = memory.
407                 // if *arg0 == arg1 {
408                 //   *arg0 = arg2
409                 //   return (true, memory)
410                 // } else {
411                 //   return (false, memory)
412                 // }
413                 // SYNC
414                 // MOVV $0, Rout
415                 // LL   (Rarg0), Rtmp
416                 // BNE  Rtmp, Rarg1, 4(PC)
417                 // MOVV Rarg2, Rout
418                 // SC   Rout, (Rarg0)
419                 // BEQ  Rout, -4(PC)
420                 // SYNC
421                 {name: "LoweredAtomicCas32", argLength: 4, reg: gpcas, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
422                 {name: "LoweredAtomicCas64", argLength: 4, reg: gpcas, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
423
424                 // pseudo-ops
425                 {name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{gpg}}, nilCheck: true, faultOnNilArg0: true}, // panic if arg0 is nil.  arg1=mem.
426
427                 {name: "FPFlagTrue", argLength: 1, reg: readflags},  // bool, true if FP flag is true
428                 {name: "FPFlagFalse", argLength: 1, reg: readflags}, // bool, true if FP flag is false
429
430                 // Scheduler ensures LoweredGetClosurePtr occurs only in entry block,
431                 // and sorts it to the very beginning of the block to prevent other
432                 // use of R22 (mips.REGCTXT, the closure pointer)
433                 {name: "LoweredGetClosurePtr", reg: regInfo{outputs: []regMask{buildReg("R22")}}, zeroWidth: true},
434
435                 // LoweredGetCallerSP returns the SP of the caller of the current function.
436                 {name: "LoweredGetCallerSP", reg: gp01, rematerializeable: true},
437
438                 // LoweredGetCallerPC evaluates to the PC to which its "caller" will return.
439                 // I.e., if f calls g "calls" getcallerpc,
440                 // the result should be the PC within f that g will return to.
441                 // See runtime/stubs.go for a more detailed discussion.
442                 {name: "LoweredGetCallerPC", reg: gp01, rematerializeable: true},
443
444                 // LoweredWB invokes runtime.gcWriteBarrier. arg0=destptr, arg1=srcptr, arg2=mem, aux=runtime.gcWriteBarrier
445                 // It saves all GP registers if necessary,
446                 // but clobbers R31 (LR) because it's a call
447                 // and R23 (REGTMP).
448                 {name: "LoweredWB", argLength: 3, reg: regInfo{inputs: []regMask{buildReg("R20"), buildReg("R21")}, clobbers: (callerSave &^ gpg) | buildReg("R31")}, clobberFlags: true, aux: "Sym", symEffect: "None"},
449
450                 // There are three of these functions so that they can have three different register inputs.
451                 // When we check 0 <= c <= cap (A), then 0 <= b <= c (B), then 0 <= a <= b (C), we want the
452                 // default registers to match so we don't need to copy registers around unnecessarily.
453                 {name: "LoweredPanicBoundsA", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{r3, r4}}, typ: "Mem", call: true}, // arg0=idx, arg1=len, arg2=mem, returns memory. AuxInt contains report code (see PanicBounds in genericOps.go).
454                 {name: "LoweredPanicBoundsB", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{r2, r3}}, typ: "Mem", call: true}, // arg0=idx, arg1=len, arg2=mem, returns memory. AuxInt contains report code (see PanicBounds in genericOps.go).
455                 {name: "LoweredPanicBoundsC", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{r1, r2}}, typ: "Mem", call: true}, // arg0=idx, arg1=len, arg2=mem, returns memory. AuxInt contains report code (see PanicBounds in genericOps.go).
456         }
457
458         blocks := []blockData{
459                 {name: "EQ", controls: 1},
460                 {name: "NE", controls: 1},
461                 {name: "LTZ", controls: 1}, // < 0
462                 {name: "LEZ", controls: 1}, // <= 0
463                 {name: "GTZ", controls: 1}, // > 0
464                 {name: "GEZ", controls: 1}, // >= 0
465                 {name: "FPT", controls: 1}, // FP flag is true
466                 {name: "FPF", controls: 1}, // FP flag is false
467         }
468
469         archs = append(archs, arch{
470                 name:            "MIPS64",
471                 pkg:             "cmd/internal/obj/mips",
472                 genfile:         "../../mips64/ssa.go",
473                 ops:             ops,
474                 blocks:          blocks,
475                 regnames:        regNamesMIPS64,
476                 gpregmask:       gp,
477                 fpregmask:       fp,
478                 specialregmask:  hi | lo,
479                 framepointerreg: -1, // not used
480                 linkreg:         int8(num["R31"]),
481         })
482 }