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