]>
Commit | Line | Data |
---|---|---|
fd67aa11 | 1 | /* Copyright (C) 2007-2024 Free Software Foundation, Inc. |
40b8e679 | 2 | |
9b201bb5 | 3 | This file is part of the GNU opcodes library. |
40b8e679 | 4 | |
9b201bb5 | 5 | This library is free software; you can redistribute it and/or modify |
40b8e679 | 6 | it under the terms of the GNU General Public License as published by |
9b201bb5 NC |
7 | the Free Software Foundation; either version 3, or (at your option) |
8 | any later version. | |
40b8e679 | 9 | |
9b201bb5 NC |
10 | It is distributed in the hope that it will be useful, but WITHOUT |
11 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
12 | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public | |
13 | License for more details. | |
40b8e679 L |
14 | |
15 | You should have received a copy of the GNU General Public License | |
16 | along with this program; if not, write to the Free Software | |
9b201bb5 NC |
17 | Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
18 | MA 02110-1301, USA. */ | |
40b8e679 | 19 | |
40fb9820 | 20 | #include "sysdep.h" |
4d97c5c8 | 21 | #include <stdbool.h> |
40b8e679 | 22 | #include <stdio.h> |
40b8e679 L |
23 | #include <errno.h> |
24 | #include "getopt.h" | |
25 | #include "libiberty.h" | |
c587b3f9 | 26 | #include "hashtab.h" |
40b8e679 L |
27 | #include "safe-ctype.h" |
28 | ||
29 | #include "i386-opc.h" | |
30 | ||
1d942ae9 JB |
31 | /* Build-time checks are preferrable over runtime ones. Use this construct |
32 | in preference where possible. */ | |
33 | #define static_assert(e) ((void)sizeof (struct { int _:1 - 2 * !(e); })) | |
34 | ||
40b8e679 L |
35 | static const char *program_name = NULL; |
36 | static int debug = 0; | |
37 | ||
4d97c5c8 | 38 | typedef struct dependency |
40fb9820 L |
39 | { |
40 | const char *name; | |
4d97c5c8 JB |
41 | /* Note: Only direct dependencies should be enumerated. */ |
42 | const char *deps; | |
43 | } dependency; | |
40fb9820 | 44 | |
4d97c5c8 | 45 | static const dependency isa_dependencies[] = |
40fb9820 | 46 | { |
4d97c5c8 | 47 | { "UNKNOWN", |
4fdeb2a3 | 48 | "~IAMCU" }, |
4d97c5c8 JB |
49 | { "GENERIC32", |
50 | "386" }, | |
51 | { "GENERIC64", | |
52 | "PENTIUMPRO|Clflush|SYSCALL|MMX|SSE2|LM" }, | |
53 | { "NONE", | |
54 | "0" }, | |
55 | { "PENTIUMPRO", | |
56 | "686|Nop" }, | |
57 | { "P2", | |
58 | "PENTIUMPRO|MMX" }, | |
59 | { "P3", | |
60 | "P2|SSE" }, | |
61 | { "P4", | |
62 | "P3|Clflush|SSE2" }, | |
63 | { "NOCONA", | |
cafa5ef7 | 64 | "GENERIC64|FISTTP|SSE3|MONITOR|CX16" }, |
4d97c5c8 | 65 | { "CORE", |
3eda60e3 | 66 | "P4|FISTTP|SSE3|MONITOR" }, |
4d97c5c8 JB |
67 | { "CORE2", |
68 | "NOCONA|SSSE3" }, | |
69 | { "COREI7", | |
c3bb24f5 | 70 | "CORE2|SSE4_2|Rdtscp|LAHF_SAHF" }, |
4d97c5c8 JB |
71 | { "K6", |
72 | "186|286|386|486|586|SYSCALL|387|MMX" }, | |
73 | { "K6_2", | |
74 | "K6|3dnow" }, | |
75 | { "ATHLON", | |
76 | "K6_2|686:min|687|Nop|3dnowA" }, | |
77 | { "K8", | |
78 | "ATHLON|Rdtscp|SSE2|LM" }, | |
79 | { "AMDFAM10", | |
cafa5ef7 | 80 | "K8|FISTTP|SSE4A|ABM|MONITOR" }, |
4d97c5c8 | 81 | { "BDVER1", |
d54678eb | 82 | "GENERIC64|FISTTP|Rdtscp|MONITOR|CX16|LAHF_SAHF|XOP|ABM|LWP|SVME|AES|PCLMULQDQ|PRFCHW" }, |
4d97c5c8 JB |
83 | { "BDVER2", |
84 | "BDVER1|FMA|BMI|TBM|F16C" }, | |
85 | { "BDVER3", | |
86 | "BDVER2|Xsaveopt|FSGSBase" }, | |
87 | { "BDVER4", | |
88 | "BDVER3|AVX2|Movbe|BMI2|RdRnd|MWAITX" }, | |
89 | { "ZNVER1", | |
d54678eb | 90 | "GENERIC64|FISTTP|Rdtscp|MONITOR|CX16|LAHF_SAHF|AVX2|SSE4A|ABM|SVME|AES|PCLMULQDQ|PRFCHW|FMA|BMI|F16C|Xsaveopt|FSGSBase|Movbe|BMI2|RdRnd|ADX|RdSeed|SMAP|SHA|XSAVEC|XSAVES|ClflushOpt|CLZERO|MWAITX" }, |
4d97c5c8 JB |
91 | { "ZNVER2", |
92 | "ZNVER1|CLWB|RDPID|RDPRU|MCOMMIT|WBNOINVD" }, | |
93 | { "ZNVER3", | |
94 | "ZNVER2|INVLPGB|TLBSYNC|VAES|VPCLMULQDQ|INVPCID|SNP|OSPKE" }, | |
95 | { "ZNVER4", | |
96 | "ZNVER3|AVX512F|AVX512DQ|AVX512IFMA|AVX512CD|AVX512BW|AVX512VL|AVX512_BF16|AVX512VBMI|AVX512_VBMI2|AVX512_VNNI|AVX512_BITALG|AVX512_VPOPCNTDQ|GFNI|RMPQUERY" }, | |
b143c979 TJ |
97 | { "ZNVER5", |
98 | "ZNVER4|AVX_VNNI|MOVDIRI|MOVDIR64B|AVX512_VP2INTERSECT|PREFETCHI" }, | |
4d97c5c8 | 99 | { "BTVER1", |
cafa5ef7 | 100 | "GENERIC64|FISTTP|MONITOR|CX16|LAHF_SAHF|Rdtscp|SSSE3|SSE4A|ABM|PRFCHW|Clflush|FISTTP|SVME" }, |
4d97c5c8 | 101 | { "BTVER2", |
d54678eb | 102 | "BTVER1|AVX|BMI|F16C|AES|PCLMULQDQ|Movbe|Xsaveopt|PRFCHW" }, |
4d97c5c8 | 103 | { "286", |
4fdeb2a3 | 104 | "186" }, |
4d97c5c8 JB |
105 | { "386", |
106 | "286" }, | |
107 | { "486", | |
108 | "386" }, | |
109 | { "586", | |
110 | "486|387" }, | |
111 | { "586:nofpu", | |
112 | "486" }, | |
113 | { "686", | |
114 | "586|687|CMOV|FXSR" }, | |
115 | { "686:min", | |
116 | "586|687" }, | |
117 | { "687", | |
4fdeb2a3 | 118 | "387" }, |
4d97c5c8 JB |
119 | { "FISTTP", |
120 | "687" }, | |
88bd2203 JB |
121 | { "SSE", |
122 | "FXSR" }, | |
4d97c5c8 | 123 | { "SSE2", |
4fdeb2a3 | 124 | "SSE" }, |
4d97c5c8 JB |
125 | { "SSE3", |
126 | "SSE2" }, | |
127 | { "SSSE3", | |
128 | "SSE3" }, | |
129 | { "SSE4_1", | |
130 | "SSSE3" }, | |
131 | { "SSE4_2", | |
132 | "SSE4_1|POPCNT" }, | |
133 | { "Xsaveopt", | |
134 | "XSAVE" }, | |
135 | { "AES", | |
136 | "SSE2" }, | |
d54678eb | 137 | { "PCLMULQDQ", |
4d97c5c8 JB |
138 | "SSE2" }, |
139 | { "FMA", | |
140 | "AVX" }, | |
141 | { "FMA4", | |
142 | "AVX" }, | |
143 | { "XOP", | |
144 | "SSE4A|FMA4" }, | |
145 | { "LWP", | |
146 | "XSAVE" }, | |
147 | { "F16C", | |
148 | "AVX" }, | |
149 | { "3dnow", | |
150 | "MMX" }, | |
151 | { "3dnowA", | |
152 | "3dnow" }, | |
153 | { "SSE4a", | |
154 | "SSE3" }, | |
155 | { "ABM", | |
4fdeb2a3 | 156 | "LZCNT|POPCNT" }, |
4d97c5c8 JB |
157 | { "AVX", |
158 | "SSE4_2|XSAVE" }, | |
159 | { "AVX2", | |
160 | "AVX" }, | |
161 | { "AVX_VNNI", | |
162 | "AVX2" }, | |
163 | { "AVX_IFMA", | |
164 | "AVX2" }, | |
165 | { "AVX_VNNI_INT8", | |
166 | "AVX2" }, | |
b5c37946 SJ |
167 | { "AVX_VNNI_INT16", |
168 | "AVX2" }, | |
4d97c5c8 JB |
169 | { "AVX_NE_CONVERT", |
170 | "AVX2" }, | |
3e624fa4 JB |
171 | { "CX16", |
172 | "64" }, | |
173 | { "LKGS", | |
174 | "64" }, | |
c88ed92f ZJ |
175 | { "FRED", |
176 | "LKGS" }, | |
4d97c5c8 JB |
177 | { "AVX512F", |
178 | "AVX2" }, | |
179 | { "AVX512CD", | |
180 | "AVX512F" }, | |
181 | { "AVX512ER", | |
182 | "AVX512F" }, | |
183 | { "AVX512PF", | |
184 | "AVX512F" }, | |
185 | { "AVX512DQ", | |
186 | "AVX512F" }, | |
187 | { "AVX512BW", | |
188 | "AVX512F" }, | |
189 | { "AVX512VL", | |
190 | "AVX512F" }, | |
191 | { "AVX512IFMA", | |
192 | "AVX512F" }, | |
193 | { "AVX512VBMI", | |
9a019125 | 194 | "AVX512BW" }, |
4d97c5c8 JB |
195 | { "AVX512_4FMAPS", |
196 | "AVX512F" }, | |
197 | { "AVX512_4VNNIW", | |
198 | "AVX512F" }, | |
199 | { "AVX512_VPOPCNTDQ", | |
200 | "AVX512F" }, | |
201 | { "AVX512_VBMI2", | |
9a019125 | 202 | "AVX512BW" }, |
4d97c5c8 JB |
203 | { "AVX512_VNNI", |
204 | "AVX512F" }, | |
205 | { "AVX512_BITALG", | |
9a019125 | 206 | "AVX512BW" }, |
4d97c5c8 JB |
207 | { "AVX512_VP2INTERSECT", |
208 | "AVX512F" }, | |
209 | { "AVX512_BF16", | |
9a019125 | 210 | "AVX512BW" }, |
4d97c5c8 JB |
211 | { "AVX512_FP16", |
212 | "AVX512BW" }, | |
213 | { "IAMCU", | |
214 | "586:nofpu" }, | |
25626f79 JB |
215 | { "EPT", |
216 | "VMX" }, | |
217 | { "VMFUNC", | |
218 | "VMX" }, | |
4d97c5c8 JB |
219 | { "MPX", |
220 | "XSAVE" }, | |
221 | { "SHA", | |
222 | "SSE2" }, | |
b5c37946 SJ |
223 | { "SHA512", |
224 | "AVX2" }, | |
225 | { "SM3", | |
226 | "AVX" }, | |
227 | { "SM4", | |
228 | "AVX2" }, | |
4d97c5c8 | 229 | { "XSAVES", |
af1ad9aa | 230 | "XSAVEC" }, |
4d97c5c8 JB |
231 | { "XSAVEC", |
232 | "XSAVE" }, | |
233 | { "OSPKE", | |
234 | "XSAVE" }, | |
88bd2203 JB |
235 | { "GFNI", |
236 | "SSE2" }, | |
b20f4261 | 237 | { "VAES", |
d5f9027c | 238 | "AVX2|AES" }, |
b20f4261 | 239 | { "VPCLMULQDQ", |
d5f9027c | 240 | "AVX2|PCLMULQDQ" }, |
2548c261 JB |
241 | { "AVX10_1", |
242 | "AVX512VL|AVX512DQ|AVX512CD|AVX512VBMI|AVX512_VBMI2|AVX512IFMA" | |
243 | "|AVX512_VNNI|AVX512_BF16|AVX512_FP16|AVX512_VPOPCNTDQ|AVX512_BITALG" }, | |
0919e770 JB |
244 | { "SEV_ES", |
245 | "SVME" }, | |
246 | { "SNP", | |
247 | "SEV_ES" }, | |
248 | { "RMPQUERY", | |
3e624fa4 | 249 | "SNP|64" }, |
760ab3d0 JB |
250 | { "TSX", |
251 | "RTM|HLE" }, | |
252 | { "TSXLDTRK", | |
253 | "RTM" }, | |
af1ad9aa | 254 | { "AMX_TILE", |
3e624fa4 | 255 | "XSAVE|64" }, |
4d97c5c8 JB |
256 | { "AMX_INT8", |
257 | "AMX_TILE" }, | |
258 | { "AMX_BF16", | |
259 | "AMX_TILE" }, | |
260 | { "AMX_FP16", | |
4fdeb2a3 | 261 | "AMX_TILE" }, |
d100d8c1 HJ |
262 | { "AMX_COMPLEX", |
263 | "AMX_TILE" }, | |
88bd2203 JB |
264 | { "KL", |
265 | "SSE2" }, | |
266 | { "WIDEKL", | |
267 | "KL" }, | |
3e624fa4 JB |
268 | { "PBNDKB", |
269 | "64" }, | |
270 | { "UINTR", | |
271 | "64" }, | |
272 | { "PREFETCHI", | |
273 | "64" }, | |
274 | { "CMPCCXADD", | |
275 | "64" }, | |
276 | { "MSRLIST", | |
277 | "64" }, | |
278 | { "USER_MSR", | |
279 | "64" }, | |
80d61d8d CL |
280 | { "APX_F", |
281 | "XSAVE|64" }, | |
40fb9820 L |
282 | }; |
283 | ||
4d97c5c8 | 284 | /* This array is populated as process_i386_initializers() walks cpu_flags[]. */ |
da5f9eb4 | 285 | static unsigned char isa_reverse_deps[CpuMax][CpuMax]; |
4d97c5c8 | 286 | |
40fb9820 L |
287 | typedef struct bitfield |
288 | { | |
289 | int position; | |
290 | int value; | |
291 | const char *name; | |
292 | } bitfield; | |
293 | ||
4fdeb2a3 | 294 | #define BITFIELD(n) { Cpu##n, 0, #n } |
40fb9820 L |
295 | |
296 | static bitfield cpu_flags[] = | |
297 | { | |
4fdeb2a3 JB |
298 | BITFIELD (186), |
299 | BITFIELD (286), | |
300 | BITFIELD (386), | |
301 | BITFIELD (486), | |
302 | BITFIELD (586), | |
303 | BITFIELD (686), | |
304 | BITFIELD (CMOV), | |
305 | BITFIELD (FXSR), | |
306 | BITFIELD (Clflush), | |
307 | BITFIELD (Nop), | |
308 | BITFIELD (SYSCALL), | |
309 | BITFIELD (8087), | |
310 | BITFIELD (287), | |
311 | BITFIELD (387), | |
312 | BITFIELD (687), | |
313 | BITFIELD (FISTTP), | |
314 | BITFIELD (MMX), | |
315 | BITFIELD (SSE), | |
316 | BITFIELD (SSE2), | |
317 | BITFIELD (SSE3), | |
318 | BITFIELD (SSSE3), | |
319 | BITFIELD (SSE4_1), | |
320 | BITFIELD (SSE4_2), | |
321 | BITFIELD (AVX), | |
322 | BITFIELD (AVX2), | |
323 | BITFIELD (AVX512F), | |
324 | BITFIELD (AVX512CD), | |
325 | BITFIELD (AVX512ER), | |
326 | BITFIELD (AVX512PF), | |
327 | BITFIELD (AVX512VL), | |
328 | BITFIELD (AVX512DQ), | |
329 | BITFIELD (AVX512BW), | |
330 | BITFIELD (IAMCU), | |
331 | BITFIELD (SSE4a), | |
332 | BITFIELD (3dnow), | |
333 | BITFIELD (3dnowA), | |
334 | BITFIELD (PadLock), | |
335 | BITFIELD (SVME), | |
336 | BITFIELD (VMX), | |
337 | BITFIELD (SMX), | |
338 | BITFIELD (Xsave), | |
339 | BITFIELD (Xsaveopt), | |
340 | BITFIELD (AES), | |
d54678eb | 341 | BITFIELD (PCLMULQDQ), |
4fdeb2a3 JB |
342 | BITFIELD (FMA), |
343 | BITFIELD (FMA4), | |
344 | BITFIELD (XOP), | |
345 | BITFIELD (LWP), | |
346 | BITFIELD (BMI), | |
347 | BITFIELD (TBM), | |
4fdeb2a3 JB |
348 | BITFIELD (Movbe), |
349 | BITFIELD (CX16), | |
c3bb24f5 | 350 | BITFIELD (LAHF_SAHF), |
4fdeb2a3 JB |
351 | BITFIELD (EPT), |
352 | BITFIELD (Rdtscp), | |
353 | BITFIELD (FSGSBase), | |
354 | BITFIELD (RdRnd), | |
355 | BITFIELD (F16C), | |
356 | BITFIELD (BMI2), | |
357 | BITFIELD (LZCNT), | |
358 | BITFIELD (POPCNT), | |
cafa5ef7 | 359 | BITFIELD (MONITOR), |
4fdeb2a3 JB |
360 | BITFIELD (HLE), |
361 | BITFIELD (RTM), | |
362 | BITFIELD (INVPCID), | |
363 | BITFIELD (VMFUNC), | |
364 | BITFIELD (RDSEED), | |
365 | BITFIELD (ADX), | |
366 | BITFIELD (PRFCHW), | |
367 | BITFIELD (SMAP), | |
368 | BITFIELD (SHA), | |
b5c37946 SJ |
369 | BITFIELD (SHA512), |
370 | BITFIELD (SM3), | |
371 | BITFIELD (SM4), | |
4fdeb2a3 JB |
372 | BITFIELD (ClflushOpt), |
373 | BITFIELD (XSAVES), | |
374 | BITFIELD (XSAVEC), | |
375 | BITFIELD (PREFETCHWT1), | |
376 | BITFIELD (SE1), | |
377 | BITFIELD (CLWB), | |
378 | BITFIELD (MPX), | |
379 | BITFIELD (AVX512IFMA), | |
380 | BITFIELD (AVX512VBMI), | |
381 | BITFIELD (AVX512_4FMAPS), | |
382 | BITFIELD (AVX512_4VNNIW), | |
383 | BITFIELD (AVX512_VPOPCNTDQ), | |
384 | BITFIELD (AVX512_VBMI2), | |
385 | BITFIELD (AVX512_VNNI), | |
386 | BITFIELD (AVX512_BITALG), | |
387 | BITFIELD (AVX512_BF16), | |
388 | BITFIELD (AVX512_VP2INTERSECT), | |
389 | BITFIELD (TDX), | |
390 | BITFIELD (AVX_VNNI), | |
391 | BITFIELD (AVX512_FP16), | |
392 | BITFIELD (PREFETCHI), | |
393 | BITFIELD (AVX_IFMA), | |
394 | BITFIELD (AVX_VNNI_INT8), | |
b5c37946 | 395 | BITFIELD (AVX_VNNI_INT16), |
4fdeb2a3 JB |
396 | BITFIELD (CMPCCXADD), |
397 | BITFIELD (WRMSRNS), | |
398 | BITFIELD (MSRLIST), | |
399 | BITFIELD (AVX_NE_CONVERT), | |
400 | BITFIELD (RAO_INT), | |
c88ed92f ZJ |
401 | BITFIELD (FRED), |
402 | BITFIELD (LKGS), | |
8170af78 | 403 | BITFIELD (USER_MSR), |
80d61d8d | 404 | BITFIELD (APX_F), |
4fdeb2a3 JB |
405 | BITFIELD (MWAITX), |
406 | BITFIELD (CLZERO), | |
407 | BITFIELD (OSPKE), | |
408 | BITFIELD (RDPID), | |
409 | BITFIELD (PTWRITE), | |
410 | BITFIELD (IBT), | |
411 | BITFIELD (SHSTK), | |
412 | BITFIELD (GFNI), | |
413 | BITFIELD (VAES), | |
414 | BITFIELD (VPCLMULQDQ), | |
415 | BITFIELD (WBNOINVD), | |
416 | BITFIELD (PCONFIG), | |
b5c37946 | 417 | BITFIELD (PBNDKB), |
4fdeb2a3 JB |
418 | BITFIELD (WAITPKG), |
419 | BITFIELD (UINTR), | |
420 | BITFIELD (CLDEMOTE), | |
421 | BITFIELD (AMX_INT8), | |
422 | BITFIELD (AMX_BF16), | |
423 | BITFIELD (AMX_FP16), | |
d100d8c1 | 424 | BITFIELD (AMX_COMPLEX), |
4fdeb2a3 JB |
425 | BITFIELD (AMX_TILE), |
426 | BITFIELD (MOVDIRI), | |
427 | BITFIELD (MOVDIR64B), | |
428 | BITFIELD (ENQCMD), | |
429 | BITFIELD (SERIALIZE), | |
430 | BITFIELD (RDPRU), | |
431 | BITFIELD (MCOMMIT), | |
432 | BITFIELD (SEV_ES), | |
433 | BITFIELD (TSXLDTRK), | |
434 | BITFIELD (KL), | |
435 | BITFIELD (WideKL), | |
436 | BITFIELD (HRESET), | |
437 | BITFIELD (INVLPGB), | |
438 | BITFIELD (TLBSYNC), | |
439 | BITFIELD (SNP), | |
440 | BITFIELD (RMPQUERY), | |
441 | BITFIELD (64), | |
442 | BITFIELD (No64), | |
40fb9820 | 443 | #ifdef CpuUnused |
4fdeb2a3 | 444 | BITFIELD (Unused), |
40fb9820 L |
445 | #endif |
446 | }; | |
447 | ||
4fdeb2a3 JB |
448 | #undef BITFIELD |
449 | #define BITFIELD(n) { n, 0, #n } | |
450 | ||
40fb9820 L |
451 | static bitfield opcode_modifiers[] = |
452 | { | |
453 | BITFIELD (D), | |
454 | BITFIELD (W), | |
86fa6981 | 455 | BITFIELD (Load), |
40fb9820 | 456 | BITFIELD (Modrm), |
40fb9820 | 457 | BITFIELD (Jump), |
40fb9820 | 458 | BITFIELD (FloatMF), |
673fe0f0 | 459 | BITFIELD (Size), |
9c19e9ec | 460 | BITFIELD (CheckOperandSize), |
255571cd | 461 | BITFIELD (OperandConstraint), |
3cd7f3e3 | 462 | BITFIELD (MnemonicSize), |
40fb9820 L |
463 | BITFIELD (No_bSuf), |
464 | BITFIELD (No_wSuf), | |
465 | BITFIELD (No_lSuf), | |
466 | BITFIELD (No_sSuf), | |
467 | BITFIELD (No_qSuf), | |
40fb9820 L |
468 | BITFIELD (FWait), |
469 | BITFIELD (IsString), | |
dfd69174 | 470 | BITFIELD (RegMem), |
7e8b059b | 471 | BITFIELD (BNDPrefixOk), |
742732c7 | 472 | BITFIELD (PrefixOk), |
40fb9820 L |
473 | BITFIELD (IsPrefix), |
474 | BITFIELD (ImmExt), | |
475 | BITFIELD (NoRex64), | |
c0f3af97 | 476 | BITFIELD (Vex), |
2426c15f | 477 | BITFIELD (VexVVVV), |
1ef99a7b | 478 | BITFIELD (VexW), |
7b47a312 | 479 | BITFIELD (OpcodePrefix), |
63112cd6 | 480 | BITFIELD (SIB), |
c0f3af97 | 481 | BITFIELD (SSE2AVX), |
43234a1e L |
482 | BITFIELD (EVex), |
483 | BITFIELD (Masking), | |
43234a1e L |
484 | BITFIELD (Broadcast), |
485 | BITFIELD (StaticRounding), | |
486 | BITFIELD (SAE), | |
487 | BITFIELD (Disp8MemShift), | |
b6f8c7c4 | 488 | BITFIELD (Optimize), |
35266cb1 | 489 | BITFIELD (Dialect), |
4b5aaf5f | 490 | BITFIELD (ISA64), |
80d61d8d | 491 | BITFIELD (NoEgpr), |
6177c84d | 492 | BITFIELD (NF), |
3037cefe | 493 | BITFIELD (Rex2), |
40fb9820 L |
494 | }; |
495 | ||
bab6aec1 JB |
496 | #define CLASS(n) #n, n |
497 | ||
498 | static const struct { | |
499 | const char *name; | |
500 | enum operand_class value; | |
501 | } operand_classes[] = { | |
502 | CLASS (Reg), | |
00cee14f | 503 | CLASS (SReg), |
4a5c67ed JB |
504 | CLASS (RegCR), |
505 | CLASS (RegDR), | |
506 | CLASS (RegTR), | |
3528c362 JB |
507 | CLASS (RegMMX), |
508 | CLASS (RegSIMD), | |
f74a6307 JB |
509 | CLASS (RegMask), |
510 | CLASS (RegBND), | |
bab6aec1 JB |
511 | }; |
512 | ||
513 | #undef CLASS | |
514 | ||
75e5731b JB |
515 | #define INSTANCE(n) #n, n |
516 | ||
517 | static const struct { | |
518 | const char *name; | |
519 | enum operand_instance value; | |
520 | } operand_instances[] = { | |
521 | INSTANCE (Accum), | |
522 | INSTANCE (RegC), | |
523 | INSTANCE (RegD), | |
474da251 | 524 | INSTANCE (RegB), |
75e5731b JB |
525 | }; |
526 | ||
527 | #undef INSTANCE | |
528 | ||
40fb9820 L |
529 | static bitfield operand_types[] = |
530 | { | |
94ff3a50 | 531 | BITFIELD (Imm1), |
40fb9820 L |
532 | BITFIELD (Imm8), |
533 | BITFIELD (Imm8S), | |
534 | BITFIELD (Imm16), | |
535 | BITFIELD (Imm32), | |
536 | BITFIELD (Imm32S), | |
537 | BITFIELD (Imm64), | |
40fb9820 L |
538 | BITFIELD (BaseIndex), |
539 | BITFIELD (Disp8), | |
540 | BITFIELD (Disp16), | |
541 | BITFIELD (Disp32), | |
40fb9820 | 542 | BITFIELD (Disp64), |
7d5e4556 L |
543 | BITFIELD (Byte), |
544 | BITFIELD (Word), | |
545 | BITFIELD (Dword), | |
546 | BITFIELD (Fword), | |
547 | BITFIELD (Qword), | |
548 | BITFIELD (Tbyte), | |
549 | BITFIELD (Xmmword), | |
c0f3af97 | 550 | BITFIELD (Ymmword), |
43234a1e | 551 | BITFIELD (Zmmword), |
260cd341 | 552 | BITFIELD (Tmmword), |
7d5e4556 | 553 | BITFIELD (Unspecified), |
40fb9820 L |
554 | #ifdef OTUnused |
555 | BITFIELD (OTUnused), | |
556 | #endif | |
557 | }; | |
558 | ||
3d4d5afa | 559 | static const char *filename; |
7ac20022 JB |
560 | static i386_cpu_flags active_cpu_flags; |
561 | static int active_isstring; | |
3d4d5afa | 562 | |
4c4898e8 JB |
563 | struct template_arg { |
564 | const struct template_arg *next; | |
565 | const char *val; | |
566 | }; | |
567 | ||
568 | struct template_instance { | |
569 | const struct template_instance *next; | |
570 | const char *name; | |
571 | const struct template_arg *args; | |
572 | }; | |
573 | ||
574 | struct template_param { | |
575 | const struct template_param *next; | |
576 | const char *name; | |
577 | }; | |
578 | ||
579 | struct template { | |
e07ae9a3 | 580 | struct template *next; |
4c4898e8 JB |
581 | const char *name; |
582 | const struct template_instance *instances; | |
583 | const struct template_param *params; | |
584 | }; | |
585 | ||
e07ae9a3 | 586 | static struct template *templates; |
4c4898e8 | 587 | |
40fb9820 L |
588 | static int |
589 | compare (const void *x, const void *y) | |
590 | { | |
591 | const bitfield *xp = (const bitfield *) x; | |
592 | const bitfield *yp = (const bitfield *) y; | |
593 | return xp->position - yp->position; | |
594 | } | |
595 | ||
40b8e679 L |
596 | static void |
597 | fail (const char *message, ...) | |
598 | { | |
599 | va_list args; | |
29c048b6 | 600 | |
40b8e679 | 601 | va_start (args, message); |
06ceca3a | 602 | fprintf (stderr, "%s: error: ", program_name); |
40b8e679 L |
603 | vfprintf (stderr, message, args); |
604 | va_end (args); | |
605 | xexit (1); | |
606 | } | |
607 | ||
72ffa0fb L |
608 | static void |
609 | process_copyright (FILE *fp) | |
610 | { | |
611 | fprintf (fp, "/* This file is automatically generated by i386-gen. Do not edit! */\n\ | |
fd67aa11 | 612 | /* Copyright (C) 2007-2024 Free Software Foundation, Inc.\n\ |
72ffa0fb L |
613 | \n\ |
614 | This file is part of the GNU opcodes library.\n\ | |
615 | \n\ | |
616 | This library is free software; you can redistribute it and/or modify\n\ | |
617 | it under the terms of the GNU General Public License as published by\n\ | |
618 | the Free Software Foundation; either version 3, or (at your option)\n\ | |
619 | any later version.\n\ | |
620 | \n\ | |
621 | It is distributed in the hope that it will be useful, but WITHOUT\n\ | |
622 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n\ | |
623 | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public\n\ | |
624 | License for more details.\n\ | |
625 | \n\ | |
626 | You should have received a copy of the GNU General Public License\n\ | |
627 | along with this program; if not, write to the Free Software\n\ | |
628 | Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,\n\ | |
629 | MA 02110-1301, USA. */\n"); | |
630 | } | |
631 | ||
40b8e679 L |
632 | /* Remove leading white spaces. */ |
633 | ||
634 | static char * | |
635 | remove_leading_whitespaces (char *str) | |
636 | { | |
637 | while (ISSPACE (*str)) | |
638 | str++; | |
639 | return str; | |
640 | } | |
641 | ||
642 | /* Remove trailing white spaces. */ | |
643 | ||
644 | static void | |
645 | remove_trailing_whitespaces (char *str) | |
646 | { | |
647 | size_t last = strlen (str); | |
648 | ||
649 | if (last == 0) | |
650 | return; | |
651 | ||
652 | do | |
653 | { | |
654 | last--; | |
655 | if (ISSPACE (str [last])) | |
656 | str[last] = '\0'; | |
657 | else | |
658 | break; | |
659 | } | |
660 | while (last != 0); | |
661 | } | |
662 | ||
93b1ec2c | 663 | /* Find next field separated by SEP and terminate it. Return a |
40b8e679 L |
664 | pointer to the one after it. */ |
665 | ||
666 | static char * | |
c587b3f9 | 667 | next_field (char *str, char sep, char **next, char *last) |
40b8e679 L |
668 | { |
669 | char *p; | |
670 | ||
671 | p = remove_leading_whitespaces (str); | |
93b1ec2c | 672 | for (str = p; *str != sep && *str != '\0'; str++); |
40b8e679 L |
673 | |
674 | *str = '\0'; | |
675 | remove_trailing_whitespaces (p); | |
676 | ||
29c048b6 | 677 | *next = str + 1; |
40b8e679 | 678 | |
c587b3f9 L |
679 | if (p >= last) |
680 | abort (); | |
681 | ||
40b8e679 L |
682 | return p; |
683 | } | |
684 | ||
1848e567 L |
685 | static void set_bitfield (char *, bitfield *, int, unsigned int, int); |
686 | ||
40fb9820 | 687 | static void |
1848e567 | 688 | set_bitfield (char *f, bitfield *array, int value, |
8a9036a4 | 689 | unsigned int size, int lineno) |
40fb9820 L |
690 | { |
691 | unsigned int i; | |
692 | ||
3677e4c1 JB |
693 | /* Ignore empty fields; they may result from template expansions. */ |
694 | if (*f == '\0') | |
695 | return; | |
696 | ||
40fb9820 L |
697 | for (i = 0; i < size; i++) |
698 | if (strcasecmp (array[i].name, f) == 0) | |
699 | { | |
8a9036a4 | 700 | array[i].value = value; |
40fb9820 L |
701 | return; |
702 | } | |
703 | ||
2bf05e57 L |
704 | if (value) |
705 | { | |
706 | const char *v = strchr (f, '='); | |
707 | ||
708 | if (v) | |
709 | { | |
710 | size_t n = v - f; | |
711 | char *end; | |
712 | ||
713 | for (i = 0; i < size; i++) | |
714 | if (strncasecmp (array[i].name, f, n) == 0) | |
715 | { | |
716 | value = strtol (v + 1, &end, 0); | |
717 | if (*end == '\0') | |
718 | { | |
719 | array[i].value = value; | |
720 | return; | |
721 | } | |
722 | break; | |
723 | } | |
724 | } | |
725 | } | |
726 | ||
bd5295b2 | 727 | if (lineno != -1) |
06ceca3a | 728 | fail ("%s: %d: unknown bitfield: %s\n", filename, lineno, f); |
bd5295b2 | 729 | else |
06ceca3a | 730 | fail ("unknown bitfield: %s\n", f); |
40fb9820 L |
731 | } |
732 | ||
4d97c5c8 JB |
733 | static void |
734 | add_isa_dependencies (bitfield *flags, const char *f, int value, | |
735 | unsigned int reverse) | |
736 | { | |
737 | unsigned int i; | |
738 | char *str = NULL; | |
739 | const char *isa = f; | |
d5f9027c JB |
740 | static bool is_avx; |
741 | bool is_isa = false, orig_is_avx = is_avx; | |
4d97c5c8 JB |
742 | |
743 | /* Need to find base entry for references to auxiliary ones. */ | |
744 | if (strchr (f, ':')) | |
745 | { | |
746 | str = xstrdup (f); | |
747 | *strchr (str, ':') = '\0'; | |
748 | isa = str; | |
749 | } | |
da5f9eb4 JB |
750 | /* isa_dependencies[] prefers "LM" over "64". */ |
751 | else if (!strcmp (f, "LM")) | |
752 | isa = "64"; | |
753 | for (i = 0; i < CpuMax; ++i) | |
4d97c5c8 JB |
754 | if (strcasecmp (flags[i].name, isa) == 0) |
755 | { | |
756 | flags[i].value = value; | |
757 | if (reverse < ARRAY_SIZE (isa_reverse_deps[0]) | |
758 | /* Don't record the feature itself here. */ | |
759 | && reverse != i | |
760 | /* Don't record base architectures. */ | |
761 | && reverse > Cpu686) | |
762 | isa_reverse_deps[i][reverse] = 1; | |
763 | is_isa = true; | |
d5f9027c | 764 | if (i == CpuAVX || i == CpuXOP || i == CpuVAES || i == CpuVPCLMULQDQ) |
4d97c5c8 JB |
765 | is_avx = true; |
766 | break; | |
767 | } | |
768 | free (str); | |
769 | ||
770 | /* Do not turn off dependencies. */ | |
771 | if (is_isa && !value) | |
d5f9027c JB |
772 | { |
773 | is_avx = orig_is_avx; | |
774 | return; | |
775 | } | |
4d97c5c8 JB |
776 | |
777 | for (i = 0; i < ARRAY_SIZE (isa_dependencies); ++i) | |
778 | if (strcasecmp (isa_dependencies[i].name, f) == 0) | |
779 | { | |
780 | char *deps = xstrdup (isa_dependencies[i].deps); | |
781 | char *next = deps; | |
782 | char *last = deps + strlen (deps); | |
783 | ||
784 | for (; next && next < last; ) | |
785 | { | |
786 | char *str = next_field (next, '|', &next, last); | |
787 | ||
788 | /* No AVX/XOP -> SSE reverse dependencies. */ | |
789 | if (is_avx && strncmp (str, "SSE", 3) == 0) | |
790 | add_isa_dependencies (flags, str, value, CpuMax); | |
791 | else | |
792 | add_isa_dependencies (flags, str, value, reverse); | |
793 | } | |
794 | free (deps); | |
795 | ||
3e624fa4 JB |
796 | /* ISA extensions with dependencies need CPU_ANY_*_FLAGS emitted, |
797 | unless the sole dependency is the "64-bit mode only" one. */ | |
798 | if (reverse < ARRAY_SIZE (isa_reverse_deps[0]) | |
799 | && strcmp (isa_dependencies[i].deps, "64")) | |
4d97c5c8 JB |
800 | isa_reverse_deps[reverse][reverse] = 1; |
801 | ||
d5f9027c | 802 | is_avx = orig_is_avx; |
4d97c5c8 JB |
803 | return; |
804 | } | |
805 | ||
806 | if (!is_isa) | |
06ceca3a | 807 | fail ("unknown bitfield: %s\n", f); |
d5f9027c JB |
808 | |
809 | is_avx = orig_is_avx; | |
4d97c5c8 JB |
810 | } |
811 | ||
40fb9820 L |
812 | static void |
813 | output_cpu_flags (FILE *table, bitfield *flags, unsigned int size, | |
a5e91879 | 814 | int mode, const char *comma, const char *indent, int lineno) |
40fb9820 | 815 | { |
734dfd1c | 816 | unsigned int i = 0, j = 0; |
40fb9820 | 817 | |
a5e91879 JB |
818 | if (mode < 0) |
819 | memset (&active_cpu_flags, 0, sizeof(active_cpu_flags)); | |
7ac20022 | 820 | |
40fb9820 L |
821 | fprintf (table, "%s{ { ", indent); |
822 | ||
a5e91879 | 823 | if (mode <= 0) |
40fb9820 | 824 | { |
734dfd1c JB |
825 | for (j = ~0u; i < CpuAttrEnums; i++) |
826 | { | |
827 | if (!flags[i].value) | |
828 | continue; | |
829 | ||
830 | if (j < ~0u) | |
831 | fail ("%s: %d: invalid combination of CPU identifiers\n", | |
832 | filename, lineno); | |
833 | j = i; | |
a5e91879 JB |
834 | if (mode) |
835 | active_cpu_flags.array[i / 32] |= 1U << (i % 32); | |
734dfd1c JB |
836 | } |
837 | ||
838 | /* Write 0 to indicate "no associated flag". */ | |
839 | fprintf (table, "%u, ", j + 1); | |
840 | ||
841 | j = 1; | |
842 | } | |
843 | ||
844 | for (; i < size - 1; i++, j++) | |
845 | { | |
846 | if (((j + 1) % 20) != 0) | |
10632b79 L |
847 | fprintf (table, "%d, ", flags[i].value); |
848 | else | |
849 | fprintf (table, "%d,", flags[i].value); | |
734dfd1c | 850 | if (((j + 1) % 20) == 0) |
40fb9820 L |
851 | { |
852 | /* We need \\ for macro. */ | |
a5e91879 | 853 | if (mode > 0) |
40fb9820 L |
854 | fprintf (table, " \\\n %s", indent); |
855 | else | |
856 | fprintf (table, "\n %s", indent); | |
857 | } | |
a5e91879 | 858 | if (mode < 0 && flags[i].value) |
7ac20022 | 859 | active_cpu_flags.array[i / 32] |= 1U << (i % 32); |
40fb9820 L |
860 | } |
861 | ||
a12915cc JB |
862 | #if defined(CpuAttrUnused) != defined(CpuUnused) |
863 | if (mode <= 0) | |
864 | # ifdef CpuUnused | |
865 | fprintf (table, " } }%s\n", comma); | |
866 | # else | |
867 | fprintf (table, "%d, 0 } }%s\n", flags[i].value, comma); | |
868 | # endif | |
869 | else | |
870 | #endif | |
871 | fprintf (table, "%d } }%s\n", flags[i].value, comma); | |
40fb9820 L |
872 | } |
873 | ||
874 | static void | |
4d97c5c8 JB |
875 | process_i386_cpu_flag (FILE *table, char *flag, |
876 | const char *name, | |
bd5295b2 | 877 | const char *comma, const char *indent, |
4d97c5c8 | 878 | int lineno, unsigned int reverse) |
40fb9820 | 879 | { |
ad9de929 | 880 | char *str, *next = flag, *last; |
8a9036a4 | 881 | unsigned int i; |
ad9de929 | 882 | int value = 1; |
4d97c5c8 | 883 | bool is_isa = false; |
a5e91879 JB |
884 | bitfield all [ARRAY_SIZE (cpu_flags)]; |
885 | bitfield any [ARRAY_SIZE (cpu_flags)]; | |
40fb9820 L |
886 | |
887 | /* Copy the default cpu flags. */ | |
a5e91879 JB |
888 | memcpy (all, cpu_flags, sizeof (cpu_flags)); |
889 | memcpy (any, cpu_flags, sizeof (cpu_flags)); | |
40fb9820 | 890 | |
4d97c5c8 JB |
891 | if (flag == NULL) |
892 | { | |
893 | for (i = 0; i < ARRAY_SIZE (isa_reverse_deps[0]); ++i) | |
a5e91879 | 894 | any[i].value = isa_reverse_deps[reverse][i]; |
4d97c5c8 JB |
895 | goto output; |
896 | } | |
897 | ||
ad9de929 | 898 | if (flag[0] == '~') |
8a9036a4 L |
899 | { |
900 | last = flag + strlen (flag); | |
901 | ||
902 | if (flag[1] == '(') | |
903 | { | |
904 | last -= 1; | |
905 | next = flag + 2; | |
906 | if (*last != ')') | |
06ceca3a | 907 | fail ("%s: %d: missing `)' in bitfield: %s\n", filename, |
8a9036a4 L |
908 | lineno, flag); |
909 | *last = '\0'; | |
910 | } | |
911 | else | |
912 | next = flag + 1; | |
913 | ||
da5f9eb4 | 914 | /* First we turn on everything except for cpuno64 and - if |
13ed231a | 915 | present - the padding field. */ |
a5e91879 JB |
916 | for (i = 0; i < ARRAY_SIZE (any); i++) |
917 | if (any[i].position < CpuNo64) | |
918 | any[i].value = 1; | |
8a9036a4 L |
919 | |
920 | /* Turn off selective bits. */ | |
ad9de929 | 921 | value = 0; |
40fb9820 | 922 | } |
ad9de929 | 923 | |
4d97c5c8 JB |
924 | if (name != NULL && value != 0) |
925 | { | |
a5e91879 JB |
926 | for (i = 0; i < ARRAY_SIZE (any); i++) |
927 | if (strcasecmp (any[i].name, name) == 0) | |
4d97c5c8 | 928 | { |
a5e91879 | 929 | add_isa_dependencies (any, name, 1, reverse); |
4d97c5c8 JB |
930 | is_isa = true; |
931 | break; | |
932 | } | |
933 | } | |
934 | ||
ad9de929 | 935 | if (strcmp (flag, "0")) |
40fb9820 | 936 | { |
a5e91879 JB |
937 | bool combined = false; |
938 | ||
4d97c5c8 JB |
939 | if (is_isa) |
940 | return; | |
941 | ||
ad9de929 | 942 | /* Turn on/off selective bits. */ |
40fb9820 | 943 | last = flag + strlen (flag); |
a5e91879 JB |
944 | if (name == NULL && strchr (flag, '&')) |
945 | { | |
946 | for (; next < last && *next != '('; ) | |
947 | { | |
948 | str = next_field (next, '&', &next, last); | |
949 | set_bitfield (str, all, value, ARRAY_SIZE (all), lineno); | |
950 | } | |
951 | if (*next == '(') | |
952 | { | |
953 | if (*--last != ')') | |
954 | fail ("%s: %d: missing `)' in bitfield: %s\n", filename, | |
955 | lineno, flag); | |
956 | ++next; | |
957 | *last = '\0'; | |
958 | } | |
959 | combined = true; | |
960 | } | |
ad9de929 | 961 | for (; next && next < last; ) |
40fb9820 | 962 | { |
c587b3f9 | 963 | str = next_field (next, '|', &next, last); |
a5e91879 JB |
964 | if (name) |
965 | add_isa_dependencies (any, str, value, reverse); | |
966 | else if (combined || next < last) | |
967 | set_bitfield (str, any, value, ARRAY_SIZE (any), lineno); | |
968 | else /* Singular specifiers go into "all". */ | |
969 | set_bitfield (str, all, value, ARRAY_SIZE (all), lineno); | |
970 | combined = true; | |
40fb9820 L |
971 | } |
972 | } | |
973 | ||
4d97c5c8 JB |
974 | output: |
975 | if (name != NULL) | |
976 | { | |
977 | size_t len = strlen (name); | |
978 | char *upper = xmalloc (len + 1); | |
979 | ||
3e624fa4 JB |
980 | /* Cpu64 is special: It specifies a mode dependency, not an ISA one. Zap |
981 | the flag from ISA initializer macros (and from CPU_ANY_64_FLAGS | |
982 | itself we only care about tracking its dependents. Also don't emit the | |
983 | (otherwise all zero) CPU_64_FLAGS. */ | |
984 | if (flag != NULL && reverse == Cpu64) | |
985 | return; | |
986 | if (is_isa || flag == NULL) | |
a5e91879 | 987 | any[Cpu64].value = 0; |
3e624fa4 | 988 | |
4d97c5c8 JB |
989 | for (i = 0; i < len; ++i) |
990 | { | |
991 | /* Don't emit #define-s for auxiliary entries. */ | |
992 | if (name[i] == ':') | |
993 | return; | |
994 | upper[i] = TOUPPER (name[i]); | |
995 | } | |
996 | upper[i] = '\0'; | |
997 | fprintf (table, "\n#define CPU_%s%s_FLAGS \\\n", | |
998 | flag != NULL ? "": "ANY_", upper); | |
999 | free (upper); | |
1000 | } | |
3e624fa4 JB |
1001 | else |
1002 | { | |
1003 | /* Synthesize "64-bit mode only" dependencies from the dependencies we | |
1004 | have accumulated. */ | |
1005 | for (i = 0; i < ARRAY_SIZE (isa_reverse_deps[0]); ++i) | |
a5e91879 JB |
1006 | if (all[i].value && isa_reverse_deps[Cpu64][i]) |
1007 | all[Cpu64].value = 1; | |
1008 | ||
1009 | output_cpu_flags(table, all, ARRAY_SIZE (all), -1, comma, indent, lineno); | |
3e624fa4 | 1010 | } |
4d97c5c8 | 1011 | |
a5e91879 | 1012 | output_cpu_flags (table, any, ARRAY_SIZE (any), name != NULL, |
734dfd1c | 1013 | comma, indent, lineno); |
40fb9820 L |
1014 | } |
1015 | ||
1016 | static void | |
1017 | output_opcode_modifier (FILE *table, bitfield *modifier, unsigned int size) | |
1018 | { | |
1019 | unsigned int i; | |
1020 | ||
1021 | fprintf (table, " { "); | |
1022 | ||
1023 | for (i = 0; i < size - 1; i++) | |
1024 | { | |
10632b79 L |
1025 | if (((i + 1) % 20) != 0) |
1026 | fprintf (table, "%d, ", modifier[i].value); | |
1027 | else | |
1028 | fprintf (table, "%d,", modifier[i].value); | |
40fb9820 L |
1029 | if (((i + 1) % 20) == 0) |
1030 | fprintf (table, "\n "); | |
1031 | } | |
1032 | ||
1033 | fprintf (table, "%d },\n", modifier[i].value); | |
1034 | } | |
1035 | ||
73d214b2 | 1036 | /* Returns LOG2 of element size. */ |
4a1b91ea | 1037 | static int |
73d214b2 | 1038 | get_element_size (char **opnd, int lineno) |
4a1b91ea L |
1039 | { |
1040 | char *str, *next, *last, *op; | |
73d214b2 JB |
1041 | const char *full = opnd[0]; |
1042 | int elem_size = INT_MAX; | |
4a1b91ea | 1043 | |
73d214b2 JB |
1044 | /* Find the memory operand. */ |
1045 | while (full != NULL && strstr(full, "BaseIndex") == NULL) | |
1046 | full = *++opnd; | |
1047 | if (full == NULL) | |
06ceca3a | 1048 | fail ("%s: %d: no memory operand\n", filename, lineno); |
4a1b91ea | 1049 | |
73d214b2 | 1050 | op = xstrdup (full); |
4a1b91ea L |
1051 | last = op + strlen (op); |
1052 | for (next = op; next && next < last; ) | |
1053 | { | |
1054 | str = next_field (next, '|', &next, last); | |
1055 | if (str) | |
1056 | { | |
1057 | if (strcasecmp(str, "Byte") == 0) | |
1058 | { | |
73d214b2 | 1059 | /* The smallest element size, no need to check |
4a1b91ea | 1060 | further. */ |
73d214b2 | 1061 | elem_size = 0; |
4a1b91ea L |
1062 | break; |
1063 | } | |
1064 | else if (strcasecmp(str, "Word") == 0) | |
1065 | { | |
73d214b2 JB |
1066 | if (elem_size > 1) |
1067 | elem_size = 1; | |
4a1b91ea L |
1068 | } |
1069 | else if (strcasecmp(str, "Dword") == 0) | |
1070 | { | |
73d214b2 JB |
1071 | if (elem_size > 2) |
1072 | elem_size = 2; | |
4a1b91ea L |
1073 | } |
1074 | else if (strcasecmp(str, "Qword") == 0) | |
1075 | { | |
73d214b2 JB |
1076 | if (elem_size > 3) |
1077 | elem_size = 3; | |
4a1b91ea L |
1078 | } |
1079 | } | |
1080 | } | |
1081 | free (op); | |
1082 | ||
73d214b2 | 1083 | if (elem_size == INT_MAX) |
06ceca3a | 1084 | fail ("%s: %d: unknown element size: %s\n", filename, lineno, full); |
4a1b91ea | 1085 | |
73d214b2 | 1086 | return elem_size; |
4a1b91ea L |
1087 | } |
1088 | ||
80d61d8d CL |
1089 | static bool |
1090 | rex2_disallowed (const unsigned long long opcode, unsigned int length, | |
1091 | unsigned int space, const char *cpu_flags) | |
1092 | { | |
1093 | /* Some opcodes encode a ModR/M-like byte directly in the opcode. */ | |
1094 | unsigned int base_opcode = opcode >> (8 * length - 8); | |
1095 | ||
1096 | /* All opcodes listed map0 0x4*, 0x7*, 0xa*, 0xe* and map1 0x3*, 0x8* | |
1097 | are reserved under REX2 and triggers #UD when prefixed with REX2 */ | |
1098 | if (space == 0) | |
1099 | switch (base_opcode >> 4) | |
1100 | { | |
1101 | case 0x4: | |
1102 | case 0x7: | |
1103 | case 0xA: | |
1104 | case 0xE: | |
1105 | return true; | |
1106 | default: | |
1107 | return false; | |
1108 | } | |
1109 | ||
1110 | if (space == SPACE_0F) | |
1111 | switch (base_opcode >> 4) | |
1112 | { | |
1113 | case 0x3: | |
1114 | case 0x8: | |
1115 | return true; | |
1116 | default: | |
1117 | return false; | |
1118 | } | |
1119 | ||
1120 | return false; | |
1121 | } | |
1122 | ||
35648716 | 1123 | static void |
389d00a5 | 1124 | process_i386_opcode_modifier (FILE *table, char *mod, unsigned int space, |
ddb62495 | 1125 | unsigned int prefix, const char *extension_opcode, |
80d61d8d | 1126 | char **opnd, int lineno, bool rex2_disallowed) |
40fb9820 L |
1127 | { |
1128 | char *str, *next, *last; | |
d125c4bb | 1129 | bool disp8_shift_derived = false; |
40fb9820 | 1130 | bitfield modifiers [ARRAY_SIZE (opcode_modifiers)]; |
ddb62495 JB |
1131 | static const char *const spaces[] = { |
1132 | #define SPACE(n) [SPACE_##n] = #n | |
1133 | SPACE(BASE), | |
1134 | SPACE(0F), | |
1135 | SPACE(0F38), | |
1136 | SPACE(0F3A), | |
6177c84d | 1137 | SPACE(EVEXMAP4), |
ddb62495 JB |
1138 | SPACE(EVEXMAP5), |
1139 | SPACE(EVEXMAP6), | |
8170af78 | 1140 | SPACE(VEXMAP7), |
ddb62495 JB |
1141 | SPACE(XOP08), |
1142 | SPACE(XOP09), | |
1143 | SPACE(XOP0A), | |
1144 | #undef SPACE | |
1145 | }; | |
40fb9820 | 1146 | |
7ac20022 JB |
1147 | active_isstring = 0; |
1148 | ||
40fb9820 L |
1149 | /* Copy the default opcode modifier. */ |
1150 | memcpy (modifiers, opcode_modifiers, sizeof (modifiers)); | |
1151 | ||
1152 | if (strcmp (mod, "0")) | |
1153 | { | |
507916b8 JB |
1154 | unsigned int have_w = 0, bwlq_suf = 0xf; |
1155 | ||
40fb9820 L |
1156 | last = mod + strlen (mod); |
1157 | for (next = mod; next && next < last; ) | |
1158 | { | |
c587b3f9 | 1159 | str = next_field (next, '|', &next, last); |
40fb9820 | 1160 | if (str) |
7ac20022 | 1161 | { |
4a1b91ea | 1162 | int val = 1; |
ddb62495 JB |
1163 | |
1164 | if (strncmp(str, "OpcodeSpace", 11) == 0) | |
1165 | { | |
1166 | char *end; | |
1167 | ||
1168 | if (str[11] != '=') | |
1169 | fail ("%s:%d: Missing value for `OpcodeSpace'\n", | |
1170 | filename, lineno); | |
1171 | ||
1172 | val = strtol (str + 12, &end, 0); | |
1173 | if (*end) | |
1174 | fail ("%s:%d: Bogus value `%s' for `OpcodeSpace'\n", | |
1175 | filename, lineno, end); | |
1176 | ||
1177 | if (space) | |
1178 | { | |
1179 | if (val != space) | |
1180 | fail ("%s:%d: Conflicting opcode space specifications\n", | |
1181 | filename, lineno); | |
1182 | fprintf (stderr, | |
1183 | "%s:%d: Warning: redundant opcode space specification\n", | |
1184 | filename, lineno); | |
1185 | } | |
1186 | ||
1187 | space = val; | |
1188 | continue; | |
1189 | } | |
1190 | ||
4a1b91ea | 1191 | if (strcasecmp(str, "Broadcast") == 0) |
73d214b2 JB |
1192 | val = get_element_size (opnd, lineno) + BYTE_BROADCAST; |
1193 | else if (strcasecmp(str, "Disp8MemShift") == 0) | |
d125c4bb JB |
1194 | { |
1195 | val = get_element_size (opnd, lineno); | |
1196 | disp8_shift_derived = true; | |
1197 | } | |
8b65b895 | 1198 | |
4a1b91ea | 1199 | set_bitfield (str, modifiers, val, ARRAY_SIZE (modifiers), |
8b65b895 | 1200 | lineno); |
7ac20022 JB |
1201 | if (strcasecmp(str, "IsString") == 0) |
1202 | active_isstring = 1; | |
507916b8 JB |
1203 | |
1204 | if (strcasecmp(str, "W") == 0) | |
1205 | have_w = 1; | |
1206 | ||
1207 | if (strcasecmp(str, "No_bSuf") == 0) | |
1208 | bwlq_suf &= ~1; | |
1209 | if (strcasecmp(str, "No_wSuf") == 0) | |
1210 | bwlq_suf &= ~2; | |
1211 | if (strcasecmp(str, "No_lSuf") == 0) | |
1212 | bwlq_suf &= ~4; | |
1213 | if (strcasecmp(str, "No_qSuf") == 0) | |
1214 | bwlq_suf &= ~8; | |
7ac20022 | 1215 | } |
40fb9820 | 1216 | } |
507916b8 | 1217 | |
35648716 JB |
1218 | if (prefix) |
1219 | { | |
1220 | if (!modifiers[OpcodePrefix].value) | |
1221 | modifiers[OpcodePrefix].value = prefix; | |
1222 | else if (modifiers[OpcodePrefix].value != prefix) | |
06ceca3a | 1223 | fail ("%s:%d: Conflicting prefix specifications\n", |
35648716 JB |
1224 | filename, lineno); |
1225 | else | |
1226 | fprintf (stderr, | |
06ceca3a | 1227 | "%s:%d: Warning: redundant prefix specification\n", |
35648716 JB |
1228 | filename, lineno); |
1229 | } | |
1230 | ||
507916b8 JB |
1231 | if (have_w && !bwlq_suf) |
1232 | fail ("%s: %d: stray W modifier\n", filename, lineno); | |
1233 | if (have_w && !(bwlq_suf & 1)) | |
1234 | fprintf (stderr, "%s: %d: W modifier without Byte operand(s)\n", | |
1235 | filename, lineno); | |
1236 | if (have_w && !(bwlq_suf & ~1)) | |
1237 | fprintf (stderr, | |
1238 | "%s: %d: W modifier without Word/Dword/Qword operand(s)\n", | |
1239 | filename, lineno); | |
40fb9820 | 1240 | } |
ddb62495 JB |
1241 | |
1242 | if (space >= ARRAY_SIZE (spaces) || !spaces[space]) | |
1243 | fail ("%s:%d: Unknown opcode space %u\n", filename, lineno, space); | |
1244 | ||
1245 | fprintf (table, " SPACE_%s, %s,\n", | |
1246 | spaces[space], extension_opcode ? extension_opcode : "None"); | |
1247 | ||
706ce984 JB |
1248 | /* Rather than evaluating multiple conditions at runtime to determine |
1249 | whether an EVEX encoding is being dealt with, derive that information | |
d125c4bb JB |
1250 | right here. A missing EVex attribute means "dynamic". There's one |
1251 | exception though: A value-less Disp8MemShift needs zapping rather than | |
1252 | respecting if no other attribute indicates EVEX encoding. This is for | |
1253 | certain SSE2AVX templatized templates to work reasonably. */ | |
1254 | if (!modifiers[EVex].value) | |
1255 | { | |
1256 | if (modifiers[Broadcast].value | |
706ce984 | 1257 | || modifiers[Masking].value |
d125c4bb JB |
1258 | || modifiers[SAE].value) |
1259 | modifiers[EVex].value = EVEXDYN; | |
1260 | else if (disp8_shift_derived) | |
1261 | modifiers[Disp8MemShift].value = 0; | |
1262 | else if (modifiers[Disp8MemShift].value) | |
1263 | modifiers[EVex].value = EVEXDYN; | |
1264 | } | |
706ce984 | 1265 | |
80d61d8d CL |
1266 | /* Vex, legacy map2 and map3 and rex2_disallowed do not support EGPR. |
1267 | For templates supporting both Vex and EVex allowing EGPR. */ | |
1268 | if ((modifiers[Vex].value || space > SPACE_0F || rex2_disallowed) | |
1269 | && !modifiers[EVex].value) | |
1270 | modifiers[NoEgpr].value = 1; | |
1271 | ||
40fb9820 L |
1272 | output_opcode_modifier (table, modifiers, ARRAY_SIZE (modifiers)); |
1273 | } | |
1274 | ||
7ac20022 JB |
1275 | enum stage { |
1276 | stage_macros, | |
1277 | stage_opcodes, | |
1278 | stage_registers, | |
1279 | }; | |
1280 | ||
40fb9820 | 1281 | static void |
bab6aec1 | 1282 | output_operand_type (FILE *table, enum operand_class class, |
75e5731b | 1283 | enum operand_instance instance, |
bab6aec1 | 1284 | const bitfield *types, unsigned int size, |
7ac20022 | 1285 | enum stage stage, const char *indent) |
40fb9820 L |
1286 | { |
1287 | unsigned int i; | |
1288 | ||
75e5731b | 1289 | fprintf (table, "{ { %d, %d, ", class, instance); |
40fb9820 L |
1290 | |
1291 | for (i = 0; i < size - 1; i++) | |
1292 | { | |
75e5731b | 1293 | if (((i + 3) % 20) != 0) |
10632b79 L |
1294 | fprintf (table, "%d, ", types[i].value); |
1295 | else | |
1296 | fprintf (table, "%d,", types[i].value); | |
75e5731b | 1297 | if (((i + 3) % 20) == 0) |
40fb9820 L |
1298 | { |
1299 | /* We need \\ for macro. */ | |
7ac20022 | 1300 | if (stage == stage_macros) |
10632b79 | 1301 | fprintf (table, " \\\n%s", indent); |
40fb9820 L |
1302 | else |
1303 | fprintf (table, "\n%s", indent); | |
1304 | } | |
1305 | } | |
1306 | ||
1307 | fprintf (table, "%d } }", types[i].value); | |
1308 | } | |
1309 | ||
1310 | static void | |
7ac20022 | 1311 | process_i386_operand_type (FILE *table, char *op, enum stage stage, |
bd5295b2 | 1312 | const char *indent, int lineno) |
40fb9820 L |
1313 | { |
1314 | char *str, *next, *last; | |
bab6aec1 | 1315 | enum operand_class class = ClassNone; |
75e5731b | 1316 | enum operand_instance instance = InstanceNone; |
40fb9820 L |
1317 | bitfield types [ARRAY_SIZE (operand_types)]; |
1318 | ||
1319 | /* Copy the default operand type. */ | |
1320 | memcpy (types, operand_types, sizeof (types)); | |
1321 | ||
1322 | if (strcmp (op, "0")) | |
1323 | { | |
7ac20022 JB |
1324 | int baseindex = 0; |
1325 | ||
40fb9820 L |
1326 | last = op + strlen (op); |
1327 | for (next = op; next && next < last; ) | |
1328 | { | |
c587b3f9 | 1329 | str = next_field (next, '|', &next, last); |
bab6aec1 JB |
1330 | if (str) |
1331 | { | |
1332 | unsigned int i; | |
1333 | ||
1334 | if (!strncmp(str, "Class=", 6)) | |
1335 | { | |
1336 | for (i = 0; i < ARRAY_SIZE(operand_classes); ++i) | |
1337 | if (!strcmp(str + 6, operand_classes[i].name)) | |
1338 | { | |
1339 | class = operand_classes[i].value; | |
1340 | str = NULL; | |
1341 | break; | |
1342 | } | |
1343 | } | |
75e5731b JB |
1344 | |
1345 | if (str && !strncmp(str, "Instance=", 9)) | |
1346 | { | |
1347 | for (i = 0; i < ARRAY_SIZE(operand_instances); ++i) | |
1348 | if (!strcmp(str + 9, operand_instances[i].name)) | |
1349 | { | |
1350 | instance = operand_instances[i].value; | |
1351 | str = NULL; | |
1352 | break; | |
1353 | } | |
1354 | } | |
bab6aec1 | 1355 | } |
40fb9820 | 1356 | if (str) |
7ac20022 JB |
1357 | { |
1358 | set_bitfield (str, types, 1, ARRAY_SIZE (types), lineno); | |
1359 | if (strcasecmp(str, "BaseIndex") == 0) | |
1360 | baseindex = 1; | |
1361 | } | |
1362 | } | |
1363 | ||
1364 | if (stage == stage_opcodes && baseindex && !active_isstring) | |
1365 | { | |
1366 | set_bitfield("Disp8", types, 1, ARRAY_SIZE (types), lineno); | |
1367 | if (!active_cpu_flags.bitfield.cpu64 | |
1368 | && !active_cpu_flags.bitfield.cpumpx) | |
1369 | set_bitfield("Disp16", types, 1, ARRAY_SIZE (types), lineno); | |
a775efc8 | 1370 | set_bitfield("Disp32", types, 1, ARRAY_SIZE (types), lineno); |
40fb9820 L |
1371 | } |
1372 | } | |
75e5731b JB |
1373 | output_operand_type (table, class, instance, types, ARRAY_SIZE (types), |
1374 | stage, indent); | |
40fb9820 L |
1375 | } |
1376 | ||
5c139202 JB |
1377 | static char *mkident (const char *mnem) |
1378 | { | |
1379 | char *ident = xstrdup (mnem), *p = ident; | |
1380 | ||
1381 | do | |
1382 | { | |
1383 | if (!ISALNUM (*p)) | |
1384 | *p = '_'; | |
1385 | } | |
1386 | while (*++p); | |
1387 | ||
1388 | return ident; | |
1389 | } | |
1390 | ||
c587b3f9 L |
1391 | static void |
1392 | output_i386_opcode (FILE *table, const char *name, char *str, | |
bd5295b2 | 1393 | char *last, int lineno) |
c587b3f9 | 1394 | { |
389d00a5 | 1395 | unsigned int i, length, prefix = 0, space = 0; |
5c139202 | 1396 | char *base_opcode, *extension_opcode, *end, *ident; |
c587b3f9 | 1397 | char *cpu_flags, *opcode_modifier, *operand_types [MAX_OPERANDS]; |
73e45eb2 | 1398 | unsigned long long opcode; |
c587b3f9 | 1399 | |
c587b3f9 L |
1400 | /* Find base_opcode. */ |
1401 | base_opcode = next_field (str, ',', &str, last); | |
1402 | ||
68993386 JB |
1403 | /* Find extension_opcode, if any. */ |
1404 | extension_opcode = strchr (base_opcode, '/'); | |
1405 | if (extension_opcode) | |
1406 | *extension_opcode++ = '\0'; | |
c587b3f9 | 1407 | |
c587b3f9 L |
1408 | /* Find cpu_flags. */ |
1409 | cpu_flags = next_field (str, ',', &str, last); | |
1410 | ||
1411 | /* Find opcode_modifier. */ | |
1412 | opcode_modifier = next_field (str, ',', &str, last); | |
1413 | ||
1414 | /* Remove the first {. */ | |
1415 | str = remove_leading_whitespaces (str); | |
1416 | if (*str != '{') | |
1417 | abort (); | |
1418 | str = remove_leading_whitespaces (str + 1); | |
75363b6d | 1419 | remove_trailing_whitespaces (str); |
c587b3f9 | 1420 | |
75363b6d | 1421 | /* Remove } and trailing white space. */ |
c587b3f9 | 1422 | i = strlen (str); |
75363b6d | 1423 | if (!i || str[i - 1] != '}') |
c587b3f9 | 1424 | abort (); |
75363b6d JB |
1425 | str[--i] = '\0'; |
1426 | remove_trailing_whitespaces (str); | |
c587b3f9 | 1427 | |
75363b6d JB |
1428 | if (!*str) |
1429 | operand_types [i = 0] = NULL; | |
1430 | else | |
c587b3f9 | 1431 | { |
75363b6d | 1432 | last = str + strlen (str); |
c587b3f9 | 1433 | |
75363b6d JB |
1434 | /* Find operand_types. */ |
1435 | for (i = 0; i < ARRAY_SIZE (operand_types); i++) | |
c587b3f9 | 1436 | { |
75363b6d JB |
1437 | if (str >= last) |
1438 | { | |
1439 | operand_types [i] = NULL; | |
1440 | break; | |
1441 | } | |
c587b3f9 | 1442 | |
75363b6d | 1443 | operand_types [i] = next_field (str, ',', &str, last); |
c587b3f9 L |
1444 | } |
1445 | } | |
1446 | ||
73e45eb2 | 1447 | opcode = strtoull (base_opcode, &end, 0); |
c587b3f9 | 1448 | |
9a182d04 | 1449 | /* Determine opcode length. */ |
73e45eb2 | 1450 | for (length = 1; length < 8; ++length) |
9a182d04 JB |
1451 | if (!(opcode >> (8 * length))) |
1452 | break; | |
1453 | ||
35648716 JB |
1454 | /* Transform prefixes encoded in the opcode into opcode modifier |
1455 | representation. */ | |
9a182d04 | 1456 | if (length > 1) |
8b65b895 | 1457 | { |
9a182d04 | 1458 | switch (opcode >> (8 * length - 8)) |
8b65b895 | 1459 | { |
35648716 JB |
1460 | case 0x66: prefix = PREFIX_0X66; break; |
1461 | case 0xF3: prefix = PREFIX_0XF3; break; | |
1462 | case 0xF2: prefix = PREFIX_0XF2; break; | |
8b65b895 | 1463 | } |
35648716 | 1464 | |
9a182d04 | 1465 | if (prefix) |
73e45eb2 | 1466 | opcode &= (1ULL << (8 * --length)) - 1; |
8b65b895 | 1467 | } |
c587b3f9 | 1468 | |
389d00a5 JB |
1469 | /* Transform opcode space encoded in the opcode into opcode modifier |
1470 | representation. */ | |
1471 | if (length > 1 && (opcode >> (8 * length - 8)) == 0xf) | |
1472 | { | |
1473 | switch ((opcode >> (8 * length - 16)) & 0xff) | |
1474 | { | |
1475 | default: space = SPACE_0F; break; | |
1476 | case 0x38: space = SPACE_0F38; break; | |
1477 | case 0x3A: space = SPACE_0F3A; break; | |
1478 | } | |
1479 | ||
1480 | if (space != SPACE_0F && --length == 1) | |
06ceca3a | 1481 | fail ("%s:%d: %s: unrecognized opcode encoding space\n", |
389d00a5 | 1482 | filename, lineno, name); |
73e45eb2 | 1483 | opcode &= (1ULL << (8 * --length)) - 1; |
389d00a5 JB |
1484 | } |
1485 | ||
73e45eb2 | 1486 | if (length > 2) |
06ceca3a | 1487 | fail ("%s:%d: %s: residual opcode (0x%0*llx) too large\n", |
73e45eb2 JB |
1488 | filename, lineno, name, 2 * length, opcode); |
1489 | ||
5c139202 | 1490 | ident = mkident (name); |
ddb62495 JB |
1491 | fprintf (table, " { MN_%s, 0x%0*llx%s, %u,", |
1492 | ident, 2 * (int)length, opcode, end, i); | |
5c139202 | 1493 | free (ident); |
35648716 | 1494 | |
389d00a5 | 1495 | process_i386_opcode_modifier (table, opcode_modifier, space, prefix, |
80d61d8d CL |
1496 | extension_opcode, operand_types, lineno, |
1497 | rex2_disallowed (opcode, length, space, | |
1498 | cpu_flags)); | |
35648716 | 1499 | |
4d97c5c8 | 1500 | process_i386_cpu_flag (table, cpu_flags, NULL, ",", " ", lineno, CpuMax); |
dac10fb0 | 1501 | |
c587b3f9 L |
1502 | fprintf (table, " { "); |
1503 | ||
1504 | for (i = 0; i < ARRAY_SIZE (operand_types); i++) | |
1505 | { | |
75363b6d | 1506 | if (!operand_types[i]) |
c587b3f9 L |
1507 | { |
1508 | if (i == 0) | |
7ac20022 JB |
1509 | process_i386_operand_type (table, "0", stage_opcodes, "\t ", |
1510 | lineno); | |
c587b3f9 L |
1511 | break; |
1512 | } | |
1513 | ||
1514 | if (i != 0) | |
1515 | fprintf (table, ",\n "); | |
1516 | ||
7ac20022 | 1517 | process_i386_operand_type (table, operand_types[i], stage_opcodes, |
bd5295b2 | 1518 | "\t ", lineno); |
c587b3f9 L |
1519 | } |
1520 | fprintf (table, " } },\n"); | |
1521 | } | |
1522 | ||
1523 | struct opcode_hash_entry | |
1524 | { | |
a2e2f5ad JB |
1525 | const char *name; |
1526 | struct opcode_entry | |
1527 | { | |
1528 | struct opcode_entry *next; | |
1529 | char *opcode; | |
1530 | int lineno; | |
1531 | } entry; | |
c587b3f9 L |
1532 | }; |
1533 | ||
1534 | /* Calculate the hash value of an opcode hash entry P. */ | |
1535 | ||
1536 | static hashval_t | |
1537 | opcode_hash_hash (const void *p) | |
1538 | { | |
1539 | struct opcode_hash_entry *entry = (struct opcode_hash_entry *) p; | |
1540 | return htab_hash_string (entry->name); | |
1541 | } | |
1542 | ||
1543 | /* Compare a string Q against an opcode hash entry P. */ | |
1544 | ||
1545 | static int | |
1546 | opcode_hash_eq (const void *p, const void *q) | |
1547 | { | |
1548 | struct opcode_hash_entry *entry = (struct opcode_hash_entry *) p; | |
1549 | const char *name = (const char *) q; | |
1550 | return strcmp (name, entry->name) == 0; | |
1551 | } | |
1552 | ||
cd9ca24d | 1553 | static bool |
4c4898e8 JB |
1554 | parse_template (char *buf, int lineno) |
1555 | { | |
cd9ca24d | 1556 | char sep, *end, *ptr; |
e07ae9a3 | 1557 | struct template *tmpl; |
4c4898e8 JB |
1558 | struct template_instance *last_inst = NULL; |
1559 | ||
1560 | buf = remove_leading_whitespaces (buf + 1); | |
1561 | end = strchr (buf, ':'); | |
1562 | if (end == NULL) | |
e07ae9a3 JB |
1563 | { |
1564 | struct template *prev = NULL; | |
1565 | ||
1566 | end = strchr (buf, '>'); | |
1567 | if (end == NULL) | |
1568 | fail ("%s: %d: missing ':' or '>'\n", filename, lineno); | |
1569 | if (*remove_leading_whitespaces (end + 1)) | |
1570 | fail ("%s: %d: malformed template purge\n", filename, lineno); | |
1571 | *end = '\0'; | |
1572 | remove_trailing_whitespaces (buf); | |
1573 | /* Don't bother freeing the various structures. */ | |
1574 | for (tmpl = templates; tmpl != NULL; tmpl = (prev = tmpl)->next) | |
1575 | if (!strcmp (buf, tmpl->name)) | |
1576 | break; | |
1577 | if (tmpl == NULL) | |
1578 | fail ("%s: %d: no template '%s'\n", filename, lineno, buf); | |
1579 | if (prev) | |
1580 | prev->next = tmpl->next; | |
1581 | else | |
1582 | templates = tmpl->next; | |
cd9ca24d | 1583 | return true; |
e07ae9a3 | 1584 | } |
cd9ca24d JB |
1585 | |
1586 | /* Check whether this actually is a reference to an existing template: | |
1587 | If there's '>' ahead of ':', it can't be a new template definition | |
1588 | (and template undefs have are dealt with above). */ | |
1589 | ptr = strchr (buf, '>'); | |
1590 | if (ptr != NULL && ptr < end) | |
1591 | return false; | |
1592 | ||
4c4898e8 JB |
1593 | *end++ = '\0'; |
1594 | remove_trailing_whitespaces (buf); | |
1595 | ||
1596 | if (*buf == '\0') | |
1597 | fail ("%s: %d: missing template identifier\n", filename, lineno); | |
e07ae9a3 | 1598 | tmpl = xmalloc (sizeof (*tmpl)); |
4c4898e8 JB |
1599 | tmpl->name = xstrdup (buf); |
1600 | ||
1601 | tmpl->params = NULL; | |
1602 | do { | |
1603 | struct template_param *param; | |
1604 | ||
1605 | buf = remove_leading_whitespaces (end); | |
1606 | end = strpbrk (buf, ":,"); | |
1607 | if (end == NULL) | |
1608 | fail ("%s: %d: missing ':' or ','\n", filename, lineno); | |
1609 | ||
1610 | sep = *end; | |
1611 | *end++ = '\0'; | |
1612 | remove_trailing_whitespaces (buf); | |
1613 | ||
1614 | param = xmalloc (sizeof (*param)); | |
1615 | param->name = xstrdup (buf); | |
1616 | param->next = tmpl->params; | |
1617 | tmpl->params = param; | |
1618 | } while (sep == ':'); | |
1619 | ||
1620 | tmpl->instances = NULL; | |
1621 | do { | |
1622 | struct template_instance *inst; | |
1623 | char *cur, *next; | |
1624 | const struct template_param *param; | |
1625 | ||
1626 | buf = remove_leading_whitespaces (end); | |
1627 | end = strpbrk (buf, ",>"); | |
1628 | if (end == NULL) | |
1629 | fail ("%s: %d: missing ',' or '>'\n", filename, lineno); | |
1630 | ||
1631 | sep = *end; | |
1632 | *end++ = '\0'; | |
1633 | ||
1634 | inst = xmalloc (sizeof (*inst)); | |
c3ffb8f3 AM |
1635 | inst->next = NULL; |
1636 | inst->args = NULL; | |
4c4898e8 JB |
1637 | |
1638 | cur = next_field (buf, ':', &next, end); | |
5cdaf100 | 1639 | inst->name = *cur != '$' ? xstrdup (cur) : ""; |
4c4898e8 JB |
1640 | |
1641 | for (param = tmpl->params; param; param = param->next) | |
1642 | { | |
1643 | struct template_arg *arg = xmalloc (sizeof (*arg)); | |
1644 | ||
1645 | cur = next_field (next, ':', &next, end); | |
1646 | if (next > end) | |
1647 | fail ("%s: %d: missing argument for '%s'\n", filename, lineno, param->name); | |
1648 | arg->val = xstrdup (cur); | |
1649 | arg->next = inst->args; | |
1650 | inst->args = arg; | |
1651 | } | |
1652 | ||
1653 | if (tmpl->instances) | |
1654 | last_inst->next = inst; | |
1655 | else | |
1656 | tmpl->instances = inst; | |
1657 | last_inst = inst; | |
1658 | } while (sep == ','); | |
1659 | ||
1660 | buf = remove_leading_whitespaces (end); | |
1661 | if (*buf) | |
1662 | fprintf(stderr, "%s: %d: excess characters '%s'\n", | |
1663 | filename, lineno, buf); | |
1664 | ||
1665 | tmpl->next = templates; | |
1666 | templates = tmpl; | |
cd9ca24d JB |
1667 | |
1668 | return true; | |
4c4898e8 JB |
1669 | } |
1670 | ||
1671 | static unsigned int | |
1672 | expand_templates (char *name, const char *str, htab_t opcode_hash_table, | |
1673 | struct opcode_hash_entry ***opcode_array_p, int lineno) | |
1674 | { | |
1675 | static unsigned int idx, opcode_array_size; | |
1676 | struct opcode_hash_entry **opcode_array = *opcode_array_p; | |
a2e2f5ad JB |
1677 | struct opcode_hash_entry **hash_slot; |
1678 | struct opcode_entry *entry; | |
4c4898e8 JB |
1679 | char *ptr1 = strchr(name, '<'), *ptr2; |
1680 | ||
1681 | if (ptr1 == NULL) | |
1682 | { | |
1683 | /* Get the slot in hash table. */ | |
1684 | hash_slot = (struct opcode_hash_entry **) | |
1685 | htab_find_slot_with_hash (opcode_hash_table, name, | |
1686 | htab_hash_string (name), | |
1687 | INSERT); | |
1688 | ||
1689 | if (*hash_slot == NULL) | |
1690 | { | |
1691 | /* It is the new one. Put it on opcode array. */ | |
1692 | if (idx >= opcode_array_size) | |
1693 | { | |
1694 | /* Grow the opcode array when needed. */ | |
1695 | opcode_array_size += 1024; | |
1696 | opcode_array = (struct opcode_hash_entry **) | |
1697 | xrealloc (opcode_array, | |
1698 | sizeof (*opcode_array) * opcode_array_size); | |
1699 | *opcode_array_p = opcode_array; | |
1700 | } | |
1701 | ||
1702 | opcode_array[idx] = (struct opcode_hash_entry *) | |
1703 | xmalloc (sizeof (struct opcode_hash_entry)); | |
4c4898e8 | 1704 | opcode_array[idx]->name = xstrdup (name); |
4c4898e8 | 1705 | *hash_slot = opcode_array[idx]; |
a2e2f5ad | 1706 | entry = &opcode_array[idx]->entry; |
4c4898e8 JB |
1707 | idx++; |
1708 | } | |
1709 | else | |
1710 | { | |
1711 | /* Append it to the existing one. */ | |
a2e2f5ad JB |
1712 | struct opcode_entry **entryp = &(*hash_slot)->entry.next; |
1713 | ||
1714 | while (*entryp != NULL) | |
1715 | entryp = &(*entryp)->next; | |
1716 | entry = (struct opcode_entry *)xmalloc (sizeof (struct opcode_entry)); | |
1717 | *entryp = entry; | |
4c4898e8 | 1718 | } |
a2e2f5ad JB |
1719 | |
1720 | entry->next = NULL; | |
1721 | entry->opcode = xstrdup (str); | |
1722 | entry->lineno = lineno; | |
4c4898e8 JB |
1723 | } |
1724 | else if ((ptr2 = strchr(ptr1 + 1, '>')) == NULL) | |
1725 | fail ("%s: %d: missing '>'\n", filename, lineno); | |
1726 | else | |
1727 | { | |
1728 | const struct template *tmpl; | |
1729 | const struct template_instance *inst; | |
1730 | ||
1731 | *ptr1 = '\0'; | |
1732 | ptr1 = remove_leading_whitespaces (ptr1 + 1); | |
1733 | remove_trailing_whitespaces (ptr1); | |
1734 | ||
1735 | *ptr2++ = '\0'; | |
1736 | ||
1737 | for ( tmpl = templates; tmpl; tmpl = tmpl->next ) | |
1738 | if (!strcmp(ptr1, tmpl->name)) | |
1739 | break; | |
1740 | if (!tmpl) | |
1741 | fail ("reference to unknown template '%s'\n", ptr1); | |
1742 | ||
1743 | for (inst = tmpl->instances; inst; inst = inst->next) | |
1744 | { | |
1745 | char *name2 = xmalloc(strlen(name) + strlen(inst->name) + strlen(ptr2) + 1); | |
1746 | char *str2 = xmalloc(2 * strlen(str)); | |
1747 | const char *src; | |
1748 | ||
1749 | strcpy (name2, name); | |
1750 | strcat (name2, inst->name); | |
1751 | strcat (name2, ptr2); | |
1752 | ||
1753 | for (ptr1 = str2, src = str; *src; ) | |
1754 | { | |
1755 | const char *ident = tmpl->name, *end; | |
1756 | const struct template_param *param; | |
1757 | const struct template_arg *arg; | |
1758 | ||
1759 | if ((*ptr1 = *src++) != '<') | |
1760 | { | |
1761 | ++ptr1; | |
1762 | continue; | |
1763 | } | |
1764 | while (ISSPACE(*src)) | |
1765 | ++src; | |
1766 | while (*ident && *src == *ident) | |
1767 | ++src, ++ident; | |
1768 | while (ISSPACE(*src)) | |
1769 | ++src; | |
1770 | if (*src != ':' || *ident != '\0') | |
1771 | { | |
1772 | memcpy (++ptr1, tmpl->name, ident - tmpl->name); | |
1773 | ptr1 += ident - tmpl->name; | |
1774 | continue; | |
1775 | } | |
1776 | while (ISSPACE(*++src)) | |
1777 | ; | |
1778 | ||
1779 | end = src; | |
1780 | while (*end != '\0' && !ISSPACE(*end) && *end != '>') | |
1781 | ++end; | |
1782 | ||
1783 | for (param = tmpl->params, arg = inst->args; param; | |
1784 | param = param->next, arg = arg->next) | |
1785 | { | |
1786 | if (end - src == strlen (param->name) | |
1787 | && !memcmp (src, param->name, end - src)) | |
1788 | { | |
1789 | src = end; | |
1790 | break; | |
1791 | } | |
1792 | } | |
1793 | ||
1794 | if (param == NULL) | |
1795 | fail ("template '%s' has no parameter '%.*s'\n", | |
1796 | tmpl->name, (int)(end - src), src); | |
1797 | ||
1798 | while (ISSPACE(*src)) | |
1799 | ++src; | |
1800 | if (*src != '>') | |
1801 | fail ("%s: %d: missing '>'\n", filename, lineno); | |
1802 | ||
1803 | memcpy(ptr1, arg->val, strlen(arg->val)); | |
1804 | ptr1 += strlen(arg->val); | |
1805 | ++src; | |
1806 | } | |
1807 | ||
1808 | *ptr1 = '\0'; | |
1809 | ||
1810 | expand_templates (name2, str2, opcode_hash_table, opcode_array_p, | |
1811 | lineno); | |
1812 | ||
1813 | free (str2); | |
1814 | free (name2); | |
1815 | } | |
1816 | } | |
1817 | ||
1818 | return idx; | |
1819 | } | |
1820 | ||
3e451ee4 JB |
1821 | static int mnemonic_cmp(const void *p1, const void *p2) |
1822 | { | |
1823 | const struct opcode_hash_entry *const *e1 = p1, *const *e2 = p2; | |
1824 | const char *s1 = (*e1)->name, *s2 = (*e2)->name; | |
1825 | unsigned int i; | |
1826 | size_t l1 = strlen (s1), l2 = strlen (s2); | |
1827 | ||
1828 | for (i = 1; i <= l1 && i <= l2; ++i) | |
1829 | { | |
1830 | if (s1[l1 - i] != s2[l2 - i]) | |
1831 | return (unsigned char)s1[l1 - i] - (unsigned char)s2[l2 - i]; | |
1832 | } | |
1833 | ||
1834 | return (int)(l1 - l2); | |
1835 | } | |
1836 | ||
40b8e679 | 1837 | static void |
72ffa0fb | 1838 | process_i386_opcodes (FILE *table) |
40b8e679 | 1839 | { |
3d4d5afa | 1840 | FILE *fp; |
40b8e679 | 1841 | char buf[2048]; |
5c139202 | 1842 | unsigned int i, j, nr, offs; |
3e451ee4 | 1843 | size_t l; |
a2e2f5ad | 1844 | char *str, *p, *last; |
c587b3f9 | 1845 | htab_t opcode_hash_table; |
4c4898e8 | 1846 | struct opcode_hash_entry **opcode_array = NULL; |
c30be56e | 1847 | int lineno = 0, marker = 0; |
40b8e679 | 1848 | |
3d4d5afa | 1849 | filename = "i386-opc.tbl"; |
c30be56e | 1850 | fp = stdin; |
40b8e679 | 1851 | |
c587b3f9 | 1852 | i = 0; |
c587b3f9 L |
1853 | opcode_hash_table = htab_create_alloc (16, opcode_hash_hash, |
1854 | opcode_hash_eq, NULL, | |
1855 | xcalloc, free); | |
1856 | ||
5c139202 | 1857 | fprintf (table, "\n#include \"i386-mnem.h\"\n"); |
34edb9ad | 1858 | fprintf (table, "\n/* i386 opcode table. */\n\n"); |
99f0fb12 | 1859 | fprintf (table, "static const insn_template i386_optab[] =\n{\n"); |
40b8e679 | 1860 | |
c587b3f9 | 1861 | /* Put everything on opcode array. */ |
40b8e679 L |
1862 | while (!feof (fp)) |
1863 | { | |
a2e2f5ad JB |
1864 | char *name; |
1865 | ||
40b8e679 L |
1866 | if (fgets (buf, sizeof (buf), fp) == NULL) |
1867 | break; | |
1868 | ||
1869 | p = remove_leading_whitespaces (buf); | |
1870 | ||
33b6a20a JB |
1871 | for ( ; ; ) |
1872 | { | |
1873 | lineno++; | |
1874 | ||
1875 | /* Skip comments. */ | |
1876 | str = strstr (p, "//"); | |
1877 | if (str != NULL) | |
1878 | { | |
1879 | str[0] = '\0'; | |
1880 | remove_trailing_whitespaces (p); | |
1881 | break; | |
1882 | } | |
40b8e679 | 1883 | |
33b6a20a JB |
1884 | /* Look for line continuation character. */ |
1885 | remove_trailing_whitespaces (p); | |
1886 | j = strlen (buf); | |
1887 | if (!j || buf[j - 1] != '+') | |
1888 | break; | |
1889 | if (j >= sizeof (buf) - 1) | |
06ceca3a | 1890 | fail ("%s: %d: (continued) line too long\n", filename, lineno); |
33b6a20a JB |
1891 | |
1892 | if (fgets (buf + j - 1, sizeof (buf) - j + 1, fp) == NULL) | |
1893 | { | |
1894 | fprintf (stderr, "%s: Line continuation on last line?\n", | |
1895 | filename); | |
1896 | break; | |
1897 | } | |
1898 | } | |
40b8e679 L |
1899 | |
1900 | switch (p[0]) | |
1901 | { | |
1902 | case '#': | |
c30be56e JB |
1903 | if (!strcmp("### MARKER ###", buf)) |
1904 | marker = 1; | |
1905 | else | |
1906 | { | |
1907 | /* Since we ignore all included files (we only care about their | |
1908 | #define-s here), we don't need to monitor filenames. The final | |
1909 | line number directive is going to refer to the main source file | |
1910 | again. */ | |
1911 | char *end; | |
1912 | unsigned long ln; | |
1913 | ||
1914 | p = remove_leading_whitespaces (p + 1); | |
1915 | if (!strncmp(p, "line", 4)) | |
1916 | p += 4; | |
1917 | ln = strtoul (p, &end, 10); | |
1918 | if (ln > 1 && ln < INT_MAX | |
1919 | && *remove_leading_whitespaces (end) == '"') | |
1920 | lineno = ln - 1; | |
1921 | } | |
c587b3f9 | 1922 | /* Ignore comments. */ |
40b8e679 L |
1923 | case '\0': |
1924 | continue; | |
cd9ca24d | 1925 | |
4c4898e8 | 1926 | case '<': |
cd9ca24d JB |
1927 | if (parse_template (p, lineno)) |
1928 | continue; | |
1929 | break; | |
1930 | ||
40b8e679 | 1931 | default: |
c30be56e JB |
1932 | if (!marker) |
1933 | continue; | |
40b8e679 L |
1934 | break; |
1935 | } | |
1936 | ||
1937 | last = p + strlen (p); | |
1938 | ||
1939 | /* Find name. */ | |
c587b3f9 | 1940 | name = next_field (p, ',', &str, last); |
40b8e679 | 1941 | |
4c4898e8 JB |
1942 | i = expand_templates (name, str, opcode_hash_table, &opcode_array, |
1943 | lineno); | |
c587b3f9 | 1944 | } |
40b8e679 | 1945 | |
c587b3f9 L |
1946 | /* Process opcode array. */ |
1947 | for (j = 0; j < i; j++) | |
1948 | { | |
a2e2f5ad JB |
1949 | const char *name = opcode_array[j]->name; |
1950 | struct opcode_entry *next; | |
4c4898e8 | 1951 | |
a2e2f5ad | 1952 | for (next = &opcode_array[j]->entry; next; next = next->next) |
c587b3f9 | 1953 | { |
c587b3f9 | 1954 | str = next->opcode; |
bd5295b2 | 1955 | lineno = next->lineno; |
c587b3f9 | 1956 | last = str + strlen (str); |
bd5295b2 | 1957 | output_i386_opcode (table, name, str, last, lineno); |
40b8e679 | 1958 | } |
40b8e679 L |
1959 | } |
1960 | ||
34edb9ad L |
1961 | fclose (fp); |
1962 | ||
34edb9ad | 1963 | fprintf (table, "};\n"); |
65f440c8 JB |
1964 | |
1965 | /* Generate opcode sets array. */ | |
1966 | fprintf (table, "\n/* i386 opcode sets table. */\n\n"); | |
d3b01414 JB |
1967 | fprintf (table, "typedef unsigned short i386_op_off_t;\n"); |
1968 | fprintf (table, "static const i386_op_off_t i386_op_sets[] =\n{\n "); | |
65f440c8 JB |
1969 | |
1970 | for (nr = j = 0; j < i; j++) | |
1971 | { | |
a2e2f5ad | 1972 | struct opcode_entry *next = &opcode_array[j]->entry; |
65f440c8 | 1973 | |
d3b01414 JB |
1974 | if ((j + 1) % 8 != 0) |
1975 | fprintf (table, "%5u,", nr); | |
1976 | else | |
1977 | fprintf (table, "%5u,\n ", nr); | |
65f440c8 JB |
1978 | do |
1979 | { | |
1980 | ++nr; | |
1981 | next = next->next; | |
1982 | } | |
1983 | while (next); | |
65f440c8 JB |
1984 | } |
1985 | ||
d3b01414 | 1986 | fprintf (table, "%5u\n};\n", nr); |
5c139202 JB |
1987 | |
1988 | /* Emit mnemonics and associated #define-s. */ | |
3e451ee4 JB |
1989 | qsort (opcode_array, i, sizeof (*opcode_array), mnemonic_cmp); |
1990 | ||
5c139202 JB |
1991 | fp = fopen ("i386-mnem.h", "w"); |
1992 | if (fp == NULL) | |
06ceca3a | 1993 | fail ("can't create i386-mnem.h, errno = %s\n", |
5c139202 JB |
1994 | xstrerror (errno)); |
1995 | ||
1996 | process_copyright (fp); | |
1997 | ||
1998 | fprintf (table, "\n/* i386 mnemonics table. */\n\n"); | |
1999 | fprintf (table, "const char i386_mnemonics[] =\n"); | |
2000 | fprintf (fp, "\nextern const char i386_mnemonics[];\n\n"); | |
2001 | ||
992dd393 | 2002 | str = NULL; |
3e451ee4 | 2003 | for (l = strlen (opcode_array[offs = j = 0]->name); j < i; j++) |
5c139202 | 2004 | { |
a2e2f5ad | 2005 | const char *name = opcode_array[j]->name; |
3e451ee4 JB |
2006 | const char *next = NULL; |
2007 | size_t l1 = j + 1 < i ? strlen(next = opcode_array[j + 1]->name) : 0; | |
2008 | ||
992dd393 JB |
2009 | if (str == NULL) |
2010 | str = mkident (name); | |
3e451ee4 JB |
2011 | if (l < l1 && !strcmp(name, next + l1 - l)) |
2012 | { | |
2013 | fprintf (fp, "#define MN_%s ", str); | |
2014 | free (str); | |
2015 | str = mkident (next); | |
d2ac569f | 2016 | fprintf (fp, "(MN_%s + %zu)\n", str, l1 - l); |
3e451ee4 JB |
2017 | } |
2018 | else | |
2019 | { | |
2020 | fprintf (table, " \"\\0\"\"%s\"\n", name); | |
2021 | fprintf (fp, "#define MN_%s %#x\n", str, offs + 1); | |
2022 | offs += strlen (name) + 1; | |
992dd393 JB |
2023 | free (str); |
2024 | str = NULL; | |
3e451ee4 | 2025 | } |
3e451ee4 | 2026 | l = l1; |
5c139202 JB |
2027 | } |
2028 | ||
edd67638 JB |
2029 | fprintf (table, " \"\\0\"\".insn\"\n"); |
2030 | fprintf (fp, "#define MN__insn %#x\n", offs + 1); | |
2031 | ||
5c139202 JB |
2032 | fprintf (table, ";\n"); |
2033 | ||
2034 | fclose (fp); | |
40b8e679 L |
2035 | } |
2036 | ||
2037 | static void | |
72ffa0fb | 2038 | process_i386_registers (FILE *table) |
40b8e679 | 2039 | { |
3d4d5afa | 2040 | FILE *fp; |
40b8e679 L |
2041 | char buf[2048]; |
2042 | char *str, *p, *last; | |
2043 | char *reg_name, *reg_type, *reg_flags, *reg_num; | |
a60de03c | 2044 | char *dw2_32_num, *dw2_64_num; |
bd5295b2 | 2045 | int lineno = 0; |
40b8e679 | 2046 | |
3d4d5afa L |
2047 | filename = "i386-reg.tbl"; |
2048 | fp = fopen (filename, "r"); | |
40b8e679 | 2049 | if (fp == NULL) |
06ceca3a | 2050 | fail ("can't find i386-reg.tbl for reading, errno = %s\n", |
40fb9820 | 2051 | xstrerror (errno)); |
40b8e679 | 2052 | |
34edb9ad | 2053 | fprintf (table, "\n/* i386 register table. */\n\n"); |
99f0fb12 | 2054 | fprintf (table, "static const reg_entry i386_regtab[] =\n{\n"); |
40b8e679 L |
2055 | |
2056 | while (!feof (fp)) | |
2057 | { | |
2058 | if (fgets (buf, sizeof (buf), fp) == NULL) | |
2059 | break; | |
2060 | ||
3d4d5afa L |
2061 | lineno++; |
2062 | ||
40b8e679 L |
2063 | p = remove_leading_whitespaces (buf); |
2064 | ||
2065 | /* Skip comments. */ | |
2066 | str = strstr (p, "//"); | |
2067 | if (str != NULL) | |
2068 | str[0] = '\0'; | |
2069 | ||
2070 | /* Remove trailing white spaces. */ | |
2071 | remove_trailing_whitespaces (p); | |
2072 | ||
2073 | switch (p[0]) | |
2074 | { | |
2075 | case '#': | |
34edb9ad | 2076 | fprintf (table, "%s\n", p); |
40b8e679 L |
2077 | case '\0': |
2078 | continue; | |
2079 | break; | |
2080 | default: | |
2081 | break; | |
2082 | } | |
2083 | ||
2084 | last = p + strlen (p); | |
2085 | ||
2086 | /* Find reg_name. */ | |
c587b3f9 | 2087 | reg_name = next_field (p, ',', &str, last); |
40b8e679 L |
2088 | |
2089 | /* Find reg_type. */ | |
c587b3f9 | 2090 | reg_type = next_field (str, ',', &str, last); |
40b8e679 L |
2091 | |
2092 | /* Find reg_flags. */ | |
c587b3f9 | 2093 | reg_flags = next_field (str, ',', &str, last); |
40b8e679 L |
2094 | |
2095 | /* Find reg_num. */ | |
c587b3f9 | 2096 | reg_num = next_field (str, ',', &str, last); |
a60de03c | 2097 | |
40fb9820 L |
2098 | fprintf (table, " { \"%s\",\n ", reg_name); |
2099 | ||
7ac20022 JB |
2100 | process_i386_operand_type (table, reg_type, stage_registers, "\t", |
2101 | lineno); | |
40fb9820 | 2102 | |
a60de03c | 2103 | /* Find 32-bit Dwarf2 register number. */ |
c587b3f9 | 2104 | dw2_32_num = next_field (str, ',', &str, last); |
a60de03c JB |
2105 | |
2106 | /* Find 64-bit Dwarf2 register number. */ | |
c587b3f9 | 2107 | dw2_64_num = next_field (str, ',', &str, last); |
a60de03c JB |
2108 | |
2109 | fprintf (table, ",\n %s, %s, { %s, %s } },\n", | |
2110 | reg_flags, reg_num, dw2_32_num, dw2_64_num); | |
40b8e679 L |
2111 | } |
2112 | ||
34edb9ad L |
2113 | fclose (fp); |
2114 | ||
2115 | fprintf (table, "};\n"); | |
40b8e679 | 2116 | |
99f0fb12 | 2117 | fprintf (table, "\nstatic const unsigned int i386_regtab_size = ARRAY_SIZE (i386_regtab);\n"); |
40b8e679 L |
2118 | } |
2119 | ||
40fb9820 L |
2120 | static void |
2121 | process_i386_initializers (void) | |
2122 | { | |
2123 | unsigned int i; | |
2124 | FILE *fp = fopen ("i386-init.h", "w"); | |
40fb9820 L |
2125 | |
2126 | if (fp == NULL) | |
06ceca3a | 2127 | fail ("can't create i386-init.h, errno = %s\n", |
40fb9820 L |
2128 | xstrerror (errno)); |
2129 | ||
2130 | process_copyright (fp); | |
2131 | ||
da5f9eb4 | 2132 | for (i = 0; i < CpuMax; i++) |
4d97c5c8 JB |
2133 | process_i386_cpu_flag (fp, "0", cpu_flags[i].name, "", " ", -1, i); |
2134 | ||
2135 | for (i = 0; i < ARRAY_SIZE (isa_dependencies); i++) | |
2136 | { | |
2137 | char *deps = xstrdup (isa_dependencies[i].deps); | |
2138 | ||
2139 | process_i386_cpu_flag (fp, deps, isa_dependencies[i].name, | |
2140 | "", " ", -1, CpuMax); | |
2141 | free (deps); | |
2142 | } | |
2143 | ||
2144 | /* Early x87 is somewhat special: Both 287 and 387 not only add new insns | |
2145 | but also remove some. Hence 8087 isn't a prereq to 287, and 287 isn't | |
2146 | one to 387. We want the reverse to be true though: Disabling 8087 also | |
2147 | is to disable 287+ and later; disabling 287 also means disabling 387+. */ | |
2148 | memcpy (isa_reverse_deps[Cpu287], isa_reverse_deps[Cpu387], | |
2149 | sizeof (isa_reverse_deps[0])); | |
2150 | isa_reverse_deps[Cpu287][Cpu387] = 1; | |
2151 | memcpy (isa_reverse_deps[Cpu8087], isa_reverse_deps[Cpu287], | |
2152 | sizeof (isa_reverse_deps[0])); | |
2153 | isa_reverse_deps[Cpu8087][Cpu287] = 1; | |
2154 | ||
2155 | /* While we treat POPCNT as a prereq to SSE4.2, its disabling should not | |
2156 | lead to disabling of anything else. */ | |
2157 | memset (isa_reverse_deps[CpuPOPCNT], 0, sizeof (isa_reverse_deps[0])); | |
2158 | ||
2159 | for (i = Cpu686 + 1; i < ARRAY_SIZE (isa_reverse_deps); i++) | |
40fb9820 | 2160 | { |
4d97c5c8 JB |
2161 | size_t len; |
2162 | char *upper; | |
2163 | ||
2164 | if (memchr(isa_reverse_deps[i], 1, | |
2165 | ARRAY_SIZE (isa_reverse_deps[0])) == NULL) | |
2166 | continue; | |
2167 | ||
2168 | isa_reverse_deps[i][i] = 1; | |
2169 | process_i386_cpu_flag (fp, NULL, cpu_flags[i].name, "", " ", -1, i); | |
40fb9820 L |
2170 | } |
2171 | ||
40fb9820 L |
2172 | fprintf (fp, "\n"); |
2173 | ||
2174 | fclose (fp); | |
2175 | } | |
2176 | ||
40b8e679 L |
2177 | /* Program options. */ |
2178 | #define OPTION_SRCDIR 200 | |
2179 | ||
29c048b6 | 2180 | struct option long_options[] = |
40b8e679 L |
2181 | { |
2182 | {"srcdir", required_argument, NULL, OPTION_SRCDIR}, | |
2183 | {"debug", no_argument, NULL, 'd'}, | |
2184 | {"version", no_argument, NULL, 'V'}, | |
2185 | {"help", no_argument, NULL, 'h'}, | |
2186 | {0, no_argument, NULL, 0} | |
2187 | }; | |
2188 | ||
2189 | static void | |
2190 | print_version (void) | |
2191 | { | |
2192 | printf ("%s: version 1.0\n", program_name); | |
2193 | xexit (0); | |
2194 | } | |
2195 | ||
2196 | static void | |
2197 | usage (FILE * stream, int status) | |
2198 | { | |
2199 | fprintf (stream, "Usage: %s [-V | --version] [-d | --debug] [--srcdir=dirname] [--help]\n", | |
2200 | program_name); | |
2201 | xexit (status); | |
2202 | } | |
2203 | ||
2204 | int | |
2205 | main (int argc, char **argv) | |
2206 | { | |
2207 | extern int chdir (char *); | |
2208 | char *srcdir = NULL; | |
8b40d594 | 2209 | int c; |
e92bae62 | 2210 | unsigned int i, cpumax; |
72ffa0fb | 2211 | FILE *table; |
29c048b6 | 2212 | |
40b8e679 L |
2213 | program_name = *argv; |
2214 | xmalloc_set_program_name (program_name); | |
2215 | ||
2216 | while ((c = getopt_long (argc, argv, "vVdh", long_options, 0)) != EOF) | |
2217 | switch (c) | |
2218 | { | |
2219 | case OPTION_SRCDIR: | |
2220 | srcdir = optarg; | |
2221 | break; | |
2222 | case 'V': | |
2223 | case 'v': | |
2224 | print_version (); | |
2225 | break; | |
2226 | case 'd': | |
2227 | debug = 1; | |
2228 | break; | |
2229 | case 'h': | |
2230 | case '?': | |
2231 | usage (stderr, 0); | |
2232 | default: | |
2233 | case 0: | |
2234 | break; | |
2235 | } | |
2236 | ||
2237 | if (optind != argc) | |
2238 | usage (stdout, 1); | |
2239 | ||
29c048b6 | 2240 | if (srcdir != NULL) |
40b8e679 | 2241 | if (chdir (srcdir) != 0) |
06ceca3a | 2242 | fail ("unable to change directory to \"%s\", errno = %s\n", |
40fb9820 L |
2243 | srcdir, xstrerror (errno)); |
2244 | ||
e92bae62 L |
2245 | /* cpu_flags isn't sorted by position. */ |
2246 | cpumax = 0; | |
2247 | for (i = 0; i < ARRAY_SIZE (cpu_flags); i++) | |
2248 | if (cpu_flags[i].position > cpumax) | |
2249 | cpumax = cpu_flags[i].position; | |
2250 | ||
40fb9820 | 2251 | /* Check the unused bitfield in i386_cpu_flags. */ |
e89c5eaa | 2252 | #ifdef CpuUnused |
1d942ae9 JB |
2253 | static_assert (ARRAY_SIZE (cpu_flags) == CpuMax + 2); |
2254 | ||
e92bae62 | 2255 | if ((cpumax - 1) != CpuMax) |
06ceca3a | 2256 | fail ("CpuMax != %d!\n", cpumax); |
e89c5eaa | 2257 | #else |
1d942ae9 JB |
2258 | static_assert (ARRAY_SIZE (cpu_flags) == CpuMax + 1); |
2259 | ||
e92bae62 | 2260 | if (cpumax != CpuMax) |
06ceca3a | 2261 | fail ("CpuMax != %d!\n", cpumax); |
e89c5eaa | 2262 | |
8b40d594 L |
2263 | c = CpuNumOfBits - CpuMax - 1; |
2264 | if (c) | |
06ceca3a | 2265 | fail ("%d unused bits in i386_cpu_flags.\n", c); |
734dfd1c JB |
2266 | #endif |
2267 | ||
2268 | /* If this triggers, CpuIsaBits needs to be increased. */ | |
2269 | static_assert (CpuAttrEnums <= (1u << CpuIsaBits)); | |
2270 | ||
2271 | /* Check the unused bitfield in i386_cpu_attr. */ | |
2272 | #ifndef CpuAttrUnused | |
2273 | c = CpuAttrNumOfBits - (CpuIsaBits + CpuMax + 1 - CpuAttrEnums); | |
2274 | if (c) | |
2275 | fail ("%d unused bits in i386_cpu_attr.\n", c); | |
40fb9820 L |
2276 | #endif |
2277 | ||
1d942ae9 JB |
2278 | static_assert (ARRAY_SIZE (opcode_modifiers) == Opcode_Modifier_Num); |
2279 | ||
40fb9820 | 2280 | /* Check the unused bitfield in i386_operand_type. */ |
1d942ae9 | 2281 | #ifdef OTUnused |
75e5731b JB |
2282 | static_assert (ARRAY_SIZE (operand_types) + CLASS_WIDTH + INSTANCE_WIDTH |
2283 | == OTNum + 1); | |
1d942ae9 | 2284 | #else |
75e5731b JB |
2285 | static_assert (ARRAY_SIZE (operand_types) + CLASS_WIDTH + INSTANCE_WIDTH |
2286 | == OTNum); | |
1d942ae9 | 2287 | |
51c8edf6 | 2288 | c = OTNumOfBits - OTNum; |
8b40d594 | 2289 | if (c) |
06ceca3a | 2290 | fail ("%d unused bits in i386_operand_type.\n", c); |
40fb9820 L |
2291 | #endif |
2292 | ||
2293 | qsort (cpu_flags, ARRAY_SIZE (cpu_flags), sizeof (cpu_flags [0]), | |
2294 | compare); | |
2295 | ||
2296 | qsort (opcode_modifiers, ARRAY_SIZE (opcode_modifiers), | |
2297 | sizeof (opcode_modifiers [0]), compare); | |
2298 | ||
2299 | qsort (operand_types, ARRAY_SIZE (operand_types), | |
2300 | sizeof (operand_types [0]), compare); | |
40b8e679 | 2301 | |
3e624fa4 JB |
2302 | process_i386_initializers (); |
2303 | ||
34edb9ad L |
2304 | table = fopen ("i386-tbl.h", "w"); |
2305 | if (table == NULL) | |
06ceca3a | 2306 | fail ("can't create i386-tbl.h, errno = %s\n", |
40fb9820 | 2307 | xstrerror (errno)); |
34edb9ad | 2308 | |
72ffa0fb | 2309 | process_copyright (table); |
40b8e679 | 2310 | |
72ffa0fb L |
2311 | process_i386_opcodes (table); |
2312 | process_i386_registers (table); | |
40b8e679 | 2313 | |
34edb9ad L |
2314 | fclose (table); |
2315 | ||
40b8e679 L |
2316 | exit (0); |
2317 | } |