insns: Introduce insns-flags.pl
[platform/upstream/nasm.git] / insns-iflags.pl
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:
11 ##
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.
18 ##
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.
32 ##
33 ## --------------------------------------------------------------------------
34
35 #
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).
40
41 #
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 = (
46     #
47     # dword bound, index 0 - specific flags
48     #
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"],
66
67     #
68     # dword bound, index 1 - instruction filtering flags
69     #
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, ""],
101
102     #
103     # dword bound, index 2 - instruction filtering flags
104     #
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"],
112
113     #
114     # dword bound, index 3 - cpu type flags
115     #
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"],
134 );
135
136 my %insns_flag_hash = ();
137 my @insns_flag_values = ();
138
139 sub insns_flag_index(@) {
140     return undef if $_[0] eq "ignore";
141
142     my @prekey = sort(@_);
143     my $key = join("", @prekey);
144
145     if (not defined($insns_flag_hash{$key})) {
146         my @newkey = ([], [], [], []);
147         my $str = "";
148
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";
161             }
162         }
163
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";
170             }
171             $str .= sprintf(".field[%d] = %s, ", $j, $v);
172         }
173
174         push @insns_flag_values, $str;
175         $insns_flag_hash{$key} = $#insns_flag_values;
176     }
177
178     return $insns_flag_hash{$key};
179 }
180
181 sub write_iflags() {
182     print STDERR "Writing iflag.h ...\n";
183
184     open N, ">iflag.h";
185
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";
189
190     print N "#include <inttypes.h>\n\n";
191     print N "#include <string.h>\n\n";
192
193     print N "#include \"compiler.h\"\n";
194
195     print N "extern int ilog2_32(uint32_t v);\n\n";
196
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]);
228     }
229
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";
234
235     print N "\n";
236     print N sprintf("extern iflag_t insns_flags[%d];\n\n", $#insns_flag_values + 1);
237
238     print N "#define IF_GENBIT(bit)          (UINT32_C(1) << (bit))\n\n";
239
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";
245
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";
251
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";
257
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";
262
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";
267
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";
281
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";
290
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";
302
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";
317
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";
320
321     print N "\n";
322     print N "/* Maximum processor level at moment */\n";
323     print N "#define IF_PLEVEL               IF_IA64\n";
324
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";
341
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";
350
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";
370
371
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";
387
388     print N "\n";
389     print N "#define iflag_pfmask(itemp)        __iflag_pfmask(&insns_flags[(itemp)->iflag_idx])\n";
390
391     print N "\n";
392     print N "#endif /* NASM_IFLAG_H__ */\n";
393     close N;
394
395     print STDERR "Writing iflag.c ...\n";
396
397     open N, ">iflag.c";
398
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]);
405     }
406     print N "};\n\n";
407     close N;
408 }
409
410 1;