github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/compile/internal/arm/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 arm 6 7 import ( 8 "fmt" 9 "math" 10 "math/bits" 11 12 "github.com/gagliardetto/golang-go/cmd/compile/internal/gc" 13 "github.com/gagliardetto/golang-go/cmd/compile/internal/logopt" 14 "github.com/gagliardetto/golang-go/cmd/compile/internal/ssa" 15 "github.com/gagliardetto/golang-go/cmd/compile/internal/types" 16 "github.com/gagliardetto/golang-go/cmd/internal/obj" 17 "github.com/gagliardetto/golang-go/cmd/internal/obj/arm" 18 "github.com/gagliardetto/golang-go/cmd/internal/objabi" 19 ) 20 21 // loadByType returns the load instruction of the given type. 22 func loadByType(t *types.Type) obj.As { 23 if t.IsFloat() { 24 switch t.Size() { 25 case 4: 26 return arm.AMOVF 27 case 8: 28 return arm.AMOVD 29 } 30 } else { 31 switch t.Size() { 32 case 1: 33 if t.IsSigned() { 34 return arm.AMOVB 35 } else { 36 return arm.AMOVBU 37 } 38 case 2: 39 if t.IsSigned() { 40 return arm.AMOVH 41 } else { 42 return arm.AMOVHU 43 } 44 case 4: 45 return arm.AMOVW 46 } 47 } 48 panic("bad load type") 49 } 50 51 // storeByType returns the store instruction of the given type. 52 func storeByType(t *types.Type) obj.As { 53 if t.IsFloat() { 54 switch t.Size() { 55 case 4: 56 return arm.AMOVF 57 case 8: 58 return arm.AMOVD 59 } 60 } else { 61 switch t.Size() { 62 case 1: 63 return arm.AMOVB 64 case 2: 65 return arm.AMOVH 66 case 4: 67 return arm.AMOVW 68 } 69 } 70 panic("bad store type") 71 } 72 73 // shift type is used as Offset in obj.TYPE_SHIFT operands to encode shifted register operands 74 type shift int64 75 76 // copied from ../../../internal/obj/util.go:/TYPE_SHIFT 77 func (v shift) String() string { 78 op := "<<>>->@>"[((v>>5)&3)<<1:] 79 if v&(1<<4) != 0 { 80 // register shift 81 return fmt.Sprintf("R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15) 82 } else { 83 // constant shift 84 return fmt.Sprintf("R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31) 85 } 86 } 87 88 // makeshift encodes a register shifted by a constant 89 func makeshift(reg int16, typ int64, s int64) shift { 90 return shift(int64(reg&0xf) | typ | (s&31)<<7) 91 } 92 93 // genshift generates a Prog for r = r0 op (r1 shifted by n) 94 func genshift(s *gc.SSAGenState, as obj.As, r0, r1, r int16, typ int64, n int64) *obj.Prog { 95 p := s.Prog(as) 96 p.From.Type = obj.TYPE_SHIFT 97 p.From.Offset = int64(makeshift(r1, typ, n)) 98 p.Reg = r0 99 if r != 0 { 100 p.To.Type = obj.TYPE_REG 101 p.To.Reg = r 102 } 103 return p 104 } 105 106 // makeregshift encodes a register shifted by a register 107 func makeregshift(r1 int16, typ int64, r2 int16) shift { 108 return shift(int64(r1&0xf) | typ | int64(r2&0xf)<<8 | 1<<4) 109 } 110 111 // genregshift generates a Prog for r = r0 op (r1 shifted by r2) 112 func genregshift(s *gc.SSAGenState, as obj.As, r0, r1, r2, r int16, typ int64) *obj.Prog { 113 p := s.Prog(as) 114 p.From.Type = obj.TYPE_SHIFT 115 p.From.Offset = int64(makeregshift(r1, typ, r2)) 116 p.Reg = r0 117 if r != 0 { 118 p.To.Type = obj.TYPE_REG 119 p.To.Reg = r 120 } 121 return p 122 } 123 124 // find a (lsb, width) pair for BFC 125 // lsb must be in [0, 31], width must be in [1, 32 - lsb] 126 // return (0xffffffff, 0) if v is not a binary like 0...01...10...0 127 func getBFC(v uint32) (uint32, uint32) { 128 var m, l uint32 129 // BFC is not applicable with zero 130 if v == 0 { 131 return 0xffffffff, 0 132 } 133 // find the lowest set bit, for example l=2 for 0x3ffffffc 134 l = uint32(bits.TrailingZeros32(v)) 135 // m-1 represents the highest set bit index, for example m=30 for 0x3ffffffc 136 m = 32 - uint32(bits.LeadingZeros32(v)) 137 // check if v is a binary like 0...01...10...0 138 if (1<<m)-(1<<l) == v { 139 // it must be m > l for non-zero v 140 return l, m - l 141 } 142 // invalid 143 return 0xffffffff, 0 144 } 145 146 func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { 147 switch v.Op { 148 case ssa.OpCopy, ssa.OpARMMOVWreg: 149 if v.Type.IsMemory() { 150 return 151 } 152 x := v.Args[0].Reg() 153 y := v.Reg() 154 if x == y { 155 return 156 } 157 as := arm.AMOVW 158 if v.Type.IsFloat() { 159 switch v.Type.Size() { 160 case 4: 161 as = arm.AMOVF 162 case 8: 163 as = arm.AMOVD 164 default: 165 panic("bad float size") 166 } 167 } 168 p := s.Prog(as) 169 p.From.Type = obj.TYPE_REG 170 p.From.Reg = x 171 p.To.Type = obj.TYPE_REG 172 p.To.Reg = y 173 case ssa.OpARMMOVWnop: 174 if v.Reg() != v.Args[0].Reg() { 175 v.Fatalf("input[0] and output not in same register %s", v.LongString()) 176 } 177 // nothing to do 178 case ssa.OpLoadReg: 179 if v.Type.IsFlags() { 180 v.Fatalf("load flags not implemented: %v", v.LongString()) 181 return 182 } 183 p := s.Prog(loadByType(v.Type)) 184 gc.AddrAuto(&p.From, v.Args[0]) 185 p.To.Type = obj.TYPE_REG 186 p.To.Reg = v.Reg() 187 case ssa.OpStoreReg: 188 if v.Type.IsFlags() { 189 v.Fatalf("store flags not implemented: %v", v.LongString()) 190 return 191 } 192 p := s.Prog(storeByType(v.Type)) 193 p.From.Type = obj.TYPE_REG 194 p.From.Reg = v.Args[0].Reg() 195 gc.AddrAuto(&p.To, v) 196 case ssa.OpARMADD, 197 ssa.OpARMADC, 198 ssa.OpARMSUB, 199 ssa.OpARMSBC, 200 ssa.OpARMRSB, 201 ssa.OpARMAND, 202 ssa.OpARMOR, 203 ssa.OpARMXOR, 204 ssa.OpARMBIC, 205 ssa.OpARMMUL, 206 ssa.OpARMADDF, 207 ssa.OpARMADDD, 208 ssa.OpARMSUBF, 209 ssa.OpARMSUBD, 210 ssa.OpARMSLL, 211 ssa.OpARMSRL, 212 ssa.OpARMSRA, 213 ssa.OpARMMULF, 214 ssa.OpARMMULD, 215 ssa.OpARMNMULF, 216 ssa.OpARMNMULD, 217 ssa.OpARMDIVF, 218 ssa.OpARMDIVD: 219 r := v.Reg() 220 r1 := v.Args[0].Reg() 221 r2 := v.Args[1].Reg() 222 p := s.Prog(v.Op.Asm()) 223 p.From.Type = obj.TYPE_REG 224 p.From.Reg = r2 225 p.Reg = r1 226 p.To.Type = obj.TYPE_REG 227 p.To.Reg = r 228 case ssa.OpARMSRR: 229 genregshift(s, arm.AMOVW, 0, v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm.SHIFT_RR) 230 case ssa.OpARMMULAF, ssa.OpARMMULAD, ssa.OpARMMULSF, ssa.OpARMMULSD, ssa.OpARMFMULAD: 231 r := v.Reg() 232 r0 := v.Args[0].Reg() 233 r1 := v.Args[1].Reg() 234 r2 := v.Args[2].Reg() 235 if r != r0 { 236 v.Fatalf("result and addend are not in the same register: %v", v.LongString()) 237 } 238 p := s.Prog(v.Op.Asm()) 239 p.From.Type = obj.TYPE_REG 240 p.From.Reg = r2 241 p.Reg = r1 242 p.To.Type = obj.TYPE_REG 243 p.To.Reg = r 244 case ssa.OpARMADDS, 245 ssa.OpARMSUBS: 246 r := v.Reg0() 247 r1 := v.Args[0].Reg() 248 r2 := v.Args[1].Reg() 249 p := s.Prog(v.Op.Asm()) 250 p.Scond = arm.C_SBIT 251 p.From.Type = obj.TYPE_REG 252 p.From.Reg = r2 253 p.Reg = r1 254 p.To.Type = obj.TYPE_REG 255 p.To.Reg = r 256 case ssa.OpARMSRAcond: 257 // ARM shift instructions uses only the low-order byte of the shift amount 258 // generate conditional instructions to deal with large shifts 259 // flag is already set 260 // SRA.HS $31, Rarg0, Rdst // shift 31 bits to get the sign bit 261 // SRA.LO Rarg1, Rarg0, Rdst 262 r := v.Reg() 263 r1 := v.Args[0].Reg() 264 r2 := v.Args[1].Reg() 265 p := s.Prog(arm.ASRA) 266 p.Scond = arm.C_SCOND_HS 267 p.From.Type = obj.TYPE_CONST 268 p.From.Offset = 31 269 p.Reg = r1 270 p.To.Type = obj.TYPE_REG 271 p.To.Reg = r 272 p = s.Prog(arm.ASRA) 273 p.Scond = arm.C_SCOND_LO 274 p.From.Type = obj.TYPE_REG 275 p.From.Reg = r2 276 p.Reg = r1 277 p.To.Type = obj.TYPE_REG 278 p.To.Reg = r 279 case ssa.OpARMBFX, ssa.OpARMBFXU: 280 p := s.Prog(v.Op.Asm()) 281 p.From.Type = obj.TYPE_CONST 282 p.From.Offset = v.AuxInt >> 8 283 p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: v.AuxInt & 0xff}) 284 p.Reg = v.Args[0].Reg() 285 p.To.Type = obj.TYPE_REG 286 p.To.Reg = v.Reg() 287 case ssa.OpARMANDconst, ssa.OpARMBICconst: 288 // try to optimize ANDconst and BICconst to BFC, which saves bytes and ticks 289 // BFC is only available on ARMv7, and its result and source are in the same register 290 if objabi.GOARM == 7 && v.Reg() == v.Args[0].Reg() { 291 var val uint32 292 if v.Op == ssa.OpARMANDconst { 293 val = ^uint32(v.AuxInt) 294 } else { // BICconst 295 val = uint32(v.AuxInt) 296 } 297 lsb, width := getBFC(val) 298 // omit BFC for ARM's imm12 299 if 8 < width && width < 24 { 300 p := s.Prog(arm.ABFC) 301 p.From.Type = obj.TYPE_CONST 302 p.From.Offset = int64(width) 303 p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: int64(lsb)}) 304 p.To.Type = obj.TYPE_REG 305 p.To.Reg = v.Reg() 306 break 307 } 308 } 309 // fall back to ordinary form 310 fallthrough 311 case ssa.OpARMADDconst, 312 ssa.OpARMADCconst, 313 ssa.OpARMSUBconst, 314 ssa.OpARMSBCconst, 315 ssa.OpARMRSBconst, 316 ssa.OpARMRSCconst, 317 ssa.OpARMORconst, 318 ssa.OpARMXORconst, 319 ssa.OpARMSLLconst, 320 ssa.OpARMSRLconst, 321 ssa.OpARMSRAconst: 322 p := s.Prog(v.Op.Asm()) 323 p.From.Type = obj.TYPE_CONST 324 p.From.Offset = v.AuxInt 325 p.Reg = v.Args[0].Reg() 326 p.To.Type = obj.TYPE_REG 327 p.To.Reg = v.Reg() 328 case ssa.OpARMADDSconst, 329 ssa.OpARMSUBSconst, 330 ssa.OpARMRSBSconst: 331 p := s.Prog(v.Op.Asm()) 332 p.Scond = arm.C_SBIT 333 p.From.Type = obj.TYPE_CONST 334 p.From.Offset = v.AuxInt 335 p.Reg = v.Args[0].Reg() 336 p.To.Type = obj.TYPE_REG 337 p.To.Reg = v.Reg0() 338 case ssa.OpARMSRRconst: 339 genshift(s, arm.AMOVW, 0, v.Args[0].Reg(), v.Reg(), arm.SHIFT_RR, v.AuxInt) 340 case ssa.OpARMADDshiftLL, 341 ssa.OpARMADCshiftLL, 342 ssa.OpARMSUBshiftLL, 343 ssa.OpARMSBCshiftLL, 344 ssa.OpARMRSBshiftLL, 345 ssa.OpARMRSCshiftLL, 346 ssa.OpARMANDshiftLL, 347 ssa.OpARMORshiftLL, 348 ssa.OpARMXORshiftLL, 349 ssa.OpARMBICshiftLL: 350 genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm.SHIFT_LL, v.AuxInt) 351 case ssa.OpARMADDSshiftLL, 352 ssa.OpARMSUBSshiftLL, 353 ssa.OpARMRSBSshiftLL: 354 p := genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg0(), arm.SHIFT_LL, v.AuxInt) 355 p.Scond = arm.C_SBIT 356 case ssa.OpARMADDshiftRL, 357 ssa.OpARMADCshiftRL, 358 ssa.OpARMSUBshiftRL, 359 ssa.OpARMSBCshiftRL, 360 ssa.OpARMRSBshiftRL, 361 ssa.OpARMRSCshiftRL, 362 ssa.OpARMANDshiftRL, 363 ssa.OpARMORshiftRL, 364 ssa.OpARMXORshiftRL, 365 ssa.OpARMBICshiftRL: 366 genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm.SHIFT_LR, v.AuxInt) 367 case ssa.OpARMADDSshiftRL, 368 ssa.OpARMSUBSshiftRL, 369 ssa.OpARMRSBSshiftRL: 370 p := genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg0(), arm.SHIFT_LR, v.AuxInt) 371 p.Scond = arm.C_SBIT 372 case ssa.OpARMADDshiftRA, 373 ssa.OpARMADCshiftRA, 374 ssa.OpARMSUBshiftRA, 375 ssa.OpARMSBCshiftRA, 376 ssa.OpARMRSBshiftRA, 377 ssa.OpARMRSCshiftRA, 378 ssa.OpARMANDshiftRA, 379 ssa.OpARMORshiftRA, 380 ssa.OpARMXORshiftRA, 381 ssa.OpARMBICshiftRA: 382 genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm.SHIFT_AR, v.AuxInt) 383 case ssa.OpARMADDSshiftRA, 384 ssa.OpARMSUBSshiftRA, 385 ssa.OpARMRSBSshiftRA: 386 p := genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg0(), arm.SHIFT_AR, v.AuxInt) 387 p.Scond = arm.C_SBIT 388 case ssa.OpARMXORshiftRR: 389 genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm.SHIFT_RR, v.AuxInt) 390 case ssa.OpARMMVNshiftLL: 391 genshift(s, v.Op.Asm(), 0, v.Args[0].Reg(), v.Reg(), arm.SHIFT_LL, v.AuxInt) 392 case ssa.OpARMMVNshiftRL: 393 genshift(s, v.Op.Asm(), 0, v.Args[0].Reg(), v.Reg(), arm.SHIFT_LR, v.AuxInt) 394 case ssa.OpARMMVNshiftRA: 395 genshift(s, v.Op.Asm(), 0, v.Args[0].Reg(), v.Reg(), arm.SHIFT_AR, v.AuxInt) 396 case ssa.OpARMMVNshiftLLreg: 397 genregshift(s, v.Op.Asm(), 0, v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm.SHIFT_LL) 398 case ssa.OpARMMVNshiftRLreg: 399 genregshift(s, v.Op.Asm(), 0, v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm.SHIFT_LR) 400 case ssa.OpARMMVNshiftRAreg: 401 genregshift(s, v.Op.Asm(), 0, v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm.SHIFT_AR) 402 case ssa.OpARMADDshiftLLreg, 403 ssa.OpARMADCshiftLLreg, 404 ssa.OpARMSUBshiftLLreg, 405 ssa.OpARMSBCshiftLLreg, 406 ssa.OpARMRSBshiftLLreg, 407 ssa.OpARMRSCshiftLLreg, 408 ssa.OpARMANDshiftLLreg, 409 ssa.OpARMORshiftLLreg, 410 ssa.OpARMXORshiftLLreg, 411 ssa.OpARMBICshiftLLreg: 412 genregshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Args[2].Reg(), v.Reg(), arm.SHIFT_LL) 413 case ssa.OpARMADDSshiftLLreg, 414 ssa.OpARMSUBSshiftLLreg, 415 ssa.OpARMRSBSshiftLLreg: 416 p := genregshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Args[2].Reg(), v.Reg0(), arm.SHIFT_LL) 417 p.Scond = arm.C_SBIT 418 case ssa.OpARMADDshiftRLreg, 419 ssa.OpARMADCshiftRLreg, 420 ssa.OpARMSUBshiftRLreg, 421 ssa.OpARMSBCshiftRLreg, 422 ssa.OpARMRSBshiftRLreg, 423 ssa.OpARMRSCshiftRLreg, 424 ssa.OpARMANDshiftRLreg, 425 ssa.OpARMORshiftRLreg, 426 ssa.OpARMXORshiftRLreg, 427 ssa.OpARMBICshiftRLreg: 428 genregshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Args[2].Reg(), v.Reg(), arm.SHIFT_LR) 429 case ssa.OpARMADDSshiftRLreg, 430 ssa.OpARMSUBSshiftRLreg, 431 ssa.OpARMRSBSshiftRLreg: 432 p := genregshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Args[2].Reg(), v.Reg0(), arm.SHIFT_LR) 433 p.Scond = arm.C_SBIT 434 case ssa.OpARMADDshiftRAreg, 435 ssa.OpARMADCshiftRAreg, 436 ssa.OpARMSUBshiftRAreg, 437 ssa.OpARMSBCshiftRAreg, 438 ssa.OpARMRSBshiftRAreg, 439 ssa.OpARMRSCshiftRAreg, 440 ssa.OpARMANDshiftRAreg, 441 ssa.OpARMORshiftRAreg, 442 ssa.OpARMXORshiftRAreg, 443 ssa.OpARMBICshiftRAreg: 444 genregshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Args[2].Reg(), v.Reg(), arm.SHIFT_AR) 445 case ssa.OpARMADDSshiftRAreg, 446 ssa.OpARMSUBSshiftRAreg, 447 ssa.OpARMRSBSshiftRAreg: 448 p := genregshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Args[2].Reg(), v.Reg0(), arm.SHIFT_AR) 449 p.Scond = arm.C_SBIT 450 case ssa.OpARMHMUL, 451 ssa.OpARMHMULU: 452 // 32-bit high multiplication 453 p := s.Prog(v.Op.Asm()) 454 p.From.Type = obj.TYPE_REG 455 p.From.Reg = v.Args[0].Reg() 456 p.Reg = v.Args[1].Reg() 457 p.To.Type = obj.TYPE_REGREG 458 p.To.Reg = v.Reg() 459 p.To.Offset = arm.REGTMP // throw away low 32-bit into tmp register 460 case ssa.OpARMMULLU: 461 // 32-bit multiplication, results 64-bit, high 32-bit in out0, low 32-bit in out1 462 p := s.Prog(v.Op.Asm()) 463 p.From.Type = obj.TYPE_REG 464 p.From.Reg = v.Args[0].Reg() 465 p.Reg = v.Args[1].Reg() 466 p.To.Type = obj.TYPE_REGREG 467 p.To.Reg = v.Reg0() // high 32-bit 468 p.To.Offset = int64(v.Reg1()) // low 32-bit 469 case ssa.OpARMMULA, ssa.OpARMMULS: 470 p := s.Prog(v.Op.Asm()) 471 p.From.Type = obj.TYPE_REG 472 p.From.Reg = v.Args[0].Reg() 473 p.Reg = v.Args[1].Reg() 474 p.To.Type = obj.TYPE_REGREG2 475 p.To.Reg = v.Reg() // result 476 p.To.Offset = int64(v.Args[2].Reg()) // addend 477 case ssa.OpARMMOVWconst: 478 p := s.Prog(v.Op.Asm()) 479 p.From.Type = obj.TYPE_CONST 480 p.From.Offset = v.AuxInt 481 p.To.Type = obj.TYPE_REG 482 p.To.Reg = v.Reg() 483 case ssa.OpARMMOVFconst, 484 ssa.OpARMMOVDconst: 485 p := s.Prog(v.Op.Asm()) 486 p.From.Type = obj.TYPE_FCONST 487 p.From.Val = math.Float64frombits(uint64(v.AuxInt)) 488 p.To.Type = obj.TYPE_REG 489 p.To.Reg = v.Reg() 490 case ssa.OpARMCMP, 491 ssa.OpARMCMN, 492 ssa.OpARMTST, 493 ssa.OpARMTEQ, 494 ssa.OpARMCMPF, 495 ssa.OpARMCMPD: 496 p := s.Prog(v.Op.Asm()) 497 p.From.Type = obj.TYPE_REG 498 // Special layout in ARM assembly 499 // Comparing to x86, the operands of ARM's CMP are reversed. 500 p.From.Reg = v.Args[1].Reg() 501 p.Reg = v.Args[0].Reg() 502 case ssa.OpARMCMPconst, 503 ssa.OpARMCMNconst, 504 ssa.OpARMTSTconst, 505 ssa.OpARMTEQconst: 506 // Special layout in ARM assembly 507 p := s.Prog(v.Op.Asm()) 508 p.From.Type = obj.TYPE_CONST 509 p.From.Offset = v.AuxInt 510 p.Reg = v.Args[0].Reg() 511 case ssa.OpARMCMPF0, 512 ssa.OpARMCMPD0: 513 p := s.Prog(v.Op.Asm()) 514 p.From.Type = obj.TYPE_REG 515 p.From.Reg = v.Args[0].Reg() 516 case ssa.OpARMCMPshiftLL, ssa.OpARMCMNshiftLL, ssa.OpARMTSTshiftLL, ssa.OpARMTEQshiftLL: 517 genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), 0, arm.SHIFT_LL, v.AuxInt) 518 case ssa.OpARMCMPshiftRL, ssa.OpARMCMNshiftRL, ssa.OpARMTSTshiftRL, ssa.OpARMTEQshiftRL: 519 genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), 0, arm.SHIFT_LR, v.AuxInt) 520 case ssa.OpARMCMPshiftRA, ssa.OpARMCMNshiftRA, ssa.OpARMTSTshiftRA, ssa.OpARMTEQshiftRA: 521 genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), 0, arm.SHIFT_AR, v.AuxInt) 522 case ssa.OpARMCMPshiftLLreg, ssa.OpARMCMNshiftLLreg, ssa.OpARMTSTshiftLLreg, ssa.OpARMTEQshiftLLreg: 523 genregshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Args[2].Reg(), 0, arm.SHIFT_LL) 524 case ssa.OpARMCMPshiftRLreg, ssa.OpARMCMNshiftRLreg, ssa.OpARMTSTshiftRLreg, ssa.OpARMTEQshiftRLreg: 525 genregshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Args[2].Reg(), 0, arm.SHIFT_LR) 526 case ssa.OpARMCMPshiftRAreg, ssa.OpARMCMNshiftRAreg, ssa.OpARMTSTshiftRAreg, ssa.OpARMTEQshiftRAreg: 527 genregshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Args[2].Reg(), 0, arm.SHIFT_AR) 528 case ssa.OpARMMOVWaddr: 529 p := s.Prog(arm.AMOVW) 530 p.From.Type = obj.TYPE_ADDR 531 p.From.Reg = v.Args[0].Reg() 532 p.To.Type = obj.TYPE_REG 533 p.To.Reg = v.Reg() 534 535 var wantreg string 536 // MOVW $sym+off(base), R 537 // the assembler expands it as the following: 538 // - base is SP: add constant offset to SP (R13) 539 // when constant is large, tmp register (R11) may be used 540 // - base is SB: load external address from constant pool (use relocation) 541 switch v.Aux.(type) { 542 default: 543 v.Fatalf("aux is of unknown type %T", v.Aux) 544 case *obj.LSym: 545 wantreg = "SB" 546 gc.AddAux(&p.From, v) 547 case *gc.Node: 548 wantreg = "SP" 549 gc.AddAux(&p.From, v) 550 case nil: 551 // No sym, just MOVW $off(SP), R 552 wantreg = "SP" 553 p.From.Offset = v.AuxInt 554 } 555 if reg := v.Args[0].RegName(); reg != wantreg { 556 v.Fatalf("bad reg %s for symbol type %T, want %s", reg, v.Aux, wantreg) 557 } 558 559 case ssa.OpARMMOVBload, 560 ssa.OpARMMOVBUload, 561 ssa.OpARMMOVHload, 562 ssa.OpARMMOVHUload, 563 ssa.OpARMMOVWload, 564 ssa.OpARMMOVFload, 565 ssa.OpARMMOVDload: 566 p := s.Prog(v.Op.Asm()) 567 p.From.Type = obj.TYPE_MEM 568 p.From.Reg = v.Args[0].Reg() 569 gc.AddAux(&p.From, v) 570 p.To.Type = obj.TYPE_REG 571 p.To.Reg = v.Reg() 572 case ssa.OpARMMOVBstore, 573 ssa.OpARMMOVHstore, 574 ssa.OpARMMOVWstore, 575 ssa.OpARMMOVFstore, 576 ssa.OpARMMOVDstore: 577 p := s.Prog(v.Op.Asm()) 578 p.From.Type = obj.TYPE_REG 579 p.From.Reg = v.Args[1].Reg() 580 p.To.Type = obj.TYPE_MEM 581 p.To.Reg = v.Args[0].Reg() 582 gc.AddAux(&p.To, v) 583 case ssa.OpARMMOVWloadidx, ssa.OpARMMOVBUloadidx, ssa.OpARMMOVBloadidx, ssa.OpARMMOVHUloadidx, ssa.OpARMMOVHloadidx: 584 // this is just shift 0 bits 585 fallthrough 586 case ssa.OpARMMOVWloadshiftLL: 587 p := genshift(s, v.Op.Asm(), 0, v.Args[1].Reg(), v.Reg(), arm.SHIFT_LL, v.AuxInt) 588 p.From.Reg = v.Args[0].Reg() 589 case ssa.OpARMMOVWloadshiftRL: 590 p := genshift(s, v.Op.Asm(), 0, v.Args[1].Reg(), v.Reg(), arm.SHIFT_LR, v.AuxInt) 591 p.From.Reg = v.Args[0].Reg() 592 case ssa.OpARMMOVWloadshiftRA: 593 p := genshift(s, v.Op.Asm(), 0, v.Args[1].Reg(), v.Reg(), arm.SHIFT_AR, v.AuxInt) 594 p.From.Reg = v.Args[0].Reg() 595 case ssa.OpARMMOVWstoreidx, ssa.OpARMMOVBstoreidx, ssa.OpARMMOVHstoreidx: 596 // this is just shift 0 bits 597 fallthrough 598 case ssa.OpARMMOVWstoreshiftLL: 599 p := s.Prog(v.Op.Asm()) 600 p.From.Type = obj.TYPE_REG 601 p.From.Reg = v.Args[2].Reg() 602 p.To.Type = obj.TYPE_SHIFT 603 p.To.Reg = v.Args[0].Reg() 604 p.To.Offset = int64(makeshift(v.Args[1].Reg(), arm.SHIFT_LL, v.AuxInt)) 605 case ssa.OpARMMOVWstoreshiftRL: 606 p := s.Prog(v.Op.Asm()) 607 p.From.Type = obj.TYPE_REG 608 p.From.Reg = v.Args[2].Reg() 609 p.To.Type = obj.TYPE_SHIFT 610 p.To.Reg = v.Args[0].Reg() 611 p.To.Offset = int64(makeshift(v.Args[1].Reg(), arm.SHIFT_LR, v.AuxInt)) 612 case ssa.OpARMMOVWstoreshiftRA: 613 p := s.Prog(v.Op.Asm()) 614 p.From.Type = obj.TYPE_REG 615 p.From.Reg = v.Args[2].Reg() 616 p.To.Type = obj.TYPE_SHIFT 617 p.To.Reg = v.Args[0].Reg() 618 p.To.Offset = int64(makeshift(v.Args[1].Reg(), arm.SHIFT_AR, v.AuxInt)) 619 case ssa.OpARMMOVBreg, 620 ssa.OpARMMOVBUreg, 621 ssa.OpARMMOVHreg, 622 ssa.OpARMMOVHUreg: 623 a := v.Args[0] 624 for a.Op == ssa.OpCopy || a.Op == ssa.OpARMMOVWreg || a.Op == ssa.OpARMMOVWnop { 625 a = a.Args[0] 626 } 627 if a.Op == ssa.OpLoadReg { 628 t := a.Type 629 switch { 630 case v.Op == ssa.OpARMMOVBreg && t.Size() == 1 && t.IsSigned(), 631 v.Op == ssa.OpARMMOVBUreg && t.Size() == 1 && !t.IsSigned(), 632 v.Op == ssa.OpARMMOVHreg && t.Size() == 2 && t.IsSigned(), 633 v.Op == ssa.OpARMMOVHUreg && t.Size() == 2 && !t.IsSigned(): 634 // arg is a proper-typed load, already zero/sign-extended, don't extend again 635 if v.Reg() == v.Args[0].Reg() { 636 return 637 } 638 p := s.Prog(arm.AMOVW) 639 p.From.Type = obj.TYPE_REG 640 p.From.Reg = v.Args[0].Reg() 641 p.To.Type = obj.TYPE_REG 642 p.To.Reg = v.Reg() 643 return 644 default: 645 } 646 } 647 if objabi.GOARM >= 6 { 648 // generate more efficient "MOVB/MOVBU/MOVH/MOVHU Reg@>0, Reg" on ARMv6 & ARMv7 649 genshift(s, v.Op.Asm(), 0, v.Args[0].Reg(), v.Reg(), arm.SHIFT_RR, 0) 650 return 651 } 652 fallthrough 653 case ssa.OpARMMVN, 654 ssa.OpARMCLZ, 655 ssa.OpARMREV, 656 ssa.OpARMREV16, 657 ssa.OpARMRBIT, 658 ssa.OpARMSQRTD, 659 ssa.OpARMNEGF, 660 ssa.OpARMNEGD, 661 ssa.OpARMABSD, 662 ssa.OpARMMOVWF, 663 ssa.OpARMMOVWD, 664 ssa.OpARMMOVFW, 665 ssa.OpARMMOVDW, 666 ssa.OpARMMOVFD, 667 ssa.OpARMMOVDF: 668 p := s.Prog(v.Op.Asm()) 669 p.From.Type = obj.TYPE_REG 670 p.From.Reg = v.Args[0].Reg() 671 p.To.Type = obj.TYPE_REG 672 p.To.Reg = v.Reg() 673 case ssa.OpARMMOVWUF, 674 ssa.OpARMMOVWUD, 675 ssa.OpARMMOVFWU, 676 ssa.OpARMMOVDWU: 677 p := s.Prog(v.Op.Asm()) 678 p.Scond = arm.C_UBIT 679 p.From.Type = obj.TYPE_REG 680 p.From.Reg = v.Args[0].Reg() 681 p.To.Type = obj.TYPE_REG 682 p.To.Reg = v.Reg() 683 case ssa.OpARMCMOVWHSconst: 684 p := s.Prog(arm.AMOVW) 685 p.Scond = arm.C_SCOND_HS 686 p.From.Type = obj.TYPE_CONST 687 p.From.Offset = v.AuxInt 688 p.To.Type = obj.TYPE_REG 689 p.To.Reg = v.Reg() 690 case ssa.OpARMCMOVWLSconst: 691 p := s.Prog(arm.AMOVW) 692 p.Scond = arm.C_SCOND_LS 693 p.From.Type = obj.TYPE_CONST 694 p.From.Offset = v.AuxInt 695 p.To.Type = obj.TYPE_REG 696 p.To.Reg = v.Reg() 697 case ssa.OpARMCALLstatic, ssa.OpARMCALLclosure, ssa.OpARMCALLinter: 698 s.Call(v) 699 case ssa.OpARMCALLudiv: 700 p := s.Prog(obj.ACALL) 701 p.To.Type = obj.TYPE_MEM 702 p.To.Name = obj.NAME_EXTERN 703 p.To.Sym = gc.Udiv 704 case ssa.OpARMLoweredWB: 705 p := s.Prog(obj.ACALL) 706 p.To.Type = obj.TYPE_MEM 707 p.To.Name = obj.NAME_EXTERN 708 p.To.Sym = v.Aux.(*obj.LSym) 709 case ssa.OpARMLoweredPanicBoundsA, ssa.OpARMLoweredPanicBoundsB, ssa.OpARMLoweredPanicBoundsC: 710 p := s.Prog(obj.ACALL) 711 p.To.Type = obj.TYPE_MEM 712 p.To.Name = obj.NAME_EXTERN 713 p.To.Sym = gc.BoundsCheckFunc[v.AuxInt] 714 s.UseArgs(8) // space used in callee args area by assembly stubs 715 case ssa.OpARMLoweredPanicExtendA, ssa.OpARMLoweredPanicExtendB, ssa.OpARMLoweredPanicExtendC: 716 p := s.Prog(obj.ACALL) 717 p.To.Type = obj.TYPE_MEM 718 p.To.Name = obj.NAME_EXTERN 719 p.To.Sym = gc.ExtendCheckFunc[v.AuxInt] 720 s.UseArgs(12) // space used in callee args area by assembly stubs 721 case ssa.OpARMDUFFZERO: 722 p := s.Prog(obj.ADUFFZERO) 723 p.To.Type = obj.TYPE_MEM 724 p.To.Name = obj.NAME_EXTERN 725 p.To.Sym = gc.Duffzero 726 p.To.Offset = v.AuxInt 727 case ssa.OpARMDUFFCOPY: 728 p := s.Prog(obj.ADUFFCOPY) 729 p.To.Type = obj.TYPE_MEM 730 p.To.Name = obj.NAME_EXTERN 731 p.To.Sym = gc.Duffcopy 732 p.To.Offset = v.AuxInt 733 case ssa.OpARMLoweredNilCheck: 734 // Issue a load which will fault if arg is nil. 735 p := s.Prog(arm.AMOVB) 736 p.From.Type = obj.TYPE_MEM 737 p.From.Reg = v.Args[0].Reg() 738 gc.AddAux(&p.From, v) 739 p.To.Type = obj.TYPE_REG 740 p.To.Reg = arm.REGTMP 741 if logopt.Enabled() { 742 logopt.LogOpt(v.Pos, "nilcheck", "genssa", v.Block.Func.Name) 743 } 744 if gc.Debug_checknil != 0 && v.Pos.Line() > 1 { // v.Pos.Line()==1 in generated wrappers 745 gc.Warnl(v.Pos, "generated nil check") 746 } 747 case ssa.OpARMLoweredZero: 748 // MOVW.P Rarg2, 4(R1) 749 // CMP Rarg1, R1 750 // BLE -2(PC) 751 // arg1 is the address of the last element to zero 752 // arg2 is known to be zero 753 // auxint is alignment 754 var sz int64 755 var mov obj.As 756 switch { 757 case v.AuxInt%4 == 0: 758 sz = 4 759 mov = arm.AMOVW 760 case v.AuxInt%2 == 0: 761 sz = 2 762 mov = arm.AMOVH 763 default: 764 sz = 1 765 mov = arm.AMOVB 766 } 767 p := s.Prog(mov) 768 p.Scond = arm.C_PBIT 769 p.From.Type = obj.TYPE_REG 770 p.From.Reg = v.Args[2].Reg() 771 p.To.Type = obj.TYPE_MEM 772 p.To.Reg = arm.REG_R1 773 p.To.Offset = sz 774 p2 := s.Prog(arm.ACMP) 775 p2.From.Type = obj.TYPE_REG 776 p2.From.Reg = v.Args[1].Reg() 777 p2.Reg = arm.REG_R1 778 p3 := s.Prog(arm.ABLE) 779 p3.To.Type = obj.TYPE_BRANCH 780 gc.Patch(p3, p) 781 case ssa.OpARMLoweredMove: 782 // MOVW.P 4(R1), Rtmp 783 // MOVW.P Rtmp, 4(R2) 784 // CMP Rarg2, R1 785 // BLE -3(PC) 786 // arg2 is the address of the last element of src 787 // auxint is alignment 788 var sz int64 789 var mov obj.As 790 switch { 791 case v.AuxInt%4 == 0: 792 sz = 4 793 mov = arm.AMOVW 794 case v.AuxInt%2 == 0: 795 sz = 2 796 mov = arm.AMOVH 797 default: 798 sz = 1 799 mov = arm.AMOVB 800 } 801 p := s.Prog(mov) 802 p.Scond = arm.C_PBIT 803 p.From.Type = obj.TYPE_MEM 804 p.From.Reg = arm.REG_R1 805 p.From.Offset = sz 806 p.To.Type = obj.TYPE_REG 807 p.To.Reg = arm.REGTMP 808 p2 := s.Prog(mov) 809 p2.Scond = arm.C_PBIT 810 p2.From.Type = obj.TYPE_REG 811 p2.From.Reg = arm.REGTMP 812 p2.To.Type = obj.TYPE_MEM 813 p2.To.Reg = arm.REG_R2 814 p2.To.Offset = sz 815 p3 := s.Prog(arm.ACMP) 816 p3.From.Type = obj.TYPE_REG 817 p3.From.Reg = v.Args[2].Reg() 818 p3.Reg = arm.REG_R1 819 p4 := s.Prog(arm.ABLE) 820 p4.To.Type = obj.TYPE_BRANCH 821 gc.Patch(p4, p) 822 case ssa.OpARMEqual, 823 ssa.OpARMNotEqual, 824 ssa.OpARMLessThan, 825 ssa.OpARMLessEqual, 826 ssa.OpARMGreaterThan, 827 ssa.OpARMGreaterEqual, 828 ssa.OpARMLessThanU, 829 ssa.OpARMLessEqualU, 830 ssa.OpARMGreaterThanU, 831 ssa.OpARMGreaterEqualU: 832 // generate boolean values 833 // use conditional move 834 p := s.Prog(arm.AMOVW) 835 p.From.Type = obj.TYPE_CONST 836 p.From.Offset = 0 837 p.To.Type = obj.TYPE_REG 838 p.To.Reg = v.Reg() 839 p = s.Prog(arm.AMOVW) 840 p.Scond = condBits[v.Op] 841 p.From.Type = obj.TYPE_CONST 842 p.From.Offset = 1 843 p.To.Type = obj.TYPE_REG 844 p.To.Reg = v.Reg() 845 case ssa.OpARMLoweredGetClosurePtr: 846 // Closure pointer is R7 (arm.REGCTXT). 847 gc.CheckLoweredGetClosurePtr(v) 848 case ssa.OpARMLoweredGetCallerSP: 849 // caller's SP is FixedFrameSize below the address of the first arg 850 p := s.Prog(arm.AMOVW) 851 p.From.Type = obj.TYPE_ADDR 852 p.From.Offset = -gc.Ctxt.FixedFrameSize() 853 p.From.Name = obj.NAME_PARAM 854 p.To.Type = obj.TYPE_REG 855 p.To.Reg = v.Reg() 856 case ssa.OpARMLoweredGetCallerPC: 857 p := s.Prog(obj.AGETCALLERPC) 858 p.To.Type = obj.TYPE_REG 859 p.To.Reg = v.Reg() 860 case ssa.OpARMFlagEQ, 861 ssa.OpARMFlagLT_ULT, 862 ssa.OpARMFlagLT_UGT, 863 ssa.OpARMFlagGT_ULT, 864 ssa.OpARMFlagGT_UGT: 865 v.Fatalf("Flag* ops should never make it to codegen %v", v.LongString()) 866 case ssa.OpARMInvertFlags: 867 v.Fatalf("InvertFlags should never make it to codegen %v", v.LongString()) 868 case ssa.OpClobber: 869 // TODO: implement for clobberdead experiment. Nop is ok for now. 870 default: 871 v.Fatalf("genValue not implemented: %s", v.LongString()) 872 } 873 } 874 875 var condBits = map[ssa.Op]uint8{ 876 ssa.OpARMEqual: arm.C_SCOND_EQ, 877 ssa.OpARMNotEqual: arm.C_SCOND_NE, 878 ssa.OpARMLessThan: arm.C_SCOND_LT, 879 ssa.OpARMLessThanU: arm.C_SCOND_LO, 880 ssa.OpARMLessEqual: arm.C_SCOND_LE, 881 ssa.OpARMLessEqualU: arm.C_SCOND_LS, 882 ssa.OpARMGreaterThan: arm.C_SCOND_GT, 883 ssa.OpARMGreaterThanU: arm.C_SCOND_HI, 884 ssa.OpARMGreaterEqual: arm.C_SCOND_GE, 885 ssa.OpARMGreaterEqualU: arm.C_SCOND_HS, 886 } 887 888 var blockJump = map[ssa.BlockKind]struct { 889 asm, invasm obj.As 890 }{ 891 ssa.BlockARMEQ: {arm.ABEQ, arm.ABNE}, 892 ssa.BlockARMNE: {arm.ABNE, arm.ABEQ}, 893 ssa.BlockARMLT: {arm.ABLT, arm.ABGE}, 894 ssa.BlockARMGE: {arm.ABGE, arm.ABLT}, 895 ssa.BlockARMLE: {arm.ABLE, arm.ABGT}, 896 ssa.BlockARMGT: {arm.ABGT, arm.ABLE}, 897 ssa.BlockARMULT: {arm.ABLO, arm.ABHS}, 898 ssa.BlockARMUGE: {arm.ABHS, arm.ABLO}, 899 ssa.BlockARMUGT: {arm.ABHI, arm.ABLS}, 900 ssa.BlockARMULE: {arm.ABLS, arm.ABHI}, 901 } 902 903 func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) { 904 switch b.Kind { 905 case ssa.BlockPlain: 906 if b.Succs[0].Block() != next { 907 p := s.Prog(obj.AJMP) 908 p.To.Type = obj.TYPE_BRANCH 909 s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()}) 910 } 911 912 case ssa.BlockDefer: 913 // defer returns in R0: 914 // 0 if we should continue executing 915 // 1 if we should jump to deferreturn call 916 p := s.Prog(arm.ACMP) 917 p.From.Type = obj.TYPE_CONST 918 p.From.Offset = 0 919 p.Reg = arm.REG_R0 920 p = s.Prog(arm.ABNE) 921 p.To.Type = obj.TYPE_BRANCH 922 s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()}) 923 if b.Succs[0].Block() != next { 924 p := s.Prog(obj.AJMP) 925 p.To.Type = obj.TYPE_BRANCH 926 s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()}) 927 } 928 929 case ssa.BlockExit: 930 931 case ssa.BlockRet: 932 s.Prog(obj.ARET) 933 934 case ssa.BlockRetJmp: 935 p := s.Prog(obj.ARET) 936 p.To.Type = obj.TYPE_MEM 937 p.To.Name = obj.NAME_EXTERN 938 p.To.Sym = b.Aux.(*obj.LSym) 939 940 case ssa.BlockARMEQ, ssa.BlockARMNE, 941 ssa.BlockARMLT, ssa.BlockARMGE, 942 ssa.BlockARMLE, ssa.BlockARMGT, 943 ssa.BlockARMULT, ssa.BlockARMUGT, 944 ssa.BlockARMULE, ssa.BlockARMUGE: 945 jmp := blockJump[b.Kind] 946 switch next { 947 case b.Succs[0].Block(): 948 s.Br(jmp.invasm, b.Succs[1].Block()) 949 case b.Succs[1].Block(): 950 s.Br(jmp.asm, b.Succs[0].Block()) 951 default: 952 if b.Likely != ssa.BranchUnlikely { 953 s.Br(jmp.asm, b.Succs[0].Block()) 954 s.Br(obj.AJMP, b.Succs[1].Block()) 955 } else { 956 s.Br(jmp.invasm, b.Succs[1].Block()) 957 s.Br(obj.AJMP, b.Succs[0].Block()) 958 } 959 } 960 961 default: 962 b.Fatalf("branch not implemented: %s", b.LongString()) 963 } 964 }