Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1#!/bin/awk -f
2# SPDX-License-Identifier: GPL-2.0
3# gen-insn-attr-x86.awk: Instruction attribute table generator
4# Written by Masami Hiramatsu <mhiramat@redhat.com>
5#
6# Usage: awk -f gen-insn-attr-x86.awk x86-opcode-map.txt > inat-tables.c
7
8# Awk implementation sanity check
9function check_awk_implement() {
10 if (sprintf("%x", 0) != "0")
11 return "Your awk has a printf-format problem."
12 return ""
13}
14
15# Clear working vars
16function clear_vars() {
17 delete table
18 delete lptable2
19 delete lptable1
20 delete lptable3
21 eid = -1 # escape id
22 gid = -1 # group id
23 aid = -1 # AVX id
24 xopid = -1 # XOP id
25 tname = ""
26}
27
28BEGIN {
29 # Implementation error checking
30 awkchecked = check_awk_implement()
31 if (awkchecked != "") {
32 print "Error: " awkchecked > "/dev/stderr"
33 print "Please try to use gawk." > "/dev/stderr"
34 exit 1
35 }
36
37 # Setup generating tables
38 print "/* x86 opcode map generated from x86-opcode-map.txt */"
39 print "/* Do not change this code. */\n"
40 ggid = 1
41 geid = 1
42 gaid = 0
43 gxopid = 0
44 delete etable
45 delete gtable
46 delete atable
47 delete xoptable
48
49 opnd_expr = "^[A-Za-z/]"
50 ext_expr = "^\\("
51 sep_expr = "^\\|$"
52 group_expr = "^Grp[0-9A-Za-z]+"
53
54 imm_expr = "^[IJAOL][a-z]"
55 imm_flag["Ib"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)"
56 imm_flag["Jb"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)"
57 imm_flag["Iw"] = "INAT_MAKE_IMM(INAT_IMM_WORD)"
58 imm_flag["Id"] = "INAT_MAKE_IMM(INAT_IMM_DWORD)"
59 imm_flag["Iq"] = "INAT_MAKE_IMM(INAT_IMM_QWORD)"
60 imm_flag["Ap"] = "INAT_MAKE_IMM(INAT_IMM_PTR)"
61 imm_flag["Iz"] = "INAT_MAKE_IMM(INAT_IMM_VWORD32)"
62 imm_flag["Jz"] = "INAT_MAKE_IMM(INAT_IMM_VWORD32)"
63 imm_flag["Iv"] = "INAT_MAKE_IMM(INAT_IMM_VWORD)"
64 imm_flag["Ob"] = "INAT_MOFFSET"
65 imm_flag["Ov"] = "INAT_MOFFSET"
66 imm_flag["Lx"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)"
67 imm_flag["Lo"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)"
68
69 modrm_expr = "^([CDEGMNPQRSUVW/][a-z]+|NTA|T[012])"
70 force64_expr = "\\([df]64\\)"
71 invalid64_expr = "\\(i64\\)"
72 only64_expr = "\\(o64\\)"
73 rex_expr = "^((REX(\\.[XRWB]+)+)|(REX$))"
74 rex2_expr = "\\(REX2\\)"
75 no_rex2_expr = "\\(!REX2\\)"
76 fpu_expr = "^ESC" # TODO
77
78 lprefix1_expr = "\\((66|!F3)\\)"
79 lprefix2_expr = "\\(F3\\)"
80 lprefix3_expr = "\\((F2|!F3|66&F2)\\)"
81 lprefix_expr = "\\((66|F2|F3)\\)"
82 max_lprefix = 4
83
84 # All opcodes starting with lower-case 'v', 'k' or with (v1) superscript
85 # accepts VEX prefix
86 vexok_opcode_expr = "^[vk].*"
87 vexok_expr = "\\(v1\\)"
88 # All opcodes with (v) superscript supports *only* VEX prefix
89 vexonly_expr = "\\(v\\)"
90 # All opcodes with (ev) superscript supports *only* EVEX prefix
91 evexonly_expr = "\\(ev\\)"
92 # (es) is the same as (ev) but also "SCALABLE" i.e. W and pp determine operand size
93 evex_scalable_expr = "\\(es\\)"
94 # All opcodes in XOP table or with (xop) superscript accept XOP prefix
95 xopok_expr = "\\(xop\\)"
96
97 prefix_expr = "\\(Prefix\\)"
98 prefix_num["Operand-Size"] = "INAT_PFX_OPNDSZ"
99 prefix_num["REPNE"] = "INAT_PFX_REPNE"
100 prefix_num["REP/REPE"] = "INAT_PFX_REPE"
101 prefix_num["XACQUIRE"] = "INAT_PFX_REPNE"
102 prefix_num["XRELEASE"] = "INAT_PFX_REPE"
103 prefix_num["LOCK"] = "INAT_PFX_LOCK"
104 prefix_num["SEG=CS"] = "INAT_PFX_CS"
105 prefix_num["SEG=DS"] = "INAT_PFX_DS"
106 prefix_num["SEG=ES"] = "INAT_PFX_ES"
107 prefix_num["SEG=FS"] = "INAT_PFX_FS"
108 prefix_num["SEG=GS"] = "INAT_PFX_GS"
109 prefix_num["SEG=SS"] = "INAT_PFX_SS"
110 prefix_num["Address-Size"] = "INAT_PFX_ADDRSZ"
111 prefix_num["VEX+1byte"] = "INAT_PFX_VEX2"
112 prefix_num["VEX+2byte"] = "INAT_PFX_VEX3"
113 prefix_num["EVEX"] = "INAT_PFX_EVEX"
114 prefix_num["REX2"] = "INAT_PFX_REX2"
115 prefix_num["XOP"] = "INAT_PFX_XOP"
116
117 clear_vars()
118}
119
120function semantic_error(msg) {
121 print "Semantic error at " NR ": " msg > "/dev/stderr"
122 exit 1
123}
124
125function debug(msg) {
126 print "DEBUG: " msg
127}
128
129function array_size(arr, i,c) {
130 c = 0
131 for (i in arr)
132 c++
133 return c
134}
135
136/^Table:/ {
137 print "/* " $0 " */"
138 if (tname != "")
139 semantic_error("Hit Table: before EndTable:.");
140}
141
142/^Referrer:/ {
143 if (NF != 1) {
144 # escape opcode table
145 ref = ""
146 for (i = 2; i <= NF; i++)
147 ref = ref $i
148 eid = escape[ref]
149 tname = sprintf("inat_escape_table_%d", eid)
150 }
151}
152
153/^AVXcode:/ {
154 if (NF != 1) {
155 # AVX/escape opcode table
156 aid = $2
157 xopid = -1
158 if (gaid <= aid)
159 gaid = aid + 1
160 if (tname == "") # AVX only opcode table
161 tname = sprintf("inat_avx_table_%d", $2)
162 }
163 if (aid == -1 && eid == -1) # primary opcode table
164 tname = "inat_primary_table"
165}
166
167/^XOPcode:/ {
168 if (NF != 1) {
169 # XOP opcode table
170 xopid = $2
171 aid = -1
172 if (gxopid <= xopid)
173 gxopid = xopid + 1
174 if (tname == "") # XOP only opcode table
175 tname = sprintf("inat_xop_table_%d", $2)
176 }
177 if (xopid == -1 && eid == -1) # primary opcode table
178 tname = "inat_primary_table"
179}
180
181/^GrpTable:/ {
182 print "/* " $0 " */"
183 if (!($2 in group))
184 semantic_error("No group: " $2 )
185 gid = group[$2]
186 tname = "inat_group_table_" gid
187}
188
189function print_table(tbl,name,fmt,n)
190{
191 print "const insn_attr_t " name " = {"
192 for (i = 0; i < n; i++) {
193 id = sprintf(fmt, i)
194 if (tbl[id])
195 print " [" id "] = " tbl[id] ","
196 }
197 print "};"
198}
199
200/^EndTable/ {
201 if (gid != -1) {
202 # print group tables
203 if (array_size(table) != 0) {
204 print_table(table, tname "[INAT_GROUP_TABLE_SIZE]",
205 "0x%x", 8)
206 gtable[gid,0] = tname
207 }
208 if (array_size(lptable1) != 0) {
209 print_table(lptable1, tname "_1[INAT_GROUP_TABLE_SIZE]",
210 "0x%x", 8)
211 gtable[gid,1] = tname "_1"
212 }
213 if (array_size(lptable2) != 0) {
214 print_table(lptable2, tname "_2[INAT_GROUP_TABLE_SIZE]",
215 "0x%x", 8)
216 gtable[gid,2] = tname "_2"
217 }
218 if (array_size(lptable3) != 0) {
219 print_table(lptable3, tname "_3[INAT_GROUP_TABLE_SIZE]",
220 "0x%x", 8)
221 gtable[gid,3] = tname "_3"
222 }
223 } else {
224 # print primary/escaped tables
225 if (array_size(table) != 0) {
226 print_table(table, tname "[INAT_OPCODE_TABLE_SIZE]",
227 "0x%02x", 256)
228 etable[eid,0] = tname
229 if (aid >= 0)
230 atable[aid,0] = tname
231 else if (xopid >= 0)
232 xoptable[xopid] = tname
233 }
234 if (array_size(lptable1) != 0) {
235 print_table(lptable1,tname "_1[INAT_OPCODE_TABLE_SIZE]",
236 "0x%02x", 256)
237 etable[eid,1] = tname "_1"
238 if (aid >= 0)
239 atable[aid,1] = tname "_1"
240 }
241 if (array_size(lptable2) != 0) {
242 print_table(lptable2,tname "_2[INAT_OPCODE_TABLE_SIZE]",
243 "0x%02x", 256)
244 etable[eid,2] = tname "_2"
245 if (aid >= 0)
246 atable[aid,2] = tname "_2"
247 }
248 if (array_size(lptable3) != 0) {
249 print_table(lptable3,tname "_3[INAT_OPCODE_TABLE_SIZE]",
250 "0x%02x", 256)
251 etable[eid,3] = tname "_3"
252 if (aid >= 0)
253 atable[aid,3] = tname "_3"
254 }
255 }
256 print ""
257 clear_vars()
258}
259
260function add_flags(old,new) {
261 if (old && new)
262 return old " | " new
263 else if (old)
264 return old
265 else
266 return new
267}
268
269# convert operands to flags.
270function convert_operands(count,opnd, i,j,imm,mod)
271{
272 imm = null
273 mod = null
274 for (j = 1; j <= count; j++) {
275 i = opnd[j]
276 if (match(i, imm_expr) == 1) {
277 if (!imm_flag[i])
278 semantic_error("Unknown imm opnd: " i)
279 if (imm) {
280 if (i != "Ib")
281 semantic_error("Second IMM error")
282 imm = add_flags(imm, "INAT_SCNDIMM")
283 } else
284 imm = imm_flag[i]
285 } else if (match(i, modrm_expr))
286 mod = "INAT_MODRM"
287 }
288 return add_flags(imm, mod)
289}
290
291/^[0-9a-f]+:/ {
292 if (NR == 1)
293 next
294 # get index
295 idx = "0x" substr($1, 1, index($1,":") - 1)
296 if (idx in table)
297 semantic_error("Redefine " idx " in " tname)
298
299 # check if escaped opcode
300 if ("escape" == $2) {
301 if ($3 != "#")
302 semantic_error("No escaped name")
303 ref = ""
304 for (i = 4; i <= NF; i++)
305 ref = ref $i
306 if (ref in escape)
307 semantic_error("Redefine escape (" ref ")")
308 escape[ref] = geid
309 geid++
310 table[idx] = "INAT_MAKE_ESCAPE(" escape[ref] ")"
311 next
312 }
313
314 variant = null
315 # converts
316 i = 2
317 while (i <= NF) {
318 opcode = $(i++)
319 delete opnds
320 ext = null
321 flags = null
322 opnd = null
323 # parse one opcode
324 if (match($i, opnd_expr)) {
325 opnd = $i
326 count = split($(i++), opnds, ",")
327 flags = convert_operands(count, opnds)
328 }
329 if (match($i, ext_expr))
330 ext = $(i++)
331 if (match($i, sep_expr))
332 i++
333 else if (i < NF)
334 semantic_error($i " is not a separator")
335
336 # check if group opcode
337 if (match(opcode, group_expr)) {
338 if (!(opcode in group)) {
339 group[opcode] = ggid
340 ggid++
341 }
342 flags = add_flags(flags, "INAT_MAKE_GROUP(" group[opcode] ")")
343 }
344 # check force(or default) 64bit
345 if (match(ext, force64_expr))
346 flags = add_flags(flags, "INAT_FORCE64")
347
348 # check invalid in 64-bit (and no only64)
349 if (match(ext, invalid64_expr) &&
350 !match($0, only64_expr))
351 flags = add_flags(flags, "INAT_INV64")
352
353 # check REX2 not allowed
354 if (match(ext, no_rex2_expr))
355 flags = add_flags(flags, "INAT_NO_REX2")
356
357 # check REX prefix
358 if (match(opcode, rex_expr))
359 flags = add_flags(flags, "INAT_MAKE_PREFIX(INAT_PFX_REX)")
360
361 # check coprocessor escape : TODO
362 if (match(opcode, fpu_expr))
363 flags = add_flags(flags, "INAT_MODRM")
364
365 # check VEX codes
366 if (match(ext, evexonly_expr))
367 flags = add_flags(flags, "INAT_VEXOK | INAT_EVEXONLY")
368 else if (match(ext, evex_scalable_expr))
369 flags = add_flags(flags, "INAT_VEXOK | INAT_EVEXONLY | INAT_EVEX_SCALABLE")
370 else if (match(ext, vexonly_expr))
371 flags = add_flags(flags, "INAT_VEXOK | INAT_VEXONLY")
372 else if (match(ext, vexok_expr) || match(opcode, vexok_opcode_expr))
373 flags = add_flags(flags, "INAT_VEXOK")
374 else if (match(ext, xopok_expr) || xopid >= 0)
375 flags = add_flags(flags, "INAT_XOPOK")
376
377 # check prefixes
378 if (match(ext, prefix_expr)) {
379 if (!prefix_num[opcode])
380 semantic_error("Unknown prefix: " opcode)
381 flags = add_flags(flags, "INAT_MAKE_PREFIX(" prefix_num[opcode] ")")
382 }
383 if (length(flags) == 0)
384 continue
385 # check if last prefix
386 if (match(ext, lprefix1_expr)) {
387 lptable1[idx] = add_flags(lptable1[idx],flags)
388 variant = "INAT_VARIANT"
389 }
390 if (match(ext, lprefix2_expr)) {
391 lptable2[idx] = add_flags(lptable2[idx],flags)
392 variant = "INAT_VARIANT"
393 }
394 if (match(ext, lprefix3_expr)) {
395 lptable3[idx] = add_flags(lptable3[idx],flags)
396 variant = "INAT_VARIANT"
397 }
398 if (match(ext, rex2_expr))
399 table[idx] = add_flags(table[idx], "INAT_REX2_VARIANT")
400 if (!match(ext, lprefix_expr)){
401 table[idx] = add_flags(table[idx],flags)
402 }
403 }
404 if (variant)
405 table[idx] = add_flags(table[idx],variant)
406}
407
408END {
409 if (awkchecked != "")
410 exit 1
411
412 print "#ifndef __BOOT_COMPRESSED\n"
413
414 # print escape opcode map's array
415 print "/* Escape opcode map array */"
416 print "const insn_attr_t * const inat_escape_tables[INAT_ESC_MAX + 1]" \
417 "[INAT_LSTPFX_MAX + 1] = {"
418 for (i = 0; i < geid; i++)
419 for (j = 0; j < max_lprefix; j++)
420 if (etable[i,j])
421 print " ["i"]["j"] = "etable[i,j]","
422 print "};\n"
423 # print group opcode map's array
424 print "/* Group opcode map array */"
425 print "const insn_attr_t * const inat_group_tables[INAT_GRP_MAX + 1]"\
426 "[INAT_LSTPFX_MAX + 1] = {"
427 for (i = 0; i < ggid; i++)
428 for (j = 0; j < max_lprefix; j++)
429 if (gtable[i,j])
430 print " ["i"]["j"] = "gtable[i,j]","
431 print "};\n"
432 # print AVX opcode map's array
433 print "/* AVX opcode map array */"
434 print "const insn_attr_t * const inat_avx_tables[X86_VEX_M_MAX + 1]"\
435 "[INAT_LSTPFX_MAX + 1] = {"
436 for (i = 0; i < gaid; i++)
437 for (j = 0; j < max_lprefix; j++)
438 if (atable[i,j])
439 print " ["i"]["j"] = "atable[i,j]","
440 print "};\n"
441
442 print "/* XOP opcode map array */"
443 print "const insn_attr_t * const inat_xop_tables[X86_XOP_M_MAX - X86_XOP_M_MIN + 1]" \
444 " = {"
445 for (i = 0; i < gxopid; i++)
446 if (xoptable[i])
447 print " ["i"] = "xoptable[i]","
448 print "};"
449
450 print "#else /* !__BOOT_COMPRESSED */\n"
451
452 print "/* Escape opcode map array */"
453 print "static const insn_attr_t *inat_escape_tables[INAT_ESC_MAX + 1]" \
454 "[INAT_LSTPFX_MAX + 1];"
455 print ""
456
457 print "/* Group opcode map array */"
458 print "static const insn_attr_t *inat_group_tables[INAT_GRP_MAX + 1]"\
459 "[INAT_LSTPFX_MAX + 1];"
460 print ""
461
462 print "/* AVX opcode map array */"
463 print "static const insn_attr_t *inat_avx_tables[X86_VEX_M_MAX + 1]"\
464 "[INAT_LSTPFX_MAX + 1];"
465 print ""
466
467 print "/* XOP opcode map array */"
468 print "static const insn_attr_t *inat_xop_tables[X86_XOP_M_MAX - X86_XOP_M_MIN + 1];"
469 print ""
470
471 print "static void inat_init_tables(void)"
472 print "{"
473
474 # print escape opcode map's array
475 print "\t/* Print Escape opcode map array */"
476 for (i = 0; i < geid; i++)
477 for (j = 0; j < max_lprefix; j++)
478 if (etable[i,j])
479 print "\tinat_escape_tables["i"]["j"] = "etable[i,j]";"
480 print ""
481
482 # print group opcode map's array
483 print "\t/* Print Group opcode map array */"
484 for (i = 0; i < ggid; i++)
485 for (j = 0; j < max_lprefix; j++)
486 if (gtable[i,j])
487 print "\tinat_group_tables["i"]["j"] = "gtable[i,j]";"
488 print ""
489 # print AVX opcode map's array
490 print "\t/* Print AVX opcode map array */"
491 for (i = 0; i < gaid; i++)
492 for (j = 0; j < max_lprefix; j++)
493 if (atable[i,j])
494 print "\tinat_avx_tables["i"]["j"] = "atable[i,j]";"
495
496 print ""
497 print "\t/* Print XOP opcode map array */"
498 for (i = 0; i < gxopid; i++)
499 if (xoptable[i])
500 print "\tinat_xop_tables["i"] = "xoptable[i]";"
501
502 print "}"
503 print "#endif"
504}
505