1
2
3
4
5 package main
6
7 import (
8 "fmt"
9 "log"
10 "regexp"
11 "strings"
12
13 "golang.org/x/arch/x86/xeddata"
14 )
15
16
17 type encoding struct {
18
19
20
21 opbyte string
22
23
24
25 opdigit string
26
27
28
29 vex struct {
30 P string
31 L string
32 M string
33 W string
34 }
35
36
37 evexScale string
38
39
40
41 evexBcstScale string
42
43
44
45 evex struct {
46
47
48
49 SAE bool
50 Rounding bool
51 Zeroing bool
52 }
53 }
54
55 type decoder struct {
56 ctx *context
57 insts []*instruction
58 }
59
60
61
62
63 func decodeGroups(ctx *context) {
64 d := decoder{ctx: ctx}
65 groups := make(map[string][]*instruction)
66 for _, inst := range d.DecodeAll() {
67 groups[inst.opcode] = append(groups[inst.opcode], inst)
68 }
69 for op, insts := range groups {
70 ctx.groups = append(ctx.groups, &instGroup{
71 opcode: op,
72 list: insts,
73 })
74 }
75 }
76
77
78 func (d *decoder) DecodeAll() []*instruction {
79 err := xeddata.WalkInsts(d.ctx.xedPath, func(inst *xeddata.Inst) {
80 inst.Pattern = xeddata.ExpandStates(d.ctx.db, inst.Pattern)
81 pset := xeddata.NewPatternSet(inst.Pattern)
82
83 opcode := inst.Iclass
84
85 switch {
86 case inst.HasAttribute("AMDONLY") || inst.Extension == "XOP":
87 return
88 case !pset.Is("VEX") && !pset.Is("EVEX"):
89 return
90 case inst.RealOpcode == "N":
91 return
92 }
93
94
95 pset.Replace("FIX_ROUND_LEN128()", "VL=0")
96 pset.Replace("FIX_ROUND_LEN512()", "VL=2")
97
98 mask, args := d.decodeArgs(pset, inst)
99 d.insts = append(d.insts, &instruction{
100 pset: pset,
101 opcode: opcode,
102 mask: mask,
103 args: args,
104 enc: d.decodePattern(pset, inst),
105 })
106 })
107 if err != nil {
108 log.Fatalf("walk insts: %v", err)
109 }
110 return d.insts
111 }
112
113
114 var registerArgs = map[string]argument{
115 "GPR32_R()": {"Yrl", "reg"},
116 "GPR64_R()": {"Yrl", "reg"},
117 "VGPR32_R()": {"Yrl", "reg"},
118 "VGPR64_R()": {"Yrl", "reg"},
119 "VGPR32_N()": {"Yrl", "regV"},
120 "VGPR64_N()": {"Yrl", "regV"},
121 "GPR32_B()": {"Yrl", "reg/mem"},
122 "GPR64_B()": {"Yrl", "reg/mem"},
123 "VGPR32_B()": {"Yrl", "reg/mem"},
124 "VGPR64_B()": {"Yrl", "reg/mem"},
125
126 "XMM_R()": {"Yxr", "reg"},
127 "XMM_R3()": {"YxrEvex", "reg"},
128 "XMM_N()": {"Yxr", "regV"},
129 "XMM_N3()": {"YxrEvex", "regV"},
130 "XMM_B()": {"Yxr", "reg/mem"},
131 "XMM_B3()": {"YxrEvex", "reg/mem"},
132 "XMM_SE()": {"Yxr", "regIH"},
133
134 "YMM_R()": {"Yyr", "reg"},
135 "YMM_R3()": {"YyrEvex", "reg"},
136 "YMM_N()": {"Yyr", "regV"},
137 "YMM_N3()": {"YyrEvex", "regV"},
138 "YMM_B()": {"Yyr", "reg/mem"},
139 "YMM_B3()": {"YyrEvex", "reg/mem"},
140 "YMM_SE()": {"Yyr", "regIH"},
141
142 "ZMM_R3()": {"Yzr", "reg"},
143 "ZMM_N3()": {"Yzr", "regV"},
144 "ZMM_B3()": {"Yzr", "reg/mem"},
145
146 "MASK_R()": {"Yk", "reg"},
147 "MASK_N()": {"Yk", "regV"},
148 "MASK_B()": {"Yk", "reg/mem"},
149
150 "MASKNOT0()": {"Yknot0", "kmask"},
151
152
153 "MASK1()": {"MASK1()", "MASK1()"},
154 }
155
156 func (d *decoder) decodeArgs(pset xeddata.PatternSet, inst *xeddata.Inst) (mask *argument, args []*argument) {
157 for i, f := range strings.Fields(inst.Operands) {
158 xarg, err := xeddata.NewOperand(d.ctx.db, f)
159 if err != nil {
160 log.Fatalf("%s: args[%d]: %v", inst, i, err)
161 }
162
163 switch {
164 case xarg.Action == "":
165 continue
166 case !xarg.IsVisible():
167 continue
168 }
169
170 arg := &argument{}
171 args = append(args, arg)
172
173 switch xarg.NameLHS() {
174 case "IMM0":
175 if xarg.Width != "b" {
176 log.Fatalf("%s: args[%d]: expected width=b, found %s", inst, i, xarg.Width)
177 }
178 if pset["IMM0SIGNED=1"] {
179 arg.ytype = "Yi8"
180 } else {
181 arg.ytype = "Yu8"
182 }
183 arg.zkind = "imm8"
184
185 case "REG0", "REG1", "REG2", "REG3":
186 rhs := xarg.NameRHS()
187 if rhs == "MASK1()" {
188 mask = arg
189 }
190 *arg = registerArgs[rhs]
191 if arg.ytype == "" {
192 log.Fatalf("%s: args[%d]: unexpected %s reg", inst, i, rhs)
193 }
194 if xarg.Attributes["MULTISOURCE4"] {
195 arg.ytype += "Multi4"
196 }
197
198 case "MEM0":
199 arg.ytype = pset.MatchOrDefault("Ym",
200 "VMODRM_XMM()", "Yxvm",
201 "VMODRM_YMM()", "Yyvm",
202 "UISA_VMODRM_XMM()", "YxvmEvex",
203 "UISA_VMODRM_YMM()", "YyvmEvex",
204 "UISA_VMODRM_ZMM()", "Yzvm",
205 )
206 arg.zkind = "reg/mem"
207
208 default:
209 log.Fatalf("%s: args[%d]: unexpected %s", inst, i, xarg.NameRHS())
210 }
211 }
212
213
214 for i := len(args)/2 - 1; i >= 0; i-- {
215 j := len(args) - 1 - i
216 args[i], args[j] = args[j], args[i]
217 }
218
219 return mask, args
220 }
221
222 func (d *decoder) decodePattern(pset xeddata.PatternSet, inst *xeddata.Inst) *encoding {
223 var enc encoding
224
225 enc.opdigit = d.findOpdigit(pset)
226 enc.opbyte = d.findOpbyte(pset, inst)
227
228 if strings.Contains(inst.Attributes, "DISP8_") {
229 enc.evexScale = d.findEVEXScale(pset)
230 enc.evexBcstScale = d.findEVEXBcstScale(pset, inst)
231 }
232
233 enc.vex.P = pset.Match(
234 "VEX_PREFIX=1", "66",
235 "VEX_PREFIX=2", "F2",
236 "VEX_PREFIX=3", "F3")
237 enc.vex.M = pset.Match(
238 "MAP=1", "0F",
239 "MAP=2", "0F38",
240 "MAP=3", "0F3A")
241 enc.vex.L = pset.MatchOrDefault("128",
242 "VL=0", "128",
243 "VL=1", "256",
244 "VL=2", "512")
245 enc.vex.W = pset.MatchOrDefault("W0",
246 "REXW=0", "W0",
247 "REXW=1", "W1")
248
249 if pset.Is("EVEX") {
250 enc.evex.SAE = strings.Contains(inst.Operands, "TXT=SAESTR")
251 enc.evex.Rounding = strings.Contains(inst.Operands, "TXT=ROUNDC")
252 enc.evex.Zeroing = strings.Contains(inst.Operands, "TXT=ZEROSTR")
253 }
254
255
256 parts := [...]*string{
257 &enc.evexScale, &enc.evexBcstScale,
258 &enc.vex.P, &enc.vex.M, &enc.vex.L, &enc.vex.W,
259 }
260 for _, p := range parts {
261 if *p == "" {
262 continue
263 }
264 if pset.Is("EVEX") {
265 *p = "evex" + *p
266 } else {
267 *p = "vex" + *p
268 }
269 }
270
271 return &enc
272 }
273
274 func (d *decoder) findOpdigit(pset xeddata.PatternSet) string {
275 reg := pset.Index(
276 "REG[0b000]",
277 "REG[0b001]",
278 "REG[0b010]",
279 "REG[0b011]",
280 "REG[0b100]",
281 "REG[0b101]",
282 "REG[0b110]",
283 "REG[0b111]",
284 )
285
286 if reg != -1 {
287 return fmt.Sprintf("0%d", reg)
288 }
289 return ""
290 }
291
292
293 var opbyteRE = regexp.MustCompile(`0x[0-9A-F]{2}`)
294
295 func (d *decoder) findOpbyte(pset xeddata.PatternSet, inst *xeddata.Inst) string {
296 opbyte := ""
297 for k := range pset {
298 if opbyteRE.MatchString(k) {
299 if opbyte == "" {
300 opbyte = k
301 } else {
302 log.Fatalf("%s: multiple opbytes", inst)
303 }
304 }
305 }
306 return opbyte
307 }
308
309 func (d *decoder) findEVEXScale(pset xeddata.PatternSet) string {
310 switch {
311 case pset["NELEM_FULL()"], pset["NELEM_FULLMEM()"]:
312 return pset.Match(
313 "VL=0", "N16",
314 "VL=1", "N32",
315 "VL=2", "N64")
316 case pset["NELEM_MOVDDUP()"]:
317 return pset.Match(
318 "VL=0", "N8",
319 "VL=1", "N32",
320 "VL=2", "N64")
321 case pset["NELEM_HALF()"], pset["NELEM_HALFMEM()"]:
322 return pset.Match(
323 "VL=0", "N8",
324 "VL=1", "N16",
325 "VL=2", "N32")
326 case pset["NELEM_QUARTERMEM()"]:
327 return pset.Match(
328 "VL=0", "N4",
329 "VL=1", "N8",
330 "VL=2", "N16")
331 case pset["NELEM_EIGHTHMEM()"]:
332 return pset.Match(
333 "VL=0", "N2",
334 "VL=1", "N4",
335 "VL=2", "N8")
336 case pset["NELEM_TUPLE2()"]:
337 return pset.Match(
338 "ESIZE_32_BITS()", "N8",
339 "ESIZE_64_BITS()", "N16")
340 case pset["NELEM_TUPLE4()"]:
341 return pset.Match(
342 "ESIZE_32_BITS()", "N16",
343 "ESIZE_64_BITS()", "N32")
344 case pset["NELEM_TUPLE8()"]:
345 return "N32"
346 case pset["NELEM_MEM128()"], pset["NELEM_TUPLE1_4X()"]:
347 return "N16"
348 }
349
350
351
352 scalars := [...]string{
353 "NELEM_SCALAR()",
354 "NELEM_GSCAT()",
355 "NELEM_GPR_READER()",
356 "NELEM_GPR_READER_BYTE()",
357 "NELEM_GPR_READER_WORD()",
358 "NELEM_GPR_WRITER_STORE()",
359 "NELEM_GPR_WRITER_STORE_BYTE()",
360 "NELEM_GPR_WRITER_STORE_WORD()",
361 "NELEM_GPR_WRITER_LDOP_D()",
362 "NELEM_GPR_WRITER_LDOP_Q()",
363 "NELEM_TUPLE1()",
364 "NELEM_TUPLE1_BYTE()",
365 "NELEM_TUPLE1_WORD()",
366 }
367 for _, scalar := range scalars {
368 if pset[scalar] {
369 return pset.Match(
370 "ESIZE_8_BITS()", "N1",
371 "ESIZE_16_BITS()", "N2",
372 "ESIZE_32_BITS()", "N4",
373 "ESIZE_64_BITS()", "N8")
374 }
375 }
376
377 return ""
378 }
379
380 func (d *decoder) findEVEXBcstScale(pset xeddata.PatternSet, inst *xeddata.Inst) string {
381
382 switch {
383 case pset["NELEM_FULL()"]:
384 return pset.Match(
385 "ESIZE_32_BITS()", "BcstN4",
386 "ESIZE_64_BITS()", "BcstN8")
387 case pset["NELEM_HALF()"]:
388 return "BcstN4"
389 default:
390 if inst.HasAttribute("BROADCAST_ENABLED") {
391 log.Fatalf("%s: unexpected tuple for bcst", inst)
392 }
393 return ""
394 }
395 }
396
View as plain text