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