...

Source file src/pkg/cmd/compile/internal/arm/ssa.go

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

View as plain text