github.com/bir3/gocompiler@v0.3.205/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 package main 6 7 import "strings" 8 9 // Notes: 10 // - Integer types live in the low portion of registers. Upper portions are junk. 11 // - Boolean types use the low-order byte of a register. 0=false, 1=true. 12 // Upper bytes are junk. 13 // - Unused portions of AuxInt are filled by sign-extending the used portion. 14 // - *const instructions may use a constant larger than the instruction can encode. 15 // In this case the assembler expands to multiple instructions and uses tmp 16 // register (R23). 17 18 // Suffixes encode the bit width of various instructions. 19 // W (word) = 32 bit 20 // H (half word) = 16 bit 21 // HU = 16 bit unsigned 22 // B (byte) = 8 bit 23 // BU = 8 bit unsigned 24 // F (float) = 32 bit float 25 // D (double) = 64 bit float 26 27 // Note: registers not used in regalloc are not included in this list, 28 // so that regmask stays within int64 29 // Be careful when hand coding regmasks. 30 var regNamesMIPS = []string{ 31 "R0", // constant 0 32 "R1", 33 "R2", 34 "R3", 35 "R4", 36 "R5", 37 "R6", 38 "R7", 39 "R8", 40 "R9", 41 "R10", 42 "R11", 43 "R12", 44 "R13", 45 "R14", 46 "R15", 47 "R16", 48 "R17", 49 "R18", 50 "R19", 51 "R20", 52 "R21", 53 "R22", 54 //REGTMP 55 "R24", 56 "R25", 57 // R26 reserved by kernel 58 // R27 reserved by kernel 59 "R28", 60 "SP", // aka R29 61 "g", // aka R30 62 "R31", // REGLINK 63 64 // odd FP registers contain high parts of 64-bit FP values 65 "F0", 66 "F2", 67 "F4", 68 "F6", 69 "F8", 70 "F10", 71 "F12", 72 "F14", 73 "F16", 74 "F18", 75 "F20", 76 "F22", 77 "F24", 78 "F26", 79 "F28", 80 "F30", 81 82 "HI", // high bits of multiplication 83 "LO", // low bits of multiplication 84 85 // If you add registers, update asyncPreempt in runtime. 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 r1 = buildReg("R1") 124 r2 = buildReg("R2") 125 r3 = buildReg("R3") 126 r4 = buildReg("R4") 127 r5 = buildReg("R5") 128 ) 129 // Common regInfo 130 var ( 131 gp01 = regInfo{inputs: nil, outputs: []regMask{gp}} 132 gp11 = regInfo{inputs: []regMask{gpg}, outputs: []regMask{gp}} 133 gp11sp = regInfo{inputs: []regMask{gpspg}, outputs: []regMask{gp}} 134 gp21 = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{gp}} 135 gp31 = regInfo{inputs: []regMask{gp, gp, gp}, outputs: []regMask{gp}} 136 gp2hilo = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{hi, lo}} 137 gpload = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}} 138 gpstore = regInfo{inputs: []regMask{gpspsbg, gpg}} 139 gpxchg = regInfo{inputs: []regMask{gpspsbg, gpg}, outputs: []regMask{gp}} 140 gpcas = regInfo{inputs: []regMask{gpspsbg, gpg, gpg}, outputs: []regMask{gp}} 141 gpstore0 = regInfo{inputs: []regMask{gpspsbg}} 142 fp01 = regInfo{inputs: nil, outputs: []regMask{fp}} 143 fp11 = regInfo{inputs: []regMask{fp}, outputs: []regMask{fp}} 144 fp21 = regInfo{inputs: []regMask{fp, fp}, outputs: []regMask{fp}} 145 fp2flags = regInfo{inputs: []regMask{fp, fp}} 146 fpload = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{fp}} 147 fpstore = regInfo{inputs: []regMask{gpspsbg, fp}} 148 readflags = regInfo{inputs: nil, outputs: []regMask{gp}} 149 ) 150 ops := []opData{ 151 {name: "ADD", argLength: 2, reg: gp21, asm: "ADDU", commutative: true}, // arg0 + arg1 152 {name: "ADDconst", argLength: 1, reg: gp11sp, asm: "ADDU", aux: "Int32"}, // arg0 + auxInt 153 {name: "SUB", argLength: 2, reg: gp21, asm: "SUBU"}, // arg0 - arg1 154 {name: "SUBconst", argLength: 1, reg: gp11, asm: "SUBU", aux: "Int32"}, // arg0 - auxInt 155 {name: "MUL", argLength: 2, reg: regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{gp}, clobbers: hi | lo}, asm: "MUL", commutative: true}, // arg0 * arg1 156 {name: "MULT", argLength: 2, reg: gp2hilo, asm: "MUL", commutative: true, typ: "(Int32,Int32)"}, // arg0 * arg1, signed, results hi,lo 157 {name: "MULTU", argLength: 2, reg: gp2hilo, asm: "MULU", commutative: true, typ: "(UInt32,UInt32)"}, // arg0 * arg1, unsigned, results hi,lo 158 {name: "DIV", argLength: 2, reg: gp2hilo, asm: "DIV", typ: "(Int32,Int32)"}, // arg0 / arg1, signed, results hi=arg0%arg1,lo=arg0/arg1 159 {name: "DIVU", argLength: 2, reg: gp2hilo, asm: "DIVU", typ: "(UInt32,UInt32)"}, // arg0 / arg1, signed, results hi=arg0%arg1,lo=arg0/arg1 160 161 {name: "ADDF", argLength: 2, reg: fp21, asm: "ADDF", commutative: true}, // arg0 + arg1 162 {name: "ADDD", argLength: 2, reg: fp21, asm: "ADDD", commutative: true}, // arg0 + arg1 163 {name: "SUBF", argLength: 2, reg: fp21, asm: "SUBF"}, // arg0 - arg1 164 {name: "SUBD", argLength: 2, reg: fp21, asm: "SUBD"}, // arg0 - arg1 165 {name: "MULF", argLength: 2, reg: fp21, asm: "MULF", commutative: true}, // arg0 * arg1 166 {name: "MULD", argLength: 2, reg: fp21, asm: "MULD", commutative: true}, // arg0 * arg1 167 {name: "DIVF", argLength: 2, reg: fp21, asm: "DIVF"}, // arg0 / arg1 168 {name: "DIVD", argLength: 2, reg: fp21, asm: "DIVD"}, // arg0 / arg1 169 170 {name: "AND", argLength: 2, reg: gp21, asm: "AND", commutative: true}, // arg0 & arg1 171 {name: "ANDconst", argLength: 1, reg: gp11, asm: "AND", aux: "Int32"}, // arg0 & auxInt 172 {name: "OR", argLength: 2, reg: gp21, asm: "OR", commutative: true}, // arg0 | arg1 173 {name: "ORconst", argLength: 1, reg: gp11, asm: "OR", aux: "Int32"}, // arg0 | auxInt 174 {name: "XOR", argLength: 2, reg: gp21, asm: "XOR", commutative: true, typ: "UInt32"}, // arg0 ^ arg1 175 {name: "XORconst", argLength: 1, reg: gp11, asm: "XOR", aux: "Int32", typ: "UInt32"}, // arg0 ^ auxInt 176 {name: "NOR", argLength: 2, reg: gp21, asm: "NOR", commutative: true}, // ^(arg0 | arg1) 177 {name: "NORconst", argLength: 1, reg: gp11, asm: "NOR", aux: "Int32"}, // ^(arg0 | auxInt) 178 179 {name: "NEG", argLength: 1, reg: gp11}, // -arg0 180 {name: "NEGF", argLength: 1, reg: fp11, asm: "NEGF"}, // -arg0, float32 181 {name: "NEGD", argLength: 1, reg: fp11, asm: "NEGD"}, // -arg0, float64 182 {name: "SQRTD", argLength: 1, reg: fp11, asm: "SQRTD"}, // sqrt(arg0), float64 183 {name: "SQRTF", argLength: 1, reg: fp11, asm: "SQRTF"}, // sqrt(arg0), float32 184 185 // shifts 186 {name: "SLL", argLength: 2, reg: gp21, asm: "SLL"}, // arg0 << arg1, shift amount is mod 32 187 {name: "SLLconst", argLength: 1, reg: gp11, asm: "SLL", aux: "Int32"}, // arg0 << auxInt, shift amount must be 0 through 31 inclusive 188 {name: "SRL", argLength: 2, reg: gp21, asm: "SRL"}, // arg0 >> arg1, unsigned, shift amount is mod 32 189 {name: "SRLconst", argLength: 1, reg: gp11, asm: "SRL", aux: "Int32"}, // arg0 >> auxInt, shift amount must be 0 through 31 inclusive 190 {name: "SRA", argLength: 2, reg: gp21, asm: "SRA"}, // arg0 >> arg1, signed, shift amount is mod 32 191 {name: "SRAconst", argLength: 1, reg: gp11, asm: "SRA", aux: "Int32"}, // arg0 >> auxInt, signed, shift amount must be 0 through 31 inclusive 192 193 {name: "CLZ", argLength: 1, reg: gp11, asm: "CLZ"}, 194 195 // comparisons 196 {name: "SGT", argLength: 2, reg: gp21, asm: "SGT", typ: "Bool"}, // 1 if arg0 > arg1 (signed), 0 otherwise 197 {name: "SGTconst", argLength: 1, reg: gp11, asm: "SGT", aux: "Int32", typ: "Bool"}, // 1 if auxInt > arg0 (signed), 0 otherwise 198 {name: "SGTzero", argLength: 1, reg: gp11, asm: "SGT", typ: "Bool"}, // 1 if arg0 > 0 (signed), 0 otherwise 199 {name: "SGTU", argLength: 2, reg: gp21, asm: "SGTU", typ: "Bool"}, // 1 if arg0 > arg1 (unsigned), 0 otherwise 200 {name: "SGTUconst", argLength: 1, reg: gp11, asm: "SGTU", aux: "Int32", typ: "Bool"}, // 1 if auxInt > arg0 (unsigned), 0 otherwise 201 {name: "SGTUzero", argLength: 1, reg: gp11, asm: "SGTU", typ: "Bool"}, // 1 if arg0 > 0 (unsigned), 0 otherwise 202 203 {name: "CMPEQF", argLength: 2, reg: fp2flags, asm: "CMPEQF", typ: "Flags"}, // flags=true if arg0 = arg1, float32 204 {name: "CMPEQD", argLength: 2, reg: fp2flags, asm: "CMPEQD", typ: "Flags"}, // flags=true if arg0 = arg1, float64 205 {name: "CMPGEF", argLength: 2, reg: fp2flags, asm: "CMPGEF", typ: "Flags"}, // flags=true if arg0 >= arg1, float32 206 {name: "CMPGED", argLength: 2, reg: fp2flags, asm: "CMPGED", typ: "Flags"}, // flags=true if arg0 >= arg1, float64 207 {name: "CMPGTF", argLength: 2, reg: fp2flags, asm: "CMPGTF", typ: "Flags"}, // flags=true if arg0 > arg1, float32 208 {name: "CMPGTD", argLength: 2, reg: fp2flags, asm: "CMPGTD", typ: "Flags"}, // flags=true if arg0 > arg1, float64 209 210 // moves 211 {name: "MOVWconst", argLength: 0, reg: gp01, aux: "Int32", asm: "MOVW", typ: "UInt32", rematerializeable: true}, // auxint 212 {name: "MOVFconst", argLength: 0, reg: fp01, aux: "Float32", asm: "MOVF", typ: "Float32", rematerializeable: true}, // auxint as 64-bit float, convert to 32-bit float 213 {name: "MOVDconst", argLength: 0, reg: fp01, aux: "Float64", asm: "MOVD", typ: "Float64", rematerializeable: true}, // auxint as 64-bit float 214 215 {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 216 217 {name: "MOVBload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVB", typ: "Int8", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 218 {name: "MOVBUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVBU", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 219 {name: "MOVHload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVH", typ: "Int16", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 220 {name: "MOVHUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVHU", typ: "UInt16", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 221 {name: "MOVWload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVW", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 222 {name: "MOVFload", argLength: 2, reg: fpload, aux: "SymOff", asm: "MOVF", typ: "Float32", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 223 {name: "MOVDload", argLength: 2, reg: fpload, aux: "SymOff", asm: "MOVD", typ: "Float64", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. 224 225 {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. 226 {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. 227 {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. 228 {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. 229 {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. 230 231 {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. 232 {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. 233 {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. 234 235 // conversions 236 {name: "MOVBreg", argLength: 1, reg: gp11, asm: "MOVB"}, // move from arg0, sign-extended from byte 237 {name: "MOVBUreg", argLength: 1, reg: gp11, asm: "MOVBU"}, // move from arg0, unsign-extended from byte 238 {name: "MOVHreg", argLength: 1, reg: gp11, asm: "MOVH"}, // move from arg0, sign-extended from half 239 {name: "MOVHUreg", argLength: 1, reg: gp11, asm: "MOVHU"}, // move from arg0, unsign-extended from half 240 {name: "MOVWreg", argLength: 1, reg: gp11, asm: "MOVW"}, // move from arg0 241 242 {name: "MOVWnop", argLength: 1, reg: regInfo{inputs: []regMask{gp}, outputs: []regMask{gp}}, resultInArg0: true}, // nop, return arg0 in same register 243 244 // conditional move on zero (returns arg1 if arg2 is 0, otherwise arg0) 245 // order of parameters is reversed so we can use resultInArg0 (OpCMOVZ result arg1 arg2-> CMOVZ arg2reg, arg1reg, resultReg) 246 {name: "CMOVZ", argLength: 3, reg: gp31, asm: "CMOVZ", resultInArg0: true}, 247 {name: "CMOVZzero", argLength: 2, reg: regInfo{inputs: []regMask{gp, gpg}, outputs: []regMask{gp}}, asm: "CMOVZ", resultInArg0: true}, 248 249 {name: "MOVWF", argLength: 1, reg: fp11, asm: "MOVWF"}, // int32 -> float32 250 {name: "MOVWD", argLength: 1, reg: fp11, asm: "MOVWD"}, // int32 -> float64 251 {name: "TRUNCFW", argLength: 1, reg: fp11, asm: "TRUNCFW"}, // float32 -> int32 252 {name: "TRUNCDW", argLength: 1, reg: fp11, asm: "TRUNCDW"}, // float64 -> int32 253 {name: "MOVFD", argLength: 1, reg: fp11, asm: "MOVFD"}, // float32 -> float64 254 {name: "MOVDF", argLength: 1, reg: fp11, asm: "MOVDF"}, // float64 -> float32 255 256 // function calls 257 {name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call static function aux.(*obj.LSym). arg0=mem, auxint=argsize, returns mem 258 {name: "CALLtail", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true, tailCall: true}, // tail call static function aux.(*obj.LSym). arg0=mem, auxint=argsize, returns mem 259 {name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{gpsp, buildReg("R22"), 0}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem 260 {name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem 261 262 // atomic ops 263 264 // load from arg0. arg1=mem. 265 // returns <value,memory> so they can be properly ordered with other loads. 266 // SYNC 267 // MOV(B|W) (Rarg0), Rout 268 // SYNC 269 {name: "LoweredAtomicLoad8", argLength: 2, reg: gpload, faultOnNilArg0: true}, 270 {name: "LoweredAtomicLoad32", argLength: 2, reg: gpload, faultOnNilArg0: true}, 271 272 // store arg1 to arg0. arg2=mem. returns memory. 273 // SYNC 274 // MOV(B|W) Rarg1, (Rarg0) 275 // SYNC 276 {name: "LoweredAtomicStore8", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true}, 277 {name: "LoweredAtomicStore32", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true}, 278 {name: "LoweredAtomicStorezero", argLength: 2, reg: gpstore0, faultOnNilArg0: true, hasSideEffects: true}, 279 280 // atomic exchange. 281 // store arg1 to arg0. arg2=mem. returns <old content of *arg0, memory>. 282 // SYNC 283 // LL (Rarg0), Rout 284 // MOVW Rarg1, Rtmp 285 // SC Rtmp, (Rarg0) 286 // BEQ Rtmp, -3(PC) 287 // SYNC 288 {name: "LoweredAtomicExchange", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true}, 289 290 // atomic add. 291 // *arg0 += arg1. arg2=mem. returns <new content of *arg0, memory>. 292 // SYNC 293 // LL (Rarg0), Rout 294 // ADDU Rarg1, Rout, Rtmp 295 // SC Rtmp, (Rarg0) 296 // BEQ Rtmp, -3(PC) 297 // SYNC 298 // ADDU Rarg1, Rout 299 {name: "LoweredAtomicAdd", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true}, 300 {name: "LoweredAtomicAddconst", argLength: 2, reg: regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}}, aux: "Int32", resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true}, 301 302 // atomic compare and swap. 303 // arg0 = pointer, arg1 = old value, arg2 = new value, arg3 = memory. 304 // if *arg0 == arg1 { 305 // *arg0 = arg2 306 // return (true, memory) 307 // } else { 308 // return (false, memory) 309 // } 310 // SYNC 311 // MOVW $0, Rout 312 // LL (Rarg0), Rtmp 313 // BNE Rtmp, Rarg1, 4(PC) 314 // MOVW Rarg2, Rout 315 // SC Rout, (Rarg0) 316 // BEQ Rout, -4(PC) 317 // SYNC 318 {name: "LoweredAtomicCas", argLength: 4, reg: gpcas, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true}, 319 320 // atomic and/or. 321 // *arg0 &= (|=) arg1. arg2=mem. returns memory. 322 // SYNC 323 // LL (Rarg0), Rtmp 324 // AND Rarg1, Rtmp 325 // SC Rtmp, (Rarg0) 326 // BEQ Rtmp, -3(PC) 327 // SYNC 328 {name: "LoweredAtomicAnd", argLength: 3, reg: gpstore, asm: "AND", faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true}, 329 {name: "LoweredAtomicOr", argLength: 3, reg: gpstore, asm: "OR", faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true}, 330 331 // large or unaligned zeroing 332 // arg0 = address of memory to zero (in R1, changed as side effect) 333 // arg1 = address of the last element to zero 334 // arg2 = mem 335 // auxint = alignment 336 // returns mem 337 // SUBU $4, R1 338 // MOVW R0, 4(R1) 339 // ADDU $4, R1 340 // BNE Rarg1, R1, -2(PC) 341 { 342 name: "LoweredZero", 343 aux: "Int32", 344 argLength: 3, 345 reg: regInfo{ 346 inputs: []regMask{buildReg("R1"), gp}, 347 clobbers: buildReg("R1"), 348 }, 349 faultOnNilArg0: true, 350 }, 351 352 // large or unaligned move 353 // arg0 = address of dst memory (in R2, changed as side effect) 354 // arg1 = address of src memory (in R1, changed as side effect) 355 // arg2 = address of the last element of src 356 // arg3 = mem 357 // auxint = alignment 358 // returns mem 359 // SUBU $4, R1 360 // MOVW 4(R1), Rtmp 361 // MOVW Rtmp, (R2) 362 // ADDU $4, R1 363 // ADDU $4, R2 364 // BNE Rarg2, R1, -4(PC) 365 { 366 name: "LoweredMove", 367 aux: "Int32", 368 argLength: 4, 369 reg: regInfo{ 370 inputs: []regMask{buildReg("R2"), buildReg("R1"), gp}, 371 clobbers: buildReg("R1 R2"), 372 }, 373 faultOnNilArg0: true, 374 faultOnNilArg1: true, 375 }, 376 377 // pseudo-ops 378 {name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{gpg}}, nilCheck: true, faultOnNilArg0: true}, // panic if arg0 is nil. arg1=mem. 379 380 {name: "FPFlagTrue", argLength: 1, reg: readflags}, // bool, true if FP flag is true 381 {name: "FPFlagFalse", argLength: 1, reg: readflags}, // bool, true if FP flag is false 382 383 // Scheduler ensures LoweredGetClosurePtr occurs only in entry block, 384 // and sorts it to the very beginning of the block to prevent other 385 // use of R22 (mips.REGCTXT, the closure pointer) 386 {name: "LoweredGetClosurePtr", reg: regInfo{outputs: []regMask{buildReg("R22")}}, zeroWidth: true}, 387 388 // LoweredGetCallerSP returns the SP of the caller of the current function. 389 {name: "LoweredGetCallerSP", reg: gp01, rematerializeable: true}, 390 391 // LoweredGetCallerPC evaluates to the PC to which its "caller" will return. 392 // I.e., if f calls g "calls" getcallerpc, 393 // the result should be the PC within f that g will return to. 394 // See runtime/stubs.go for a more detailed discussion. 395 {name: "LoweredGetCallerPC", reg: gp01, rematerializeable: true}, 396 397 // LoweredWB invokes runtime.gcWriteBarrier. arg0=destptr, arg1=srcptr, arg2=mem, aux=runtime.gcWriteBarrier 398 // It saves all GP registers if necessary, 399 // but clobbers R31 (LR) because it's a call 400 // and R23 (REGTMP). 401 {name: "LoweredWB", argLength: 3, reg: regInfo{inputs: []regMask{buildReg("R20"), buildReg("R21")}, clobbers: (callerSave &^ gpg) | buildReg("R31")}, clobberFlags: true, aux: "Sym", symEffect: "None"}, 402 403 // There are three of these functions so that they can have three different register inputs. 404 // When we check 0 <= c <= cap (A), then 0 <= b <= c (B), then 0 <= a <= b (C), we want the 405 // default registers to match so we don't need to copy registers around unnecessarily. 406 {name: "LoweredPanicBoundsA", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{r3, r4}}, typ: "Mem", call: true}, // arg0=idx, arg1=len, arg2=mem, returns memory. AuxInt contains report code (see PanicBounds in genericOps.go). 407 {name: "LoweredPanicBoundsB", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{r2, r3}}, typ: "Mem", call: true}, // arg0=idx, arg1=len, arg2=mem, returns memory. AuxInt contains report code (see PanicBounds in genericOps.go). 408 {name: "LoweredPanicBoundsC", argLength: 3, aux: "Int64", reg: regInfo{inputs: []regMask{r1, r2}}, typ: "Mem", call: true}, // arg0=idx, arg1=len, arg2=mem, returns memory. AuxInt contains report code (see PanicBounds in genericOps.go). 409 // Extend ops are the same as Bounds ops except the indexes are 64-bit. 410 {name: "LoweredPanicExtendA", argLength: 4, aux: "Int64", reg: regInfo{inputs: []regMask{r5, r3, r4}}, typ: "Mem", call: true}, // arg0=idxHi, arg1=idxLo, arg2=len, arg3=mem, returns memory. AuxInt contains report code (see PanicExtend in genericOps.go). 411 {name: "LoweredPanicExtendB", argLength: 4, aux: "Int64", reg: regInfo{inputs: []regMask{r5, r2, r3}}, typ: "Mem", call: true}, // arg0=idxHi, arg1=idxLo, arg2=len, arg3=mem, returns memory. AuxInt contains report code (see PanicExtend in genericOps.go). 412 {name: "LoweredPanicExtendC", argLength: 4, aux: "Int64", reg: regInfo{inputs: []regMask{r5, r1, r2}}, typ: "Mem", call: true}, // arg0=idxHi, arg1=idxLo, arg2=len, arg3=mem, returns memory. AuxInt contains report code (see PanicExtend in genericOps.go). 413 } 414 415 blocks := []blockData{ 416 {name: "EQ", controls: 1}, 417 {name: "NE", controls: 1}, 418 {name: "LTZ", controls: 1}, // < 0 419 {name: "LEZ", controls: 1}, // <= 0 420 {name: "GTZ", controls: 1}, // > 0 421 {name: "GEZ", controls: 1}, // >= 0 422 {name: "FPT", controls: 1}, // FP flag is true 423 {name: "FPF", controls: 1}, // FP flag is false 424 } 425 426 archs = append(archs, arch{ 427 name: "MIPS", 428 pkg: "cmd/internal/obj/mips", 429 genfile: "../../mips/ssa.go", 430 ops: ops, 431 blocks: blocks, 432 regnames: regNamesMIPS, 433 gpregmask: gp, 434 fpregmask: fp, 435 specialregmask: hi | lo, 436 framepointerreg: -1, // not used 437 linkreg: int8(num["R31"]), 438 }) 439 }