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>
6 # Usage: awk -f gen-insn-attr-x86.awk x86-opcode-map.txt > inat-tables.c
8 # Awk implementation sanity check
9 function check_awk_implement
() {
10 if (sprintf("%x", 0) != "0")
11 return "Your awk has a printf-format problem."
16 function clear_vars
() {
28 # Implementation error checking
29 awkchecked = check_awk_implement
()
30 if (awkchecked
!= "") {
31 print "Error: " awkchecked
> "/dev/stderr"
32 print "Please try to use gawk." > "/dev/stderr"
36 # Setup generating tables
37 print "/* x86 opcode map generated from x86-opcode-map.txt */"
38 print "/* Do not change this code. */\n"
46 opnd_expr =
"^[A-Za-z/]"
49 group_expr =
"^Grp[0-9A-Za-z]+"
51 imm_expr =
"^[IJAOL][a-z]"
52 imm_flag
["Ib"] =
"INAT_MAKE_IMM(INAT_IMM_BYTE)"
53 imm_flag
["Jb"] =
"INAT_MAKE_IMM(INAT_IMM_BYTE)"
54 imm_flag
["Iw"] =
"INAT_MAKE_IMM(INAT_IMM_WORD)"
55 imm_flag
["Id"] =
"INAT_MAKE_IMM(INAT_IMM_DWORD)"
56 imm_flag
["Iq"] =
"INAT_MAKE_IMM(INAT_IMM_QWORD)"
57 imm_flag
["Ap"] =
"INAT_MAKE_IMM(INAT_IMM_PTR)"
58 imm_flag
["Iz"] =
"INAT_MAKE_IMM(INAT_IMM_VWORD32)"
59 imm_flag
["Jz"] =
"INAT_MAKE_IMM(INAT_IMM_VWORD32)"
60 imm_flag
["Iv"] =
"INAT_MAKE_IMM(INAT_IMM_VWORD)"
61 imm_flag
["Ob"] =
"INAT_MOFFSET"
62 imm_flag
["Ov"] =
"INAT_MOFFSET"
63 imm_flag
["Lx"] =
"INAT_MAKE_IMM(INAT_IMM_BYTE)"
65 modrm_expr =
"^([CDEGMNPQRSUVW/][a-z]+|NTA|T[012])"
66 force64_expr =
"\\([df]64\\)"
67 rex_expr =
"^((REX(\\.[XRWB]+)+)|(REX$))"
68 rex2_expr =
"\\(REX2\\)"
69 no_rex2_expr =
"\\(!REX2\\)"
70 fpu_expr =
"^ESC" # TODO
72 lprefix1_expr =
"\\((66|!F3)\\)"
73 lprefix2_expr =
"\\(F3\\)"
74 lprefix3_expr =
"\\((F2|!F3|66&F2)\\)"
75 lprefix_expr =
"\\((66|F2|F3)\\)"
78 # All opcodes starting with lower-case 'v', 'k' or with (v1) superscript
80 vexok_opcode_expr =
"^[vk].*"
81 vexok_expr =
"\\(v1\\)"
82 # All opcodes with (v) superscript supports *only* VEX prefix
83 vexonly_expr =
"\\(v\\)"
84 # All opcodes with (ev) superscript supports *only* EVEX prefix
85 evexonly_expr =
"\\(ev\\)"
86 # (es) is the same as (ev) but also "SCALABLE" i.e. W and pp determine operand size
87 evex_scalable_expr =
"\\(es\\)"
89 prefix_expr =
"\\(Prefix\\)"
90 prefix_num
["Operand-Size"] =
"INAT_PFX_OPNDSZ"
91 prefix_num
["REPNE"] =
"INAT_PFX_REPNE"
92 prefix_num
["REP/REPE"] =
"INAT_PFX_REPE"
93 prefix_num
["XACQUIRE"] =
"INAT_PFX_REPNE"
94 prefix_num
["XRELEASE"] =
"INAT_PFX_REPE"
95 prefix_num
["LOCK"] =
"INAT_PFX_LOCK"
96 prefix_num
["SEG=CS"] =
"INAT_PFX_CS"
97 prefix_num
["SEG=DS"] =
"INAT_PFX_DS"
98 prefix_num
["SEG=ES"] =
"INAT_PFX_ES"
99 prefix_num
["SEG=FS"] =
"INAT_PFX_FS"
100 prefix_num
["SEG=GS"] =
"INAT_PFX_GS"
101 prefix_num
["SEG=SS"] =
"INAT_PFX_SS"
102 prefix_num
["Address-Size"] =
"INAT_PFX_ADDRSZ"
103 prefix_num
["VEX+1byte"] =
"INAT_PFX_VEX2"
104 prefix_num
["VEX+2byte"] =
"INAT_PFX_VEX3"
105 prefix_num
["EVEX"] =
"INAT_PFX_EVEX"
106 prefix_num
["REX2"] =
"INAT_PFX_REX2"
111 function semantic_error
(msg
) {
112 print "Semantic error at " NR ": " msg
> "/dev/stderr"
116 function debug
(msg
) {
120 function array_size
(arr
, i
,c
) {
130 semantic_error
("Hit Table: before EndTable:.");
135 # escape opcode table
137 for (i =
2; i
<=
NF; i
++)
140 tname =
sprintf("inat_escape_table_%d", eid
)
146 # AVX/escape opcode table
150 if (tname ==
"") # AVX only opcode table
151 tname =
sprintf("inat_avx_table_%d", $
2)
153 if (aid ==
-1 && eid ==
-1) # primary opcode table
154 tname =
"inat_primary_table"
160 semantic_error
("No group: " $
2 )
162 tname =
"inat_group_table_" gid
165 function print_table
(tbl
,name
,fmt
,n
)
167 print "const insn_attr_t " name
" = {"
168 for (i =
0; i
< n
; i
++) {
171 print " [" id
"] = " tbl
[id
] ","
179 if (array_size
(table
) != 0) {
180 print_table
(table
, tname
"[INAT_GROUP_TABLE_SIZE]",
182 gtable
[gid
,0] = tname
184 if (array_size
(lptable1
) != 0) {
185 print_table
(lptable1
, tname
"_1[INAT_GROUP_TABLE_SIZE]",
187 gtable
[gid
,1] = tname
"_1"
189 if (array_size
(lptable2
) != 0) {
190 print_table
(lptable2
, tname
"_2[INAT_GROUP_TABLE_SIZE]",
192 gtable
[gid
,2] = tname
"_2"
194 if (array_size
(lptable3
) != 0) {
195 print_table
(lptable3
, tname
"_3[INAT_GROUP_TABLE_SIZE]",
197 gtable
[gid
,3] = tname
"_3"
200 # print primary/escaped tables
201 if (array_size
(table
) != 0) {
202 print_table
(table
, tname
"[INAT_OPCODE_TABLE_SIZE]",
204 etable
[eid
,0] = tname
206 atable
[aid
,0] = tname
208 if (array_size
(lptable1
) != 0) {
209 print_table
(lptable1
,tname
"_1[INAT_OPCODE_TABLE_SIZE]",
211 etable
[eid
,1] = tname
"_1"
213 atable
[aid
,1] = tname
"_1"
215 if (array_size
(lptable2
) != 0) {
216 print_table
(lptable2
,tname
"_2[INAT_OPCODE_TABLE_SIZE]",
218 etable
[eid
,2] = tname
"_2"
220 atable
[aid
,2] = tname
"_2"
222 if (array_size
(lptable3
) != 0) {
223 print_table
(lptable3
,tname
"_3[INAT_OPCODE_TABLE_SIZE]",
225 etable
[eid
,3] = tname
"_3"
227 atable
[aid
,3] = tname
"_3"
234 function add_flags
(old
,new
) {
243 # convert operands to flags.
244 function convert_operands
(count
,opnd
, i
,j
,imm
,mod
)
248 for (j =
1; j
<= count
; j
++) {
250 if (match(i
, imm_expr
) ==
1) {
252 semantic_error
("Unknown imm opnd: " i
)
255 semantic_error
("Second IMM error")
256 imm = add_flags
(imm
, "INAT_SCNDIMM")
259 } else if (match(i
, modrm_expr
))
262 return add_flags
(imm
, mod
)
269 idx =
"0x" substr($
1, 1, index($
1,":") - 1)
271 semantic_error
("Redefine " idx
" in " tname
)
273 # check if escaped opcode
274 if ("escape" == $
2) {
276 semantic_error
("No escaped name")
278 for (i =
4; i
<=
NF; i
++)
281 semantic_error
("Redefine escape (" ref
")")
284 table
[idx
] =
"INAT_MAKE_ESCAPE(" escape
[ref
] ")"
298 if (match($i
, opnd_expr
)) {
300 count =
split($
(i
++), opnds
, ",")
301 flags = convert_operands
(count
, opnds
)
303 if (match($i
, ext_expr
))
305 if (match($i
, sep_expr
))
308 semantic_error
($i
" is not a separator")
310 # check if group opcode
311 if (match(opcode
, group_expr
)) {
312 if (!
(opcode in group
)) {
316 flags = add_flags
(flags
, "INAT_MAKE_GROUP(" group
[opcode
] ")")
318 # check force(or default) 64bit
319 if (match(ext
, force64_expr
))
320 flags = add_flags
(flags
, "INAT_FORCE64")
322 # check REX2 not allowed
323 if (match(ext
, no_rex2_expr
))
324 flags = add_flags
(flags
, "INAT_NO_REX2")
327 if (match(opcode
, rex_expr
))
328 flags = add_flags
(flags
, "INAT_MAKE_PREFIX(INAT_PFX_REX)")
330 # check coprocessor escape : TODO
331 if (match(opcode
, fpu_expr
))
332 flags = add_flags
(flags
, "INAT_MODRM")
335 if (match(ext
, evexonly_expr
))
336 flags = add_flags
(flags
, "INAT_VEXOK | INAT_EVEXONLY")
337 else if (match(ext
, evex_scalable_expr
))
338 flags = add_flags
(flags
, "INAT_VEXOK | INAT_EVEXONLY | INAT_EVEX_SCALABLE")
339 else if (match(ext
, vexonly_expr
))
340 flags = add_flags
(flags
, "INAT_VEXOK | INAT_VEXONLY")
341 else if (match(ext
, vexok_expr
) || match(opcode
, vexok_opcode_expr
))
342 flags = add_flags
(flags
, "INAT_VEXOK")
345 if (match(ext
, prefix_expr
)) {
346 if (!prefix_num
[opcode
])
347 semantic_error
("Unknown prefix: " opcode
)
348 flags = add_flags
(flags
, "INAT_MAKE_PREFIX(" prefix_num
[opcode
] ")")
350 if (length(flags
) ==
0)
352 # check if last prefix
353 if (match(ext
, lprefix1_expr
)) {
354 lptable1
[idx
] = add_flags
(lptable1
[idx
],flags
)
355 variant =
"INAT_VARIANT"
357 if (match(ext
, lprefix2_expr
)) {
358 lptable2
[idx
] = add_flags
(lptable2
[idx
],flags
)
359 variant =
"INAT_VARIANT"
361 if (match(ext
, lprefix3_expr
)) {
362 lptable3
[idx
] = add_flags
(lptable3
[idx
],flags
)
363 variant =
"INAT_VARIANT"
365 if (match(ext
, rex2_expr
))
366 table
[idx
] = add_flags
(table
[idx
], "INAT_REX2_VARIANT")
367 if (!
match(ext
, lprefix_expr
)){
368 table
[idx
] = add_flags
(table
[idx
],flags
)
372 table
[idx
] = add_flags
(table
[idx
],variant
)
376 if (awkchecked
!= "")
379 print "#ifndef __BOOT_COMPRESSED\n"
381 # print escape opcode map's array
382 print "/* Escape opcode map array */"
383 print "const insn_attr_t * const inat_escape_tables[INAT_ESC_MAX + 1]" \
384 "[INAT_LSTPFX_MAX + 1] = {"
385 for (i =
0; i
< geid
; i
++)
386 for (j =
0; j
< max_lprefix
; j
++)
388 print " ["i
"]["j
"] = "etable
[i
,j
]","
390 # print group opcode map's array
391 print "/* Group opcode map array */"
392 print "const insn_attr_t * const inat_group_tables[INAT_GRP_MAX + 1]"\
393 "[INAT_LSTPFX_MAX + 1] = {"
394 for (i =
0; i
< ggid
; i
++)
395 for (j =
0; j
< max_lprefix
; j
++)
397 print " ["i
"]["j
"] = "gtable
[i
,j
]","
399 # print AVX opcode map's array
400 print "/* AVX opcode map array */"
401 print "const insn_attr_t * const inat_avx_tables[X86_VEX_M_MAX + 1]"\
402 "[INAT_LSTPFX_MAX + 1] = {"
403 for (i =
0; i
< gaid
; i
++)
404 for (j =
0; j
< max_lprefix
; j
++)
406 print " ["i
"]["j
"] = "atable
[i
,j
]","
409 print "#else /* !__BOOT_COMPRESSED */\n"
411 print "/* Escape opcode map array */"
412 print "static const insn_attr_t *inat_escape_tables[INAT_ESC_MAX + 1]" \
413 "[INAT_LSTPFX_MAX + 1];"
416 print "/* Group opcode map array */"
417 print "static const insn_attr_t *inat_group_tables[INAT_GRP_MAX + 1]"\
418 "[INAT_LSTPFX_MAX + 1];"
421 print "/* AVX opcode map array */"
422 print "static const insn_attr_t *inat_avx_tables[X86_VEX_M_MAX + 1]"\
423 "[INAT_LSTPFX_MAX + 1];"
426 print "static void inat_init_tables(void)"
429 # print escape opcode map's array
430 print "\t/* Print Escape opcode map array */"
431 for (i =
0; i
< geid
; i
++)
432 for (j =
0; j
< max_lprefix
; j
++)
434 print "\tinat_escape_tables["i
"]["j
"] = "etable
[i
,j
]";"
437 # print group opcode map's array
438 print "\t/* Print Group opcode map array */"
439 for (i =
0; i
< ggid
; i
++)
440 for (j =
0; j
< max_lprefix
; j
++)
442 print "\tinat_group_tables["i
"]["j
"] = "gtable
[i
,j
]";"
444 # print AVX opcode map's array
445 print "\t/* Print AVX opcode map array */"
446 for (i =
0; i
< gaid
; i
++)
447 for (j =
0; j
< max_lprefix
; j
++)
449 print "\tinat_avx_tables["i
"]["j
"] = "atable
[i
,j
]";"