github.com/goproxy0/go@v0.0.0-20171111080102-49cc0c489d2c/src/cmd/compile/internal/ssa/gen/MIPSOps.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 // - Unused portions of AuxInt are filled by sign-extending the used portion. 16 // - *const instructions may use a constant larger than the instruction can encode. 17 // In this case the assembler expands to multiple instructions and uses tmp 18 // register (R23). 19 20 // Suffixes encode the bit width of various instructions. 21 // W (word) = 32 bit 22 // H (half word) = 16 bit 23 // HU = 16 bit unsigned 24 // B (byte) = 8 bit 25 // BU = 8 bit unsigned 26 // F (float) = 32 bit float 27 // D (double) = 64 bit float 28 29 // Note: registers not used in regalloc are not included in this list, 30 // so that regmask stays within int64 31 // Be careful when hand coding regmasks. 32 var regNamesMIPS = []string{ 33 "R0", // constant 0 34 "R1", 35 "R2", 36 "R3", 37 "R4", 38 "R5", 39 "R6", 40 "R7", 41 "R8", 42 "R9", 43 "R10", 44 "R11", 45 "R12", 46 "R13", 47 "R14", 48 "R15", 49 "R16", 50 "R17", 51 "R18", 52 "R19", 53 "R20", 54 "R21", 55 "R22", 56 //REGTMP 57 "R24", 58 "R25", 59 // R26 reserved by kernel 60 // R27 reserved by kernel 61 "R28", 62 "SP", // aka R29 63 "g", // aka R30 64 "R31", // REGLINK 65 66 // odd FP registers contain high parts of 64-bit FP values 67 "F0", 68 "F2", 69 "F4", 70 "F6", 71 "F8", 72 "F10", 73 "F12", 74 "F14", 75 "F16", 76 "F18", 77 "F20", 78 "F22", 79 "F24", 80 "F26", 81 "F28", 82 "F30", 83 84 "HI", // high bits of multiplication 85 "LO", // low bits of multiplication 86 87 // pseudo-registers 88 "SB", 89 } 90 91 func init() { 92 // Make map from reg names to reg integers. 93 if len(regNamesMIPS) > 64 { 94 panic("too many registers") 95 } 96 num := map[string]int{} 97 for i, name := range regNamesMIPS { 98 num[name] = i 99 } 100 buildReg := func(s string) regMask { 101 m := regMask(0) 102 for _, r := range strings.Split(s, " ") { 103 if n, ok := num[r]; ok { 104 m |= regMask(1) << uint(n) 105 continue 106 } 107 panic("register " + r + " not found") 108 } 109 return m 110 } 111 112 // Common individual register masks 113 var ( 114 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 R28 R31") 115 gpg = gp | buildReg("g") 116 gpsp = gp | buildReg("SP") 117 gpspg = gpg | buildReg("SP") 118 gpspsbg = gpspg | buildReg("SB") 119 fp = buildReg("F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30") 120 lo = buildReg("LO") 121 hi = buildReg("HI") 122 callerSave = gp | fp | lo | hi | buildReg("g") // runtime.setg (and anything calling it) may clobber g 123 ) 124 // Common regInfo 125 var ( 126 gp01 = regInfo{inputs: nil, outputs: []regMask{gp}} 127 gp11 = regInfo{inputs: []regMask{gpg}, outputs: []regMask{gp}} 128 gp11sp = regInfo{inputs: []regMask{gpspg}, outputs: []regMask{gp}} 129 gp21 = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{gp}} 130 gp31 = regInfo{inputs: []regMask{gp, gp, gp}, outputs: []regMask{gp}} 131 gp2hilo = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{hi, lo}} 132 gpload = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}} 133 gpstore = regInfo{inputs: []regMask{gpspsbg, gpg}} 134 gpxchg = regInfo{inputs: []regMask{gpspsbg, gpg}, outputs: []regMask{gp}} 135 gpcas = regInfo{inputs: []regMask{gpspsbg, gpg, gpg}, outputs: []regMask{gp}} 136 gpstore0 = regInfo{inputs: []regMask{gpspsbg}} 137 fp01 = regInfo{inputs: nil, outputs: []regMask{fp}} 138 fp11 = regInfo{inputs: []regMask{fp}, outputs: []regMask{fp}} 139 fp21 = regInfo{inputs: []regMask{fp, fp}, outputs: []regMask{fp}} 140 fp2flags = regInfo{inputs: []regMask{fp, fp}} 141 fpload = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{fp}} 142 fpstore = regInfo{inputs: []regMask{gpspsbg, fp}} 143 readflags = regInfo{inputs: nil, outputs: []regMask{gp}} 144 ) 145 ops := []opData{ 146 {name: "ADD", argLength: 2, reg: gp21, asm: "ADDU", commutative: true}, // arg0 + arg1 147 {name: "ADDconst", argLength: 1, reg: gp11sp, asm: "ADDU", aux: "Int32"}, // arg0 + auxInt 148 {name: "SUB", argLength: 2, reg: gp21, asm: "SUBU"}, // arg0 - arg1 149 {name: "SUBconst", argLength: 1, reg: gp11, asm: "SUBU", aux: "Int32"}, // arg0 - auxInt 150 {name: "MUL", argLength: 2, reg: regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{gp}, clobbers: hi | lo}, asm: "MUL", commutative: true}, // arg0 * arg1 151 {name: "MULT", argLength: 2, reg: gp2hilo, asm: "MUL", commutative: true, typ: "(Int32,Int32)"}, // arg0 * arg1, signed, results hi,lo 152 {name: "MULTU", argLength: 2, reg: gp2hilo, asm: "MULU", commutative: true, typ: "(UInt32,UInt32)"}, // arg0 * arg1, unsigned, results hi,lo 153 {name: "DIV", argLength: 2, reg: gp2hilo, asm: "DIV", typ: "(Int32,Int32)"}, // arg0 / arg1, signed, results hi=arg0%arg1,lo=arg0/arg1 154 {name: "DIVU", argLength: 2, reg: gp2hilo, asm: "DIVU", typ: "(UInt32,UInt32)"}, // arg0 / arg1, signed, results hi=arg0%arg1,lo=arg0/arg1 155 156 {name: "ADDF", argLength: 2, reg: fp21, asm: "ADDF", commutative: true}, // arg0 + arg1 157 {name: "ADDD", argLength: 2, reg: fp21, asm: "ADDD", commutative: true}, // arg0 + arg1 158 {name: "SUBF", argLength: 2, reg: fp21, asm: "SUBF"}, // arg0 - arg1 159 {name: "SUBD", argLength: 2, reg: fp21, asm: "SUBD"}, // arg0 - arg1 160 {name: "MULF", argLength: 2, reg: fp21, asm: "MULF", commutative: true}, // arg0 * arg1 161 {name: "MULD", argLength: 2, reg: fp21, asm: "MULD", commutative: true}, // arg0 * arg1 162 {name: "DIVF", argLength: 2, reg: fp21, asm: "DIVF"}, // arg0 / arg1 163 {name: "DIVD", argLength: 2, reg: fp21, asm: "DIVD"}, // arg0 / arg1 164 165 {name: "AND", argLength: 2, reg: gp21, asm: "AND", commutative: true}, // arg0 & arg1 166 {name: "ANDconst", argLength: 1, reg: gp11, asm: "AND", aux: "Int32"}, // arg0 & auxInt 167 {name: "OR", argLength: 2, reg: gp21, asm: "OR", commutative: true}, // arg0 | arg1 168 {name: "ORconst", argLength: 1, reg: gp11, asm: "OR", aux: "Int32"}, // arg0 | auxInt 169 {name: "XOR", argLength: 2, reg: gp21, asm: "XOR", commutative: true, typ: "UInt32"}, // arg0 ^ arg1 170 {name: "XORconst", argLength: 1, reg: gp11, asm: "XOR", aux: "Int32", typ: "UInt32"}, // arg0 ^ auxInt 171 {name: "NOR", argLength: 2, reg: gp21, asm: "NOR", commutative: true}, // ^(arg0 | arg1) 172 {name: "NORconst", argLength: 1, reg: gp11, asm: "NOR", aux: "Int32"}, // ^(arg0 | auxInt) 173 174 {name: "NEG", argLength: 1, reg: gp11}, // -arg0 175 {name: "NEGF", argLength: 1, reg: fp11, asm: "NEGF"}, // -arg0, float32 176 {name: "NEGD", argLength: 1, reg: fp11, asm: "NEGD"}, // -arg0, float64 177 {name: "SQRTD", argLength: 1, reg: fp11, asm: "SQRTD"}, // sqrt(arg0), float64 178 179 // shifts 180 {name: "SLL", argLength: 2, reg: gp21, asm: "SLL"}, // arg0 << arg1, shift amount is mod 32 181 {name: "SLLconst", argLength: 1, reg: gp11, asm: "SLL", aux: "Int32"}, // arg0 << auxInt 182 {name: "SRL", argLength: 2, reg: gp21, asm: "SRL"}, // arg0 >> arg1, unsigned, shift amount is mod 32 183 {name: "SRLconst", argLength: 1, reg: gp11, asm: "SRL", aux: "Int32"}, // arg0 >> auxInt, unsigned 184 {name: "SRA", argLength: 2, reg: gp21, asm: "SRA"}, // arg0 >> arg1, signed, shift amount is mod 32 185 {name: "SRAconst", argLength: 1, reg: gp11, asm: "SRA", aux: "Int32"}, // arg0 >> auxInt, signed 186 187 {name: "CLZ", argLength: 1, reg: gp11, asm: "CLZ"}, 188 189 // comparisons 190 {name: "SGT", argLength: 2, reg: gp21, asm: "SGT", typ: "Bool"}, // 1 if arg0 > arg1 (signed), 0 otherwise 191 {name: "SGTconst", argLength: 1, reg: gp11, asm: "SGT", aux: "Int32", typ: "Bool"}, // 1 if auxInt > arg0 (signed), 0 otherwise 192 {name: "SGTzero", argLength: 1, reg: gp11, asm: "SGT", typ: "Bool"}, // 1 if arg0 > 0 (signed), 0 otherwise 193 {name: "SGTU", argLength: 2, reg: gp21, asm: "SGTU", typ: "Bool"}, // 1 if arg0 > arg1 (unsigned), 0 otherwise 194 {name: "SGTUconst", argLength: 1, reg: gp11, asm: "SGTU", aux: "Int32", typ: "Bool"}, // 1 if auxInt > arg0 (unsigned), 0 otherwise 195 {name: "SGTUzero", argLength: 1, reg: gp11, asm: "SGTU", typ: "Bool"}, // 1 if arg0 > 0 (unsigned), 0 otherwise 196 197 {name: "CMPEQF", argLength: 2, reg: fp2flags, asm: "CMPEQF", typ: "Flags"}, // flags=true if arg0 = arg1, float32 198 {name: "CMPEQD", argLength: 2, reg: fp2flags, asm: "CMPEQD", typ: "Flags"}, // flags=true if arg0 = arg1, float64 199 {name: "CMPGEF", argLength: 2, reg: fp2flags, asm: "CMPGEF", typ: "Flags"}, // flags=true if arg0 >= arg1, float32 200 {name: "CMPGED", argLength: 2, reg: fp2flags, asm: "CMPGED", typ: "Flags"}, // flags=true if arg0 >= arg1, float64 201 {name: "CMPGTF", argLength: 2, reg: fp2flags, asm: "CMPGTF", typ: "Flags"}, // flags=true if arg0 > arg1, float32 202 {name: "CMPGTD", argLength: 2, reg: fp2flags, asm: "CMPGTD", typ: "Flags"}, // flags=true if arg0 > arg1, float64 203 204 // moves 205 {name: "MOVWconst", argLength: 0, reg: gp01, aux: "Int32", asm: "MOVW", typ: "UInt32", rematerializeable: true}, // auxint 206 {name: "MOVFconst", argLength: 0, reg: fp01, aux: "Float32", asm: "MOVF", typ: "Float32", rematerializeable: true}, // auxint as 64-bit float, convert to 32-bit float 207 {name: "MOVDconst", argLength: 0, reg: fp01, aux: "Float64", asm: "MOVD", typ: "Float64", rematerializeable: true}, // auxint as 64-bit float 208 209 {name: "MOVWaddr", argLength: 1, reg: regInfo{inputs: []regMask{buildReg("SP") | buildReg("SB")}, outputs: []regMask{gp}}, aux: "SymOff", asm: "MOVW", rematerializeable: true, symEffect: "Addr"}, // arg0 + auxInt + aux.(*gc.Sym), arg0=SP/SB 210 211 {name: "MOVBload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVB", typ: "Int8", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 212 {name: "MOVBUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVBU", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 213 {name: "MOVHload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVH", typ: "Int16", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 214 {name: "MOVHUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVHU", typ: "UInt16", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 215 {name: "MOVWload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVW", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 216 {name: "MOVFload", argLength: 2, reg: fpload, aux: "SymOff", asm: "MOVF", typ: "Float32", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 217 {name: "MOVDload", argLength: 2, reg: fpload, aux: "SymOff", asm: "MOVD", typ: "Float64", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 218 219 {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. 220 {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. 221 {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. 222 {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. 223 {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. 224 225 {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. 226 {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. 227 {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. 228 229 // conversions 230 {name: "MOVBreg", argLength: 1, reg: gp11, asm: "MOVB"}, // move from arg0, sign-extended from byte 231 {name: "MOVBUreg", argLength: 1, reg: gp11, asm: "MOVBU"}, // move from arg0, unsign-extended from byte 232 {name: "MOVHreg", argLength: 1, reg: gp11, asm: "MOVH"}, // move from arg0, sign-extended from half 233 {name: "MOVHUreg", argLength: 1, reg: gp11, asm: "MOVHU"}, // move from arg0, unsign-extended from half 234 {name: "MOVWreg", argLength: 1, reg: gp11, asm: "MOVW"}, // move from arg0 235 236 {name: "MOVWnop", argLength: 1, reg: regInfo{inputs: []regMask{gp}, outputs: []regMask{gp}}, resultInArg0: true}, // nop, return arg0 in same register 237 238 // conditional move on zero (returns arg1 if arg2 is 0, otherwise arg0) 239 // order of parameters is reversed so we can use resultInArg0 (OpCMOVZ result arg1 arg2-> CMOVZ arg2reg, arg1reg, resultReg) 240 {name: "CMOVZ", argLength: 3, reg: gp31, asm: "CMOVZ", resultInArg0: true}, 241 {name: "CMOVZzero", argLength: 2, reg: regInfo{inputs: []regMask{gp, gpg}, outputs: []regMask{gp}}, asm: "CMOVZ", resultInArg0: true}, 242 243 {name: "MOVWF", argLength: 1, reg: fp11, asm: "MOVWF"}, // int32 -> float32 244 {name: "MOVWD", argLength: 1, reg: fp11, asm: "MOVWD"}, // int32 -> float64 245 {name: "TRUNCFW", argLength: 1, reg: fp11, asm: "TRUNCFW"}, // float32 -> int32 246 {name: "TRUNCDW", argLength: 1, reg: fp11, asm: "TRUNCDW"}, // float64 -> int32 247 {name: "MOVFD", argLength: 1, reg: fp11, asm: "MOVFD"}, // float32 -> float64 248 {name: "MOVDF", argLength: 1, reg: fp11, asm: "MOVDF"}, // float64 -> float32 249 250 // function calls 251 {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 252 {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 253 {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 254 255 // atomic ops 256 257 // load from arg0. arg1=mem. 258 // returns <value,memory> so they can be properly ordered with other loads. 259 // SYNC 260 // MOVW (Rarg0), Rout 261 // SYNC 262 {name: "LoweredAtomicLoad", argLength: 2, reg: gpload, faultOnNilArg0: true}, 263 264 // store arg1 to arg0. arg2=mem. returns memory. 265 // SYNC 266 // MOVW Rarg1, (Rarg0) 267 // SYNC 268 {name: "LoweredAtomicStore", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true}, 269 {name: "LoweredAtomicStorezero", argLength: 2, reg: gpstore0, faultOnNilArg0: true, hasSideEffects: true}, 270 271 // atomic exchange. 272 // store arg1 to arg0. arg2=mem. returns <old content of *arg0, memory>. 273 // SYNC 274 // LL (Rarg0), Rout 275 // MOVW Rarg1, Rtmp 276 // SC Rtmp, (Rarg0) 277 // BEQ Rtmp, -3(PC) 278 // SYNC 279 {name: "LoweredAtomicExchange", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true}, 280 281 // atomic add. 282 // *arg0 += arg1. arg2=mem. returns <new content of *arg0, memory>. 283 // SYNC 284 // LL (Rarg0), Rout 285 // ADDU Rarg1, Rout, Rtmp 286 // SC Rtmp, (Rarg0) 287 // BEQ Rtmp, -3(PC) 288 // SYNC 289 // ADDU Rarg1, Rout 290 {name: "LoweredAtomicAdd", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true}, 291 {name: "LoweredAtomicAddconst", argLength: 2, reg: regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}}, aux: "Int32", resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true}, 292 293 // atomic compare and swap. 294 // arg0 = pointer, arg1 = old value, arg2 = new value, arg3 = memory. 295 // if *arg0 == arg1 { 296 // *arg0 = arg2 297 // return (true, memory) 298 // } else { 299 // return (false, memory) 300 // } 301 // SYNC 302 // MOVW $0, Rout 303 // LL (Rarg0), Rtmp 304 // BNE Rtmp, Rarg1, 4(PC) 305 // MOVW Rarg2, Rout 306 // SC Rout, (Rarg0) 307 // BEQ Rout, -4(PC) 308 // SYNC 309 {name: "LoweredAtomicCas", argLength: 4, reg: gpcas, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true}, 310 311 // atomic and/or. 312 // *arg0 &= (|=) arg1. arg2=mem. returns memory. 313 // SYNC 314 // LL (Rarg0), Rtmp 315 // AND Rarg1, Rtmp 316 // SC Rtmp, (Rarg0) 317 // BEQ Rtmp, -3(PC) 318 // SYNC 319 {name: "LoweredAtomicAnd", argLength: 3, reg: gpstore, asm: "AND", faultOnNilArg0: true, hasSideEffects: true}, 320 {name: "LoweredAtomicOr", argLength: 3, reg: gpstore, asm: "OR", faultOnNilArg0: true, hasSideEffects: true}, 321 322 // large or unaligned zeroing 323 // arg0 = address of memory to zero (in R1, changed as side effect) 324 // arg1 = address of the last element to zero 325 // arg2 = mem 326 // auxint = alignment 327 // returns mem 328 // SUBU $4, R1 329 // MOVW R0, 4(R1) 330 // ADDU $4, R1 331 // BNE Rarg1, R1, -2(PC) 332 { 333 name: "LoweredZero", 334 aux: "Int32", 335 argLength: 3, 336 reg: regInfo{ 337 inputs: []regMask{buildReg("R1"), gp}, 338 clobbers: buildReg("R1"), 339 }, 340 faultOnNilArg0: true, 341 }, 342 343 // large or unaligned move 344 // arg0 = address of dst memory (in R2, changed as side effect) 345 // arg1 = address of src memory (in R1, changed as side effect) 346 // arg2 = address of the last element of src 347 // arg3 = mem 348 // auxint = alignment 349 // returns mem 350 // SUBU $4, R1 351 // MOVW 4(R1), Rtmp 352 // MOVW Rtmp, (R2) 353 // ADDU $4, R1 354 // ADDU $4, R2 355 // BNE Rarg2, R1, -4(PC) 356 { 357 name: "LoweredMove", 358 aux: "Int32", 359 argLength: 4, 360 reg: regInfo{ 361 inputs: []regMask{buildReg("R2"), buildReg("R1"), gp}, 362 clobbers: buildReg("R1 R2"), 363 }, 364 faultOnNilArg0: true, 365 faultOnNilArg1: true, 366 }, 367 368 // pseudo-ops 369 {name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{gpg}}, nilCheck: true, faultOnNilArg0: true}, // panic if arg0 is nil. arg1=mem. 370 371 {name: "FPFlagTrue", argLength: 1, reg: readflags}, // bool, true if FP flag is true 372 {name: "FPFlagFalse", argLength: 1, reg: readflags}, // bool, true if FP flag is false 373 374 // Scheduler ensures LoweredGetClosurePtr occurs only in entry block, 375 // and sorts it to the very beginning of the block to prevent other 376 // use of R22 (mips.REGCTXT, the closure pointer) 377 {name: "LoweredGetClosurePtr", reg: regInfo{outputs: []regMask{buildReg("R22")}}}, 378 379 // LoweredGetCallerSP returns the SP of the caller of the current function. 380 {name: "LoweredGetCallerSP", reg: gp01, rematerializeable: true}, 381 382 // MOVWconvert converts between pointers and integers. 383 // We have a special op for this so as to not confuse GC 384 // (particularly stack maps). It takes a memory arg so it 385 // gets correctly ordered with respect to GC safepoints. 386 // arg0=ptr/int arg1=mem, output=int/ptr 387 {name: "MOVWconvert", argLength: 2, reg: gp11, asm: "MOVW"}, 388 } 389 390 blocks := []blockData{ 391 {name: "EQ"}, 392 {name: "NE"}, 393 {name: "LTZ"}, // < 0 394 {name: "LEZ"}, // <= 0 395 {name: "GTZ"}, // > 0 396 {name: "GEZ"}, // >= 0 397 {name: "FPT"}, // FP flag is true 398 {name: "FPF"}, // FP flag is false 399 } 400 401 archs = append(archs, arch{ 402 name: "MIPS", 403 pkg: "cmd/internal/obj/mips", 404 genfile: "../../mips/ssa.go", 405 ops: ops, 406 blocks: blocks, 407 regnames: regNamesMIPS, 408 gpregmask: gp, 409 fpregmask: fp, 410 specialregmask: hi | lo, 411 framepointerreg: -1, // not used 412 linkreg: int8(num["R31"]), 413 }) 414 }