2 # gen-insn-attr-x86.awk: Instruction attribute table generator
3 # Written by Masami Hiramatsu <mhiramat@redhat.com>
5 # Usage: awk -f gen-insn-attr-x86.awk x86-opcode-map.txt > inat-tables.c
7 # Awk implementation sanity check
8 function check_awk_implement
() {
9 if (sprintf("%x", 0) != "0")
10 return "Your awk has a printf-format problem."
15 function clear_vars
() {
27 # Implementation error checking
28 awkchecked = check_awk_implement
()
29 if (awkchecked
!= "") {
30 print "Error: " awkchecked
> "/dev/stderr"
31 print "Please try to use gawk." > "/dev/stderr"
35 # Setup generating tables
36 print "/* x86 opcode map generated from x86-opcode-map.txt */"
37 print "/* Do not change this code. */\n"
45 opnd_expr =
"^[A-Za-z/]"
48 group_expr =
"^Grp[0-9A-Za-z]+"
50 imm_expr =
"^[IJAOL][a-z]"
51 imm_flag
["Ib"] =
"INAT_MAKE_IMM(INAT_IMM_BYTE)"
52 imm_flag
["Jb"] =
"INAT_MAKE_IMM(INAT_IMM_BYTE)"
53 imm_flag
["Iw"] =
"INAT_MAKE_IMM(INAT_IMM_WORD)"
54 imm_flag
["Id"] =
"INAT_MAKE_IMM(INAT_IMM_DWORD)"
55 imm_flag
["Iq"] =
"INAT_MAKE_IMM(INAT_IMM_QWORD)"
56 imm_flag
["Ap"] =
"INAT_MAKE_IMM(INAT_IMM_PTR)"
57 imm_flag
["Iz"] =
"INAT_MAKE_IMM(INAT_IMM_VWORD32)"
58 imm_flag
["Jz"] =
"INAT_MAKE_IMM(INAT_IMM_VWORD32)"
59 imm_flag
["Iv"] =
"INAT_MAKE_IMM(INAT_IMM_VWORD)"
60 imm_flag
["Ob"] =
"INAT_MOFFSET"
61 imm_flag
["Ov"] =
"INAT_MOFFSET"
62 imm_flag
["Lx"] =
"INAT_MAKE_IMM(INAT_IMM_BYTE)"
64 modrm_expr =
"^([CDEGMNPQRSUVW/][a-z]+|NTA|T[012])"
65 force64_expr =
"\\([df]64\\)"
66 rex_expr =
"^REX(\\.[XRWB]+)*"
67 fpu_expr =
"^ESC" # TODO
69 lprefix1_expr =
"\\(66\\)"
70 lprefix2_expr =
"\\(F3\\)"
71 lprefix3_expr =
"\\(F2\\)"
74 # All opcodes starting with lower-case 'v' or with (v1) superscript
76 vexok_opcode_expr =
"^v.*"
77 vexok_expr =
"\\(v1\\)"
78 # All opcodes with (v) superscript supports *only* VEX prefix
79 vexonly_expr =
"\\(v\\)"
81 prefix_expr =
"\\(Prefix\\)"
82 prefix_num
["Operand-Size"] =
"INAT_PFX_OPNDSZ"
83 prefix_num
["REPNE"] =
"INAT_PFX_REPNE"
84 prefix_num
["REP/REPE"] =
"INAT_PFX_REPE"
85 prefix_num
["LOCK"] =
"INAT_PFX_LOCK"
86 prefix_num
["SEG=CS"] =
"INAT_PFX_CS"
87 prefix_num
["SEG=DS"] =
"INAT_PFX_DS"
88 prefix_num
["SEG=ES"] =
"INAT_PFX_ES"
89 prefix_num
["SEG=FS"] =
"INAT_PFX_FS"
90 prefix_num
["SEG=GS"] =
"INAT_PFX_GS"
91 prefix_num
["SEG=SS"] =
"INAT_PFX_SS"
92 prefix_num
["Address-Size"] =
"INAT_PFX_ADDRSZ"
93 prefix_num
["VEX+1byte"] =
"INAT_PFX_VEX2"
94 prefix_num
["VEX+2byte"] =
"INAT_PFX_VEX3"
99 function semantic_error
(msg
) {
100 print "Semantic error at " NR ": " msg
> "/dev/stderr"
104 function debug
(msg
) {
108 function array_size
(arr
, i
,c
) {
118 semantic_error
("Hit Table: before EndTable:.");
123 # escape opcode table
125 for (i =
2; i
<=
NF; i
++)
128 tname =
sprintf("inat_escape_table_%d", eid
)
134 # AVX/escape opcode table
138 if (tname ==
"") # AVX only opcode table
139 tname =
sprintf("inat_avx_table_%d", $
2)
141 if (aid ==
-1 && eid ==
-1) # primary opcode table
142 tname =
"inat_primary_table"
148 semantic_error
("No group: " $
2 )
150 tname =
"inat_group_table_" gid
153 function print_table
(tbl
,name
,fmt
,n
)
155 print "const insn_attr_t " name
" = {"
156 for (i =
0; i
< n
; i
++) {
159 print " [" id
"] = " tbl
[id
] ","
167 if (array_size
(table
) != 0) {
168 print_table
(table
, tname
"[INAT_GROUP_TABLE_SIZE]",
170 gtable
[gid
,0] = tname
172 if (array_size
(lptable1
) != 0) {
173 print_table
(lptable1
, tname
"_1[INAT_GROUP_TABLE_SIZE]",
175 gtable
[gid
,1] = tname
"_1"
177 if (array_size
(lptable2
) != 0) {
178 print_table
(lptable2
, tname
"_2[INAT_GROUP_TABLE_SIZE]",
180 gtable
[gid
,2] = tname
"_2"
182 if (array_size
(lptable3
) != 0) {
183 print_table
(lptable3
, tname
"_3[INAT_GROUP_TABLE_SIZE]",
185 gtable
[gid
,3] = tname
"_3"
188 # print primary/escaped tables
189 if (array_size
(table
) != 0) {
190 print_table
(table
, tname
"[INAT_OPCODE_TABLE_SIZE]",
192 etable
[eid
,0] = tname
194 atable
[aid
,0] = tname
196 if (array_size
(lptable1
) != 0) {
197 print_table
(lptable1
,tname
"_1[INAT_OPCODE_TABLE_SIZE]",
199 etable
[eid
,1] = tname
"_1"
201 atable
[aid
,1] = tname
"_1"
203 if (array_size
(lptable2
) != 0) {
204 print_table
(lptable2
,tname
"_2[INAT_OPCODE_TABLE_SIZE]",
206 etable
[eid
,2] = tname
"_2"
208 atable
[aid
,2] = tname
"_2"
210 if (array_size
(lptable3
) != 0) {
211 print_table
(lptable3
,tname
"_3[INAT_OPCODE_TABLE_SIZE]",
213 etable
[eid
,3] = tname
"_3"
215 atable
[aid
,3] = tname
"_3"
222 function add_flags
(old
,new
) {
231 # convert operands to flags.
232 function convert_operands
(count
,opnd
, i
,j
,imm
,mod
)
236 for (j =
1; j
<= count
; j
++) {
238 if (match(i
, imm_expr
) ==
1) {
240 semantic_error
("Unknown imm opnd: " i
)
243 semantic_error
("Second IMM error")
244 imm = add_flags
(imm
, "INAT_SCNDIMM")
247 } else if (match(i
, modrm_expr
))
250 return add_flags
(imm
, mod
)
257 idx =
"0x" substr($
1, 1, index($
1,":") - 1)
259 semantic_error
("Redefine " idx
" in " tname
)
261 # check if escaped opcode
262 if ("escape" == $
2) {
264 semantic_error
("No escaped name")
266 for (i =
4; i
<=
NF; i
++)
269 semantic_error
("Redefine escape (" ref
")")
272 table
[idx
] =
"INAT_MAKE_ESCAPE(" escape
[ref
] ")"
286 if (match($i
, opnd_expr
)) {
288 count =
split($
(i
++), opnds
, ",")
289 flags = convert_operands
(count
, opnds
)
291 if (match($i
, ext_expr
))
293 if (match($i
, sep_expr
))
296 semantic_error
($i
" is not a separator")
298 # check if group opcode
299 if (match(opcode
, group_expr
)) {
300 if (!
(opcode in group
)) {
304 flags = add_flags
(flags
, "INAT_MAKE_GROUP(" group
[opcode
] ")")
306 # check force(or default) 64bit
307 if (match(ext
, force64_expr
))
308 flags = add_flags
(flags
, "INAT_FORCE64")
311 if (match(opcode
, rex_expr
))
312 flags = add_flags
(flags
, "INAT_MAKE_PREFIX(INAT_PFX_REX)")
314 # check coprocessor escape : TODO
315 if (match(opcode
, fpu_expr
))
316 flags = add_flags
(flags
, "INAT_MODRM")
319 if (match(ext
, vexonly_expr
))
320 flags = add_flags
(flags
, "INAT_VEXOK | INAT_VEXONLY")
321 else if (match(ext
, vexok_expr
) || match(opcode
, vexok_opcode_expr
))
322 flags = add_flags
(flags
, "INAT_VEXOK")
325 if (match(ext
, prefix_expr
)) {
326 if (!prefix_num
[opcode
])
327 semantic_error
("Unknown prefix: " opcode
)
328 flags = add_flags
(flags
, "INAT_MAKE_PREFIX(" prefix_num
[opcode
] ")")
330 if (length(flags
) ==
0)
332 # check if last prefix
333 if (match(ext
, lprefix1_expr
)) {
334 lptable1
[idx
] = add_flags
(lptable1
[idx
],flags
)
335 variant =
"INAT_VARIANT"
336 } else if (match(ext
, lprefix2_expr
)) {
337 lptable2
[idx
] = add_flags
(lptable2
[idx
],flags
)
338 variant =
"INAT_VARIANT"
339 } else if (match(ext
, lprefix3_expr
)) {
340 lptable3
[idx
] = add_flags
(lptable3
[idx
],flags
)
341 variant =
"INAT_VARIANT"
343 table
[idx
] = add_flags
(table
[idx
],flags
)
347 table
[idx
] = add_flags
(table
[idx
],variant
)
351 if (awkchecked
!= "")
353 # print escape opcode map's array
354 print "/* Escape opcode map array */"
355 print "const insn_attr_t const *inat_escape_tables[INAT_ESC_MAX + 1]" \
356 "[INAT_LSTPFX_MAX + 1] = {"
357 for (i =
0; i
< geid
; i
++)
358 for (j =
0; j
< max_lprefix
; j
++)
360 print " ["i
"]["j
"] = "etable
[i
,j
]","
362 # print group opcode map's array
363 print "/* Group opcode map array */"
364 print "const insn_attr_t const *inat_group_tables[INAT_GRP_MAX + 1]"\
365 "[INAT_LSTPFX_MAX + 1] = {"
366 for (i =
0; i
< ggid
; i
++)
367 for (j =
0; j
< max_lprefix
; j
++)
369 print " ["i
"]["j
"] = "gtable
[i
,j
]","
371 # print AVX opcode map's array
372 print "/* AVX opcode map array */"
373 print "const insn_attr_t const *inat_avx_tables[X86_VEX_M_MAX + 1]"\
374 "[INAT_LSTPFX_MAX + 1] = {"
375 for (i =
0; i
< gaid
; i
++)
376 for (j =
0; j
< max_lprefix
; j
++)
378 print " ["i
"]["j
"] = "atable
[i
,j
]","