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