blob: 19ba096b7dd1567489a58df42e3dafce890d8d1b [file] [log] [blame]
Masami Hiramatsueb132962009-08-13 16:34:13 -04001#!/bin/awk -f
2# gen-insn-attr-x86.awk: Instruction attribute table generator
3# Written by Masami Hiramatsu <mhiramat@redhat.com>
4#
5# Usage: awk -f gen-insn-attr-x86.awk x86-opcode-map.txt > inat-tables.c
6
Masami Hiramatsu69d991f2009-08-21 15:43:16 -04007# Awk implementation sanity check
8function check_awk_implement() {
9 if (!match("abc", "[[:lower:]]+"))
10 return "Your awk doesn't support charactor-class."
11 if (sprintf("%x", 0) != "0")
12 return "Your awk has a printf-format problem."
13 return ""
14}
15
Masami Hiramatsueb132962009-08-13 16:34:13 -040016BEGIN {
Masami Hiramatsu69d991f2009-08-21 15:43:16 -040017 # Implementation error checking
18 awkchecked = check_awk_implement()
19 if (awkchecked != "") {
20 print "Error: " awkchecked > "/dev/stderr"
21 print "Please try to use gawk." > "/dev/stderr"
22 exit 1
23 }
24
25 # Setup generating tables
Masami Hiramatsueb132962009-08-13 16:34:13 -040026 print "/* x86 opcode map generated from x86-opcode-map.txt */"
27 print "/* Do not change this code. */"
28 ggid = 1
29 geid = 1
30
31 opnd_expr = "^[[:alpha:]]"
32 ext_expr = "^\\("
33 sep_expr = "^\\|$"
34 group_expr = "^Grp[[:alnum:]]+"
35
36 imm_expr = "^[IJAO][[:lower:]]"
37 imm_flag["Ib"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)"
38 imm_flag["Jb"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)"
39 imm_flag["Iw"] = "INAT_MAKE_IMM(INAT_IMM_WORD)"
40 imm_flag["Id"] = "INAT_MAKE_IMM(INAT_IMM_DWORD)"
41 imm_flag["Iq"] = "INAT_MAKE_IMM(INAT_IMM_QWORD)"
42 imm_flag["Ap"] = "INAT_MAKE_IMM(INAT_IMM_PTR)"
43 imm_flag["Iz"] = "INAT_MAKE_IMM(INAT_IMM_VWORD32)"
44 imm_flag["Jz"] = "INAT_MAKE_IMM(INAT_IMM_VWORD32)"
45 imm_flag["Iv"] = "INAT_MAKE_IMM(INAT_IMM_VWORD)"
46 imm_flag["Ob"] = "INAT_MOFFSET"
47 imm_flag["Ov"] = "INAT_MOFFSET"
48
49 modrm_expr = "^([CDEGMNPQRSUVW][[:lower:]]+|NTA|T[012])"
50 force64_expr = "\\([df]64\\)"
51 rex_expr = "^REX(\\.[XRWB]+)*"
52 fpu_expr = "^ESC" # TODO
53
54 lprefix1_expr = "\\(66\\)"
55 delete lptable1
56 lprefix2_expr = "\\(F2\\)"
57 delete lptable2
58 lprefix3_expr = "\\(F3\\)"
59 delete lptable3
60 max_lprefix = 4
61
62 prefix_expr = "\\(Prefix\\)"
63 prefix_num["Operand-Size"] = "INAT_PFX_OPNDSZ"
64 prefix_num["REPNE"] = "INAT_PFX_REPNE"
65 prefix_num["REP/REPE"] = "INAT_PFX_REPE"
66 prefix_num["LOCK"] = "INAT_PFX_LOCK"
67 prefix_num["SEG=CS"] = "INAT_PFX_CS"
68 prefix_num["SEG=DS"] = "INAT_PFX_DS"
69 prefix_num["SEG=ES"] = "INAT_PFX_ES"
70 prefix_num["SEG=FS"] = "INAT_PFX_FS"
71 prefix_num["SEG=GS"] = "INAT_PFX_GS"
72 prefix_num["SEG=SS"] = "INAT_PFX_SS"
73 prefix_num["Address-Size"] = "INAT_PFX_ADDRSZ"
74
75 delete table
76 delete etable
77 delete gtable
78 eid = -1
79 gid = -1
80}
81
82function semantic_error(msg) {
83 print "Semantic error at " NR ": " msg > "/dev/stderr"
84 exit 1
85}
86
87function debug(msg) {
88 print "DEBUG: " msg
89}
90
91function array_size(arr, i,c) {
92 c = 0
93 for (i in arr)
94 c++
95 return c
96}
97
98/^Table:/ {
99 print "/* " $0 " */"
100}
101
102/^Referrer:/ {
103 if (NF == 1) {
104 # primary opcode table
105 tname = "inat_primary_table"
106 eid = -1
107 } else {
108 # escape opcode table
109 ref = ""
110 for (i = 2; i <= NF; i++)
111 ref = ref $i
112 eid = escape[ref]
113 tname = sprintf("inat_escape_table_%d", eid)
114 }
115}
116
117/^GrpTable:/ {
118 print "/* " $0 " */"
119 if (!($2 in group))
120 semantic_error("No group: " $2 )
121 gid = group[$2]
122 tname = "inat_group_table_" gid
123}
124
125function print_table(tbl,name,fmt,n)
126{
127 print "const insn_attr_t " name " = {"
128 for (i = 0; i < n; i++) {
129 id = sprintf(fmt, i)
130 if (tbl[id])
131 print " [" id "] = " tbl[id] ","
132 }
133 print "};"
134}
135
136/^EndTable/ {
137 if (gid != -1) {
138 # print group tables
139 if (array_size(table) != 0) {
140 print_table(table, tname "[INAT_GROUP_TABLE_SIZE]",
141 "0x%x", 8)
142 gtable[gid,0] = tname
143 }
144 if (array_size(lptable1) != 0) {
145 print_table(lptable1, tname "_1[INAT_GROUP_TABLE_SIZE]",
146 "0x%x", 8)
147 gtable[gid,1] = tname "_1"
148 }
149 if (array_size(lptable2) != 0) {
150 print_table(lptable2, tname "_2[INAT_GROUP_TABLE_SIZE]",
151 "0x%x", 8)
152 gtable[gid,2] = tname "_2"
153 }
154 if (array_size(lptable3) != 0) {
155 print_table(lptable3, tname "_3[INAT_GROUP_TABLE_SIZE]",
156 "0x%x", 8)
157 gtable[gid,3] = tname "_3"
158 }
159 } else {
160 # print primary/escaped tables
161 if (array_size(table) != 0) {
162 print_table(table, tname "[INAT_OPCODE_TABLE_SIZE]",
163 "0x%02x", 256)
164 etable[eid,0] = tname
165 }
166 if (array_size(lptable1) != 0) {
167 print_table(lptable1,tname "_1[INAT_OPCODE_TABLE_SIZE]",
168 "0x%02x", 256)
169 etable[eid,1] = tname "_1"
170 }
171 if (array_size(lptable2) != 0) {
172 print_table(lptable2,tname "_2[INAT_OPCODE_TABLE_SIZE]",
173 "0x%02x", 256)
174 etable[eid,2] = tname "_2"
175 }
176 if (array_size(lptable3) != 0) {
177 print_table(lptable3,tname "_3[INAT_OPCODE_TABLE_SIZE]",
178 "0x%02x", 256)
179 etable[eid,3] = tname "_3"
180 }
181 }
182 print ""
183 delete table
184 delete lptable1
185 delete lptable2
186 delete lptable3
187 gid = -1
188 eid = -1
189}
190
191function add_flags(old,new) {
192 if (old && new)
193 return old " | " new
194 else if (old)
195 return old
196 else
197 return new
198}
199
200# convert operands to flags.
201function convert_operands(opnd, i,imm,mod)
202{
203 imm = null
204 mod = null
205 for (i in opnd) {
206 i = opnd[i]
207 if (match(i, imm_expr) == 1) {
208 if (!imm_flag[i])
209 semantic_error("Unknown imm opnd: " i)
210 if (imm) {
211 if (i != "Ib")
212 semantic_error("Second IMM error")
213 imm = add_flags(imm, "INAT_SCNDIMM")
214 } else
215 imm = imm_flag[i]
216 } else if (match(i, modrm_expr))
217 mod = "INAT_MODRM"
218 }
219 return add_flags(imm, mod)
220}
221
222/^[0-9a-f]+\:/ {
223 if (NR == 1)
224 next
225 # get index
226 idx = "0x" substr($1, 1, index($1,":") - 1)
227 if (idx in table)
228 semantic_error("Redefine " idx " in " tname)
229
230 # check if escaped opcode
231 if ("escape" == $2) {
232 if ($3 != "#")
233 semantic_error("No escaped name")
234 ref = ""
235 for (i = 4; i <= NF; i++)
236 ref = ref $i
237 if (ref in escape)
238 semantic_error("Redefine escape (" ref ")")
239 escape[ref] = geid
240 geid++
241 table[idx] = "INAT_MAKE_ESCAPE(" escape[ref] ")"
242 next
243 }
244
245 variant = null
246 # converts
247 i = 2
248 while (i <= NF) {
249 opcode = $(i++)
250 delete opnds
251 ext = null
252 flags = null
253 opnd = null
254 # parse one opcode
255 if (match($i, opnd_expr)) {
256 opnd = $i
257 split($(i++), opnds, ",")
258 flags = convert_operands(opnds)
259 }
260 if (match($i, ext_expr))
261 ext = $(i++)
262 if (match($i, sep_expr))
263 i++
264 else if (i < NF)
265 semantic_error($i " is not a separator")
266
267 # check if group opcode
268 if (match(opcode, group_expr)) {
269 if (!(opcode in group)) {
270 group[opcode] = ggid
271 ggid++
272 }
273 flags = add_flags(flags, "INAT_MAKE_GROUP(" group[opcode] ")")
274 }
275 # check force(or default) 64bit
276 if (match(ext, force64_expr))
277 flags = add_flags(flags, "INAT_FORCE64")
278
279 # check REX prefix
280 if (match(opcode, rex_expr))
281 flags = add_flags(flags, "INAT_REXPFX")
282
283 # check coprocessor escape : TODO
284 if (match(opcode, fpu_expr))
285 flags = add_flags(flags, "INAT_MODRM")
286
287 # check prefixes
288 if (match(ext, prefix_expr)) {
289 if (!prefix_num[opcode])
290 semantic_error("Unknown prefix: " opcode)
291 flags = add_flags(flags, "INAT_MAKE_PREFIX(" prefix_num[opcode] ")")
292 }
293 if (length(flags) == 0)
294 continue
295 # check if last prefix
296 if (match(ext, lprefix1_expr)) {
297 lptable1[idx] = add_flags(lptable1[idx],flags)
298 variant = "INAT_VARIANT"
299 } else if (match(ext, lprefix2_expr)) {
300 lptable2[idx] = add_flags(lptable2[idx],flags)
301 variant = "INAT_VARIANT"
302 } else if (match(ext, lprefix3_expr)) {
303 lptable3[idx] = add_flags(lptable3[idx],flags)
304 variant = "INAT_VARIANT"
305 } else {
306 table[idx] = add_flags(table[idx],flags)
307 }
308 }
309 if (variant)
310 table[idx] = add_flags(table[idx],variant)
311}
312
313END {
Masami Hiramatsu69d991f2009-08-21 15:43:16 -0400314 if (awkchecked != "")
315 exit 1
Masami Hiramatsueb132962009-08-13 16:34:13 -0400316 # print escape opcode map's array
317 print "/* Escape opcode map array */"
318 print "const insn_attr_t const *inat_escape_tables[INAT_ESC_MAX + 1]" \
319 "[INAT_LPREFIX_MAX + 1] = {"
320 for (i = 0; i < geid; i++)
321 for (j = 0; j < max_lprefix; j++)
322 if (etable[i,j])
323 print " ["i"]["j"] = "etable[i,j]","
324 print "};\n"
325 # print group opcode map's array
326 print "/* Group opcode map array */"
327 print "const insn_attr_t const *inat_group_tables[INAT_GRP_MAX + 1]"\
328 "[INAT_LPREFIX_MAX + 1] = {"
329 for (i = 0; i < ggid; i++)
330 for (j = 0; j < max_lprefix; j++)
331 if (gtable[i,j])
332 print " ["i"]["j"] = "gtable[i,j]","
333 print "};"
334}