github.com/corona10/go@v0.0.0-20180224231303-7a218942be57/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 // +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 // 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 ) 140 // Common regInfo 141 var ( 142 gp01 = regInfo{inputs: nil, outputs: []regMask{gp}} 143 gp11 = regInfo{inputs: []regMask{gpg}, outputs: []regMask{gp}} 144 gp11sp = regInfo{inputs: []regMask{gpspg}, outputs: []regMask{gp}} 145 gp21 = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{gp}} 146 gp2hilo = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{hi, lo}} 147 gpload = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}} 148 gpstore = regInfo{inputs: []regMask{gpspsbg, gpg}} 149 gpstore0 = regInfo{inputs: []regMask{gpspsbg}} 150 gpxchg = regInfo{inputs: []regMask{gpspsbg, gpg}, outputs: []regMask{gp}} 151 gpcas = regInfo{inputs: []regMask{gpspsbg, gpg, gpg}, outputs: []regMask{gp}} 152 fp01 = regInfo{inputs: nil, outputs: []regMask{fp}} 153 fp11 = regInfo{inputs: []regMask{fp}, outputs: []regMask{fp}} 154 //fp1flags = regInfo{inputs: []regMask{fp}} 155 //fpgp = regInfo{inputs: []regMask{fp}, outputs: []regMask{gp}} 156 //gpfp = regInfo{inputs: []regMask{gp}, outputs: []regMask{fp}} 157 fp21 = regInfo{inputs: []regMask{fp, fp}, outputs: []regMask{fp}} 158 fp2flags = regInfo{inputs: []regMask{fp, fp}} 159 fpload = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{fp}} 160 fpstore = regInfo{inputs: []regMask{gpspsbg, fp}} 161 readflags = regInfo{inputs: nil, outputs: []regMask{gp}} 162 ) 163 ops := []opData{ 164 // binary ops 165 {name: "ADDV", argLength: 2, reg: gp21, asm: "ADDVU", commutative: true}, // arg0 + arg1 166 {name: "ADDVconst", argLength: 1, reg: gp11sp, asm: "ADDVU", aux: "Int64"}, // arg0 + auxInt. auxInt is 32-bit, also in other *const ops. 167 {name: "SUBV", argLength: 2, reg: gp21, asm: "SUBVU"}, // arg0 - arg1 168 {name: "SUBVconst", argLength: 1, reg: gp11, asm: "SUBVU", aux: "Int64"}, // arg0 - auxInt 169 {name: "MULV", argLength: 2, reg: gp2hilo, asm: "MULV", commutative: true, typ: "(Int64,Int64)"}, // arg0 * arg1, signed, results hi,lo 170 {name: "MULVU", argLength: 2, reg: gp2hilo, asm: "MULVU", commutative: true, typ: "(UInt64,UInt64)"}, // arg0 * arg1, unsigned, results hi,lo 171 {name: "DIVV", argLength: 2, reg: gp2hilo, asm: "DIVV", typ: "(Int64,Int64)"}, // arg0 / arg1, signed, results hi=arg0%arg1,lo=arg0/arg1 172 {name: "DIVVU", argLength: 2, reg: gp2hilo, asm: "DIVVU", typ: "(UInt64,UInt64)"}, // arg0 / arg1, signed, results hi=arg0%arg1,lo=arg0/arg1 173 174 {name: "ADDF", argLength: 2, reg: fp21, asm: "ADDF", commutative: true}, // arg0 + arg1 175 {name: "ADDD", argLength: 2, reg: fp21, asm: "ADDD", commutative: true}, // arg0 + arg1 176 {name: "SUBF", argLength: 2, reg: fp21, asm: "SUBF"}, // arg0 - arg1 177 {name: "SUBD", argLength: 2, reg: fp21, asm: "SUBD"}, // arg0 - arg1 178 {name: "MULF", argLength: 2, reg: fp21, asm: "MULF", commutative: true}, // arg0 * arg1 179 {name: "MULD", argLength: 2, reg: fp21, asm: "MULD", commutative: true}, // arg0 * arg1 180 {name: "DIVF", argLength: 2, reg: fp21, asm: "DIVF"}, // arg0 / arg1 181 {name: "DIVD", argLength: 2, reg: fp21, asm: "DIVD"}, // arg0 / arg1 182 183 {name: "AND", argLength: 2, reg: gp21, asm: "AND", commutative: true}, // arg0 & arg1 184 {name: "ANDconst", argLength: 1, reg: gp11, asm: "AND", aux: "Int64"}, // arg0 & auxInt 185 {name: "OR", argLength: 2, reg: gp21, asm: "OR", commutative: true}, // arg0 | arg1 186 {name: "ORconst", argLength: 1, reg: gp11, asm: "OR", aux: "Int64"}, // arg0 | auxInt 187 {name: "XOR", argLength: 2, reg: gp21, asm: "XOR", commutative: true, typ: "UInt64"}, // arg0 ^ arg1 188 {name: "XORconst", argLength: 1, reg: gp11, asm: "XOR", aux: "Int64", typ: "UInt64"}, // arg0 ^ auxInt 189 {name: "NOR", argLength: 2, reg: gp21, asm: "NOR", commutative: true}, // ^(arg0 | arg1) 190 {name: "NORconst", argLength: 1, reg: gp11, asm: "NOR", aux: "Int64"}, // ^(arg0 | auxInt) 191 192 {name: "NEGV", argLength: 1, reg: gp11}, // -arg0 193 {name: "NEGF", argLength: 1, reg: fp11, asm: "NEGF"}, // -arg0, float32 194 {name: "NEGD", argLength: 1, reg: fp11, asm: "NEGD"}, // -arg0, float64 195 {name: "SQRTD", argLength: 1, reg: fp11, asm: "SQRTD"}, // sqrt(arg0), float64 196 197 // shifts 198 {name: "SLLV", argLength: 2, reg: gp21, asm: "SLLV"}, // arg0 << arg1, shift amount is mod 64 199 {name: "SLLVconst", argLength: 1, reg: gp11, asm: "SLLV", aux: "Int64"}, // arg0 << auxInt 200 {name: "SRLV", argLength: 2, reg: gp21, asm: "SRLV"}, // arg0 >> arg1, unsigned, shift amount is mod 64 201 {name: "SRLVconst", argLength: 1, reg: gp11, asm: "SRLV", aux: "Int64"}, // arg0 >> auxInt, unsigned 202 {name: "SRAV", argLength: 2, reg: gp21, asm: "SRAV"}, // arg0 >> arg1, signed, shift amount is mod 64 203 {name: "SRAVconst", argLength: 1, reg: gp11, asm: "SRAV", aux: "Int64"}, // arg0 >> auxInt, signed 204 205 // comparisons 206 {name: "SGT", argLength: 2, reg: gp21, asm: "SGT", typ: "Bool"}, // 1 if arg0 > arg1 (signed), 0 otherwise 207 {name: "SGTconst", argLength: 1, reg: gp11, asm: "SGT", aux: "Int64", typ: "Bool"}, // 1 if auxInt > arg0 (signed), 0 otherwise 208 {name: "SGTU", argLength: 2, reg: gp21, asm: "SGTU", typ: "Bool"}, // 1 if arg0 > arg1 (unsigned), 0 otherwise 209 {name: "SGTUconst", argLength: 1, reg: gp11, asm: "SGTU", aux: "Int64", typ: "Bool"}, // 1 if auxInt > arg0 (unsigned), 0 otherwise 210 211 {name: "CMPEQF", argLength: 2, reg: fp2flags, asm: "CMPEQF", typ: "Flags"}, // flags=true if arg0 = arg1, float32 212 {name: "CMPEQD", argLength: 2, reg: fp2flags, asm: "CMPEQD", typ: "Flags"}, // flags=true if arg0 = arg1, float64 213 {name: "CMPGEF", argLength: 2, reg: fp2flags, asm: "CMPGEF", typ: "Flags"}, // flags=true if arg0 >= arg1, float32 214 {name: "CMPGED", argLength: 2, reg: fp2flags, asm: "CMPGED", typ: "Flags"}, // flags=true if arg0 >= arg1, float64 215 {name: "CMPGTF", argLength: 2, reg: fp2flags, asm: "CMPGTF", typ: "Flags"}, // flags=true if arg0 > arg1, float32 216 {name: "CMPGTD", argLength: 2, reg: fp2flags, asm: "CMPGTD", typ: "Flags"}, // flags=true if arg0 > arg1, float64 217 218 // moves 219 {name: "MOVVconst", argLength: 0, reg: gp01, aux: "Int64", asm: "MOVV", typ: "UInt64", rematerializeable: true}, // auxint 220 {name: "MOVFconst", argLength: 0, reg: fp01, aux: "Float64", asm: "MOVF", typ: "Float32", rematerializeable: true}, // auxint as 64-bit float, convert to 32-bit float 221 {name: "MOVDconst", argLength: 0, reg: fp01, aux: "Float64", asm: "MOVD", typ: "Float64", rematerializeable: true}, // auxint as 64-bit float 222 223 {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 224 225 {name: "MOVBload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVB", typ: "Int8", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 226 {name: "MOVBUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVBU", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 227 {name: "MOVHload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVH", typ: "Int16", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 228 {name: "MOVHUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVHU", typ: "UInt16", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 229 {name: "MOVWload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVW", typ: "Int32", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 230 {name: "MOVWUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVWU", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 231 {name: "MOVVload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVV", typ: "UInt64", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 232 {name: "MOVFload", argLength: 2, reg: fpload, aux: "SymOff", asm: "MOVF", typ: "Float32", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 233 {name: "MOVDload", argLength: 2, reg: fpload, aux: "SymOff", asm: "MOVD", typ: "Float64", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 234 235 {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. 236 {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. 237 {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. 238 {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. 239 {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. 240 {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. 241 242 {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. 243 {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. 244 {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. 245 {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. 246 247 // conversions 248 {name: "MOVBreg", argLength: 1, reg: gp11, asm: "MOVB"}, // move from arg0, sign-extended from byte 249 {name: "MOVBUreg", argLength: 1, reg: gp11, asm: "MOVBU"}, // move from arg0, unsign-extended from byte 250 {name: "MOVHreg", argLength: 1, reg: gp11, asm: "MOVH"}, // move from arg0, sign-extended from half 251 {name: "MOVHUreg", argLength: 1, reg: gp11, asm: "MOVHU"}, // move from arg0, unsign-extended from half 252 {name: "MOVWreg", argLength: 1, reg: gp11, asm: "MOVW"}, // move from arg0, sign-extended from word 253 {name: "MOVWUreg", argLength: 1, reg: gp11, asm: "MOVWU"}, // move from arg0, unsign-extended from word 254 {name: "MOVVreg", argLength: 1, reg: gp11, asm: "MOVV"}, // move from arg0 255 256 {name: "MOVVnop", argLength: 1, reg: regInfo{inputs: []regMask{gp}, outputs: []regMask{gp}}, resultInArg0: true}, // nop, return arg0 in same register 257 258 {name: "MOVWF", argLength: 1, reg: fp11, asm: "MOVWF"}, // int32 -> float32 259 {name: "MOVWD", argLength: 1, reg: fp11, asm: "MOVWD"}, // int32 -> float64 260 {name: "MOVVF", argLength: 1, reg: fp11, asm: "MOVVF"}, // int64 -> float32 261 {name: "MOVVD", argLength: 1, reg: fp11, asm: "MOVVD"}, // int64 -> float64 262 {name: "TRUNCFW", argLength: 1, reg: fp11, asm: "TRUNCFW"}, // float32 -> int32 263 {name: "TRUNCDW", argLength: 1, reg: fp11, asm: "TRUNCDW"}, // float64 -> int32 264 {name: "TRUNCFV", argLength: 1, reg: fp11, asm: "TRUNCFV"}, // float32 -> int64 265 {name: "TRUNCDV", argLength: 1, reg: fp11, asm: "TRUNCDV"}, // float64 -> int64 266 {name: "MOVFD", argLength: 1, reg: fp11, asm: "MOVFD"}, // float32 -> float64 267 {name: "MOVDF", argLength: 1, reg: fp11, asm: "MOVDF"}, // float64 -> float32 268 269 // function calls 270 {name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "SymOff", clobberFlags: true, call: true, symEffect: "None"}, // call static function aux.(*obj.LSym). arg0=mem, auxint=argsize, returns mem 271 {name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{gpsp, buildReg("R22"), 0}, clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem 272 {name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true}, // call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem 273 274 // duffzero 275 // arg0 = address of memory to zero 276 // arg1 = mem 277 // auxint = offset into duffzero code to start executing 278 // returns mem 279 // R1 aka mips.REGRT1 changed as side effect 280 { 281 name: "DUFFZERO", 282 aux: "Int64", 283 argLength: 2, 284 reg: regInfo{ 285 inputs: []regMask{gp}, 286 clobbers: buildReg("R1 R31"), 287 }, 288 faultOnNilArg0: true, 289 }, 290 291 // large or unaligned zeroing 292 // arg0 = address of memory to zero (in R1, changed as side effect) 293 // arg1 = address of the last element to zero 294 // arg2 = mem 295 // auxint = alignment 296 // returns mem 297 // SUBV $8, R1 298 // MOVV R0, 8(R1) 299 // ADDV $8, R1 300 // BNE Rarg1, R1, -2(PC) 301 { 302 name: "LoweredZero", 303 aux: "Int64", 304 argLength: 3, 305 reg: regInfo{ 306 inputs: []regMask{buildReg("R1"), gp}, 307 clobbers: buildReg("R1"), 308 }, 309 clobberFlags: true, 310 faultOnNilArg0: true, 311 }, 312 313 // large or unaligned move 314 // arg0 = address of dst memory (in R2, changed as side effect) 315 // arg1 = address of src memory (in R1, changed as side effect) 316 // arg2 = address of the last element of src 317 // arg3 = mem 318 // auxint = alignment 319 // returns mem 320 // SUBV $8, R1 321 // MOVV 8(R1), Rtmp 322 // MOVV Rtmp, (R2) 323 // ADDV $8, R1 324 // ADDV $8, R2 325 // BNE Rarg2, R1, -4(PC) 326 { 327 name: "LoweredMove", 328 aux: "Int64", 329 argLength: 4, 330 reg: regInfo{ 331 inputs: []regMask{buildReg("R2"), buildReg("R1"), gp}, 332 clobbers: buildReg("R1 R2"), 333 }, 334 clobberFlags: true, 335 faultOnNilArg0: true, 336 faultOnNilArg1: true, 337 }, 338 339 // atomic loads. 340 // load from arg0. arg1=mem. 341 // returns <value,memory> so they can be properly ordered with other loads. 342 {name: "LoweredAtomicLoad32", argLength: 2, reg: gpload, faultOnNilArg0: true}, 343 {name: "LoweredAtomicLoad64", argLength: 2, reg: gpload, faultOnNilArg0: true}, 344 345 // atomic stores. 346 // store arg1 to arg0. arg2=mem. returns memory. 347 {name: "LoweredAtomicStore32", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true}, 348 {name: "LoweredAtomicStore64", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true}, 349 // store zero to arg0. arg1=mem. returns memory. 350 {name: "LoweredAtomicStorezero32", argLength: 2, reg: gpstore0, faultOnNilArg0: true, hasSideEffects: true}, 351 {name: "LoweredAtomicStorezero64", argLength: 2, reg: gpstore0, faultOnNilArg0: true, hasSideEffects: true}, 352 353 // atomic exchange. 354 // store arg1 to arg0. arg2=mem. returns <old content of *arg0, memory>. 355 // SYNC 356 // LL (Rarg0), Rout 357 // MOVV Rarg1, Rtmp 358 // SC Rtmp, (Rarg0) 359 // BEQ Rtmp, -3(PC) 360 // SYNC 361 {name: "LoweredAtomicExchange32", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true}, 362 {name: "LoweredAtomicExchange64", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true}, 363 364 // atomic add. 365 // *arg0 += arg1. arg2=mem. returns <new content of *arg0, memory>. 366 // SYNC 367 // LL (Rarg0), Rout 368 // ADDV Rarg1, Rout, Rtmp 369 // SC Rtmp, (Rarg0) 370 // BEQ Rtmp, -3(PC) 371 // SYNC 372 // ADDV Rarg1, Rout 373 {name: "LoweredAtomicAdd32", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true}, 374 {name: "LoweredAtomicAdd64", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true}, 375 // *arg0 += auxint. arg1=mem. returns <new content of *arg0, memory>. auxint is 32-bit. 376 {name: "LoweredAtomicAddconst32", argLength: 2, reg: regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}}, aux: "Int32", resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true}, 377 {name: "LoweredAtomicAddconst64", argLength: 2, reg: regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}}, aux: "Int64", resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true}, 378 379 // atomic compare and swap. 380 // arg0 = pointer, arg1 = old value, arg2 = new value, arg3 = memory. 381 // if *arg0 == arg1 { 382 // *arg0 = arg2 383 // return (true, memory) 384 // } else { 385 // return (false, memory) 386 // } 387 // SYNC 388 // MOVV $0, Rout 389 // LL (Rarg0), Rtmp 390 // BNE Rtmp, Rarg1, 4(PC) 391 // MOVV Rarg2, Rout 392 // SC Rout, (Rarg0) 393 // BEQ Rout, -4(PC) 394 // SYNC 395 {name: "LoweredAtomicCas32", argLength: 4, reg: gpcas, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true}, 396 {name: "LoweredAtomicCas64", argLength: 4, reg: gpcas, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true}, 397 398 // pseudo-ops 399 {name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{gpg}}, nilCheck: true, faultOnNilArg0: true}, // panic if arg0 is nil. arg1=mem. 400 401 {name: "FPFlagTrue", argLength: 1, reg: readflags}, // bool, true if FP flag is true 402 {name: "FPFlagFalse", argLength: 1, reg: readflags}, // bool, true if FP flag is false 403 404 // Scheduler ensures LoweredGetClosurePtr occurs only in entry block, 405 // and sorts it to the very beginning of the block to prevent other 406 // use of R22 (mips.REGCTXT, the closure pointer) 407 {name: "LoweredGetClosurePtr", reg: regInfo{outputs: []regMask{buildReg("R22")}}}, 408 409 // LoweredGetCallerSP returns the SP of the caller of the current function. 410 {name: "LoweredGetCallerSP", reg: gp01, rematerializeable: true}, 411 412 // LoweredWB invokes runtime.gcWriteBarrier. arg0=destptr, arg1=srcptr, arg2=mem, aux=runtime.gcWriteBarrier 413 // It saves all GP registers if necessary, 414 // but clobbers R31 (LR) because it's a call 415 // and R23 (REGTMP). 416 {name: "LoweredWB", argLength: 3, reg: regInfo{inputs: []regMask{buildReg("R20"), buildReg("R21")}, clobbers: (callerSave &^ gpg) | buildReg("R31")}, clobberFlags: true, aux: "Sym", symEffect: "None"}, 417 418 // MOVDconvert converts between pointers and integers. 419 // We have a special op for this so as to not confuse GC 420 // (particularly stack maps). It takes a memory arg so it 421 // gets correctly ordered with respect to GC safepoints. 422 // arg0=ptr/int arg1=mem, output=int/ptr 423 {name: "MOVVconvert", argLength: 2, reg: gp11, asm: "MOVV"}, 424 } 425 426 blocks := []blockData{ 427 {name: "EQ"}, 428 {name: "NE"}, 429 {name: "LTZ"}, // < 0 430 {name: "LEZ"}, // <= 0 431 {name: "GTZ"}, // > 0 432 {name: "GEZ"}, // >= 0 433 {name: "FPT"}, // FP flag is true 434 {name: "FPF"}, // FP flag is false 435 } 436 437 archs = append(archs, arch{ 438 name: "MIPS64", 439 pkg: "cmd/internal/obj/mips", 440 genfile: "../../mips64/ssa.go", 441 ops: ops, 442 blocks: blocks, 443 regnames: regNamesMIPS64, 444 gpregmask: gp, 445 fpregmask: fp, 446 specialregmask: hi | lo, 447 framepointerreg: -1, // not used 448 linkreg: int8(num["R31"]), 449 }) 450 }