Home | History | Annotate | Download | only in 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 	"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 }
    905