github.com/bir3/gocompiler@v0.3.205/src/cmd/compile/internal/ssa/_gen/MIPS64Ops.go (about) 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 package main 6 7 import "strings" 8 9 // Notes: 10 // - Integer types live in the low portion of registers. Upper portions are junk. 11 // - Boolean types use the low-order byte of a register. 0=false, 1=true. 12 // Upper bytes are junk. 13 // - *const instructions may use a constant larger than the instruction can encode. 14 // In this case the assembler expands to multiple instructions and uses tmp 15 // register (R23). 16 17 // Suffixes encode the bit width of various instructions. 18 // V (vlong) = 64 bit 19 // WU (word) = 32 bit unsigned 20 // W (word) = 32 bit 21 // H (half word) = 16 bit 22 // HU = 16 bit unsigned 23 // B (byte) = 8 bit 24 // BU = 8 bit unsigned 25 // F (float) = 32 bit float 26 // D (double) = 64 bit float 27 28 // Note: registers not used in regalloc are not included in this list, 29 // so that regmask stays within int64 30 // Be careful when hand coding regmasks. 31 var regNamesMIPS64 = []string{ 32 "R0", // constant 0 33 "R1", 34 "R2", 35 "R3", 36 "R4", 37 "R5", 38 "R6", 39 "R7", 40 "R8", 41 "R9", 42 "R10", 43 "R11", 44 "R12", 45 "R13", 46 "R14", 47 "R15", 48 "R16", 49 "R17", 50 "R18", 51 "R19", 52 "R20", 53 "R21", 54 "R22", 55 // R23 = REGTMP not used in regalloc 56 "R24", 57 "R25", 58 // R26 reserved by kernel 59 // R27 reserved by kernel 60 // R28 = REGSB not used in regalloc 61 "SP", // aka R29 62 "g", // aka R30 63 "R31", // aka REGLINK 64 65 "F0", 66 "F1", 67 "F2", 68 "F3", 69 "F4", 70 "F5", 71 "F6", 72 "F7", 73 "F8", 74 "F9", 75 "F10", 76 "F11", 77 "F12", 78 "F13", 79 "F14", 80 "F15", 81 "F16", 82 "F17", 83 "F18", 84 "F19", 85 "F20", 86 "F21", 87 "F22", 88 "F23", 89 "F24", 90 "F25", 91 "F26", 92 "F27", 93 "F28", 94 "F29", 95 "F30", 96 "F31", 97 98 "HI", // high bits of multiplication 99 "LO", // low bits of multiplication 100 101 // If you add registers, update asyncPreempt in runtime. 102 103 // pseudo-registers 104 "SB", 105 } 106 107 func init() { 108 // Make map from reg names to reg integers. 109 if len(regNamesMIPS64) > 64 { 110 panic("too many registers") 111 } 112 num := map[string]int{} 113 for i, name := range regNamesMIPS64 { 114 num[name] = i 115 } 116 buildReg := func(s string) regMask { 117 m := regMask(0) 118 for _, r := range strings.Split(s, " ") { 119 if n, ok := num[r]; ok { 120 m |= regMask(1) << uint(n) 121 continue 122 } 123 panic("register " + r + " not found") 124 } 125 return m 126 } 127 128 // Common individual register masks 129 var ( 130 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") 131 gpg = gp | buildReg("g") 132 gpsp = gp | buildReg("SP") 133 gpspg = gpg | buildReg("SP") 134 gpspsbg = gpspg | buildReg("SB") 135 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") 136 lo = buildReg("LO") 137 hi = buildReg("HI") 138 callerSave = gp | fp | lo | hi | buildReg("g") // runtime.setg (and anything calling it) may clobber g 139 r1 = buildReg("R1") 140 r2 = buildReg("R2") 141 r3 = buildReg("R3") 142 r4 = buildReg("R4") 143 ) 144 // Common regInfo 145 var ( 146 gp01 = regInfo{inputs: nil, outputs: []regMask{gp}} 147 gp11 = regInfo{inputs: []regMask{gpg}, outputs: []regMask{gp}} 148 gp11sp = regInfo{inputs: []regMask{gpspg}, outputs: []regMask{gp}} 149 gp21 = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{gp}} 150 gp2hilo = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{hi, lo}} 151 gpload = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}} 152 gpstore = regInfo{inputs: []regMask{gpspsbg, gpg}} 153 gpstore0 = regInfo{inputs: []regMask{gpspsbg}} 154 gpxchg = regInfo{inputs: []regMask{gpspsbg, gpg}, outputs: []regMask{gp}} 155 gpcas = regInfo{inputs: []regMask{gpspsbg, gpg, gpg}, outputs: []regMask{gp}} 156 fp01 = regInfo{inputs: nil, outputs: []regMask{fp}} 157 fp11 = regInfo{inputs: []regMask{fp}, outputs: []regMask{fp}} 158 //fp1flags = regInfo{inputs: []regMask{fp}} 159 //fpgp = regInfo{inputs: []regMask{fp}, outputs: []regMask{gp}} 160 //gpfp = regInfo{inputs: []regMask{gp}, outputs: []regMask{fp}} 161 fp21 = regInfo{inputs: []regMask{fp, fp}, outputs: []regMask{fp}} 162 fp2flags = regInfo{inputs: []regMask{fp, fp}} 163 fpload = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{fp}} 164 fpstore = regInfo{inputs: []regMask{gpspsbg, fp}} 165 readflags = regInfo{inputs: nil, outputs: []regMask{gp}} 166 ) 167 ops := []opData{ 168 // binary ops 169 {name: "ADDV", argLength: 2, reg: gp21, asm: "ADDVU", commutative: true}, // arg0 + arg1 170 {name: "ADDVconst", argLength: 1, reg: gp11sp, asm: "ADDVU", aux: "Int64"}, // arg0 + auxInt. auxInt is 32-bit, also in other *const ops. 171 {name: "SUBV", argLength: 2, reg: gp21, asm: "SUBVU"}, // arg0 - arg1 172 {name: "SUBVconst", argLength: 1, reg: gp11, asm: "SUBVU", aux: "Int64"}, // arg0 - auxInt 173 {name: "MULV", argLength: 2, reg: gp2hilo, asm: "MULV", commutative: true, typ: "(Int64,Int64)"}, // arg0 * arg1, signed, results hi,lo 174 {name: "MULVU", argLength: 2, reg: gp2hilo, asm: "MULVU", commutative: true, typ: "(UInt64,UInt64)"}, // arg0 * arg1, unsigned, results hi,lo 175 {name: "DIVV", argLength: 2, reg: gp2hilo, asm: "DIVV", typ: "(Int64,Int64)"}, // arg0 / arg1, signed, results hi=arg0%arg1,lo=arg0/arg1 176 {name: "DIVVU", argLength: 2, reg: gp2hilo, asm: "DIVVU", typ: "(UInt64,UInt64)"}, // arg0 / arg1, signed, results hi=arg0%arg1,lo=arg0/arg1 177 178 {name: "ADDF", argLength: 2, reg: fp21, asm: "ADDF", commutative: true}, // arg0 + arg1 179 {name: "ADDD", argLength: 2, reg: fp21, asm: "ADDD", commutative: true}, // arg0 + arg1 180 {name: "SUBF", argLength: 2, reg: fp21, asm: "SUBF"}, // arg0 - arg1 181 {name: "SUBD", argLength: 2, reg: fp21, asm: "SUBD"}, // arg0 - arg1 182 {name: "MULF", argLength: 2, reg: fp21, asm: "MULF", commutative: true}, // arg0 * arg1 183 {name: "MULD", argLength: 2, reg: fp21, asm: "MULD", commutative: true}, // arg0 * arg1 184 {name: "DIVF", argLength: 2, reg: fp21, asm: "DIVF"}, // arg0 / arg1 185 {name: "DIVD", argLength: 2, reg: fp21, asm: "DIVD"}, // arg0 / arg1 186 187 {name: "AND", argLength: 2, reg: gp21, asm: "AND", commutative: true}, // arg0 & arg1 188 {name: "ANDconst", argLength: 1, reg: gp11, asm: "AND", aux: "Int64"}, // arg0 & auxInt 189 {name: "OR", argLength: 2, reg: gp21, asm: "OR", commutative: true}, // arg0 | arg1 190 {name: "ORconst", argLength: 1, reg: gp11, asm: "OR", aux: "Int64"}, // arg0 | auxInt 191 {name: "XOR", argLength: 2, reg: gp21, asm: "XOR", commutative: true, typ: "UInt64"}, // arg0 ^ arg1 192 {name: "XORconst", argLength: 1, reg: gp11, asm: "XOR", aux: "Int64", typ: "UInt64"}, // arg0 ^ auxInt 193 {name: "NOR", argLength: 2, reg: gp21, asm: "NOR", commutative: true}, // ^(arg0 | arg1) 194 {name: "NORconst", argLength: 1, reg: gp11, asm: "NOR", aux: "Int64"}, // ^(arg0 | auxInt) 195 196 {name: "NEGV", argLength: 1, reg: gp11}, // -arg0 197 {name: "NEGF", argLength: 1, reg: fp11, asm: "NEGF"}, // -arg0, float32 198 {name: "NEGD", argLength: 1, reg: fp11, asm: "NEGD"}, // -arg0, float64 199 {name: "SQRTD", argLength: 1, reg: fp11, asm: "SQRTD"}, // sqrt(arg0), float64 200 {name: "SQRTF", argLength: 1, reg: fp11, asm: "SQRTF"}, // sqrt(arg0), float32 201 202 // shifts 203 {name: "SLLV", argLength: 2, reg: gp21, asm: "SLLV"}, // arg0 << arg1, shift amount is mod 64 204 {name: "SLLVconst", argLength: 1, reg: gp11, asm: "SLLV", aux: "Int64"}, // arg0 << auxInt 205 {name: "SRLV", argLength: 2, reg: gp21, asm: "SRLV"}, // arg0 >> arg1, unsigned, shift amount is mod 64 206 {name: "SRLVconst", argLength: 1, reg: gp11, asm: "SRLV", aux: "Int64"}, // arg0 >> auxInt, unsigned 207 {name: "SRAV", argLength: 2, reg: gp21, asm: "SRAV"}, // arg0 >> arg1, signed, shift amount is mod 64 208 {name: "SRAVconst", argLength: 1, reg: gp11, asm: "SRAV", aux: "Int64"}, // arg0 >> auxInt, signed 209 210 // comparisons 211 {name: "SGT", argLength: 2, reg: gp21, asm: "SGT", typ: "Bool"}, // 1 if arg0 > arg1 (signed), 0 otherwise 212 {name: "SGTconst", argLength: 1, reg: gp11, asm: "SGT", aux: "Int64", typ: "Bool"}, // 1 if auxInt > arg0 (signed), 0 otherwise 213 {name: "SGTU", argLength: 2, reg: gp21, asm: "SGTU", typ: "Bool"}, // 1 if arg0 > arg1 (unsigned), 0 otherwise 214 {name: "SGTUconst", argLength: 1, reg: gp11, asm: "SGTU", aux: "Int64", typ: "Bool"}, // 1 if auxInt > arg0 (unsigned), 0 otherwise 215 216 {name: "CMPEQF", argLength: 2, reg: fp2flags, asm: "CMPEQF", typ: "Flags"}, // flags=true if arg0 = arg1, float32 217 {name: "CMPEQD", argLength: 2, reg: fp2flags, asm: "CMPEQD", typ: "Flags"}, // flags=true if arg0 = arg1, float64 218 {name: "CMPGEF", argLength: 2, reg: fp2flags, asm: "CMPGEF", typ: "Flags"}, // flags=true if arg0 >= arg1, float32 219 {name: "CMPGED", argLength: 2, reg: fp2flags, asm: "CMPGED", typ: "Flags"}, // flags=true if arg0 >= arg1, float64 220 {name: "CMPGTF", argLength: 2, reg: fp2flags, asm: "CMPGTF", typ: "Flags"}, // flags=true if arg0 > arg1, float32 221 {name: "CMPGTD", argLength: 2, reg: fp2flags, asm: "CMPGTD", typ: "Flags"}, // flags=true if arg0 > arg1, float64 222 223 // moves 224 {name: "MOVVconst", argLength: 0, reg: gp01, aux: "Int64", asm: "MOVV", typ: "UInt64", rematerializeable: true}, // auxint 225 {name: "MOVFconst", argLength: 0, reg: fp01, aux: "Float64", asm: "MOVF", typ: "Float32", rematerializeable: true}, // auxint as 64-bit float, convert to 32-bit float 226 {name: "MOVDconst", argLength: 0, reg: fp01, aux: "Float64", asm: "MOVD", typ: "Float64", rematerializeable: true}, // auxint as 64-bit float 227 228 {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 229 230 {name: "MOVBload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVB", typ: "Int8", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 231 {name: "MOVBUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVBU", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 232 {name: "MOVHload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVH", typ: "Int16", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 233 {name: "MOVHUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVHU", typ: "UInt16", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 234 {name: "MOVWload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVW", typ: "Int32", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 235 {name: "MOVWUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVWU", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 236 {name: "MOVVload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVV", typ: "UInt64", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 237 {name: "MOVFload", argLength: 2, reg: fpload, aux: "SymOff", asm: "MOVF", typ: "Float32", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 238 {name: "MOVDload", argLength: 2, reg: fpload, aux: "SymOff", asm: "MOVD", typ: "Float64", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 239 240 {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. 241 {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. 242 {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. 243 {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. 244 {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. 245 {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. 246 247 {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. 248 {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. 249 {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. 250 {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. 251 252 // conversions 253 {name: "MOVBreg", argLength: 1, reg: gp11, asm: "MOVB"}, // move from arg0, sign-extended from byte 254 {name: "MOVBUreg", argLength: 1, reg: gp11, asm: "MOVBU"}, // move from arg0, unsign-extended from byte 255 {name: "MOVHreg", argLength: 1, reg: gp11, asm: "MOVH"}, // move from arg0, sign-extended from half 256 {name: "MOVHUreg", argLength: 1, reg: gp11, asm: "MOVHU"}, // move from arg0, unsign-extended from half 257 {name: "MOVWreg", argLength: 1, reg: gp11, asm: "MOVW"}, // move from arg0, sign-extended from word 258 {name: "MOVWUreg", argLength: 1, reg: gp11, asm: "MOVWU"}, // move from arg0, unsign-extended from word 259 {name: "MOVVreg", argLength: 1, reg: gp11, asm: "MOVV"}, // move from arg0 260 261 {name: "MOVVnop", argLength: 1, reg: regInfo{inputs: []regMask{gp}, outputs: []regMask{gp}}, resultInArg0: true}, // nop, return arg0 in same register 262 263 {name: "MOVWF", argLength: 1, reg: fp11, asm: "MOVWF"}, // int32 -> float32 264 {name: "MOVWD", argLength: 1, reg: fp11, asm: "MOVWD"}, // int32 -> float64 265 {name: "MOVVF", argLength: 1, reg: fp11, asm: "MOVVF"}, // int64 -> float32 266 {name: "MOVVD", argLength: 1, reg: fp11, asm: "MOVVD"}, // int64 -> float64 267 {name: "TRUNCFW", argLength: 1, reg: fp11, asm: "TRUNCFW"}, // float32 -> int32 268 {name: "TRUNCDW", argLength: 1, reg: fp11, asm: "TRUNCDW"}, // float64 -> int32 269 {name: "TRUNCFV", argLength: 1, reg: fp11, asm: "TRUNCFV"}, // float32 -> int64 270 {name: "TRUNCDV", argLength: 1, reg: fp11, asm: "TRUNCDV"}, // float64 -> int64 271 {name: "MOVFD", argLength: 1, reg: fp11, asm: "MOVFD"}, // float32 -> float64 272 {name: "MOVDF", argLength: 1, reg: fp11, asm: "MOVDF"}, // float64 -> float32 273 274 // function calls 275 {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 276 {name: "CALLtail", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true, tailCall: true}, // tail 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 }