github.com/zxy12/go_duplicate_112_new@v0.0.0-20200807091221-747231827200/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 arm64.ASTXP, arm64.ASTXPW, arm64.ASTLXP, arm64.ASTLXPW, 76 arm64.ASWPB, arm64.ASWPH, arm64.ASWPW, arm64.ASWPD, 77 arm64.ASWPALB, arm64.ASWPALH, arm64.ASWPALW, arm64.ASWPALD, 78 arm64.ALDADDB, arm64.ALDADDH, arm64.ALDADDW, arm64.ALDADDD, 79 arm64.ALDANDB, arm64.ALDANDH, arm64.ALDANDW, arm64.ALDANDD, 80 arm64.ALDEORB, arm64.ALDEORH, arm64.ALDEORW, arm64.ALDEORD, 81 arm64.ALDORB, arm64.ALDORH, arm64.ALDORW, arm64.ALDORD, 82 arm64.ALDADDALD, arm64.ALDADDALW, arm64.ALDADDALH, arm64.ALDADDALB: 83 return true 84 } 85 return false 86 } 87 88 // ARM64Suffix handles the special suffix for the ARM64. 89 // It returns a boolean to indicate success; failure means 90 // cond was unrecognized. 91 func ARM64Suffix(prog *obj.Prog, cond string) bool { 92 if cond == "" { 93 return true 94 } 95 bits, ok := parseARM64Suffix(cond) 96 if !ok { 97 return false 98 } 99 prog.Scond = bits 100 return true 101 } 102 103 // parseARM64Suffix parses the suffix attached to an ARM64 instruction. 104 // The input is a single string consisting of period-separated condition 105 // codes, such as ".P.W". An initial period is ignored. 106 func parseARM64Suffix(cond string) (uint8, bool) { 107 if cond == "" { 108 return 0, true 109 } 110 return parseARMCondition(cond, arm64LS, nil) 111 } 112 113 func arm64RegisterNumber(name string, n int16) (int16, bool) { 114 switch name { 115 case "F": 116 if 0 <= n && n <= 31 { 117 return arm64.REG_F0 + n, true 118 } 119 case "R": 120 if 0 <= n && n <= 30 { // not 31 121 return arm64.REG_R0 + n, true 122 } 123 case "V": 124 if 0 <= n && n <= 31 { 125 return arm64.REG_V0 + n, true 126 } 127 } 128 return 0, false 129 } 130 131 // IsARM64TBL reports whether the op (as defined by an arm64.A* 132 // constant) is one of the table lookup instructions that require special 133 // handling. 134 func IsARM64TBL(op obj.As) bool { 135 return op == arm64.AVTBL 136 } 137 138 // ARM64RegisterExtension parses an ARM64 register with extension or arrangement. 139 func ARM64RegisterExtension(a *obj.Addr, ext string, reg, num int16, isAmount, isIndex bool) error { 140 Rnum := (reg & 31) + int16(num<<5) 141 if isAmount { 142 if num < 0 || num > 7 { 143 return errors.New("index shift amount is out of range") 144 } 145 } 146 switch ext { 147 case "UXTB": 148 if !isAmount { 149 return errors.New("invalid register extension") 150 } 151 if a.Type == obj.TYPE_MEM { 152 return errors.New("invalid shift for the register offset addressing mode") 153 } 154 a.Reg = arm64.REG_UXTB + Rnum 155 case "UXTH": 156 if !isAmount { 157 return errors.New("invalid register extension") 158 } 159 if a.Type == obj.TYPE_MEM { 160 return errors.New("invalid shift for the register offset addressing mode") 161 } 162 a.Reg = arm64.REG_UXTH + Rnum 163 case "UXTW": 164 if !isAmount { 165 return errors.New("invalid register extension") 166 } 167 // effective address of memory is a base register value and an offset register value. 168 if a.Type == obj.TYPE_MEM { 169 a.Index = arm64.REG_UXTW + Rnum 170 } else { 171 a.Reg = arm64.REG_UXTW + Rnum 172 } 173 case "UXTX": 174 if !isAmount { 175 return errors.New("invalid register extension") 176 } 177 if a.Type == obj.TYPE_MEM { 178 return errors.New("invalid shift for the register offset addressing mode") 179 } 180 a.Reg = arm64.REG_UXTX + Rnum 181 case "SXTB": 182 if !isAmount { 183 return errors.New("invalid register extension") 184 } 185 a.Reg = arm64.REG_SXTB + Rnum 186 case "SXTH": 187 if !isAmount { 188 return errors.New("invalid register extension") 189 } 190 if a.Type == obj.TYPE_MEM { 191 return errors.New("invalid shift for the register offset addressing mode") 192 } 193 a.Reg = arm64.REG_SXTH + Rnum 194 case "SXTW": 195 if !isAmount { 196 return errors.New("invalid register extension") 197 } 198 if a.Type == obj.TYPE_MEM { 199 a.Index = arm64.REG_SXTW + Rnum 200 } else { 201 a.Reg = arm64.REG_SXTW + Rnum 202 } 203 case "SXTX": 204 if !isAmount { 205 return errors.New("invalid register extension") 206 } 207 if a.Type == obj.TYPE_MEM { 208 a.Index = arm64.REG_SXTX + Rnum 209 } else { 210 a.Reg = arm64.REG_SXTX + Rnum 211 } 212 case "LSL": 213 if !isAmount { 214 return errors.New("invalid register extension") 215 } 216 a.Index = arm64.REG_LSL + Rnum 217 case "B8": 218 if isIndex { 219 return errors.New("invalid register extension") 220 } 221 a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_8B & 15) << 5) 222 case "B16": 223 if isIndex { 224 return errors.New("invalid register extension") 225 } 226 a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_16B & 15) << 5) 227 case "H4": 228 if isIndex { 229 return errors.New("invalid register extension") 230 } 231 a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_4H & 15) << 5) 232 case "H8": 233 if isIndex { 234 return errors.New("invalid register extension") 235 } 236 a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_8H & 15) << 5) 237 case "S2": 238 if isIndex { 239 return errors.New("invalid register extension") 240 } 241 a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_2S & 15) << 5) 242 case "S4": 243 if isIndex { 244 return errors.New("invalid register extension") 245 } 246 a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_4S & 15) << 5) 247 case "D1": 248 if isIndex { 249 return errors.New("invalid register extension") 250 } 251 a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_1D & 15) << 5) 252 case "D2": 253 if isIndex { 254 return errors.New("invalid register extension") 255 } 256 a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_2D & 15) << 5) 257 case "Q1": 258 if isIndex { 259 return errors.New("invalid register extension") 260 } 261 a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_1Q & 15) << 5) 262 case "B": 263 if !isIndex { 264 return nil 265 } 266 a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_B & 15) << 5) 267 a.Index = num 268 case "H": 269 if !isIndex { 270 return nil 271 } 272 a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_H & 15) << 5) 273 a.Index = num 274 case "S": 275 if !isIndex { 276 return nil 277 } 278 a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_S & 15) << 5) 279 a.Index = num 280 case "D": 281 if !isIndex { 282 return nil 283 } 284 a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_D & 15) << 5) 285 a.Index = num 286 default: 287 return errors.New("unsupported register extension type: " + ext) 288 } 289 290 return nil 291 } 292 293 // ARM64RegisterArrangement parses an ARM64 vector register arrangement. 294 func ARM64RegisterArrangement(reg int16, name, arng string) (int64, error) { 295 var curQ, curSize uint16 296 if name[0] != 'V' { 297 return 0, errors.New("expect V0 through V31; found: " + name) 298 } 299 if reg < 0 { 300 return 0, errors.New("invalid register number: " + name) 301 } 302 switch arng { 303 case "B8": 304 curSize = 0 305 curQ = 0 306 case "B16": 307 curSize = 0 308 curQ = 1 309 case "H4": 310 curSize = 1 311 curQ = 0 312 case "H8": 313 curSize = 1 314 curQ = 1 315 case "S2": 316 curSize = 2 317 curQ = 0 318 case "S4": 319 curSize = 2 320 curQ = 1 321 case "D1": 322 curSize = 3 323 curQ = 0 324 case "D2": 325 curSize = 3 326 curQ = 1 327 default: 328 return 0, errors.New("invalid arrangement in ARM64 register list") 329 } 330 return (int64(curQ) & 1 << 30) | (int64(curSize&3) << 10), nil 331 } 332 333 // ARM64RegisterListOffset generates offset encoding according to AArch64 specification. 334 func ARM64RegisterListOffset(firstReg, regCnt int, arrangement int64) (int64, error) { 335 offset := int64(firstReg) 336 switch regCnt { 337 case 1: 338 offset |= 0x7 << 12 339 case 2: 340 offset |= 0xa << 12 341 case 3: 342 offset |= 0x6 << 12 343 case 4: 344 offset |= 0x2 << 12 345 default: 346 return 0, errors.New("invalid register numbers in ARM64 register list") 347 } 348 offset |= arrangement 349 // arm64 uses the 60th bit to differentiate from other archs 350 // For more details, refer to: obj/arm64/list7.go 351 offset |= 1 << 60 352 return offset, nil 353 }