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