make: Update deps
[nasm.git] / insns-iflags.pl
blob56da13409022297f1a041e0975ef904bd7c61389
1 #!/usr/bin/perl
2 ## --------------------------------------------------------------------------
3 ##
4 ## Copyright 1996-2013 The NASM Authors - All Rights Reserved
5 ## See the file AUTHORS included with the NASM distribution for
6 ## the specific copyright holders.
7 ##
8 ## Redistribution and use in source and binary forms, with or without
9 ## modification, are permitted provided that the following
10 ## conditions are met:
12 ## * Redistributions of source code must retain the above copyright
13 ## notice, this list of conditions and the following disclaimer.
14 ## * Redistributions in binary form must reproduce the above
15 ## copyright notice, this list of conditions and the following
16 ## disclaimer in the documentation and/or other materials provided
17 ## with the distribution.
19 ## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
20 ## CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
21 ## INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
22 ## MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 ## DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 ## CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 ## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 ## NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 ## LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 ## HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 ## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30 ## OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
31 ## EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 ## --------------------------------------------------------------------------
36 # Here we generate instrcution template flags. Note we assume that at moment
37 # less than 128 bits are used for all flags. If needed it can be extended
38 # arbitrary, but it'll be needed to extend arrays (they are 4 32 bit elements
39 # by now).
42 # The order does matter here. We use some predefined masks to quick test
43 # for a set of flags, so be carefull moving bits (and
44 # don't forget to update C code generation then).
45 my %insns_flag_bit = (
47 # dword bound, index 0 - specific flags
49 "SM" => [ 0, "Size match"],
50 "SM2" => [ 1, "Size match first two operands"],
51 "SB" => [ 2, "Unsized operands can't be non-byte"],
52 "SW" => [ 3, "Unsized operands can't be non-word"],
53 "SD" => [ 4, "Unsized operands can't be non-dword"],
54 "SQ" => [ 5, "Unsized operands can't be non-qword"],
55 "SO" => [ 6, "Unsized operands can't be non-oword"],
56 "SY" => [ 7, "Unsized operands can't be non-yword"],
57 "SZ" => [ 8, "Unsized operands can't be non-zword"],
58 "SIZE" => [ 9, "Unsized operands must match the bitsize"],
59 "SX" => [ 10, "Unsized operands not allowed"],
60 "AR0" => [ 11, "SB, SW, SD applies to argument 0"],
61 "AR1" => [ 12, "SB, SW, SD applies to argument 1"],
62 "AR2" => [ 13, "SB, SW, SD applies to argument 2"],
63 "AR3" => [ 14, "SB, SW, SD applies to argument 3"],
64 "AR4" => [ 15, "SB, SW, SD applies to argument 4"],
65 "OPT" => [ 16, "Optimizing assembly only"],
68 # dword bound, index 1 - instruction filtering flags
70 "PRIV" => [ 32, "Privileged instruction"],
71 "SMM" => [ 33, "Only valid in SMM"],
72 "PROT" => [ 34, "Protected mode only"],
73 "LOCK" => [ 35, "Lockable if operand 0 is memory"],
74 "NOLONG" => [ 36, "Not available in long mode"],
75 "LONG" => [ 37, "Long mode"],
76 "NOHLE" => [ 38, "HLE prefixes forbidden"],
77 "MIB" => [ 39, "disassemble with split EA"],
78 "BND" => [ 40, "BND (0xF2) prefix available"],
79 "UNDOC" => [ 41, "Undocumented"],
80 "HLE" => [ 42, "HLE prefixed"],
81 "FPU" => [ 43, "FPU"],
82 "MMX" => [ 44, "MMX"],
83 "3DNOW" => [ 45, "3DNow!"],
84 "SSE" => [ 46, "SSE (KNI, MMX2)"],
85 "SSE2" => [ 47, "SSE2"],
86 "SSE3" => [ 48, "SSE3 (PNI)"],
87 "VMX" => [ 49, "VMX"],
88 "SSSE3" => [ 50, "SSSE3"],
89 "SSE4A" => [ 51, "AMD SSE4a"],
90 "SSE41" => [ 52, "SSE4.1"],
91 "SSE42" => [ 53, "SSE4.2"],
92 "SSE5" => [ 54, "SSE5"],
93 "AVX" => [ 55, "AVX (128b)"],
94 "AVX2" => [ 56, "AVX2 (256b)"],
95 "FMA" => [ 57, ""],
96 "BMI1" => [ 58, ""],
97 "BMI2" => [ 59, ""],
98 "TBM" => [ 60, ""],
99 "RTM" => [ 61, ""],
100 "INVPCID" => [ 62, ""],
103 # dword bound, index 2 - instruction filtering flags
105 "AVX512" => [ 64, "AVX-512F (512b)"],
106 "AVX512CD" => [ 65, "AVX-512 Conflict Detection"],
107 "AVX512ER" => [ 66, "AVX-512 Exponential and Reciprocal"],
108 "AVX512PF" => [ 67, "AVX-512 Prefetch"],
109 "MPX" => [ 68 ,"MPX"],
110 "SHA" => [ 69 ,"SHA"],
111 "PREFETCHWT1" => [ 70 ,"PREFETCHWT1"],
114 # dword bound, index 3 - cpu type flags
116 "8086" => [ 96, "8086"],
117 "186" => [ 97, "186+"],
118 "286" => [ 98, "286+"],
119 "386" => [ 99, "386+"],
120 "486" => [100, "486+"],
121 "PENT" => [101, "Pentium"],
122 "P6" => [102, "P6"],
123 "KATMAI" => [103, "Katmai"],
124 "WILLAMETTE" => [104, "Willamette"],
125 "PRESCOTT" => [105, "Prescott"],
126 "X86_64" => [106, "x86-64 (long or legacy mode)"],
127 "NEHALEM" => [107, "Nehalem"],
128 "WESTMERE" => [108, "Westmere"],
129 "SANDYBRIDGE" => [109, "Sandy Bridge"],
130 "FUTURE" => [110, "Future processor (not yet disclosed)"],
131 "IA64" => [111, "IA64 (in x86 mode)"],
132 "CYRIX" => [112, "Cyrix-specific"],
133 "AMD" => [113, "AMD-specific"],
136 my %insns_flag_hash = ();
137 my @insns_flag_values = ();
139 sub insns_flag_index(@) {
140 return undef if $_[0] eq "ignore";
142 my @prekey = sort(@_);
143 my $key = join("", @prekey);
145 if (not defined($insns_flag_hash{$key})) {
146 my @newkey = ([], [], [], []);
147 my $str = "";
149 for my $i (@prekey) {
150 die "No key for $i\n" if not defined($insns_flag_bit{$i});
151 if ($insns_flag_bit{$i}[0] < 32) {
152 push @newkey[0], $insns_flag_bit{$i}[0] - 0;
153 } elsif ($insns_flag_bit{$i}[0] < 64) {
154 push @newkey[1], $insns_flag_bit{$i}[0] - 32;
155 } elsif ($insns_flag_bit{$i}[0] < 96) {
156 push @newkey[2], $insns_flag_bit{$i}[0] - 64;
157 } elsif ($insns_flag_bit{$i}[0] < 128) {
158 push @newkey[3], $insns_flag_bit{$i}[0] - 96;
159 } else {
160 die "Key value is too big ", $insns_flag_bit{$i}[0], "\n";
164 for my $j (0 .. $#newkey) {
165 my $v = "";
166 if (scalar(@{$newkey[$j]})) {
167 $v = join(" | ", map { map { sprintf("(UINT32_C(1) << %d)", $_) } @$_; } $newkey[$j]);
168 } else {
169 $v = "0";
171 $str .= sprintf(".field[%d] = %s, ", $j, $v);
174 push @insns_flag_values, $str;
175 $insns_flag_hash{$key} = $#insns_flag_values;
178 return $insns_flag_hash{$key};
181 sub write_iflags() {
182 print STDERR "Writing iflag.h ...\n";
184 open N, ">iflag.h";
186 print N "/* This file is auto-generated. Don't edit. */\n";
187 print N "#ifndef NASM_IFLAG_H__\n";
188 print N "#define NASM_IFLAG_H__\n\n";
190 print N "#include <inttypes.h>\n\n";
191 print N "#include <string.h>\n\n";
193 print N "#include \"compiler.h\"\n";
195 print N "extern int ilog2_32(uint32_t v);\n\n";
197 print N "/*\n";
198 print N " * Instruction template flags. These specify which processor\n";
199 print N " * targets the instruction is eligible for, whether it is\n";
200 print N " * privileged or undocumented, and also specify extra error\n";
201 print N " * checking on the matching of the instruction.\n";
202 print N " *\n";
203 print N " * IF_SM stands for Size Match: any operand whose size is not\n";
204 print N " * explicitly specified by the template is `really' intended to be\n";
205 print N " * the same size as the first size-specified operand.\n";
206 print N " * Non-specification is tolerated in the input instruction, but\n";
207 print N " * _wrong_ specification is not.\n";
208 print N " *\n";
209 print N " * IF_SM2 invokes Size Match on only the first _two_ operands, for\n";
210 print N " * three-operand instructions such as SHLD: it implies that the\n";
211 print N " * first two operands must match in size, but that the third is\n";
212 print N " * required to be _unspecified_.\n";
213 print N " *\n";
214 print N " * IF_SB invokes Size Byte: operands with unspecified size in the\n";
215 print N " * template are really bytes, and so no non-byte specification in\n";
216 print N " * the input instruction will be tolerated. IF_SW similarly invokes\n";
217 print N " * Size Word, and IF_SD invokes Size Doubleword.\n";
218 print N " *\n";
219 print N " * (The default state if neither IF_SM nor IF_SM2 is specified is\n";
220 print N " * that any operand with unspecified size in the template is\n";
221 print N " * required to have unspecified size in the instruction too...)\n";
222 print N " *\n";
223 print N " * iflag_t is defined to store these flags.\n";
224 print N " */\n";
225 foreach my $key (sort { $insns_flag_bit{$a}[0] <=> $insns_flag_bit{$b}[0] } keys(%insns_flag_bit)) {
226 print N sprintf("#define IF_%-16s (%3d) /* %-64s */\n",
227 $key, $insns_flag_bit{$key}[0], $insns_flag_bit{$key}[1]);
230 print N "\n";
231 print N "typedef struct {\n";
232 print N " uint32_t field[4];\n";
233 print N "} iflag_t;\n\n";
235 print N "\n";
236 print N sprintf("extern iflag_t insns_flags[%d];\n\n", $#insns_flag_values + 1);
238 print N "#define IF_GENBIT(bit) (UINT32_C(1) << (bit))\n\n";
240 print N "static inline unsigned int iflag_test(iflag_t *f,unsigned int bit)\n";
241 print N "{\n";
242 print N " unsigned int index = bit / 32;\n";
243 print N " return f->field[index] & (UINT32_C(1) << (bit - (index * 32)));\n";
244 print N "}\n\n";
246 print N "static inline void iflag_set(iflag_t *f, unsigned int bit)\n";
247 print N "{\n";
248 print N " unsigned int index = bit / 32;\n";
249 print N " f->field[index] |= (UINT32_C(1) << (bit - (index * 32)));\n";
250 print N "}\n\n";
252 print N "static inline void iflag_clear(iflag_t *f, unsigned int bit)\n";
253 print N "{\n";
254 print N " unsigned int index = bit / 32;\n";
255 print N " f->field[index] &= ~(UINT32_C(1) << (bit - (index * 32)));\n";
256 print N "}\n\n";
258 print N "static inline void iflag_clear_all(iflag_t *f)\n";
259 print N "{\n";
260 print N " memset(f, 0, sizeof(*f));\n";
261 print N "}\n\n";
263 print N "static inline void iflag_set_all(iflag_t *f)\n";
264 print N "{\n";
265 print N " memset(f, 0xff, sizeof(*f));\n";
266 print N "}\n\n";
268 print N "static inline int iflag_cmp(iflag_t *a, iflag_t *b)\n";
269 print N "{\n";
270 print N " unsigned int i;\n";
271 print N "\n";
272 print N " for (i = 0; i < sizeof(a->field) / sizeof(a->field[0]); i++) {\n";
273 print N " if (a->field[i] < b->field[i])\n";
274 print N " return -1;\n";
275 print N " else if (a->field[i] > b->field[i])\n";
276 print N " return 1;\n";
277 print N " }\n";
278 print N "\n";
279 print N " return 0;\n";
280 print N "}\n\n";
282 print N "static inline int iflag_cmp_cpu(iflag_t *a, iflag_t *b)\n";
283 print N "{\n";
284 print N " if (a->field[3] < b->field[3])\n";
285 print N " return -1;\n";
286 print N " else if (a->field[3] > b->field[3])\n";
287 print N " return 1;\n";
288 print N " return 0;\n";
289 print N "}\n\n";
291 print N "static inline unsigned int iflag_ffs(iflag_t *a)\n";
292 print N "{\n";
293 print N " unsigned int i;\n";
294 print N "\n";
295 print N " for (i = 0; i < sizeof(a->field) / sizeof(a->field[0]); i++) {\n";
296 print N " if (a->field[i])\n";
297 print N " return ilog2_32(a->field[i]) + (i * 32);\n";
298 print N " }\n";
299 print N "\n";
300 print N " return 0;\n";
301 print N "}\n\n";
303 print N "#define IF_GEN_HELPER(name, op) \\\n";
304 print N " static inline iflag_t iflag_##name(iflag_t *a, iflag_t *b) \\\n";
305 print N " { \\\n";
306 print N " unsigned int i; \\\n";
307 print N " iflag_t res; \\\n";
308 print N " \\\n";
309 print N " for (i = 0; i < sizeof(a->field) / sizeof(a->field[0]); i++) \\\n";
310 print N " res.field[i] = a->field[i] op b->field[i]; \\\n";
311 print N " \\\n";
312 print N " return res; \\\n";
313 print N " }\n";
314 print N "\n";
315 print N "IF_GEN_HELPER(xor, ^)\n";
316 print N "\n\n";
318 print N "/* Use this helper to test instruction template flags */\n";
319 print N "#define itemp_has(itemp, bit) iflag_test(&insns_flags[(itemp)->iflag_idx], bit)\n\n";
321 print N "\n";
322 print N "/* Maximum processor level at moment */\n";
323 print N "#define IF_PLEVEL IF_IA64\n";
325 print N "/* Some helpers which are to work with predefined masks */\n";
326 print N "#define IF_SMASK \\\n";
327 print N " (IF_GENBIT(IF_SB) |\\\n";
328 print N " IF_GENBIT(IF_SW) |\\\n";
329 print N " IF_GENBIT(IF_SD) |\\\n";
330 print N " IF_GENBIT(IF_SQ) |\\\n";
331 print N " IF_GENBIT(IF_SO) |\\\n";
332 print N " IF_GENBIT(IF_SY) |\\\n";
333 print N " IF_GENBIT(IF_SZ) |\\\n";
334 print N " IF_GENBIT(IF_SIZE))\n";
335 print N "#define IF_ARMASK \\\n";
336 print N " (IF_GENBIT(IF_AR0) |\\\n";
337 print N " IF_GENBIT(IF_AR1) |\\\n";
338 print N " IF_GENBIT(IF_AR2) |\\\n";
339 print N " IF_GENBIT(IF_AR3) |\\\n";
340 print N " IF_GENBIT(IF_AR4))\n";
342 print N "\n";
343 print N "#define __itemp_smask(idx) (insns_flags[(idx)].field[0] & IF_SMASK)\n";
344 print N "#define __itemp_armask(idx) (insns_flags[(idx)].field[0] & IF_ARMASK)\n";
345 print N "#define __itemp_arg(idx) ((__itemp_armask(idx) >> IF_AR0) - 1)\n";
346 print N "\n";
347 print N "#define itemp_smask(itemp) __itemp_smask((itemp)->iflag_idx)\n";
348 print N "#define itemp_arg(itemp) __itemp_arg((itemp)->iflag_idx)\n";
349 print N "#define itemp_armask(itemp) __itemp_armask((itemp)->iflag_idx)\n";
351 print N "\n";
352 print N "static inline int iflag_cmp_cpu_level(iflag_t *a, iflag_t *b)\n";
353 print N "{\n";
354 print N " iflag_t v1 = *a;\n";
355 print N " iflag_t v2 = *b;\n";
356 print N "\n";
357 print N " iflag_clear(&v1, IF_CYRIX);\n";
358 print N " iflag_clear(&v1, IF_AMD);\n";
359 print N "\n";
360 print N " iflag_clear(&v2, IF_CYRIX);\n";
361 print N " iflag_clear(&v2, IF_AMD);\n";
362 print N "\n";
363 print N " if (v1.field[3] < v2.field[3])\n";
364 print N " return -1;\n";
365 print N " else if (v1.field[3] > v2.field[3])\n";
366 print N " return 1;\n";
367 print N "\n";
368 print N " return 0;\n";
369 print N "}\n";
372 print N "\n";
373 print N "static inline iflag_t __iflag_pfmask(iflag_t *a)\n";
374 print N "{\n";
375 print N " iflag_t r = (iflag_t) {\n";
376 print N " .field[1] = a->field[1],\n";
377 print N " .field[2] = a->field[2],\n";
378 print N " };\n";
379 print N "\n";
380 print N " if (iflag_test(a, IF_CYRIX))\n";
381 print N " iflag_set(&r, IF_CYRIX);\n";
382 print N " if (iflag_test(a, IF_AMD))\n";
383 print N " iflag_set(&r, IF_AMD);\n";
384 print N "\n";
385 print N " return r;\n";
386 print N "}\n";
388 print N "\n";
389 print N "#define iflag_pfmask(itemp) __iflag_pfmask(&insns_flags[(itemp)->iflag_idx])\n";
391 print N "\n";
392 print N "#endif /* NASM_IFLAG_H__ */\n";
393 close N;
395 print STDERR "Writing iflag.c ...\n";
397 open N, ">iflag.c";
399 print N "/* This file is auto-generated. Don't edit. */\n";
400 print N "#include \"iflag.h\"\n\n";
401 print N "/* Global flags referenced from instruction templates */\n";
402 print N sprintf("iflag_t insns_flags[%d] = {\n", $#insns_flag_values + 1);
403 foreach my $i (0 .. $#insns_flag_values) {
404 print N sprintf(" [%8d] = { %s },\n", $i, $insns_flag_values[$i]);
406 print N "};\n\n";
407 close N;