]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/compile/internal/ssa/gen/MIPSOps.go
[dev.cmdgo] codereview.cfg: add config for dev.cmdgo
[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
186                 // shifts
187                 {name: "SLL", argLength: 2, reg: gp21, asm: "SLL"},                    // arg0 << arg1, shift amount is mod 32
188                 {name: "SLLconst", argLength: 1, reg: gp11, asm: "SLL", aux: "Int32"}, // arg0 << auxInt, shift amount must be 0 through 31 inclusive
189                 {name: "SRL", argLength: 2, reg: gp21, asm: "SRL"},                    // arg0 >> arg1, unsigned, shift amount is mod 32
190                 {name: "SRLconst", argLength: 1, reg: gp11, asm: "SRL", aux: "Int32"}, // arg0 >> auxInt, shift amount must be 0 through 31 inclusive
191                 {name: "SRA", argLength: 2, reg: gp21, asm: "SRA"},                    // arg0 >> arg1, signed, shift amount is mod 32
192                 {name: "SRAconst", argLength: 1, reg: gp11, asm: "SRA", aux: "Int32"}, // arg0 >> auxInt, signed, shift amount must be 0 through 31 inclusive
193
194                 {name: "CLZ", argLength: 1, reg: gp11, asm: "CLZ"},
195
196                 // comparisons
197                 {name: "SGT", argLength: 2, reg: gp21, asm: "SGT", typ: "Bool"},                      // 1 if arg0 > arg1 (signed), 0 otherwise
198                 {name: "SGTconst", argLength: 1, reg: gp11, asm: "SGT", aux: "Int32", typ: "Bool"},   // 1 if auxInt > arg0 (signed), 0 otherwise
199                 {name: "SGTzero", argLength: 1, reg: gp11, asm: "SGT", typ: "Bool"},                  // 1 if arg0 > 0 (signed), 0 otherwise
200                 {name: "SGTU", argLength: 2, reg: gp21, asm: "SGTU", typ: "Bool"},                    // 1 if arg0 > arg1 (unsigned), 0 otherwise
201                 {name: "SGTUconst", argLength: 1, reg: gp11, asm: "SGTU", aux: "Int32", typ: "Bool"}, // 1 if auxInt > arg0 (unsigned), 0 otherwise
202                 {name: "SGTUzero", argLength: 1, reg: gp11, asm: "SGTU", typ: "Bool"},                // 1 if arg0 > 0 (unsigned), 0 otherwise
203
204                 {name: "CMPEQF", argLength: 2, reg: fp2flags, asm: "CMPEQF", typ: "Flags"}, // flags=true if arg0 = arg1, float32
205                 {name: "CMPEQD", argLength: 2, reg: fp2flags, asm: "CMPEQD", typ: "Flags"}, // flags=true if arg0 = arg1, float64
206                 {name: "CMPGEF", argLength: 2, reg: fp2flags, asm: "CMPGEF", typ: "Flags"}, // flags=true if arg0 >= arg1, float32
207                 {name: "CMPGED", argLength: 2, reg: fp2flags, asm: "CMPGED", typ: "Flags"}, // flags=true if arg0 >= arg1, float64
208                 {name: "CMPGTF", argLength: 2, reg: fp2flags, asm: "CMPGTF", typ: "Flags"}, // flags=true if arg0 > arg1, float32
209                 {name: "CMPGTD", argLength: 2, reg: fp2flags, asm: "CMPGTD", typ: "Flags"}, // flags=true if arg0 > arg1, float64
210
211                 // moves
212                 {name: "MOVWconst", argLength: 0, reg: gp01, aux: "Int32", asm: "MOVW", typ: "UInt32", rematerializeable: true},    // auxint
213                 {name: "MOVFconst", argLength: 0, reg: fp01, aux: "Float32", asm: "MOVF", typ: "Float32", rematerializeable: true}, // auxint as 64-bit float, convert to 32-bit float
214                 {name: "MOVDconst", argLength: 0, reg: fp01, aux: "Float64", asm: "MOVD", typ: "Float64", rematerializeable: true}, // auxint as 64-bit float
215
216                 {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
217
218                 {name: "MOVBload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVB", typ: "Int8", faultOnNilArg0: true, symEffect: "Read"},     // load from arg0 + auxInt + aux.  arg1=mem.
219                 {name: "MOVBUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVBU", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read"},  // load from arg0 + auxInt + aux.  arg1=mem.
220                 {name: "MOVHload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVH", typ: "Int16", faultOnNilArg0: true, symEffect: "Read"},    // load from arg0 + auxInt + aux.  arg1=mem.
221                 {name: "MOVHUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVHU", typ: "UInt16", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux.  arg1=mem.
222                 {name: "MOVWload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVW", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read"},   // load from arg0 + auxInt + aux.  arg1=mem.
223                 {name: "MOVFload", argLength: 2, reg: fpload, aux: "SymOff", asm: "MOVF", typ: "Float32", faultOnNilArg0: true, symEffect: "Read"},  // load from arg0 + auxInt + aux.  arg1=mem.
224                 {name: "MOVDload", argLength: 2, reg: fpload, aux: "SymOff", asm: "MOVD", typ: "Float64", faultOnNilArg0: true, symEffect: "Read"},  // load from arg0 + auxInt + aux.  arg1=mem.
225
226                 {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.
227                 {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.
228                 {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.
229                 {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.
230                 {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.
231
232                 {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.
233                 {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.
234                 {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.
235
236                 // conversions
237                 {name: "MOVBreg", argLength: 1, reg: gp11, asm: "MOVB"},   // move from arg0, sign-extended from byte
238                 {name: "MOVBUreg", argLength: 1, reg: gp11, asm: "MOVBU"}, // move from arg0, unsign-extended from byte
239                 {name: "MOVHreg", argLength: 1, reg: gp11, asm: "MOVH"},   // move from arg0, sign-extended from half
240                 {name: "MOVHUreg", argLength: 1, reg: gp11, asm: "MOVHU"}, // move from arg0, unsign-extended from half
241                 {name: "MOVWreg", argLength: 1, reg: gp11, asm: "MOVW"},   // move from arg0
242
243                 {name: "MOVWnop", argLength: 1, reg: regInfo{inputs: []regMask{gp}, outputs: []regMask{gp}}, resultInArg0: true}, // nop, return arg0 in same register
244
245                 // conditional move on zero (returns arg1 if arg2 is 0, otherwise arg0)
246                 // order of parameters is reversed so we can use resultInArg0 (OpCMOVZ result arg1 arg2-> CMOVZ arg2reg, arg1reg, resultReg)
247                 {name: "CMOVZ", argLength: 3, reg: gp31, asm: "CMOVZ", resultInArg0: true},
248                 {name: "CMOVZzero", argLength: 2, reg: regInfo{inputs: []regMask{gp, gpg}, outputs: []regMask{gp}}, asm: "CMOVZ", resultInArg0: true},
249
250                 {name: "MOVWF", argLength: 1, reg: fp11, asm: "MOVWF"},     // int32 -> float32
251                 {name: "MOVWD", argLength: 1, reg: fp11, asm: "MOVWD"},     // int32 -> float64
252                 {name: "TRUNCFW", argLength: 1, reg: fp11, asm: "TRUNCFW"}, // float32 -> int32
253                 {name: "TRUNCDW", argLength: 1, reg: fp11, asm: "TRUNCDW"}, // float64 -> int32
254                 {name: "MOVFD", argLength: 1, reg: fp11, asm: "MOVFD"},     // float32 -> float64
255                 {name: "MOVDF", argLength: 1, reg: fp11, asm: "MOVDF"},     // float64 -> float32
256
257                 // function calls
258                 {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
259                 {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
260                 {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
261
262                 // atomic ops
263
264                 // load from arg0. arg1=mem.
265                 // returns <value,memory> so they can be properly ordered with other loads.
266                 // SYNC
267                 // MOV(B|W)     (Rarg0), Rout
268                 // SYNC
269                 {name: "LoweredAtomicLoad8", argLength: 2, reg: gpload, faultOnNilArg0: true},
270                 {name: "LoweredAtomicLoad32", argLength: 2, reg: gpload, faultOnNilArg0: true},
271
272                 // store arg1 to arg0. arg2=mem. returns memory.
273                 // SYNC
274                 // MOV(B|W)     Rarg1, (Rarg0)
275                 // SYNC
276                 {name: "LoweredAtomicStore8", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true},
277                 {name: "LoweredAtomicStore32", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true},
278                 {name: "LoweredAtomicStorezero", argLength: 2, reg: gpstore0, faultOnNilArg0: true, hasSideEffects: true},
279
280                 // atomic exchange.
281                 // store arg1 to arg0. arg2=mem. returns <old content of *arg0, memory>.
282                 // SYNC
283                 // LL   (Rarg0), Rout
284                 // MOVW Rarg1, Rtmp
285                 // SC   Rtmp, (Rarg0)
286                 // BEQ  Rtmp, -3(PC)
287                 // SYNC
288                 {name: "LoweredAtomicExchange", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
289
290                 // atomic add.
291                 // *arg0 += arg1. arg2=mem. returns <new content of *arg0, memory>.
292                 // SYNC
293                 // LL   (Rarg0), Rout
294                 // ADDU Rarg1, Rout, Rtmp
295                 // SC   Rtmp, (Rarg0)
296                 // BEQ  Rtmp, -3(PC)
297                 // SYNC
298                 // ADDU Rarg1, Rout
299                 {name: "LoweredAtomicAdd", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
300                 {name: "LoweredAtomicAddconst", argLength: 2, reg: regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}}, aux: "Int32", resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
301
302                 // atomic compare and swap.
303                 // arg0 = pointer, arg1 = old value, arg2 = new value, arg3 = memory.
304                 // if *arg0 == arg1 {
305                 //   *arg0 = arg2
306                 //   return (true, memory)
307                 // } else {
308                 //   return (false, memory)
309                 // }
310                 // SYNC
311                 // MOVW $0, Rout
312                 // LL   (Rarg0), Rtmp
313                 // BNE  Rtmp, Rarg1, 4(PC)
314                 // MOVW Rarg2, Rout
315                 // SC   Rout, (Rarg0)
316                 // BEQ  Rout, -4(PC)
317                 // SYNC
318                 {name: "LoweredAtomicCas", argLength: 4, reg: gpcas, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
319
320                 // atomic and/or.
321                 // *arg0 &= (|=) arg1. arg2=mem. returns memory.
322                 // SYNC
323                 // LL   (Rarg0), Rtmp
324                 // AND  Rarg1, Rtmp
325                 // SC   Rtmp, (Rarg0)
326                 // BEQ  Rtmp, -3(PC)
327                 // SYNC
328                 {name: "LoweredAtomicAnd", argLength: 3, reg: gpstore, asm: "AND", faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
329                 {name: "LoweredAtomicOr", argLength: 3, reg: gpstore, asm: "OR", faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
330
331                 // large or unaligned zeroing
332                 // arg0 = address of memory to zero (in R1, changed as side effect)
333                 // arg1 = address of the last element to zero
334                 // arg2 = mem
335                 // auxint = alignment
336                 // returns mem
337                 //      SUBU    $4, R1
338                 //      MOVW    R0, 4(R1)
339                 //      ADDU    $4, R1
340                 //      BNE     Rarg1, R1, -2(PC)
341                 {
342                         name:      "LoweredZero",
343                         aux:       "Int32",
344                         argLength: 3,
345                         reg: regInfo{
346                                 inputs:   []regMask{buildReg("R1"), gp},
347                                 clobbers: buildReg("R1"),
348                         },
349                         faultOnNilArg0: true,
350                 },
351
352                 // large or unaligned move
353                 // arg0 = address of dst memory (in R2, changed as side effect)
354                 // arg1 = address of src memory (in R1, changed as side effect)
355                 // arg2 = address of the last element of src
356                 // arg3 = mem
357                 // auxint = alignment
358                 // returns mem
359                 //      SUBU    $4, R1
360                 //      MOVW    4(R1), Rtmp
361                 //      MOVW    Rtmp, (R2)
362                 //      ADDU    $4, R1
363                 //      ADDU    $4, R2
364                 //      BNE     Rarg2, R1, -4(PC)
365                 {
366                         name:      "LoweredMove",
367                         aux:       "Int32",
368                         argLength: 4,
369                         reg: regInfo{
370                                 inputs:   []regMask{buildReg("R2"), buildReg("R1"), gp},
371                                 clobbers: buildReg("R1 R2"),
372                         },
373                         faultOnNilArg0: true,
374                         faultOnNilArg1: true,
375                 },
376
377                 // pseudo-ops
378                 {name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{gpg}}, nilCheck: true, faultOnNilArg0: true}, // panic if arg0 is nil.  arg1=mem.
379
380                 {name: "FPFlagTrue", argLength: 1, reg: readflags},  // bool, true if FP flag is true
381                 {name: "FPFlagFalse", argLength: 1, reg: readflags}, // bool, true if FP flag is false
382
383                 // Scheduler ensures LoweredGetClosurePtr occurs only in entry block,
384                 // and sorts it to the very beginning of the block to prevent other
385                 // use of R22 (mips.REGCTXT, the closure pointer)
386                 {name: "LoweredGetClosurePtr", reg: regInfo{outputs: []regMask{buildReg("R22")}}, zeroWidth: true},
387
388                 // LoweredGetCallerSP returns the SP of the caller of the current function.
389                 {name: "LoweredGetCallerSP", reg: gp01, rematerializeable: true},
390
391                 // LoweredGetCallerPC evaluates to the PC to which its "caller" will return.
392                 // I.e., if f calls g "calls" getcallerpc,
393                 // the result should be the PC within f that g will return to.
394                 // See runtime/stubs.go for a more detailed discussion.
395                 {name: "LoweredGetCallerPC", reg: gp01, rematerializeable: true},
396
397                 // LoweredWB invokes runtime.gcWriteBarrier. arg0=destptr, arg1=srcptr, arg2=mem, aux=runtime.gcWriteBarrier
398                 // It saves all GP registers if necessary,
399                 // but clobbers R31 (LR) because it's a call
400                 // and R23 (REGTMP).
401                 {name: "LoweredWB", argLength: 3, reg: regInfo{inputs: []regMask{buildReg("R20"), buildReg("R21")}, clobbers: (callerSave &^ gpg) | buildReg("R31")}, clobberFlags: true, aux: "Sym", symEffect: "None"},
402
403                 // There are three of these functions so that they can have three different register inputs.
404                 // When we check 0 <= c <= cap (A), then 0 <= b <= c (B), then 0 <= a <= b (C), we want the
405                 // default registers to match so we don't need to copy registers around unnecessarily.
406                 {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).
407                 {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).
408                 {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).
409                 // Extend ops are the same as Bounds ops except the indexes are 64-bit.
410                 {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).
411                 {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).
412                 {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).
413         }
414
415         blocks := []blockData{
416                 {name: "EQ", controls: 1},
417                 {name: "NE", controls: 1},
418                 {name: "LTZ", controls: 1}, // < 0
419                 {name: "LEZ", controls: 1}, // <= 0
420                 {name: "GTZ", controls: 1}, // > 0
421                 {name: "GEZ", controls: 1}, // >= 0
422                 {name: "FPT", controls: 1}, // FP flag is true
423                 {name: "FPF", controls: 1}, // FP flag is false
424         }
425
426         archs = append(archs, arch{
427                 name:            "MIPS",
428                 pkg:             "cmd/internal/obj/mips",
429                 genfile:         "../../mips/ssa.go",
430                 ops:             ops,
431                 blocks:          blocks,
432                 regnames:        regNamesMIPS,
433                 gpregmask:       gp,
434                 fpregmask:       fp,
435                 specialregmask:  hi | lo,
436                 framepointerreg: -1, // not used
437                 linkreg:         int8(num["R31"]),
438         })
439 }