github.com/stingnevermore/go@v0.0.0-20180120041312-3810f5bfed72/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 arrangment. 124 func ARM64RegisterExtension(a *obj.Addr, ext string, reg, num int16, isAmount, isIndex bool) error { 125 rm := uint32(reg) 126 switch ext { 127 case "UXTB": 128 if !isAmount { 129 return errors.New("invalid register extension") 130 } 131 a.Reg = arm64.REG_UXTB + (reg & 31) + int16(num<<5) 132 a.Offset = int64(((rm & 31) << 16) | (uint32(num) << 10)) 133 case "UXTH": 134 if !isAmount { 135 return errors.New("invalid register extension") 136 } 137 a.Reg = arm64.REG_UXTH + (num & 31) + int16(num<<5) 138 a.Offset = int64(((rm & 31) << 16) | (1 << 13) | (uint32(num) << 10)) 139 case "UXTW": 140 if !isAmount { 141 return errors.New("invalid register extension") 142 } 143 a.Reg = arm64.REG_UXTW + (reg & 31) + int16(num<<5) 144 a.Offset = int64(((rm & 31) << 16) | (2 << 13) | (uint32(num) << 10)) 145 case "UXTX": 146 if !isAmount { 147 return errors.New("invalid register extension") 148 } 149 a.Reg = arm64.REG_UXTX + (reg & 31) + int16(num<<5) 150 a.Offset = int64(((rm & 31) << 16) | (3 << 13) | (uint32(num) << 10)) 151 case "SXTB": 152 if !isAmount { 153 return errors.New("invalid register extension") 154 } 155 a.Reg = arm64.REG_SXTB + (reg & 31) + int16(num<<5) 156 a.Offset = int64(((rm & 31) << 16) | (4 << 13) | (uint32(num) << 10)) 157 case "SXTH": 158 if !isAmount { 159 return errors.New("invalid register extension") 160 } 161 a.Reg = arm64.REG_SXTH + (reg & 31) + int16(num<<5) 162 a.Offset = int64(((rm & 31) << 16) | (5 << 13) | (uint32(num) << 10)) 163 case "SXTW": 164 if !isAmount { 165 return errors.New("invalid register extension") 166 } 167 a.Reg = arm64.REG_SXTW + (reg & 31) + int16(num<<5) 168 a.Offset = int64(((rm & 31) << 16) | (6 << 13) | (uint32(num) << 10)) 169 case "SXTX": 170 if !isAmount { 171 return errors.New("invalid register extension") 172 } 173 a.Reg = arm64.REG_SXTX + (reg & 31) + int16(num<<5) 174 a.Offset = int64(((rm & 31) << 16) | (7 << 13) | (uint32(num) << 10)) 175 case "B8": 176 a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_8B & 15) << 5) 177 case "B16": 178 a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_16B & 15) << 5) 179 case "H4": 180 a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_4H & 15) << 5) 181 case "H8": 182 a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_8H & 15) << 5) 183 case "S2": 184 a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_2S & 15) << 5) 185 case "S4": 186 a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_4S & 15) << 5) 187 case "D2": 188 a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_2D & 15) << 5) 189 case "B": 190 if !isIndex { 191 return nil 192 } 193 a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_B & 15) << 5) 194 a.Index = num 195 case "H": 196 if !isIndex { 197 return nil 198 } 199 a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_H & 15) << 5) 200 a.Index = num 201 case "S": 202 if !isIndex { 203 return nil 204 } 205 a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_S & 15) << 5) 206 a.Index = num 207 case "D": 208 if !isIndex { 209 return nil 210 } 211 a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_D & 15) << 5) 212 a.Index = num 213 default: 214 return errors.New("unsupported register extension type: " + ext) 215 } 216 a.Type = obj.TYPE_REG 217 return nil 218 } 219 220 // ARM64RegisterArrangement parses an ARM64 vector register arrangment. 221 func ARM64RegisterArrangement(reg int16, name, arng string) (int64, error) { 222 var curQ, curSize uint16 223 if name[0] != 'V' { 224 return 0, errors.New("expect V0 through V31; found: " + name) 225 } 226 if reg < 0 { 227 return 0, errors.New("invalid register number: " + name) 228 } 229 switch arng { 230 case "B8": 231 curSize = 0 232 curQ = 0 233 case "B16": 234 curSize = 0 235 curQ = 1 236 case "H4": 237 curSize = 1 238 curQ = 0 239 case "H8": 240 curSize = 1 241 curQ = 1 242 case "S2": 243 curSize = 1 244 curQ = 0 245 case "S4": 246 curSize = 2 247 curQ = 1 248 case "D1": 249 curSize = 3 250 curQ = 0 251 case "D2": 252 curSize = 3 253 curQ = 1 254 default: 255 return 0, errors.New("invalid arrangement in ARM64 register list") 256 } 257 return (int64(curQ) & 1 << 30) | (int64(curSize&3) << 10), nil 258 } 259 260 // ARM64RegisterListOffset generates offset encoding according to AArch64 specification. 261 func ARM64RegisterListOffset(firstReg, regCnt int, arrangement int64) (int64, error) { 262 offset := int64(firstReg) 263 switch regCnt { 264 case 1: 265 offset |= 0x7 << 12 266 case 2: 267 offset |= 0xa << 12 268 case 3: 269 offset |= 0x6 << 12 270 case 4: 271 offset |= 0x2 << 12 272 default: 273 return 0, errors.New("invalid register numbers in ARM64 register list") 274 } 275 offset |= arrangement 276 // arm64 uses the 60th bit to differentiate from other archs 277 // For more details, refer to: obj/arm64/list7.go 278 offset |= 1 << 60 279 return offset, nil 280 }