x86: Check awk features before generating inat-tables.c
[pandora-kernel.git] / arch / x86 / tools / gen-insn-attr-x86.awk
1 #!/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
7 # Awk implementation sanity check
8 function 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
16 BEGIN {
17         # 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
26         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
82 function semantic_error(msg) {
83         print "Semantic error at " NR ": " msg > "/dev/stderr"
84         exit 1
85 }
86
87 function debug(msg) {
88         print "DEBUG: " msg
89 }
90
91 function 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
125 function 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
191 function 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.
201 function 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
313 END {
314         if (awkchecked != "")
315                 exit 1
316         # 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 }