github.com/epfl-dcsl/gotee@v0.0.0-20200909122901-014b35f5e5e9/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 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 a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_8B & 15) << 5) 182 case "B16": 183 a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_16B & 15) << 5) 184 case "H4": 185 a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_4H & 15) << 5) 186 case "H8": 187 a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_8H & 15) << 5) 188 case "S2": 189 a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_2S & 15) << 5) 190 case "S4": 191 a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_4S & 15) << 5) 192 case "D2": 193 a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_2D & 15) << 5) 194 case "B": 195 if !isIndex { 196 return nil 197 } 198 a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_B & 15) << 5) 199 a.Index = num 200 case "H": 201 if !isIndex { 202 return nil 203 } 204 a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_H & 15) << 5) 205 a.Index = num 206 case "S": 207 if !isIndex { 208 return nil 209 } 210 a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_S & 15) << 5) 211 a.Index = num 212 case "D": 213 if !isIndex { 214 return nil 215 } 216 a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_D & 15) << 5) 217 a.Index = num 218 default: 219 return errors.New("unsupported register extension type: " + ext) 220 } 221 a.Type = obj.TYPE_REG 222 return nil 223 } 224 225 // ARM64RegisterArrangement parses an ARM64 vector register arrangment. 226 func ARM64RegisterArrangement(reg int16, name, arng string) (int64, error) { 227 var curQ, curSize uint16 228 if name[0] != 'V' { 229 return 0, errors.New("expect V0 through V31; found: " + name) 230 } 231 if reg < 0 { 232 return 0, errors.New("invalid register number: " + name) 233 } 234 switch arng { 235 case "B8": 236 curSize = 0 237 curQ = 0 238 case "B16": 239 curSize = 0 240 curQ = 1 241 case "H4": 242 curSize = 1 243 curQ = 0 244 case "H8": 245 curSize = 1 246 curQ = 1 247 case "S2": 248 curSize = 1 249 curQ = 0 250 case "S4": 251 curSize = 2 252 curQ = 1 253 case "D1": 254 curSize = 3 255 curQ = 0 256 case "D2": 257 curSize = 3 258 curQ = 1 259 default: 260 return 0, errors.New("invalid arrangement in ARM64 register list") 261 } 262 return (int64(curQ) & 1 << 30) | (int64(curSize&3) << 10), nil 263 } 264 265 // ARM64RegisterListOffset generates offset encoding according to AArch64 specification. 266 func ARM64RegisterListOffset(firstReg, regCnt int, arrangement int64) (int64, error) { 267 offset := int64(firstReg) 268 switch regCnt { 269 case 1: 270 offset |= 0x7 << 12 271 case 2: 272 offset |= 0xa << 12 273 case 3: 274 offset |= 0x6 << 12 275 case 4: 276 offset |= 0x2 << 12 277 default: 278 return 0, errors.New("invalid register numbers in ARM64 register list") 279 } 280 offset |= arrangement 281 // arm64 uses the 60th bit to differentiate from other archs 282 // For more details, refer to: obj/arm64/list7.go 283 offset |= 1 << 60 284 return offset, nil 285 }