github.com/ltltlt/go-source-code@v0.0.0-20190830023027-95be009773aa/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 196 // shifts 197 {name: "SLLV", argLength: 2, reg: gp21, asm: "SLLV"}, // arg0 << arg1, shift amount is mod 64 198 {name: "SLLVconst", argLength: 1, reg: gp11, asm: "SLLV", aux: "Int64"}, // arg0 << auxInt 199 {name: "SRLV", argLength: 2, reg: gp21, asm: "SRLV"}, // arg0 >> arg1, unsigned, shift amount is mod 64 200 {name: "SRLVconst", argLength: 1, reg: gp11, asm: "SRLV", aux: "Int64"}, // arg0 >> auxInt, unsigned 201 {name: "SRAV", argLength: 2, reg: gp21, asm: "SRAV"}, // arg0 >> arg1, signed, shift amount is mod 64 202 {name: "SRAVconst", argLength: 1, reg: gp11, asm: "SRAV", aux: "Int64"}, // arg0 >> auxInt, signed 203 204 // comparisons 205 {name: "SGT", argLength: 2, reg: gp21, asm: "SGT", typ: "Bool"}, // 1 if arg0 > arg1 (signed), 0 otherwise 206 {name: "SGTconst", argLength: 1, reg: gp11, asm: "SGT", aux: "Int64", typ: "Bool"}, // 1 if auxInt > arg0 (signed), 0 otherwise 207 {name: "SGTU", argLength: 2, reg: gp21, asm: "SGTU", typ: "Bool"}, // 1 if arg0 > arg1 (unsigned), 0 otherwise 208 {name: "SGTUconst", argLength: 1, reg: gp11, asm: "SGTU", aux: "Int64", typ: "Bool"}, // 1 if auxInt > arg0 (unsigned), 0 otherwise 209 210 {name: "CMPEQF", argLength: 2, reg: fp2flags, asm: "CMPEQF", typ: "Flags"}, // flags=true if arg0 = arg1, float32 211 {name: "CMPEQD", argLength: 2, reg: fp2flags, asm: "CMPEQD", typ: "Flags"}, // flags=true if arg0 = arg1, float64 212 {name: "CMPGEF", argLength: 2, reg: fp2flags, asm: "CMPGEF", typ: "Flags"}, // flags=true if arg0 >= arg1, float32 213 {name: "CMPGED", argLength: 2, reg: fp2flags, asm: "CMPGED", typ: "Flags"}, // flags=true if arg0 >= arg1, float64 214 {name: "CMPGTF", argLength: 2, reg: fp2flags, asm: "CMPGTF", typ: "Flags"}, // flags=true if arg0 > arg1, float32 215 {name: "CMPGTD", argLength: 2, reg: fp2flags, asm: "CMPGTD", typ: "Flags"}, // flags=true if arg0 > arg1, float64 216 217 // moves 218 {name: "MOVVconst", argLength: 0, reg: gp01, aux: "Int64", asm: "MOVV", typ: "UInt64", rematerializeable: true}, // auxint 219 {name: "MOVFconst", argLength: 0, reg: fp01, aux: "Float64", asm: "MOVF", typ: "Float32", rematerializeable: true}, // auxint as 64-bit float, convert to 32-bit float 220 {name: "MOVDconst", argLength: 0, reg: fp01, aux: "Float64", asm: "MOVD", typ: "Float64", rematerializeable: true}, // auxint as 64-bit float 221 222 {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 223 224 {name: "MOVBload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVB", typ: "Int8", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 225 {name: "MOVBUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVBU", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 226 {name: "MOVHload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVH", typ: "Int16", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 227 {name: "MOVHUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVHU", typ: "UInt16", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 228 {name: "MOVWload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVW", typ: "Int32", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 229 {name: "MOVWUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVWU", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 230 {name: "MOVVload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVV", typ: "UInt64", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 231 {name: "MOVFload", argLength: 2, reg: fpload, aux: "SymOff", asm: "MOVF", typ: "Float32", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 232 {name: "MOVDload", argLength: 2, reg: fpload, aux: "SymOff", asm: "MOVD", typ: "Float64", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 233 234 {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. 235 {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. 236 {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. 237 {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. 238 {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. 239 {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. 240 241 {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. 242 {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. 243 {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. 244 {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. 245 246 // conversions 247 {name: "MOVBreg", argLength: 1, reg: gp11, asm: "MOVB"}, // move from arg0, sign-extended from byte 248 {name: "MOVBUreg", argLength: 1, reg: gp11, asm: "MOVBU"}, // move from arg0, unsign-extended from byte 249 {name: "MOVHreg", argLength: 1, reg: gp11, asm: "MOVH"}, // move from arg0, sign-extended from half 250 {name: "MOVHUreg", argLength: 1, reg: gp11, asm: "MOVHU"}, // move from arg0, unsign-extended from half 251 {name: "MOVWreg", argLength: 1, reg: gp11, asm: "MOVW"}, // move from arg0, sign-extended from word 252 {name: "MOVWUreg", argLength: 1, reg: gp11, asm: "MOVWU"}, // move from arg0, unsign-extended from word 253 {name: "MOVVreg", argLength: 1, reg: gp11, asm: "MOVV"}, // move from arg0 254 255 {name: "MOVVnop", argLength: 1, reg: regInfo{inputs: []regMask{gp}, outputs: []regMask{gp}}, resultInArg0: true}, // nop, return arg0 in same register 256 257 {name: "MOVWF", argLength: 1, reg: fp11, asm: "MOVWF"}, // int32 -> float32 258 {name: "MOVWD", argLength: 1, reg: fp11, asm: "MOVWD"}, // int32 -> float64 259 {name: "MOVVF", argLength: 1, reg: fp11, asm: "MOVVF"}, // int64 -> float32 260 {name: "MOVVD", argLength: 1, reg: fp11, asm: "MOVVD"}, // int64 -> float64 261 {name: "TRUNCFW", argLength: 1, reg: fp11, asm: "TRUNCFW"}, // float32 -> int32 262 {name: "TRUNCDW", argLength: 1, reg: fp11, asm: "TRUNCDW"}, // float64 -> int32 263 {name: "TRUNCFV", argLength: 1, reg: fp11, asm: "TRUNCFV"}, // float32 -> int64 264 {name: "TRUNCDV", argLength: 1, reg: fp11, asm: "TRUNCDV"}, // float64 -> int64 265 {name: "MOVFD", argLength: 1, reg: fp11, asm: "MOVFD"}, // float32 -> float64 266 {name: "MOVDF", argLength: 1, reg: fp11, asm: "MOVDF"}, // float64 -> float32 267 268 // function calls 269 {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 270 {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 271 {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 272 273 // duffzero 274 // arg0 = address of memory to zero 275 // arg1 = mem 276 // auxint = offset into duffzero code to start executing 277 // returns mem 278 // R1 aka mips.REGRT1 changed as side effect 279 { 280 name: "DUFFZERO", 281 aux: "Int64", 282 argLength: 2, 283 reg: regInfo{ 284 inputs: []regMask{gp}, 285 clobbers: buildReg("R1 R31"), 286 }, 287 faultOnNilArg0: true, 288 }, 289 290 // large or unaligned zeroing 291 // arg0 = address of memory to zero (in R1, changed as side effect) 292 // arg1 = address of the last element to zero 293 // arg2 = mem 294 // auxint = alignment 295 // returns mem 296 // SUBV $8, R1 297 // MOVV R0, 8(R1) 298 // ADDV $8, R1 299 // BNE Rarg1, R1, -2(PC) 300 { 301 name: "LoweredZero", 302 aux: "Int64", 303 argLength: 3, 304 reg: regInfo{ 305 inputs: []regMask{buildReg("R1"), gp}, 306 clobbers: buildReg("R1"), 307 }, 308 clobberFlags: true, 309 faultOnNilArg0: true, 310 }, 311 312 // large or unaligned move 313 // arg0 = address of dst memory (in R2, changed as side effect) 314 // arg1 = address of src memory (in R1, changed as side effect) 315 // arg2 = address of the last element of src 316 // arg3 = mem 317 // auxint = alignment 318 // returns mem 319 // SUBV $8, R1 320 // MOVV 8(R1), Rtmp 321 // MOVV Rtmp, (R2) 322 // ADDV $8, R1 323 // ADDV $8, R2 324 // BNE Rarg2, R1, -4(PC) 325 { 326 name: "LoweredMove", 327 aux: "Int64", 328 argLength: 4, 329 reg: regInfo{ 330 inputs: []regMask{buildReg("R2"), buildReg("R1"), gp}, 331 clobbers: buildReg("R1 R2"), 332 }, 333 clobberFlags: true, 334 faultOnNilArg0: true, 335 faultOnNilArg1: true, 336 }, 337 338 // atomic loads. 339 // load from arg0. arg1=mem. 340 // returns <value,memory> so they can be properly ordered with other loads. 341 {name: "LoweredAtomicLoad32", argLength: 2, reg: gpload, faultOnNilArg0: true}, 342 {name: "LoweredAtomicLoad64", argLength: 2, reg: gpload, faultOnNilArg0: true}, 343 344 // atomic stores. 345 // store arg1 to arg0. arg2=mem. returns memory. 346 {name: "LoweredAtomicStore32", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true}, 347 {name: "LoweredAtomicStore64", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true}, 348 // store zero to arg0. arg1=mem. returns memory. 349 {name: "LoweredAtomicStorezero32", argLength: 2, reg: gpstore0, faultOnNilArg0: true, hasSideEffects: true}, 350 {name: "LoweredAtomicStorezero64", argLength: 2, reg: gpstore0, faultOnNilArg0: true, hasSideEffects: true}, 351 352 // atomic exchange. 353 // store arg1 to arg0. arg2=mem. returns <old content of *arg0, memory>. 354 // SYNC 355 // LL (Rarg0), Rout 356 // MOVV Rarg1, Rtmp 357 // SC Rtmp, (Rarg0) 358 // BEQ Rtmp, -3(PC) 359 // SYNC 360 {name: "LoweredAtomicExchange32", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true}, 361 {name: "LoweredAtomicExchange64", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true}, 362 363 // atomic add. 364 // *arg0 += arg1. arg2=mem. returns <new content of *arg0, memory>. 365 // SYNC 366 // LL (Rarg0), Rout 367 // ADDV Rarg1, Rout, Rtmp 368 // SC Rtmp, (Rarg0) 369 // BEQ Rtmp, -3(PC) 370 // SYNC 371 // ADDV Rarg1, Rout 372 {name: "LoweredAtomicAdd32", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true}, 373 {name: "LoweredAtomicAdd64", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true}, 374 // *arg0 += auxint. arg1=mem. returns <new content of *arg0, memory>. auxint is 32-bit. 375 {name: "LoweredAtomicAddconst32", argLength: 2, reg: regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}}, aux: "Int32", resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true}, 376 {name: "LoweredAtomicAddconst64", argLength: 2, reg: regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}}, aux: "Int64", resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true}, 377 378 // atomic compare and swap. 379 // arg0 = pointer, arg1 = old value, arg2 = new value, arg3 = memory. 380 // if *arg0 == arg1 { 381 // *arg0 = arg2 382 // return (true, memory) 383 // } else { 384 // return (false, memory) 385 // } 386 // SYNC 387 // MOVV $0, Rout 388 // LL (Rarg0), Rtmp 389 // BNE Rtmp, Rarg1, 4(PC) 390 // MOVV Rarg2, Rout 391 // SC Rout, (Rarg0) 392 // BEQ Rout, -4(PC) 393 // SYNC 394 {name: "LoweredAtomicCas32", argLength: 4, reg: gpcas, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true}, 395 {name: "LoweredAtomicCas64", argLength: 4, reg: gpcas, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true}, 396 397 // pseudo-ops 398 {name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{gpg}}, nilCheck: true, faultOnNilArg0: true}, // panic if arg0 is nil. arg1=mem. 399 400 {name: "FPFlagTrue", argLength: 1, reg: readflags}, // bool, true if FP flag is true 401 {name: "FPFlagFalse", argLength: 1, reg: readflags}, // bool, true if FP flag is false 402 403 // Scheduler ensures LoweredGetClosurePtr occurs only in entry block, 404 // and sorts it to the very beginning of the block to prevent other 405 // use of R22 (mips.REGCTXT, the closure pointer) 406 {name: "LoweredGetClosurePtr", reg: regInfo{outputs: []regMask{buildReg("R22")}}}, 407 408 // LoweredGetCallerSP returns the SP of the caller of the current function. 409 {name: "LoweredGetCallerSP", reg: gp01, rematerializeable: true}, 410 411 // MOVDconvert converts between pointers and integers. 412 // We have a special op for this so as to not confuse GC 413 // (particularly stack maps). It takes a memory arg so it 414 // gets correctly ordered with respect to GC safepoints. 415 // arg0=ptr/int arg1=mem, output=int/ptr 416 {name: "MOVVconvert", argLength: 2, reg: gp11, asm: "MOVV"}, 417 } 418 419 blocks := []blockData{ 420 {name: "EQ"}, 421 {name: "NE"}, 422 {name: "LTZ"}, // < 0 423 {name: "LEZ"}, // <= 0 424 {name: "GTZ"}, // > 0 425 {name: "GEZ"}, // >= 0 426 {name: "FPT"}, // FP flag is true 427 {name: "FPF"}, // FP flag is false 428 } 429 430 archs = append(archs, arch{ 431 name: "MIPS64", 432 pkg: "cmd/internal/obj/mips", 433 genfile: "../../mips64/ssa.go", 434 ops: ops, 435 blocks: blocks, 436 regnames: regNamesMIPS64, 437 gpregmask: gp, 438 fpregmask: fp, 439 specialregmask: hi | lo, 440 framepointerreg: -1, // not used 441 linkreg: int8(num["R31"]), 442 }) 443 }