github.com/mattn/go@v0.0.0-20171011075504-07f7db3ea99f/src/cmd/compile/internal/arm/ssa.go (about)

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