github.com/corona10/go@v0.0.0-20180224231303-7a218942be57/src/cmd/asm/internal/arch/arm64.go (about) 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 "cmd/internal/obj" 13 "cmd/internal/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 return true 76 } 77 return false 78 } 79 80 // ARM64Suffix handles the special suffix for the ARM64. 81 // It returns a boolean to indicate success; failure means 82 // cond was unrecognized. 83 func ARM64Suffix(prog *obj.Prog, cond string) bool { 84 if cond == "" { 85 return true 86 } 87 bits, ok := ParseARM64Suffix(cond) 88 if !ok { 89 return false 90 } 91 prog.Scond = bits 92 return true 93 } 94 95 // ParseARM64Suffix parses the suffix attached to an ARM64 instruction. 96 // The input is a single string consisting of period-separated condition 97 // codes, such as ".P.W". An initial period is ignored. 98 func ParseARM64Suffix(cond string) (uint8, bool) { 99 if cond == "" { 100 return 0, true 101 } 102 return parseARMCondition(cond, arm64LS, nil) 103 } 104 105 func arm64RegisterNumber(name string, n int16) (int16, bool) { 106 switch name { 107 case "F": 108 if 0 <= n && n <= 31 { 109 return arm64.REG_F0 + n, true 110 } 111 case "R": 112 if 0 <= n && n <= 30 { // not 31 113 return arm64.REG_R0 + n, true 114 } 115 case "V": 116 if 0 <= n && n <= 31 { 117 return arm64.REG_V0 + n, true 118 } 119 } 120 return 0, false 121 } 122 123 // ARM64RegisterExtension parses an ARM64 register with extension or arrangement. 124 func ARM64RegisterExtension(a *obj.Addr, ext string, reg, num int16, isAmount, isIndex bool) error { 125 rm := uint32(reg) 126 if isAmount { 127 if num < 0 || num > 7 { 128 return errors.New("shift amount out of range") 129 } 130 } 131 switch ext { 132 case "UXTB": 133 if !isAmount { 134 return errors.New("invalid register extension") 135 } 136 a.Reg = arm64.REG_UXTB + (reg & 31) + int16(num<<5) 137 a.Offset = int64(((rm & 31) << 16) | (uint32(num) << 10)) 138 case "UXTH": 139 if !isAmount { 140 return errors.New("invalid register extension") 141 } 142 a.Reg = arm64.REG_UXTH + (reg & 31) + int16(num<<5) 143 a.Offset = int64(((rm & 31) << 16) | (1 << 13) | (uint32(num) << 10)) 144 case "UXTW": 145 if !isAmount { 146 return errors.New("invalid register extension") 147 } 148 a.Reg = arm64.REG_UXTW + (reg & 31) + int16(num<<5) 149 a.Offset = int64(((rm & 31) << 16) | (2 << 13) | (uint32(num) << 10)) 150 case "UXTX": 151 if !isAmount { 152 return errors.New("invalid register extension") 153 } 154 a.Reg = arm64.REG_UXTX + (reg & 31) + int16(num<<5) 155 a.Offset = int64(((rm & 31) << 16) | (3 << 13) | (uint32(num) << 10)) 156 case "SXTB": 157 if !isAmount { 158 return errors.New("invalid register extension") 159 } 160 a.Reg = arm64.REG_SXTB + (reg & 31) + int16(num<<5) 161 a.Offset = int64(((rm & 31) << 16) | (4 << 13) | (uint32(num) << 10)) 162 case "SXTH": 163 if !isAmount { 164 return errors.New("invalid register extension") 165 } 166 a.Reg = arm64.REG_SXTH + (reg & 31) + int16(num<<5) 167 a.Offset = int64(((rm & 31) << 16) | (5 << 13) | (uint32(num) << 10)) 168 case "SXTW": 169 if !isAmount { 170 return errors.New("invalid register extension") 171 } 172 a.Reg = arm64.REG_SXTW + (reg & 31) + int16(num<<5) 173 a.Offset = int64(((rm & 31) << 16) | (6 << 13) | (uint32(num) << 10)) 174 case "SXTX": 175 if !isAmount { 176 return errors.New("invalid register extension") 177 } 178 a.Reg = arm64.REG_SXTX + (reg & 31) + int16(num<<5) 179 a.Offset = int64(((rm & 31) << 16) | (7 << 13) | (uint32(num) << 10)) 180 case "B8": 181 if isIndex { 182 return errors.New("invalid register extension") 183 } 184 a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_8B & 15) << 5) 185 case "B16": 186 if isIndex { 187 return errors.New("invalid register extension") 188 } 189 a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_16B & 15) << 5) 190 case "H4": 191 if isIndex { 192 return errors.New("invalid register extension") 193 } 194 a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_4H & 15) << 5) 195 case "H8": 196 if isIndex { 197 return errors.New("invalid register extension") 198 } 199 a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_8H & 15) << 5) 200 case "S2": 201 if isIndex { 202 return errors.New("invalid register extension") 203 } 204 a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_2S & 15) << 5) 205 case "S4": 206 if isIndex { 207 return errors.New("invalid register extension") 208 } 209 a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_4S & 15) << 5) 210 case "D2": 211 if isIndex { 212 return errors.New("invalid register extension") 213 } 214 a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_2D & 15) << 5) 215 case "B": 216 if !isIndex { 217 return nil 218 } 219 a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_B & 15) << 5) 220 a.Index = num 221 case "H": 222 if !isIndex { 223 return nil 224 } 225 a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_H & 15) << 5) 226 a.Index = num 227 case "S": 228 if !isIndex { 229 return nil 230 } 231 a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_S & 15) << 5) 232 a.Index = num 233 case "D": 234 if !isIndex { 235 return nil 236 } 237 a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_D & 15) << 5) 238 a.Index = num 239 default: 240 return errors.New("unsupported register extension type: " + ext) 241 } 242 a.Type = obj.TYPE_REG 243 return nil 244 } 245 246 // ARM64RegisterArrangement parses an ARM64 vector register arrangement. 247 func ARM64RegisterArrangement(reg int16, name, arng string) (int64, error) { 248 var curQ, curSize uint16 249 if name[0] != 'V' { 250 return 0, errors.New("expect V0 through V31; found: " + name) 251 } 252 if reg < 0 { 253 return 0, errors.New("invalid register number: " + name) 254 } 255 switch arng { 256 case "B8": 257 curSize = 0 258 curQ = 0 259 case "B16": 260 curSize = 0 261 curQ = 1 262 case "H4": 263 curSize = 1 264 curQ = 0 265 case "H8": 266 curSize = 1 267 curQ = 1 268 case "S2": 269 curSize = 1 270 curQ = 0 271 case "S4": 272 curSize = 2 273 curQ = 1 274 case "D1": 275 curSize = 3 276 curQ = 0 277 case "D2": 278 curSize = 3 279 curQ = 1 280 default: 281 return 0, errors.New("invalid arrangement in ARM64 register list") 282 } 283 return (int64(curQ) & 1 << 30) | (int64(curSize&3) << 10), nil 284 } 285 286 // ARM64RegisterListOffset generates offset encoding according to AArch64 specification. 287 func ARM64RegisterListOffset(firstReg, regCnt int, arrangement int64) (int64, error) { 288 offset := int64(firstReg) 289 switch regCnt { 290 case 1: 291 offset |= 0x7 << 12 292 case 2: 293 offset |= 0xa << 12 294 case 3: 295 offset |= 0x6 << 12 296 case 4: 297 offset |= 0x2 << 12 298 default: 299 return 0, errors.New("invalid register numbers in ARM64 register list") 300 } 301 offset |= arrangement 302 // arm64 uses the 60th bit to differentiate from other archs 303 // For more details, refer to: obj/arm64/list7.go 304 offset |= 1 << 60 305 return offset, nil 306 }