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.
13 "cmd/compile/internal/base"
14 "cmd/compile/internal/ir"
15 "cmd/compile/internal/logopt"
16 "cmd/compile/internal/ssa"
17 "cmd/compile/internal/ssagen"
18 "cmd/compile/internal/types"
20 "cmd/internal/obj/arm"
23 // loadByType returns the load instruction of the given type.
24 func loadByType(t *types.Type) obj.As {
50 panic("bad load type")
53 // storeByType returns the store instruction of the given type.
54 func storeByType(t *types.Type) obj.As {
72 panic("bad store type")
75 // shift type is used as Offset in obj.TYPE_SHIFT operands to encode shifted register operands
78 // copied from ../../../internal/obj/util.go:/TYPE_SHIFT
79 func (v shift) String() string {
80 op := "<<>>->@>"[((v>>5)&3)<<1:]
83 return fmt.Sprintf("R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15)
86 return fmt.Sprintf("R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31)
90 // makeshift encodes a register shifted by a constant
91 func makeshift(reg int16, typ int64, s int64) shift {
92 return shift(int64(reg&0xf) | typ | (s&31)<<7)
95 // genshift generates a Prog for r = r0 op (r1 shifted by n)
96 func genshift(s *ssagen.State, as obj.As, r0, r1, r int16, typ int64, n int64) *obj.Prog {
98 p.From.Type = obj.TYPE_SHIFT
99 p.From.Offset = int64(makeshift(r1, typ, n))
102 p.To.Type = obj.TYPE_REG
108 // makeregshift encodes a register shifted by a register
109 func makeregshift(r1 int16, typ int64, r2 int16) shift {
110 return shift(int64(r1&0xf) | typ | int64(r2&0xf)<<8 | 1<<4)
113 // genregshift generates a Prog for r = r0 op (r1 shifted by r2)
114 func genregshift(s *ssagen.State, as obj.As, r0, r1, r2, r int16, typ int64) *obj.Prog {
116 p.From.Type = obj.TYPE_SHIFT
117 p.From.Offset = int64(makeregshift(r1, typ, r2))
120 p.To.Type = obj.TYPE_REG
126 // find a (lsb, width) pair for BFC
127 // lsb must be in [0, 31], width must be in [1, 32 - lsb]
128 // return (0xffffffff, 0) if v is not a binary like 0...01...10...0
129 func getBFC(v uint32) (uint32, uint32) {
131 // BFC is not applicable with zero
135 // find the lowest set bit, for example l=2 for 0x3ffffffc
136 l = uint32(bits.TrailingZeros32(v))
137 // m-1 represents the highest set bit index, for example m=30 for 0x3ffffffc
138 m = 32 - uint32(bits.LeadingZeros32(v))
139 // check if v is a binary like 0...01...10...0
140 if (1<<m)-(1<<l) == v {
141 // it must be m > l for non-zero v
148 func ssaGenValue(s *ssagen.State, v *ssa.Value) {
150 case ssa.OpCopy, ssa.OpARMMOVWreg:
151 if v.Type.IsMemory() {
160 if v.Type.IsFloat() {
161 switch v.Type.Size() {
167 panic("bad float size")
171 p.From.Type = obj.TYPE_REG
173 p.To.Type = obj.TYPE_REG
175 case ssa.OpARMMOVWnop:
178 if v.Type.IsFlags() {
179 v.Fatalf("load flags not implemented: %v", v.LongString())
182 p := s.Prog(loadByType(v.Type))
183 ssagen.AddrAuto(&p.From, v.Args[0])
184 p.To.Type = obj.TYPE_REG
187 if v.Type.IsFlags() {
188 v.Fatalf("store flags not implemented: %v", v.LongString())
191 p := s.Prog(storeByType(v.Type))
192 p.From.Type = obj.TYPE_REG
193 p.From.Reg = v.Args[0].Reg()
194 ssagen.AddrAuto(&p.To, v)
219 r1 := v.Args[0].Reg()
220 r2 := v.Args[1].Reg()
221 p := s.Prog(v.Op.Asm())
222 p.From.Type = obj.TYPE_REG
225 p.To.Type = obj.TYPE_REG
228 genregshift(s, arm.AMOVW, 0, v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm.SHIFT_RR)
229 case ssa.OpARMMULAF, ssa.OpARMMULAD, ssa.OpARMMULSF, ssa.OpARMMULSD, ssa.OpARMFMULAD:
231 r0 := v.Args[0].Reg()
232 r1 := v.Args[1].Reg()
233 r2 := v.Args[2].Reg()
235 v.Fatalf("result and addend are not in the same register: %v", v.LongString())
237 p := s.Prog(v.Op.Asm())
238 p.From.Type = obj.TYPE_REG
241 p.To.Type = obj.TYPE_REG
246 r1 := v.Args[0].Reg()
247 r2 := v.Args[1].Reg()
248 p := s.Prog(v.Op.Asm())
250 p.From.Type = obj.TYPE_REG
253 p.To.Type = obj.TYPE_REG
255 case ssa.OpARMSRAcond:
256 // ARM shift instructions uses only the low-order byte of the shift amount
257 // generate conditional instructions to deal with large shifts
258 // flag is already set
259 // SRA.HS $31, Rarg0, Rdst // shift 31 bits to get the sign bit
260 // SRA.LO Rarg1, Rarg0, Rdst
262 r1 := v.Args[0].Reg()
263 r2 := v.Args[1].Reg()
264 p := s.Prog(arm.ASRA)
265 p.Scond = arm.C_SCOND_HS
266 p.From.Type = obj.TYPE_CONST
269 p.To.Type = obj.TYPE_REG
272 p.Scond = arm.C_SCOND_LO
273 p.From.Type = obj.TYPE_REG
276 p.To.Type = obj.TYPE_REG
278 case ssa.OpARMBFX, ssa.OpARMBFXU:
279 p := s.Prog(v.Op.Asm())
280 p.From.Type = obj.TYPE_CONST
281 p.From.Offset = v.AuxInt >> 8
282 p.SetFrom3Const(v.AuxInt & 0xff)
283 p.Reg = v.Args[0].Reg()
284 p.To.Type = obj.TYPE_REG
286 case ssa.OpARMANDconst, ssa.OpARMBICconst:
287 // try to optimize ANDconst and BICconst to BFC, which saves bytes and ticks
288 // BFC is only available on ARMv7, and its result and source are in the same register
289 if buildcfg.GOARM == 7 && v.Reg() == v.Args[0].Reg() {
291 if v.Op == ssa.OpARMANDconst {
292 val = ^uint32(v.AuxInt)
294 val = uint32(v.AuxInt)
296 lsb, width := getBFC(val)
297 // omit BFC for ARM's imm12
298 if 8 < width && width < 24 {
299 p := s.Prog(arm.ABFC)
300 p.From.Type = obj.TYPE_CONST
301 p.From.Offset = int64(width)
302 p.SetFrom3Const(int64(lsb))
303 p.To.Type = obj.TYPE_REG
308 // fall back to ordinary form
310 case ssa.OpARMADDconst,
321 p := s.Prog(v.Op.Asm())
322 p.From.Type = obj.TYPE_CONST
323 p.From.Offset = v.AuxInt
324 p.Reg = v.Args[0].Reg()
325 p.To.Type = obj.TYPE_REG
327 case ssa.OpARMADDSconst,
330 p := s.Prog(v.Op.Asm())
332 p.From.Type = obj.TYPE_CONST
333 p.From.Offset = v.AuxInt
334 p.Reg = v.Args[0].Reg()
335 p.To.Type = obj.TYPE_REG
337 case ssa.OpARMSRRconst:
338 genshift(s, arm.AMOVW, 0, v.Args[0].Reg(), v.Reg(), arm.SHIFT_RR, v.AuxInt)
339 case ssa.OpARMADDshiftLL,
349 genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm.SHIFT_LL, v.AuxInt)
350 case ssa.OpARMADDSshiftLL,
351 ssa.OpARMSUBSshiftLL,
352 ssa.OpARMRSBSshiftLL:
353 p := genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg0(), arm.SHIFT_LL, v.AuxInt)
355 case ssa.OpARMADDshiftRL,
365 genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm.SHIFT_LR, v.AuxInt)
366 case ssa.OpARMADDSshiftRL,
367 ssa.OpARMSUBSshiftRL,
368 ssa.OpARMRSBSshiftRL:
369 p := genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg0(), arm.SHIFT_LR, v.AuxInt)
371 case ssa.OpARMADDshiftRA,
381 genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm.SHIFT_AR, v.AuxInt)
382 case ssa.OpARMADDSshiftRA,
383 ssa.OpARMSUBSshiftRA,
384 ssa.OpARMRSBSshiftRA:
385 p := genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg0(), arm.SHIFT_AR, v.AuxInt)
387 case ssa.OpARMXORshiftRR:
388 genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm.SHIFT_RR, v.AuxInt)
389 case ssa.OpARMMVNshiftLL:
390 genshift(s, v.Op.Asm(), 0, v.Args[0].Reg(), v.Reg(), arm.SHIFT_LL, v.AuxInt)
391 case ssa.OpARMMVNshiftRL:
392 genshift(s, v.Op.Asm(), 0, v.Args[0].Reg(), v.Reg(), arm.SHIFT_LR, v.AuxInt)
393 case ssa.OpARMMVNshiftRA:
394 genshift(s, v.Op.Asm(), 0, v.Args[0].Reg(), v.Reg(), arm.SHIFT_AR, v.AuxInt)
395 case ssa.OpARMMVNshiftLLreg:
396 genregshift(s, v.Op.Asm(), 0, v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm.SHIFT_LL)
397 case ssa.OpARMMVNshiftRLreg:
398 genregshift(s, v.Op.Asm(), 0, v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm.SHIFT_LR)
399 case ssa.OpARMMVNshiftRAreg:
400 genregshift(s, v.Op.Asm(), 0, v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm.SHIFT_AR)
401 case ssa.OpARMADDshiftLLreg,
402 ssa.OpARMADCshiftLLreg,
403 ssa.OpARMSUBshiftLLreg,
404 ssa.OpARMSBCshiftLLreg,
405 ssa.OpARMRSBshiftLLreg,
406 ssa.OpARMRSCshiftLLreg,
407 ssa.OpARMANDshiftLLreg,
408 ssa.OpARMORshiftLLreg,
409 ssa.OpARMXORshiftLLreg,
410 ssa.OpARMBICshiftLLreg:
411 genregshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Args[2].Reg(), v.Reg(), arm.SHIFT_LL)
412 case ssa.OpARMADDSshiftLLreg,
413 ssa.OpARMSUBSshiftLLreg,
414 ssa.OpARMRSBSshiftLLreg:
415 p := genregshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Args[2].Reg(), v.Reg0(), arm.SHIFT_LL)
417 case ssa.OpARMADDshiftRLreg,
418 ssa.OpARMADCshiftRLreg,
419 ssa.OpARMSUBshiftRLreg,
420 ssa.OpARMSBCshiftRLreg,
421 ssa.OpARMRSBshiftRLreg,
422 ssa.OpARMRSCshiftRLreg,
423 ssa.OpARMANDshiftRLreg,
424 ssa.OpARMORshiftRLreg,
425 ssa.OpARMXORshiftRLreg,
426 ssa.OpARMBICshiftRLreg:
427 genregshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Args[2].Reg(), v.Reg(), arm.SHIFT_LR)
428 case ssa.OpARMADDSshiftRLreg,
429 ssa.OpARMSUBSshiftRLreg,
430 ssa.OpARMRSBSshiftRLreg:
431 p := genregshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Args[2].Reg(), v.Reg0(), arm.SHIFT_LR)
433 case ssa.OpARMADDshiftRAreg,
434 ssa.OpARMADCshiftRAreg,
435 ssa.OpARMSUBshiftRAreg,
436 ssa.OpARMSBCshiftRAreg,
437 ssa.OpARMRSBshiftRAreg,
438 ssa.OpARMRSCshiftRAreg,
439 ssa.OpARMANDshiftRAreg,
440 ssa.OpARMORshiftRAreg,
441 ssa.OpARMXORshiftRAreg,
442 ssa.OpARMBICshiftRAreg:
443 genregshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Args[2].Reg(), v.Reg(), arm.SHIFT_AR)
444 case ssa.OpARMADDSshiftRAreg,
445 ssa.OpARMSUBSshiftRAreg,
446 ssa.OpARMRSBSshiftRAreg:
447 p := genregshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Args[2].Reg(), v.Reg0(), arm.SHIFT_AR)
451 // 32-bit high multiplication
452 p := s.Prog(v.Op.Asm())
453 p.From.Type = obj.TYPE_REG
454 p.From.Reg = v.Args[0].Reg()
455 p.Reg = v.Args[1].Reg()
456 p.To.Type = obj.TYPE_REGREG
458 p.To.Offset = arm.REGTMP // throw away low 32-bit into tmp register
460 // 32-bit multiplication, results 64-bit, high 32-bit in out0, low 32-bit in out1
461 p := s.Prog(v.Op.Asm())
462 p.From.Type = obj.TYPE_REG
463 p.From.Reg = v.Args[0].Reg()
464 p.Reg = v.Args[1].Reg()
465 p.To.Type = obj.TYPE_REGREG
466 p.To.Reg = v.Reg0() // high 32-bit
467 p.To.Offset = int64(v.Reg1()) // low 32-bit
468 case ssa.OpARMMULA, ssa.OpARMMULS:
469 p := s.Prog(v.Op.Asm())
470 p.From.Type = obj.TYPE_REG
471 p.From.Reg = v.Args[0].Reg()
472 p.Reg = v.Args[1].Reg()
473 p.To.Type = obj.TYPE_REGREG2
474 p.To.Reg = v.Reg() // result
475 p.To.Offset = int64(v.Args[2].Reg()) // addend
476 case ssa.OpARMMOVWconst:
477 p := s.Prog(v.Op.Asm())
478 p.From.Type = obj.TYPE_CONST
479 p.From.Offset = v.AuxInt
480 p.To.Type = obj.TYPE_REG
482 case ssa.OpARMMOVFconst,
484 p := s.Prog(v.Op.Asm())
485 p.From.Type = obj.TYPE_FCONST
486 p.From.Val = math.Float64frombits(uint64(v.AuxInt))
487 p.To.Type = obj.TYPE_REG
495 p := s.Prog(v.Op.Asm())
496 p.From.Type = obj.TYPE_REG
497 // Special layout in ARM assembly
498 // Comparing to x86, the operands of ARM's CMP are reversed.
499 p.From.Reg = v.Args[1].Reg()
500 p.Reg = v.Args[0].Reg()
501 case ssa.OpARMCMPconst,
505 // Special layout in ARM assembly
506 p := s.Prog(v.Op.Asm())
507 p.From.Type = obj.TYPE_CONST
508 p.From.Offset = v.AuxInt
509 p.Reg = v.Args[0].Reg()
512 p := s.Prog(v.Op.Asm())
513 p.From.Type = obj.TYPE_REG
514 p.From.Reg = v.Args[0].Reg()
515 case ssa.OpARMCMPshiftLL, ssa.OpARMCMNshiftLL, ssa.OpARMTSTshiftLL, ssa.OpARMTEQshiftLL:
516 genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), 0, arm.SHIFT_LL, v.AuxInt)
517 case ssa.OpARMCMPshiftRL, ssa.OpARMCMNshiftRL, ssa.OpARMTSTshiftRL, ssa.OpARMTEQshiftRL:
518 genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), 0, arm.SHIFT_LR, v.AuxInt)
519 case ssa.OpARMCMPshiftRA, ssa.OpARMCMNshiftRA, ssa.OpARMTSTshiftRA, ssa.OpARMTEQshiftRA:
520 genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), 0, arm.SHIFT_AR, v.AuxInt)
521 case ssa.OpARMCMPshiftLLreg, ssa.OpARMCMNshiftLLreg, ssa.OpARMTSTshiftLLreg, ssa.OpARMTEQshiftLLreg:
522 genregshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Args[2].Reg(), 0, arm.SHIFT_LL)
523 case ssa.OpARMCMPshiftRLreg, ssa.OpARMCMNshiftRLreg, ssa.OpARMTSTshiftRLreg, ssa.OpARMTEQshiftRLreg:
524 genregshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Args[2].Reg(), 0, arm.SHIFT_LR)
525 case ssa.OpARMCMPshiftRAreg, ssa.OpARMCMNshiftRAreg, ssa.OpARMTSTshiftRAreg, ssa.OpARMTEQshiftRAreg:
526 genregshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Args[2].Reg(), 0, arm.SHIFT_AR)
527 case ssa.OpARMMOVWaddr:
528 p := s.Prog(arm.AMOVW)
529 p.From.Type = obj.TYPE_ADDR
530 p.From.Reg = v.Args[0].Reg()
531 p.To.Type = obj.TYPE_REG
535 // MOVW $sym+off(base), R
536 // the assembler expands it as the following:
537 // - base is SP: add constant offset to SP (R13)
538 // when constant is large, tmp register (R11) may be used
539 // - base is SB: load external address from constant pool (use relocation)
540 switch v.Aux.(type) {
542 v.Fatalf("aux is of unknown type %T", v.Aux)
545 ssagen.AddAux(&p.From, v)
548 ssagen.AddAux(&p.From, v)
550 // No sym, just MOVW $off(SP), R
552 p.From.Offset = v.AuxInt
554 if reg := v.Args[0].RegName(); reg != wantreg {
555 v.Fatalf("bad reg %s for symbol type %T, want %s", reg, v.Aux, wantreg)
558 case ssa.OpARMMOVBload,
565 p := s.Prog(v.Op.Asm())
566 p.From.Type = obj.TYPE_MEM
567 p.From.Reg = v.Args[0].Reg()
568 ssagen.AddAux(&p.From, v)
569 p.To.Type = obj.TYPE_REG
571 case ssa.OpARMMOVBstore,
576 p := s.Prog(v.Op.Asm())
577 p.From.Type = obj.TYPE_REG
578 p.From.Reg = v.Args[1].Reg()
579 p.To.Type = obj.TYPE_MEM
580 p.To.Reg = v.Args[0].Reg()
581 ssagen.AddAux(&p.To, v)
582 case ssa.OpARMMOVWloadidx, ssa.OpARMMOVBUloadidx, ssa.OpARMMOVBloadidx, ssa.OpARMMOVHUloadidx, ssa.OpARMMOVHloadidx:
583 // this is just shift 0 bits
585 case ssa.OpARMMOVWloadshiftLL:
586 p := genshift(s, v.Op.Asm(), 0, v.Args[1].Reg(), v.Reg(), arm.SHIFT_LL, v.AuxInt)
587 p.From.Reg = v.Args[0].Reg()
588 case ssa.OpARMMOVWloadshiftRL:
589 p := genshift(s, v.Op.Asm(), 0, v.Args[1].Reg(), v.Reg(), arm.SHIFT_LR, v.AuxInt)
590 p.From.Reg = v.Args[0].Reg()
591 case ssa.OpARMMOVWloadshiftRA:
592 p := genshift(s, v.Op.Asm(), 0, v.Args[1].Reg(), v.Reg(), arm.SHIFT_AR, v.AuxInt)
593 p.From.Reg = v.Args[0].Reg()
594 case ssa.OpARMMOVWstoreidx, ssa.OpARMMOVBstoreidx, ssa.OpARMMOVHstoreidx:
595 // this is just shift 0 bits
597 case ssa.OpARMMOVWstoreshiftLL:
598 p := s.Prog(v.Op.Asm())
599 p.From.Type = obj.TYPE_REG
600 p.From.Reg = v.Args[2].Reg()
601 p.To.Type = obj.TYPE_SHIFT
602 p.To.Reg = v.Args[0].Reg()
603 p.To.Offset = int64(makeshift(v.Args[1].Reg(), arm.SHIFT_LL, v.AuxInt))
604 case ssa.OpARMMOVWstoreshiftRL:
605 p := s.Prog(v.Op.Asm())
606 p.From.Type = obj.TYPE_REG
607 p.From.Reg = v.Args[2].Reg()
608 p.To.Type = obj.TYPE_SHIFT
609 p.To.Reg = v.Args[0].Reg()
610 p.To.Offset = int64(makeshift(v.Args[1].Reg(), arm.SHIFT_LR, v.AuxInt))
611 case ssa.OpARMMOVWstoreshiftRA:
612 p := s.Prog(v.Op.Asm())
613 p.From.Type = obj.TYPE_REG
614 p.From.Reg = v.Args[2].Reg()
615 p.To.Type = obj.TYPE_SHIFT
616 p.To.Reg = v.Args[0].Reg()
617 p.To.Offset = int64(makeshift(v.Args[1].Reg(), arm.SHIFT_AR, v.AuxInt))
618 case ssa.OpARMMOVBreg,
623 for a.Op == ssa.OpCopy || a.Op == ssa.OpARMMOVWreg || a.Op == ssa.OpARMMOVWnop {
626 if a.Op == ssa.OpLoadReg {
629 case v.Op == ssa.OpARMMOVBreg && t.Size() == 1 && t.IsSigned(),
630 v.Op == ssa.OpARMMOVBUreg && t.Size() == 1 && !t.IsSigned(),
631 v.Op == ssa.OpARMMOVHreg && t.Size() == 2 && t.IsSigned(),
632 v.Op == ssa.OpARMMOVHUreg && t.Size() == 2 && !t.IsSigned():
633 // arg is a proper-typed load, already zero/sign-extended, don't extend again
634 if v.Reg() == v.Args[0].Reg() {
637 p := s.Prog(arm.AMOVW)
638 p.From.Type = obj.TYPE_REG
639 p.From.Reg = v.Args[0].Reg()
640 p.To.Type = obj.TYPE_REG
646 if buildcfg.GOARM >= 6 {
647 // generate more efficient "MOVB/MOVBU/MOVH/MOVHU Reg@>0, Reg" on ARMv6 & ARMv7
648 genshift(s, v.Op.Asm(), 0, v.Args[0].Reg(), v.Reg(), arm.SHIFT_RR, 0)
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
673 case ssa.OpARMMOVWUF,
677 p := s.Prog(v.Op.Asm())
679 p.From.Type = obj.TYPE_REG
680 p.From.Reg = v.Args[0].Reg()
681 p.To.Type = obj.TYPE_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
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
697 case ssa.OpARMCALLstatic, ssa.OpARMCALLclosure, ssa.OpARMCALLinter:
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 = ir.Syms.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 = ssagen.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 = ssagen.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 = ir.Syms.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 = ir.Syms.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 ssagen.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)
744 if base.Debug.Nil != 0 && v.Pos.Line() > 1 { // v.Pos.Line()==1 in generated wrappers
745 base.WarnfAt(v.Pos, "generated nil check")
747 case ssa.OpARMLoweredZero:
748 // MOVW.P Rarg2, 4(R1)
751 // arg1 is the address of the last element to zero
752 // arg2 is known to be zero
753 // auxint is alignment
757 case v.AuxInt%4 == 0:
760 case v.AuxInt%2 == 0:
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
774 p2 := s.Prog(arm.ACMP)
775 p2.From.Type = obj.TYPE_REG
776 p2.From.Reg = v.Args[1].Reg()
778 p3 := s.Prog(arm.ABLE)
779 p3.To.Type = obj.TYPE_BRANCH
781 case ssa.OpARMLoweredMove:
782 // MOVW.P 4(R1), Rtmp
783 // MOVW.P Rtmp, 4(R2)
786 // arg2 is the address of the last element of src
787 // auxint is alignment
791 case v.AuxInt%4 == 0:
794 case v.AuxInt%2 == 0:
803 p.From.Type = obj.TYPE_MEM
804 p.From.Reg = arm.REG_R1
806 p.To.Type = obj.TYPE_REG
807 p.To.Reg = arm.REGTMP
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
815 p3 := s.Prog(arm.ACMP)
816 p3.From.Type = obj.TYPE_REG
817 p3.From.Reg = v.Args[2].Reg()
819 p4 := s.Prog(arm.ABLE)
820 p4.To.Type = obj.TYPE_BRANCH
826 ssa.OpARMGreaterThan,
827 ssa.OpARMGreaterEqual,
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
837 p.To.Type = obj.TYPE_REG
839 p = s.Prog(arm.AMOVW)
840 p.Scond = condBits[v.Op]
841 p.From.Type = obj.TYPE_CONST
843 p.To.Type = obj.TYPE_REG
845 case ssa.OpARMLoweredGetClosurePtr:
846 // Closure pointer is R7 (arm.REGCTXT).
847 ssagen.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 = -base.Ctxt.FixedFrameSize()
853 p.From.Name = obj.NAME_PARAM
854 p.To.Type = obj.TYPE_REG
856 case ssa.OpARMLoweredGetCallerPC:
857 p := s.Prog(obj.AGETCALLERPC)
858 p.To.Type = obj.TYPE_REG
860 case ssa.OpARMFlagConstant:
861 v.Fatalf("FlagConstant op should never make it to codegen %v", v.LongString())
862 case ssa.OpARMInvertFlags:
863 v.Fatalf("InvertFlags should never make it to codegen %v", v.LongString())
864 case ssa.OpClobber, ssa.OpClobberReg:
865 // TODO: implement for clobberdead experiment. Nop is ok for now.
867 v.Fatalf("genValue not implemented: %s", v.LongString())
871 var condBits = map[ssa.Op]uint8{
872 ssa.OpARMEqual: arm.C_SCOND_EQ,
873 ssa.OpARMNotEqual: arm.C_SCOND_NE,
874 ssa.OpARMLessThan: arm.C_SCOND_LT,
875 ssa.OpARMLessThanU: arm.C_SCOND_LO,
876 ssa.OpARMLessEqual: arm.C_SCOND_LE,
877 ssa.OpARMLessEqualU: arm.C_SCOND_LS,
878 ssa.OpARMGreaterThan: arm.C_SCOND_GT,
879 ssa.OpARMGreaterThanU: arm.C_SCOND_HI,
880 ssa.OpARMGreaterEqual: arm.C_SCOND_GE,
881 ssa.OpARMGreaterEqualU: arm.C_SCOND_HS,
884 var blockJump = map[ssa.BlockKind]struct {
887 ssa.BlockARMEQ: {arm.ABEQ, arm.ABNE},
888 ssa.BlockARMNE: {arm.ABNE, arm.ABEQ},
889 ssa.BlockARMLT: {arm.ABLT, arm.ABGE},
890 ssa.BlockARMGE: {arm.ABGE, arm.ABLT},
891 ssa.BlockARMLE: {arm.ABLE, arm.ABGT},
892 ssa.BlockARMGT: {arm.ABGT, arm.ABLE},
893 ssa.BlockARMULT: {arm.ABLO, arm.ABHS},
894 ssa.BlockARMUGE: {arm.ABHS, arm.ABLO},
895 ssa.BlockARMUGT: {arm.ABHI, arm.ABLS},
896 ssa.BlockARMULE: {arm.ABLS, arm.ABHI},
897 ssa.BlockARMLTnoov: {arm.ABMI, arm.ABPL},
898 ssa.BlockARMGEnoov: {arm.ABPL, arm.ABMI},
901 // To model a 'LEnoov' ('<=' without overflow checking) branching
902 var leJumps = [2][2]ssagen.IndexJump{
903 {{Jump: arm.ABEQ, Index: 0}, {Jump: arm.ABPL, Index: 1}}, // next == b.Succs[0]
904 {{Jump: arm.ABMI, Index: 0}, {Jump: arm.ABEQ, Index: 0}}, // next == b.Succs[1]
907 // To model a 'GTnoov' ('>' without overflow checking) branching
908 var gtJumps = [2][2]ssagen.IndexJump{
909 {{Jump: arm.ABMI, Index: 1}, {Jump: arm.ABEQ, Index: 1}}, // next == b.Succs[0]
910 {{Jump: arm.ABEQ, Index: 1}, {Jump: arm.ABPL, Index: 0}}, // next == b.Succs[1]
913 func ssaGenBlock(s *ssagen.State, b, next *ssa.Block) {
916 if b.Succs[0].Block() != next {
917 p := s.Prog(obj.AJMP)
918 p.To.Type = obj.TYPE_BRANCH
919 s.Branches = append(s.Branches, ssagen.Branch{P: p, B: b.Succs[0].Block()})
923 // defer returns in R0:
924 // 0 if we should continue executing
925 // 1 if we should jump to deferreturn call
926 p := s.Prog(arm.ACMP)
927 p.From.Type = obj.TYPE_CONST
931 p.To.Type = obj.TYPE_BRANCH
932 s.Branches = append(s.Branches, ssagen.Branch{P: p, B: b.Succs[1].Block()})
933 if b.Succs[0].Block() != next {
934 p := s.Prog(obj.AJMP)
935 p.To.Type = obj.TYPE_BRANCH
936 s.Branches = append(s.Branches, ssagen.Branch{P: p, B: b.Succs[0].Block()})
944 case ssa.BlockRetJmp:
945 p := s.Prog(obj.ARET)
946 p.To.Type = obj.TYPE_MEM
947 p.To.Name = obj.NAME_EXTERN
948 p.To.Sym = b.Aux.(*obj.LSym)
950 case ssa.BlockARMEQ, ssa.BlockARMNE,
951 ssa.BlockARMLT, ssa.BlockARMGE,
952 ssa.BlockARMLE, ssa.BlockARMGT,
953 ssa.BlockARMULT, ssa.BlockARMUGT,
954 ssa.BlockARMULE, ssa.BlockARMUGE,
955 ssa.BlockARMLTnoov, ssa.BlockARMGEnoov:
956 jmp := blockJump[b.Kind]
958 case b.Succs[0].Block():
959 s.Br(jmp.invasm, b.Succs[1].Block())
960 case b.Succs[1].Block():
961 s.Br(jmp.asm, b.Succs[0].Block())
963 if b.Likely != ssa.BranchUnlikely {
964 s.Br(jmp.asm, b.Succs[0].Block())
965 s.Br(obj.AJMP, b.Succs[1].Block())
967 s.Br(jmp.invasm, b.Succs[1].Block())
968 s.Br(obj.AJMP, b.Succs[0].Block())
972 case ssa.BlockARMLEnoov:
973 s.CombJump(b, next, &leJumps)
975 case ssa.BlockARMGTnoov:
976 s.CombJump(b, next, >Jumps)
979 b.Fatalf("branch not implemented: %s", b.LongString())