github.com/bir3/gocompiler@v0.9.2202/src/cmd/compile/internal/mips64/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 mips64 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 if t.IsSigned() { 54 return mips.AMOVW 55 } else { 56 return mips.AMOVWU 57 } 58 case 8: 59 return mips.AMOVV 60 } 61 } 62 panic("bad load type") 63 } 64 65 // storeByType returns the store instruction of the given type. 66 func storeByType(t *types.Type, r int16) obj.As { 67 if isFPreg(r) { 68 if t.Size() == 4 { // float32 or int32 69 return mips.AMOVF 70 } else { // float64 or int64 71 return mips.AMOVD 72 } 73 } else { 74 switch t.Size() { 75 case 1: 76 return mips.AMOVB 77 case 2: 78 return mips.AMOVH 79 case 4: 80 return mips.AMOVW 81 case 8: 82 return mips.AMOVV 83 } 84 } 85 panic("bad store type") 86 } 87 88 func ssaGenValue(s *ssagen.State, v *ssa.Value) { 89 switch v.Op { 90 case ssa.OpCopy, ssa.OpMIPS64MOVVreg: 91 if v.Type.IsMemory() { 92 return 93 } 94 x := v.Args[0].Reg() 95 y := v.Reg() 96 if x == y { 97 return 98 } 99 as := mips.AMOVV 100 if isFPreg(x) && isFPreg(y) { 101 as = mips.AMOVD 102 } 103 p := s.Prog(as) 104 p.From.Type = obj.TYPE_REG 105 p.From.Reg = x 106 p.To.Type = obj.TYPE_REG 107 p.To.Reg = y 108 if isHILO(x) && isHILO(y) || isHILO(x) && isFPreg(y) || isFPreg(x) && isHILO(y) { 109 // cannot move between special registers, use TMP as intermediate 110 p.To.Reg = mips.REGTMP 111 p = s.Prog(mips.AMOVV) 112 p.From.Type = obj.TYPE_REG 113 p.From.Reg = mips.REGTMP 114 p.To.Type = obj.TYPE_REG 115 p.To.Reg = y 116 } 117 case ssa.OpMIPS64MOVVnop: 118 // nothing to do 119 case ssa.OpLoadReg: 120 if v.Type.IsFlags() { 121 v.Fatalf("load flags not implemented: %v", v.LongString()) 122 return 123 } 124 r := v.Reg() 125 p := s.Prog(loadByType(v.Type, r)) 126 ssagen.AddrAuto(&p.From, v.Args[0]) 127 p.To.Type = obj.TYPE_REG 128 p.To.Reg = r 129 if isHILO(r) { 130 // cannot directly load, load to TMP and move 131 p.To.Reg = mips.REGTMP 132 p = s.Prog(mips.AMOVV) 133 p.From.Type = obj.TYPE_REG 134 p.From.Reg = mips.REGTMP 135 p.To.Type = obj.TYPE_REG 136 p.To.Reg = r 137 } 138 case ssa.OpStoreReg: 139 if v.Type.IsFlags() { 140 v.Fatalf("store flags not implemented: %v", v.LongString()) 141 return 142 } 143 r := v.Args[0].Reg() 144 if isHILO(r) { 145 // cannot directly store, move to TMP and store 146 p := s.Prog(mips.AMOVV) 147 p.From.Type = obj.TYPE_REG 148 p.From.Reg = r 149 p.To.Type = obj.TYPE_REG 150 p.To.Reg = mips.REGTMP 151 r = mips.REGTMP 152 } 153 p := s.Prog(storeByType(v.Type, r)) 154 p.From.Type = obj.TYPE_REG 155 p.From.Reg = r 156 ssagen.AddrAuto(&p.To, v) 157 case ssa.OpMIPS64ADDV, 158 ssa.OpMIPS64SUBV, 159 ssa.OpMIPS64AND, 160 ssa.OpMIPS64OR, 161 ssa.OpMIPS64XOR, 162 ssa.OpMIPS64NOR, 163 ssa.OpMIPS64SLLV, 164 ssa.OpMIPS64SRLV, 165 ssa.OpMIPS64SRAV, 166 ssa.OpMIPS64ADDF, 167 ssa.OpMIPS64ADDD, 168 ssa.OpMIPS64SUBF, 169 ssa.OpMIPS64SUBD, 170 ssa.OpMIPS64MULF, 171 ssa.OpMIPS64MULD, 172 ssa.OpMIPS64DIVF, 173 ssa.OpMIPS64DIVD: 174 p := s.Prog(v.Op.Asm()) 175 p.From.Type = obj.TYPE_REG 176 p.From.Reg = v.Args[1].Reg() 177 p.Reg = v.Args[0].Reg() 178 p.To.Type = obj.TYPE_REG 179 p.To.Reg = v.Reg() 180 case ssa.OpMIPS64SGT, 181 ssa.OpMIPS64SGTU: 182 p := s.Prog(v.Op.Asm()) 183 p.From.Type = obj.TYPE_REG 184 p.From.Reg = v.Args[0].Reg() 185 p.Reg = v.Args[1].Reg() 186 p.To.Type = obj.TYPE_REG 187 p.To.Reg = v.Reg() 188 case ssa.OpMIPS64ADDVconst, 189 ssa.OpMIPS64SUBVconst, 190 ssa.OpMIPS64ANDconst, 191 ssa.OpMIPS64ORconst, 192 ssa.OpMIPS64XORconst, 193 ssa.OpMIPS64NORconst, 194 ssa.OpMIPS64SLLVconst, 195 ssa.OpMIPS64SRLVconst, 196 ssa.OpMIPS64SRAVconst, 197 ssa.OpMIPS64SGTconst, 198 ssa.OpMIPS64SGTUconst: 199 p := s.Prog(v.Op.Asm()) 200 p.From.Type = obj.TYPE_CONST 201 p.From.Offset = v.AuxInt 202 p.Reg = v.Args[0].Reg() 203 p.To.Type = obj.TYPE_REG 204 p.To.Reg = v.Reg() 205 case ssa.OpMIPS64MULV, 206 ssa.OpMIPS64MULVU, 207 ssa.OpMIPS64DIVV, 208 ssa.OpMIPS64DIVVU: 209 // result in hi,lo 210 p := s.Prog(v.Op.Asm()) 211 p.From.Type = obj.TYPE_REG 212 p.From.Reg = v.Args[1].Reg() 213 p.Reg = v.Args[0].Reg() 214 case ssa.OpMIPS64MOVVconst: 215 r := v.Reg() 216 p := s.Prog(v.Op.Asm()) 217 p.From.Type = obj.TYPE_CONST 218 p.From.Offset = v.AuxInt 219 p.To.Type = obj.TYPE_REG 220 p.To.Reg = r 221 if isFPreg(r) || isHILO(r) { 222 // cannot move into FP or special registers, use TMP as intermediate 223 p.To.Reg = mips.REGTMP 224 p = s.Prog(mips.AMOVV) 225 p.From.Type = obj.TYPE_REG 226 p.From.Reg = mips.REGTMP 227 p.To.Type = obj.TYPE_REG 228 p.To.Reg = r 229 } 230 case ssa.OpMIPS64MOVFconst, 231 ssa.OpMIPS64MOVDconst: 232 p := s.Prog(v.Op.Asm()) 233 p.From.Type = obj.TYPE_FCONST 234 p.From.Val = math.Float64frombits(uint64(v.AuxInt)) 235 p.To.Type = obj.TYPE_REG 236 p.To.Reg = v.Reg() 237 case ssa.OpMIPS64CMPEQF, 238 ssa.OpMIPS64CMPEQD, 239 ssa.OpMIPS64CMPGEF, 240 ssa.OpMIPS64CMPGED, 241 ssa.OpMIPS64CMPGTF, 242 ssa.OpMIPS64CMPGTD: 243 p := s.Prog(v.Op.Asm()) 244 p.From.Type = obj.TYPE_REG 245 p.From.Reg = v.Args[0].Reg() 246 p.Reg = v.Args[1].Reg() 247 case ssa.OpMIPS64MOVVaddr: 248 p := s.Prog(mips.AMOVV) 249 p.From.Type = obj.TYPE_ADDR 250 p.From.Reg = v.Args[0].Reg() 251 var wantreg string 252 // MOVV $sym+off(base), R 253 // the assembler expands it as the following: 254 // - base is SP: add constant offset to SP (R29) 255 // when constant is large, tmp register (R23) may be used 256 // - base is SB: load external address with relocation 257 switch v.Aux.(type) { 258 default: 259 v.Fatalf("aux is of unknown type %T", v.Aux) 260 case *obj.LSym: 261 wantreg = "SB" 262 ssagen.AddAux(&p.From, v) 263 case *ir.Name: 264 wantreg = "SP" 265 ssagen.AddAux(&p.From, v) 266 case nil: 267 // No sym, just MOVV $off(SP), R 268 wantreg = "SP" 269 p.From.Offset = v.AuxInt 270 } 271 if reg := v.Args[0].RegName(); reg != wantreg { 272 v.Fatalf("bad reg %s for symbol type %T, want %s", reg, v.Aux, wantreg) 273 } 274 p.To.Type = obj.TYPE_REG 275 p.To.Reg = v.Reg() 276 case ssa.OpMIPS64MOVBload, 277 ssa.OpMIPS64MOVBUload, 278 ssa.OpMIPS64MOVHload, 279 ssa.OpMIPS64MOVHUload, 280 ssa.OpMIPS64MOVWload, 281 ssa.OpMIPS64MOVWUload, 282 ssa.OpMIPS64MOVVload, 283 ssa.OpMIPS64MOVFload, 284 ssa.OpMIPS64MOVDload: 285 p := s.Prog(v.Op.Asm()) 286 p.From.Type = obj.TYPE_MEM 287 p.From.Reg = v.Args[0].Reg() 288 ssagen.AddAux(&p.From, v) 289 p.To.Type = obj.TYPE_REG 290 p.To.Reg = v.Reg() 291 case ssa.OpMIPS64MOVBstore, 292 ssa.OpMIPS64MOVHstore, 293 ssa.OpMIPS64MOVWstore, 294 ssa.OpMIPS64MOVVstore, 295 ssa.OpMIPS64MOVFstore, 296 ssa.OpMIPS64MOVDstore: 297 p := s.Prog(v.Op.Asm()) 298 p.From.Type = obj.TYPE_REG 299 p.From.Reg = v.Args[1].Reg() 300 p.To.Type = obj.TYPE_MEM 301 p.To.Reg = v.Args[0].Reg() 302 ssagen.AddAux(&p.To, v) 303 case ssa.OpMIPS64MOVBstorezero, 304 ssa.OpMIPS64MOVHstorezero, 305 ssa.OpMIPS64MOVWstorezero, 306 ssa.OpMIPS64MOVVstorezero: 307 p := s.Prog(v.Op.Asm()) 308 p.From.Type = obj.TYPE_REG 309 p.From.Reg = mips.REGZERO 310 p.To.Type = obj.TYPE_MEM 311 p.To.Reg = v.Args[0].Reg() 312 ssagen.AddAux(&p.To, v) 313 case ssa.OpMIPS64MOVBreg, 314 ssa.OpMIPS64MOVBUreg, 315 ssa.OpMIPS64MOVHreg, 316 ssa.OpMIPS64MOVHUreg, 317 ssa.OpMIPS64MOVWreg, 318 ssa.OpMIPS64MOVWUreg: 319 a := v.Args[0] 320 for a.Op == ssa.OpCopy || a.Op == ssa.OpMIPS64MOVVreg { 321 a = a.Args[0] 322 } 323 if a.Op == ssa.OpLoadReg && mips.REG_R0 <= a.Reg() && a.Reg() <= mips.REG_R31 { 324 // LoadReg from a narrower type does an extension, except loading 325 // to a floating point register. So only eliminate the extension 326 // if it is loaded to an integer register. 327 t := a.Type 328 switch { 329 case v.Op == ssa.OpMIPS64MOVBreg && t.Size() == 1 && t.IsSigned(), 330 v.Op == ssa.OpMIPS64MOVBUreg && t.Size() == 1 && !t.IsSigned(), 331 v.Op == ssa.OpMIPS64MOVHreg && t.Size() == 2 && t.IsSigned(), 332 v.Op == ssa.OpMIPS64MOVHUreg && t.Size() == 2 && !t.IsSigned(), 333 v.Op == ssa.OpMIPS64MOVWreg && t.Size() == 4 && t.IsSigned(), 334 v.Op == ssa.OpMIPS64MOVWUreg && t.Size() == 4 && !t.IsSigned(): 335 // arg is a proper-typed load, already zero/sign-extended, don't extend again 336 if v.Reg() == v.Args[0].Reg() { 337 return 338 } 339 p := s.Prog(mips.AMOVV) 340 p.From.Type = obj.TYPE_REG 341 p.From.Reg = v.Args[0].Reg() 342 p.To.Type = obj.TYPE_REG 343 p.To.Reg = v.Reg() 344 return 345 default: 346 } 347 } 348 fallthrough 349 case ssa.OpMIPS64MOVWF, 350 ssa.OpMIPS64MOVWD, 351 ssa.OpMIPS64TRUNCFW, 352 ssa.OpMIPS64TRUNCDW, 353 ssa.OpMIPS64MOVVF, 354 ssa.OpMIPS64MOVVD, 355 ssa.OpMIPS64TRUNCFV, 356 ssa.OpMIPS64TRUNCDV, 357 ssa.OpMIPS64MOVFD, 358 ssa.OpMIPS64MOVDF, 359 ssa.OpMIPS64MOVWfpgp, 360 ssa.OpMIPS64MOVWgpfp, 361 ssa.OpMIPS64MOVVfpgp, 362 ssa.OpMIPS64MOVVgpfp, 363 ssa.OpMIPS64NEGF, 364 ssa.OpMIPS64NEGD, 365 ssa.OpMIPS64ABSD, 366 ssa.OpMIPS64SQRTF, 367 ssa.OpMIPS64SQRTD: 368 p := s.Prog(v.Op.Asm()) 369 p.From.Type = obj.TYPE_REG 370 p.From.Reg = v.Args[0].Reg() 371 p.To.Type = obj.TYPE_REG 372 p.To.Reg = v.Reg() 373 case ssa.OpMIPS64NEGV: 374 // SUB from REGZERO 375 p := s.Prog(mips.ASUBVU) 376 p.From.Type = obj.TYPE_REG 377 p.From.Reg = v.Args[0].Reg() 378 p.Reg = mips.REGZERO 379 p.To.Type = obj.TYPE_REG 380 p.To.Reg = v.Reg() 381 case ssa.OpMIPS64DUFFZERO: 382 // runtime.duffzero expects start address - 8 in R1 383 p := s.Prog(mips.ASUBVU) 384 p.From.Type = obj.TYPE_CONST 385 p.From.Offset = 8 386 p.Reg = v.Args[0].Reg() 387 p.To.Type = obj.TYPE_REG 388 p.To.Reg = mips.REG_R1 389 p = s.Prog(obj.ADUFFZERO) 390 p.To.Type = obj.TYPE_MEM 391 p.To.Name = obj.NAME_EXTERN 392 p.To.Sym = ir.Syms.Duffzero 393 p.To.Offset = v.AuxInt 394 case ssa.OpMIPS64LoweredZero: 395 // SUBV $8, R1 396 // MOVV R0, 8(R1) 397 // ADDV $8, R1 398 // BNE Rarg1, R1, -2(PC) 399 // arg1 is the address of the last element to zero 400 var sz int64 401 var mov obj.As 402 switch { 403 case v.AuxInt%8 == 0: 404 sz = 8 405 mov = mips.AMOVV 406 case v.AuxInt%4 == 0: 407 sz = 4 408 mov = mips.AMOVW 409 case v.AuxInt%2 == 0: 410 sz = 2 411 mov = mips.AMOVH 412 default: 413 sz = 1 414 mov = mips.AMOVB 415 } 416 p := s.Prog(mips.ASUBVU) 417 p.From.Type = obj.TYPE_CONST 418 p.From.Offset = sz 419 p.To.Type = obj.TYPE_REG 420 p.To.Reg = mips.REG_R1 421 p2 := s.Prog(mov) 422 p2.From.Type = obj.TYPE_REG 423 p2.From.Reg = mips.REGZERO 424 p2.To.Type = obj.TYPE_MEM 425 p2.To.Reg = mips.REG_R1 426 p2.To.Offset = sz 427 p3 := s.Prog(mips.AADDVU) 428 p3.From.Type = obj.TYPE_CONST 429 p3.From.Offset = sz 430 p3.To.Type = obj.TYPE_REG 431 p3.To.Reg = mips.REG_R1 432 p4 := s.Prog(mips.ABNE) 433 p4.From.Type = obj.TYPE_REG 434 p4.From.Reg = v.Args[1].Reg() 435 p4.Reg = mips.REG_R1 436 p4.To.Type = obj.TYPE_BRANCH 437 p4.To.SetTarget(p2) 438 case ssa.OpMIPS64DUFFCOPY: 439 p := s.Prog(obj.ADUFFCOPY) 440 p.To.Type = obj.TYPE_MEM 441 p.To.Name = obj.NAME_EXTERN 442 p.To.Sym = ir.Syms.Duffcopy 443 p.To.Offset = v.AuxInt 444 case ssa.OpMIPS64LoweredMove: 445 // SUBV $8, R1 446 // MOVV 8(R1), Rtmp 447 // MOVV Rtmp, (R2) 448 // ADDV $8, R1 449 // ADDV $8, R2 450 // BNE Rarg2, R1, -4(PC) 451 // arg2 is the address of the last element of src 452 var sz int64 453 var mov obj.As 454 switch { 455 case v.AuxInt%8 == 0: 456 sz = 8 457 mov = mips.AMOVV 458 case v.AuxInt%4 == 0: 459 sz = 4 460 mov = mips.AMOVW 461 case v.AuxInt%2 == 0: 462 sz = 2 463 mov = mips.AMOVH 464 default: 465 sz = 1 466 mov = mips.AMOVB 467 } 468 p := s.Prog(mips.ASUBVU) 469 p.From.Type = obj.TYPE_CONST 470 p.From.Offset = sz 471 p.To.Type = obj.TYPE_REG 472 p.To.Reg = mips.REG_R1 473 p2 := s.Prog(mov) 474 p2.From.Type = obj.TYPE_MEM 475 p2.From.Reg = mips.REG_R1 476 p2.From.Offset = sz 477 p2.To.Type = obj.TYPE_REG 478 p2.To.Reg = mips.REGTMP 479 p3 := s.Prog(mov) 480 p3.From.Type = obj.TYPE_REG 481 p3.From.Reg = mips.REGTMP 482 p3.To.Type = obj.TYPE_MEM 483 p3.To.Reg = mips.REG_R2 484 p4 := s.Prog(mips.AADDVU) 485 p4.From.Type = obj.TYPE_CONST 486 p4.From.Offset = sz 487 p4.To.Type = obj.TYPE_REG 488 p4.To.Reg = mips.REG_R1 489 p5 := s.Prog(mips.AADDVU) 490 p5.From.Type = obj.TYPE_CONST 491 p5.From.Offset = sz 492 p5.To.Type = obj.TYPE_REG 493 p5.To.Reg = mips.REG_R2 494 p6 := s.Prog(mips.ABNE) 495 p6.From.Type = obj.TYPE_REG 496 p6.From.Reg = v.Args[2].Reg() 497 p6.Reg = mips.REG_R1 498 p6.To.Type = obj.TYPE_BRANCH 499 p6.To.SetTarget(p2) 500 case ssa.OpMIPS64CALLstatic, ssa.OpMIPS64CALLclosure, ssa.OpMIPS64CALLinter: 501 s.Call(v) 502 case ssa.OpMIPS64CALLtail: 503 s.TailCall(v) 504 case ssa.OpMIPS64LoweredWB: 505 p := s.Prog(obj.ACALL) 506 p.To.Type = obj.TYPE_MEM 507 p.To.Name = obj.NAME_EXTERN 508 // AuxInt encodes how many buffer entries we need. 509 p.To.Sym = ir.Syms.GCWriteBarrier[v.AuxInt-1] 510 case ssa.OpMIPS64LoweredPanicBoundsA, ssa.OpMIPS64LoweredPanicBoundsB, ssa.OpMIPS64LoweredPanicBoundsC: 511 p := s.Prog(obj.ACALL) 512 p.To.Type = obj.TYPE_MEM 513 p.To.Name = obj.NAME_EXTERN 514 p.To.Sym = ssagen.BoundsCheckFunc[v.AuxInt] 515 s.UseArgs(16) // space used in callee args area by assembly stubs 516 case ssa.OpMIPS64LoweredAtomicLoad8, ssa.OpMIPS64LoweredAtomicLoad32, ssa.OpMIPS64LoweredAtomicLoad64: 517 as := mips.AMOVV 518 switch v.Op { 519 case ssa.OpMIPS64LoweredAtomicLoad8: 520 as = mips.AMOVB 521 case ssa.OpMIPS64LoweredAtomicLoad32: 522 as = mips.AMOVW 523 } 524 s.Prog(mips.ASYNC) 525 p := s.Prog(as) 526 p.From.Type = obj.TYPE_MEM 527 p.From.Reg = v.Args[0].Reg() 528 p.To.Type = obj.TYPE_REG 529 p.To.Reg = v.Reg0() 530 s.Prog(mips.ASYNC) 531 case ssa.OpMIPS64LoweredAtomicStore8, ssa.OpMIPS64LoweredAtomicStore32, ssa.OpMIPS64LoweredAtomicStore64: 532 as := mips.AMOVV 533 switch v.Op { 534 case ssa.OpMIPS64LoweredAtomicStore8: 535 as = mips.AMOVB 536 case ssa.OpMIPS64LoweredAtomicStore32: 537 as = mips.AMOVW 538 } 539 s.Prog(mips.ASYNC) 540 p := s.Prog(as) 541 p.From.Type = obj.TYPE_REG 542 p.From.Reg = v.Args[1].Reg() 543 p.To.Type = obj.TYPE_MEM 544 p.To.Reg = v.Args[0].Reg() 545 s.Prog(mips.ASYNC) 546 case ssa.OpMIPS64LoweredAtomicStorezero32, ssa.OpMIPS64LoweredAtomicStorezero64: 547 as := mips.AMOVV 548 if v.Op == ssa.OpMIPS64LoweredAtomicStorezero32 { 549 as = mips.AMOVW 550 } 551 s.Prog(mips.ASYNC) 552 p := s.Prog(as) 553 p.From.Type = obj.TYPE_REG 554 p.From.Reg = mips.REGZERO 555 p.To.Type = obj.TYPE_MEM 556 p.To.Reg = v.Args[0].Reg() 557 s.Prog(mips.ASYNC) 558 case ssa.OpMIPS64LoweredAtomicExchange32, ssa.OpMIPS64LoweredAtomicExchange64: 559 // SYNC 560 // MOVV Rarg1, Rtmp 561 // LL (Rarg0), Rout 562 // SC Rtmp, (Rarg0) 563 // BEQ Rtmp, -3(PC) 564 // SYNC 565 ll := mips.ALLV 566 sc := mips.ASCV 567 if v.Op == ssa.OpMIPS64LoweredAtomicExchange32 { 568 ll = mips.ALL 569 sc = mips.ASC 570 } 571 s.Prog(mips.ASYNC) 572 p := s.Prog(mips.AMOVV) 573 p.From.Type = obj.TYPE_REG 574 p.From.Reg = v.Args[1].Reg() 575 p.To.Type = obj.TYPE_REG 576 p.To.Reg = mips.REGTMP 577 p1 := s.Prog(ll) 578 p1.From.Type = obj.TYPE_MEM 579 p1.From.Reg = v.Args[0].Reg() 580 p1.To.Type = obj.TYPE_REG 581 p1.To.Reg = v.Reg0() 582 p2 := s.Prog(sc) 583 p2.From.Type = obj.TYPE_REG 584 p2.From.Reg = mips.REGTMP 585 p2.To.Type = obj.TYPE_MEM 586 p2.To.Reg = v.Args[0].Reg() 587 p3 := s.Prog(mips.ABEQ) 588 p3.From.Type = obj.TYPE_REG 589 p3.From.Reg = mips.REGTMP 590 p3.To.Type = obj.TYPE_BRANCH 591 p3.To.SetTarget(p) 592 s.Prog(mips.ASYNC) 593 case ssa.OpMIPS64LoweredAtomicAdd32, ssa.OpMIPS64LoweredAtomicAdd64: 594 // SYNC 595 // LL (Rarg0), Rout 596 // ADDV Rarg1, Rout, Rtmp 597 // SC Rtmp, (Rarg0) 598 // BEQ Rtmp, -3(PC) 599 // SYNC 600 // ADDV Rarg1, Rout 601 ll := mips.ALLV 602 sc := mips.ASCV 603 if v.Op == ssa.OpMIPS64LoweredAtomicAdd32 { 604 ll = mips.ALL 605 sc = mips.ASC 606 } 607 s.Prog(mips.ASYNC) 608 p := s.Prog(ll) 609 p.From.Type = obj.TYPE_MEM 610 p.From.Reg = v.Args[0].Reg() 611 p.To.Type = obj.TYPE_REG 612 p.To.Reg = v.Reg0() 613 p1 := s.Prog(mips.AADDVU) 614 p1.From.Type = obj.TYPE_REG 615 p1.From.Reg = v.Args[1].Reg() 616 p1.Reg = v.Reg0() 617 p1.To.Type = obj.TYPE_REG 618 p1.To.Reg = mips.REGTMP 619 p2 := s.Prog(sc) 620 p2.From.Type = obj.TYPE_REG 621 p2.From.Reg = mips.REGTMP 622 p2.To.Type = obj.TYPE_MEM 623 p2.To.Reg = v.Args[0].Reg() 624 p3 := s.Prog(mips.ABEQ) 625 p3.From.Type = obj.TYPE_REG 626 p3.From.Reg = mips.REGTMP 627 p3.To.Type = obj.TYPE_BRANCH 628 p3.To.SetTarget(p) 629 s.Prog(mips.ASYNC) 630 p4 := s.Prog(mips.AADDVU) 631 p4.From.Type = obj.TYPE_REG 632 p4.From.Reg = v.Args[1].Reg() 633 p4.Reg = v.Reg0() 634 p4.To.Type = obj.TYPE_REG 635 p4.To.Reg = v.Reg0() 636 case ssa.OpMIPS64LoweredAtomicAddconst32, ssa.OpMIPS64LoweredAtomicAddconst64: 637 // SYNC 638 // LL (Rarg0), Rout 639 // ADDV $auxint, Rout, Rtmp 640 // SC Rtmp, (Rarg0) 641 // BEQ Rtmp, -3(PC) 642 // SYNC 643 // ADDV $auxint, Rout 644 ll := mips.ALLV 645 sc := mips.ASCV 646 if v.Op == ssa.OpMIPS64LoweredAtomicAddconst32 { 647 ll = mips.ALL 648 sc = mips.ASC 649 } 650 s.Prog(mips.ASYNC) 651 p := s.Prog(ll) 652 p.From.Type = obj.TYPE_MEM 653 p.From.Reg = v.Args[0].Reg() 654 p.To.Type = obj.TYPE_REG 655 p.To.Reg = v.Reg0() 656 p1 := s.Prog(mips.AADDVU) 657 p1.From.Type = obj.TYPE_CONST 658 p1.From.Offset = v.AuxInt 659 p1.Reg = v.Reg0() 660 p1.To.Type = obj.TYPE_REG 661 p1.To.Reg = mips.REGTMP 662 p2 := s.Prog(sc) 663 p2.From.Type = obj.TYPE_REG 664 p2.From.Reg = mips.REGTMP 665 p2.To.Type = obj.TYPE_MEM 666 p2.To.Reg = v.Args[0].Reg() 667 p3 := s.Prog(mips.ABEQ) 668 p3.From.Type = obj.TYPE_REG 669 p3.From.Reg = mips.REGTMP 670 p3.To.Type = obj.TYPE_BRANCH 671 p3.To.SetTarget(p) 672 s.Prog(mips.ASYNC) 673 p4 := s.Prog(mips.AADDVU) 674 p4.From.Type = obj.TYPE_CONST 675 p4.From.Offset = v.AuxInt 676 p4.Reg = v.Reg0() 677 p4.To.Type = obj.TYPE_REG 678 p4.To.Reg = v.Reg0() 679 case ssa.OpMIPS64LoweredAtomicAnd32, 680 ssa.OpMIPS64LoweredAtomicOr32: 681 // SYNC 682 // LL (Rarg0), Rtmp 683 // AND/OR Rarg1, Rtmp 684 // SC Rtmp, (Rarg0) 685 // BEQ Rtmp, -3(PC) 686 // SYNC 687 s.Prog(mips.ASYNC) 688 689 p := s.Prog(mips.ALL) 690 p.From.Type = obj.TYPE_MEM 691 p.From.Reg = v.Args[0].Reg() 692 p.To.Type = obj.TYPE_REG 693 p.To.Reg = mips.REGTMP 694 695 p1 := s.Prog(v.Op.Asm()) 696 p1.From.Type = obj.TYPE_REG 697 p1.From.Reg = v.Args[1].Reg() 698 p1.Reg = mips.REGTMP 699 p1.To.Type = obj.TYPE_REG 700 p1.To.Reg = mips.REGTMP 701 702 p2 := s.Prog(mips.ASC) 703 p2.From.Type = obj.TYPE_REG 704 p2.From.Reg = mips.REGTMP 705 p2.To.Type = obj.TYPE_MEM 706 p2.To.Reg = v.Args[0].Reg() 707 708 p3 := s.Prog(mips.ABEQ) 709 p3.From.Type = obj.TYPE_REG 710 p3.From.Reg = mips.REGTMP 711 p3.To.Type = obj.TYPE_BRANCH 712 p3.To.SetTarget(p) 713 714 s.Prog(mips.ASYNC) 715 716 case ssa.OpMIPS64LoweredAtomicCas32, ssa.OpMIPS64LoweredAtomicCas64: 717 // MOVV $0, Rout 718 // SYNC 719 // LL (Rarg0), Rtmp 720 // BNE Rtmp, Rarg1, 4(PC) 721 // MOVV Rarg2, Rout 722 // SC Rout, (Rarg0) 723 // BEQ Rout, -4(PC) 724 // SYNC 725 ll := mips.ALLV 726 sc := mips.ASCV 727 if v.Op == ssa.OpMIPS64LoweredAtomicCas32 { 728 ll = mips.ALL 729 sc = mips.ASC 730 } 731 p := s.Prog(mips.AMOVV) 732 p.From.Type = obj.TYPE_REG 733 p.From.Reg = mips.REGZERO 734 p.To.Type = obj.TYPE_REG 735 p.To.Reg = v.Reg0() 736 s.Prog(mips.ASYNC) 737 p1 := s.Prog(ll) 738 p1.From.Type = obj.TYPE_MEM 739 p1.From.Reg = v.Args[0].Reg() 740 p1.To.Type = obj.TYPE_REG 741 p1.To.Reg = mips.REGTMP 742 p2 := s.Prog(mips.ABNE) 743 p2.From.Type = obj.TYPE_REG 744 p2.From.Reg = v.Args[1].Reg() 745 p2.Reg = mips.REGTMP 746 p2.To.Type = obj.TYPE_BRANCH 747 p3 := s.Prog(mips.AMOVV) 748 p3.From.Type = obj.TYPE_REG 749 p3.From.Reg = v.Args[2].Reg() 750 p3.To.Type = obj.TYPE_REG 751 p3.To.Reg = v.Reg0() 752 p4 := s.Prog(sc) 753 p4.From.Type = obj.TYPE_REG 754 p4.From.Reg = v.Reg0() 755 p4.To.Type = obj.TYPE_MEM 756 p4.To.Reg = v.Args[0].Reg() 757 p5 := s.Prog(mips.ABEQ) 758 p5.From.Type = obj.TYPE_REG 759 p5.From.Reg = v.Reg0() 760 p5.To.Type = obj.TYPE_BRANCH 761 p5.To.SetTarget(p1) 762 p6 := s.Prog(mips.ASYNC) 763 p2.To.SetTarget(p6) 764 case ssa.OpMIPS64LoweredNilCheck: 765 // Issue a load which will fault if arg is nil. 766 p := s.Prog(mips.AMOVB) 767 p.From.Type = obj.TYPE_MEM 768 p.From.Reg = v.Args[0].Reg() 769 ssagen.AddAux(&p.From, v) 770 p.To.Type = obj.TYPE_REG 771 p.To.Reg = mips.REGTMP 772 if logopt.Enabled() { 773 logopt.LogOpt(v.Pos, "nilcheck", "genssa", v.Block.Func.Name) 774 } 775 if base.Debug.Nil != 0 && v.Pos.Line() > 1 { // v.Pos.Line()==1 in generated wrappers 776 base.WarnfAt(v.Pos, "generated nil check") 777 } 778 case ssa.OpMIPS64FPFlagTrue, 779 ssa.OpMIPS64FPFlagFalse: 780 // MOVV $0, r 781 // BFPF 2(PC) 782 // MOVV $1, r 783 branch := mips.ABFPF 784 if v.Op == ssa.OpMIPS64FPFlagFalse { 785 branch = mips.ABFPT 786 } 787 p := s.Prog(mips.AMOVV) 788 p.From.Type = obj.TYPE_REG 789 p.From.Reg = mips.REGZERO 790 p.To.Type = obj.TYPE_REG 791 p.To.Reg = v.Reg() 792 p2 := s.Prog(branch) 793 p2.To.Type = obj.TYPE_BRANCH 794 p3 := s.Prog(mips.AMOVV) 795 p3.From.Type = obj.TYPE_CONST 796 p3.From.Offset = 1 797 p3.To.Type = obj.TYPE_REG 798 p3.To.Reg = v.Reg() 799 p4 := s.Prog(obj.ANOP) // not a machine instruction, for branch to land 800 p2.To.SetTarget(p4) 801 case ssa.OpMIPS64LoweredGetClosurePtr: 802 // Closure pointer is R22 (mips.REGCTXT). 803 ssagen.CheckLoweredGetClosurePtr(v) 804 case ssa.OpMIPS64LoweredGetCallerSP: 805 // caller's SP is FixedFrameSize below the address of the first arg 806 p := s.Prog(mips.AMOVV) 807 p.From.Type = obj.TYPE_ADDR 808 p.From.Offset = -base.Ctxt.Arch.FixedFrameSize 809 p.From.Name = obj.NAME_PARAM 810 p.To.Type = obj.TYPE_REG 811 p.To.Reg = v.Reg() 812 case ssa.OpMIPS64LoweredGetCallerPC: 813 p := s.Prog(obj.AGETCALLERPC) 814 p.To.Type = obj.TYPE_REG 815 p.To.Reg = v.Reg() 816 case ssa.OpClobber, ssa.OpClobberReg: 817 // TODO: implement for clobberdead experiment. Nop is ok for now. 818 default: 819 v.Fatalf("genValue not implemented: %s", v.LongString()) 820 } 821 } 822 823 var blockJump = map[ssa.BlockKind]struct { 824 asm, invasm obj.As 825 }{ 826 ssa.BlockMIPS64EQ: {mips.ABEQ, mips.ABNE}, 827 ssa.BlockMIPS64NE: {mips.ABNE, mips.ABEQ}, 828 ssa.BlockMIPS64LTZ: {mips.ABLTZ, mips.ABGEZ}, 829 ssa.BlockMIPS64GEZ: {mips.ABGEZ, mips.ABLTZ}, 830 ssa.BlockMIPS64LEZ: {mips.ABLEZ, mips.ABGTZ}, 831 ssa.BlockMIPS64GTZ: {mips.ABGTZ, mips.ABLEZ}, 832 ssa.BlockMIPS64FPT: {mips.ABFPT, mips.ABFPF}, 833 ssa.BlockMIPS64FPF: {mips.ABFPF, mips.ABFPT}, 834 } 835 836 func ssaGenBlock(s *ssagen.State, b, next *ssa.Block) { 837 switch b.Kind { 838 case ssa.BlockPlain: 839 if b.Succs[0].Block() != next { 840 p := s.Prog(obj.AJMP) 841 p.To.Type = obj.TYPE_BRANCH 842 s.Branches = append(s.Branches, ssagen.Branch{P: p, B: b.Succs[0].Block()}) 843 } 844 case ssa.BlockDefer: 845 // defer returns in R1: 846 // 0 if we should continue executing 847 // 1 if we should jump to deferreturn call 848 p := s.Prog(mips.ABNE) 849 p.From.Type = obj.TYPE_REG 850 p.From.Reg = mips.REGZERO 851 p.Reg = mips.REG_R1 852 p.To.Type = obj.TYPE_BRANCH 853 s.Branches = append(s.Branches, ssagen.Branch{P: p, B: b.Succs[1].Block()}) 854 if b.Succs[0].Block() != next { 855 p := s.Prog(obj.AJMP) 856 p.To.Type = obj.TYPE_BRANCH 857 s.Branches = append(s.Branches, ssagen.Branch{P: p, B: b.Succs[0].Block()}) 858 } 859 case ssa.BlockExit, ssa.BlockRetJmp: 860 case ssa.BlockRet: 861 s.Prog(obj.ARET) 862 case ssa.BlockMIPS64EQ, ssa.BlockMIPS64NE, 863 ssa.BlockMIPS64LTZ, ssa.BlockMIPS64GEZ, 864 ssa.BlockMIPS64LEZ, ssa.BlockMIPS64GTZ, 865 ssa.BlockMIPS64FPT, ssa.BlockMIPS64FPF: 866 jmp := blockJump[b.Kind] 867 var p *obj.Prog 868 switch next { 869 case b.Succs[0].Block(): 870 p = s.Br(jmp.invasm, b.Succs[1].Block()) 871 case b.Succs[1].Block(): 872 p = s.Br(jmp.asm, b.Succs[0].Block()) 873 default: 874 if b.Likely != ssa.BranchUnlikely { 875 p = s.Br(jmp.asm, b.Succs[0].Block()) 876 s.Br(obj.AJMP, b.Succs[1].Block()) 877 } else { 878 p = s.Br(jmp.invasm, b.Succs[1].Block()) 879 s.Br(obj.AJMP, b.Succs[0].Block()) 880 } 881 } 882 if !b.Controls[0].Type.IsFlags() { 883 p.From.Type = obj.TYPE_REG 884 p.From.Reg = b.Controls[0].Reg() 885 } 886 default: 887 b.Fatalf("branch not implemented: %s", b.LongString()) 888 } 889 }