github.com/FenixAra/go@v0.0.0-20170127160404-96ea0918e670/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 fp01 = regInfo{inputs: nil, outputs: []regMask{fp}} 151 fp11 = regInfo{inputs: []regMask{fp}, outputs: []regMask{fp}} 152 //fp1flags = regInfo{inputs: []regMask{fp}} 153 //fpgp = regInfo{inputs: []regMask{fp}, outputs: []regMask{gp}} 154 //gpfp = regInfo{inputs: []regMask{gp}, outputs: []regMask{fp}} 155 fp21 = regInfo{inputs: []regMask{fp, fp}, outputs: []regMask{fp}} 156 fp2flags = regInfo{inputs: []regMask{fp, fp}} 157 fpload = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{fp}} 158 fpstore = regInfo{inputs: []regMask{gpspsbg, fp}} 159 readflags = regInfo{inputs: nil, outputs: []regMask{gp}} 160 ) 161 ops := []opData{ 162 // binary ops 163 {name: "ADDV", argLength: 2, reg: gp21, asm: "ADDVU", commutative: true}, // arg0 + arg1 164 {name: "ADDVconst", argLength: 1, reg: gp11sp, asm: "ADDVU", aux: "Int64"}, // arg0 + auxInt 165 {name: "SUBV", argLength: 2, reg: gp21, asm: "SUBVU"}, // arg0 - arg1 166 {name: "SUBVconst", argLength: 1, reg: gp11, asm: "SUBVU", aux: "Int64"}, // arg0 - auxInt 167 {name: "MULV", argLength: 2, reg: gp2hilo, asm: "MULV", commutative: true, typ: "(Int64,Int64)"}, // arg0 * arg1, signed, results hi,lo 168 {name: "MULVU", argLength: 2, reg: gp2hilo, asm: "MULVU", commutative: true, typ: "(UInt64,UInt64)"}, // arg0 * arg1, unsigned, results hi,lo 169 {name: "DIVV", argLength: 2, reg: gp2hilo, asm: "DIVV", typ: "(Int64,Int64)"}, // arg0 / arg1, signed, results hi=arg0%arg1,lo=arg0/arg1 170 {name: "DIVVU", argLength: 2, reg: gp2hilo, asm: "DIVVU", typ: "(UInt64,UInt64)"}, // arg0 / arg1, signed, results hi=arg0%arg1,lo=arg0/arg1 171 172 {name: "ADDF", argLength: 2, reg: fp21, asm: "ADDF", commutative: true}, // arg0 + arg1 173 {name: "ADDD", argLength: 2, reg: fp21, asm: "ADDD", commutative: true}, // arg0 + arg1 174 {name: "SUBF", argLength: 2, reg: fp21, asm: "SUBF"}, // arg0 - arg1 175 {name: "SUBD", argLength: 2, reg: fp21, asm: "SUBD"}, // arg0 - arg1 176 {name: "MULF", argLength: 2, reg: fp21, asm: "MULF", commutative: true}, // arg0 * arg1 177 {name: "MULD", argLength: 2, reg: fp21, asm: "MULD", commutative: true}, // arg0 * arg1 178 {name: "DIVF", argLength: 2, reg: fp21, asm: "DIVF"}, // arg0 / arg1 179 {name: "DIVD", argLength: 2, reg: fp21, asm: "DIVD"}, // arg0 / arg1 180 181 {name: "AND", argLength: 2, reg: gp21, asm: "AND", commutative: true}, // arg0 & arg1 182 {name: "ANDconst", argLength: 1, reg: gp11, asm: "AND", aux: "Int64"}, // arg0 & auxInt 183 {name: "OR", argLength: 2, reg: gp21, asm: "OR", commutative: true}, // arg0 | arg1 184 {name: "ORconst", argLength: 1, reg: gp11, asm: "OR", aux: "Int64"}, // arg0 | auxInt 185 {name: "XOR", argLength: 2, reg: gp21, asm: "XOR", commutative: true, typ: "UInt64"}, // arg0 ^ arg1 186 {name: "XORconst", argLength: 1, reg: gp11, asm: "XOR", aux: "Int64", typ: "UInt64"}, // arg0 ^ auxInt 187 {name: "NOR", argLength: 2, reg: gp21, asm: "NOR", commutative: true}, // ^(arg0 | arg1) 188 {name: "NORconst", argLength: 1, reg: gp11, asm: "NOR", aux: "Int64"}, // ^(arg0 | auxInt) 189 190 {name: "NEGV", argLength: 1, reg: gp11}, // -arg0 191 {name: "NEGF", argLength: 1, reg: fp11, asm: "NEGF"}, // -arg0, float32 192 {name: "NEGD", argLength: 1, reg: fp11, asm: "NEGD"}, // -arg0, float64 193 194 // shifts 195 {name: "SLLV", argLength: 2, reg: gp21, asm: "SLLV"}, // arg0 << arg1, shift amount is mod 64 196 {name: "SLLVconst", argLength: 1, reg: gp11, asm: "SLLV", aux: "Int64"}, // arg0 << auxInt 197 {name: "SRLV", argLength: 2, reg: gp21, asm: "SRLV"}, // arg0 >> arg1, unsigned, shift amount is mod 64 198 {name: "SRLVconst", argLength: 1, reg: gp11, asm: "SRLV", aux: "Int64"}, // arg0 >> auxInt, unsigned 199 {name: "SRAV", argLength: 2, reg: gp21, asm: "SRAV"}, // arg0 >> arg1, signed, shift amount is mod 64 200 {name: "SRAVconst", argLength: 1, reg: gp11, asm: "SRAV", aux: "Int64"}, // arg0 >> auxInt, signed 201 202 // comparisons 203 {name: "SGT", argLength: 2, reg: gp21, asm: "SGT", typ: "Bool"}, // 1 if arg0 > arg1 (signed), 0 otherwise 204 {name: "SGTconst", argLength: 1, reg: gp11, asm: "SGT", aux: "Int64", typ: "Bool"}, // 1 if auxInt > arg0 (signed), 0 otherwise 205 {name: "SGTU", argLength: 2, reg: gp21, asm: "SGTU", typ: "Bool"}, // 1 if arg0 > arg1 (unsigned), 0 otherwise 206 {name: "SGTUconst", argLength: 1, reg: gp11, asm: "SGTU", aux: "Int64", typ: "Bool"}, // 1 if auxInt > arg0 (unsigned), 0 otherwise 207 208 {name: "CMPEQF", argLength: 2, reg: fp2flags, asm: "CMPEQF", typ: "Flags"}, // flags=true if arg0 = arg1, float32 209 {name: "CMPEQD", argLength: 2, reg: fp2flags, asm: "CMPEQD", typ: "Flags"}, // flags=true if arg0 = arg1, float64 210 {name: "CMPGEF", argLength: 2, reg: fp2flags, asm: "CMPGEF", typ: "Flags"}, // flags=true if arg0 >= arg1, float32 211 {name: "CMPGED", argLength: 2, reg: fp2flags, asm: "CMPGED", typ: "Flags"}, // flags=true if arg0 >= arg1, float64 212 {name: "CMPGTF", argLength: 2, reg: fp2flags, asm: "CMPGTF", typ: "Flags"}, // flags=true if arg0 > arg1, float32 213 {name: "CMPGTD", argLength: 2, reg: fp2flags, asm: "CMPGTD", typ: "Flags"}, // flags=true if arg0 > arg1, float64 214 215 // moves 216 {name: "MOVVconst", argLength: 0, reg: gp01, aux: "Int64", asm: "MOVV", typ: "UInt64", rematerializeable: true}, // auxint 217 {name: "MOVFconst", argLength: 0, reg: fp01, aux: "Float64", asm: "MOVF", typ: "Float32", rematerializeable: true}, // auxint as 64-bit float, convert to 32-bit float 218 {name: "MOVDconst", argLength: 0, reg: fp01, aux: "Float64", asm: "MOVD", typ: "Float64", rematerializeable: true}, // auxint as 64-bit float 219 220 {name: "MOVVaddr", argLength: 1, reg: regInfo{inputs: []regMask{buildReg("SP") | buildReg("SB")}, outputs: []regMask{gp}}, aux: "SymOff", asm: "MOVV", rematerializeable: true}, // arg0 + auxInt + aux.(*gc.Sym), arg0=SP/SB 221 222 {name: "MOVBload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVB", typ: "Int8", faultOnNilArg0: true}, // load from arg0 + auxInt + aux. arg1=mem. 223 {name: "MOVBUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVBU", typ: "UInt8", faultOnNilArg0: true}, // load from arg0 + auxInt + aux. arg1=mem. 224 {name: "MOVHload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVH", typ: "Int16", faultOnNilArg0: true}, // load from arg0 + auxInt + aux. arg1=mem. 225 {name: "MOVHUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVHU", typ: "UInt16", faultOnNilArg0: true}, // load from arg0 + auxInt + aux. arg1=mem. 226 {name: "MOVWload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVW", typ: "Int32", faultOnNilArg0: true}, // load from arg0 + auxInt + aux. arg1=mem. 227 {name: "MOVWUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVWU", typ: "UInt32", faultOnNilArg0: true}, // load from arg0 + auxInt + aux. arg1=mem. 228 {name: "MOVVload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVV", typ: "UInt64", faultOnNilArg0: true}, // load from arg0 + auxInt + aux. arg1=mem. 229 {name: "MOVFload", argLength: 2, reg: fpload, aux: "SymOff", asm: "MOVF", typ: "Float32", faultOnNilArg0: true}, // load from arg0 + auxInt + aux. arg1=mem. 230 {name: "MOVDload", argLength: 2, reg: fpload, aux: "SymOff", asm: "MOVD", typ: "Float64", faultOnNilArg0: true}, // load from arg0 + auxInt + aux. arg1=mem. 231 232 {name: "MOVBstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVB", typ: "Mem", faultOnNilArg0: true}, // store 1 byte of arg1 to arg0 + auxInt + aux. arg2=mem. 233 {name: "MOVHstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVH", typ: "Mem", faultOnNilArg0: true}, // store 2 bytes of arg1 to arg0 + auxInt + aux. arg2=mem. 234 {name: "MOVWstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVW", typ: "Mem", faultOnNilArg0: true}, // store 4 bytes of arg1 to arg0 + auxInt + aux. arg2=mem. 235 {name: "MOVVstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVV", typ: "Mem", faultOnNilArg0: true}, // store 8 bytes of arg1 to arg0 + auxInt + aux. arg2=mem. 236 {name: "MOVFstore", argLength: 3, reg: fpstore, aux: "SymOff", asm: "MOVF", typ: "Mem", faultOnNilArg0: true}, // store 4 bytes of arg1 to arg0 + auxInt + aux. arg2=mem. 237 {name: "MOVDstore", argLength: 3, reg: fpstore, aux: "SymOff", asm: "MOVD", typ: "Mem", faultOnNilArg0: true}, // store 8 bytes of arg1 to arg0 + auxInt + aux. arg2=mem. 238 239 {name: "MOVBstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVB", typ: "Mem", faultOnNilArg0: true}, // store 1 byte of zero to arg0 + auxInt + aux. arg1=mem. 240 {name: "MOVHstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVH", typ: "Mem", faultOnNilArg0: true}, // store 2 bytes of zero to arg0 + auxInt + aux. arg1=mem. 241 {name: "MOVWstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVW", typ: "Mem", faultOnNilArg0: true}, // store 4 bytes of zero to arg0 + auxInt + aux. arg1=mem. 242 {name: "MOVVstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVV", typ: "Mem", faultOnNilArg0: true}, // store 8 bytes of zero to arg0 + auxInt + aux. ar12=mem. 243 244 // conversions 245 {name: "MOVBreg", argLength: 1, reg: gp11, asm: "MOVB"}, // move from arg0, sign-extended from byte 246 {name: "MOVBUreg", argLength: 1, reg: gp11, asm: "MOVBU"}, // move from arg0, unsign-extended from byte 247 {name: "MOVHreg", argLength: 1, reg: gp11, asm: "MOVH"}, // move from arg0, sign-extended from half 248 {name: "MOVHUreg", argLength: 1, reg: gp11, asm: "MOVHU"}, // move from arg0, unsign-extended from half 249 {name: "MOVWreg", argLength: 1, reg: gp11, asm: "MOVW"}, // move from arg0, sign-extended from word 250 {name: "MOVWUreg", argLength: 1, reg: gp11, asm: "MOVWU"}, // move from arg0, unsign-extended from word 251 {name: "MOVVreg", argLength: 1, reg: gp11, asm: "MOVV"}, // move from arg0 252 253 {name: "MOVVnop", argLength: 1, reg: regInfo{inputs: []regMask{gp}, outputs: []regMask{gp}}, resultInArg0: true}, // nop, return arg0 in same register 254 255 {name: "MOVWF", argLength: 1, reg: fp11, asm: "MOVWF"}, // int32 -> float32 256 {name: "MOVWD", argLength: 1, reg: fp11, asm: "MOVWD"}, // int32 -> float64 257 {name: "MOVVF", argLength: 1, reg: fp11, asm: "MOVVF"}, // int64 -> float32 258 {name: "MOVVD", argLength: 1, reg: fp11, asm: "MOVVD"}, // int64 -> float64 259 {name: "TRUNCFW", argLength: 1, reg: fp11, asm: "TRUNCFW"}, // float32 -> int32 260 {name: "TRUNCDW", argLength: 1, reg: fp11, asm: "TRUNCDW"}, // float64 -> int32 261 {name: "TRUNCFV", argLength: 1, reg: fp11, asm: "TRUNCFV"}, // float32 -> int64 262 {name: "TRUNCDV", argLength: 1, reg: fp11, asm: "TRUNCDV"}, // float64 -> int64 263 {name: "MOVFD", argLength: 1, reg: fp11, asm: "MOVFD"}, // float32 -> float64 264 {name: "MOVDF", argLength: 1, reg: fp11, asm: "MOVDF"}, // float64 -> float32 265 266 // function calls 267 {name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "SymOff", clobberFlags: true, call: true}, // call static function aux.(*gc.Sym). arg0=mem, auxint=argsize, returns mem 268 {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 269 {name: "CALLdefer", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true}, // call deferproc. arg0=mem, auxint=argsize, returns mem 270 {name: "CALLgo", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64", clobberFlags: true, call: true}, // call newproc. arg0=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 // pseudo-ops 339 {name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{gpg}}, nilCheck: true, faultOnNilArg0: true}, // panic if arg0 is nil. arg1=mem. 340 341 {name: "FPFlagTrue", argLength: 1, reg: readflags}, // bool, true if FP flag is true 342 {name: "FPFlagFalse", argLength: 1, reg: readflags}, // bool, true if FP flag is false 343 344 // Scheduler ensures LoweredGetClosurePtr occurs only in entry block, 345 // and sorts it to the very beginning of the block to prevent other 346 // use of R22 (mips.REGCTXT, the closure pointer) 347 {name: "LoweredGetClosurePtr", reg: regInfo{outputs: []regMask{buildReg("R22")}}}, 348 349 // MOVDconvert converts between pointers and integers. 350 // We have a special op for this so as to not confuse GC 351 // (particularly stack maps). It takes a memory arg so it 352 // gets correctly ordered with respect to GC safepoints. 353 // arg0=ptr/int arg1=mem, output=int/ptr 354 {name: "MOVVconvert", argLength: 2, reg: gp11, asm: "MOVV"}, 355 } 356 357 blocks := []blockData{ 358 {name: "EQ"}, 359 {name: "NE"}, 360 {name: "LTZ"}, // < 0 361 {name: "LEZ"}, // <= 0 362 {name: "GTZ"}, // > 0 363 {name: "GEZ"}, // >= 0 364 {name: "FPT"}, // FP flag is true 365 {name: "FPF"}, // FP flag is false 366 } 367 368 archs = append(archs, arch{ 369 name: "MIPS64", 370 pkg: "cmd/internal/obj/mips", 371 genfile: "../../mips64/ssa.go", 372 ops: ops, 373 blocks: blocks, 374 regnames: regNamesMIPS64, 375 gpregmask: gp, 376 fpregmask: fp, 377 specialregmask: hi | lo, 378 framepointerreg: -1, // not used 379 linkreg: int8(num["R31"]), 380 }) 381 }