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