1
2
3
4
5
6
7
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
56
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
69
70
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
79 if arm64.IsAtomicInstruction(op) {
80 return true
81 }
82 return false
83 }
84
85
86
87
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
101
102
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 {
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
129
130
131 func IsARM64TBL(op obj.As) bool {
132 return op == arm64.AVTBL
133 }
134
135
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
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
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
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
347
348 offset |= 1 << 60
349 return offset, nil
350 }
351
View as plain text