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

View as plain text