gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

arm64.go (8658B)


      1 // Copyright 2015 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 // This file encapsulates some of the odd characteristics of the ARM64
      6 // instruction set, to minimize its interaction with the core of the
      7 // assembler.
      8 
      9 package arch
     10 
     11 import (
     12 	"github.com/twitchyliquid64/golang-asm/obj"
     13 	"github.com/twitchyliquid64/golang-asm/obj/arm64"
     14 	"errors"
     15 )
     16 
     17 var arm64LS = map[string]uint8{
     18 	"P": arm64.C_XPOST,
     19 	"W": arm64.C_XPRE,
     20 }
     21 
     22 var arm64Jump = map[string]bool{
     23 	"B":     true,
     24 	"BL":    true,
     25 	"BEQ":   true,
     26 	"BNE":   true,
     27 	"BCS":   true,
     28 	"BHS":   true,
     29 	"BCC":   true,
     30 	"BLO":   true,
     31 	"BMI":   true,
     32 	"BPL":   true,
     33 	"BVS":   true,
     34 	"BVC":   true,
     35 	"BHI":   true,
     36 	"BLS":   true,
     37 	"BGE":   true,
     38 	"BLT":   true,
     39 	"BGT":   true,
     40 	"BLE":   true,
     41 	"CALL":  true,
     42 	"CBZ":   true,
     43 	"CBZW":  true,
     44 	"CBNZ":  true,
     45 	"CBNZW": true,
     46 	"JMP":   true,
     47 	"TBNZ":  true,
     48 	"TBZ":   true,
     49 }
     50 
     51 func jumpArm64(word string) bool {
     52 	return arm64Jump[word]
     53 }
     54 
     55 // IsARM64CMP reports whether the op (as defined by an arm.A* constant) is
     56 // one of the comparison instructions that require special handling.
     57 func IsARM64CMP(op obj.As) bool {
     58 	switch op {
     59 	case arm64.ACMN, arm64.ACMP, arm64.ATST,
     60 		arm64.ACMNW, arm64.ACMPW, arm64.ATSTW,
     61 		arm64.AFCMPS, arm64.AFCMPD,
     62 		arm64.AFCMPES, arm64.AFCMPED:
     63 		return true
     64 	}
     65 	return false
     66 }
     67 
     68 // IsARM64STLXR reports whether the op (as defined by an arm64.A*
     69 // constant) is one of the STLXR-like instructions that require special
     70 // handling.
     71 func IsARM64STLXR(op obj.As) bool {
     72 	switch op {
     73 	case arm64.ASTLXRB, arm64.ASTLXRH, arm64.ASTLXRW, arm64.ASTLXR,
     74 		arm64.ASTXRB, arm64.ASTXRH, arm64.ASTXRW, arm64.ASTXR,
     75 		arm64.ASTXP, arm64.ASTXPW, arm64.ASTLXP, arm64.ASTLXPW:
     76 		return true
     77 	}
     78 	// atomic instructions
     79 	if arm64.IsAtomicInstruction(op) {
     80 		return true
     81 	}
     82 	return false
     83 }
     84 
     85 // ARM64Suffix handles the special suffix for the ARM64.
     86 // It returns a boolean to indicate success; failure means
     87 // cond was unrecognized.
     88 func ARM64Suffix(prog *obj.Prog, cond string) bool {
     89 	if cond == "" {
     90 		return true
     91 	}
     92 	bits, ok := parseARM64Suffix(cond)
     93 	if !ok {
     94 		return false
     95 	}
     96 	prog.Scond = bits
     97 	return true
     98 }
     99 
    100 // parseARM64Suffix parses the suffix attached to an ARM64 instruction.
    101 // The input is a single string consisting of period-separated condition
    102 // codes, such as ".P.W". An initial period is ignored.
    103 func parseARM64Suffix(cond string) (uint8, bool) {
    104 	if cond == "" {
    105 		return 0, true
    106 	}
    107 	return parseARMCondition(cond, arm64LS, nil)
    108 }
    109 
    110 func arm64RegisterNumber(name string, n int16) (int16, bool) {
    111 	switch name {
    112 	case "F":
    113 		if 0 <= n && n <= 31 {
    114 			return arm64.REG_F0 + n, true
    115 		}
    116 	case "R":
    117 		if 0 <= n && n <= 30 { // not 31
    118 			return arm64.REG_R0 + n, true
    119 		}
    120 	case "V":
    121 		if 0 <= n && n <= 31 {
    122 			return arm64.REG_V0 + n, true
    123 		}
    124 	}
    125 	return 0, false
    126 }
    127 
    128 // IsARM64TBL reports whether the op (as defined by an arm64.A*
    129 // constant) is one of the table lookup instructions that require special
    130 // handling.
    131 func IsARM64TBL(op obj.As) bool {
    132 	return op == arm64.AVTBL
    133 }
    134 
    135 // ARM64RegisterExtension parses an ARM64 register with extension or arrangement.
    136 func ARM64RegisterExtension(a *obj.Addr, ext string, reg, num int16, isAmount, isIndex bool) error {
    137 	Rnum := (reg & 31) + int16(num<<5)
    138 	if isAmount {
    139 		if num < 0 || num > 7 {
    140 			return errors.New("index shift amount is out of range")
    141 		}
    142 	}
    143 	switch ext {
    144 	case "UXTB":
    145 		if !isAmount {
    146 			return errors.New("invalid register extension")
    147 		}
    148 		if a.Type == obj.TYPE_MEM {
    149 			return errors.New("invalid shift for the register offset addressing mode")
    150 		}
    151 		a.Reg = arm64.REG_UXTB + Rnum
    152 	case "UXTH":
    153 		if !isAmount {
    154 			return errors.New("invalid register extension")
    155 		}
    156 		if a.Type == obj.TYPE_MEM {
    157 			return errors.New("invalid shift for the register offset addressing mode")
    158 		}
    159 		a.Reg = arm64.REG_UXTH + Rnum
    160 	case "UXTW":
    161 		if !isAmount {
    162 			return errors.New("invalid register extension")
    163 		}
    164 		// effective address of memory is a base register value and an offset register value.
    165 		if a.Type == obj.TYPE_MEM {
    166 			a.Index = arm64.REG_UXTW + Rnum
    167 		} else {
    168 			a.Reg = arm64.REG_UXTW + Rnum
    169 		}
    170 	case "UXTX":
    171 		if !isAmount {
    172 			return errors.New("invalid register extension")
    173 		}
    174 		if a.Type == obj.TYPE_MEM {
    175 			return errors.New("invalid shift for the register offset addressing mode")
    176 		}
    177 		a.Reg = arm64.REG_UXTX + Rnum
    178 	case "SXTB":
    179 		if !isAmount {
    180 			return errors.New("invalid register extension")
    181 		}
    182 		a.Reg = arm64.REG_SXTB + Rnum
    183 	case "SXTH":
    184 		if !isAmount {
    185 			return errors.New("invalid register extension")
    186 		}
    187 		if a.Type == obj.TYPE_MEM {
    188 			return errors.New("invalid shift for the register offset addressing mode")
    189 		}
    190 		a.Reg = arm64.REG_SXTH + Rnum
    191 	case "SXTW":
    192 		if !isAmount {
    193 			return errors.New("invalid register extension")
    194 		}
    195 		if a.Type == obj.TYPE_MEM {
    196 			a.Index = arm64.REG_SXTW + Rnum
    197 		} else {
    198 			a.Reg = arm64.REG_SXTW + Rnum
    199 		}
    200 	case "SXTX":
    201 		if !isAmount {
    202 			return errors.New("invalid register extension")
    203 		}
    204 		if a.Type == obj.TYPE_MEM {
    205 			a.Index = arm64.REG_SXTX + Rnum
    206 		} else {
    207 			a.Reg = arm64.REG_SXTX + Rnum
    208 		}
    209 	case "LSL":
    210 		if !isAmount {
    211 			return errors.New("invalid register extension")
    212 		}
    213 		a.Index = arm64.REG_LSL + Rnum
    214 	case "B8":
    215 		if isIndex {
    216 			return errors.New("invalid register extension")
    217 		}
    218 		a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_8B & 15) << 5)
    219 	case "B16":
    220 		if isIndex {
    221 			return errors.New("invalid register extension")
    222 		}
    223 		a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_16B & 15) << 5)
    224 	case "H4":
    225 		if isIndex {
    226 			return errors.New("invalid register extension")
    227 		}
    228 		a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_4H & 15) << 5)
    229 	case "H8":
    230 		if isIndex {
    231 			return errors.New("invalid register extension")
    232 		}
    233 		a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_8H & 15) << 5)
    234 	case "S2":
    235 		if isIndex {
    236 			return errors.New("invalid register extension")
    237 		}
    238 		a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_2S & 15) << 5)
    239 	case "S4":
    240 		if isIndex {
    241 			return errors.New("invalid register extension")
    242 		}
    243 		a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_4S & 15) << 5)
    244 	case "D1":
    245 		if isIndex {
    246 			return errors.New("invalid register extension")
    247 		}
    248 		a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_1D & 15) << 5)
    249 	case "D2":
    250 		if isIndex {
    251 			return errors.New("invalid register extension")
    252 		}
    253 		a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_2D & 15) << 5)
    254 	case "Q1":
    255 		if isIndex {
    256 			return errors.New("invalid register extension")
    257 		}
    258 		a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_1Q & 15) << 5)
    259 	case "B":
    260 		if !isIndex {
    261 			return nil
    262 		}
    263 		a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_B & 15) << 5)
    264 		a.Index = num
    265 	case "H":
    266 		if !isIndex {
    267 			return nil
    268 		}
    269 		a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_H & 15) << 5)
    270 		a.Index = num
    271 	case "S":
    272 		if !isIndex {
    273 			return nil
    274 		}
    275 		a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_S & 15) << 5)
    276 		a.Index = num
    277 	case "D":
    278 		if !isIndex {
    279 			return nil
    280 		}
    281 		a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_D & 15) << 5)
    282 		a.Index = num
    283 	default:
    284 		return errors.New("unsupported register extension type: " + ext)
    285 	}
    286 
    287 	return nil
    288 }
    289 
    290 // ARM64RegisterArrangement parses an ARM64 vector register arrangement.
    291 func ARM64RegisterArrangement(reg int16, name, arng string) (int64, error) {
    292 	var curQ, curSize uint16
    293 	if name[0] != 'V' {
    294 		return 0, errors.New("expect V0 through V31; found: " + name)
    295 	}
    296 	if reg < 0 {
    297 		return 0, errors.New("invalid register number: " + name)
    298 	}
    299 	switch arng {
    300 	case "B8":
    301 		curSize = 0
    302 		curQ = 0
    303 	case "B16":
    304 		curSize = 0
    305 		curQ = 1
    306 	case "H4":
    307 		curSize = 1
    308 		curQ = 0
    309 	case "H8":
    310 		curSize = 1
    311 		curQ = 1
    312 	case "S2":
    313 		curSize = 2
    314 		curQ = 0
    315 	case "S4":
    316 		curSize = 2
    317 		curQ = 1
    318 	case "D1":
    319 		curSize = 3
    320 		curQ = 0
    321 	case "D2":
    322 		curSize = 3
    323 		curQ = 1
    324 	default:
    325 		return 0, errors.New("invalid arrangement in ARM64 register list")
    326 	}
    327 	return (int64(curQ) & 1 << 30) | (int64(curSize&3) << 10), nil
    328 }
    329 
    330 // ARM64RegisterListOffset generates offset encoding according to AArch64 specification.
    331 func ARM64RegisterListOffset(firstReg, regCnt int, arrangement int64) (int64, error) {
    332 	offset := int64(firstReg)
    333 	switch regCnt {
    334 	case 1:
    335 		offset |= 0x7 << 12
    336 	case 2:
    337 		offset |= 0xa << 12
    338 	case 3:
    339 		offset |= 0x6 << 12
    340 	case 4:
    341 		offset |= 0x2 << 12
    342 	default:
    343 		return 0, errors.New("invalid register numbers in ARM64 register list")
    344 	}
    345 	offset |= arrangement
    346 	// arm64 uses the 60th bit to differentiate from other archs
    347 	// For more details, refer to: obj/arm64/list7.go
    348 	offset |= 1 << 60
    349 	return offset, nil
    350 }