1
2
3
4
5 package x86
6
7 import (
8 "github.com/twitchyliquid64/golang-asm/obj"
9 "errors"
10 "fmt"
11 "strings"
12 )
13
14
15 type evexBits struct {
16 b1 byte
17 b2 byte
18
19
20 opcode byte
21 }
22
23
24 func newEVEXBits(z int, enc *opBytes) evexBits {
25 return evexBits{
26 b1: enc[z+0],
27 b2: enc[z+1],
28 opcode: enc[z+2],
29 }
30 }
31
32
33 func (evex evexBits) P() byte { return (evex.b1 & evexP) >> 0 }
34
35
36 func (evex evexBits) L() byte { return (evex.b1 & evexL) >> 2 }
37
38
39 func (evex evexBits) M() byte { return (evex.b1 & evexM) >> 4 }
40
41
42 func (evex evexBits) W() byte { return (evex.b1 & evexW) >> 7 }
43
44
45 func (evex evexBits) BroadcastEnabled() bool {
46 return evex.b2&evexBcst != 0
47 }
48
49
50 func (evex evexBits) ZeroingEnabled() bool {
51 return (evex.b2&evexZeroing)>>2 != 0
52 }
53
54
55
56 func (evex evexBits) RoundingEnabled() bool {
57 return (evex.b2&evexRounding)>>1 != 0
58 }
59
60
61 func (evex evexBits) SaeEnabled() bool {
62 return (evex.b2&evexSae)>>0 != 0
63 }
64
65
66
67
68 func (evex evexBits) DispMultiplier(bcst bool) int32 {
69 if bcst {
70 switch evex.b2 & evexBcst {
71 case evexBcstN4:
72 return 4
73 case evexBcstN8:
74 return 8
75 }
76 return 1
77 }
78
79 switch evex.b2 & evexN {
80 case evexN1:
81 return 1
82 case evexN2:
83 return 2
84 case evexN4:
85 return 4
86 case evexN8:
87 return 8
88 case evexN16:
89 return 16
90 case evexN32:
91 return 32
92 case evexN64:
93 return 64
94 case evexN128:
95 return 128
96 }
97 return 1
98 }
99
100
101
102 const (
103 evexW = 0x80
104 evexWIG = 0 << 7
105 evexW0 = 0 << 7
106 evexW1 = 1 << 7
107
108 evexM = 0x30
109 evex0F = 1 << 4
110 evex0F38 = 2 << 4
111 evex0F3A = 3 << 4
112
113 evexL = 0x0C
114 evexLIG = 0 << 2
115 evex128 = 0 << 2
116 evex256 = 1 << 2
117 evex512 = 2 << 2
118
119 evexP = 0x03
120 evex66 = 1 << 0
121 evexF3 = 2 << 0
122 evexF2 = 3 << 0
123
124
125
126
127 evexN = 0xE0
128 evexN1 = 0 << 5
129 evexN2 = 1 << 5
130 evexN4 = 2 << 5
131 evexN8 = 3 << 5
132 evexN16 = 4 << 5
133 evexN32 = 5 << 5
134 evexN64 = 6 << 5
135 evexN128 = 7 << 5
136
137
138 evexBcst = 0x18
139 evexBcstN4 = 1 << 3
140 evexBcstN8 = 2 << 3
141
142
143
144 evexZeroing = 0x4
145 evexZeroingEnabled = 1 << 2
146 evexRounding = 0x2
147 evexRoundingEnabled = 1 << 1
148 evexSae = 0x1
149 evexSaeEnabled = 1 << 0
150 )
151
152
153 func compressedDisp8(disp, elemSize int32) (disp8 byte, ok bool) {
154 if disp%elemSize == 0 {
155 v := disp / elemSize
156 if v >= -128 && v <= 127 {
157 return byte(v), true
158 }
159 }
160 return 0, false
161 }
162
163
164 func evexZcase(zcase uint8) bool {
165 return zcase > Zevex_first && zcase < Zevex_last
166 }
167
168
169
170
171
172
173
174
175 type evexSuffix struct {
176 rounding byte
177 sae bool
178 zeroing bool
179 broadcast bool
180 }
181
182
183
184 const (
185 rcRNSAE = 0
186 rcRDSAE = 1
187 rcRUSAE = 2
188 rcRZSAE = 3
189 rcUnset = 4
190 )
191
192
193 func newEVEXSuffix() evexSuffix {
194 return evexSuffix{rounding: rcUnset}
195 }
196
197
198
199 var evexSuffixMap [255]evexSuffix
200
201 func init() {
202
203 for i := range opSuffixTable {
204 suffix := newEVEXSuffix()
205 parts := strings.Split(opSuffixTable[i], ".")
206 for j := range parts {
207 switch parts[j] {
208 case "Z":
209 suffix.zeroing = true
210 case "BCST":
211 suffix.broadcast = true
212 case "SAE":
213 suffix.sae = true
214
215 case "RN_SAE":
216 suffix.rounding = rcRNSAE
217 case "RD_SAE":
218 suffix.rounding = rcRDSAE
219 case "RU_SAE":
220 suffix.rounding = rcRUSAE
221 case "RZ_SAE":
222 suffix.rounding = rcRZSAE
223 }
224 }
225 evexSuffixMap[i] = suffix
226 }
227 }
228
229
230 func toDisp8(disp int32, p *obj.Prog, asmbuf *AsmBuf) (disp8 byte, ok bool) {
231 if asmbuf.evexflag {
232 bcst := evexSuffixMap[p.Scond].broadcast
233 elemSize := asmbuf.evex.DispMultiplier(bcst)
234 return compressedDisp8(disp, elemSize)
235 }
236 return byte(disp), disp >= -128 && disp < 128
237 }
238
239
240
241 func EncodeRegisterRange(reg0, reg1 int16) int64 {
242 return (int64(reg0) << 0) |
243 (int64(reg1) << 16) |
244 obj.RegListX86Lo
245 }
246
247
248 func decodeRegisterRange(list int64) (reg0, reg1 int) {
249 return int((list >> 0) & 0xFFFF),
250 int((list >> 16) & 0xFFFF)
251 }
252
253
254
255
256
257 func ParseSuffix(p *obj.Prog, cond string) error {
258 cond = strings.TrimPrefix(cond, ".")
259
260 suffix := newOpSuffix(cond)
261 if !suffix.IsValid() {
262 return inferSuffixError(cond)
263 }
264
265 p.Scond = uint8(suffix)
266 return nil
267 }
268
269
270
271
272
273
274
275
276
277
278
279
280 func inferSuffixError(cond string) error {
281 suffixSet := make(map[string]bool)
282 unknownSet := make(map[string]bool)
283 hasBcst := false
284 hasRoundSae := false
285 var msg []string
286
287 suffixes := strings.Split(cond, ".")
288 for i, suffix := range suffixes {
289 switch suffix {
290 case "Z":
291 if i != len(suffixes)-1 {
292 msg = append(msg, "Z suffix should be the last")
293 }
294 case "BCST":
295 hasBcst = true
296 case "SAE", "RN_SAE", "RZ_SAE", "RD_SAE", "RU_SAE":
297 hasRoundSae = true
298 default:
299 if !unknownSet[suffix] {
300 msg = append(msg, fmt.Sprintf("unknown suffix %q", suffix))
301 }
302 unknownSet[suffix] = true
303 }
304
305 if suffixSet[suffix] {
306 msg = append(msg, fmt.Sprintf("duplicate suffix %q", suffix))
307 }
308 suffixSet[suffix] = true
309 }
310
311 if hasBcst && hasRoundSae {
312 msg = append(msg, "can't combine rounding/SAE and broadcast")
313 }
314
315 if len(msg) == 0 {
316 return errors.New("bad suffix combination")
317 }
318 return errors.New(strings.Join(msg, "; "))
319 }
320
321
322
323
324 var opSuffixTable = [...]string{
325 "",
326
327 "Z",
328
329 "SAE",
330 "SAE.Z",
331
332 "RN_SAE",
333 "RZ_SAE",
334 "RD_SAE",
335 "RU_SAE",
336 "RN_SAE.Z",
337 "RZ_SAE.Z",
338 "RD_SAE.Z",
339 "RU_SAE.Z",
340
341 "BCST",
342 "BCST.Z",
343
344 "<bad suffix>",
345 }
346
347
348
349
350
351 type opSuffix uint8
352
353
354 const badOpSuffix = opSuffix(len(opSuffixTable) - 1)
355
356
357
358
359
360 func newOpSuffix(suffixes string) opSuffix {
361 for i := range opSuffixTable {
362 if opSuffixTable[i] == suffixes {
363 return opSuffix(i)
364 }
365 }
366 return badOpSuffix
367 }
368
369
370
371 func (suffix opSuffix) IsValid() bool {
372 return suffix != badOpSuffix
373 }
374
375
376
377
378
379
380 func (suffix opSuffix) String() string {
381 return opSuffixTable[suffix]
382 }
383
View as plain text