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

View as plain text