github.com/corona10/go@v0.0.0-20180224231303-7a218942be57/src/cmd/compile/internal/arm64/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 arm64 6 7 import ( 8 "math" 9 10 "cmd/compile/internal/gc" 11 "cmd/compile/internal/ssa" 12 "cmd/compile/internal/types" 13 "cmd/internal/obj" 14 "cmd/internal/obj/arm64" 15 ) 16 17 // loadByType returns the load instruction of the given type. 18 func loadByType(t *types.Type) obj.As { 19 if t.IsFloat() { 20 switch t.Size() { 21 case 4: 22 return arm64.AFMOVS 23 case 8: 24 return arm64.AFMOVD 25 } 26 } else { 27 switch t.Size() { 28 case 1: 29 if t.IsSigned() { 30 return arm64.AMOVB 31 } else { 32 return arm64.AMOVBU 33 } 34 case 2: 35 if t.IsSigned() { 36 return arm64.AMOVH 37 } else { 38 return arm64.AMOVHU 39 } 40 case 4: 41 if t.IsSigned() { 42 return arm64.AMOVW 43 } else { 44 return arm64.AMOVWU 45 } 46 case 8: 47 return arm64.AMOVD 48 } 49 } 50 panic("bad load type") 51 } 52 53 // storeByType returns the store instruction of the given type. 54 func storeByType(t *types.Type) obj.As { 55 if t.IsFloat() { 56 switch t.Size() { 57 case 4: 58 return arm64.AFMOVS 59 case 8: 60 return arm64.AFMOVD 61 } 62 } else { 63 switch t.Size() { 64 case 1: 65 return arm64.AMOVB 66 case 2: 67 return arm64.AMOVH 68 case 4: 69 return arm64.AMOVW 70 case 8: 71 return arm64.AMOVD 72 } 73 } 74 panic("bad store type") 75 } 76 77 // makeshift encodes a register shifted by a constant, used as an Offset in Prog 78 func makeshift(reg int16, typ int64, s int64) int64 { 79 return int64(reg&31)<<16 | typ | (s&63)<<10 80 } 81 82 // genshift generates a Prog for r = r0 op (r1 shifted by n) 83 func genshift(s *gc.SSAGenState, as obj.As, r0, r1, r int16, typ int64, n int64) *obj.Prog { 84 p := s.Prog(as) 85 p.From.Type = obj.TYPE_SHIFT 86 p.From.Offset = makeshift(r1, typ, n) 87 p.Reg = r0 88 if r != 0 { 89 p.To.Type = obj.TYPE_REG 90 p.To.Reg = r 91 } 92 return p 93 } 94 95 func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { 96 switch v.Op { 97 case ssa.OpCopy, ssa.OpARM64MOVDconvert, ssa.OpARM64MOVDreg: 98 if v.Type.IsMemory() { 99 return 100 } 101 x := v.Args[0].Reg() 102 y := v.Reg() 103 if x == y { 104 return 105 } 106 as := arm64.AMOVD 107 if v.Type.IsFloat() { 108 switch v.Type.Size() { 109 case 4: 110 as = arm64.AFMOVS 111 case 8: 112 as = arm64.AFMOVD 113 default: 114 panic("bad float size") 115 } 116 } 117 p := s.Prog(as) 118 p.From.Type = obj.TYPE_REG 119 p.From.Reg = x 120 p.To.Type = obj.TYPE_REG 121 p.To.Reg = y 122 case ssa.OpARM64MOVDnop: 123 if v.Reg() != v.Args[0].Reg() { 124 v.Fatalf("input[0] and output not in same register %s", v.LongString()) 125 } 126 // nothing to do 127 case ssa.OpLoadReg: 128 if v.Type.IsFlags() { 129 v.Fatalf("load flags not implemented: %v", v.LongString()) 130 return 131 } 132 p := s.Prog(loadByType(v.Type)) 133 gc.AddrAuto(&p.From, v.Args[0]) 134 p.To.Type = obj.TYPE_REG 135 p.To.Reg = v.Reg() 136 case ssa.OpStoreReg: 137 if v.Type.IsFlags() { 138 v.Fatalf("store flags not implemented: %v", v.LongString()) 139 return 140 } 141 p := s.Prog(storeByType(v.Type)) 142 p.From.Type = obj.TYPE_REG 143 p.From.Reg = v.Args[0].Reg() 144 gc.AddrAuto(&p.To, v) 145 case ssa.OpARM64ADD, 146 ssa.OpARM64SUB, 147 ssa.OpARM64AND, 148 ssa.OpARM64OR, 149 ssa.OpARM64XOR, 150 ssa.OpARM64BIC, 151 ssa.OpARM64MUL, 152 ssa.OpARM64MULW, 153 ssa.OpARM64MNEG, 154 ssa.OpARM64MNEGW, 155 ssa.OpARM64MULH, 156 ssa.OpARM64UMULH, 157 ssa.OpARM64MULL, 158 ssa.OpARM64UMULL, 159 ssa.OpARM64DIV, 160 ssa.OpARM64UDIV, 161 ssa.OpARM64DIVW, 162 ssa.OpARM64UDIVW, 163 ssa.OpARM64MOD, 164 ssa.OpARM64UMOD, 165 ssa.OpARM64MODW, 166 ssa.OpARM64UMODW, 167 ssa.OpARM64SLL, 168 ssa.OpARM64SRL, 169 ssa.OpARM64SRA, 170 ssa.OpARM64FADDS, 171 ssa.OpARM64FADDD, 172 ssa.OpARM64FSUBS, 173 ssa.OpARM64FSUBD, 174 ssa.OpARM64FMULS, 175 ssa.OpARM64FMULD, 176 ssa.OpARM64FNMULS, 177 ssa.OpARM64FNMULD, 178 ssa.OpARM64FDIVS, 179 ssa.OpARM64FDIVD: 180 r := v.Reg() 181 r1 := v.Args[0].Reg() 182 r2 := v.Args[1].Reg() 183 p := s.Prog(v.Op.Asm()) 184 p.From.Type = obj.TYPE_REG 185 p.From.Reg = r2 186 p.Reg = r1 187 p.To.Type = obj.TYPE_REG 188 p.To.Reg = r 189 case ssa.OpARM64FMADDS, 190 ssa.OpARM64FMADDD, 191 ssa.OpARM64FNMADDS, 192 ssa.OpARM64FNMADDD, 193 ssa.OpARM64FMSUBS, 194 ssa.OpARM64FMSUBD, 195 ssa.OpARM64FNMSUBS, 196 ssa.OpARM64FNMSUBD: 197 rt := v.Reg() 198 ra := v.Args[0].Reg() 199 rm := v.Args[1].Reg() 200 rn := v.Args[2].Reg() 201 p := s.Prog(v.Op.Asm()) 202 p.Reg = ra 203 p.From.Type = obj.TYPE_REG 204 p.From.Reg = rm 205 p.SetFrom3(obj.Addr{Type: obj.TYPE_REG, Reg: rn}) 206 p.To.Type = obj.TYPE_REG 207 p.To.Reg = rt 208 case ssa.OpARM64ADDconst, 209 ssa.OpARM64SUBconst, 210 ssa.OpARM64ANDconst, 211 ssa.OpARM64ORconst, 212 ssa.OpARM64XORconst, 213 ssa.OpARM64BICconst, 214 ssa.OpARM64SLLconst, 215 ssa.OpARM64SRLconst, 216 ssa.OpARM64SRAconst, 217 ssa.OpARM64RORconst, 218 ssa.OpARM64RORWconst: 219 p := s.Prog(v.Op.Asm()) 220 p.From.Type = obj.TYPE_CONST 221 p.From.Offset = v.AuxInt 222 p.Reg = v.Args[0].Reg() 223 p.To.Type = obj.TYPE_REG 224 p.To.Reg = v.Reg() 225 case ssa.OpARM64ADDshiftLL, 226 ssa.OpARM64SUBshiftLL, 227 ssa.OpARM64ANDshiftLL, 228 ssa.OpARM64ORshiftLL, 229 ssa.OpARM64XORshiftLL, 230 ssa.OpARM64BICshiftLL: 231 genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm64.SHIFT_LL, v.AuxInt) 232 case ssa.OpARM64ADDshiftRL, 233 ssa.OpARM64SUBshiftRL, 234 ssa.OpARM64ANDshiftRL, 235 ssa.OpARM64ORshiftRL, 236 ssa.OpARM64XORshiftRL, 237 ssa.OpARM64BICshiftRL: 238 genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm64.SHIFT_LR, v.AuxInt) 239 case ssa.OpARM64ADDshiftRA, 240 ssa.OpARM64SUBshiftRA, 241 ssa.OpARM64ANDshiftRA, 242 ssa.OpARM64ORshiftRA, 243 ssa.OpARM64XORshiftRA, 244 ssa.OpARM64BICshiftRA: 245 genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm64.SHIFT_AR, v.AuxInt) 246 case ssa.OpARM64MOVDconst: 247 p := s.Prog(v.Op.Asm()) 248 p.From.Type = obj.TYPE_CONST 249 p.From.Offset = v.AuxInt 250 p.To.Type = obj.TYPE_REG 251 p.To.Reg = v.Reg() 252 case ssa.OpARM64FMOVSconst, 253 ssa.OpARM64FMOVDconst: 254 p := s.Prog(v.Op.Asm()) 255 p.From.Type = obj.TYPE_FCONST 256 p.From.Val = math.Float64frombits(uint64(v.AuxInt)) 257 p.To.Type = obj.TYPE_REG 258 p.To.Reg = v.Reg() 259 case ssa.OpARM64CMP, 260 ssa.OpARM64CMPW, 261 ssa.OpARM64CMN, 262 ssa.OpARM64CMNW, 263 ssa.OpARM64FCMPS, 264 ssa.OpARM64FCMPD: 265 p := s.Prog(v.Op.Asm()) 266 p.From.Type = obj.TYPE_REG 267 p.From.Reg = v.Args[1].Reg() 268 p.Reg = v.Args[0].Reg() 269 case ssa.OpARM64CMPconst, 270 ssa.OpARM64CMPWconst, 271 ssa.OpARM64CMNconst, 272 ssa.OpARM64CMNWconst: 273 p := s.Prog(v.Op.Asm()) 274 p.From.Type = obj.TYPE_CONST 275 p.From.Offset = v.AuxInt 276 p.Reg = v.Args[0].Reg() 277 case ssa.OpARM64CMPshiftLL: 278 genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), 0, arm64.SHIFT_LL, v.AuxInt) 279 case ssa.OpARM64CMPshiftRL: 280 genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), 0, arm64.SHIFT_LR, v.AuxInt) 281 case ssa.OpARM64CMPshiftRA: 282 genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), 0, arm64.SHIFT_AR, v.AuxInt) 283 case ssa.OpARM64MOVDaddr: 284 p := s.Prog(arm64.AMOVD) 285 p.From.Type = obj.TYPE_ADDR 286 p.From.Reg = v.Args[0].Reg() 287 p.To.Type = obj.TYPE_REG 288 p.To.Reg = v.Reg() 289 290 var wantreg string 291 // MOVD $sym+off(base), R 292 // the assembler expands it as the following: 293 // - base is SP: add constant offset to SP (R13) 294 // when constant is large, tmp register (R11) may be used 295 // - base is SB: load external address from constant pool (use relocation) 296 switch v.Aux.(type) { 297 default: 298 v.Fatalf("aux is of unknown type %T", v.Aux) 299 case *obj.LSym: 300 wantreg = "SB" 301 gc.AddAux(&p.From, v) 302 case *gc.Node: 303 wantreg = "SP" 304 gc.AddAux(&p.From, v) 305 case nil: 306 // No sym, just MOVD $off(SP), R 307 wantreg = "SP" 308 p.From.Offset = v.AuxInt 309 } 310 if reg := v.Args[0].RegName(); reg != wantreg { 311 v.Fatalf("bad reg %s for symbol type %T, want %s", reg, v.Aux, wantreg) 312 } 313 case ssa.OpARM64MOVBload, 314 ssa.OpARM64MOVBUload, 315 ssa.OpARM64MOVHload, 316 ssa.OpARM64MOVHUload, 317 ssa.OpARM64MOVWload, 318 ssa.OpARM64MOVWUload, 319 ssa.OpARM64MOVDload, 320 ssa.OpARM64FMOVSload, 321 ssa.OpARM64FMOVDload: 322 p := s.Prog(v.Op.Asm()) 323 p.From.Type = obj.TYPE_MEM 324 p.From.Reg = v.Args[0].Reg() 325 gc.AddAux(&p.From, v) 326 p.To.Type = obj.TYPE_REG 327 p.To.Reg = v.Reg() 328 case ssa.OpARM64LDAR, 329 ssa.OpARM64LDARW: 330 p := s.Prog(v.Op.Asm()) 331 p.From.Type = obj.TYPE_MEM 332 p.From.Reg = v.Args[0].Reg() 333 gc.AddAux(&p.From, v) 334 p.To.Type = obj.TYPE_REG 335 p.To.Reg = v.Reg0() 336 case ssa.OpARM64MOVBstore, 337 ssa.OpARM64MOVHstore, 338 ssa.OpARM64MOVWstore, 339 ssa.OpARM64MOVDstore, 340 ssa.OpARM64FMOVSstore, 341 ssa.OpARM64FMOVDstore, 342 ssa.OpARM64STLR, 343 ssa.OpARM64STLRW: 344 p := s.Prog(v.Op.Asm()) 345 p.From.Type = obj.TYPE_REG 346 p.From.Reg = v.Args[1].Reg() 347 p.To.Type = obj.TYPE_MEM 348 p.To.Reg = v.Args[0].Reg() 349 gc.AddAux(&p.To, v) 350 case ssa.OpARM64STP: 351 p := s.Prog(v.Op.Asm()) 352 p.From.Type = obj.TYPE_REGREG 353 p.From.Reg = v.Args[1].Reg() 354 p.From.Offset = int64(v.Args[2].Reg()) 355 p.To.Type = obj.TYPE_MEM 356 p.To.Reg = v.Args[0].Reg() 357 gc.AddAux(&p.To, v) 358 case ssa.OpARM64MOVBstorezero, 359 ssa.OpARM64MOVHstorezero, 360 ssa.OpARM64MOVWstorezero, 361 ssa.OpARM64MOVDstorezero: 362 p := s.Prog(v.Op.Asm()) 363 p.From.Type = obj.TYPE_REG 364 p.From.Reg = arm64.REGZERO 365 p.To.Type = obj.TYPE_MEM 366 p.To.Reg = v.Args[0].Reg() 367 gc.AddAux(&p.To, v) 368 case ssa.OpARM64MOVQstorezero: 369 p := s.Prog(v.Op.Asm()) 370 p.From.Type = obj.TYPE_REGREG 371 p.From.Reg = arm64.REGZERO 372 p.From.Offset = int64(arm64.REGZERO) 373 p.To.Type = obj.TYPE_MEM 374 p.To.Reg = v.Args[0].Reg() 375 gc.AddAux(&p.To, v) 376 case ssa.OpARM64LoweredAtomicExchange64, 377 ssa.OpARM64LoweredAtomicExchange32: 378 // LDAXR (Rarg0), Rout 379 // STLXR Rarg1, (Rarg0), Rtmp 380 // CBNZ Rtmp, -2(PC) 381 ld := arm64.ALDAXR 382 st := arm64.ASTLXR 383 if v.Op == ssa.OpARM64LoweredAtomicExchange32 { 384 ld = arm64.ALDAXRW 385 st = arm64.ASTLXRW 386 } 387 r0 := v.Args[0].Reg() 388 r1 := v.Args[1].Reg() 389 out := v.Reg0() 390 p := s.Prog(ld) 391 p.From.Type = obj.TYPE_MEM 392 p.From.Reg = r0 393 p.To.Type = obj.TYPE_REG 394 p.To.Reg = out 395 p1 := s.Prog(st) 396 p1.From.Type = obj.TYPE_REG 397 p1.From.Reg = r1 398 p1.To.Type = obj.TYPE_MEM 399 p1.To.Reg = r0 400 p1.RegTo2 = arm64.REGTMP 401 p2 := s.Prog(arm64.ACBNZ) 402 p2.From.Type = obj.TYPE_REG 403 p2.From.Reg = arm64.REGTMP 404 p2.To.Type = obj.TYPE_BRANCH 405 gc.Patch(p2, p) 406 case ssa.OpARM64LoweredAtomicAdd64, 407 ssa.OpARM64LoweredAtomicAdd32: 408 // LDAXR (Rarg0), Rout 409 // ADD Rarg1, Rout 410 // STLXR Rout, (Rarg0), Rtmp 411 // CBNZ Rtmp, -3(PC) 412 ld := arm64.ALDAXR 413 st := arm64.ASTLXR 414 if v.Op == ssa.OpARM64LoweredAtomicAdd32 { 415 ld = arm64.ALDAXRW 416 st = arm64.ASTLXRW 417 } 418 r0 := v.Args[0].Reg() 419 r1 := v.Args[1].Reg() 420 out := v.Reg0() 421 p := s.Prog(ld) 422 p.From.Type = obj.TYPE_MEM 423 p.From.Reg = r0 424 p.To.Type = obj.TYPE_REG 425 p.To.Reg = out 426 p1 := s.Prog(arm64.AADD) 427 p1.From.Type = obj.TYPE_REG 428 p1.From.Reg = r1 429 p1.To.Type = obj.TYPE_REG 430 p1.To.Reg = out 431 p2 := s.Prog(st) 432 p2.From.Type = obj.TYPE_REG 433 p2.From.Reg = out 434 p2.To.Type = obj.TYPE_MEM 435 p2.To.Reg = r0 436 p2.RegTo2 = arm64.REGTMP 437 p3 := s.Prog(arm64.ACBNZ) 438 p3.From.Type = obj.TYPE_REG 439 p3.From.Reg = arm64.REGTMP 440 p3.To.Type = obj.TYPE_BRANCH 441 gc.Patch(p3, p) 442 case ssa.OpARM64LoweredAtomicCas64, 443 ssa.OpARM64LoweredAtomicCas32: 444 // LDAXR (Rarg0), Rtmp 445 // CMP Rarg1, Rtmp 446 // BNE 3(PC) 447 // STLXR Rarg2, (Rarg0), Rtmp 448 // CBNZ Rtmp, -4(PC) 449 // CSET EQ, Rout 450 ld := arm64.ALDAXR 451 st := arm64.ASTLXR 452 cmp := arm64.ACMP 453 if v.Op == ssa.OpARM64LoweredAtomicCas32 { 454 ld = arm64.ALDAXRW 455 st = arm64.ASTLXRW 456 cmp = arm64.ACMPW 457 } 458 r0 := v.Args[0].Reg() 459 r1 := v.Args[1].Reg() 460 r2 := v.Args[2].Reg() 461 out := v.Reg0() 462 p := s.Prog(ld) 463 p.From.Type = obj.TYPE_MEM 464 p.From.Reg = r0 465 p.To.Type = obj.TYPE_REG 466 p.To.Reg = arm64.REGTMP 467 p1 := s.Prog(cmp) 468 p1.From.Type = obj.TYPE_REG 469 p1.From.Reg = r1 470 p1.Reg = arm64.REGTMP 471 p2 := s.Prog(arm64.ABNE) 472 p2.To.Type = obj.TYPE_BRANCH 473 p3 := s.Prog(st) 474 p3.From.Type = obj.TYPE_REG 475 p3.From.Reg = r2 476 p3.To.Type = obj.TYPE_MEM 477 p3.To.Reg = r0 478 p3.RegTo2 = arm64.REGTMP 479 p4 := s.Prog(arm64.ACBNZ) 480 p4.From.Type = obj.TYPE_REG 481 p4.From.Reg = arm64.REGTMP 482 p4.To.Type = obj.TYPE_BRANCH 483 gc.Patch(p4, p) 484 p5 := s.Prog(arm64.ACSET) 485 p5.From.Type = obj.TYPE_REG // assembler encodes conditional bits in Reg 486 p5.From.Reg = arm64.COND_EQ 487 p5.To.Type = obj.TYPE_REG 488 p5.To.Reg = out 489 gc.Patch(p2, p5) 490 case ssa.OpARM64LoweredAtomicAnd8, 491 ssa.OpARM64LoweredAtomicOr8: 492 // LDAXRB (Rarg0), Rtmp 493 // AND/OR Rarg1, Rtmp 494 // STLXRB Rtmp, (Rarg0), Rtmp 495 // CBNZ Rtmp, -3(PC) 496 r0 := v.Args[0].Reg() 497 r1 := v.Args[1].Reg() 498 p := s.Prog(arm64.ALDAXRB) 499 p.From.Type = obj.TYPE_MEM 500 p.From.Reg = r0 501 p.To.Type = obj.TYPE_REG 502 p.To.Reg = arm64.REGTMP 503 p1 := s.Prog(v.Op.Asm()) 504 p1.From.Type = obj.TYPE_REG 505 p1.From.Reg = r1 506 p1.To.Type = obj.TYPE_REG 507 p1.To.Reg = arm64.REGTMP 508 p2 := s.Prog(arm64.ASTLXRB) 509 p2.From.Type = obj.TYPE_REG 510 p2.From.Reg = arm64.REGTMP 511 p2.To.Type = obj.TYPE_MEM 512 p2.To.Reg = r0 513 p2.RegTo2 = arm64.REGTMP 514 p3 := s.Prog(arm64.ACBNZ) 515 p3.From.Type = obj.TYPE_REG 516 p3.From.Reg = arm64.REGTMP 517 p3.To.Type = obj.TYPE_BRANCH 518 gc.Patch(p3, p) 519 case ssa.OpARM64MOVBreg, 520 ssa.OpARM64MOVBUreg, 521 ssa.OpARM64MOVHreg, 522 ssa.OpARM64MOVHUreg, 523 ssa.OpARM64MOVWreg, 524 ssa.OpARM64MOVWUreg: 525 a := v.Args[0] 526 for a.Op == ssa.OpCopy || a.Op == ssa.OpARM64MOVDreg { 527 a = a.Args[0] 528 } 529 if a.Op == ssa.OpLoadReg { 530 t := a.Type 531 switch { 532 case v.Op == ssa.OpARM64MOVBreg && t.Size() == 1 && t.IsSigned(), 533 v.Op == ssa.OpARM64MOVBUreg && t.Size() == 1 && !t.IsSigned(), 534 v.Op == ssa.OpARM64MOVHreg && t.Size() == 2 && t.IsSigned(), 535 v.Op == ssa.OpARM64MOVHUreg && t.Size() == 2 && !t.IsSigned(), 536 v.Op == ssa.OpARM64MOVWreg && t.Size() == 4 && t.IsSigned(), 537 v.Op == ssa.OpARM64MOVWUreg && t.Size() == 4 && !t.IsSigned(): 538 // arg is a proper-typed load, already zero/sign-extended, don't extend again 539 if v.Reg() == v.Args[0].Reg() { 540 return 541 } 542 p := s.Prog(arm64.AMOVD) 543 p.From.Type = obj.TYPE_REG 544 p.From.Reg = v.Args[0].Reg() 545 p.To.Type = obj.TYPE_REG 546 p.To.Reg = v.Reg() 547 return 548 default: 549 } 550 } 551 fallthrough 552 case ssa.OpARM64MVN, 553 ssa.OpARM64NEG, 554 ssa.OpARM64FMOVDfpgp, 555 ssa.OpARM64FMOVDgpfp, 556 ssa.OpARM64FNEGS, 557 ssa.OpARM64FNEGD, 558 ssa.OpARM64FSQRTD, 559 ssa.OpARM64FCVTZSSW, 560 ssa.OpARM64FCVTZSDW, 561 ssa.OpARM64FCVTZUSW, 562 ssa.OpARM64FCVTZUDW, 563 ssa.OpARM64FCVTZSS, 564 ssa.OpARM64FCVTZSD, 565 ssa.OpARM64FCVTZUS, 566 ssa.OpARM64FCVTZUD, 567 ssa.OpARM64SCVTFWS, 568 ssa.OpARM64SCVTFWD, 569 ssa.OpARM64SCVTFS, 570 ssa.OpARM64SCVTFD, 571 ssa.OpARM64UCVTFWS, 572 ssa.OpARM64UCVTFWD, 573 ssa.OpARM64UCVTFS, 574 ssa.OpARM64UCVTFD, 575 ssa.OpARM64FCVTSD, 576 ssa.OpARM64FCVTDS, 577 ssa.OpARM64REV, 578 ssa.OpARM64REVW, 579 ssa.OpARM64REV16W, 580 ssa.OpARM64RBIT, 581 ssa.OpARM64RBITW, 582 ssa.OpARM64CLZ, 583 ssa.OpARM64CLZW, 584 ssa.OpARM64FRINTAD, 585 ssa.OpARM64FRINTMD, 586 ssa.OpARM64FRINTPD, 587 ssa.OpARM64FRINTZD: 588 p := s.Prog(v.Op.Asm()) 589 p.From.Type = obj.TYPE_REG 590 p.From.Reg = v.Args[0].Reg() 591 p.To.Type = obj.TYPE_REG 592 p.To.Reg = v.Reg() 593 case ssa.OpARM64LoweredRound32F, ssa.OpARM64LoweredRound64F: 594 // input is already rounded 595 case ssa.OpARM64VCNT: 596 p := s.Prog(v.Op.Asm()) 597 p.From.Type = obj.TYPE_REG 598 p.From.Reg = (v.Args[0].Reg()-arm64.REG_F0)&31 + arm64.REG_ARNG + ((arm64.ARNG_8B & 15) << 5) 599 p.To.Type = obj.TYPE_REG 600 p.To.Reg = (v.Reg()-arm64.REG_F0)&31 + arm64.REG_ARNG + ((arm64.ARNG_8B & 15) << 5) 601 case ssa.OpARM64VUADDLV: 602 p := s.Prog(v.Op.Asm()) 603 p.From.Type = obj.TYPE_REG 604 p.From.Reg = (v.Args[0].Reg()-arm64.REG_F0)&31 + arm64.REG_ARNG + ((arm64.ARNG_8B & 15) << 5) 605 p.To.Type = obj.TYPE_REG 606 p.To.Reg = v.Reg() - arm64.REG_F0 + arm64.REG_V0 607 case ssa.OpARM64CSEL, ssa.OpARM64CSEL0: 608 r1 := int16(arm64.REGZERO) 609 if v.Op != ssa.OpARM64CSEL0 { 610 r1 = v.Args[1].Reg() 611 } 612 p := s.Prog(v.Op.Asm()) 613 p.From.Type = obj.TYPE_REG // assembler encodes conditional bits in Reg 614 p.From.Reg = condBits[v.Aux.(ssa.Op)] 615 p.Reg = v.Args[0].Reg() 616 p.SetFrom3(obj.Addr{Type: obj.TYPE_REG, Reg: r1}) 617 p.To.Type = obj.TYPE_REG 618 p.To.Reg = v.Reg() 619 case ssa.OpARM64DUFFZERO: 620 // runtime.duffzero expects start address in R16 621 p := s.Prog(obj.ADUFFZERO) 622 p.To.Type = obj.TYPE_MEM 623 p.To.Name = obj.NAME_EXTERN 624 p.To.Sym = gc.Duffzero 625 p.To.Offset = v.AuxInt 626 case ssa.OpARM64LoweredZero: 627 // STP.P (ZR,ZR), 16(R16) 628 // CMP Rarg1, R16 629 // BLE -2(PC) 630 // arg1 is the address of the last 16-byte unit to zero 631 p := s.Prog(arm64.ASTP) 632 p.Scond = arm64.C_XPOST 633 p.From.Type = obj.TYPE_REGREG 634 p.From.Reg = arm64.REGZERO 635 p.From.Offset = int64(arm64.REGZERO) 636 p.To.Type = obj.TYPE_MEM 637 p.To.Reg = arm64.REG_R16 638 p.To.Offset = 16 639 p2 := s.Prog(arm64.ACMP) 640 p2.From.Type = obj.TYPE_REG 641 p2.From.Reg = v.Args[1].Reg() 642 p2.Reg = arm64.REG_R16 643 p3 := s.Prog(arm64.ABLE) 644 p3.To.Type = obj.TYPE_BRANCH 645 gc.Patch(p3, p) 646 case ssa.OpARM64DUFFCOPY: 647 p := s.Prog(obj.ADUFFCOPY) 648 p.To.Type = obj.TYPE_MEM 649 p.To.Name = obj.NAME_EXTERN 650 p.To.Sym = gc.Duffcopy 651 p.To.Offset = v.AuxInt 652 case ssa.OpARM64LoweredMove: 653 // MOVD.P 8(R16), Rtmp 654 // MOVD.P Rtmp, 8(R17) 655 // CMP Rarg2, R16 656 // BLE -3(PC) 657 // arg2 is the address of the last element of src 658 p := s.Prog(arm64.AMOVD) 659 p.Scond = arm64.C_XPOST 660 p.From.Type = obj.TYPE_MEM 661 p.From.Reg = arm64.REG_R16 662 p.From.Offset = 8 663 p.To.Type = obj.TYPE_REG 664 p.To.Reg = arm64.REGTMP 665 p2 := s.Prog(arm64.AMOVD) 666 p2.Scond = arm64.C_XPOST 667 p2.From.Type = obj.TYPE_REG 668 p2.From.Reg = arm64.REGTMP 669 p2.To.Type = obj.TYPE_MEM 670 p2.To.Reg = arm64.REG_R17 671 p2.To.Offset = 8 672 p3 := s.Prog(arm64.ACMP) 673 p3.From.Type = obj.TYPE_REG 674 p3.From.Reg = v.Args[2].Reg() 675 p3.Reg = arm64.REG_R16 676 p4 := s.Prog(arm64.ABLE) 677 p4.To.Type = obj.TYPE_BRANCH 678 gc.Patch(p4, p) 679 case ssa.OpARM64CALLstatic, ssa.OpARM64CALLclosure, ssa.OpARM64CALLinter: 680 s.Call(v) 681 case ssa.OpARM64LoweredWB: 682 p := s.Prog(obj.ACALL) 683 p.To.Type = obj.TYPE_MEM 684 p.To.Name = obj.NAME_EXTERN 685 p.To.Sym = v.Aux.(*obj.LSym) 686 case ssa.OpARM64LoweredNilCheck: 687 // Issue a load which will fault if arg is nil. 688 p := s.Prog(arm64.AMOVB) 689 p.From.Type = obj.TYPE_MEM 690 p.From.Reg = v.Args[0].Reg() 691 gc.AddAux(&p.From, v) 692 p.To.Type = obj.TYPE_REG 693 p.To.Reg = arm64.REGTMP 694 if gc.Debug_checknil != 0 && v.Pos.Line() > 1 { // v.Line==1 in generated wrappers 695 gc.Warnl(v.Pos, "generated nil check") 696 } 697 case ssa.OpARM64Equal, 698 ssa.OpARM64NotEqual, 699 ssa.OpARM64LessThan, 700 ssa.OpARM64LessEqual, 701 ssa.OpARM64GreaterThan, 702 ssa.OpARM64GreaterEqual, 703 ssa.OpARM64LessThanU, 704 ssa.OpARM64LessEqualU, 705 ssa.OpARM64GreaterThanU, 706 ssa.OpARM64GreaterEqualU: 707 // generate boolean values using CSET 708 p := s.Prog(arm64.ACSET) 709 p.From.Type = obj.TYPE_REG // assembler encodes conditional bits in Reg 710 p.From.Reg = condBits[v.Op] 711 p.To.Type = obj.TYPE_REG 712 p.To.Reg = v.Reg() 713 case ssa.OpARM64LoweredGetClosurePtr: 714 // Closure pointer is R26 (arm64.REGCTXT). 715 gc.CheckLoweredGetClosurePtr(v) 716 case ssa.OpARM64LoweredGetCallerSP: 717 // caller's SP is FixedFrameSize below the address of the first arg 718 p := s.Prog(arm64.AMOVD) 719 p.From.Type = obj.TYPE_ADDR 720 p.From.Offset = -gc.Ctxt.FixedFrameSize() 721 p.From.Name = obj.NAME_PARAM 722 p.To.Type = obj.TYPE_REG 723 p.To.Reg = v.Reg() 724 case ssa.OpARM64FlagEQ, 725 ssa.OpARM64FlagLT_ULT, 726 ssa.OpARM64FlagLT_UGT, 727 ssa.OpARM64FlagGT_ULT, 728 ssa.OpARM64FlagGT_UGT: 729 v.Fatalf("Flag* ops should never make it to codegen %v", v.LongString()) 730 case ssa.OpARM64InvertFlags: 731 v.Fatalf("InvertFlags should never make it to codegen %v", v.LongString()) 732 case ssa.OpClobber: 733 // TODO: implement for clobberdead experiment. Nop is ok for now. 734 default: 735 v.Fatalf("genValue not implemented: %s", v.LongString()) 736 } 737 } 738 739 var condBits = map[ssa.Op]int16{ 740 ssa.OpARM64Equal: arm64.COND_EQ, 741 ssa.OpARM64NotEqual: arm64.COND_NE, 742 ssa.OpARM64LessThan: arm64.COND_LT, 743 ssa.OpARM64LessThanU: arm64.COND_LO, 744 ssa.OpARM64LessEqual: arm64.COND_LE, 745 ssa.OpARM64LessEqualU: arm64.COND_LS, 746 ssa.OpARM64GreaterThan: arm64.COND_GT, 747 ssa.OpARM64GreaterThanU: arm64.COND_HI, 748 ssa.OpARM64GreaterEqual: arm64.COND_GE, 749 ssa.OpARM64GreaterEqualU: arm64.COND_HS, 750 } 751 752 var blockJump = map[ssa.BlockKind]struct { 753 asm, invasm obj.As 754 }{ 755 ssa.BlockARM64EQ: {arm64.ABEQ, arm64.ABNE}, 756 ssa.BlockARM64NE: {arm64.ABNE, arm64.ABEQ}, 757 ssa.BlockARM64LT: {arm64.ABLT, arm64.ABGE}, 758 ssa.BlockARM64GE: {arm64.ABGE, arm64.ABLT}, 759 ssa.BlockARM64LE: {arm64.ABLE, arm64.ABGT}, 760 ssa.BlockARM64GT: {arm64.ABGT, arm64.ABLE}, 761 ssa.BlockARM64ULT: {arm64.ABLO, arm64.ABHS}, 762 ssa.BlockARM64UGE: {arm64.ABHS, arm64.ABLO}, 763 ssa.BlockARM64UGT: {arm64.ABHI, arm64.ABLS}, 764 ssa.BlockARM64ULE: {arm64.ABLS, arm64.ABHI}, 765 ssa.BlockARM64Z: {arm64.ACBZ, arm64.ACBNZ}, 766 ssa.BlockARM64NZ: {arm64.ACBNZ, arm64.ACBZ}, 767 ssa.BlockARM64ZW: {arm64.ACBZW, arm64.ACBNZW}, 768 ssa.BlockARM64NZW: {arm64.ACBNZW, arm64.ACBZW}, 769 ssa.BlockARM64TBZ: {arm64.ATBZ, arm64.ATBNZ}, 770 ssa.BlockARM64TBNZ: {arm64.ATBNZ, arm64.ATBZ}, 771 } 772 773 func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) { 774 switch b.Kind { 775 case ssa.BlockPlain: 776 if b.Succs[0].Block() != next { 777 p := s.Prog(obj.AJMP) 778 p.To.Type = obj.TYPE_BRANCH 779 s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()}) 780 } 781 782 case ssa.BlockDefer: 783 // defer returns in R0: 784 // 0 if we should continue executing 785 // 1 if we should jump to deferreturn call 786 p := s.Prog(arm64.ACMP) 787 p.From.Type = obj.TYPE_CONST 788 p.From.Offset = 0 789 p.Reg = arm64.REG_R0 790 p = s.Prog(arm64.ABNE) 791 p.To.Type = obj.TYPE_BRANCH 792 s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()}) 793 if b.Succs[0].Block() != next { 794 p := s.Prog(obj.AJMP) 795 p.To.Type = obj.TYPE_BRANCH 796 s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()}) 797 } 798 799 case ssa.BlockExit: 800 s.Prog(obj.AUNDEF) // tell plive.go that we never reach here 801 802 case ssa.BlockRet: 803 s.Prog(obj.ARET) 804 805 case ssa.BlockRetJmp: 806 p := s.Prog(obj.ARET) 807 p.To.Type = obj.TYPE_MEM 808 p.To.Name = obj.NAME_EXTERN 809 p.To.Sym = b.Aux.(*obj.LSym) 810 811 case ssa.BlockARM64EQ, ssa.BlockARM64NE, 812 ssa.BlockARM64LT, ssa.BlockARM64GE, 813 ssa.BlockARM64LE, ssa.BlockARM64GT, 814 ssa.BlockARM64ULT, ssa.BlockARM64UGT, 815 ssa.BlockARM64ULE, ssa.BlockARM64UGE, 816 ssa.BlockARM64Z, ssa.BlockARM64NZ, 817 ssa.BlockARM64ZW, ssa.BlockARM64NZW: 818 jmp := blockJump[b.Kind] 819 var p *obj.Prog 820 switch next { 821 case b.Succs[0].Block(): 822 p = s.Prog(jmp.invasm) 823 p.To.Type = obj.TYPE_BRANCH 824 s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()}) 825 case b.Succs[1].Block(): 826 p = s.Prog(jmp.asm) 827 p.To.Type = obj.TYPE_BRANCH 828 s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()}) 829 default: 830 p = s.Prog(jmp.asm) 831 p.To.Type = obj.TYPE_BRANCH 832 s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()}) 833 q := s.Prog(obj.AJMP) 834 q.To.Type = obj.TYPE_BRANCH 835 s.Branches = append(s.Branches, gc.Branch{P: q, B: b.Succs[1].Block()}) 836 } 837 if !b.Control.Type.IsFlags() { 838 p.From.Type = obj.TYPE_REG 839 p.From.Reg = b.Control.Reg() 840 } 841 case ssa.BlockARM64TBZ, ssa.BlockARM64TBNZ: 842 jmp := blockJump[b.Kind] 843 var p *obj.Prog 844 switch next { 845 case b.Succs[0].Block(): 846 p = s.Prog(jmp.invasm) 847 p.To.Type = obj.TYPE_BRANCH 848 p.From.Offset = b.Aux.(int64) 849 p.From.Type = obj.TYPE_CONST 850 p.Reg = b.Control.Reg() 851 s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()}) 852 case b.Succs[1].Block(): 853 p = s.Prog(jmp.asm) 854 p.To.Type = obj.TYPE_BRANCH 855 p.From.Offset = b.Aux.(int64) 856 p.From.Type = obj.TYPE_CONST 857 p.Reg = b.Control.Reg() 858 s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()}) 859 default: 860 p = s.Prog(jmp.asm) 861 p.To.Type = obj.TYPE_BRANCH 862 p.From.Offset = b.Aux.(int64) 863 p.From.Type = obj.TYPE_CONST 864 p.Reg = b.Control.Reg() 865 s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()}) 866 q := s.Prog(obj.AJMP) 867 q.To.Type = obj.TYPE_BRANCH 868 s.Branches = append(s.Branches, gc.Branch{P: q, B: b.Succs[1].Block()}) 869 } 870 871 default: 872 b.Fatalf("branch not implemented: %s. Control: %s", b.LongString(), b.Control.LongString()) 873 } 874 }