podman

Форк
0
350 строк · 8.5 Кб
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
	"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
// 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
		return true
77
	}
78
	// atomic instructions
79
	if arm64.IsAtomicInstruction(op) {
80
		return true
81
	}
82
	return false
83
}
84

85
// ARM64Suffix handles the special suffix for the ARM64.
86
// It returns a boolean to indicate success; failure means
87
// cond was unrecognized.
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
// parseARM64Suffix parses the suffix attached to an ARM64 instruction.
101
// The input is a single string consisting of period-separated condition
102
// codes, such as ".P.W". An initial period is ignored.
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 { // not 31
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
// IsARM64TBL reports whether the op (as defined by an arm64.A*
129
// constant) is one of the table lookup instructions that require special
130
// handling.
131
func IsARM64TBL(op obj.As) bool {
132
	return op == arm64.AVTBL
133
}
134

135
// ARM64RegisterExtension parses an ARM64 register with extension or arrangement.
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
		// effective address of memory is a base register value and an offset register value.
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
// ARM64RegisterArrangement parses an ARM64 vector register arrangement.
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
// ARM64RegisterListOffset generates offset encoding according to AArch64 specification.
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
	// arm64 uses the 60th bit to differentiate from other archs
347
	// For more details, refer to: obj/arm64/list7.go
348
	offset |= 1 << 60
349
	return offset, nil
350
}
351

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.