github.com/zebozhuang/go@v0.0.0-20200207033046-f8a98f6f5c5d/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.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 *ssa.ExternSymbol: 277 wantreg = "SB" 278 gc.AddAux(&p.From, v) 279 case *ssa.ArgSymbol, *ssa.AutoSymbol: 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.OpARM64MOVBstorezero, 328 ssa.OpARM64MOVHstorezero, 329 ssa.OpARM64MOVWstorezero, 330 ssa.OpARM64MOVDstorezero: 331 p := s.Prog(v.Op.Asm()) 332 p.From.Type = obj.TYPE_REG 333 p.From.Reg = arm64.REGZERO 334 p.To.Type = obj.TYPE_MEM 335 p.To.Reg = v.Args[0].Reg() 336 gc.AddAux(&p.To, v) 337 case ssa.OpARM64LoweredAtomicExchange64, 338 ssa.OpARM64LoweredAtomicExchange32: 339 // LDAXR (Rarg0), Rout 340 // STLXR Rarg1, (Rarg0), Rtmp 341 // CBNZ Rtmp, -2(PC) 342 ld := arm64.ALDAXR 343 st := arm64.ASTLXR 344 if v.Op == ssa.OpARM64LoweredAtomicExchange32 { 345 ld = arm64.ALDAXRW 346 st = arm64.ASTLXRW 347 } 348 r0 := v.Args[0].Reg() 349 r1 := v.Args[1].Reg() 350 out := v.Reg0() 351 p := s.Prog(ld) 352 p.From.Type = obj.TYPE_MEM 353 p.From.Reg = r0 354 p.To.Type = obj.TYPE_REG 355 p.To.Reg = out 356 p1 := s.Prog(st) 357 p1.From.Type = obj.TYPE_REG 358 p1.From.Reg = r1 359 p1.To.Type = obj.TYPE_MEM 360 p1.To.Reg = r0 361 p1.RegTo2 = arm64.REGTMP 362 p2 := s.Prog(arm64.ACBNZ) 363 p2.From.Type = obj.TYPE_REG 364 p2.From.Reg = arm64.REGTMP 365 p2.To.Type = obj.TYPE_BRANCH 366 gc.Patch(p2, p) 367 case ssa.OpARM64LoweredAtomicAdd64, 368 ssa.OpARM64LoweredAtomicAdd32: 369 // LDAXR (Rarg0), Rout 370 // ADD Rarg1, Rout 371 // STLXR Rout, (Rarg0), Rtmp 372 // CBNZ Rtmp, -3(PC) 373 ld := arm64.ALDAXR 374 st := arm64.ASTLXR 375 if v.Op == ssa.OpARM64LoweredAtomicAdd32 { 376 ld = arm64.ALDAXRW 377 st = arm64.ASTLXRW 378 } 379 r0 := v.Args[0].Reg() 380 r1 := v.Args[1].Reg() 381 out := v.Reg0() 382 p := s.Prog(ld) 383 p.From.Type = obj.TYPE_MEM 384 p.From.Reg = r0 385 p.To.Type = obj.TYPE_REG 386 p.To.Reg = out 387 p1 := s.Prog(arm64.AADD) 388 p1.From.Type = obj.TYPE_REG 389 p1.From.Reg = r1 390 p1.To.Type = obj.TYPE_REG 391 p1.To.Reg = out 392 p2 := s.Prog(st) 393 p2.From.Type = obj.TYPE_REG 394 p2.From.Reg = out 395 p2.To.Type = obj.TYPE_MEM 396 p2.To.Reg = r0 397 p2.RegTo2 = arm64.REGTMP 398 p3 := s.Prog(arm64.ACBNZ) 399 p3.From.Type = obj.TYPE_REG 400 p3.From.Reg = arm64.REGTMP 401 p3.To.Type = obj.TYPE_BRANCH 402 gc.Patch(p3, p) 403 case ssa.OpARM64LoweredAtomicCas64, 404 ssa.OpARM64LoweredAtomicCas32: 405 // LDAXR (Rarg0), Rtmp 406 // CMP Rarg1, Rtmp 407 // BNE 3(PC) 408 // STLXR Rarg2, (Rarg0), Rtmp 409 // CBNZ Rtmp, -4(PC) 410 // CSET EQ, Rout 411 ld := arm64.ALDAXR 412 st := arm64.ASTLXR 413 cmp := arm64.ACMP 414 if v.Op == ssa.OpARM64LoweredAtomicCas32 { 415 ld = arm64.ALDAXRW 416 st = arm64.ASTLXRW 417 cmp = arm64.ACMPW 418 } 419 r0 := v.Args[0].Reg() 420 r1 := v.Args[1].Reg() 421 r2 := v.Args[2].Reg() 422 out := v.Reg0() 423 p := s.Prog(ld) 424 p.From.Type = obj.TYPE_MEM 425 p.From.Reg = r0 426 p.To.Type = obj.TYPE_REG 427 p.To.Reg = arm64.REGTMP 428 p1 := s.Prog(cmp) 429 p1.From.Type = obj.TYPE_REG 430 p1.From.Reg = r1 431 p1.Reg = arm64.REGTMP 432 p2 := s.Prog(arm64.ABNE) 433 p2.To.Type = obj.TYPE_BRANCH 434 p3 := s.Prog(st) 435 p3.From.Type = obj.TYPE_REG 436 p3.From.Reg = r2 437 p3.To.Type = obj.TYPE_MEM 438 p3.To.Reg = r0 439 p3.RegTo2 = arm64.REGTMP 440 p4 := s.Prog(arm64.ACBNZ) 441 p4.From.Type = obj.TYPE_REG 442 p4.From.Reg = arm64.REGTMP 443 p4.To.Type = obj.TYPE_BRANCH 444 gc.Patch(p4, p) 445 p5 := s.Prog(arm64.ACSET) 446 p5.From.Type = obj.TYPE_REG // assembler encodes conditional bits in Reg 447 p5.From.Reg = arm64.COND_EQ 448 p5.To.Type = obj.TYPE_REG 449 p5.To.Reg = out 450 gc.Patch(p2, p5) 451 case ssa.OpARM64LoweredAtomicAnd8, 452 ssa.OpARM64LoweredAtomicOr8: 453 // LDAXRB (Rarg0), Rtmp 454 // AND/OR Rarg1, Rtmp 455 // STLXRB Rtmp, (Rarg0), Rtmp 456 // CBNZ Rtmp, -3(PC) 457 r0 := v.Args[0].Reg() 458 r1 := v.Args[1].Reg() 459 p := s.Prog(arm64.ALDAXRB) 460 p.From.Type = obj.TYPE_MEM 461 p.From.Reg = r0 462 p.To.Type = obj.TYPE_REG 463 p.To.Reg = arm64.REGTMP 464 p1 := s.Prog(v.Op.Asm()) 465 p1.From.Type = obj.TYPE_REG 466 p1.From.Reg = r1 467 p1.To.Type = obj.TYPE_REG 468 p1.To.Reg = arm64.REGTMP 469 p2 := s.Prog(arm64.ASTLXRB) 470 p2.From.Type = obj.TYPE_REG 471 p2.From.Reg = arm64.REGTMP 472 p2.To.Type = obj.TYPE_MEM 473 p2.To.Reg = r0 474 p2.RegTo2 = arm64.REGTMP 475 p3 := s.Prog(arm64.ACBNZ) 476 p3.From.Type = obj.TYPE_REG 477 p3.From.Reg = arm64.REGTMP 478 p3.To.Type = obj.TYPE_BRANCH 479 gc.Patch(p3, p) 480 case ssa.OpARM64MOVBreg, 481 ssa.OpARM64MOVBUreg, 482 ssa.OpARM64MOVHreg, 483 ssa.OpARM64MOVHUreg, 484 ssa.OpARM64MOVWreg, 485 ssa.OpARM64MOVWUreg: 486 a := v.Args[0] 487 for a.Op == ssa.OpCopy || a.Op == ssa.OpARM64MOVDreg { 488 a = a.Args[0] 489 } 490 if a.Op == ssa.OpLoadReg { 491 t := a.Type 492 switch { 493 case v.Op == ssa.OpARM64MOVBreg && t.Size() == 1 && t.IsSigned(), 494 v.Op == ssa.OpARM64MOVBUreg && t.Size() == 1 && !t.IsSigned(), 495 v.Op == ssa.OpARM64MOVHreg && t.Size() == 2 && t.IsSigned(), 496 v.Op == ssa.OpARM64MOVHUreg && t.Size() == 2 && !t.IsSigned(), 497 v.Op == ssa.OpARM64MOVWreg && t.Size() == 4 && t.IsSigned(), 498 v.Op == ssa.OpARM64MOVWUreg && t.Size() == 4 && !t.IsSigned(): 499 // arg is a proper-typed load, already zero/sign-extended, don't extend again 500 if v.Reg() == v.Args[0].Reg() { 501 return 502 } 503 p := s.Prog(arm64.AMOVD) 504 p.From.Type = obj.TYPE_REG 505 p.From.Reg = v.Args[0].Reg() 506 p.To.Type = obj.TYPE_REG 507 p.To.Reg = v.Reg() 508 return 509 default: 510 } 511 } 512 fallthrough 513 case ssa.OpARM64MVN, 514 ssa.OpARM64NEG, 515 ssa.OpARM64FNEGS, 516 ssa.OpARM64FNEGD, 517 ssa.OpARM64FSQRTD, 518 ssa.OpARM64FCVTZSSW, 519 ssa.OpARM64FCVTZSDW, 520 ssa.OpARM64FCVTZUSW, 521 ssa.OpARM64FCVTZUDW, 522 ssa.OpARM64FCVTZSS, 523 ssa.OpARM64FCVTZSD, 524 ssa.OpARM64FCVTZUS, 525 ssa.OpARM64FCVTZUD, 526 ssa.OpARM64SCVTFWS, 527 ssa.OpARM64SCVTFWD, 528 ssa.OpARM64SCVTFS, 529 ssa.OpARM64SCVTFD, 530 ssa.OpARM64UCVTFWS, 531 ssa.OpARM64UCVTFWD, 532 ssa.OpARM64UCVTFS, 533 ssa.OpARM64UCVTFD, 534 ssa.OpARM64FCVTSD, 535 ssa.OpARM64FCVTDS, 536 ssa.OpARM64REV, 537 ssa.OpARM64REVW, 538 ssa.OpARM64REV16W, 539 ssa.OpARM64RBIT, 540 ssa.OpARM64RBITW, 541 ssa.OpARM64CLZ, 542 ssa.OpARM64CLZW: 543 p := s.Prog(v.Op.Asm()) 544 p.From.Type = obj.TYPE_REG 545 p.From.Reg = v.Args[0].Reg() 546 p.To.Type = obj.TYPE_REG 547 p.To.Reg = v.Reg() 548 case ssa.OpARM64CSELULT, 549 ssa.OpARM64CSELULT0: 550 r1 := int16(arm64.REGZERO) 551 if v.Op == ssa.OpARM64CSELULT { 552 r1 = v.Args[1].Reg() 553 } 554 p := s.Prog(v.Op.Asm()) 555 p.From.Type = obj.TYPE_REG // assembler encodes conditional bits in Reg 556 p.From.Reg = arm64.COND_LO 557 p.Reg = v.Args[0].Reg() 558 p.From3 = &obj.Addr{Type: obj.TYPE_REG, Reg: r1} 559 p.To.Type = obj.TYPE_REG 560 p.To.Reg = v.Reg() 561 case ssa.OpARM64DUFFZERO: 562 // runtime.duffzero expects start address - 8 in R16 563 p := s.Prog(arm64.ASUB) 564 p.From.Type = obj.TYPE_CONST 565 p.From.Offset = 8 566 p.Reg = v.Args[0].Reg() 567 p.To.Type = obj.TYPE_REG 568 p.To.Reg = arm64.REG_R16 569 p = s.Prog(obj.ADUFFZERO) 570 p.To.Type = obj.TYPE_MEM 571 p.To.Name = obj.NAME_EXTERN 572 p.To.Sym = gc.Duffzero 573 p.To.Offset = v.AuxInt 574 case ssa.OpARM64LoweredZero: 575 // MOVD.P ZR, 8(R16) 576 // CMP Rarg1, R16 577 // BLE -2(PC) 578 // arg1 is the address of the last element to zero 579 p := s.Prog(arm64.AMOVD) 580 p.Scond = arm64.C_XPOST 581 p.From.Type = obj.TYPE_REG 582 p.From.Reg = arm64.REGZERO 583 p.To.Type = obj.TYPE_MEM 584 p.To.Reg = arm64.REG_R16 585 p.To.Offset = 8 586 p2 := s.Prog(arm64.ACMP) 587 p2.From.Type = obj.TYPE_REG 588 p2.From.Reg = v.Args[1].Reg() 589 p2.Reg = arm64.REG_R16 590 p3 := s.Prog(arm64.ABLE) 591 p3.To.Type = obj.TYPE_BRANCH 592 gc.Patch(p3, p) 593 case ssa.OpARM64DUFFCOPY: 594 p := s.Prog(obj.ADUFFCOPY) 595 p.To.Type = obj.TYPE_MEM 596 p.To.Name = obj.NAME_EXTERN 597 p.To.Sym = gc.Duffcopy 598 p.To.Offset = v.AuxInt 599 case ssa.OpARM64LoweredMove: 600 // MOVD.P 8(R16), Rtmp 601 // MOVD.P Rtmp, 8(R17) 602 // CMP Rarg2, R16 603 // BLE -3(PC) 604 // arg2 is the address of the last element of src 605 p := s.Prog(arm64.AMOVD) 606 p.Scond = arm64.C_XPOST 607 p.From.Type = obj.TYPE_MEM 608 p.From.Reg = arm64.REG_R16 609 p.From.Offset = 8 610 p.To.Type = obj.TYPE_REG 611 p.To.Reg = arm64.REGTMP 612 p2 := s.Prog(arm64.AMOVD) 613 p2.Scond = arm64.C_XPOST 614 p2.From.Type = obj.TYPE_REG 615 p2.From.Reg = arm64.REGTMP 616 p2.To.Type = obj.TYPE_MEM 617 p2.To.Reg = arm64.REG_R17 618 p2.To.Offset = 8 619 p3 := s.Prog(arm64.ACMP) 620 p3.From.Type = obj.TYPE_REG 621 p3.From.Reg = v.Args[2].Reg() 622 p3.Reg = arm64.REG_R16 623 p4 := s.Prog(arm64.ABLE) 624 p4.To.Type = obj.TYPE_BRANCH 625 gc.Patch(p4, p) 626 case ssa.OpARM64CALLstatic, ssa.OpARM64CALLclosure, ssa.OpARM64CALLinter: 627 s.Call(v) 628 case ssa.OpARM64LoweredNilCheck: 629 // Issue a load which will fault if arg is nil. 630 p := s.Prog(arm64.AMOVB) 631 p.From.Type = obj.TYPE_MEM 632 p.From.Reg = v.Args[0].Reg() 633 gc.AddAux(&p.From, v) 634 p.To.Type = obj.TYPE_REG 635 p.To.Reg = arm64.REGTMP 636 if gc.Debug_checknil != 0 && v.Pos.Line() > 1 { // v.Line==1 in generated wrappers 637 gc.Warnl(v.Pos, "generated nil check") 638 } 639 case ssa.OpARM64Equal, 640 ssa.OpARM64NotEqual, 641 ssa.OpARM64LessThan, 642 ssa.OpARM64LessEqual, 643 ssa.OpARM64GreaterThan, 644 ssa.OpARM64GreaterEqual, 645 ssa.OpARM64LessThanU, 646 ssa.OpARM64LessEqualU, 647 ssa.OpARM64GreaterThanU, 648 ssa.OpARM64GreaterEqualU: 649 // generate boolean values using CSET 650 p := s.Prog(arm64.ACSET) 651 p.From.Type = obj.TYPE_REG // assembler encodes conditional bits in Reg 652 p.From.Reg = condBits[v.Op] 653 p.To.Type = obj.TYPE_REG 654 p.To.Reg = v.Reg() 655 case ssa.OpARM64LoweredGetClosurePtr: 656 // Closure pointer is R26 (arm64.REGCTXT). 657 gc.CheckLoweredGetClosurePtr(v) 658 case ssa.OpARM64FlagEQ, 659 ssa.OpARM64FlagLT_ULT, 660 ssa.OpARM64FlagLT_UGT, 661 ssa.OpARM64FlagGT_ULT, 662 ssa.OpARM64FlagGT_UGT: 663 v.Fatalf("Flag* ops should never make it to codegen %v", v.LongString()) 664 case ssa.OpARM64InvertFlags: 665 v.Fatalf("InvertFlags should never make it to codegen %v", v.LongString()) 666 case ssa.OpClobber: 667 // TODO: implement for clobberdead experiment. Nop is ok for now. 668 default: 669 v.Fatalf("genValue not implemented: %s", v.LongString()) 670 } 671 } 672 673 var condBits = map[ssa.Op]int16{ 674 ssa.OpARM64Equal: arm64.COND_EQ, 675 ssa.OpARM64NotEqual: arm64.COND_NE, 676 ssa.OpARM64LessThan: arm64.COND_LT, 677 ssa.OpARM64LessThanU: arm64.COND_LO, 678 ssa.OpARM64LessEqual: arm64.COND_LE, 679 ssa.OpARM64LessEqualU: arm64.COND_LS, 680 ssa.OpARM64GreaterThan: arm64.COND_GT, 681 ssa.OpARM64GreaterThanU: arm64.COND_HI, 682 ssa.OpARM64GreaterEqual: arm64.COND_GE, 683 ssa.OpARM64GreaterEqualU: arm64.COND_HS, 684 } 685 686 var blockJump = map[ssa.BlockKind]struct { 687 asm, invasm obj.As 688 }{ 689 ssa.BlockARM64EQ: {arm64.ABEQ, arm64.ABNE}, 690 ssa.BlockARM64NE: {arm64.ABNE, arm64.ABEQ}, 691 ssa.BlockARM64LT: {arm64.ABLT, arm64.ABGE}, 692 ssa.BlockARM64GE: {arm64.ABGE, arm64.ABLT}, 693 ssa.BlockARM64LE: {arm64.ABLE, arm64.ABGT}, 694 ssa.BlockARM64GT: {arm64.ABGT, arm64.ABLE}, 695 ssa.BlockARM64ULT: {arm64.ABLO, arm64.ABHS}, 696 ssa.BlockARM64UGE: {arm64.ABHS, arm64.ABLO}, 697 ssa.BlockARM64UGT: {arm64.ABHI, arm64.ABLS}, 698 ssa.BlockARM64ULE: {arm64.ABLS, arm64.ABHI}, 699 ssa.BlockARM64Z: {arm64.ACBZ, arm64.ACBNZ}, 700 ssa.BlockARM64NZ: {arm64.ACBNZ, arm64.ACBZ}, 701 ssa.BlockARM64ZW: {arm64.ACBZW, arm64.ACBNZW}, 702 ssa.BlockARM64NZW: {arm64.ACBNZW, arm64.ACBZW}, 703 } 704 705 func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) { 706 switch b.Kind { 707 case ssa.BlockPlain: 708 if b.Succs[0].Block() != next { 709 p := s.Prog(obj.AJMP) 710 p.To.Type = obj.TYPE_BRANCH 711 s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()}) 712 } 713 714 case ssa.BlockDefer: 715 // defer returns in R0: 716 // 0 if we should continue executing 717 // 1 if we should jump to deferreturn call 718 p := s.Prog(arm64.ACMP) 719 p.From.Type = obj.TYPE_CONST 720 p.From.Offset = 0 721 p.Reg = arm64.REG_R0 722 p = s.Prog(arm64.ABNE) 723 p.To.Type = obj.TYPE_BRANCH 724 s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()}) 725 if b.Succs[0].Block() != next { 726 p := s.Prog(obj.AJMP) 727 p.To.Type = obj.TYPE_BRANCH 728 s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()}) 729 } 730 731 case ssa.BlockExit: 732 s.Prog(obj.AUNDEF) // tell plive.go that we never reach here 733 734 case ssa.BlockRet: 735 s.Prog(obj.ARET) 736 737 case ssa.BlockRetJmp: 738 p := s.Prog(obj.ARET) 739 p.To.Type = obj.TYPE_MEM 740 p.To.Name = obj.NAME_EXTERN 741 p.To.Sym = b.Aux.(*obj.LSym) 742 743 case ssa.BlockARM64EQ, ssa.BlockARM64NE, 744 ssa.BlockARM64LT, ssa.BlockARM64GE, 745 ssa.BlockARM64LE, ssa.BlockARM64GT, 746 ssa.BlockARM64ULT, ssa.BlockARM64UGT, 747 ssa.BlockARM64ULE, ssa.BlockARM64UGE, 748 ssa.BlockARM64Z, ssa.BlockARM64NZ, 749 ssa.BlockARM64ZW, ssa.BlockARM64NZW: 750 jmp := blockJump[b.Kind] 751 var p *obj.Prog 752 switch next { 753 case b.Succs[0].Block(): 754 p = s.Prog(jmp.invasm) 755 p.To.Type = obj.TYPE_BRANCH 756 s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()}) 757 case b.Succs[1].Block(): 758 p = s.Prog(jmp.asm) 759 p.To.Type = obj.TYPE_BRANCH 760 s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()}) 761 default: 762 p = s.Prog(jmp.asm) 763 p.To.Type = obj.TYPE_BRANCH 764 s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()}) 765 q := s.Prog(obj.AJMP) 766 q.To.Type = obj.TYPE_BRANCH 767 s.Branches = append(s.Branches, gc.Branch{P: q, B: b.Succs[1].Block()}) 768 } 769 if !b.Control.Type.IsFlags() { 770 p.From.Type = obj.TYPE_REG 771 p.From.Reg = b.Control.Reg() 772 } 773 774 default: 775 b.Fatalf("branch not implemented: %s. Control: %s", b.LongString(), b.Control.LongString()) 776 } 777 }