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

View as plain text