#!/usr/bin/perl ## -------------------------------------------------------------------------- ## ## Copyright 1996-2018 The NASM Authors - All Rights Reserved ## See the file AUTHORS included with the NASM distribution for ## the specific copyright holders. ## ## Redistribution and use in source and binary forms, with or without ## modification, are permitted provided that the following ## conditions are met: ## ## * Redistributions of source code must retain the above copyright ## notice, this list of conditions and the following disclaimer. ## * Redistributions in binary form must reproduce the above ## copyright notice, this list of conditions and the following ## disclaimer in the documentation and/or other materials provided ## with the distribution. ## ## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND ## CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, ## INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF ## MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ## DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR ## CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ## NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ## LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ## HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR ## OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, ## EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ## ## -------------------------------------------------------------------------- # # Instruction template flags. These specify which processor # targets the instruction is eligible for, whether it is # privileged or undocumented, and also specify extra error # checking on the matching of the instruction. # # IF_SM stands for Size Match: any operand whose size is not # explicitly specified by the template is `really' intended to be # the same size as the first size-specified operand. # Non-specification is tolerated in the input instruction, but # _wrong_ specification is not. # # IF_SM2 invokes Size Match on only the first _two_ operands, for # three-operand instructions such as SHLD: it implies that the # first two operands must match in size, but that the third is # required to be _unspecified_. # # IF_SB invokes Size Byte: operands with unspecified size in the # template are really bytes, and so no non-byte specification in # the input instruction will be tolerated. IF_SW similarly invokes # Size Word, and IF_SD invokes Size Doubleword. # # (The default state if neither IF_SM nor IF_SM2 is specified is # that any operand with unspecified size in the template is # required to have unspecified size in the instruction too...) # # iflag_t is defined to store these flags. # # The order does matter here. We use some predefined masks to quick test # for a set of flags, so be careful moving bits (and # don't forget to update C code generation then). # sub dword_align($) { my($n) = @_; $$n = ($$n + 31) & ~31; return $n; } my $f = 0; my %insns_flag_bit = ( # # dword bound, index 0 - specific flags # "SM" => [$f++, "Size match"], "SM2" => [$f++, "Size match first two operands"], "SB" => [$f++, "Unsized operands can't be non-byte"], "SW" => [$f++, "Unsized operands can't be non-word"], "SD" => [$f++, "Unsized operands can't be non-dword"], "SQ" => [$f++, "Unsized operands can't be non-qword"], "SO" => [$f++, "Unsized operands can't be non-oword"], "SY" => [$f++, "Unsized operands can't be non-yword"], "SZ" => [$f++, "Unsized operands can't be non-zword"], "SIZE" => [$f++, "Unsized operands must match the bitsize"], "SX" => [$f++, "Unsized operands not allowed"], "AR0" => [$f++, "SB, SW, SD applies to argument 0"], "AR1" => [$f++, "SB, SW, SD applies to argument 1"], "AR2" => [$f++, "SB, SW, SD applies to argument 2"], "AR3" => [$f++, "SB, SW, SD applies to argument 3"], "AR4" => [$f++, "SB, SW, SD applies to argument 4"], "OPT" => [$f++, "Optimizing assembly only"], # # dword bound - instruction filtering flags # "PRIV" => [${dword_align(\$f)}++, "Privileged instruction"], "SMM" => [$f++, "Only valid in SMM"], "PROT" => [$f++, "Protected mode only"], "LOCK" => [$f++, "Lockable if operand 0 is memory"], "NOLONG" => [$f++, "Not available in long mode"], "LONG" => [$f++, "Long mode"], "NOHLE" => [$f++, "HLE prefixes forbidden"], "MIB" => [$f++, "disassemble with split EA"], "BND" => [$f++, "BND (0xF2) prefix available"], "UNDOC" => [$f++, "Undocumented"], "HLE" => [$f++, "HLE prefixed"], "FPU" => [$f++, "FPU"], "MMX" => [$f++, "MMX"], "3DNOW" => [$f++, "3DNow!"], "SSE" => [$f++, "SSE (KNI, MMX2)"], "SSE2" => [$f++, "SSE2"], "SSE3" => [$f++, "SSE3 (PNI)"], "VMX" => [$f++, "VMX"], "SSSE3" => [$f++, "SSSE3"], "SSE4A" => [$f++, "AMD SSE4a"], "SSE41" => [$f++, "SSE4.1"], "SSE42" => [$f++, "SSE4.2"], "SSE5" => [$f++, "SSE5"], "AVX" => [$f++, "AVX (256-bit floating point)"], "AVX2" => [$f++, "AVX2 (256-bit integer)"], "FMA" => [$f++, ""], "BMI1" => [$f++, ""], "BMI2" => [$f++, ""], "TBM" => [$f++, ""], "RTM" => [$f++, ""], "INVPCID" => [$f++, ""], "AVX512" => [$f++, "AVX-512F (512-bit base architecture)"], "AVX512CD" => [$f++, "AVX-512 Conflict Detection"], "AVX512ER" => [$f++, "AVX-512 Exponential and Reciprocal"], "AVX512PF" => [$f++, "AVX-512 Prefetch"], "MPX" => [$f++, "MPX"], "SHA" => [$f++, "SHA"], "PREFETCHWT1" => [$f++, "PREFETCHWT1"], "AVX512VL" => [$f++, "AVX-512 Vector Length Orthogonality"], "AVX512DQ" => [$f++, "AVX-512 Dword and Qword"], "AVX512BW" => [$f++, "AVX-512 Byte and Word"], "AVX512IFMA" => [$f++, "AVX-512 IFMA instructions"], "AVX512VBMI" => [$f++, "AVX-512 VBMI instructions"], "AES" => [$f++, "AES instructions"], "VAES" => [$f++, "AES AVX instructions"], "VPCLMULQDQ" => [$f++, "AVX Carryless Multiplication"], "GFNI" => [$f++, "Galois Field instructions"], "AVX512VBMI2" => [$f++, "AVX-512 VBMI2 instructions"], "AVX512VNNI" => [$f++, "AVX-512 VNNI instructions"], "AVX512BITALG" => [$f++, "AVX-512 Bit Algorithm instructions"], "AVX512VPOPCNTDQ" => [$f++, "AVX-512 VPOPCNTD/VPOPCNTQ"], "AVX5124FMAPS" => [$f++, "AVX-512 4-iteration multiply-add"], "AVX5124VNNIW" => [$f++, "AVX-512 4-iteration dot product"], "SGX" => [$f++, "Intel Software Guard Extensions (SGX)"], # Put these last "OBSOLETE" => [$f++, "Instruction removed from architecture"], "VEX" => [$f++, "VEX or XOP encoded instruction"], "EVEX" => [$f++, "EVEX encoded instruction"], # # dword bound - cpu type flags # # The CYRIX and AMD flags should have the highest bit values; the # disassembler selection algorithm depends on it. # "8086" => [${dword_align(\$f)}++, "8086"], "186" => [$f++, "186+"], "286" => [$f++, "286+"], "386" => [$f++, "386+"], "486" => [$f++, "486+"], "PENT" => [$f++, "Pentium"], "P6" => [$f++, "P6"], "KATMAI" => [$f++, "Katmai"], "WILLAMETTE" => [$f++, "Willamette"], "PRESCOTT" => [$f++, "Prescott"], "X86_64" => [$f++, "x86-64 (long or legacy mode)"], "NEHALEM" => [$f++, "Nehalem"], "WESTMERE" => [$f++, "Westmere"], "SANDYBRIDGE" => [$f++, "Sandy Bridge"], "FUTURE" => [$f++, "Future processor (not yet disclosed)"], "IA64" => [$f++, "IA64 (in x86 mode)"], # Put these last "CYRIX" => [$f++, "Cyrix-specific"], "AMD" => [$f++, "AMD-specific"], ); my %insns_flag_hash = (); my @insns_flag_values = (); my $iflag_words; sub get_flag_words() { my $max = -1; foreach my $vp (values(%insns_flag_bit)) { if ($vp->[0] > $max) { $max = $vp->[0]; } } return int($max/32)+1; } sub insns_flag_index(@) { return undef if $_[0] eq "ignore"; my @prekey = sort(@_); my $key = join("", @prekey); if (not defined($insns_flag_hash{$key})) { my @newkey = (0) x $iflag_words; for my $i (@prekey) { die "No key for $i\n" if not defined($insns_flag_bit{$i}); $newkey[$insns_flag_bit{$i}[0]/32] |= (1 << ($insns_flag_bit{$i}[0] % 32)); } my $str = join(',', map { sprintf("UINT32_C(0x%08x)",$_) } @newkey); push @insns_flag_values, $str; $insns_flag_hash{$key} = $#insns_flag_values; } return $insns_flag_hash{$key}; } sub write_iflaggen_h() { print STDERR "Writing $oname...\n"; open(N, '>', $oname) or die "$0: $!\n"; print N "/* This file is auto-generated. Don't edit. */\n"; print N "#ifndef NASM_IFLAGGEN_H\n"; print N "#define NASM_IFLAGGEN_H 1\n\n"; my @flagnames = keys(%insns_flag_bit); @flagnames = sort { $insns_flag_bit{$a}->[0] <=> $insns_flag_bit{$b}->[0] } @flagnames; my $next = 0; foreach my $key (@flagnames) { my $v = $insns_flag_bit{$key}; if ($v->[0] > $next) { printf N "%-31s /* %-64s */\n", '', ($next != $v->[0]-1) ? sprintf("%d...%d unused", $next, $v->[0]-1) : sprintf("%d unused", $next); } print N sprintf("#define IF_%-16s %3d /* %-64s */\n", $key, $v->[0], $v->[1]); $next = $v->[0] + 1; } print N "\n"; printf N "#define IF_FIELD_COUNT %d\n", $iflag_words; print N "typedef struct {\n"; print N " uint32_t field[IF_FIELD_COUNT];\n"; print N "} iflag_t;\n"; print N "\n"; printf N "extern const iflag_t insns_flags[%d];\n\n", $#insns_flag_values + 1; print N "#endif /* NASM_IFLAGGEN_H */\n"; close N; } sub write_iflag_c() { print STDERR "Writing $oname...\n"; open(N, '>', $oname) or die "$0: $!\n"; print N "/* This file is auto-generated. Don't edit. */\n"; print N "#include \"iflag.h\"\n\n"; print N "/* Global flags referenced from instruction templates */\n"; printf N "const iflag_t insns_flags[%d] = {\n", $#insns_flag_values + 1; foreach my $i (0 .. $#insns_flag_values) { print N sprintf(" /* %4d */ {{ %s }},\n", $i, $insns_flag_values[$i]); } print N "};\n\n"; close N; } $iflag_words = get_flag_words(); 1;