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