github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/compile/internal/mips/ssa.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 mips 6 7 import ( 8 "math" 9 10 "github.com/gagliardetto/golang-go/cmd/compile/internal/gc" 11 "github.com/gagliardetto/golang-go/cmd/compile/internal/logopt" 12 "github.com/gagliardetto/golang-go/cmd/compile/internal/ssa" 13 "github.com/gagliardetto/golang-go/cmd/compile/internal/types" 14 "github.com/gagliardetto/golang-go/cmd/internal/obj" 15 "github.com/gagliardetto/golang-go/cmd/internal/obj/mips" 16 ) 17 18 // isFPreg reports whether r is an FP register 19 func isFPreg(r int16) bool { 20 return mips.REG_F0 <= r && r <= mips.REG_F31 21 } 22 23 // isHILO reports whether r is HI or LO register 24 func isHILO(r int16) bool { 25 return r == mips.REG_HI || r == mips.REG_LO 26 } 27 28 // loadByType returns the load instruction of the given type. 29 func loadByType(t *types.Type, r int16) obj.As { 30 if isFPreg(r) { 31 if t.Size() == 4 { // float32 or int32 32 return mips.AMOVF 33 } else { // float64 or int64 34 return mips.AMOVD 35 } 36 } else { 37 switch t.Size() { 38 case 1: 39 if t.IsSigned() { 40 return mips.AMOVB 41 } else { 42 return mips.AMOVBU 43 } 44 case 2: 45 if t.IsSigned() { 46 return mips.AMOVH 47 } else { 48 return mips.AMOVHU 49 } 50 case 4: 51 return mips.AMOVW 52 } 53 } 54 panic("bad load type") 55 } 56 57 // storeByType returns the store instruction of the given type. 58 func storeByType(t *types.Type, r int16) obj.As { 59 if isFPreg(r) { 60 if t.Size() == 4 { // float32 or int32 61 return mips.AMOVF 62 } else { // float64 or int64 63 return mips.AMOVD 64 } 65 } else { 66 switch t.Size() { 67 case 1: 68 return mips.AMOVB 69 case 2: 70 return mips.AMOVH 71 case 4: 72 return mips.AMOVW 73 } 74 } 75 panic("bad store type") 76 } 77 78 func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { 79 switch v.Op { 80 case ssa.OpCopy, ssa.OpMIPSMOVWreg: 81 t := v.Type 82 if t.IsMemory() { 83 return 84 } 85 x := v.Args[0].Reg() 86 y := v.Reg() 87 if x == y { 88 return 89 } 90 as := mips.AMOVW 91 if isFPreg(x) && isFPreg(y) { 92 as = mips.AMOVF 93 if t.Size() == 8 { 94 as = mips.AMOVD 95 } 96 } 97 98 p := s.Prog(as) 99 p.From.Type = obj.TYPE_REG 100 p.From.Reg = x 101 p.To.Type = obj.TYPE_REG 102 p.To.Reg = y 103 if isHILO(x) && isHILO(y) || isHILO(x) && isFPreg(y) || isFPreg(x) && isHILO(y) { 104 // cannot move between special registers, use TMP as intermediate 105 p.To.Reg = mips.REGTMP 106 p = s.Prog(mips.AMOVW) 107 p.From.Type = obj.TYPE_REG 108 p.From.Reg = mips.REGTMP 109 p.To.Type = obj.TYPE_REG 110 p.To.Reg = y 111 } 112 case ssa.OpMIPSMOVWnop: 113 if v.Reg() != v.Args[0].Reg() { 114 v.Fatalf("input[0] and output not in same register %s", v.LongString()) 115 } 116 // nothing to do 117 case ssa.OpLoadReg: 118 if v.Type.IsFlags() { 119 v.Fatalf("load flags not implemented: %v", v.LongString()) 120 return 121 } 122 r := v.Reg() 123 p := s.Prog(loadByType(v.Type, r)) 124 gc.AddrAuto(&p.From, v.Args[0]) 125 p.To.Type = obj.TYPE_REG 126 p.To.Reg = r 127 if isHILO(r) { 128 // cannot directly load, load to TMP and move 129 p.To.Reg = mips.REGTMP 130 p = s.Prog(mips.AMOVW) 131 p.From.Type = obj.TYPE_REG 132 p.From.Reg = mips.REGTMP 133 p.To.Type = obj.TYPE_REG 134 p.To.Reg = r 135 } 136 case ssa.OpStoreReg: 137 if v.Type.IsFlags() { 138 v.Fatalf("store flags not implemented: %v", v.LongString()) 139 return 140 } 141 r := v.Args[0].Reg() 142 if isHILO(r) { 143 // cannot directly store, move to TMP and store 144 p := s.Prog(mips.AMOVW) 145 p.From.Type = obj.TYPE_REG 146 p.From.Reg = r 147 p.To.Type = obj.TYPE_REG 148 p.To.Reg = mips.REGTMP 149 r = mips.REGTMP 150 } 151 p := s.Prog(storeByType(v.Type, r)) 152 p.From.Type = obj.TYPE_REG 153 p.From.Reg = r 154 gc.AddrAuto(&p.To, v) 155 case ssa.OpMIPSADD, 156 ssa.OpMIPSSUB, 157 ssa.OpMIPSAND, 158 ssa.OpMIPSOR, 159 ssa.OpMIPSXOR, 160 ssa.OpMIPSNOR, 161 ssa.OpMIPSSLL, 162 ssa.OpMIPSSRL, 163 ssa.OpMIPSSRA, 164 ssa.OpMIPSADDF, 165 ssa.OpMIPSADDD, 166 ssa.OpMIPSSUBF, 167 ssa.OpMIPSSUBD, 168 ssa.OpMIPSMULF, 169 ssa.OpMIPSMULD, 170 ssa.OpMIPSDIVF, 171 ssa.OpMIPSDIVD, 172 ssa.OpMIPSMUL: 173 p := s.Prog(v.Op.Asm()) 174 p.From.Type = obj.TYPE_REG 175 p.From.Reg = v.Args[1].Reg() 176 p.Reg = v.Args[0].Reg() 177 p.To.Type = obj.TYPE_REG 178 p.To.Reg = v.Reg() 179 case ssa.OpMIPSSGT, 180 ssa.OpMIPSSGTU: 181 p := s.Prog(v.Op.Asm()) 182 p.From.Type = obj.TYPE_REG 183 p.From.Reg = v.Args[0].Reg() 184 p.Reg = v.Args[1].Reg() 185 p.To.Type = obj.TYPE_REG 186 p.To.Reg = v.Reg() 187 case ssa.OpMIPSSGTzero, 188 ssa.OpMIPSSGTUzero: 189 p := s.Prog(v.Op.Asm()) 190 p.From.Type = obj.TYPE_REG 191 p.From.Reg = v.Args[0].Reg() 192 p.Reg = mips.REGZERO 193 p.To.Type = obj.TYPE_REG 194 p.To.Reg = v.Reg() 195 case ssa.OpMIPSADDconst, 196 ssa.OpMIPSSUBconst, 197 ssa.OpMIPSANDconst, 198 ssa.OpMIPSORconst, 199 ssa.OpMIPSXORconst, 200 ssa.OpMIPSNORconst, 201 ssa.OpMIPSSLLconst, 202 ssa.OpMIPSSRLconst, 203 ssa.OpMIPSSRAconst, 204 ssa.OpMIPSSGTconst, 205 ssa.OpMIPSSGTUconst: 206 p := s.Prog(v.Op.Asm()) 207 p.From.Type = obj.TYPE_CONST 208 p.From.Offset = v.AuxInt 209 p.Reg = v.Args[0].Reg() 210 p.To.Type = obj.TYPE_REG 211 p.To.Reg = v.Reg() 212 case ssa.OpMIPSMULT, 213 ssa.OpMIPSMULTU, 214 ssa.OpMIPSDIV, 215 ssa.OpMIPSDIVU: 216 // result in hi,lo 217 p := s.Prog(v.Op.Asm()) 218 p.From.Type = obj.TYPE_REG 219 p.From.Reg = v.Args[1].Reg() 220 p.Reg = v.Args[0].Reg() 221 case ssa.OpMIPSMOVWconst: 222 r := v.Reg() 223 p := s.Prog(v.Op.Asm()) 224 p.From.Type = obj.TYPE_CONST 225 p.From.Offset = v.AuxInt 226 p.To.Type = obj.TYPE_REG 227 p.To.Reg = r 228 if isFPreg(r) || isHILO(r) { 229 // cannot move into FP or special registers, use TMP as intermediate 230 p.To.Reg = mips.REGTMP 231 p = s.Prog(mips.AMOVW) 232 p.From.Type = obj.TYPE_REG 233 p.From.Reg = mips.REGTMP 234 p.To.Type = obj.TYPE_REG 235 p.To.Reg = r 236 } 237 case ssa.OpMIPSMOVFconst, 238 ssa.OpMIPSMOVDconst: 239 p := s.Prog(v.Op.Asm()) 240 p.From.Type = obj.TYPE_FCONST 241 p.From.Val = math.Float64frombits(uint64(v.AuxInt)) 242 p.To.Type = obj.TYPE_REG 243 p.To.Reg = v.Reg() 244 case ssa.OpMIPSCMOVZ: 245 if v.Reg() != v.Args[0].Reg() { 246 v.Fatalf("input[0] and output not in same register %s", v.LongString()) 247 } 248 p := s.Prog(v.Op.Asm()) 249 p.From.Type = obj.TYPE_REG 250 p.From.Reg = v.Args[2].Reg() 251 p.Reg = v.Args[1].Reg() 252 p.To.Type = obj.TYPE_REG 253 p.To.Reg = v.Reg() 254 case ssa.OpMIPSCMOVZzero: 255 if v.Reg() != v.Args[0].Reg() { 256 v.Fatalf("input[0] and output not in same register %s", v.LongString()) 257 } 258 p := s.Prog(v.Op.Asm()) 259 p.From.Type = obj.TYPE_REG 260 p.From.Reg = v.Args[1].Reg() 261 p.Reg = mips.REGZERO 262 p.To.Type = obj.TYPE_REG 263 p.To.Reg = v.Reg() 264 case ssa.OpMIPSCMPEQF, 265 ssa.OpMIPSCMPEQD, 266 ssa.OpMIPSCMPGEF, 267 ssa.OpMIPSCMPGED, 268 ssa.OpMIPSCMPGTF, 269 ssa.OpMIPSCMPGTD: 270 p := s.Prog(v.Op.Asm()) 271 p.From.Type = obj.TYPE_REG 272 p.From.Reg = v.Args[0].Reg() 273 p.Reg = v.Args[1].Reg() 274 case ssa.OpMIPSMOVWaddr: 275 p := s.Prog(mips.AMOVW) 276 p.From.Type = obj.TYPE_ADDR 277 p.From.Reg = v.Args[0].Reg() 278 var wantreg string 279 // MOVW $sym+off(base), R 280 // the assembler expands it as the following: 281 // - base is SP: add constant offset to SP (R29) 282 // when constant is large, tmp register (R23) may be used 283 // - base is SB: load external address with relocation 284 switch v.Aux.(type) { 285 default: 286 v.Fatalf("aux is of unknown type %T", v.Aux) 287 case *obj.LSym: 288 wantreg = "SB" 289 gc.AddAux(&p.From, v) 290 case *gc.Node: 291 wantreg = "SP" 292 gc.AddAux(&p.From, v) 293 case nil: 294 // No sym, just MOVW $off(SP), R 295 wantreg = "SP" 296 p.From.Offset = v.AuxInt 297 } 298 if reg := v.Args[0].RegName(); reg != wantreg { 299 v.Fatalf("bad reg %s for symbol type %T, want %s", reg, v.Aux, wantreg) 300 } 301 p.To.Type = obj.TYPE_REG 302 p.To.Reg = v.Reg() 303 case ssa.OpMIPSMOVBload, 304 ssa.OpMIPSMOVBUload, 305 ssa.OpMIPSMOVHload, 306 ssa.OpMIPSMOVHUload, 307 ssa.OpMIPSMOVWload, 308 ssa.OpMIPSMOVFload, 309 ssa.OpMIPSMOVDload: 310 p := s.Prog(v.Op.Asm()) 311 p.From.Type = obj.TYPE_MEM 312 p.From.Reg = v.Args[0].Reg() 313 gc.AddAux(&p.From, v) 314 p.To.Type = obj.TYPE_REG 315 p.To.Reg = v.Reg() 316 case ssa.OpMIPSMOVBstore, 317 ssa.OpMIPSMOVHstore, 318 ssa.OpMIPSMOVWstore, 319 ssa.OpMIPSMOVFstore, 320 ssa.OpMIPSMOVDstore: 321 p := s.Prog(v.Op.Asm()) 322 p.From.Type = obj.TYPE_REG 323 p.From.Reg = v.Args[1].Reg() 324 p.To.Type = obj.TYPE_MEM 325 p.To.Reg = v.Args[0].Reg() 326 gc.AddAux(&p.To, v) 327 case ssa.OpMIPSMOVBstorezero, 328 ssa.OpMIPSMOVHstorezero, 329 ssa.OpMIPSMOVWstorezero: 330 p := s.Prog(v.Op.Asm()) 331 p.From.Type = obj.TYPE_REG 332 p.From.Reg = mips.REGZERO 333 p.To.Type = obj.TYPE_MEM 334 p.To.Reg = v.Args[0].Reg() 335 gc.AddAux(&p.To, v) 336 case ssa.OpMIPSMOVBreg, 337 ssa.OpMIPSMOVBUreg, 338 ssa.OpMIPSMOVHreg, 339 ssa.OpMIPSMOVHUreg: 340 a := v.Args[0] 341 for a.Op == ssa.OpCopy || a.Op == ssa.OpMIPSMOVWreg || a.Op == ssa.OpMIPSMOVWnop { 342 a = a.Args[0] 343 } 344 if a.Op == ssa.OpLoadReg { 345 t := a.Type 346 switch { 347 case v.Op == ssa.OpMIPSMOVBreg && t.Size() == 1 && t.IsSigned(), 348 v.Op == ssa.OpMIPSMOVBUreg && t.Size() == 1 && !t.IsSigned(), 349 v.Op == ssa.OpMIPSMOVHreg && t.Size() == 2 && t.IsSigned(), 350 v.Op == ssa.OpMIPSMOVHUreg && t.Size() == 2 && !t.IsSigned(): 351 // arg is a proper-typed load, already zero/sign-extended, don't extend again 352 if v.Reg() == v.Args[0].Reg() { 353 return 354 } 355 p := s.Prog(mips.AMOVW) 356 p.From.Type = obj.TYPE_REG 357 p.From.Reg = v.Args[0].Reg() 358 p.To.Type = obj.TYPE_REG 359 p.To.Reg = v.Reg() 360 return 361 default: 362 } 363 } 364 fallthrough 365 case ssa.OpMIPSMOVWF, 366 ssa.OpMIPSMOVWD, 367 ssa.OpMIPSTRUNCFW, 368 ssa.OpMIPSTRUNCDW, 369 ssa.OpMIPSMOVFD, 370 ssa.OpMIPSMOVDF, 371 ssa.OpMIPSNEGF, 372 ssa.OpMIPSNEGD, 373 ssa.OpMIPSSQRTD, 374 ssa.OpMIPSCLZ: 375 p := s.Prog(v.Op.Asm()) 376 p.From.Type = obj.TYPE_REG 377 p.From.Reg = v.Args[0].Reg() 378 p.To.Type = obj.TYPE_REG 379 p.To.Reg = v.Reg() 380 case ssa.OpMIPSNEG: 381 // SUB from REGZERO 382 p := s.Prog(mips.ASUBU) 383 p.From.Type = obj.TYPE_REG 384 p.From.Reg = v.Args[0].Reg() 385 p.Reg = mips.REGZERO 386 p.To.Type = obj.TYPE_REG 387 p.To.Reg = v.Reg() 388 case ssa.OpMIPSLoweredZero: 389 // SUBU $4, R1 390 // MOVW R0, 4(R1) 391 // ADDU $4, R1 392 // BNE Rarg1, R1, -2(PC) 393 // arg1 is the address of the last element to zero 394 var sz int64 395 var mov obj.As 396 switch { 397 case v.AuxInt%4 == 0: 398 sz = 4 399 mov = mips.AMOVW 400 case v.AuxInt%2 == 0: 401 sz = 2 402 mov = mips.AMOVH 403 default: 404 sz = 1 405 mov = mips.AMOVB 406 } 407 p := s.Prog(mips.ASUBU) 408 p.From.Type = obj.TYPE_CONST 409 p.From.Offset = sz 410 p.To.Type = obj.TYPE_REG 411 p.To.Reg = mips.REG_R1 412 p2 := s.Prog(mov) 413 p2.From.Type = obj.TYPE_REG 414 p2.From.Reg = mips.REGZERO 415 p2.To.Type = obj.TYPE_MEM 416 p2.To.Reg = mips.REG_R1 417 p2.To.Offset = sz 418 p3 := s.Prog(mips.AADDU) 419 p3.From.Type = obj.TYPE_CONST 420 p3.From.Offset = sz 421 p3.To.Type = obj.TYPE_REG 422 p3.To.Reg = mips.REG_R1 423 p4 := s.Prog(mips.ABNE) 424 p4.From.Type = obj.TYPE_REG 425 p4.From.Reg = v.Args[1].Reg() 426 p4.Reg = mips.REG_R1 427 p4.To.Type = obj.TYPE_BRANCH 428 gc.Patch(p4, p2) 429 case ssa.OpMIPSLoweredMove: 430 // SUBU $4, R1 431 // MOVW 4(R1), Rtmp 432 // MOVW Rtmp, (R2) 433 // ADDU $4, R1 434 // ADDU $4, R2 435 // BNE Rarg2, R1, -4(PC) 436 // arg2 is the address of the last element of src 437 var sz int64 438 var mov obj.As 439 switch { 440 case v.AuxInt%4 == 0: 441 sz = 4 442 mov = mips.AMOVW 443 case v.AuxInt%2 == 0: 444 sz = 2 445 mov = mips.AMOVH 446 default: 447 sz = 1 448 mov = mips.AMOVB 449 } 450 p := s.Prog(mips.ASUBU) 451 p.From.Type = obj.TYPE_CONST 452 p.From.Offset = sz 453 p.To.Type = obj.TYPE_REG 454 p.To.Reg = mips.REG_R1 455 p2 := s.Prog(mov) 456 p2.From.Type = obj.TYPE_MEM 457 p2.From.Reg = mips.REG_R1 458 p2.From.Offset = sz 459 p2.To.Type = obj.TYPE_REG 460 p2.To.Reg = mips.REGTMP 461 p3 := s.Prog(mov) 462 p3.From.Type = obj.TYPE_REG 463 p3.From.Reg = mips.REGTMP 464 p3.To.Type = obj.TYPE_MEM 465 p3.To.Reg = mips.REG_R2 466 p4 := s.Prog(mips.AADDU) 467 p4.From.Type = obj.TYPE_CONST 468 p4.From.Offset = sz 469 p4.To.Type = obj.TYPE_REG 470 p4.To.Reg = mips.REG_R1 471 p5 := s.Prog(mips.AADDU) 472 p5.From.Type = obj.TYPE_CONST 473 p5.From.Offset = sz 474 p5.To.Type = obj.TYPE_REG 475 p5.To.Reg = mips.REG_R2 476 p6 := s.Prog(mips.ABNE) 477 p6.From.Type = obj.TYPE_REG 478 p6.From.Reg = v.Args[2].Reg() 479 p6.Reg = mips.REG_R1 480 p6.To.Type = obj.TYPE_BRANCH 481 gc.Patch(p6, p2) 482 case ssa.OpMIPSCALLstatic, ssa.OpMIPSCALLclosure, ssa.OpMIPSCALLinter: 483 s.Call(v) 484 case ssa.OpMIPSLoweredWB: 485 p := s.Prog(obj.ACALL) 486 p.To.Type = obj.TYPE_MEM 487 p.To.Name = obj.NAME_EXTERN 488 p.To.Sym = v.Aux.(*obj.LSym) 489 case ssa.OpMIPSLoweredPanicBoundsA, ssa.OpMIPSLoweredPanicBoundsB, ssa.OpMIPSLoweredPanicBoundsC: 490 p := s.Prog(obj.ACALL) 491 p.To.Type = obj.TYPE_MEM 492 p.To.Name = obj.NAME_EXTERN 493 p.To.Sym = gc.BoundsCheckFunc[v.AuxInt] 494 s.UseArgs(8) // space used in callee args area by assembly stubs 495 case ssa.OpMIPSLoweredPanicExtendA, ssa.OpMIPSLoweredPanicExtendB, ssa.OpMIPSLoweredPanicExtendC: 496 p := s.Prog(obj.ACALL) 497 p.To.Type = obj.TYPE_MEM 498 p.To.Name = obj.NAME_EXTERN 499 p.To.Sym = gc.ExtendCheckFunc[v.AuxInt] 500 s.UseArgs(12) // space used in callee args area by assembly stubs 501 case ssa.OpMIPSLoweredAtomicLoad8, 502 ssa.OpMIPSLoweredAtomicLoad32: 503 s.Prog(mips.ASYNC) 504 505 var op obj.As 506 switch v.Op { 507 case ssa.OpMIPSLoweredAtomicLoad8: 508 op = mips.AMOVB 509 case ssa.OpMIPSLoweredAtomicLoad32: 510 op = mips.AMOVW 511 } 512 p := s.Prog(op) 513 p.From.Type = obj.TYPE_MEM 514 p.From.Reg = v.Args[0].Reg() 515 p.To.Type = obj.TYPE_REG 516 p.To.Reg = v.Reg0() 517 518 s.Prog(mips.ASYNC) 519 case ssa.OpMIPSLoweredAtomicStore8, 520 ssa.OpMIPSLoweredAtomicStore32: 521 s.Prog(mips.ASYNC) 522 523 var op obj.As 524 switch v.Op { 525 case ssa.OpMIPSLoweredAtomicStore8: 526 op = mips.AMOVB 527 case ssa.OpMIPSLoweredAtomicStore32: 528 op = mips.AMOVW 529 } 530 p := s.Prog(op) 531 p.From.Type = obj.TYPE_REG 532 p.From.Reg = v.Args[1].Reg() 533 p.To.Type = obj.TYPE_MEM 534 p.To.Reg = v.Args[0].Reg() 535 536 s.Prog(mips.ASYNC) 537 case ssa.OpMIPSLoweredAtomicStorezero: 538 s.Prog(mips.ASYNC) 539 540 p := s.Prog(mips.AMOVW) 541 p.From.Type = obj.TYPE_REG 542 p.From.Reg = mips.REGZERO 543 p.To.Type = obj.TYPE_MEM 544 p.To.Reg = v.Args[0].Reg() 545 546 s.Prog(mips.ASYNC) 547 case ssa.OpMIPSLoweredAtomicExchange: 548 // SYNC 549 // MOVW Rarg1, Rtmp 550 // LL (Rarg0), Rout 551 // SC Rtmp, (Rarg0) 552 // BEQ Rtmp, -3(PC) 553 // SYNC 554 s.Prog(mips.ASYNC) 555 556 p := s.Prog(mips.AMOVW) 557 p.From.Type = obj.TYPE_REG 558 p.From.Reg = v.Args[1].Reg() 559 p.To.Type = obj.TYPE_REG 560 p.To.Reg = mips.REGTMP 561 562 p1 := s.Prog(mips.ALL) 563 p1.From.Type = obj.TYPE_MEM 564 p1.From.Reg = v.Args[0].Reg() 565 p1.To.Type = obj.TYPE_REG 566 p1.To.Reg = v.Reg0() 567 568 p2 := s.Prog(mips.ASC) 569 p2.From.Type = obj.TYPE_REG 570 p2.From.Reg = mips.REGTMP 571 p2.To.Type = obj.TYPE_MEM 572 p2.To.Reg = v.Args[0].Reg() 573 574 p3 := s.Prog(mips.ABEQ) 575 p3.From.Type = obj.TYPE_REG 576 p3.From.Reg = mips.REGTMP 577 p3.To.Type = obj.TYPE_BRANCH 578 gc.Patch(p3, p) 579 580 s.Prog(mips.ASYNC) 581 case ssa.OpMIPSLoweredAtomicAdd: 582 // SYNC 583 // LL (Rarg0), Rout 584 // ADDU Rarg1, Rout, Rtmp 585 // SC Rtmp, (Rarg0) 586 // BEQ Rtmp, -3(PC) 587 // SYNC 588 // ADDU Rarg1, Rout 589 s.Prog(mips.ASYNC) 590 591 p := s.Prog(mips.ALL) 592 p.From.Type = obj.TYPE_MEM 593 p.From.Reg = v.Args[0].Reg() 594 p.To.Type = obj.TYPE_REG 595 p.To.Reg = v.Reg0() 596 597 p1 := s.Prog(mips.AADDU) 598 p1.From.Type = obj.TYPE_REG 599 p1.From.Reg = v.Args[1].Reg() 600 p1.Reg = v.Reg0() 601 p1.To.Type = obj.TYPE_REG 602 p1.To.Reg = mips.REGTMP 603 604 p2 := s.Prog(mips.ASC) 605 p2.From.Type = obj.TYPE_REG 606 p2.From.Reg = mips.REGTMP 607 p2.To.Type = obj.TYPE_MEM 608 p2.To.Reg = v.Args[0].Reg() 609 610 p3 := s.Prog(mips.ABEQ) 611 p3.From.Type = obj.TYPE_REG 612 p3.From.Reg = mips.REGTMP 613 p3.To.Type = obj.TYPE_BRANCH 614 gc.Patch(p3, p) 615 616 s.Prog(mips.ASYNC) 617 618 p4 := s.Prog(mips.AADDU) 619 p4.From.Type = obj.TYPE_REG 620 p4.From.Reg = v.Args[1].Reg() 621 p4.Reg = v.Reg0() 622 p4.To.Type = obj.TYPE_REG 623 p4.To.Reg = v.Reg0() 624 625 case ssa.OpMIPSLoweredAtomicAddconst: 626 // SYNC 627 // LL (Rarg0), Rout 628 // ADDU $auxInt, Rout, Rtmp 629 // SC Rtmp, (Rarg0) 630 // BEQ Rtmp, -3(PC) 631 // SYNC 632 // ADDU $auxInt, Rout 633 s.Prog(mips.ASYNC) 634 635 p := s.Prog(mips.ALL) 636 p.From.Type = obj.TYPE_MEM 637 p.From.Reg = v.Args[0].Reg() 638 p.To.Type = obj.TYPE_REG 639 p.To.Reg = v.Reg0() 640 641 p1 := s.Prog(mips.AADDU) 642 p1.From.Type = obj.TYPE_CONST 643 p1.From.Offset = v.AuxInt 644 p1.Reg = v.Reg0() 645 p1.To.Type = obj.TYPE_REG 646 p1.To.Reg = mips.REGTMP 647 648 p2 := s.Prog(mips.ASC) 649 p2.From.Type = obj.TYPE_REG 650 p2.From.Reg = mips.REGTMP 651 p2.To.Type = obj.TYPE_MEM 652 p2.To.Reg = v.Args[0].Reg() 653 654 p3 := s.Prog(mips.ABEQ) 655 p3.From.Type = obj.TYPE_REG 656 p3.From.Reg = mips.REGTMP 657 p3.To.Type = obj.TYPE_BRANCH 658 gc.Patch(p3, p) 659 660 s.Prog(mips.ASYNC) 661 662 p4 := s.Prog(mips.AADDU) 663 p4.From.Type = obj.TYPE_CONST 664 p4.From.Offset = v.AuxInt 665 p4.Reg = v.Reg0() 666 p4.To.Type = obj.TYPE_REG 667 p4.To.Reg = v.Reg0() 668 669 case ssa.OpMIPSLoweredAtomicAnd, 670 ssa.OpMIPSLoweredAtomicOr: 671 // SYNC 672 // LL (Rarg0), Rtmp 673 // AND/OR Rarg1, Rtmp 674 // SC Rtmp, (Rarg0) 675 // BEQ Rtmp, -3(PC) 676 // SYNC 677 s.Prog(mips.ASYNC) 678 679 p := s.Prog(mips.ALL) 680 p.From.Type = obj.TYPE_MEM 681 p.From.Reg = v.Args[0].Reg() 682 p.To.Type = obj.TYPE_REG 683 p.To.Reg = mips.REGTMP 684 685 p1 := s.Prog(v.Op.Asm()) 686 p1.From.Type = obj.TYPE_REG 687 p1.From.Reg = v.Args[1].Reg() 688 p1.Reg = mips.REGTMP 689 p1.To.Type = obj.TYPE_REG 690 p1.To.Reg = mips.REGTMP 691 692 p2 := s.Prog(mips.ASC) 693 p2.From.Type = obj.TYPE_REG 694 p2.From.Reg = mips.REGTMP 695 p2.To.Type = obj.TYPE_MEM 696 p2.To.Reg = v.Args[0].Reg() 697 698 p3 := s.Prog(mips.ABEQ) 699 p3.From.Type = obj.TYPE_REG 700 p3.From.Reg = mips.REGTMP 701 p3.To.Type = obj.TYPE_BRANCH 702 gc.Patch(p3, p) 703 704 s.Prog(mips.ASYNC) 705 706 case ssa.OpMIPSLoweredAtomicCas: 707 // MOVW $0, Rout 708 // SYNC 709 // LL (Rarg0), Rtmp 710 // BNE Rtmp, Rarg1, 4(PC) 711 // MOVW Rarg2, Rout 712 // SC Rout, (Rarg0) 713 // BEQ Rout, -4(PC) 714 // SYNC 715 p := s.Prog(mips.AMOVW) 716 p.From.Type = obj.TYPE_REG 717 p.From.Reg = mips.REGZERO 718 p.To.Type = obj.TYPE_REG 719 p.To.Reg = v.Reg0() 720 721 s.Prog(mips.ASYNC) 722 723 p1 := s.Prog(mips.ALL) 724 p1.From.Type = obj.TYPE_MEM 725 p1.From.Reg = v.Args[0].Reg() 726 p1.To.Type = obj.TYPE_REG 727 p1.To.Reg = mips.REGTMP 728 729 p2 := s.Prog(mips.ABNE) 730 p2.From.Type = obj.TYPE_REG 731 p2.From.Reg = v.Args[1].Reg() 732 p2.Reg = mips.REGTMP 733 p2.To.Type = obj.TYPE_BRANCH 734 735 p3 := s.Prog(mips.AMOVW) 736 p3.From.Type = obj.TYPE_REG 737 p3.From.Reg = v.Args[2].Reg() 738 p3.To.Type = obj.TYPE_REG 739 p3.To.Reg = v.Reg0() 740 741 p4 := s.Prog(mips.ASC) 742 p4.From.Type = obj.TYPE_REG 743 p4.From.Reg = v.Reg0() 744 p4.To.Type = obj.TYPE_MEM 745 p4.To.Reg = v.Args[0].Reg() 746 747 p5 := s.Prog(mips.ABEQ) 748 p5.From.Type = obj.TYPE_REG 749 p5.From.Reg = v.Reg0() 750 p5.To.Type = obj.TYPE_BRANCH 751 gc.Patch(p5, p1) 752 753 s.Prog(mips.ASYNC) 754 755 p6 := s.Prog(obj.ANOP) 756 gc.Patch(p2, p6) 757 758 case ssa.OpMIPSLoweredNilCheck: 759 // Issue a load which will fault if arg is nil. 760 p := s.Prog(mips.AMOVB) 761 p.From.Type = obj.TYPE_MEM 762 p.From.Reg = v.Args[0].Reg() 763 gc.AddAux(&p.From, v) 764 p.To.Type = obj.TYPE_REG 765 p.To.Reg = mips.REGTMP 766 if logopt.Enabled() { 767 logopt.LogOpt(v.Pos, "nilcheck", "genssa", v.Block.Func.Name) 768 } 769 if gc.Debug_checknil != 0 && v.Pos.Line() > 1 { // v.Pos.Line()==1 in generated wrappers 770 gc.Warnl(v.Pos, "generated nil check") 771 } 772 case ssa.OpMIPSFPFlagTrue, 773 ssa.OpMIPSFPFlagFalse: 774 // MOVW $1, r 775 // CMOVF R0, r 776 777 cmov := mips.ACMOVF 778 if v.Op == ssa.OpMIPSFPFlagFalse { 779 cmov = mips.ACMOVT 780 } 781 p := s.Prog(mips.AMOVW) 782 p.From.Type = obj.TYPE_CONST 783 p.From.Offset = 1 784 p.To.Type = obj.TYPE_REG 785 p.To.Reg = v.Reg() 786 p1 := s.Prog(cmov) 787 p1.From.Type = obj.TYPE_REG 788 p1.From.Reg = mips.REGZERO 789 p1.To.Type = obj.TYPE_REG 790 p1.To.Reg = v.Reg() 791 792 case ssa.OpMIPSLoweredGetClosurePtr: 793 // Closure pointer is R22 (mips.REGCTXT). 794 gc.CheckLoweredGetClosurePtr(v) 795 case ssa.OpMIPSLoweredGetCallerSP: 796 // caller's SP is FixedFrameSize below the address of the first arg 797 p := s.Prog(mips.AMOVW) 798 p.From.Type = obj.TYPE_ADDR 799 p.From.Offset = -gc.Ctxt.FixedFrameSize() 800 p.From.Name = obj.NAME_PARAM 801 p.To.Type = obj.TYPE_REG 802 p.To.Reg = v.Reg() 803 case ssa.OpMIPSLoweredGetCallerPC: 804 p := s.Prog(obj.AGETCALLERPC) 805 p.To.Type = obj.TYPE_REG 806 p.To.Reg = v.Reg() 807 case ssa.OpClobber: 808 // TODO: implement for clobberdead experiment. Nop is ok for now. 809 default: 810 v.Fatalf("genValue not implemented: %s", v.LongString()) 811 } 812 } 813 814 var blockJump = map[ssa.BlockKind]struct { 815 asm, invasm obj.As 816 }{ 817 ssa.BlockMIPSEQ: {mips.ABEQ, mips.ABNE}, 818 ssa.BlockMIPSNE: {mips.ABNE, mips.ABEQ}, 819 ssa.BlockMIPSLTZ: {mips.ABLTZ, mips.ABGEZ}, 820 ssa.BlockMIPSGEZ: {mips.ABGEZ, mips.ABLTZ}, 821 ssa.BlockMIPSLEZ: {mips.ABLEZ, mips.ABGTZ}, 822 ssa.BlockMIPSGTZ: {mips.ABGTZ, mips.ABLEZ}, 823 ssa.BlockMIPSFPT: {mips.ABFPT, mips.ABFPF}, 824 ssa.BlockMIPSFPF: {mips.ABFPF, mips.ABFPT}, 825 } 826 827 func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) { 828 switch b.Kind { 829 case ssa.BlockPlain: 830 if b.Succs[0].Block() != next { 831 p := s.Prog(obj.AJMP) 832 p.To.Type = obj.TYPE_BRANCH 833 s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()}) 834 } 835 case ssa.BlockDefer: 836 // defer returns in R1: 837 // 0 if we should continue executing 838 // 1 if we should jump to deferreturn call 839 p := s.Prog(mips.ABNE) 840 p.From.Type = obj.TYPE_REG 841 p.From.Reg = mips.REGZERO 842 p.Reg = mips.REG_R1 843 p.To.Type = obj.TYPE_BRANCH 844 s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()}) 845 if b.Succs[0].Block() != next { 846 p := s.Prog(obj.AJMP) 847 p.To.Type = obj.TYPE_BRANCH 848 s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()}) 849 } 850 case ssa.BlockExit: 851 case ssa.BlockRet: 852 s.Prog(obj.ARET) 853 case ssa.BlockRetJmp: 854 p := s.Prog(obj.ARET) 855 p.To.Type = obj.TYPE_MEM 856 p.To.Name = obj.NAME_EXTERN 857 p.To.Sym = b.Aux.(*obj.LSym) 858 case ssa.BlockMIPSEQ, ssa.BlockMIPSNE, 859 ssa.BlockMIPSLTZ, ssa.BlockMIPSGEZ, 860 ssa.BlockMIPSLEZ, ssa.BlockMIPSGTZ, 861 ssa.BlockMIPSFPT, ssa.BlockMIPSFPF: 862 jmp := blockJump[b.Kind] 863 var p *obj.Prog 864 switch next { 865 case b.Succs[0].Block(): 866 p = s.Br(jmp.invasm, b.Succs[1].Block()) 867 case b.Succs[1].Block(): 868 p = s.Br(jmp.asm, b.Succs[0].Block()) 869 default: 870 if b.Likely != ssa.BranchUnlikely { 871 p = s.Br(jmp.asm, b.Succs[0].Block()) 872 s.Br(obj.AJMP, b.Succs[1].Block()) 873 } else { 874 p = s.Br(jmp.invasm, b.Succs[1].Block()) 875 s.Br(obj.AJMP, b.Succs[0].Block()) 876 } 877 } 878 if !b.Controls[0].Type.IsFlags() { 879 p.From.Type = obj.TYPE_REG 880 p.From.Reg = b.Controls[0].Reg() 881 } 882 default: 883 b.Fatalf("branch not implemented: %s", b.LongString()) 884 } 885 }