Black Lives Matter. Support the Equal Justice Initiative.

Source file src/cmd/compile/internal/arm/ssa.go

Documentation: cmd/compile/internal/arm

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

View as plain text