]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/compile/internal/ssa/gen/MIPSOps.go
net/http: mention socks5 support in proxy
[gostls13.git] / src / cmd / compile / internal / ssa / gen / MIPSOps.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 //  - Unused portions of AuxInt are filled by sign-extending the used portion.
16 //  - *const instructions may use a constant larger than the instruction can encode.
17 //    In this case the assembler expands to multiple instructions and uses tmp
18 //    register (R23).
19
20 // Suffixes encode the bit width of various instructions.
21 // W (word)      = 32 bit
22 // H (half word) = 16 bit
23 // HU            = 16 bit unsigned
24 // B (byte)      = 8 bit
25 // BU            = 8 bit unsigned
26 // F (float)     = 32 bit float
27 // D (double)    = 64 bit float
28
29 // Note: registers not used in regalloc are not included in this list,
30 // so that regmask stays within int64
31 // Be careful when hand coding regmasks.
32 var regNamesMIPS = []string{
33         "R0", // constant 0
34         "R1",
35         "R2",
36         "R3",
37         "R4",
38         "R5",
39         "R6",
40         "R7",
41         "R8",
42         "R9",
43         "R10",
44         "R11",
45         "R12",
46         "R13",
47         "R14",
48         "R15",
49         "R16",
50         "R17",
51         "R18",
52         "R19",
53         "R20",
54         "R21",
55         "R22",
56         //REGTMP
57         "R24",
58         "R25",
59         // R26 reserved by kernel
60         // R27 reserved by kernel
61         "R28",
62         "SP",  // aka R29
63         "g",   // aka R30
64         "R31", // REGLINK
65
66         // odd FP registers contain high parts of 64-bit FP values
67         "F0",
68         "F2",
69         "F4",
70         "F6",
71         "F8",
72         "F10",
73         "F12",
74         "F14",
75         "F16",
76         "F18",
77         "F20",
78         "F22",
79         "F24",
80         "F26",
81         "F28",
82         "F30",
83
84         "HI", // high bits of multiplication
85         "LO", // low bits of multiplication
86
87         // If you add registers, update asyncPreempt in runtime.
88
89         // pseudo-registers
90         "SB",
91 }
92
93 func init() {
94         // Make map from reg names to reg integers.
95         if len(regNamesMIPS) > 64 {
96                 panic("too many registers")
97         }
98         num := map[string]int{}
99         for i, name := range regNamesMIPS {
100                 num[name] = i
101         }
102         buildReg := func(s string) regMask {
103                 m := regMask(0)
104                 for _, r := range strings.Split(s, " ") {
105                         if n, ok := num[r]; ok {
106                                 m |= regMask(1) << uint(n)
107                                 continue
108                         }
109                         panic("register " + r + " not found")
110                 }
111                 return m
112         }
113
114         // Common individual register masks
115         var (
116                 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 R28 R31")
117                 gpg        = gp | buildReg("g")
118                 gpsp       = gp | buildReg("SP")
119                 gpspg      = gpg | buildReg("SP")
120                 gpspsbg    = gpspg | buildReg("SB")
121                 fp         = buildReg("F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30")
122                 lo         = buildReg("LO")
123                 hi         = buildReg("HI")
124                 callerSave = gp | fp | lo | hi | buildReg("g") // runtime.setg (and anything calling it) may clobber g
125                 r1         = buildReg("R1")
126                 r2         = buildReg("R2")
127                 r3         = buildReg("R3")
128                 r4         = buildReg("R4")
129                 r5         = buildReg("R5")
130         )
131         // Common regInfo
132         var (
133                 gp01      = regInfo{inputs: nil, outputs: []regMask{gp}}
134                 gp11      = regInfo{inputs: []regMask{gpg}, outputs: []regMask{gp}}
135                 gp11sp    = regInfo{inputs: []regMask{gpspg}, outputs: []regMask{gp}}
136                 gp21      = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{gp}}
137                 gp31      = regInfo{inputs: []regMask{gp, gp, gp}, outputs: []regMask{gp}}
138                 gp2hilo   = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{hi, lo}}
139                 gpload    = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}}
140                 gpstore   = regInfo{inputs: []regMask{gpspsbg, gpg}}
141                 gpxchg    = regInfo{inputs: []regMask{gpspsbg, gpg}, outputs: []regMask{gp}}
142                 gpcas     = regInfo{inputs: []regMask{gpspsbg, gpg, gpg}, outputs: []regMask{gp}}
143                 gpstore0  = regInfo{inputs: []regMask{gpspsbg}}
144                 fp01      = regInfo{inputs: nil, outputs: []regMask{fp}}
145                 fp11      = regInfo{inputs: []regMask{fp}, outputs: []regMask{fp}}
146                 fp21      = regInfo{inputs: []regMask{fp, fp}, outputs: []regMask{fp}}
147                 fp2flags  = regInfo{inputs: []regMask{fp, fp}}
148                 fpload    = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{fp}}
149                 fpstore   = regInfo{inputs: []regMask{gpspsbg, fp}}
150                 readflags = regInfo{inputs: nil, outputs: []regMask{gp}}
151         )
152         ops := []opData{
153                 {name: "ADD", argLength: 2, reg: gp21, asm: "ADDU", commutative: true},                                                                           // arg0 + arg1
154                 {name: "ADDconst", argLength: 1, reg: gp11sp, asm: "ADDU", aux: "Int32"},                                                                         // arg0 + auxInt
155                 {name: "SUB", argLength: 2, reg: gp21, asm: "SUBU"},                                                                                              // arg0 - arg1
156                 {name: "SUBconst", argLength: 1, reg: gp11, asm: "SUBU", aux: "Int32"},                                                                           // arg0 - auxInt
157                 {name: "MUL", argLength: 2, reg: regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{gp}, clobbers: hi | lo}, asm: "MUL", commutative: true}, // arg0 * arg1
158                 {name: "MULT", argLength: 2, reg: gp2hilo, asm: "MUL", commutative: true, typ: "(Int32,Int32)"},                                                  // arg0 * arg1, signed, results hi,lo
159                 {name: "MULTU", argLength: 2, reg: gp2hilo, asm: "MULU", commutative: true, typ: "(UInt32,UInt32)"},                                              // arg0 * arg1, unsigned, results hi,lo
160                 {name: "DIV", argLength: 2, reg: gp2hilo, asm: "DIV", typ: "(Int32,Int32)"},                                                                      // arg0 / arg1, signed, results hi=arg0%arg1,lo=arg0/arg1
161                 {name: "DIVU", argLength: 2, reg: gp2hilo, asm: "DIVU", typ: "(UInt32,UInt32)"},                                                                  // arg0 / arg1, signed, results hi=arg0%arg1,lo=arg0/arg1
162
163                 {name: "ADDF", argLength: 2, reg: fp21, asm: "ADDF", commutative: true}, // arg0 + arg1
164                 {name: "ADDD", argLength: 2, reg: fp21, asm: "ADDD", commutative: true}, // arg0 + arg1
165                 {name: "SUBF", argLength: 2, reg: fp21, asm: "SUBF"},                    // arg0 - arg1
166                 {name: "SUBD", argLength: 2, reg: fp21, asm: "SUBD"},                    // arg0 - arg1
167                 {name: "MULF", argLength: 2, reg: fp21, asm: "MULF", commutative: true}, // arg0 * arg1
168                 {name: "MULD", argLength: 2, reg: fp21, asm: "MULD", commutative: true}, // arg0 * arg1
169                 {name: "DIVF", argLength: 2, reg: fp21, asm: "DIVF"},                    // arg0 / arg1
170                 {name: "DIVD", argLength: 2, reg: fp21, asm: "DIVD"},                    // arg0 / arg1
171
172                 {name: "AND", argLength: 2, reg: gp21, asm: "AND", commutative: true},                // arg0 & arg1
173                 {name: "ANDconst", argLength: 1, reg: gp11, asm: "AND", aux: "Int32"},                // arg0 & auxInt
174                 {name: "OR", argLength: 2, reg: gp21, asm: "OR", commutative: true},                  // arg0 | arg1
175                 {name: "ORconst", argLength: 1, reg: gp11, asm: "OR", aux: "Int32"},                  // arg0 | auxInt
176                 {name: "XOR", argLength: 2, reg: gp21, asm: "XOR", commutative: true, typ: "UInt32"}, // arg0 ^ arg1
177                 {name: "XORconst", argLength: 1, reg: gp11, asm: "XOR", aux: "Int32", typ: "UInt32"}, // arg0 ^ auxInt
178                 {name: "NOR", argLength: 2, reg: gp21, asm: "NOR", commutative: true},                // ^(arg0 | arg1)
179                 {name: "NORconst", argLength: 1, reg: gp11, asm: "NOR", aux: "Int32"},                // ^(arg0 | auxInt)
180
181                 {name: "NEG", argLength: 1, reg: gp11},                 // -arg0
182                 {name: "NEGF", argLength: 1, reg: fp11, asm: "NEGF"},   // -arg0, float32
183                 {name: "NEGD", argLength: 1, reg: fp11, asm: "NEGD"},   // -arg0, float64
184                 {name: "SQRTD", argLength: 1, reg: fp11, asm: "SQRTD"}, // sqrt(arg0), float64
185                 {name: "SQRTF", argLength: 1, reg: fp11, asm: "SQRTF"}, // sqrt(arg0), float32
186
187                 // shifts
188                 {name: "SLL", argLength: 2, reg: gp21, asm: "SLL"},                    // arg0 << arg1, shift amount is mod 32
189                 {name: "SLLconst", argLength: 1, reg: gp11, asm: "SLL", aux: "Int32"}, // arg0 << auxInt, shift amount must be 0 through 31 inclusive
190                 {name: "SRL", argLength: 2, reg: gp21, asm: "SRL"},                    // arg0 >> arg1, unsigned, shift amount is mod 32
191                 {name: "SRLconst", argLength: 1, reg: gp11, asm: "SRL", aux: "Int32"}, // arg0 >> auxInt, shift amount must be 0 through 31 inclusive
192                 {name: "SRA", argLength: 2, reg: gp21, asm: "SRA"},                    // arg0 >> arg1, signed, shift amount is mod 32
193                 {name: "SRAconst", argLength: 1, reg: gp11, asm: "SRA", aux: "Int32"}, // arg0 >> auxInt, signed, shift amount must be 0 through 31 inclusive
194
195                 {name: "CLZ", argLength: 1, reg: gp11, asm: "CLZ"},
196
197                 // comparisons
198                 {name: "SGT", argLength: 2, reg: gp21, asm: "SGT", typ: "Bool"},                      // 1 if arg0 > arg1 (signed), 0 otherwise
199                 {name: "SGTconst", argLength: 1, reg: gp11, asm: "SGT", aux: "Int32", typ: "Bool"},   // 1 if auxInt > arg0 (signed), 0 otherwise
200                 {name: "SGTzero", argLength: 1, reg: gp11, asm: "SGT", typ: "Bool"},                  // 1 if arg0 > 0 (signed), 0 otherwise
201                 {name: "SGTU", argLength: 2, reg: gp21, asm: "SGTU", typ: "Bool"},                    // 1 if arg0 > arg1 (unsigned), 0 otherwise
202                 {name: "SGTUconst", argLength: 1, reg: gp11, asm: "SGTU", aux: "Int32", typ: "Bool"}, // 1 if auxInt > arg0 (unsigned), 0 otherwise
203                 {name: "SGTUzero", argLength: 1, reg: gp11, asm: "SGTU", typ: "Bool"},                // 1 if arg0 > 0 (unsigned), 0 otherwise
204
205                 {name: "CMPEQF", argLength: 2, reg: fp2flags, asm: "CMPEQF", typ: "Flags"}, // flags=true if arg0 = arg1, float32
206                 {name: "CMPEQD", argLength: 2, reg: fp2flags, asm: "CMPEQD", typ: "Flags"}, // flags=true if arg0 = arg1, float64
207                 {name: "CMPGEF", argLength: 2, reg: fp2flags, asm: "CMPGEF", typ: "Flags"}, // flags=true if arg0 >= arg1, float32
208                 {name: "CMPGED", argLength: 2, reg: fp2flags, asm: "CMPGED", typ: "Flags"}, // flags=true if arg0 >= arg1, float64
209                 {name: "CMPGTF", argLength: 2, reg: fp2flags, asm: "CMPGTF", typ: "Flags"}, // flags=true if arg0 > arg1, float32
210                 {name: "CMPGTD", argLength: 2, reg: fp2flags, asm: "CMPGTD", typ: "Flags"}, // flags=true if arg0 > arg1, float64
211
212                 // moves
213                 {name: "MOVWconst", argLength: 0, reg: gp01, aux: "Int32", asm: "MOVW", typ: "UInt32", rematerializeable: true},    // auxint
214                 {name: "MOVFconst", argLength: 0, reg: fp01, aux: "Float32", asm: "MOVF", typ: "Float32", rematerializeable: true}, // auxint as 64-bit float, convert to 32-bit float
215                 {name: "MOVDconst", argLength: 0, reg: fp01, aux: "Float64", asm: "MOVD", typ: "Float64", rematerializeable: true}, // auxint as 64-bit float
216
217                 {name: "MOVWaddr", argLength: 1, reg: regInfo{inputs: []regMask{buildReg("SP") | buildReg("SB")}, outputs: []regMask{gp}}, aux: "SymOff", asm: "MOVW", rematerializeable: true, symEffect: "Addr"}, // arg0 + auxInt + aux.(*gc.Sym), arg0=SP/SB
218
219                 {name: "MOVBload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVB", typ: "Int8", faultOnNilArg0: true, symEffect: "Read"},     // load from arg0 + auxInt + aux.  arg1=mem.
220                 {name: "MOVBUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVBU", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read"},  // load from arg0 + auxInt + aux.  arg1=mem.
221                 {name: "MOVHload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVH", typ: "Int16", faultOnNilArg0: true, symEffect: "Read"},    // load from arg0 + auxInt + aux.  arg1=mem.
222                 {name: "MOVHUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVHU", typ: "UInt16", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux.  arg1=mem.
223                 {name: "MOVWload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVW", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read"},   // load from arg0 + auxInt + aux.  arg1=mem.
224                 {name: "MOVFload", argLength: 2, reg: fpload, aux: "SymOff", asm: "MOVF", typ: "Float32", faultOnNilArg0: true, symEffect: "Read"},  // load from arg0 + auxInt + aux.  arg1=mem.
225                 {name: "MOVDload", argLength: 2, reg: fpload, aux: "SymOff", asm: "MOVD", typ: "Float64", faultOnNilArg0: true, symEffect: "Read"},  // load from arg0 + auxInt + aux.  arg1=mem.
226
227                 {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.
228                 {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.
229                 {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.
230                 {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.
231                 {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.
232
233                 {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.
234                 {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.
235                 {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.
236
237                 // conversions
238                 {name: "MOVBreg", argLength: 1, reg: gp11, asm: "MOVB"},   // move from arg0, sign-extended from byte
239                 {name: "MOVBUreg", argLength: 1, reg: gp11, asm: "MOVBU"}, // move from arg0, unsign-extended from byte
240                 {name: "MOVHreg", argLength: 1, reg: gp11, asm: "MOVH"},   // move from arg0, sign-extended from half
241                 {name: "MOVHUreg", argLength: 1, reg: gp11, asm: "MOVHU"}, // move from arg0, unsign-extended from half
242                 {name: "MOVWreg", argLength: 1, reg: gp11, asm: "MOVW"},   // move from arg0
243
244                 {name: "MOVWnop", argLength: 1, reg: regInfo{inputs: []regMask{gp}, outputs: []regMask{gp}}, resultInArg0: true}, // nop, return arg0 in same register
245
246                 // conditional move on zero (returns arg1 if arg2 is 0, otherwise arg0)
247                 // order of parameters is reversed so we can use resultInArg0 (OpCMOVZ result arg1 arg2-> CMOVZ arg2reg, arg1reg, resultReg)
248                 {name: "CMOVZ", argLength: 3, reg: gp31, asm: "CMOVZ", resultInArg0: true},
249                 {name: "CMOVZzero", argLength: 2, reg: regInfo{inputs: []regMask{gp, gpg}, outputs: []regMask{gp}}, asm: "CMOVZ", resultInArg0: true},
250
251                 {name: "MOVWF", argLength: 1, reg: fp11, asm: "MOVWF"},     // int32 -> float32
252                 {name: "MOVWD", argLength: 1, reg: fp11, asm: "MOVWD"},     // int32 -> float64
253                 {name: "TRUNCFW", argLength: 1, reg: fp11, asm: "TRUNCFW"}, // float32 -> int32
254                 {name: "TRUNCDW", argLength: 1, reg: fp11, asm: "TRUNCDW"}, // float64 -> int32
255                 {name: "MOVFD", argLength: 1, reg: fp11, asm: "MOVFD"},     // float32 -> float64
256                 {name: "MOVDF", argLength: 1, reg: fp11, asm: "MOVDF"},     // float64 -> float32
257
258                 // function calls
259                 {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
260                 {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
261                 {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
262
263                 // atomic ops
264
265                 // load from arg0. arg1=mem.
266                 // returns <value,memory> so they can be properly ordered with other loads.
267                 // SYNC
268                 // MOV(B|W)     (Rarg0), Rout
269                 // SYNC
270                 {name: "LoweredAtomicLoad8", argLength: 2, reg: gpload, faultOnNilArg0: true},
271                 {name: "LoweredAtomicLoad32", argLength: 2, reg: gpload, faultOnNilArg0: true},
272
273                 // store arg1 to arg0. arg2=mem. returns memory.
274                 // SYNC
275                 // MOV(B|W)     Rarg1, (Rarg0)
276                 // SYNC
277                 {name: "LoweredAtomicStore8", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true},
278                 {name: "LoweredAtomicStore32", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true},
279                 {name: "LoweredAtomicStorezero", argLength: 2, reg: gpstore0, faultOnNilArg0: true, hasSideEffects: true},
280
281                 // atomic exchange.
282                 // store arg1 to arg0. arg2=mem. returns <old content of *arg0, memory>.
283                 // SYNC
284                 // LL   (Rarg0), Rout
285                 // MOVW Rarg1, Rtmp
286                 // SC   Rtmp, (Rarg0)
287                 // BEQ  Rtmp, -3(PC)
288                 // SYNC
289                 {name: "LoweredAtomicExchange", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
290
291                 // atomic add.
292                 // *arg0 += arg1. arg2=mem. returns <new content of *arg0, memory>.
293                 // SYNC
294                 // LL   (Rarg0), Rout
295                 // ADDU Rarg1, Rout, Rtmp
296                 // SC   Rtmp, (Rarg0)
297                 // BEQ  Rtmp, -3(PC)
298                 // SYNC
299                 // ADDU Rarg1, Rout
300                 {name: "LoweredAtomicAdd", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
301                 {name: "LoweredAtomicAddconst", argLength: 2, reg: regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}}, aux: "Int32", resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
302
303                 // atomic compare and swap.
304                 // arg0 = pointer, arg1 = old value, arg2 = new value, arg3 = memory.
305                 // if *arg0 == arg1 {
306                 //   *arg0 = arg2
307                 //   return (true, memory)
308                 // } else {
309                 //   return (false, memory)
310                 // }
311                 // SYNC
312                 // MOVW $0, Rout
313                 // LL   (Rarg0), Rtmp
314                 // BNE  Rtmp, Rarg1, 4(PC)
315                 // MOVW Rarg2, Rout
316                 // SC   Rout, (Rarg0)
317                 // BEQ  Rout, -4(PC)
318                 // SYNC
319                 {name: "LoweredAtomicCas", argLength: 4, reg: gpcas, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
320
321                 // atomic and/or.
322                 // *arg0 &= (|=) arg1. arg2=mem. returns memory.
323                 // SYNC
324                 // LL   (Rarg0), Rtmp
325                 // AND  Rarg1, Rtmp
326                 // SC   Rtmp, (Rarg0)
327                 // BEQ  Rtmp, -3(PC)
328                 // SYNC
329                 {name: "LoweredAtomicAnd", argLength: 3, reg: gpstore, asm: "AND", faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
330                 {name: "LoweredAtomicOr", argLength: 3, reg: gpstore, asm: "OR", faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
331
332                 // large or unaligned zeroing
333                 // arg0 = address of memory to zero (in R1, changed as side effect)
334                 // arg1 = address of the last element to zero
335                 // arg2 = mem
336                 // auxint = alignment
337                 // returns mem
338                 //      SUBU    $4, R1
339                 //      MOVW    R0, 4(R1)
340                 //      ADDU    $4, R1
341                 //      BNE     Rarg1, R1, -2(PC)
342                 {
343                         name:      "LoweredZero",
344                         aux:       "Int32",
345                         argLength: 3,
346                         reg: regInfo{
347                                 inputs:   []regMask{buildReg("R1"), gp},
348                                 clobbers: buildReg("R1"),
349                         },
350                         faultOnNilArg0: true,
351                 },
352
353                 // large or unaligned move
354                 // arg0 = address of dst memory (in R2, changed as side effect)
355                 // arg1 = address of src memory (in R1, changed as side effect)
356                 // arg2 = address of the last element of src
357                 // arg3 = mem
358                 // auxint = alignment
359                 // returns mem
360                 //      SUBU    $4, R1
361                 //      MOVW    4(R1), Rtmp
362                 //      MOVW    Rtmp, (R2)
363                 //      ADDU    $4, R1
364                 //      ADDU    $4, R2
365                 //      BNE     Rarg2, R1, -4(PC)
366                 {
367                         name:      "LoweredMove",
368                         aux:       "Int32",
369                         argLength: 4,
370                         reg: regInfo{
371                                 inputs:   []regMask{buildReg("R2"), buildReg("R1"), gp},
372                                 clobbers: buildReg("R1 R2"),
373                         },
374                         faultOnNilArg0: true,
375                         faultOnNilArg1: true,
376                 },
377
378                 // pseudo-ops
379                 {name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{gpg}}, nilCheck: true, faultOnNilArg0: true}, // panic if arg0 is nil.  arg1=mem.
380
381                 {name: "FPFlagTrue", argLength: 1, reg: readflags},  // bool, true if FP flag is true
382                 {name: "FPFlagFalse", argLength: 1, reg: readflags}, // bool, true if FP flag is false
383
384                 // Scheduler ensures LoweredGetClosurePtr occurs only in entry block,
385                 // and sorts it to the very beginning of the block to prevent other
386                 // use of R22 (mips.REGCTXT, the closure pointer)
387                 {name: "LoweredGetClosurePtr", reg: regInfo{outputs: []regMask{buildReg("R22")}}, zeroWidth: true},
388
389                 // LoweredGetCallerSP returns the SP of the caller of the current function.
390                 {name: "LoweredGetCallerSP", reg: gp01, rematerializeable: true},
391
392                 // LoweredGetCallerPC evaluates to the PC to which its "caller" will return.
393                 // I.e., if f calls g "calls" getcallerpc,
394                 // the result should be the PC within f that g will return to.
395                 // See runtime/stubs.go for a more detailed discussion.
396                 {name: "LoweredGetCallerPC", reg: gp01, rematerializeable: true},
397
398                 // LoweredWB invokes runtime.gcWriteBarrier. arg0=destptr, arg1=srcptr, arg2=mem, aux=runtime.gcWriteBarrier
399                 // It saves all GP registers if necessary,
400                 // but clobbers R31 (LR) because it's a call
401                 // and R23 (REGTMP).
402                 {name: "LoweredWB", argLength: 3, reg: regInfo{inputs: []regMask{buildReg("R20"), buildReg("R21")}, clobbers: (callerSave &^ gpg) | buildReg("R31")}, clobberFlags: true, aux: "Sym", symEffect: "None"},
403
404                 // There are three of these functions so that they can have three different register inputs.
405                 // When we check 0 <= c <= cap (A), then 0 <= b <= c (B), then 0 <= a <= b (C), we want the
406                 // default registers to match so we don't need to copy registers around unnecessarily.
407                 {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).
408                 {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).
409                 {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).
410                 // Extend ops are the same as Bounds ops except the indexes are 64-bit.
411                 {name: "LoweredPanicExtendA", argLength: 4, aux: "Int64", reg: regInfo{inputs: []regMask{r5, r3, r4}}, typ: "Mem", call: true}, // arg0=idxHi, arg1=idxLo, arg2=len, arg3=mem, returns memory. AuxInt contains report code (see PanicExtend in genericOps.go).
412                 {name: "LoweredPanicExtendB", argLength: 4, aux: "Int64", reg: regInfo{inputs: []regMask{r5, r2, r3}}, typ: "Mem", call: true}, // arg0=idxHi, arg1=idxLo, arg2=len, arg3=mem, returns memory. AuxInt contains report code (see PanicExtend in genericOps.go).
413                 {name: "LoweredPanicExtendC", argLength: 4, aux: "Int64", reg: regInfo{inputs: []regMask{r5, r1, r2}}, typ: "Mem", call: true}, // arg0=idxHi, arg1=idxLo, arg2=len, arg3=mem, returns memory. AuxInt contains report code (see PanicExtend in genericOps.go).
414         }
415
416         blocks := []blockData{
417                 {name: "EQ", controls: 1},
418                 {name: "NE", controls: 1},
419                 {name: "LTZ", controls: 1}, // < 0
420                 {name: "LEZ", controls: 1}, // <= 0
421                 {name: "GTZ", controls: 1}, // > 0
422                 {name: "GEZ", controls: 1}, // >= 0
423                 {name: "FPT", controls: 1}, // FP flag is true
424                 {name: "FPF", controls: 1}, // FP flag is false
425         }
426
427         archs = append(archs, arch{
428                 name:            "MIPS",
429                 pkg:             "cmd/internal/obj/mips",
430                 genfile:         "../../mips/ssa.go",
431                 ops:             ops,
432                 blocks:          blocks,
433                 regnames:        regNamesMIPS,
434                 gpregmask:       gp,
435                 fpregmask:       fp,
436                 specialregmask:  hi | lo,
437                 framepointerreg: -1, // not used
438                 linkreg:         int8(num["R31"]),
439         })
440 }