github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/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 // If you add registers, update asyncPreempt in runtime. 104 105 // pseudo-registers 106 "SB", 107 } 108 109 func init() { 110 // Make map from reg names to reg integers. 111 if len(regNamesMIPS64) > 64 { 112 panic("too many registers") 113 } 114 num := map[string]int{} 115 for i, name := range regNamesMIPS64 { 116 num[name] = i 117 } 118 buildReg := func(s string) regMask { 119 m := regMask(0) 120 for _, r := range strings.Split(s, " ") { 121 if n, ok := num[r]; ok { 122 m |= regMask(1) << uint(n) 123 continue 124 } 125 panic("register " + r + " not found") 126 } 127 return m 128 } 129 130 // Common individual register masks 131 var ( 132 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") 133 gpg = gp | buildReg("g") 134 gpsp = gp | buildReg("SP") 135 gpspg = gpg | buildReg("SP") 136 gpspsbg = gpspg | buildReg("SB") 137 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") 138 lo = buildReg("LO") 139 hi = buildReg("HI") 140 callerSave = gp | fp | lo | hi | buildReg("g") // runtime.setg (and anything calling it) may clobber g 141 r1 = buildReg("R1") 142 r2 = buildReg("R2") 143 r3 = buildReg("R3") 144 r4 = buildReg("R4") 145 ) 146 // Common regInfo 147 var ( 148 gp01 = regInfo{inputs: nil, outputs: []regMask{gp}} 149 gp11 = regInfo{inputs: []regMask{gpg}, outputs: []regMask{gp}} 150 gp11sp = regInfo{inputs: []regMask{gpspg}, outputs: []regMask{gp}} 151 gp21 = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{gp}} 152 gp2hilo = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{hi, lo}} 153 gpload = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}} 154 gpstore = regInfo{inputs: []regMask{gpspsbg, gpg}} 155 gpstore0 = regInfo{inputs: []regMask{gpspsbg}} 156 gpxchg = regInfo{inputs: []regMask{gpspsbg, gpg}, outputs: []regMask{gp}} 157 gpcas = regInfo{inputs: []regMask{gpspsbg, gpg, gpg}, outputs: []regMask{gp}} 158 fp01 = regInfo{inputs: nil, outputs: []regMask{fp}} 159 fp11 = regInfo{inputs: []regMask{fp}, outputs: []regMask{fp}} 160 //fp1flags = regInfo{inputs: []regMask{fp}} 161 //fpgp = regInfo{inputs: []regMask{fp}, outputs: []regMask{gp}} 162 //gpfp = regInfo{inputs: []regMask{gp}, outputs: []regMask{fp}} 163 fp21 = regInfo{inputs: []regMask{fp, fp}, outputs: []regMask{fp}} 164 fp2flags = regInfo{inputs: []regMask{fp, fp}} 165 fpload = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{fp}} 166 fpstore = regInfo{inputs: []regMask{gpspsbg, fp}} 167 readflags = regInfo{inputs: nil, outputs: []regMask{gp}} 168 ) 169 ops := []opData{ 170 // binary ops 171 {name: "ADDV", argLength: 2, reg: gp21, asm: "ADDVU", commutative: true}, // arg0 + arg1 172 {name: "ADDVconst", argLength: 1, reg: gp11sp, asm: "ADDVU", aux: "Int64"}, // arg0 + auxInt. auxInt is 32-bit, also in other *const ops. 173 {name: "SUBV", argLength: 2, reg: gp21, asm: "SUBVU"}, // arg0 - arg1 174 {name: "SUBVconst", argLength: 1, reg: gp11, asm: "SUBVU", aux: "Int64"}, // arg0 - auxInt 175 {name: "MULV", argLength: 2, reg: gp2hilo, asm: "MULV", commutative: true, typ: "(Int64,Int64)"}, // arg0 * arg1, signed, results hi,lo 176 {name: "MULVU", argLength: 2, reg: gp2hilo, asm: "MULVU", commutative: true, typ: "(UInt64,UInt64)"}, // arg0 * arg1, unsigned, results hi,lo 177 {name: "DIVV", argLength: 2, reg: gp2hilo, asm: "DIVV", typ: "(Int64,Int64)"}, // arg0 / arg1, signed, results hi=arg0%arg1,lo=arg0/arg1 178 {name: "DIVVU", argLength: 2, reg: gp2hilo, asm: "DIVVU", typ: "(UInt64,UInt64)"}, // arg0 / arg1, signed, results hi=arg0%arg1,lo=arg0/arg1 179 180 {name: "ADDF", argLength: 2, reg: fp21, asm: "ADDF", commutative: true}, // arg0 + arg1 181 {name: "ADDD", argLength: 2, reg: fp21, asm: "ADDD", commutative: true}, // arg0 + arg1 182 {name: "SUBF", argLength: 2, reg: fp21, asm: "SUBF"}, // arg0 - arg1 183 {name: "SUBD", argLength: 2, reg: fp21, asm: "SUBD"}, // arg0 - arg1 184 {name: "MULF", argLength: 2, reg: fp21, asm: "MULF", commutative: true}, // arg0 * arg1 185 {name: "MULD", argLength: 2, reg: fp21, asm: "MULD", commutative: true}, // arg0 * arg1 186 {name: "DIVF", argLength: 2, reg: fp21, asm: "DIVF"}, // arg0 / arg1 187 {name: "DIVD", argLength: 2, reg: fp21, asm: "DIVD"}, // arg0 / arg1 188 189 {name: "AND", argLength: 2, reg: gp21, asm: "AND", commutative: true}, // arg0 & arg1 190 {name: "ANDconst", argLength: 1, reg: gp11, asm: "AND", aux: "Int64"}, // arg0 & auxInt 191 {name: "OR", argLength: 2, reg: gp21, asm: "OR", commutative: true}, // arg0 | arg1 192 {name: "ORconst", argLength: 1, reg: gp11, asm: "OR", aux: "Int64"}, // arg0 | auxInt 193 {name: "XOR", argLength: 2, reg: gp21, asm: "XOR", commutative: true, typ: "UInt64"}, // arg0 ^ arg1 194 {name: "XORconst", argLength: 1, reg: gp11, asm: "XOR", aux: "Int64", typ: "UInt64"}, // arg0 ^ auxInt 195 {name: "NOR", argLength: 2, reg: gp21, asm: "NOR", commutative: true}, // ^(arg0 | arg1) 196 {name: "NORconst", argLength: 1, reg: gp11, asm: "NOR", aux: "Int64"}, // ^(arg0 | auxInt) 197 198 {name: "NEGV", argLength: 1, reg: gp11}, // -arg0 199 {name: "NEGF", argLength: 1, reg: fp11, asm: "NEGF"}, // -arg0, float32 200 {name: "NEGD", argLength: 1, reg: fp11, asm: "NEGD"}, // -arg0, float64 201 {name: "SQRTD", argLength: 1, reg: fp11, asm: "SQRTD"}, // sqrt(arg0), float64 202 203 // shifts 204 {name: "SLLV", argLength: 2, reg: gp21, asm: "SLLV"}, // arg0 << arg1, shift amount is mod 64 205 {name: "SLLVconst", argLength: 1, reg: gp11, asm: "SLLV", aux: "Int64"}, // arg0 << auxInt 206 {name: "SRLV", argLength: 2, reg: gp21, asm: "SRLV"}, // arg0 >> arg1, unsigned, shift amount is mod 64 207 {name: "SRLVconst", argLength: 1, reg: gp11, asm: "SRLV", aux: "Int64"}, // arg0 >> auxInt, unsigned 208 {name: "SRAV", argLength: 2, reg: gp21, asm: "SRAV"}, // arg0 >> arg1, signed, shift amount is mod 64 209 {name: "SRAVconst", argLength: 1, reg: gp11, asm: "SRAV", aux: "Int64"}, // arg0 >> auxInt, signed 210 211 // comparisons 212 {name: "SGT", argLength: 2, reg: gp21, asm: "SGT", typ: "Bool"}, // 1 if arg0 > arg1 (signed), 0 otherwise 213 {name: "SGTconst", argLength: 1, reg: gp11, asm: "SGT", aux: "Int64", typ: "Bool"}, // 1 if auxInt > arg0 (signed), 0 otherwise 214 {name: "SGTU", argLength: 2, reg: gp21, asm: "SGTU", typ: "Bool"}, // 1 if arg0 > arg1 (unsigned), 0 otherwise 215 {name: "SGTUconst", argLength: 1, reg: gp11, asm: "SGTU", aux: "Int64", typ: "Bool"}, // 1 if auxInt > arg0 (unsigned), 0 otherwise 216 217 {name: "CMPEQF", argLength: 2, reg: fp2flags, asm: "CMPEQF", typ: "Flags"}, // flags=true if arg0 = arg1, float32 218 {name: "CMPEQD", argLength: 2, reg: fp2flags, asm: "CMPEQD", typ: "Flags"}, // flags=true if arg0 = arg1, float64 219 {name: "CMPGEF", argLength: 2, reg: fp2flags, asm: "CMPGEF", typ: "Flags"}, // flags=true if arg0 >= arg1, float32 220 {name: "CMPGED", argLength: 2, reg: fp2flags, asm: "CMPGED", typ: "Flags"}, // flags=true if arg0 >= arg1, float64 221 {name: "CMPGTF", argLength: 2, reg: fp2flags, asm: "CMPGTF", typ: "Flags"}, // flags=true if arg0 > arg1, float32 222 {name: "CMPGTD", argLength: 2, reg: fp2flags, asm: "CMPGTD", typ: "Flags"}, // flags=true if arg0 > arg1, float64 223 224 // moves 225 {name: "MOVVconst", argLength: 0, reg: gp01, aux: "Int64", asm: "MOVV", typ: "UInt64", rematerializeable: true}, // auxint 226 {name: "MOVFconst", argLength: 0, reg: fp01, aux: "Float64", asm: "MOVF", typ: "Float32", rematerializeable: true}, // auxint as 64-bit float, convert to 32-bit float 227 {name: "MOVDconst", argLength: 0, reg: fp01, aux: "Float64", asm: "MOVD", typ: "Float64", rematerializeable: true}, // auxint as 64-bit float 228 229 {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 230 231 {name: "MOVBload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVB", typ: "Int8", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 232 {name: "MOVBUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVBU", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 233 {name: "MOVHload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVH", typ: "Int16", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 234 {name: "MOVHUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVHU", typ: "UInt16", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 235 {name: "MOVWload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVW", typ: "Int32", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 236 {name: "MOVWUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVWU", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 237 {name: "MOVVload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVV", typ: "UInt64", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 238 {name: "MOVFload", argLength: 2, reg: fpload, aux: "SymOff", asm: "MOVF", typ: "Float32", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 239 {name: "MOVDload", argLength: 2, reg: fpload, aux: "SymOff", asm: "MOVD", typ: "Float64", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 240 241 {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. 242 {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. 243 {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. 244 {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. 245 {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. 246 {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. 247 248 {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. 249 {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. 250 {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. 251 {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. 252 253 // conversions 254 {name: "MOVBreg", argLength: 1, reg: gp11, asm: "MOVB"}, // move from arg0, sign-extended from byte 255 {name: "MOVBUreg", argLength: 1, reg: gp11, asm: "MOVBU"}, // move from arg0, unsign-extended from byte 256 {name: "MOVHreg", argLength: 1, reg: gp11, asm: "MOVH"}, // move from arg0, sign-extended from half 257 {name: "MOVHUreg", argLength: 1, reg: gp11, asm: "MOVHU"}, // move from arg0, unsign-extended from half 258 {name: "MOVWreg", argLength: 1, reg: gp11, asm: "MOVW"}, // move from arg0, sign-extended from word 259 {name: "MOVWUreg", argLength: 1, reg: gp11, asm: "MOVWU"}, // move from arg0, unsign-extended from word 260 {name: "MOVVreg", argLength: 1, reg: gp11, asm: "MOVV"}, // move from arg0 261 262 {name: "MOVVnop", argLength: 1, reg: regInfo{inputs: []regMask{gp}, outputs: []regMask{gp}}, resultInArg0: true}, // nop, return arg0 in same register 263 264 {name: "MOVWF", argLength: 1, reg: fp11, asm: "MOVWF"}, // int32 -> float32 265 {name: "MOVWD", argLength: 1, reg: fp11, asm: "MOVWD"}, // int32 -> float64 266 {name: "MOVVF", argLength: 1, reg: fp11, asm: "MOVVF"}, // int64 -> float32 267 {name: "MOVVD", argLength: 1, reg: fp11, asm: "MOVVD"}, // int64 -> float64 268 {name: "TRUNCFW", argLength: 1, reg: fp11, asm: "TRUNCFW"}, // float32 -> int32 269 {name: "TRUNCDW", argLength: 1, reg: fp11, asm: "TRUNCDW"}, // float64 -> int32 270 {name: "TRUNCFV", argLength: 1, reg: fp11, asm: "TRUNCFV"}, // float32 -> int64 271 {name: "TRUNCDV", argLength: 1, reg: fp11, asm: "TRUNCDV"}, // float64 -> int64 272 {name: "MOVFD", argLength: 1, reg: fp11, asm: "MOVFD"}, // float32 -> float64 273 {name: "MOVDF", argLength: 1, reg: fp11, asm: "MOVDF"}, // float64 -> float32 274 275 // function calls 276 {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 277 {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 278 {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 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"}, // 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"}, // 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"}, // 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: "github.com/gagliardetto/golang-go/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 }