]> granicus.if.org Git - yasm/commitdiff
Rewrite x86 identifier recognition to use a minimal perfect hash table
authorPeter Johnson <peter@tortall.net>
Sat, 4 Mar 2006 22:09:26 +0000 (22:09 -0000)
committerPeter Johnson <peter@tortall.net>
Sat, 4 Mar 2006 22:09:26 +0000 (22:09 -0000)
instead of re2c-generated code.  This gives identifier recognition a
significant speedup and also drastically shortens compilation time of yasm
itself.  This rewrite encouraged combining instruction and prefix
recognition into one function and register and target modifier
recognition into a second function (rather than having 5 or so separate
functions).

Also created a state in the NASM parser (as was done in the GAS parser),
so instructions/prefixes are only looked for until an instruction is
recognized.  This avoids search time in the instructions hash for operands.

The tool used to generate the new identifier recognition is called GAP.
Someday we might extend this to generate more code than just the perfect
hash lookup.

* tools/gap: New tool to Generate Architecture Parser (aka perfect hashes).
* phash.c, phash.h: Helper functions used by GAP-generated code.

* x86id.re: Delete.  Split into..
* x86parse.gap: Contains all identifier recognition portions.
* x86id.c: Contains instruction operand tables and code and higher-level
entry points into x86parse.gap perfect hash recognizers.  Chose to flow
history of x86id.re into this file.

* arch.h: Combine instruction/prefix entry points and register/target
modifier entry points.
* lc3barch.c, lc3bid.re, lc3barch.h: Update to match.
* x86arch.c, x86arch.h: Update to match.

* Makefile.am, various Makefile.inc: Update.
* POTFILES.in: Update due to numerous file changes (not just this commit).
* Mkfiles: Update.  VC build files untested at the moment.

svn path=/trunk/yasm/; revision=1395

36 files changed:
Makefile.am
Mkfiles/Makefile.dj
Mkfiles/Makefile.flat
Mkfiles/vc/gap/gap.vcproj [new file with mode: 0644]
Mkfiles/vc/gap/run.bat [new file with mode: 0644]
Mkfiles/vc/modules/modules.vcproj
Mkfiles/vc/re2c/run.bat
Mkfiles/vc/yasm.sln
Mkfiles/vc8/gap/gap.vcproj [new file with mode: 0644]
Mkfiles/vc8/gap/run.bat [new file with mode: 0644]
Mkfiles/vc8/modules/modules.vcproj
Mkfiles/vc8/re2c/run.bat
Mkfiles/vc8/yasm.sln
libyasm/Makefile.inc
libyasm/arch.h
libyasm/phash.c [new file with mode: 0644]
libyasm/phash.h [new file with mode: 0644]
modules/arch/lc3b/lc3barch.c
modules/arch/lc3b/lc3barch.h
modules/arch/lc3b/lc3bid.re
modules/arch/x86/Makefile.inc
modules/arch/x86/x86arch.c
modules/arch/x86/x86arch.h
modules/arch/x86/x86id.c [moved from modules/arch/x86/x86id.re with 65% similarity]
modules/arch/x86/x86parse.gap [new file with mode: 0644]
modules/parsers/gas/gas-token.re
modules/parsers/nasm/nasm-bison.y
modules/parsers/nasm/nasm-parser.h
modules/parsers/nasm/nasm-token.re
po/POTFILES.in
tools/Makefile.inc
tools/gap/Makefile.inc [new file with mode: 0644]
tools/gap/gap.c [new file with mode: 0644]
tools/gap/perfect.c [new file with mode: 0644]
tools/gap/perfect.h [new file with mode: 0644]
tools/gap/standard.h [new file with mode: 0644]

index 8e938d6111d8212812cd8329a8a00f3c5f053e51..45e5dde36c140e4ced4f8a985c6f21e4079777d9 100644 (file)
@@ -67,6 +67,8 @@ EXTRA_DIST += Mkfiles/vc/libyasm/libyasm.vcproj
 EXTRA_DIST += Mkfiles/vc/modules/modules.vcproj
 EXTRA_DIST += Mkfiles/vc/re2c/re2c.vcproj
 EXTRA_DIST += Mkfiles/vc/re2c/run.bat
+EXTRA_DIST += Mkfiles/vc/gap/gap.vcproj
+EXTRA_DIST += Mkfiles/vc/gap/run.bat
 EXTRA_DIST += Mkfiles/vc8/yasm.sln
 EXTRA_DIST += Mkfiles/vc8/yasm.vcproj
 EXTRA_DIST += Mkfiles/vc8/config.h
@@ -81,6 +83,8 @@ EXTRA_DIST += Mkfiles/vc8/libyasm/libyasm.vcproj
 EXTRA_DIST += Mkfiles/vc8/modules/modules.vcproj
 EXTRA_DIST += Mkfiles/vc8/re2c/re2c.vcproj
 EXTRA_DIST += Mkfiles/vc8/re2c/run.bat
+EXTRA_DIST += Mkfiles/vc8/gap/gap.vcproj
+EXTRA_DIST += Mkfiles/vc8/gap/run.bat
 
 # Until this gets fixed in automake
 DISTCLEANFILES = libyasm/stamp-h libyasm/stamp-h[0-9]*
index 4ddcb66466c7fe8e748313963c36b94510554489..94f3a01a11ef6f110f2b20b07279a17377f9054b 100644 (file)
@@ -28,6 +28,7 @@ LIBYASM_OBJS= \
  libyasm/intnum.o \
  libyasm/linemgr.o \
  libyasm/mergesort.o \
+ libyasm/phash.o \
  libyasm/section.o \
  libyasm/splitpath.o \
  libyasm/strcasecmp.o \
@@ -42,7 +43,7 @@ MODULES_ARCH_X86_OBJS= \
  modules/arch/x86/x86arch.o \
  modules/arch/x86/x86bc.o \
  modules/arch/x86/x86expr.o \
- x86id.o
modules/arch/x86/x86id.o
 YASM_MODULES=arch_x86
 
 MODULES_ARCH_LC3B_OBJS= \
@@ -133,7 +134,7 @@ genmacro: modules/preprocs/nasm/genmacro.c
        $(BUILDCC) -o $@ $<
 
 nasm-macros.c: modules/preprocs/nasm/standard.mac genmacro
-       ./genmacro $<
+       ./genmacro modules/preprocs/nasm/standard.mac
 
 modules/preprocs/nasm/nasm-pp.c: nasm-macros.c
 
@@ -141,19 +142,21 @@ genmodule: libyasm/genmodule.c
        $(BUILDCC) -o $@ $<
 
 module.c: libyasm/module.in genmodule
-       ./genmodule $< $(YASM_MODULES)
+       ./genmodule libyasm/module.in $(YASM_MODULES)
 
-x86id.c: modules/arch/x86/x86id.re re2c
-       ./re2c -s -o $@ $<
+x86parse.c: modules/arch/x86/x86parse.gap gap
+       ./gap modules/arch/x86/x86parse.gap $@
+
+modules/arch/x86/x86id.c: x86parse.c
 
 lc3bid.c: modules/arch/lc3b/lc3bid.re re2c
-       ./re2c -s -o $@ $<
+       ./re2c -s -o $@ modules/arch/lc3b/lc3bid.re
 
 gas-token.c: modules/parsers/gas/gas-token.re re2c
-       ./re2c -b -o $@ $<
+       ./re2c -b -o $@ modules/parsers/gas/gas-token.re
 
 nasm-token.c: modules/parsers/nasm/nasm-token.re re2c
-       ./re2c -b -o $@ $<
+       ./re2c -b -o $@ modules/parsers/nasm/nasm-token.re
 
 RE2C_SRCS= \
        tools/re2c/main.c \
@@ -169,6 +172,17 @@ RE2C_SRCS= \
 re2c: $(RE2C_SRCS)
        $(BUILDCC) -I. -o re2c $(RE2C_SRCS)
 
+GAP_SRCS= \
+       tools/gap/gap.c \
+       tools/gap/perfect.c \
+       libyasm/phash.c \
+       libyasm/hamt.c \
+       libyasm/xmalloc.c \
+       libyasm/xstrdup.c
+
+gap: $(GAP_SRCS)
+       $(BUILDCC) -I. -o gap $(GAP_SRCS)
+
 yasm: $(YASM_OBJS)
        $(CC) -o yasm $(YASM_OBJS)
 
index b72e09fb6a35c24a59793701a8dc9a36664b6ac7..6752935e186cd596584da70765e7cd65670a211c 100644 (file)
@@ -9,8 +9,8 @@
 # NOTE: Needs a valid config.h for the platform being compiled on.
 #
 # This file should be customized to particular platforms by changing CC and
-#  CFLAGS appropriately, along with writing a config.h for the platform and
-#  placing it in a libyasm subdirectory.
+#  CFLAGS appropriately, along with writing a config.h and _stdint.h for the
+#  platform and placing them in a subdirectory of Mkfiles.
 
 CFLAGS=-DHAVE_CONFIG_H -IMkfiles -I.
 CC?=gcc
@@ -31,6 +31,7 @@ LIBYASM_OBJS= \
  libyasm/intnum.o \
  libyasm/linemgr.o \
  libyasm/mergesort.o \
+ libyasm/phash.o \
  libyasm/section.o \
  libyasm/splitpath.o \
  libyasm/strcasecmp.o \
@@ -45,7 +46,7 @@ MODULES_ARCH_X86_OBJS= \
  modules/arch/x86/x86arch.o \
  modules/arch/x86/x86bc.o \
  modules/arch/x86/x86expr.o \
- x86id.o
modules/arch/x86/x86id.o
 YASM_MODULES=arch_x86
 
 MODULES_ARCH_LC3B_OBJS= \
@@ -136,7 +137,7 @@ genmacro: modules/preprocs/nasm/genmacro.c
        $(BUILDCC) -o $@ $<
 
 nasm-macros.c: modules/preprocs/nasm/standard.mac genmacro
-       ./genmacro $<
+       ./genmacro modules/preprocs/nasm/standard.mac
 
 modules/preprocs/nasm/nasm-pp.c: nasm-macros.c
 
@@ -144,19 +145,21 @@ genmodule: libyasm/genmodule.c
        $(BUILDCC) -o $@ $<
 
 module.c: libyasm/module.in genmodule
-       ./genmodule $< $(YASM_MODULES)
+       ./genmodule libyasm/module.in $(YASM_MODULES)
 
-x86id.c: modules/arch/x86/x86id.re re2c
-       ./re2c -s -o $@ $<
+x86parse.c: modules/arch/x86/x86parse.gap gap
+       ./gap modules/arch/x86/x86parse.gap $@
+
+modules/arch/x86/x86id.c: x86parse.c
 
 lc3bid.c: modules/arch/lc3b/lc3bid.re re2c
-       ./re2c -s -o $@ $<
+       ./re2c -s -o $@ modules/arch/lc3b/lc3bid.re
 
 gas-token.c: modules/parsers/gas/gas-token.re re2c
-       ./re2c -b -o $@ $<
+       ./re2c -b -o $@ modules/parsers/gas/gas-token.re
 
 nasm-token.c: modules/parsers/nasm/nasm-token.re re2c
-       ./re2c -b -o $@ $<
+       ./re2c -b -o $@ modules/parsers/nasm/nasm-token.re
 
 RE2C_SRCS= \
        tools/re2c/main.c \
@@ -172,6 +175,17 @@ RE2C_SRCS= \
 re2c: $(RE2C_SRCS)
        $(BUILDCC) -I. -o re2c $(RE2C_SRCS)
 
+GAP_SRCS= \
+       tools/gap/gap.c \
+       tools/gap/perfect.c \
+       libyasm/phash.c \
+       libyasm/hamt.c \
+       libyasm/xmalloc.c \
+       libyasm/xstrdup.c
+
+gap: $(GAP_SRCS)
+       $(BUILDCC) -I. -o gap $(GAP_SRCS)
+
 yasm: $(YASM_OBJS)
        $(CC) -o yasm $(YASM_OBJS)
 
diff --git a/Mkfiles/vc/gap/gap.vcproj b/Mkfiles/vc/gap/gap.vcproj
new file mode 100644 (file)
index 0000000..6bc06a0
--- /dev/null
@@ -0,0 +1,161 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="7.10"\r
+       Name="gap"\r
+       ProjectGUID="{5758BF4E-ABC4-11DA-B012-B622A1EF5492}"\r
+       RootNamespace="gap"\r
+       Keyword="Win32Proj">\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"/>\r
+       </Platforms>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="Debug"\r
+                       IntermediateDirectory="Debug"\r
+                       ConfigurationType="1"\r
+                       CharacterSet="2">\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories="..,../../.."\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"\r
+                               MinimalRebuild="TRUE"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="5"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="TRUE"\r
+                               DebugInformationFormat="4"/>\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"/>\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               OutputFile="$(OutDir)/gap.exe"\r
+                               LinkIncremental="2"\r
+                               GenerateDebugInformation="TRUE"\r
+                               ProgramDatabaseFile="$(OutDir)/gap.pdb"\r
+                               SubSystem="1"\r
+                               TargetMachine="1"/>\r
+                       <Tool\r
+                               Name="VCMIDLTool"/>\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                               CommandLine="run.bat &quot;$(TargetPath)&quot;"/>\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"/>\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"/>\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"/>\r
+                       <Tool\r
+                               Name="VCManagedWrapperGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCAuxiliaryManagedWrapperGeneratorTool"/>\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="Release"\r
+                       IntermediateDirectory="Release"\r
+                       ConfigurationType="1"\r
+                       CharacterSet="2">\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               AdditionalIncludeDirectories="..,../../.."\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"\r
+                               RuntimeLibrary="4"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="TRUE"\r
+                               DebugInformationFormat="3"/>\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"/>\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               OutputFile="$(OutDir)/gap.exe"\r
+                               LinkIncremental="1"\r
+                               GenerateDebugInformation="TRUE"\r
+                               SubSystem="1"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               TargetMachine="1"/>\r
+                       <Tool\r
+                               Name="VCMIDLTool"/>\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                               CommandLine="run.bat &quot;$(TargetPath)&quot;"/>\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"/>\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"/>\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"/>\r
+                       <Tool\r
+                               Name="VCManagedWrapperGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCAuxiliaryManagedWrapperGeneratorTool"/>\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{7D996CB2-ABC4-11DA-B012-B622A1EF5492}">\r
+                       <File\r
+                               RelativePath="..\..\..\tools\gap\gap.c">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\tools\gap\perfect.c">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\libyasm\phash.c">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\libyasm\hamt.c">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\libyasm\xmalloc.c">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\libyasm\xstrdup.c">\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{85DD7A94-ABC4-11DA-B012-B622A1EF5492}">\r
+                       <File\r
+                               RelativePath="..\..\..\tools\gap\perfect.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\tools\gap\standard.h">\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Resource Files"\r
+                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"\r
+                       UniqueIdentifier="{8EB9B268-ABC4-11DA-B012-B622A1EF5492}">\r
+               </Filter>\r
+               <File\r
+                       RelativePath=".\run.bat">\r
+               </File>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/Mkfiles/vc/gap/run.bat b/Mkfiles/vc/gap/run.bat
new file mode 100644 (file)
index 0000000..d506080
--- /dev/null
@@ -0,0 +1,2 @@
+cd ..\..\..\\r
+%1 modules\arch\x86\x86parse.gap x86parse.c\r
index 06b9c79f4e18dd2fd1c4599087aba3bd5ef7387e..fd030f0de339c127a5338ae996945a9cca4838c8 100644 (file)
                                        </FileConfiguration>\r
                                </File>\r
                                <File\r
-                                       RelativePath="..\..\..\x86id.c">\r
+                                       RelativePath="..\..\..\modules\arch\x86\x86id.c">\r
                                        <FileConfiguration\r
                                                Name="Release|Win32">\r
                                                <Tool\r
index e2b513773e4fac9c2c5f2099882c63755160ea9f..cde2a7b6c8f5b809f7b976576ad82f07658fe518 100644 (file)
@@ -1,5 +1,4 @@
 cd ..\..\..\\r
-%1 -s modules\arch\lc3b\lc3bid.re > lc3bid.c\r
-%1 -s modules\arch\x86\x86id.re > x86id.c\r
-%1 -s modules\parsers\nasm\nasm-token.re > nasm-token.c\r
-%1 -s modules\parsers\gas\gas-token.re > gas-token.c\r
+%1 -s -o lc3bid.c modules\arch\lc3b\lc3bid.re\r
+%1 -b -o nasm-token.c modules\parsers\nasm\nasm-token.re\r
+%1 -b -o gas-token.c modules\parsers\gas\gas-token.re\r
index 56bcfd3f50dffb6a7f12e2c32fe0b5d84f234edd..e496f2da23a1444caf1538061f93c31641a8a28f 100644 (file)
@@ -7,6 +7,7 @@ EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "modules", "modules\modules.vcproj", "{D715A3D4-EFAA-442E-AD8B-5B4FF64E1DD6}"\r
        ProjectSection(ProjectDependencies) = postProject\r
                {3C58BE13-50A3-4583-984D-D8902B3D7713} = {3C58BE13-50A3-4583-984D-D8902B3D7713}\r
+               {5758BF4E-ABC4-11DA-B012-B622A1EF5492} = {5758BF4E-ABC4-11DA-B012-B622A1EF5492}\r
                {29FE7874-1256-4AD6-B889-68E399DC9608} = {29FE7874-1256-4AD6-B889-68E399DC9608}\r
                {225700A5-07B8-434E-AD61-555278BF6733} = {225700A5-07B8-434E-AD61-555278BF6733}\r
        EndProjectSection\r
@@ -25,6 +26,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "re2c", "re2c\re2c.vcproj",
        ProjectSection(ProjectDependencies) = postProject\r
        EndProjectSection\r
 EndProject\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gap", "gap\gap.vcproj", "{5758BF4E-ABC4-11DA-B012-B622A1EF5492}"\r
+       ProjectSection(ProjectDependencies) = postProject\r
+       EndProjectSection\r
+EndProject\r
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "genmodule", "genmodule\genmodule.vcproj", "{F0E8B707-00C5-4FF2-B8EF-7C39817132A0}"\r
        ProjectSection(ProjectDependencies) = postProject\r
        EndProjectSection\r
@@ -55,6 +60,10 @@ Global
                {3C58BE13-50A3-4583-984D-D8902B3D7713}.Debug.Build.0 = Debug|Win32\r
                {3C58BE13-50A3-4583-984D-D8902B3D7713}.Release.ActiveCfg = Release|Win32\r
                {3C58BE13-50A3-4583-984D-D8902B3D7713}.Release.Build.0 = Release|Win32\r
+               {5758BF4E-ABC4-11DA-B012-B622A1EF5492}.Debug.ActiveCfg = Debug|Win32\r
+               {5758BF4E-ABC4-11DA-B012-B622A1EF5492}.Debug.Build.0 = Debug|Win32\r
+               {5758BF4E-ABC4-11DA-B012-B622A1EF5492}.Release.ActiveCfg = Release|Win32\r
+               {5758BF4E-ABC4-11DA-B012-B622A1EF5492}.Release.Build.0 = Release|Win32\r
                {F0E8B707-00C5-4FF2-B8EF-7C39817132A0}.Debug.ActiveCfg = Debug|Win32\r
                {F0E8B707-00C5-4FF2-B8EF-7C39817132A0}.Debug.Build.0 = Debug|Win32\r
                {F0E8B707-00C5-4FF2-B8EF-7C39817132A0}.Release.ActiveCfg = Release|Win32\r
diff --git a/Mkfiles/vc8/gap/gap.vcproj b/Mkfiles/vc8/gap/gap.vcproj
new file mode 100644 (file)
index 0000000..9643eac
--- /dev/null
@@ -0,0 +1,235 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="gap"\r
+       ProjectGUID="{5758BF4E-ABC4-11DA-B012-B622A1EF5492}"\r
+       RootNamespace="gap"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
+                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
+                       ConfigurationType="1"\r
+                       CharacterSet="2"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories="..,../../.."\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               UsePrecompiledHeader="0"\r
+                               ProgramDataBaseFileName="$(IntDir)\"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="4"\r
+                               CompileAs="0"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               OutputFile="$(OutDir)/gap.exe"\r
+                               LinkIncremental="2"\r
+                               GenerateDebugInformation="true"\r
+                               ProgramDatabaseFile="$(OutDir)\$(TargetName).pdb"\r
+                               SubSystem="1"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                               CommandLine="run.bat &quot;$(TargetPath)&quot;"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
+                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
+                       ConfigurationType="1"\r
+                       CharacterSet="2"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="3"\r
+                               AdditionalIncludeDirectories="..,../../.."\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"\r
+                               RuntimeLibrary="0"\r
+                               UsePrecompiledHeader="0"\r
+                               ProgramDataBaseFileName="$(IntDir)\"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                               CompileAs="0"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               OutputFile="$(OutDir)/gap.exe"\r
+                               LinkIncremental="1"\r
+                               GenerateDebugInformation="false"\r
+                               ProgramDatabaseFile="$(OutDir)\$(TargetName).pdb"\r
+                               SubSystem="1"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                               CommandLine="run.bat &quot;$(TargetPath)&quot;"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{7D996CB2-ABC4-11DA-B012-B622A1EF5492}"\r
+                       >\r
+                       <File\r
+                               RelativePath="..\..\..\tools\gap\gap.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\tools\gap\perfect.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\libyasm\phash.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\libyasm\hamt.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\libyasm\xmalloc.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\libyasm\xstrdup.c"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{85DD7A94-ABC4-11DA-B012-B622A1EF5492}"\r
+                       >\r
+                       <File\r
+                               RelativePath="..\..\..\tools\gap\perfect.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\tools\gap\standard.h"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <File\r
+                       RelativePath=".\run.bat"\r
+                       >\r
+               </File>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/Mkfiles/vc8/gap/run.bat b/Mkfiles/vc8/gap/run.bat
new file mode 100644 (file)
index 0000000..d506080
--- /dev/null
@@ -0,0 +1,2 @@
+cd ..\..\..\\r
+%1 modules\arch\x86\x86parse.gap x86parse.c\r
index 0f4fe881a20f25efc6e1b24038444b9549c83cd2..5584e5c7ec40dcdf947fa75fea6c54db5c435212 100644 (file)
                                        </FileConfiguration>\r
                                </File>\r
                                <File\r
-                                       RelativePath="..\..\..\x86id.c"\r
+                                       RelativePath="..\..\..\modules\arch\x86\x86id.c"\r
                                        >\r
                                </File>\r
                        </Filter>\r
index e2b513773e4fac9c2c5f2099882c63755160ea9f..cde2a7b6c8f5b809f7b976576ad82f07658fe518 100644 (file)
@@ -1,5 +1,4 @@
 cd ..\..\..\\r
-%1 -s modules\arch\lc3b\lc3bid.re > lc3bid.c\r
-%1 -s modules\arch\x86\x86id.re > x86id.c\r
-%1 -s modules\parsers\nasm\nasm-token.re > nasm-token.c\r
-%1 -s modules\parsers\gas\gas-token.re > gas-token.c\r
+%1 -s -o lc3bid.c modules\arch\lc3b\lc3bid.re\r
+%1 -b -o nasm-token.c modules\parsers\nasm\nasm-token.re\r
+%1 -b -o gas-token.c modules\parsers\gas\gas-token.re\r
index 6fb44f4d619d01df74d43ff6e236854c1209beaf..274cf5bdb8f82fc18c7d6d735ccd378788b6b0a2 100644 (file)
@@ -8,6 +8,7 @@ EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "modules", "modules\modules.vcproj", "{D715A3D4-EFAA-442E-AD8B-5B4FF64E1DD6}"\r
        ProjectSection(ProjectDependencies) = postProject\r
                {3C58BE13-50A3-4583-984D-D8902B3D7713} = {3C58BE13-50A3-4583-984D-D8902B3D7713}\r
+               {5758BF4E-ABC4-11DA-B012-B622A1EF5492} = {5758BF4E-ABC4-11DA-B012-B622A1EF5492}\r
                {29FE7874-1256-4AD6-B889-68E399DC9608} = {29FE7874-1256-4AD6-B889-68E399DC9608}\r
                {225700A5-07B8-434E-AD61-555278BF6733} = {225700A5-07B8-434E-AD61-555278BF6733}\r
        EndProjectSection\r
@@ -22,6 +23,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "genmacro", "genmacro\genmac
 EndProject\r
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "re2c", "re2c\re2c.vcproj", "{3C58BE13-50A3-4583-984D-D8902B3D7713}"\r
 EndProject\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gap", "gap\gap.vcproj", "{5758BF4E-ABC4-11DA-B012-B622A1EF5492}"\r
+EndProject\r
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "genmodule", "genmodule\genmodule.vcproj", "{F0E8B707-00C5-4FF2-B8EF-7C39817132A0}"\r
 EndProject\r
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{825AC694-358C-4D8D-92DE-33A2691978CE}"\r
@@ -77,6 +80,14 @@ Global
                {3C58BE13-50A3-4583-984D-D8902B3D7713}.Release|Win32.Build.0 = Release|Win32\r
                {3C58BE13-50A3-4583-984D-D8902B3D7713}.Release|x64.ActiveCfg = Release|Win32\r
                {3C58BE13-50A3-4583-984D-D8902B3D7713}.Release|x64.Build.0 = Release|Win32\r
+               {5758BF4E-ABC4-11DA-B012-B622A1EF5492}.Debug|Win32.ActiveCfg = Debug|Win32\r
+               {5758BF4E-ABC4-11DA-B012-B622A1EF5492}.Debug|Win32.Build.0 = Debug|Win32\r
+               {5758BF4E-ABC4-11DA-B012-B622A1EF5492}.Debug|x64.ActiveCfg = Debug|Win32\r
+               {5758BF4E-ABC4-11DA-B012-B622A1EF5492}.Debug|x64.Build.0 = Debug|Win32\r
+               {5758BF4E-ABC4-11DA-B012-B622A1EF5492}.Release|Win32.ActiveCfg = Release|Win32\r
+               {5758BF4E-ABC4-11DA-B012-B622A1EF5492}.Release|Win32.Build.0 = Release|Win32\r
+               {5758BF4E-ABC4-11DA-B012-B622A1EF5492}.Release|x64.ActiveCfg = Release|Win32\r
+               {5758BF4E-ABC4-11DA-B012-B622A1EF5492}.Release|x64.Build.0 = Release|Win32\r
                {F0E8B707-00C5-4FF2-B8EF-7C39817132A0}.Debug|Win32.ActiveCfg = Debug|Win32\r
                {F0E8B707-00C5-4FF2-B8EF-7C39817132A0}.Debug|Win32.Build.0 = Debug|Win32\r
                {F0E8B707-00C5-4FF2-B8EF-7C39817132A0}.Debug|x64.ActiveCfg = Debug|Win32\r
index b220a2a88d8e0c7c72626a8e7ea85682232bf4d1..3dba3592554b697f83ad0af69793d73bff442964 100644 (file)
@@ -14,6 +14,7 @@ libyasm_a_SOURCES += libyasm/valparam.c
 libyasm_a_SOURCES += libyasm/errwarn.c
 libyasm_a_SOURCES += libyasm/linemgr.c
 libyasm_a_SOURCES += libyasm/assocdat.c
+libyasm_a_SOURCES += libyasm/phash.c
 libyasm_a_SOURCES += libyasm/xmalloc.c
 libyasm_a_SOURCES += libyasm/xstrdup.c
 libyasm_a_SOURCES += libyasm/strcasecmp.c
@@ -66,6 +67,7 @@ modinclude_HEADERS += libyasm/bitvect.h
 modinclude_HEADERS += libyasm/valparam.h
 modinclude_HEADERS += libyasm/compat-queue.h
 modinclude_HEADERS += libyasm/assocdat.h
+modinclude_HEADERS += libyasm/phash.h
 modinclude_HEADERS += libyasm/module.h
 
 EXTRA_DIST += libyasm/tests/Makefile.inc
index bb414355678e7078528380db4e85beacbcf2c43b..31f56868930a8e80bbe931deec4f7ad132624cb3 100644 (file)
@@ -41,6 +41,24 @@ typedef enum {
     YASM_ARCH_CREATE_BAD_PARSER                /**< Unrecognized parser name. */
 } yasm_arch_create_error;
 
+/** Return values for yasm_arch_module::parse_check_insnprefix(). */
+typedef enum {
+    YASM_ARCH_NOTINSNPREFIX = 0,       /**< Unrecognized */
+    YASM_ARCH_INSN,                    /**< An instruction */
+    YASM_ARCH_PREFIX                   /**< An instruction prefix */
+} yasm_arch_insnprefix;
+
+/** Types of registers / target modifiers that may be returned by
+ * yasm_arch_module::parse_check_regtmod().
+ */
+typedef enum {
+    YASM_ARCH_NOTREGTMOD = 0,          /**< Unrecognized */
+    YASM_ARCH_REG,                     /**< A "normal" register */
+    YASM_ARCH_REGGROUP,                        /**< A group of indexable registers */
+    YASM_ARCH_SEGREG,                  /**< A segment register */
+    YASM_ARCH_TARGETMOD                        /**< A target modifier (for jumps) */
+} yasm_arch_regtmod;
+
 /** An instruction operand (opaque type). */
 typedef struct yasm_insn_operand yasm_insn_operand;
 #ifdef YASM_LIB_INTERNAL
@@ -118,50 +136,22 @@ typedef struct yasm_arch_module {
     /** Module-level implementation of yasm_arch_parse_cpu().
      * Call yasm_arch_parse_cpu() instead of calling this function.
      */
-    void (*parse_cpu) (yasm_arch *arch, const char *cpuid,
+    void (*parse_cpu) (yasm_arch *arch, const char *cpuid, size_t cpuid_len,
                       unsigned long line);
 
-    /** Module-level implementation of yasm_arch_parse_check_reg().
-     * Call yasm_arch_parse_check_reg() instead of calling this function.
+    /** Module-level implementation of yasm_arch_parse_check_insnprefix().
+     * Call yasm_arch_parse_check_insnprefix() instead of calling this function.
      */
-    int (*parse_check_reg)
-       (yasm_arch *arch, /*@out@*/ unsigned long data[1], const char *id,
-        unsigned long line);
-
-    /** Module-level implementation of yasm_arch_parse_check_reggroup().
-     * Call yasm_arch_parse_check_reggroup() instead of calling this function.
-     */
-    int (*parse_check_reggroup)
-       (yasm_arch *arch, /*@out@*/ unsigned long data[1], const char *id,
-        unsigned long line);
-
-    /** Module-level implementation of yasm_arch_parse_check_segreg().
-     * Call yasm_arch_parse_check_segreg() instead of calling this function.
-     */
-    int (*parse_check_segreg)
-       (yasm_arch *arch, /*@out@*/ unsigned long data[1], const char *id,
-        unsigned long line);
-
-    /** Module-level implementation of yasm_arch_parse_check_insn().
-     * Call yasm_arch_parse_check_insn() instead of calling this function.
-     */
-    int (*parse_check_insn)
+    yasm_arch_insnprefix (*parse_check_insnprefix)
        (yasm_arch *arch, /*@out@*/ unsigned long data[4], const char *id,
-        unsigned long line);
+        size_t id_len, unsigned long line);
 
-    /** Module-level implementation of yasm_arch_parse_check_prefix().
-     * Call yasm_arch_parse_check_prefix() instead of calling this function.
+    /** Module-level implementation of yasm_arch_parse_check_regtmod().
+     * Call yasm_arch_parse_check_regtmod() instead of calling this function.
      */
-    int (*parse_check_prefix)
-       (yasm_arch *arch, /*@out@*/ unsigned long data[4], const char *id,
-        unsigned long line);
-
-    /** Module-level implementation of yasm_arch_parse_check_targetmod().
-     * Call yasm_arch_parse_check_targetmod() instead of calling this function.
-     */
-    int (*parse_check_targetmod)
-       (yasm_arch *arch, /*@out@*/ unsigned long data[1], const char *id,
-        unsigned long line);
+    yasm_arch_regtmod (*parse_check_regtmod)
+       (yasm_arch *arch, /*@out@*/ unsigned long *data, const char *id,
+        size_t id_len, unsigned long line);
 
     /** Module-level implementation of yasm_arch_parse_directive().
      * Call yasm_arch_parse_directive() instead of calling this function.
@@ -364,108 +354,47 @@ int yasm_arch_set_var(yasm_arch *arch, const char *var, unsigned long val);
 /** Switch available instructions/registers/etc based on a user-specified
  * CPU identifier.  Should modify behavior ONLY of parse_* functions!  The
  * bytecode and output functions should be able to handle any CPU.
- * \param arch architecture
- * \param cpuid        cpu identifier as in the input file
- * \param line virtual line (from yasm_linemap)
+ * \param arch         architecture
+ * \param cpuid                cpu identifier as in the input file
+ * \param cpuid_len    length of cpu identifier string
+ * \param line         virtual line (from yasm_linemap)
  */
-void yasm_arch_parse_cpu(yasm_arch *arch, const char *cpuid,
+void yasm_arch_parse_cpu(yasm_arch *arch, const char *cpuid, size_t cpuid_len,
                         unsigned long line);
 
 /** Check an generic identifier to see if it matches architecture specific
- * names for registers.  Unrecognized identifiers should return 0
- * so they can be treated as normal symbols.  Any additional data beyond
- * just the type (almost always necessary) should be returned into the
- * space provided by the data parameter.
- * \param arch architecture
- * \param data extra identification information (yasm_arch-specific)
- *             [output]
- * \param id   identifier as in the input file
- * \param line virtual line (from yasm_linemap)
- * \return 1 if id is a register, 0 if not.
- */
-int yasm_arch_parse_check_reg
-    (yasm_arch *arch, /*@out@*/ unsigned long data[1], const char *id,
-     unsigned long line);
-
-/** Check an generic identifier to see if it matches architecture specific
- * names for register groups.  Unrecognized identifiers should return 0
- * so they can be treated as normal symbols.  Any additional data beyond
- * just the type (almost always necessary) should be returned into the
- * space provided by the data parameter.
- * \param arch architecture
- * \param data extra identification information (yasm_arch-specific)
- *             [output]
- * \param id   identifier as in the input file
- * \param line virtual line (from yasm_linemap)
- * \return 1 if id is a register, 0 if not.
- */
-int yasm_arch_parse_check_reggroup
-    (yasm_arch *arch, /*@out@*/ unsigned long data[1], const char *id,
-     unsigned long line);
-
-/** Check an generic identifier to see if it matches architecture specific
- * names for segment registers.  Unrecognized identifiers should return 0
- * so they can be treated as normal symbols.  Any additional data beyond
- * just the type (almost always necessary) should be returned into the
- * space provided by the data parameter.
- * \param arch architecture
- * \param data extra identification information (yasm_arch-specific)
- *             [output]
- * \param id   identifier as in the input file
- * \param line virtual line (from yasm_linemap)
- * \return 1 if id is a register, 0 if not.
- */
-int yasm_arch_parse_check_segreg
-    (yasm_arch *arch, /*@out@*/ unsigned long data[1], const char *id,
-     unsigned long line);
-
-/** Check an generic identifier to see if it matches architecture specific
- * names for instructions.  Unrecognized identifiers should return 0
- * so they can be treated as normal symbols.  Any additional data beyond
- * just the type (almost always necessary) should be returned into the
- * space provided by the data parameter.
- * \param arch architecture
- * \param data extra identification information (yasm_arch-specific)
- *             [output]
- * \param id   identifier as in the input file
- * \param line virtual line (from yasm_linemap)
- * \return 1 if id is a register, 0 if not.
- */
-int yasm_arch_parse_check_insn
-    (yasm_arch *arch, /*@out@*/ unsigned long data[4], const char *id,
-     unsigned long line);
-
-/** Check an generic identifier to see if it matches architecture specific
- * names for prefixes.  Unrecognized identifiers should return 0
- * so they can be treated as normal symbols.  Any additional data beyond
- * just the type (almost always necessary) should be returned into the
- * space provided by the data parameter.
- * \param arch architecture
- * \param data extra identification information (yasm_arch-specific)
- *             [output]
- * \param id   identifier as in the input file
- * \param line virtual line (from yasm_linemap)
- * \return 1 if id is a register, 0 if not.
- */
-int yasm_arch_parse_check_prefix
+ * names for instructions or instruction prefixes.  Unrecognized identifiers
+ * should return #YASM_ARCH_NOTINSNPREFIX so they can be treated as normal
+ * symbols.  Any additional data beyond just the type (almost always necessary)
+ * should be returned into the space provided by the data parameter.
+ * \param arch         architecture
+ * \param data         extra identification information (yasm_arch-specific)
+ *                     [output]
+ * \param id           identifier as in the input file
+ * \param id_len       length of id string
+ * \param line         virtual line (from yasm_linemap)
+ * \return Identifier type (#YASM_ARCH_NOTINSNPREFIX if unrecognized)
+ */
+yasm_arch_insnprefix yasm_arch_parse_check_insnprefix
     (yasm_arch *arch, /*@out@*/ unsigned long data[4], const char *id,
-     unsigned long line);
+     size_t id_len, unsigned long line);
 
 /** Check an generic identifier to see if it matches architecture specific
- * names for target modifiers.  Unrecognized identifiers should return 0
- * so they can be treated as normal symbols.  Any additional data beyond
- * just the type (almost always necessary) should be returned into the
- * space provided by the data parameter.
- * \param arch architecture
- * \param data extra identification information (yasm_arch-specific)
- *             [output]
- * \param id   identifier as in the input file
- * \param line virtual line (from yasm_linemap)
- * \return 1 if id is a register, 0 if not.
+ * names for registers or target modifiers.  Unrecognized identifiers should
+ * return #YASM_ARCH_NOTREGTMOD.  Any additional data beyond just the type
+ * (almost always necessary) should be returned into the space provided by the
+ * data parameter.
+ * \param arch         architecture
+ * \param data         extra identification information (yasm_arch-specific)
+ *                     [output]
+ * \param id           identifier as in the input file
+ * \param id_len       length of id string
+ * \param line         virtual line (from yasm_linemap)
+ * \return Identifier type (#YASM_ARCH_NOTREGTMOD if unrecognized)
  */
-int yasm_arch_parse_check_targetmod
-    (yasm_arch *arch, /*@out@*/ unsigned long data[1], const char *id,
-     unsigned long line);
+yasm_arch_regtmod yasm_arch_parse_check_regtmod
+    (yasm_arch *arch, /*@out@*/ unsigned long *data, const char *id,
+     size_t id_len, unsigned long line);
 
 /** Handle architecture-specific directives.
  * Should modify behavior ONLY of parse functions, much like parse_cpu().
@@ -635,22 +564,14 @@ yasm_effaddr *yasm_arch_ea_create(yasm_arch *arch, /*@keep@*/ yasm_expr *e);
     ((yasm_arch_base *)arch)->module->get_address_size(arch)
 #define yasm_arch_set_var(arch, var, val) \
     ((yasm_arch_base *)arch)->module->set_var(arch, var, val)
-#define yasm_arch_parse_cpu(arch, cpuid, line) \
-    ((yasm_arch_base *)arch)->module->parse_cpu(arch, cpuid, line)
-#define yasm_arch_parse_check_reg(arch, data, id, line) \
-    ((yasm_arch_base *)arch)->module->parse_check_reg(arch, data, id, line)
-#define yasm_arch_parse_check_reggroup(arch, data, id, line) \
-    ((yasm_arch_base *)arch)->module->parse_check_reggroup(arch, data, id, \
-                                                          line)
-#define yasm_arch_parse_check_segreg(arch, data, id, line) \
-    ((yasm_arch_base *)arch)->module->parse_check_segreg(arch, data, id, line)
-#define yasm_arch_parse_check_insn(arch, data, id, line) \
-    ((yasm_arch_base *)arch)->module->parse_check_insn(arch, data, id, line)
-#define yasm_arch_parse_check_prefix(arch, data, id, line) \
-    ((yasm_arch_base *)arch)->module->parse_check_prefix(arch, data, id, line)
-#define yasm_arch_parse_check_targetmod(arch, data, id, line) \
-    ((yasm_arch_base *)arch)->module->parse_check_targetmod(arch, data, id, \
-                                                           line)
+#define yasm_arch_parse_cpu(arch, cpuid, cpuid_len, line) \
+    ((yasm_arch_base *)arch)->module->parse_cpu(arch, cpuid, cpuid_len, line)
+#define yasm_arch_parse_check_insnprefix(arch, data, id, id_len, line) \
+    ((yasm_arch_base *)arch)->module->parse_check_insnprefix(arch, data, id, \
+                                                            id_len, line)
+#define yasm_arch_parse_check_regtmod(arch, data, id, id_len, line) \
+    ((yasm_arch_base *)arch)->module->parse_check_regtmod(arch, data, id, \
+                                                         id_len, line)
 #define yasm_arch_parse_directive(arch, name, valparams, objext_valparams, \
                                  object, line) \
     ((yasm_arch_base *)arch)->module->parse_directive \
diff --git a/libyasm/phash.c b/libyasm/phash.c
new file mode 100644 (file)
index 0000000..6e23fb4
--- /dev/null
@@ -0,0 +1,252 @@
+/* Modified for use with yasm by Peter Johnson. */
+#define YASM_LIB_INTERNAL
+#include "util.h"
+/*@unused@*/ RCSID("$Id$");
+
+/*
+--------------------------------------------------------------------
+lookupa.c, by Bob Jenkins, December 1996.  Same as lookup2.c
+Use this code however you wish.  Public Domain.  No warranty.
+Source is http://burtleburtle.net/bob/c/lookupa.c
+--------------------------------------------------------------------
+*/
+#include "phash.h"
+
+#define ub4 unsigned long
+
+#define hashsize(n) ((ub4)1<<(n))
+#define hashmask(n) (hashsize(n)-1)
+
+/*
+--------------------------------------------------------------------
+mix -- mix 3 32-bit values reversibly.
+For every delta with one or two bit set, and the deltas of all three
+  high bits or all three low bits, whether the original value of a,b,c
+  is almost all zero or is uniformly distributed,
+* If mix() is run forward or backward, at least 32 bits in a,b,c
+  have at least 1/4 probability of changing.
+* If mix() is run forward, every bit of c will change between 1/3 and
+  2/3 of the time.  (Well, 22/100 and 78/100 for some 2-bit deltas.)
+mix() was built out of 36 single-cycle latency instructions in a 
+  structure that could supported 2x parallelism, like so:
+      a -= b; 
+      a -= c; x = (c>>13);
+      b -= c; a ^= x;
+      b -= a; x = (a<<8);
+      c -= a; b ^= x;
+      c -= b; x = (b>>13);
+      ...
+  Unfortunately, superscalar Pentiums and Sparcs can't take advantage 
+  of that parallelism.  They've also turned some of those single-cycle
+  latency instructions into multi-cycle latency instructions.  Still,
+  this is the fastest good hash I could find.  There were about 2^^68
+  to choose from.  I only looked at a billion or so.
+--------------------------------------------------------------------
+*/
+#define mix(a,b,c) \
+{ \
+    a -= b; a -= c; a ^= (c>>13); \
+    b -= c; b -= a; b ^= (a<<8); \
+    c -= a; c -= b; c ^= (b>>13); \
+    a -= b; a -= c; a ^= (c>>12);  \
+    b -= c; b -= a; b ^= (a<<16); \
+    c -= a; c -= b; c ^= (b>>5); \
+    a -= b; a -= c; a ^= (c>>3);  \
+    b -= c; b -= a; b ^= (a<<10); \
+    c -= a; c -= b; c ^= (b>>15); \
+}
+
+/*
+--------------------------------------------------------------------
+lookup() -- hash a variable-length key into a 32-bit value
+  k     : the key (the unaligned variable-length array of bytes)
+  len   : the length of the key, counting by bytes
+  level : can be any 4-byte value
+Returns a 32-bit value.  Every bit of the key affects every bit of
+the return value.  Every 1-bit and 2-bit delta achieves avalanche.
+About 6len+35 instructions.
+
+The best hash table sizes are powers of 2.  There is no need to do
+mod a prime (mod is sooo slow!).  If you need less than 32 bits,
+use a bitmask.  For example, if you need only 10 bits, do
+  h = (h & hashmask(10));
+In which case, the hash table should have hashsize(10) elements.
+
+If you are hashing n strings (ub1 **)k, do it like this:
+  for (i=0, h=0; i<n; ++i) h = lookup( k[i], len[i], h);
+
+By Bob Jenkins, 1996.  bob_jenkins@burtleburtle.net.  You may use this
+code any way you wish, private, educational, or commercial.
+
+See http://burtleburtle.net/bob/hash/evahash.html
+Use for hash table lookup, or anything where one collision in 2^32 is
+acceptable.  Do NOT use for cryptographic purposes.
+--------------------------------------------------------------------
+*/
+
+unsigned long
+phash_lookup(
+    register const char *sk, /* the key */
+    register unsigned long length,   /* the length of the key */
+    register unsigned long level) /* the previous hash, or an arbitrary value */
+{
+    register unsigned long a,b,c,len;
+    register const unsigned char *k = (const unsigned char *)sk;
+
+    /* Set up the internal state */
+    len = length;
+    a = b = 0x9e3779b9;  /* the golden ratio; an arbitrary value */
+    c = level;           /* the previous hash value */
+
+    /*---------------------------------------- handle most of the key */
+    while (len >= 12)
+    {
+       a += (k[0] +((ub4)k[1]<<8) +((ub4)k[2]<<16) +((ub4)k[3]<<24));
+       b += (k[4] +((ub4)k[5]<<8) +((ub4)k[6]<<16) +((ub4)k[7]<<24));
+       c += (k[8] +((ub4)k[9]<<8) +((ub4)k[10]<<16)+((ub4)k[11]<<24));
+       mix(a,b,c);
+       k += 12; len -= 12;
+    }
+
+    /*------------------------------------- handle the last 11 bytes */
+    c += length;
+    switch(len)              /* all the case statements fall through */
+    {
+       case 11: c+=((ub4)k[10]<<24);
+       case 10: c+=((ub4)k[9]<<16);
+       case 9 : c+=((ub4)k[8]<<8);
+           /* the first byte of c is reserved for the length */
+       case 8 : b+=((ub4)k[7]<<24);
+       case 7 : b+=((ub4)k[6]<<16);
+       case 6 : b+=((ub4)k[5]<<8);
+       case 5 : b+=k[4];
+       case 4 : a+=((ub4)k[3]<<24);
+       case 3 : a+=((ub4)k[2]<<16);
+       case 2 : a+=((ub4)k[1]<<8);
+       case 1 : a+=k[0];
+       /* case 0: nothing left to add */
+    }
+    mix(a,b,c);
+    /*-------------------------------------------- report the result */
+    return c;
+}
+
+
+/*
+--------------------------------------------------------------------
+mixc -- mixc 8 4-bit values as quickly and thoroughly as possible.
+Repeating mix() three times achieves avalanche.
+Repeating mix() four times eliminates all funnels and all
+  characteristics stronger than 2^{-11}.
+--------------------------------------------------------------------
+*/
+#define mixc(a,b,c,d,e,f,g,h) \
+{ \
+    a^=b<<11; d+=a; b+=c; \
+    b^=c>>2;  e+=b; c+=d; \
+    c^=d<<8;  f+=c; d+=e; \
+    d^=e>>16; g+=d; e+=f; \
+    e^=f<<10; h+=e; f+=g; \
+    f^=g>>4;  a+=f; g+=h; \
+    g^=h<<8;  b+=g; h+=a; \
+    h^=a>>9;  c+=h; a+=b; \
+}
+
+/*
+--------------------------------------------------------------------
+checksum() -- hash a variable-length key into a 256-bit value
+  k     : the key (the unaligned variable-length array of bytes)
+  len   : the length of the key, counting by bytes
+  state : an array of CHECKSTATE 4-byte values (256 bits)
+The state is the checksum.  Every bit of the key affects every bit of
+the state.  There are no funnels.  About 112+6.875len instructions.
+
+If you are hashing n strings (ub1 **)k, do it like this:
+  for (i=0; i<8; ++i) state[i] = 0x9e3779b9;
+  for (i=0, h=0; i<n; ++i) checksum( k[i], len[i], state);
+
+(c) Bob Jenkins, 1996.  bob_jenkins@burtleburtle.net.  You may use this
+code any way you wish, private, educational, or commercial, as long
+as this whole comment accompanies it.
+
+See http://burtleburtle.net/bob/hash/evahash.html
+Use to detect changes between revisions of documents, assuming nobody
+is trying to cause collisions.  Do NOT use for cryptography.
+--------------------------------------------------------------------
+*/
+void
+phash_checksum(
+    register const unsigned char *k,
+    register unsigned long len,
+    register unsigned long *state)
+{
+    register unsigned long a,b,c,d,e,f,g,h,length;
+
+    /* Use the length and level; add in the golden ratio. */
+    length = len;
+    a=state[0]; b=state[1]; c=state[2]; d=state[3];
+    e=state[4]; f=state[5]; g=state[6]; h=state[7];
+
+    /*---------------------------------------- handle most of the key */
+    while (len >= 32)
+    {
+       a += (k[0] +(k[1]<<8) +(k[2]<<16) +(k[3]<<24));
+       b += (k[4] +(k[5]<<8) +(k[6]<<16) +(k[7]<<24));
+       c += (k[8] +(k[9]<<8) +(k[10]<<16)+(k[11]<<24));
+       d += (k[12]+(k[13]<<8)+(k[14]<<16)+(k[15]<<24));
+       e += (k[16]+(k[17]<<8)+(k[18]<<16)+(k[19]<<24));
+       f += (k[20]+(k[21]<<8)+(k[22]<<16)+(k[23]<<24));
+       g += (k[24]+(k[25]<<8)+(k[26]<<16)+(k[27]<<24));
+       h += (k[28]+(k[29]<<8)+(k[30]<<16)+(k[31]<<24));
+       mixc(a,b,c,d,e,f,g,h);
+       mixc(a,b,c,d,e,f,g,h);
+       mixc(a,b,c,d,e,f,g,h);
+       mixc(a,b,c,d,e,f,g,h);
+       k += 32; len -= 32;
+    }
+
+    /*------------------------------------- handle the last 31 bytes */
+    h += length;
+    switch(len)
+    {
+       case 31: h+=(k[30]<<24);
+       case 30: h+=(k[29]<<16);
+       case 29: h+=(k[28]<<8);
+       case 28: g+=(k[27]<<24);
+       case 27: g+=(k[26]<<16);
+       case 26: g+=(k[25]<<8);
+       case 25: g+=k[24];
+       case 24: f+=(k[23]<<24);
+       case 23: f+=(k[22]<<16);
+       case 22: f+=(k[21]<<8);
+       case 21: f+=k[20];
+       case 20: e+=(k[19]<<24);
+       case 19: e+=(k[18]<<16);
+       case 18: e+=(k[17]<<8);
+       case 17: e+=k[16];
+       case 16: d+=(k[15]<<24);
+       case 15: d+=(k[14]<<16);
+       case 14: d+=(k[13]<<8);
+       case 13: d+=k[12];
+       case 12: c+=(k[11]<<24);
+       case 11: c+=(k[10]<<16);
+       case 10: c+=(k[9]<<8);
+       case 9 : c+=k[8];
+       case 8 : b+=(k[7]<<24);
+       case 7 : b+=(k[6]<<16);
+       case 6 : b+=(k[5]<<8);
+       case 5 : b+=k[4];
+       case 4 : a+=(k[3]<<24);
+       case 3 : a+=(k[2]<<16);
+       case 2 : a+=(k[1]<<8);
+       case 1 : a+=k[0];
+    }
+    mixc(a,b,c,d,e,f,g,h);
+    mixc(a,b,c,d,e,f,g,h);
+    mixc(a,b,c,d,e,f,g,h);
+    mixc(a,b,c,d,e,f,g,h);
+
+    /*-------------------------------------------- report the result */
+    state[0]=a; state[1]=b; state[2]=c; state[3]=d;
+    state[4]=e; state[5]=f; state[6]=g; state[7]=h;
+}
diff --git a/libyasm/phash.h b/libyasm/phash.h
new file mode 100644 (file)
index 0000000..1f64725
--- /dev/null
@@ -0,0 +1,16 @@
+/* Modified for use with yasm by Peter Johnson.
+ * $Id$
+ */
+/*
+------------------------------------------------------------------------------
+By Bob Jenkins, September 1996.
+lookupa.h, a hash function for table lookup, same function as lookup.c.
+Use this code in any way you wish.  Public Domain.  It has no warranty.
+Source is http://burtleburtle.net/bob/c/lookupa.h
+------------------------------------------------------------------------------
+*/
+
+unsigned long phash_lookup(const char *k, unsigned long length,
+                          unsigned long level);
+void phash_checksum(const unsigned char *k, unsigned long length,
+                   unsigned long *state);
index 04e5a9d6b0f650bd2a60ed3f6dd88d60f41c9ae8..2fb5b8ffd4ef55c928d8bfa75bf211e120dcc271 100644 (file)
@@ -176,12 +176,8 @@ yasm_arch_module yasm_lc3b_LTX_arch = {
     lc3b_get_address_size,
     lc3b_set_var,
     yasm_lc3b__parse_cpu,
-    yasm_lc3b__parse_check_reg,
-    yasm_lc3b__parse_check_reggroup,
-    yasm_lc3b__parse_check_segreg,
-    yasm_lc3b__parse_check_insn,
-    yasm_lc3b__parse_check_prefix,
-    yasm_lc3b__parse_check_targetmod,
+    yasm_lc3b__parse_check_insnprefix,
+    yasm_lc3b__parse_check_regtmod,
     lc3b_parse_directive,
     lc3b_get_fill,
     yasm_lc3b__finalize_insn,
index f034d4da85f02d4ab8c623bd47f755ebb4105aa8..fe5304d374e9cde3ba222a862b1073636f7c383a 100644 (file)
@@ -52,26 +52,14 @@ typedef struct lc3b_insn {
 
 void yasm_lc3b__bc_transform_insn(yasm_bytecode *bc, lc3b_insn *insn);
 
-void yasm_lc3b__parse_cpu(yasm_arch *arch, const char *cpuid,
+void yasm_lc3b__parse_cpu(yasm_arch *arch, const char *cpuid, size_t cpuid_len,
                          unsigned long line);
 
-int yasm_lc3b__parse_check_reg
-    (yasm_arch *arch, unsigned long data[1], const char *id,
+yasm_arch_insnprefix yasm_lc3b__parse_check_insnprefix
+    (yasm_arch *arch, unsigned long data[4], const char *id, size_t id_len,
      unsigned long line);
-int yasm_lc3b__parse_check_reggroup
-    (yasm_arch *arch, unsigned long data[1], const char *id,
-     unsigned long line);
-int yasm_lc3b__parse_check_segreg
-    (yasm_arch *arch, unsigned long data[1], const char *id,
-     unsigned long line);
-int yasm_lc3b__parse_check_insn
-    (yasm_arch *arch, unsigned long data[4], const char *id,
-     unsigned long line);
-int yasm_lc3b__parse_check_prefix
-    (yasm_arch *arch, unsigned long data[4], const char *id,
-     unsigned long line);
-int yasm_lc3b__parse_check_targetmod
-    (yasm_arch *arch, unsigned long data[1], const char *id,
+yasm_arch_regtmod yasm_lc3b__parse_check_regtmod
+    (yasm_arch *arch, unsigned long *data, const char *id, size_t id_len,
      unsigned long line);
 
 void yasm_lc3b__finalize_insn
index 85c136488be6ce72341f6de62a8b5b40922b5b49..5c81c460529be69299e830960afd7b590279056e 100644 (file)
@@ -119,7 +119,7 @@ typedef struct lc3b_insn_info {
 
 #define RET_INSN(group, mod)   do { \
     DEF_INSN_DATA(group, mod); \
-    return 1; \
+    return YASM_ARCH_INSN; \
     } while (0)
 
 /*
@@ -314,50 +314,39 @@ yasm_lc3b__finalize_insn(yasm_arch *arch, yasm_bytecode *bc,
 #define YYFILL(n)      (void)(n)
 
 void
-yasm_lc3b__parse_cpu(yasm_arch *arch, const char *id, unsigned long line)
+yasm_lc3b__parse_cpu(yasm_arch *arch, const char *cpuid, size_t cpuid_len,
+                    unsigned long line)
 {
 }
 
-int
-yasm_lc3b__parse_check_reg(yasm_arch *arch, unsigned long data[1],
-                          const char *id, unsigned long line)
+yasm_arch_regtmod
+yasm_lc3b__parse_check_regtmod(yasm_arch *arch, unsigned long *data,
+                              const char *id, size_t id_len,
+                              unsigned long line)
 {
     const char *oid = id;
     /*const char *marker;*/
     /*!re2c
        /* integer registers */
        'r' [0-7]       {
-           data[0] = (oid[1]-'0');
-           return 1;
+           *data = (oid[1]-'0');
+           return YASM_ARCH_REG;
        }
 
        /* catchalls */
        [\001-\377]+    {
-           return 0;
+           return YASM_ARCH_NOTREGTMOD;
        }
        [\000]  {
-           return 0;
+           return YASM_ARCH_NOTREGTMOD;
        }
     */
 }
 
-int
-yasm_lc3b__parse_check_reggroup(yasm_arch *arch, unsigned long data[1],
-                               const char *id, unsigned long line)
-{
-    return 0;
-}
-
-int
-yasm_lc3b__parse_check_segreg(yasm_arch *arch, unsigned long data[1],
-                             const char *id, unsigned long line)
-{
-    return 0;
-}
-
-int
-yasm_lc3b__parse_check_insn(yasm_arch *arch, unsigned long data[4],
-                           const char *id, unsigned long line)
+yasm_arch_insnprefix
+yasm_lc3b__parse_check_insnprefix(yasm_arch *arch, unsigned long data[4],
+                                 const char *id, size_t id_len,
+                                 unsigned long line)
 {
     /*const char *oid = id;*/
     /*const char *marker;*/
@@ -403,24 +392,10 @@ yasm_lc3b__parse_check_insn(yasm_arch *arch, unsigned long data[4],
 
        /* catchalls */
        [\001-\377]+    {
-           return 0;
+           return YASM_ARCH_NOTINSNPREFIX;
        }
        [\000]  {
-           return 0;
+           return YASM_ARCH_NOTINSNPREFIX;
        }
     */
 }
-
-int
-yasm_lc3b__parse_check_prefix(yasm_arch *arch, unsigned long data[4],
-                             const char *id, unsigned long line)
-{
-    return 0;
-}
-
-int
-yasm_lc3b__parse_check_targetmod(yasm_arch *arch, unsigned long data[1],
-                                const char *id, unsigned long line)
-{
-    return 0;
-}
index b50caf80c22aaf364a4841cc13c5c17782a71bf0..24e90fa71f6f125ee9c3d558cfbb834b86940e06 100644 (file)
@@ -4,18 +4,20 @@ libyasm_a_SOURCES += modules/arch/x86/x86arch.c
 libyasm_a_SOURCES += modules/arch/x86/x86arch.h
 libyasm_a_SOURCES += modules/arch/x86/x86bc.c
 libyasm_a_SOURCES += modules/arch/x86/x86expr.c
-libyasm_a_SOURCES += x86id.c
+libyasm_a_SOURCES += modules/arch/x86/x86id.c
 
 YASM_MODULES += arch_x86
 
-x86id.c: $(srcdir)/modules/arch/x86/x86id.re re2c$(EXEEXT)
-       $(top_builddir)/re2c$(EXEEXT) -s -o $@ $(srcdir)/modules/arch/x86/x86id.re
+modules/arch/x86/x86id.c: x86parse.c
 
-BUILT_SOURCES += x86id.c
+EXTRA_DIST += modules/arch/x86/x86parse.gap
 
-CLEANFILES += x86id.c
+x86parse.c: $(srcdir)/modules/arch/x86/x86parse.gap gap$(EXEEXT)
+       $(top_builddir)/gap$(EXEEXT) $(srcdir)/modules/arch/x86/x86parse.gap $@
+
+BUILT_SOURCES += x86parse.c
+CLEANFILES += x86parse.c
 
 EXTRA_DIST += modules/arch/x86/tests/Makefile.inc
-EXTRA_DIST += modules/arch/x86/x86id.re
 
 include modules/arch/x86/tests/Makefile.inc
index 825709b2349a6e4e8034563b25551559d52f46ce..eab4908937af2a1473e2d7d863a23e1297f357f8 100644 (file)
@@ -394,12 +394,8 @@ yasm_arch_module yasm_x86_LTX_arch = {
     x86_get_address_size,
     x86_set_var,
     yasm_x86__parse_cpu,
-    yasm_x86__parse_check_reg,
-    yasm_x86__parse_check_reggroup,
-    yasm_x86__parse_check_segreg,
-    yasm_x86__parse_check_insn,
-    yasm_x86__parse_check_prefix,
-    yasm_x86__parse_check_targetmod,
+    yasm_x86__parse_check_insnprefix,
+    yasm_x86__parse_check_regtmod,
     x86_parse_directive,
     x86_get_fill,
     yasm_x86__finalize_insn,
index 03fb75d346d1792b0a5e6fdd5eb875b38f75637b..1a3d7b64a158fc883c11dd8fb433eafc4b3e0cb4 100644 (file)
@@ -273,27 +273,15 @@ int yasm_x86__expr_checkea
      unsigned char *pcrel, unsigned char *rex,
      yasm_calc_bc_dist_func calc_bc_dist);
 
-void yasm_x86__parse_cpu(yasm_arch *arch, const char *cpuid,
+void yasm_x86__parse_cpu(yasm_arch *arch, const char *cpuid, size_t cpuid_len,
                         unsigned long line);
 
-int yasm_x86__parse_check_reg
-    (yasm_arch *arch, /*@out@*/ unsigned long data[1], const char *id,
-     unsigned long line);
-int yasm_x86__parse_check_reggroup
-    (yasm_arch *arch, /*@out@*/ unsigned long data[1], const char *id,
-     unsigned long line);
-int yasm_x86__parse_check_segreg
-    (yasm_arch *arch, /*@out@*/ unsigned long data[1], const char *id,
-     unsigned long line);
-int yasm_x86__parse_check_insn
+yasm_arch_insnprefix yasm_x86__parse_check_insnprefix
     (yasm_arch *arch, /*@out@*/ unsigned long data[4], const char *id,
-     unsigned long line);
-int yasm_x86__parse_check_prefix
-    (yasm_arch *arch, /*@out@*/ unsigned long data[4], const char *id,
-     unsigned long line);
-int yasm_x86__parse_check_targetmod
-    (yasm_arch *arch, /*@out@*/ unsigned long data[1], const char *id,
-     unsigned long line);
+     size_t id_len, unsigned long line);
+yasm_arch_regtmod yasm_x86__parse_check_regtmod
+    (yasm_arch *arch, /*@out@*/ unsigned long *data, const char *id,
+     size_t id_len, unsigned long line);
 
 void yasm_x86__finalize_insn
     (yasm_arch *arch, yasm_bytecode *bc, yasm_bytecode *prev_bc,
similarity index 65%
rename from modules/arch/x86/x86id.re
rename to modules/arch/x86/x86id.c
index 6f79eb2a804039694e4fb06d9c76ba4a1865196f..1b374a4928ca124de34a2851e22d3020a3a5311a 100644 (file)
@@ -24,6 +24,7 @@
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  */
+#include <ctype.h>
 #include <util.h>
 RCSID("$Id$");
 
@@ -31,6 +32,7 @@ RCSID("$Id$");
 #define YASM_BC_INTERNAL
 #define YASM_EXPR_INTERNAL
 #include <libyasm.h>
+#include <libyasm/phash.h>
 
 #include "modules/arch/x86/x86arch.h"
 
@@ -275,16 +277,6 @@ typedef struct x86_insn_info {
     unsigned long operands[3];
 } x86_insn_info;
 
-/* Define lexer arch-specific data with 0-3 modifiers.
- * This assumes arch_x86 is locally defined.
- */
-#define DEF_INSN_DATA(group, mod, cpu) do { \
-    data[0] = (unsigned long)group##_insn; \
-    data[1] = (((unsigned long)mod)<<8) | \
-             ((unsigned char)(sizeof(group##_insn)/sizeof(x86_insn_info))); \
-    data[2] = cpu; \
-    } while (0)
-
 /*
  * General instruction groupings
  */
@@ -2876,1845 +2868,223 @@ yasm_x86__finalize_insn(yasm_arch *arch, yasm_bytecode *bc,
     yasm_x86__bc_transform_insn(bc, insn);
 }
 
+/* Static parse data structure for instructions */
+typedef struct insnprefix_parse_data {
+    const char *name;
 
-#define YYCTYPE                char
-#define YYCURSOR       id
-#define YYLIMIT                id
-#define YYMARKER       marker
-#define YYFILL(n)      (void)(n)
-
-/*!re2c
-  any = [\000-\377];
-  A = [aA];
-  B = [bB];
-  C = [cC];
-  D = [dD];
-  E = [eE];
-  F = [fF];
-  G = [gG];
-  H = [hH];
-  I = [iI];
-  J = [jJ];
-  K = [kK];
-  L = [lL];
-  M = [mM];
-  N = [nN];
-  O = [oO];
-  P = [pP];
-  Q = [qQ];
-  R = [rR];
-  S = [sS];
-  T = [tT];
-  U = [uU];
-  V = [vV];
-  W = [wW];
-  X = [xX];
-  Y = [yY];
-  Z = [zZ];
-*/
-
-void
-yasm_x86__parse_cpu(yasm_arch *arch, const char *id, unsigned long line)
-{
-    yasm_arch_x86 *arch_x86 = (yasm_arch_x86 *)arch;
-    /*const char *marker;*/
+    /* instruction parse group - NULL if prefix */
+    /*@null@*/ const x86_insn_info *group;
 
-    /*!re2c
-       /* The standard CPU names /set/ cpu_enabled. */
-       "8086" {
-           arch_x86->cpu_enabled = CPU_Priv;
-           return;
-       }
-       ("80" | I)? "186" {
-           arch_x86->cpu_enabled = CPU_186|CPU_Priv;
-           return;
-       }
-       ("80" | I)? "286" {
-           arch_x86->cpu_enabled = CPU_186|CPU_286|CPU_Priv;
-           return;
-       }
-       ("80" | I)? "386" {
-           arch_x86->cpu_enabled =
-               CPU_186|CPU_286|CPU_386|CPU_SMM|CPU_Prot|CPU_Priv;
-           return;
-       }
-       ("80" | I)? "486" {
-           arch_x86->cpu_enabled =
-               CPU_186|CPU_286|CPU_386|CPU_486|CPU_FPU|CPU_SMM|CPU_Prot|
-               CPU_Priv;
-           return;
-       }
-       (I? "586") | 'pentium' | 'p5' {
-           arch_x86->cpu_enabled =
-               CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_FPU|CPU_SMM|
-               CPU_Prot|CPU_Priv;
-           return;
-       }
-       (I? "686") | 'p6' | 'ppro' | 'pentiumpro' {
-           arch_x86->cpu_enabled =
-               CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|CPU_FPU|
-               CPU_SMM|CPU_Prot|CPU_Priv;
-           return;
-       }
-       ('p2') | ('pentium' "-"? ("2" | 'ii')) {
-           arch_x86->cpu_enabled =
-               CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|CPU_FPU|
-               CPU_MMX|CPU_SMM|CPU_Prot|CPU_Priv;
-           return;
-       }
-       ('p3') | ('pentium' "-"? ("3" | 'iii')) | 'katmai' {
-           arch_x86->cpu_enabled =
-               CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|CPU_P3|CPU_FPU|
-               CPU_MMX|CPU_SSE|CPU_SMM|CPU_Prot|CPU_Priv;
-           return;
-       }
-       ('p4') | ('pentium' "-"? ("4" | 'iv')) | 'williamette' {
-           arch_x86->cpu_enabled =
-               CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|CPU_P3|CPU_P4|
-               CPU_FPU|CPU_MMX|CPU_SSE|CPU_SSE2|CPU_SMM|CPU_Prot|CPU_Priv;
-           return;
-       }
-       ('ia' "-"? "64") | 'itanium' {
-           arch_x86->cpu_enabled =
-               CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|CPU_P3|CPU_P4|
-               CPU_IA64|CPU_FPU|CPU_MMX|CPU_SSE|CPU_SSE2|CPU_SMM|CPU_Prot|
-               CPU_Priv;
-           return;
-       }
-       'k6' {
-           arch_x86->cpu_enabled =
-               CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|CPU_K6|CPU_FPU|
-               CPU_MMX|CPU_3DNow|CPU_SMM|CPU_Prot|CPU_Priv;
-           return;
-       }
-       'athlon' | 'k7' {
-           arch_x86->cpu_enabled =
-               CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|CPU_K6|
-               CPU_Athlon|CPU_FPU|CPU_MMX|CPU_SSE|CPU_3DNow|CPU_SMM|CPU_Prot|
-               CPU_Priv;
-           return;
-       }
-       ('sledge'? 'hammer') | 'opteron' | ('athlon' "-"? "64") {
-           arch_x86->cpu_enabled =
-               CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|CPU_K6|
-               CPU_Athlon|CPU_Hammer|CPU_FPU|CPU_MMX|CPU_SSE|CPU_SSE2|
-               CPU_3DNow|CPU_SMM|CPU_Prot|CPU_Priv;
-           return;
-       }
-       'prescott' {
-           arch_x86->cpu_enabled =
-               CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|CPU_K6|
-               CPU_Athlon|CPU_Hammer|CPU_FPU|CPU_MMX|CPU_SSE|CPU_SSE2|
-               CPU_SSE3|CPU_3DNow|CPU_SMM|CPU_Prot|CPU_Priv;
-           return;
-       }
-
-       /* Features have "no" versions to disable them, and only set/reset the
-        * specific feature being changed.  All other bits are left alone.
-        */
-       'fpu'           { arch_x86->cpu_enabled |= CPU_FPU; return; }
-       'nofpu'         { arch_x86->cpu_enabled &= ~CPU_FPU; return; }
-       'mmx'           { arch_x86->cpu_enabled |= CPU_MMX; return; }
-       'nommx'         { arch_x86->cpu_enabled &= ~CPU_MMX; return; }
-       'sse'           { arch_x86->cpu_enabled |= CPU_SSE; return; }
-       'nosse'         { arch_x86->cpu_enabled &= ~CPU_SSE; return; }
-       'sse2'          { arch_x86->cpu_enabled |= CPU_SSE2; return; }
-       'nosse2'        { arch_x86->cpu_enabled &= ~CPU_SSE2; return; }
-       'sse3'          { arch_x86->cpu_enabled |= CPU_SSE3; return; }
-       'nosse3'        { arch_x86->cpu_enabled &= ~CPU_SSE3; return; }
-       'pni'           { arch_x86->cpu_enabled |= CPU_SSE3; return; }
-       'nopni'         { arch_x86->cpu_enabled &= ~CPU_SSE3; return; }
-       '3dnow'         { arch_x86->cpu_enabled |= CPU_3DNow; return; }
-       'no3dnow'       { arch_x86->cpu_enabled &= ~CPU_3DNow; return; }
-       'cyrix'         { arch_x86->cpu_enabled |= CPU_Cyrix; return; }
-       'nocyrix'       { arch_x86->cpu_enabled &= ~CPU_Cyrix; return; }
-       'amd'           { arch_x86->cpu_enabled |= CPU_AMD; return; }
-       'noamd'         { arch_x86->cpu_enabled &= ~CPU_AMD; return; }
-       'smm'           { arch_x86->cpu_enabled |= CPU_SMM; return; }
-       'nosmm'         { arch_x86->cpu_enabled &= ~CPU_SMM; return; }
-       'prot'          { arch_x86->cpu_enabled |= CPU_Prot; return; }
-       'noprot'        { arch_x86->cpu_enabled &= ~CPU_Prot; return; }
-       'undoc'         { arch_x86->cpu_enabled |= CPU_Undoc; return; }
-       'noundoc'       { arch_x86->cpu_enabled &= ~CPU_Undoc; return; }
-       'obs'           { arch_x86->cpu_enabled |= CPU_Obs; return; }
-       'noobs'         { arch_x86->cpu_enabled &= ~CPU_Obs; return; }
-       'priv'          { arch_x86->cpu_enabled |= CPU_Priv; return; }
-       'nopriv'        { arch_x86->cpu_enabled &= ~CPU_Priv; return; }
-       'svm'           { arch_x86->cpu_enabled |= CPU_SVM; return; }
-       'nosvm'         { arch_x86->cpu_enabled &= ~CPU_SVM; return; }
-       'padlock'       { arch_x86->cpu_enabled |= CPU_PadLock; return; }
-       'nopadlock'     { arch_x86->cpu_enabled &= ~CPU_PadLock; return; }
-
-       /* catchalls */
-       [\001-\377]+    {
-           yasm__warning(YASM_WARN_GENERAL, line,
-                         N_("unrecognized CPU identifier `%s'"), id);
-           return;
-       }
-       [\000]          {
-           yasm__warning(YASM_WARN_GENERAL, line,
-                         N_("unrecognized CPU identifier `%s'"), id);
-           return;
-       }
-    */
-}
-
-int
-yasm_x86__parse_check_targetmod(yasm_arch *arch, unsigned long data[1],
-                               const char *id, unsigned long line)
-{
-    /*!re2c
-       /* target modifiers */
-       'near'  {
-           data[0] = X86_NEAR;
-           return 1;
-       }
-       'short' {
-           data[0] = X86_SHORT;
-           return 1;
-       }
-       'far'   {
-           data[0] = X86_FAR;
-           return 1;
-       }
-       'to'    {
-           data[0] = X86_TO;
-           return 1;
-       }
+    /* For instruction, modifier in upper 24 bits, number of elements in group
+     * in lower 8 bits.
+     * For prefix, prefix type.
+     */
+    unsigned long data1;
 
-       /* catchalls */
-       [\001-\377]+    {
-           return 0;
-       }
-       [\000]  {
-           return 0;
-       }
-    */
-    return 0;
-}
+    /* For instruction, cpu flags.
+     * For prefix, prefix value.
+     */
+    unsigned long data2;
+
+    /* suffix flags for instructions */
+    enum {
+       NONE = 0,
+       SUF_B = (MOD_GasSufB >> MOD_GasSuf_SHIFT),
+       SUF_W = (MOD_GasSufW >> MOD_GasSuf_SHIFT),
+       SUF_L = (MOD_GasSufL >> MOD_GasSuf_SHIFT),
+       SUF_Q = (MOD_GasSufQ >> MOD_GasSuf_SHIFT),
+       SUF_S = (MOD_GasSufS >> MOD_GasSuf_SHIFT),
+       WEAK = 0x80     /* Relaxed operand mode for GAS */
+    } flags;
+} insnprefix_parse_data;
+#define INSN(name, flags, group, mod, cpu) \
+    { name, group##_insn, (mod##UL<<8)|NELEMS(group##_insn), cpu, flags }
+#define PREFIX(name, type, value) \
+    { name, NULL, type, value, NONE }
+
+/* Static parse data structure for CPU feature flags */
+typedef struct cpu_parse_data {
+    const char *name;
 
-int
-yasm_x86__parse_check_prefix(yasm_arch *arch, unsigned long data[4],
-                            const char *id, unsigned long line)
+    unsigned long cpu;
+    enum {
+       CPU_MODE_VERBATIM,
+       CPU_MODE_SET,
+       CPU_MODE_CLEAR
+    } mode;
+} cpu_parse_data;
+
+typedef struct regtmod_parse_data {
+    const char *name;
+
+    unsigned long regtmod;
+} regtmod_parse_data;
+#define REG(name, type, index, bits) \
+    { name, (((unsigned long)YASM_ARCH_REG) << 24) | \
+           (((unsigned long)bits) << 16) | (type | index) }
+#define REGGROUP(name, group) \
+    { name, (((unsigned long)YASM_ARCH_REGGROUP) << 24) | (group) }
+#define SEGREG(name, prefix, num, bits) \
+    { name, (((unsigned long)YASM_ARCH_SEGREG) << 24) | \
+           (((unsigned long)bits) << 16) | (prefix << 8) | (num) }
+#define TARGETMOD(name, mod) \
+    { name, (((unsigned long)YASM_ARCH_TARGETMOD) << 24) | (mod) }
+
+/* Pull in all parse data */
+#include "x86parse.c"
+
+yasm_arch_insnprefix
+yasm_x86__parse_check_insnprefix(yasm_arch *arch, unsigned long data[4],
+                                const char *id, size_t id_len,
+                                unsigned long line)
 {
     yasm_arch_x86 *arch_x86 = (yasm_arch_x86 *)arch;
-    const char *oid = id;
-    /*!re2c
-       /* operand size overrides */
-       'o16' | 'data16' | 'word'       {
-           if (oid[0] != 'o' && arch_x86->parser != X86_PARSER_GAS)
-               return 0;
-           data[0] = X86_OPERSIZE;
-           data[1] = 16;
-           return 1;
-       }
-       'o32' | 'data32' | 'dword'      {
-           if (oid[0] != 'o' && arch_x86->parser != X86_PARSER_GAS)
-               return 0;
-           if (arch_x86->mode_bits == 64) {
-               yasm__error(line,
-                   N_("Cannot override data size to 32 bits in 64-bit mode"));
-               return 0;
-           }
-           data[0] = X86_OPERSIZE;
-           data[1] = 32;
-           return 1;
-       }
-       'o64' | 'data64' | 'qword'      {
-           if (oid[0] != 'o' && arch_x86->parser != X86_PARSER_GAS)
-               return 0;
-           if (arch_x86->mode_bits != 64) {
-               yasm__warning(YASM_WARN_GENERAL, line,
-                             N_("`%s' is a prefix in 64-bit mode"), oid);
-               return 0;
-           }
-           data[0] = X86_OPERSIZE;
-           data[1] = 64;
-           return 1;
-       }
-       /* address size overrides */
-       'a16' | 'addr16' | 'aword'      {
-           if (oid[1] != '1' && arch_x86->parser != X86_PARSER_GAS)
-               return 0;
-           if (arch_x86->mode_bits == 64) {
-               yasm__error(line,
-                   N_("Cannot override address size to 16 bits in 64-bit mode"));
-               return 0;
-           }
-           data[0] = X86_ADDRSIZE;
-           data[1] = 16;
-           return 1;
-       }
-       'a32' | 'addr32' | 'adword'     {
-           if (oid[1] != '3' && arch_x86->parser != X86_PARSER_GAS)
-               return 0;
-           data[0] = X86_ADDRSIZE;
-           data[1] = 32;
-           return 1;
-       }
-       'a64' | 'addr64' | 'aqword'     {
-           if (oid[1] != '6' && arch_x86->parser != X86_PARSER_GAS)
-               return 0;
-           if (arch_x86->mode_bits != 64) {
-               yasm__warning(YASM_WARN_GENERAL, line,
-                             N_("`%s' is a prefix in 64-bit mode"), oid);
-               return 0;
-           }
-           data[0] = X86_ADDRSIZE;
-           data[1] = 64;
-           return 1;
-       }
-
-       /* instruction prefixes */
-       'lock'  {
-           data[0] = X86_LOCKREP; 
-           data[1] = 0xF0;
-           return 1;
-       }
-       'repn' ('e' | 'z')      {
-           data[0] = X86_LOCKREP;
-           data[1] = 0xF2;
-           return 1;
-       }
-       'rep' ('e' | 'z')?      {
-           data[0] = X86_LOCKREP;
-           data[1] = 0xF3;
-           return 1;
-       }
+    /*@null@*/ const insnprefix_parse_data *pdata;
+    size_t i;
+    static char lcaseid[16];
+
+    if (id_len > 15)
+       return YASM_ARCH_NOTINSNPREFIX;
+    for (i=0; i<id_len; i++)
+       lcaseid[i] = tolower(id[i]);
+    lcaseid[id_len] = '\0';
+
+    switch (arch_x86->parser) {
+       case X86_PARSER_NASM:
+           pdata = insnprefix_nasm_find(lcaseid, id_len);
+           break;
+       case X86_PARSER_GAS:
+           pdata = insnprefix_gas_find(lcaseid, id_len);
+           break;
+       default:
+           pdata = NULL;
+    }
+    if (!pdata)
+       return YASM_ARCH_NOTINSNPREFIX;
 
-       /* other prefixes (limited to GAS-only at the moment) */
-       /* Hint taken/not taken (for jumps */
-       'ht'    {
-           if (arch_x86->parser != X86_PARSER_GAS)
-               return 0;
-           data[0] = X86_SEGREG;
-           data[1] = 0x3E;
-           return 1;
-       }
-       'hnt'   {
-           if (arch_x86->parser != X86_PARSER_GAS)
-               return 0;
-           data[0] = X86_SEGREG;
-           data[1] = 0x2E;
-           return 1;
-       }
-       /* REX byte explicit prefixes */
-       'rex'   {
-           if (arch_x86->parser != X86_PARSER_GAS
-               || arch_x86->mode_bits != 64)
-               return 0;
-           data[0] = X86_REX;
-           data[1] = 0x40;
-           return 1;
-       }
-       'rexz'  {
-           if (arch_x86->parser != X86_PARSER_GAS
-               || arch_x86->mode_bits != 64)
-               return 0;
-           data[0] = X86_REX;
-           data[1] = 0x41;
-           return 1;
-       }
-       'rexy'  {
-           if (arch_x86->parser != X86_PARSER_GAS
-               || arch_x86->mode_bits != 64)
-               return 0;
-           data[0] = X86_REX;
-           data[1] = 0x42;
-           return 1;
-       }
-       'rexyz' {
-           if (arch_x86->parser != X86_PARSER_GAS
-               || arch_x86->mode_bits != 64)
-               return 0;
-           data[0] = X86_REX;
-           data[1] = 0x43;
-           return 1;
-       }
-       'rexx'  {
-           if (arch_x86->parser != X86_PARSER_GAS
-               || arch_x86->mode_bits != 64)
-               return 0;
-           data[0] = X86_REX;
-           data[1] = 0x44;
-           return 1;
-       }
-       'rexxz' {
-           if (arch_x86->parser != X86_PARSER_GAS
-               || arch_x86->mode_bits != 64)
-               return 0;
-           data[0] = X86_REX;
-           data[1] = 0x45;
-           return 1;
-       }
-       'rexxy' {
-           if (arch_x86->parser != X86_PARSER_GAS
-               || arch_x86->mode_bits != 64)
-               return 0;
-           data[0] = X86_REX;
-           data[1] = 0x46;
-           return 1;
-       }
-       'rexxyz'    {
-           if (arch_x86->parser != X86_PARSER_GAS
-               || arch_x86->mode_bits != 64)
-               return 0;
-           data[0] = X86_REX;
-           data[1] = 0x47;
-           return 1;
-       }
-       'rex64' {
-           if (arch_x86->parser != X86_PARSER_GAS
-               || arch_x86->mode_bits != 64)
-               return 0;
-           data[0] = X86_REX;
-           data[1] = 0x48;
-           return 1;
-       }
-       'rex64z'    {
-           if (arch_x86->parser != X86_PARSER_GAS
-               || arch_x86->mode_bits != 64)
-               return 0;
-           data[0] = X86_REX;
-           data[1] = 0x49;
-           return 1;
-       }
-       'rex64y'    {
-           if (arch_x86->parser != X86_PARSER_GAS
-               || arch_x86->mode_bits != 64)
-               return 0;
-           data[0] = X86_REX;
-           data[1] = 0x4a;
-           return 1;
-       }
-       'rex64yz'   {
-           if (arch_x86->parser != X86_PARSER_GAS
-               || arch_x86->mode_bits != 64)
-               return 0;
-           data[0] = X86_REX;
-           data[1] = 0x4b;
-           return 1;
-       }
-       'rex64x'    {
-           if (arch_x86->parser != X86_PARSER_GAS
-               || arch_x86->mode_bits != 64)
-               return 0;
-           data[0] = X86_REX;
-           data[1] = 0x4c;
-           return 1;
-       }
-       'rex64xz'   {
-           if (arch_x86->parser != X86_PARSER_GAS
-               || arch_x86->mode_bits != 64)
-               return 0;
-           data[0] = X86_REX;
-           data[1] = 0x4d;
-           return 1;
-       }
-       'rex64xy'   {
-           if (arch_x86->parser != X86_PARSER_GAS
-               || arch_x86->mode_bits != 64)
-               return 0;
-           data[0] = X86_REX;
-           data[1] = 0x4e;
-           return 1;
-       }
-       'rex64xyz'  {
-           if (arch_x86->parser != X86_PARSER_GAS
-               || arch_x86->mode_bits != 64)
-               return 0;
-           data[0] = X86_REX;
-           data[1] = 0x4f;
-           return 1;
-       }
+    if (pdata->group) {
+       unsigned long cpu = pdata->data2;
 
-       /* catchalls */
-       [\001-\377]+    {
-           return 0;
-       }
-       [\000]  {
-           return 0;
+       if ((cpu & CPU_64) && arch_x86->mode_bits != 64) {
+           yasm__warning(YASM_WARN_GENERAL, line,
+                         N_("`%s' is an instruction in 64-bit mode"), id);
+           return YASM_ARCH_NOTINSNPREFIX;
+       }
+       if ((cpu & CPU_Not64) && arch_x86->mode_bits == 64) {
+           yasm__error(line, N_("`%s' invalid in 64-bit mode"), id);
+           data[0] = (unsigned long)not64_insn;
+           data[1] = NELEMS(not64_insn);
+           data[2] = CPU_Not64;
+           data[3] = arch_x86->mode_bits;
+           return YASM_ARCH_INSN;
+       }
+
+       data[0] = (unsigned long)pdata->group;
+       data[1] = pdata->data1;
+       data[2] = cpu;
+       data[3] = (((unsigned long)pdata->flags)<<8) | arch_x86->mode_bits;
+       return YASM_ARCH_INSN;
+    } else {
+       unsigned long type = pdata->data1;
+       unsigned long value = pdata->data2;
+
+       if (arch_x86->mode_bits == 64 && type == X86_OPERSIZE && value == 32) {
+           yasm__error(line,
+               N_("Cannot override data size to 32 bits in 64-bit mode"));
+           return YASM_ARCH_NOTINSNPREFIX;
+       }
+
+       if (arch_x86->mode_bits == 64 && type == X86_ADDRSIZE && value == 16) {
+           yasm__error(line,
+               N_("Cannot override address size to 16 bits in 64-bit mode"));
+           return YASM_ARCH_NOTINSNPREFIX;
+       }
+
+       if ((type == X86_REX ||
+            (value == 64 && (type == X86_OPERSIZE || type == X86_ADDRSIZE)))
+           && arch_x86->mode_bits != 64) {
+           yasm__warning(YASM_WARN_GENERAL, line,
+                         N_("`%s' is a prefix in 64-bit mode"), id);
+           return YASM_ARCH_NOTINSNPREFIX;
        }
-    */
-    return 0;
+       data[0] = type;
+       data[1] = value;
+       return YASM_ARCH_PREFIX;
+    }
 }
 
-int
-yasm_x86__parse_check_reg(yasm_arch *arch, unsigned long data[1],
-                         const char *id, unsigned long line)
+void
+yasm_x86__parse_cpu(yasm_arch *arch, const char *cpuid, size_t cpuid_len,
+                   unsigned long line)
 {
     yasm_arch_x86 *arch_x86 = (yasm_arch_x86 *)arch;
-    const char *oid = id;
-    /*!re2c
-       /* control, debug, and test registers */
-       'cr' [02-48]    {
-           if (arch_x86->mode_bits != 64 && oid[2] == '8') {
-               yasm__warning(YASM_WARN_GENERAL, line,
-                             N_("`%s' is a register in 64-bit mode"), oid);
-               return 0;
-           }
-           data[0] = X86_CRREG | (oid[2]-'0');
-           return 1;
-       }
-       'dr' [0-7]      {
-           data[0] = X86_DRREG | (oid[2]-'0');
-           return 1;
-       }
-       'tr' [0-7]      {
-           data[0] = X86_TRREG | (oid[2]-'0');
-           return 1;
-       }
-
-       /* floating point, MMX, and SSE/SSE2 registers */
-       'st' [0-7]      {
-           data[0] = X86_FPUREG | (oid[2]-'0');
-           return 1;
-       }
-       'mm' [0-7]      {
-           data[0] = X86_MMXREG | (oid[2]-'0');
-           return 1;
-       }
-       'xmm' [0-9]     {
-           if (arch_x86->mode_bits != 64 &&
-               (oid[3] == '8' || oid[3] == '9')) {
-               yasm__warning(YASM_WARN_GENERAL, line,
-                             N_("`%s' is a register in 64-bit mode"), oid);
-               return 0;
-           }
-           data[0] = X86_XMMREG | (oid[3]-'0');
-           return 1;
-       }
-       'xmm' "1" [0-5] {
-           if (arch_x86->mode_bits != 64) {
-               yasm__warning(YASM_WARN_GENERAL, line,
-                             N_("`%s' is a register in 64-bit mode"), oid);
-               return 0;
-           }
-           data[0] = X86_XMMREG | (10+oid[4]-'0');
-           return 1;
-       }
-
-       /* integer registers */
-       'rax'   {
-           if (arch_x86->mode_bits != 64) {
-               yasm__warning(YASM_WARN_GENERAL, line,
-                             N_("`%s' is a register in 64-bit mode"), oid);
-               return 0;
-           }
-           data[0] = X86_REG64 | 0;
-           return 1;
-       }
-       'rcx'   {
-           if (arch_x86->mode_bits != 64) {
-               yasm__warning(YASM_WARN_GENERAL, line,
-                             N_("`%s' is a register in 64-bit mode"), oid);
-               return 0;
-           }
-           data[0] = X86_REG64 | 1;
-           return 1;
-       }
-       'rdx'   {
-           if (arch_x86->mode_bits != 64) {
-               yasm__warning(YASM_WARN_GENERAL, line,
-                             N_("`%s' is a register in 64-bit mode"), oid);
-               return 0;
-           }
-           data[0] = X86_REG64 | 2;
-           return 1;
-       }
-       'rbx'   {
-           if (arch_x86->mode_bits != 64) {
-               yasm__warning(YASM_WARN_GENERAL, line,
-                             N_("`%s' is a register in 64-bit mode"), oid);
-               return 0;
-           }
-           data[0] = X86_REG64 | 3;
-           return 1;
-       }
-       'rsp'   {
-           if (arch_x86->mode_bits != 64) {
-               yasm__warning(YASM_WARN_GENERAL, line,
-                             N_("`%s' is a register in 64-bit mode"), oid);
-               return 0;
-           }
-           data[0] = X86_REG64 | 4;
-           return 1;
-       }
-       'rbp'   {
-           if (arch_x86->mode_bits != 64) {
-               yasm__warning(YASM_WARN_GENERAL, line,
-                             N_("`%s' is a register in 64-bit mode"), oid);
-               return 0;
-           }
-           data[0] = X86_REG64 | 5;
-           return 1;
-       }
-       'rsi'   {
-           if (arch_x86->mode_bits != 64) {
-               yasm__warning(YASM_WARN_GENERAL, line,
-                             N_("`%s' is a register in 64-bit mode"), oid);
-               return 0;
-           }
-           data[0] = X86_REG64 | 6;
-           return 1;
-       }
-       'rdi'   {
-           if (arch_x86->mode_bits != 64) {
-               yasm__warning(YASM_WARN_GENERAL, line,
-                             N_("`%s' is a register in 64-bit mode"), oid);
-               return 0;
-           }
-           data[0] = X86_REG64 | 7;
-           return 1;
-       }
-       R [8-9]   {
-           if (arch_x86->mode_bits != 64) {
-               yasm__warning(YASM_WARN_GENERAL, line,
-                             N_("`%s' is a register in 64-bit mode"), oid);
-               return 0;
-           }
-           data[0] = X86_REG64 | (oid[1]-'0');
-           return 1;
-       }
-       'r1' [0-5] {
-           if (arch_x86->mode_bits != 64) {
-               yasm__warning(YASM_WARN_GENERAL, line,
-                             N_("`%s' is a register in 64-bit mode"), oid);
-               return 0;
-           }
-           data[0] = X86_REG64 | (10+oid[2]-'0');
-           return 1;
-       }
-
-       'eax'   { data[0] = X86_REG32 | 0; return 1; }
-       'ecx'   { data[0] = X86_REG32 | 1; return 1; }
-       'edx'   { data[0] = X86_REG32 | 2; return 1; }
-       'ebx'   { data[0] = X86_REG32 | 3; return 1; }
-       'esp'   { data[0] = X86_REG32 | 4; return 1; }
-       'ebp'   { data[0] = X86_REG32 | 5; return 1; }
-       'esi'   { data[0] = X86_REG32 | 6; return 1; }
-       'edi'   { data[0] = X86_REG32 | 7; return 1; }
-       R [8-9] D {
-           if (arch_x86->mode_bits != 64) {
-               yasm__warning(YASM_WARN_GENERAL, line,
-                             N_("`%s' is a register in 64-bit mode"), oid);
-               return 0;
-           }
-           data[0] = X86_REG32 | (oid[1]-'0');
-           return 1;
-       }
-       R "1" [0-5] D {
-           if (arch_x86->mode_bits != 64) {
-               yasm__warning(YASM_WARN_GENERAL, line,
-                             N_("`%s' is a register in 64-bit mode"), oid);
-               return 0;
-           }
-           data[0] = X86_REG32 | (10+oid[2]-'0');
-           return 1;
-       }
-
-       'ax'    { data[0] = X86_REG16 | 0; return 1; }
-       'cx'    { data[0] = X86_REG16 | 1; return 1; }
-       'dx'    { data[0] = X86_REG16 | 2; return 1; }
-       'bx'    { data[0] = X86_REG16 | 3; return 1; }
-       'sp'    { data[0] = X86_REG16 | 4; return 1; }
-       'bp'    { data[0] = X86_REG16 | 5; return 1; }
-       'si'    { data[0] = X86_REG16 | 6; return 1; }
-       'di'    { data[0] = X86_REG16 | 7; return 1; }
-       R [8-9] W {
-           if (arch_x86->mode_bits != 64) {
-               yasm__warning(YASM_WARN_GENERAL, line,
-                             N_("`%s' is a register in 64-bit mode"), oid);
-               return 0;
-           }
-           data[0] = X86_REG16 | (oid[1]-'0');
-           return 1;
-       }
-       R "1" [0-5] W {
-           if (arch_x86->mode_bits != 64) {
-               yasm__warning(YASM_WARN_GENERAL, line,
-                             N_("`%s' is a register in 64-bit mode"), oid);
-               return 0;
-           }
-           data[0] = X86_REG16 | (10+oid[2]-'0');
-           return 1;
-       }
-
-       'al'    { data[0] = X86_REG8 | 0; return 1; }
-       'cl'    { data[0] = X86_REG8 | 1; return 1; }
-       'dl'    { data[0] = X86_REG8 | 2; return 1; }
-       'bl'    { data[0] = X86_REG8 | 3; return 1; }
-       'ah'    { data[0] = X86_REG8 | 4; return 1; }
-       'ch'    { data[0] = X86_REG8 | 5; return 1; }
-       'dh'    { data[0] = X86_REG8 | 6; return 1; }
-       'bh'    { data[0] = X86_REG8 | 7; return 1; }
-       'spl'   {
-           if (arch_x86->mode_bits != 64) {
-               yasm__warning(YASM_WARN_GENERAL, line,
-                             N_("`%s' is a register in 64-bit mode"), oid);
-               return 0;
-           }
-           data[0] = X86_REG8X | 4;
-           return 1;
-       }
-       'bpl'   {
-           if (arch_x86->mode_bits != 64) {
-               yasm__warning(YASM_WARN_GENERAL, line,
-                             N_("`%s' is a register in 64-bit mode"), oid);
-               return 0;
-           }
-           data[0] = X86_REG8X | 5;
-           return 1;
-       }
-       'sil'   {
-           if (arch_x86->mode_bits != 64) {
-               yasm__warning(YASM_WARN_GENERAL, line,
-                             N_("`%s' is a register in 64-bit mode"), oid);
-               return 0;
-           }
-           data[0] = X86_REG8X | 6;
-           return 1;
-       }
-       'dil'   {
-           if (arch_x86->mode_bits != 64) {
-               yasm__warning(YASM_WARN_GENERAL, line,
-                             N_("`%s' is a register in 64-bit mode"), oid);
-               return 0;
-           }
-           data[0] = X86_REG8X | 7;
-           return 1;
-       }
-       R [8-9] B {
-           if (arch_x86->mode_bits != 64) {
-               yasm__warning(YASM_WARN_GENERAL, line,
-                             N_("`%s' is a register in 64-bit mode"), oid);
-               return 0;
-           }
-           data[0] = X86_REG8 | (oid[1]-'0');
-           return 1;
-       }
-       R "1" [0-5] B {
-           if (arch_x86->mode_bits != 64) {
-               yasm__warning(YASM_WARN_GENERAL, line,
-                             N_("`%s' is a register in 64-bit mode"), oid);
-               return 0;
-           }
-           data[0] = X86_REG8 | (10+oid[2]-'0');
-           return 1;
-       }
-
-       /* RIP for 64-bit mode IP-relative offsets */
-       'rip'   {
-           if (arch_x86->mode_bits != 64) {
-               yasm__warning(YASM_WARN_GENERAL, line,
-                             N_("`%s' is a register in 64-bit mode"), oid);
-               return 0;
-           }
-           data[0] = X86_RIP;
-           return 1;
-       }
-
-       /* catchalls */
-       [\001-\377]+    {
-           return 0;
-       }
-       [\000]  {
-           return 0;
-       }
-    */
-    return 0;
-}
-
-int
-yasm_x86__parse_check_reggroup(yasm_arch *arch, unsigned long data[1],
-                              const char *id, unsigned long line)
-{
-    /*const char *oid = id;*/
-    /*!re2c
-       /* floating point, MMX, and SSE/SSE2 registers */
-       'st'            {
-           data[0] = X86_FPUREG;
-           return 1;
-       }
-       'mm'            {
-           data[0] = X86_MMXREG;
-           return 1;
-       }
-       'xmm'           {
-           data[0] = X86_XMMREG;
-           return 1;
-       }
+    /*@null@*/ const cpu_parse_data *pdata;
+    size_t i;
+    static char lcaseid[16];
 
-       /* catchalls */
-       [\001-\377]+    {
-           return 0;
-       }
-       [\000]  {
-           return 0;
-       }
-    */
-    return 0;
-}
+    if (cpuid_len > 15)
+       return;
+    for (i=0; i<cpuid_len; i++)
+       lcaseid[i] = tolower(cpuid[i]);
+    lcaseid[cpuid_len] = '\0';
 
-int
-yasm_x86__parse_check_segreg(yasm_arch *arch, unsigned long data[1],
-                            const char *id, unsigned long line)
-{
-    yasm_arch_x86 *arch_x86 = (yasm_arch_x86 *)arch;
-    const char *oid = id;
-    /*!re2c
-       /* segment registers */
-       'es'    {
-           if (arch_x86->mode_bits == 64)
-               yasm__warning(YASM_WARN_GENERAL, line,
-                   N_("`%s' segment register ignored in 64-bit mode"), oid);
-           data[0] = 0x2600;
-           return 1;
-       }
-       'cs'    { data[0] = 0x2e01; return 1; }
-       'ss'    {
-           if (arch_x86->mode_bits == 64)
-               yasm__warning(YASM_WARN_GENERAL, line,
-                   N_("`%s' segment register ignored in 64-bit mode"), oid);
-           data[0] = 0x3602;
-           return 1;
-       }
-       'ds'    {
-           if (arch_x86->mode_bits == 64)
-               yasm__warning(YASM_WARN_GENERAL, line,
-                   N_("`%s' segment register ignored in 64-bit mode"), oid);
-           data[0] = 0x3e03;
-           return 1;
-       }
-       'fs'    { data[0] = 0x6404; return 1; }
-       'gs'    { data[0] = 0x6505; return 1; }
+    pdata = cpu_find(lcaseid, cpuid_len);
+    if (!pdata) {
+       yasm__warning(YASM_WARN_GENERAL, line,
+                     N_("unrecognized CPU identifier `%s'"), cpuid);
+       return;
+    }
 
-       /* catchalls */
-       [\001-\377]+    {
-           return 0;
-       }
-       [\000]  {
-           return 0;
-       }
-    */
-    return 0;
+    switch (pdata->mode) {
+       case CPU_MODE_VERBATIM:
+           arch_x86->cpu_enabled = pdata->cpu;
+           break;
+       case CPU_MODE_SET:
+           arch_x86->cpu_enabled |= pdata->cpu;
+           break;
+       case CPU_MODE_CLEAR:
+           arch_x86->cpu_enabled &= ~pdata->cpu;
+           break;
+    }
 }
 
-#define RET_INSN(nosuffixsize, group, mod, cpu)        do { \
-    suffix = (id-oid) > nosuffixsize; \
-    DEF_INSN_DATA(group, mod, cpu); \
-    goto done; \
-    } while (0)
-
-/* No suffix version of RET_INSN */
-#define RET_INSN_NS(group, mod, cpu)   do { \
-    DEF_INSN_DATA(group, mod, cpu); \
-    goto done; \
-    } while (0)
-
-#define RET_INSN_GAS(nosuffixsize, group, mod, cpu) do { \
-    if (arch_x86->parser != X86_PARSER_GAS) \
-       return 0; \
-    RET_INSN(nosuffixsize, group, mod, cpu); \
-    } while (0)
-
-#define RET_INSN_NONGAS(nosuffixsize, group, mod, cpu) do { \
-    if (arch_x86->parser == X86_PARSER_GAS) \
-       return 0; \
-    RET_INSN(nosuffixsize, group, mod, cpu); \
-    } while (0)
-
-int
-yasm_x86__parse_check_insn(yasm_arch *arch, unsigned long data[4],
-                          const char *id, unsigned long line)
+yasm_arch_regtmod
+yasm_x86__parse_check_regtmod(yasm_arch *arch, unsigned long *data,
+                             const char *id, size_t id_len, unsigned long line)
 {
     yasm_arch_x86 *arch_x86 = (yasm_arch_x86 *)arch;
-    const char *oid = id;
-    /*const char *marker;*/
-    int suffix = 0;
-    int not64 = 0;
-    int warn64 = 0;
-    int suffix_ofs = -1;
-    char suffix_over = '\0';
-
-    data[3] = arch_x86->mode_bits;
-
-    /*!re2c
-       /* instructions */
-
-       /* Move */
-       'mov' [bBwWlL]? { RET_INSN(3, mov, 0, CPU_Any); }
-       'movabs' [bBwWlLqQ]? { RET_INSN_GAS(6, movabs, 0, CPU_Hammer|CPU_64); }
-       /* Move with sign/zero extend */
-       'movsb' [wWlL] { suffix_ofs = -2; RET_INSN_GAS(4, movszx, 0xBE, CPU_386); }
-       'movswl' { suffix_ofs = -2; RET_INSN_GAS(4, movszx, 0xBE, CPU_386); }
-       'movs' [bBwW] Q {
-           suffix_ofs = -2;
-           warn64 = 1;
-           RET_INSN_GAS(4, movszx, 0xBE, CPU_Hammer|CPU_64);
-       }
-       'movsx' [bBwW]? { RET_INSN(5, movszx, 0xBE, CPU_386); }
-       'movslq' {
-           suffix_ofs = -2;
-           warn64 = 1;
-           RET_INSN_GAS(4, movsxd, 0, CPU_Hammer|CPU_64);
-       }
-       'movsxd' {
-           warn64 = 1;
-           RET_INSN_NONGAS(6, movsxd, 0, CPU_Hammer|CPU_64);
-       }
-       'movzb' [wWlL] { suffix_ofs = -2; RET_INSN_GAS(4, movszx, 0xB6, CPU_386); }
-       'movzwl' { suffix_ofs = -2; RET_INSN_GAS(4, movszx, 0xB6, CPU_386); }
-       'movz' [bBwW] Q {
-           suffix_ofs = -2;
-           warn64 = 1;
-           RET_INSN_GAS(4, movszx, 0xB6, CPU_Hammer|CPU_64);
-       }
-       'movzx' { RET_INSN_NS(movszx, 0xB6, CPU_386); }
-       /* Push instructions */
-       'push' [wWlLqQ]? { RET_INSN(4, push, 0, CPU_Any); }
-       'pusha' {
-           not64 = 1;
-           RET_INSN_NS(onebyte, 0x0060, CPU_186);
-       }
-       'pushad' {
-           not64 = 1;
-           RET_INSN_NONGAS(6, onebyte, 0x2060, CPU_386);
-       }
-       'pushal' {
-           not64 = 1;
-           RET_INSN_GAS(6, onebyte, 0x2060, CPU_386);
-       }
-       'pushaw' {
-           not64 = 1;
-           RET_INSN_NS(onebyte, 0x1060, CPU_186);
-       }
-       /* Pop instructions */
-       'pop' [wWlLqQ]? { RET_INSN(3, pop, 0, CPU_Any); }
-       'popa' {
-           not64 = 1;
-           RET_INSN_NS(onebyte, 0x0061, CPU_186);
-       }
-       'popad' {
-           not64 = 1;
-           RET_INSN_NONGAS(5, onebyte, 0x2061, CPU_386);
-       }
-       'popal' {
-           not64 = 1;
-           RET_INSN_GAS(5, onebyte, 0x2061, CPU_386);
-       }
-       'popaw' {
-           not64 = 1;
-           RET_INSN_NS(onebyte, 0x1061, CPU_186);
-       }
-       /* Exchange */
-       'xchg' [bBwWlLqQ]? { RET_INSN(4, xchg, 0, CPU_Any); }
-       /* In/out from ports */
-       'in' [bBwWlL]? { RET_INSN(2, in, 0, CPU_Any); }
-       'out' [bBwWlL]? { RET_INSN(3, out, 0, CPU_Any); }
-       /* Load effective address */
-       'lea' [wWlLqQ]? { RET_INSN(3, lea, 0, CPU_Any); }
-       /* Load segment registers from memory */
-       'lds' [wWlL]? {
-           not64 = 1;
-           RET_INSN(3, ldes, 0xC5, CPU_Any);
-       }
-       'les' [wWlL]? {
-           not64 = 1;
-           RET_INSN(3, ldes, 0xC4, CPU_Any);
-       }
-       'lfs' [wWlL]? { RET_INSN(3, lfgss, 0xB4, CPU_386); }
-       'lgs' [wWlL]? { RET_INSN(3, lfgss, 0xB5, CPU_386); }
-       'lss' [wWlL]? { RET_INSN(3, lfgss, 0xB2, CPU_386); }
-       /* Flags register instructions */
-       'clc' { RET_INSN_NS(onebyte, 0x00F8, CPU_Any); }
-       'cld' { RET_INSN_NS(onebyte, 0x00FC, CPU_Any); }
-       'cli' { RET_INSN_NS(onebyte, 0x00FA, CPU_Any); }
-       'clts' { RET_INSN_NS(twobyte, 0x0F06, CPU_286|CPU_Priv); }
-       'cmc' { RET_INSN_NS(onebyte, 0x00F5, CPU_Any); }
-       'lahf' { RET_INSN_NS(onebyte, 0x009F, CPU_Any); }
-       'sahf' { RET_INSN_NS(onebyte, 0x009E, CPU_Any); }
-       'pushf' { RET_INSN_NS(onebyte, 0x009C, CPU_Any); }
-       'pushfd' { RET_INSN_NONGAS(6, onebyte, 0x209C, CPU_386); }
-       'pushfl' { RET_INSN_GAS(6, onebyte, 0x209C, CPU_386); }
-       'pushfw' { RET_INSN_NS(onebyte, 0x109C, CPU_Any); }
-       'pushfq' {
-           warn64 = 1;
-           RET_INSN_NS(onebyte, 0x409C, CPU_Hammer|CPU_64);
-       }
-       'popf' { RET_INSN_NS(onebyte, 0x40009D, CPU_Any); }
-       'popfd' {
-           not64 = 1;
-           RET_INSN_NONGAS(5, onebyte, 0x00209D, CPU_386);
-       }
-       'popfl' {
-           not64 = 1;
-           RET_INSN_GAS(5, onebyte, 0x00209D, CPU_386);
-       }
-       'popfw' { RET_INSN_NS(onebyte, 0x40109D, CPU_Any); }
-       'popfq' {
-           warn64 = 1;
-           RET_INSN_NS(onebyte, 0x40409D, CPU_Hammer|CPU_64);
-       }
-       'stc' { RET_INSN_NS(onebyte, 0x00F9, CPU_Any); }
-       'std' { RET_INSN_NS(onebyte, 0x00FD, CPU_Any); }
-       'sti' { RET_INSN_NS(onebyte, 0x00FB, CPU_Any); }
-       /* Arithmetic */
-       'add' [bBwWlLqQ]? { RET_INSN(3, arith, 0x0000, CPU_Any); }
-       'inc' [bBwWlLqQ]? { RET_INSN(3, incdec, 0x0040, CPU_Any); }
-       'sub' [bBwWlLqQ]? { RET_INSN(3, arith, 0x0528, CPU_Any); }
-       'dec' [bBwWlLqQ]? { RET_INSN(3, incdec, 0x0148, CPU_Any); }
-       'sbb' [bBwWlLqQ]? { RET_INSN(3, arith, 0x0318, CPU_Any); }
-       'cmp' [bBwWlLqQ]? { RET_INSN(3, arith, 0x0738, CPU_Any); }
-       'test' [bBwWlLqQ]? { RET_INSN(4, test, 0, CPU_Any); }
-       'and' [bBwWlLqQ]? { RET_INSN(3, arith, 0x0420, CPU_Any); }
-       'or' [bBwWlLqQ]? { RET_INSN(2, arith, 0x0108, CPU_Any); }
-       'xor' [bBwWlLqQ]? { RET_INSN(3, arith, 0x0630, CPU_Any); }
-       'adc' [bBwWlLqQ]? { RET_INSN(3, arith, 0x0210, CPU_Any); }
-       'neg' [bBwWlLqQ]? { RET_INSN(3, f6, 0x03, CPU_Any); }
-       'not' [bBwWlLqQ]? { RET_INSN(3, f6, 0x02, CPU_Any); }
-       'aaa' {
-           not64 = 1;
-           RET_INSN_NS(onebyte, 0x0037, CPU_Any);
-       }
-       'aas' {
-           not64 = 1;
-           RET_INSN_NS(onebyte, 0x003F, CPU_Any);
-       }
-       'daa' {
-           not64 = 1;
-           RET_INSN_NS(onebyte, 0x0027, CPU_Any);
-       }
-       'das' {
-           not64 = 1;
-           RET_INSN_NS(onebyte, 0x002F, CPU_Any);
-       }
-       'aad' {
-           not64 = 1;
-           RET_INSN_NS(aadm, 0x01, CPU_Any);
-       }
-       'aam' {
-           not64 = 1;
-           RET_INSN_NS(aadm, 0x00, CPU_Any);
-       }
-       /* Conversion instructions */
-       'cbw' { RET_INSN_NS(onebyte, 0x1098, CPU_Any); }
-       'cwde' { RET_INSN_NS(onebyte, 0x2098, CPU_386); }
-       'cdqe' {
-           warn64 = 1;
-           RET_INSN_NS(onebyte, 0x4098, CPU_Hammer|CPU_64);
-       }
-       'cwd' { RET_INSN_NS(onebyte, 0x1099, CPU_Any); }
-       'cdq' { RET_INSN_NS(onebyte, 0x2099, CPU_386); }
-       'cqo' {
-           warn64 = 1;
-           RET_INSN_NS(onebyte, 0x4099, CPU_Hammer|CPU_64);
-       }
-       /* Conversion instructions - GAS / AT&T naming */
-       'cbtw' { RET_INSN_GAS(4, onebyte, 0x1098, CPU_Any); }
-       'cwtl' { RET_INSN_GAS(4, onebyte, 0x2098, CPU_386); }
-       'cltq' {
-           warn64 = 1;
-           RET_INSN_GAS(4, onebyte, 0x4098, CPU_Hammer|CPU_64);
-       }
-       'cwtd' { RET_INSN_GAS(4, onebyte, 0x1099, CPU_Any); }
-       'cltd' { RET_INSN_GAS(4, onebyte, 0x2099, CPU_386); }
-       'cqto' {
-           warn64 = 1;
-           RET_INSN_GAS(4, onebyte, 0x4099, CPU_Hammer|CPU_64);
-       }
-       /* Multiplication and division */
-       'mul' [bBwWlLqQ]? { RET_INSN(3, f6, 0x04, CPU_Any); }
-       'imul' [bBwWlLqQ]? { RET_INSN(4, imul, 0, CPU_Any); }
-       'div' [bBwWlLqQ]? { RET_INSN(3, div, 0x06, CPU_Any); }
-       'idiv' [bBwWlLqQ]? { RET_INSN(4, div, 0x07, CPU_Any); }
-       /* Shifts */
-       'rol' [bBwWlLqQ]? { RET_INSN(3, shift, 0x00, CPU_Any); }
-       'ror' [bBwWlLqQ]? { RET_INSN(3, shift, 0x01, CPU_Any); }
-       'rcl' [bBwWlLqQ]? { RET_INSN(3, shift, 0x02, CPU_Any); }
-       'rcr' [bBwWlLqQ]? { RET_INSN(3, shift, 0x03, CPU_Any); }
-       'sal' [bBwWlLqQ]? { RET_INSN(3, shift, 0x04, CPU_Any); }
-       'shl' [bBwWlLqQ]? { RET_INSN(3, shift, 0x04, CPU_Any); }
-       'shr' [bBwWlLqQ]? { RET_INSN(3, shift, 0x05, CPU_Any); }
-       'sar' [bBwWlLqQ]? { RET_INSN(3, shift, 0x07, CPU_Any); }
-       'shld' [wWlLqQ]? { RET_INSN(4, shlrd, 0xA4, CPU_386); }
-       'shrd' [wWlLqQ]? { RET_INSN(4, shlrd, 0xAC, CPU_386); }
-       /* Control transfer instructions (unconditional) */
-       'call' { RET_INSN(4, call, 0, CPU_Any); }
-       'jmp' { RET_INSN(3, jmp, 0, CPU_Any); }
-       'ret' { RET_INSN(3, retnf, 0x00C2, CPU_Any); }
-       'retw' { RET_INSN_GAS(3, retnf, 0x10C2, CPU_Any); }
-       'retl' {
-           not64 = 1;
-           RET_INSN_GAS(3, retnf, 0x00C2, CPU_Any);
-       }
-       'retq' {
-           warn64 = 1;
-           RET_INSN_GAS(3, retnf, 0x00C2, CPU_Hammer|CPU_64);
-       }
-       'retn' { RET_INSN_NONGAS(4, retnf, 0x00C2, CPU_Any); }
-       'retf' { RET_INSN_NONGAS(4, retnf, 0x40CA, CPU_Any); }
-       'lretw' { RET_INSN_GAS(4, retnf, 0x10CA, CPU_Any); }
-       'lretl' { RET_INSN_GAS(4, retnf, 0x00CA, CPU_Any); }
-       'lretq' {
-           warn64 = 1;
-           RET_INSN_GAS(4, retnf, 0x40CA, CPU_Any);
-       }
-       'enter' [wWlLqQ]? { RET_INSN(5, enter, 0, CPU_186); }
-       'leave' { RET_INSN_NS(onebyte, 0x4000C9, CPU_186); }
-       'leave' [wW] { RET_INSN_GAS(6, onebyte, 0x0010C9, CPU_186); }
-       'leave' [lLqQ] { RET_INSN_GAS(6, onebyte, 0x4000C9, CPU_186); }
-       /* Conditional jumps */
-       'jo' { RET_INSN_NS(jcc, 0x00, CPU_Any); }
-       'jno' { RET_INSN_NS(jcc, 0x01, CPU_Any); }
-       'jb' { RET_INSN_NS(jcc, 0x02, CPU_Any); }
-       'jc' { RET_INSN_NS(jcc, 0x02, CPU_Any); }
-       'jnae' { RET_INSN_NS(jcc, 0x02, CPU_Any); }
-       'jnb' { RET_INSN_NS(jcc, 0x03, CPU_Any); }
-       'jnc' { RET_INSN_NS(jcc, 0x03, CPU_Any); }
-       'jae' { RET_INSN_NS(jcc, 0x03, CPU_Any); }
-       'je' { RET_INSN_NS(jcc, 0x04, CPU_Any); }
-       'jz' { RET_INSN_NS(jcc, 0x04, CPU_Any); }
-       'jne' { RET_INSN_NS(jcc, 0x05, CPU_Any); }
-       'jnz' { RET_INSN_NS(jcc, 0x05, CPU_Any); }
-       'jbe' { RET_INSN_NS(jcc, 0x06, CPU_Any); }
-       'jna' { RET_INSN_NS(jcc, 0x06, CPU_Any); }
-       'jnbe' { RET_INSN_NS(jcc, 0x07, CPU_Any); }
-       'ja' { RET_INSN_NS(jcc, 0x07, CPU_Any); }
-       'js' { RET_INSN_NS(jcc, 0x08, CPU_Any); }
-       'jns' { RET_INSN_NS(jcc, 0x09, CPU_Any); }
-       'jp' { RET_INSN_NS(jcc, 0x0A, CPU_Any); }
-       'jpe' { RET_INSN_NS(jcc, 0x0A, CPU_Any); }
-       'jnp' { RET_INSN_NS(jcc, 0x0B, CPU_Any); }
-       'jpo' { RET_INSN_NS(jcc, 0x0B, CPU_Any); }
-       'jl' { RET_INSN_NS(jcc, 0x0C, CPU_Any); }
-       'jnge' { RET_INSN_NS(jcc, 0x0C, CPU_Any); }
-       'jnl' { RET_INSN_NS(jcc, 0x0D, CPU_Any); }
-       'jge' { RET_INSN_NS(jcc, 0x0D, CPU_Any); }
-       'jle' { RET_INSN_NS(jcc, 0x0E, CPU_Any); }
-       'jng' { RET_INSN_NS(jcc, 0x0E, CPU_Any); }
-       'jnle' { RET_INSN_NS(jcc, 0x0F, CPU_Any); }
-       'jg' { RET_INSN_NS(jcc, 0x0F, CPU_Any); }
-       'jcxz' { RET_INSN_NS(jcxz, 16, CPU_Any); }
-       'jecxz' { RET_INSN_NS(jcxz, 32, CPU_386); }
-       'jrcxz' {
-           warn64 = 1;
-           RET_INSN_NS(jcxz, 64, CPU_Hammer|CPU_64);
-       }
-       /* Loop instructions */
-       'loop' { RET_INSN_NS(loop, 0x02, CPU_Any); }
-       'loopz' { RET_INSN_NS(loop, 0x01, CPU_Any); }
-       'loope' { RET_INSN_NS(loop, 0x01, CPU_Any); }
-       'loopnz' { RET_INSN_NS(loop, 0x00, CPU_Any); }
-       'loopne' { RET_INSN_NS(loop, 0x00, CPU_Any); }
-       /* Set byte on flag instructions */
-       'seto' B? { RET_INSN(4, setcc, 0x00, CPU_386); }
-       'setno' B? { RET_INSN(5, setcc, 0x01, CPU_386); }
-       'setb' B? { RET_INSN(4, setcc, 0x02, CPU_386); }
-       'setc' B? { RET_INSN(4, setcc, 0x02, CPU_386); }
-       'setnae' B? { RET_INSN(6, setcc, 0x02, CPU_386); }
-       'setnb' B? { RET_INSN(5, setcc, 0x03, CPU_386); }
-       'setnc' B? { RET_INSN(5, setcc, 0x03, CPU_386); }
-       'setae' B? { RET_INSN(5, setcc, 0x03, CPU_386); }
-       'sete' B? { RET_INSN(4, setcc, 0x04, CPU_386); }
-       'setz' B? { RET_INSN(4, setcc, 0x04, CPU_386); }
-       'setne' B? { RET_INSN(5, setcc, 0x05, CPU_386); }
-       'setnz' B? { RET_INSN(5, setcc, 0x05, CPU_386); }
-       'setbe' B? { RET_INSN(5, setcc, 0x06, CPU_386); }
-       'setna' B? { RET_INSN(5, setcc, 0x06, CPU_386); }
-       'setnbe' B? { RET_INSN(6, setcc, 0x07, CPU_386); }
-       'seta' B? { RET_INSN(4, setcc, 0x07, CPU_386); }
-       'sets' B? { RET_INSN(4, setcc, 0x08, CPU_386); }
-       'setns' B? { RET_INSN(5, setcc, 0x09, CPU_386); }
-       'setp' B? { RET_INSN(4, setcc, 0x0A, CPU_386); }
-       'setpe' B? { RET_INSN(5, setcc, 0x0A, CPU_386); }
-       'setnp' B? { RET_INSN(5, setcc, 0x0B, CPU_386); }
-       'setpo' B? { RET_INSN(5, setcc, 0x0B, CPU_386); }
-       'setl' B? { RET_INSN(4, setcc, 0x0C, CPU_386); }
-       'setnge' B? { RET_INSN(6, setcc, 0x0C, CPU_386); }
-       'setnl' B? { RET_INSN(5, setcc, 0x0D, CPU_386); }
-       'setge' B? { RET_INSN(5, setcc, 0x0D, CPU_386); }
-       'setle' B? { RET_INSN(5, setcc, 0x0E, CPU_386); }
-       'setng' B? { RET_INSN(5, setcc, 0x0E, CPU_386); }
-       'setnle' B? { RET_INSN(6, setcc, 0x0F, CPU_386); }
-       'setg' B? { RET_INSN(4, setcc, 0x0F, CPU_386); }
-       /* String instructions. */
-       'cmpsb' { RET_INSN_NS(onebyte, 0x00A6, CPU_Any); }
-       'cmpsw' { RET_INSN_NS(onebyte, 0x10A7, CPU_Any); }
-       'cmpsd' { RET_INSN_NS(cmpsd, 0, CPU_Any); }
-       'cmpsl' { RET_INSN_GAS(5, onebyte, 0x20A7, CPU_386); }
-       'cmpsq' {
-           warn64 = 1;
-           RET_INSN_NS(onebyte, 0x40A7, CPU_Hammer|CPU_64);
-       }
-       'insb' { RET_INSN_NS(onebyte, 0x006C, CPU_Any); }
-       'insw' { RET_INSN_NS(onebyte, 0x106D, CPU_Any); }
-       'insd' { RET_INSN_NONGAS(4, onebyte, 0x206D, CPU_386); }
-       'insl' { RET_INSN_GAS(4, onebyte, 0x206D, CPU_386); }
-       'outsb' { RET_INSN_NS(onebyte, 0x006E, CPU_Any); }
-       'outsw' { RET_INSN_NS(onebyte, 0x106F, CPU_Any); }
-       'outsd' { RET_INSN_NONGAS(5, onebyte, 0x206F, CPU_386); }
-       'outsl' { RET_INSN_GAS(5, onebyte, 0x206F, CPU_386); }
-       'lodsb' { RET_INSN_NS(onebyte, 0x00AC, CPU_Any); }
-       'lodsw' { RET_INSN_NS(onebyte, 0x10AD, CPU_Any); }
-       'lodsd' { RET_INSN_NONGAS(5, onebyte, 0x20AD, CPU_386); }
-       'lodsl' { RET_INSN_GAS(5, onebyte, 0x20AD, CPU_386); }
-       'lodsq' {
-           warn64 = 1;
-           RET_INSN_NS(onebyte, 0x40AD, CPU_Hammer|CPU_64);
-       }
-       'movsb' { RET_INSN_NS(onebyte, 0x00A4, CPU_Any); }
-       'movsw' { RET_INSN_NS(onebyte, 0x10A5, CPU_Any); }
-       'movsd' { RET_INSN_NS(movsd, 0, CPU_Any); }
-       'movsl' { RET_INSN_GAS(5, onebyte, 0x20A5, CPU_386); }
-       'movsq' {
-           warn64 = 1;
-           RET_INSN_NS(onebyte, 0x40A5, CPU_Any);
-       }
-       /* smov alias for movs in GAS mode */
-       'smovb' { RET_INSN_GAS(5, onebyte, 0x00A4, CPU_Any); }
-       'smovw' { RET_INSN_GAS(5, onebyte, 0x10A5, CPU_Any); }
-       'smovl' { RET_INSN_GAS(5, onebyte, 0x20A5, CPU_386); }
-       'smovq' {
-           warn64 = 1;
-           RET_INSN_GAS(5, onebyte, 0x40A5, CPU_Any);
-       }
-       'scasb' { RET_INSN_NS(onebyte, 0x00AE, CPU_Any); }
-       'scasw' { RET_INSN_NS(onebyte, 0x10AF, CPU_Any); }
-       'scasd' { RET_INSN_NONGAS(5, onebyte, 0x20AF, CPU_386); }
-       'scasl' { RET_INSN_GAS(5, onebyte, 0x20AF, CPU_386); }
-       'scasq' {
-           warn64 = 1;
-           RET_INSN_NS(onebyte, 0x40AF, CPU_Hammer|CPU_64);
-       }
-       /* ssca alias for scas in GAS mode */
-       'sscab' { RET_INSN_GAS(5, onebyte, 0x00AE, CPU_Any); }
-       'sscaw' { RET_INSN_GAS(5, onebyte, 0x10AF, CPU_Any); }
-       'sscal' { RET_INSN_GAS(5, onebyte, 0x20AF, CPU_386); }
-       'sscaq' {
-           warn64 = 1;
-           RET_INSN_GAS(5, onebyte, 0x40AF, CPU_Hammer|CPU_64);
-       }
-       'stosb' { RET_INSN_NS(onebyte, 0x00AA, CPU_Any); }
-       'stosw' { RET_INSN_NS(onebyte, 0x10AB, CPU_Any); }
-       'stosd' { RET_INSN_NONGAS(5, onebyte, 0x20AB, CPU_386); }
-       'stosl' { RET_INSN_GAS(5, onebyte, 0x20AB, CPU_386); }
-       'stosq' {
-           warn64 = 1;
-           RET_INSN_NS(onebyte, 0x40AB, CPU_Hammer|CPU_64);
-       }
-       'xlat' B? { RET_INSN(5, onebyte, 0x00D7, CPU_Any); }
-       /* Bit manipulation */
-       'bsf' [wWlLqQ]? { RET_INSN(3, bsfr, 0xBC, CPU_386); }
-       'bsr' [wWlLqQ]? { RET_INSN(3, bsfr, 0xBD, CPU_386); }
-       'bt' [wWlLqQ]? { RET_INSN(2, bittest, 0x04A3, CPU_386); }
-       'btc' [wWlLqQ]? { RET_INSN(3, bittest, 0x07BB, CPU_386); }
-       'btr' [wWlLqQ]? { RET_INSN(3, bittest, 0x06B3, CPU_386); }
-       'bts' [wWlLqQ]? { RET_INSN(3, bittest, 0x05AB, CPU_386); }
-       /* Interrupts and operating system instructions */
-       'int' { RET_INSN_NS(int, 0, CPU_Any); }
-       'int3' { RET_INSN_NS(onebyte, 0x00CC, CPU_Any); }
-       'int03' { RET_INSN_NONGAS(5, onebyte, 0x00CC, CPU_Any); }
-       'into' {
-           not64 = 1;
-           RET_INSN_NS(onebyte, 0x00CE, CPU_Any);
-       }
-       'iret' { RET_INSN_NS(onebyte, 0x00CF, CPU_Any); }
-       'iretw' { RET_INSN_NS(onebyte, 0x10CF, CPU_Any); }
-       'iretd' { RET_INSN_NONGAS(5, onebyte, 0x20CF, CPU_386); }
-       'iretl' { RET_INSN_GAS(5, onebyte, 0x20CF, CPU_386); }
-       'iretq' {
-           warn64 = 1;
-           RET_INSN_NS(onebyte, 0x40CF, CPU_Hammer|CPU_64);
-       }
-       'rsm' { RET_INSN_NS(twobyte, 0x0FAA, CPU_586|CPU_SMM); }
-       'bound' [wWlL]? {
-           not64 = 1;
-           RET_INSN(5, bound, 0, CPU_186);
-       }
-       'hlt' { RET_INSN_NS(onebyte, 0x00F4, CPU_Priv); }
-       'nop' { RET_INSN_NS(onebyte, 0x0090, CPU_Any); }
-       /* Protection control */
-       'arpl' W? {
-           not64 = 1;
-           RET_INSN(4, arpl, 0, CPU_286|CPU_Prot);
-       }
-       'lar' [wWlLqQ]? { RET_INSN(3, bsfr, 0x02, CPU_286|CPU_Prot); }
-       'lgdt' [wWlLqQ]? { RET_INSN(4, twobytemem, 0x020F01, CPU_286|CPU_Priv); }
-       'lidt' [wWlLqQ]? { RET_INSN(4, twobytemem, 0x030F01, CPU_286|CPU_Priv); }
-       'lldt' W? { RET_INSN(4, prot286, 0x0200, CPU_286|CPU_Prot|CPU_Priv); }
-       'lmsw' W? { RET_INSN(4, prot286, 0x0601, CPU_286|CPU_Priv); }
-       'lsl' [wWlLqQ]? { RET_INSN(3, bsfr, 0x03, CPU_286|CPU_Prot); }
-       'ltr' W? { RET_INSN(3, prot286, 0x0300, CPU_286|CPU_Prot|CPU_Priv); }
-       'sgdt' [wWlLqQ]? { RET_INSN(4, twobytemem, 0x000F01, CPU_286|CPU_Priv); }
-       'sidt' [wWlLqQ]? { RET_INSN(4, twobytemem, 0x010F01, CPU_286|CPU_Priv); }
-       'sldt' [wWlLqQ]? { RET_INSN(4, sldtmsw, 0x0000, CPU_286); }
-       'smsw' [wWlLqQ]? { RET_INSN(4, sldtmsw, 0x0401, CPU_286); }
-       'str' [wWlLqQ]? { RET_INSN(3, str, 0, CPU_286|CPU_Prot); }
-       'verr' W? { RET_INSN(4, prot286, 0x0400, CPU_286|CPU_Prot); }
-       'verw' W? { RET_INSN(4, prot286, 0x0500, CPU_286|CPU_Prot); }
-       /* Floating point instructions */
-       'fld' [lLsS]? { RET_INSN(3, fld, 0, CPU_FPU); }
-       'fldt' {
-           data[3] |= 0x80 << 8;
-           RET_INSN_GAS(4, fldstpt, 0x05, CPU_FPU);
-       }
-       'fild' [lLqQsS]? { RET_INSN(4, fildstp, 0x050200, CPU_FPU); }
-       'fildll' { RET_INSN_GAS(6, fbldstp, 0x05, CPU_FPU); }
-       'fbld' { RET_INSN(4, fbldstp, 0x04, CPU_FPU); }
-       'fst' [lLsS]? { RET_INSN(3, fst, 0, CPU_FPU); }
-       'fist' [lLsS]? { RET_INSN(4, fiarith, 0x02DB, CPU_FPU); }
-       'fstp' [lLsS]? { RET_INSN(4, fstp, 0, CPU_FPU); }
-       'fstpt' {
-           data[3] |= 0x80 << 8;
-           RET_INSN_GAS(5, fldstpt, 0x07, CPU_FPU);
-       }
-       'fistp' [lLqQsS]? { RET_INSN(5, fildstp, 0x070203, CPU_FPU); }
-       'fistpll' { RET_INSN_GAS(7, fbldstp, 0x07, CPU_FPU); }
-       'fbstp' { RET_INSN_NS(fbldstp, 0x06, CPU_FPU); }
-       'fxch' { RET_INSN_NS(fxch, 0, CPU_FPU); }
-       'fcom' [lLsS]? { RET_INSN(4, fcom, 0x02D0, CPU_FPU); }
-       'ficom' [lLsS]? { RET_INSN(5, fiarith, 0x02DA, CPU_FPU); }
-       'fcomp' [lLsS]? { RET_INSN(5, fcom, 0x03D8, CPU_FPU); }
-       'ficomp' [lLsS]? { RET_INSN(6, fiarith, 0x03DA, CPU_FPU); }
-       'fcompp' { RET_INSN_NS(twobyte, 0xDED9, CPU_FPU); }
-       'fucom' { RET_INSN_NS(fcom2, 0xDDE0, CPU_286|CPU_FPU); }
-       'fucomp' { RET_INSN_NS(fcom2, 0xDDE8, CPU_286|CPU_FPU); }
-       'fucompp' { RET_INSN_NS(twobyte, 0xDAE9, CPU_286|CPU_FPU); }
-       'ftst' { RET_INSN_NS(twobyte, 0xD9E4, CPU_FPU); }
-       'fxam' { RET_INSN_NS(twobyte, 0xD9E5, CPU_FPU); }
-       'fld1' { RET_INSN_NS(twobyte, 0xD9E8, CPU_FPU); }
-       'fldl2t' { RET_INSN_NS(twobyte, 0xD9E9, CPU_FPU); }
-       'fldl2e' { RET_INSN_NS(twobyte, 0xD9EA, CPU_FPU); }
-       'fldpi' { RET_INSN_NS(twobyte, 0xD9EB, CPU_FPU); }
-       'fldlg2' { RET_INSN_NS(twobyte, 0xD9EC, CPU_FPU); }
-       'fldln2' { RET_INSN_NS(twobyte, 0xD9ED, CPU_FPU); }
-       'fldz' { RET_INSN_NS(twobyte, 0xD9EE, CPU_FPU); }
-       'fadd' [lLsS]? { RET_INSN(4, farith, 0x00C0C0, CPU_FPU); }
-       'faddp' { RET_INSN_NS(farithp, 0xC0, CPU_FPU); }
-       'fiadd' [lLsS]? { RET_INSN(5, fiarith, 0x00DA, CPU_FPU); }
-       'fsub' [lLsS]? { RET_INSN(4, farith, 0x04E0E8, CPU_FPU); }
-       'fisub' [lLsS]? { RET_INSN(5, fiarith, 0x04DA, CPU_FPU); }
-       'fsubp' { RET_INSN_NS(farithp, 0xE8, CPU_FPU); }
-       'fsubr' [lLsS]? { RET_INSN(5, farith, 0x05E8E0, CPU_FPU); }
-       'fisubr' [lLsS]? { RET_INSN(6, fiarith, 0x05DA, CPU_FPU); }
-       'fsubrp' { RET_INSN_NS(farithp, 0xE0, CPU_FPU); }
-       'fmul' [lLsS]? { RET_INSN(4, farith, 0x01C8C8, CPU_FPU); }
-       'fimul' [lLsS]? { RET_INSN(5, fiarith, 0x01DA, CPU_FPU); }
-       'fmulp' { RET_INSN_NS(farithp, 0xC8, CPU_FPU); }
-       'fdiv' [lLsS]? { RET_INSN(4, farith, 0x06F0F8, CPU_FPU); }
-       'fidiv' [lLsS]? { RET_INSN(5, fiarith, 0x06DA, CPU_FPU); }
-       'fdivp' { RET_INSN_NS(farithp, 0xF8, CPU_FPU); }
-       'fdivr' [lLsS]? { RET_INSN(5, farith, 0x07F8F0, CPU_FPU); }
-       'fidivr' [lLsS]? { RET_INSN(6, fiarith, 0x07DA, CPU_FPU); }
-       'fdivrp' { RET_INSN_NS(farithp, 0xF0, CPU_FPU); }
-       'f2xm1' { RET_INSN_NS(twobyte, 0xD9F0, CPU_FPU); }
-       'fyl2x' { RET_INSN_NS(twobyte, 0xD9F1, CPU_FPU); }
-       'fptan' { RET_INSN_NS(twobyte, 0xD9F2, CPU_FPU); }
-       'fpatan' { RET_INSN_NS(twobyte, 0xD9F3, CPU_FPU); }
-       'fxtract' { RET_INSN_NS(twobyte, 0xD9F4, CPU_FPU); }
-       'fprem1' { RET_INSN_NS(twobyte, 0xD9F5, CPU_286|CPU_FPU); }
-       'fdecstp' { RET_INSN_NS(twobyte, 0xD9F6, CPU_FPU); }
-       'fincstp' { RET_INSN_NS(twobyte, 0xD9F7, CPU_FPU); }
-       'fprem' { RET_INSN_NS(twobyte, 0xD9F8, CPU_FPU); }
-       'fyl2xp1' { RET_INSN_NS(twobyte, 0xD9F9, CPU_FPU); }
-       'fsqrt' { RET_INSN_NS(twobyte, 0xD9FA, CPU_FPU); }
-       'fsincos' { RET_INSN_NS(twobyte, 0xD9FB, CPU_286|CPU_FPU); }
-       'frndint' { RET_INSN_NS(twobyte, 0xD9FC, CPU_FPU); }
-       'fscale' { RET_INSN_NS(twobyte, 0xD9FD, CPU_FPU); }
-       'fsin' { RET_INSN_NS(twobyte, 0xD9FE, CPU_286|CPU_FPU); }
-       'fcos' { RET_INSN_NS(twobyte, 0xD9FF, CPU_286|CPU_FPU); }
-       'fchs' { RET_INSN_NS(twobyte, 0xD9E0, CPU_FPU); }
-       'fabs' { RET_INSN_NS(twobyte, 0xD9E1, CPU_FPU); }
-       'fninit' { RET_INSN_NS(twobyte, 0xDBE3, CPU_FPU); }
-       'finit' { RET_INSN_NS(threebyte, 0x9BDBE3UL, CPU_FPU); }
-       'fldcw' W? { RET_INSN(5, fldnstcw, 0x05, CPU_FPU); }
-       'fnstcw' W? { RET_INSN(6, fldnstcw, 0x07, CPU_FPU); }
-       'fstcw' W? { RET_INSN(5, fstcw, 0, CPU_FPU); }
-       'fnstsw' W? { RET_INSN(6, fnstsw, 0, CPU_FPU); }
-       'fstsw' W? { RET_INSN(5, fstsw, 0, CPU_FPU); }
-       'fnclex' { RET_INSN_NS(twobyte, 0xDBE2, CPU_FPU); }
-       'fclex' { RET_INSN_NS(threebyte, 0x9BDBE2UL, CPU_FPU); }
-       'fnstenv' [lLsS]? { RET_INSN(7, onebytemem, 0x06D9, CPU_FPU); }
-       'fstenv' [lLsS]? { RET_INSN(6, twobytemem, 0x069BD9, CPU_FPU); }
-       'fldenv' [lLsS]? { RET_INSN(6, onebytemem, 0x04D9, CPU_FPU); }
-       'fnsave' [lLsS]? { RET_INSN(6, onebytemem, 0x06DD, CPU_FPU); }
-       'fsave' [lLsS]? { RET_INSN(5, twobytemem, 0x069BDD, CPU_FPU); }
-       'frstor' [lLsS]? { RET_INSN(6, onebytemem, 0x04DD, CPU_FPU); }
-       'ffree' { RET_INSN_NS(ffree, 0xDD, CPU_FPU); }
-       'ffreep' { RET_INSN_NS(ffree, 0xDF, CPU_686|CPU_FPU|CPU_Undoc); }
-       'fnop' { RET_INSN_NS(twobyte, 0xD9D0, CPU_FPU); }
-       'fwait' { RET_INSN_NS(onebyte, 0x009B, CPU_FPU); }
-       /* Prefixes (should the others be here too? should wait be a prefix? */
-       'wait' { RET_INSN_NS(onebyte, 0x009B, CPU_Any); }
-       /* 486 extensions */
-       'bswap' [lLqQ]? { RET_INSN(5, bswap, 0, CPU_486); }
-       'xadd' [bBwWlLqQ]? { RET_INSN(4, cmpxchgxadd, 0xC0, CPU_486); }
-       'cmpxchg' [bBwWlLqQ]? { RET_INSN(7, cmpxchgxadd, 0xB0, CPU_486); }
-       'cmpxchg486' { RET_INSN_NONGAS(10, cmpxchgxadd, 0xA6, CPU_486|CPU_Undoc); }
-       'invd' { RET_INSN_NS(twobyte, 0x0F08, CPU_486|CPU_Priv); }
-       'wbinvd' { RET_INSN_NS(twobyte, 0x0F09, CPU_486|CPU_Priv); }
-       'invlpg' { RET_INSN_NS(twobytemem, 0x070F01, CPU_486|CPU_Priv); }
-       /* 586+ and late 486 extensions */
-       'cpuid' { RET_INSN_NS(twobyte, 0x0FA2, CPU_486); }
-       /* Pentium extensions */
-       'wrmsr' { RET_INSN_NS(twobyte, 0x0F30, CPU_586|CPU_Priv); }
-       'rdtsc' { RET_INSN_NS(twobyte, 0x0F31, CPU_586); }
-       'rdmsr' { RET_INSN_NS(twobyte, 0x0F32, CPU_586|CPU_Priv); }
-       'cmpxchg8b' Q? { RET_INSN(9, cmpxchg8b, 0, CPU_586); }
-       /* Pentium II/Pentium Pro extensions */
-       'sysenter' {
-           not64 = 1;
-           RET_INSN_NS(twobyte, 0x0F34, CPU_686);
-       }
-       'sysexit' {
-           not64 = 1;
-           RET_INSN_NS(twobyte, 0x0F35, CPU_686|CPU_Priv);
-       }
-       'fxsave' Q? { RET_INSN(6, twobytemem, 0x000FAE, CPU_686|CPU_FPU); }
-       'fxrstor' Q? { RET_INSN(7, twobytemem, 0x010FAE, CPU_686|CPU_FPU); }
-       'rdpmc' { RET_INSN_NS(twobyte, 0x0F33, CPU_686); }
-       'ud2' { RET_INSN_NS(twobyte, 0x0F0B, CPU_286); }
-       'ud1' { RET_INSN_NS(twobyte, 0x0FB9, CPU_286|CPU_Undoc); }
-       'cmovo' [wWlLqQ]? { RET_INSN(5, cmovcc, 0x00, CPU_686); }
-       'cmovno' [wWlLqQ]? { RET_INSN(6, cmovcc, 0x01, CPU_686); }
-       'cmovb' [wWlLqQ]? { RET_INSN(5, cmovcc, 0x02, CPU_686); }
-       'cmovc' [wWlLqQ]? { RET_INSN(5, cmovcc, 0x02, CPU_686); }
-       'cmovnae' [wWlLqQ]? { RET_INSN(7, cmovcc, 0x02, CPU_686); }
-       'cmovnb' [wWlLqQ]? { RET_INSN(6, cmovcc, 0x03, CPU_686); }
-       'cmovnc' [wWlLqQ]? { RET_INSN(6, cmovcc, 0x03, CPU_686); }
-       'cmovae' [wWlLqQ]? { RET_INSN(6, cmovcc, 0x03, CPU_686); }
-       'cmove' [wWlLqQ]? { RET_INSN(5, cmovcc, 0x04, CPU_686); }
-       'cmovz' [wWlLqQ]? { RET_INSN(5, cmovcc, 0x04, CPU_686); }
-       'cmovne' [wWlLqQ]? { RET_INSN(6, cmovcc, 0x05, CPU_686); }
-       'cmovnz' [wWlLqQ]? { RET_INSN(6, cmovcc, 0x05, CPU_686); }
-       'cmovbe' [wWlLqQ]? { RET_INSN(6, cmovcc, 0x06, CPU_686); }
-       'cmovna' [wWlLqQ]? { RET_INSN(6, cmovcc, 0x06, CPU_686); }
-       'cmovnbe' [wWlLqQ]? { RET_INSN(7, cmovcc, 0x07, CPU_686); }
-       'cmova' [wWlLqQ]? { RET_INSN(5, cmovcc, 0x07, CPU_686); }
-       'cmovs' [wWlLqQ]? { RET_INSN(5, cmovcc, 0x08, CPU_686); }
-       'cmovns' [wWlLqQ]? { RET_INSN(6, cmovcc, 0x09, CPU_686); }
-       'cmovp' [wWlLqQ]? { RET_INSN(5, cmovcc, 0x0A, CPU_686); }
-       'cmovpe' [wWlLqQ]? { RET_INSN(6, cmovcc, 0x0A, CPU_686); }
-       'cmovnp' [wWlLqQ]? { RET_INSN(6, cmovcc, 0x0B, CPU_686); }
-       'cmovpo' [wWlLqQ]? { RET_INSN(6, cmovcc, 0x0B, CPU_686); }
-       'cmovl' [wWlLqQ]? { RET_INSN(5, cmovcc, 0x0C, CPU_686); }
-       'cmovnge' [wWlLqQ]? { RET_INSN(7, cmovcc, 0x0C, CPU_686); }
-       'cmovnl' [wWlLqQ]? { RET_INSN(6, cmovcc, 0x0D, CPU_686); }
-       'cmovge' [wWlLqQ]? { RET_INSN(6, cmovcc, 0x0D, CPU_686); }
-       'cmovle' [wWlLqQ]? { RET_INSN(6, cmovcc, 0x0E, CPU_686); }
-       'cmovng' [wWlLqQ]? { RET_INSN(6, cmovcc, 0x0E, CPU_686); }
-       'cmovnle' [wWlLqQ]? { RET_INSN(7, cmovcc, 0x0F, CPU_686); }
-       'cmovg' [wWlLqQ]? { RET_INSN(5, cmovcc, 0x0F, CPU_686); }
-       'fcmovb' { RET_INSN_NS(fcmovcc, 0xDAC0, CPU_686|CPU_FPU); }
-       'fcmove' { RET_INSN_NS(fcmovcc, 0xDAC8, CPU_686|CPU_FPU); }
-       'fcmovbe' { RET_INSN_NS(fcmovcc, 0xDAD0, CPU_686|CPU_FPU); }
-       'fcmovu' { RET_INSN_NS(fcmovcc, 0xDAD8, CPU_686|CPU_FPU); }
-       'fcmovnb' { RET_INSN_NS(fcmovcc, 0xDBC0, CPU_686|CPU_FPU); }
-       'fcmovne' { RET_INSN_NS(fcmovcc, 0xDBC8, CPU_686|CPU_FPU); }
-       'fcmovnbe' { RET_INSN_NS(fcmovcc, 0xDBD0, CPU_686|CPU_FPU); }
-       'fcmovnu' { RET_INSN_NS(fcmovcc, 0xDBD8, CPU_686|CPU_FPU); }
-       'fcomi' { RET_INSN_NS(fcom2, 0xDBF0, CPU_686|CPU_FPU); }
-       'fucomi' { RET_INSN_NS(fcom2, 0xDBE8, CPU_686|CPU_FPU); }
-       'fcomip' { RET_INSN_NS(fcom2, 0xDFF0, CPU_686|CPU_FPU); }
-       'fucomip' { RET_INSN_NS(fcom2, 0xDFE8, CPU_686|CPU_FPU); }
-       /* Pentium4 extensions */
-       'movnti' [lLqQ]? { RET_INSN(6, movnti, 0, CPU_P4); }
-       'clflush' { RET_INSN_NS(clflush, 0, CPU_P3); }
-       'lfence' { RET_INSN_NS(threebyte, 0x0FAEE8, CPU_P3); }
-       'mfence' { RET_INSN_NS(threebyte, 0x0FAEF0, CPU_P3); }
-       'pause' { RET_INSN_NS(onebyte_prefix, 0xF390, CPU_P4); }
-       /* MMX/SSE2 instructions */
-       'emms' { RET_INSN_NS(twobyte, 0x0F77, CPU_MMX); }
-       'movd' { RET_INSN_NS(movd, 0, CPU_MMX); }
-       'movq' {
-           if (arch_x86->parser == X86_PARSER_GAS)
-               RET_INSN(3, mov, 0, CPU_Any);
-           else
-               RET_INSN_NS(movq, 0, CPU_MMX);
-       }
-       'packssdw' { RET_INSN_NS(mmxsse2, 0x6B, CPU_MMX); }
-       'packsswb' { RET_INSN_NS(mmxsse2, 0x63, CPU_MMX); }
-       'packuswb' { RET_INSN_NS(mmxsse2, 0x67, CPU_MMX); }
-       'paddb' { RET_INSN_NS(mmxsse2, 0xFC, CPU_MMX); }
-       'paddw' { RET_INSN_NS(mmxsse2, 0xFD, CPU_MMX); }
-       'paddd' { RET_INSN_NS(mmxsse2, 0xFE, CPU_MMX); }
-       'paddq' { RET_INSN_NS(mmxsse2, 0xD4, CPU_MMX); }
-       'paddsb' { RET_INSN_NS(mmxsse2, 0xEC, CPU_MMX); }
-       'paddsw' { RET_INSN_NS(mmxsse2, 0xED, CPU_MMX); }
-       'paddusb' { RET_INSN_NS(mmxsse2, 0xDC, CPU_MMX); }
-       'paddusw' { RET_INSN_NS(mmxsse2, 0xDD, CPU_MMX); }
-       'pand' { RET_INSN_NS(mmxsse2, 0xDB, CPU_MMX); }
-       'pandn' { RET_INSN_NS(mmxsse2, 0xDF, CPU_MMX); }
-       'pcmpeqb' { RET_INSN_NS(mmxsse2, 0x74, CPU_MMX); }
-       'pcmpeqw' { RET_INSN_NS(mmxsse2, 0x75, CPU_MMX); }
-       'pcmpeqd' { RET_INSN_NS(mmxsse2, 0x76, CPU_MMX); }
-       'pcmpgtb' { RET_INSN_NS(mmxsse2, 0x64, CPU_MMX); }
-       'pcmpgtw' { RET_INSN_NS(mmxsse2, 0x65, CPU_MMX); }
-       'pcmpgtd' { RET_INSN_NS(mmxsse2, 0x66, CPU_MMX); }
-       'pmaddwd' { RET_INSN_NS(mmxsse2, 0xF5, CPU_MMX); }
-       'pmulhw' { RET_INSN_NS(mmxsse2, 0xE5, CPU_MMX); }
-       'pmullw' { RET_INSN_NS(mmxsse2, 0xD5, CPU_MMX); }
-       'por' { RET_INSN_NS(mmxsse2, 0xEB, CPU_MMX); }
-       'psllw' { RET_INSN_NS(pshift, 0x0671F1, CPU_MMX); }
-       'pslld' { RET_INSN_NS(pshift, 0x0672F2, CPU_MMX); }
-       'psllq' { RET_INSN_NS(pshift, 0x0673F3, CPU_MMX); }
-       'psraw' { RET_INSN_NS(pshift, 0x0471E1, CPU_MMX); }
-       'psrad' { RET_INSN_NS(pshift, 0x0472E2, CPU_MMX); }
-       'psrlw' { RET_INSN_NS(pshift, 0x0271D1, CPU_MMX); }
-       'psrld' { RET_INSN_NS(pshift, 0x0272D2, CPU_MMX); }
-       'psrlq' { RET_INSN_NS(pshift, 0x0273D3, CPU_MMX); }
-       'psubb' { RET_INSN_NS(mmxsse2, 0xF8, CPU_MMX); }
-       'psubw' { RET_INSN_NS(mmxsse2, 0xF9, CPU_MMX); }
-       'psubd' { RET_INSN_NS(mmxsse2, 0xFA, CPU_MMX); }
-       'psubq' { RET_INSN_NS(mmxsse2, 0xFB, CPU_MMX); }
-       'psubsb' { RET_INSN_NS(mmxsse2, 0xE8, CPU_MMX); }
-       'psubsw' { RET_INSN_NS(mmxsse2, 0xE9, CPU_MMX); }
-       'psubusb' { RET_INSN_NS(mmxsse2, 0xD8, CPU_MMX); }
-       'psubusw' { RET_INSN_NS(mmxsse2, 0xD9, CPU_MMX); }
-       'punpckhbw' { RET_INSN_NS(mmxsse2, 0x68, CPU_MMX); }
-       'punpckhwd' { RET_INSN_NS(mmxsse2, 0x69, CPU_MMX); }
-       'punpckhdq' { RET_INSN_NS(mmxsse2, 0x6A, CPU_MMX); }
-       'punpcklbw' { RET_INSN_NS(mmxsse2, 0x60, CPU_MMX); }
-       'punpcklwd' { RET_INSN_NS(mmxsse2, 0x61, CPU_MMX); }
-       'punpckldq' { RET_INSN_NS(mmxsse2, 0x62, CPU_MMX); }
-       'pxor' { RET_INSN_NS(mmxsse2, 0xEF, CPU_MMX); }
-       /* PIII (Katmai) new instructions / SIMD instructions */
-       'addps' { RET_INSN_NS(sseps, 0x58, CPU_SSE); }
-       'addss' { RET_INSN_NS(ssess, 0xF358, CPU_SSE); }
-       'andnps' { RET_INSN_NS(sseps, 0x55, CPU_SSE); }
-       'andps' { RET_INSN_NS(sseps, 0x54, CPU_SSE); }
-       'cmpeqps' { RET_INSN_NS(ssecmpps, 0x00, CPU_SSE); }
-       'cmpeqss' { RET_INSN_NS(ssecmpss, 0x00F3, CPU_SSE); }
-       'cmpleps' { RET_INSN_NS(ssecmpps, 0x02, CPU_SSE); }
-       'cmpless' { RET_INSN_NS(ssecmpss, 0x02F3, CPU_SSE); }
-       'cmpltps' { RET_INSN_NS(ssecmpps, 0x01, CPU_SSE); }
-       'cmpltss' { RET_INSN_NS(ssecmpss, 0x01F3, CPU_SSE); }
-       'cmpneqps' { RET_INSN_NS(ssecmpps, 0x04, CPU_SSE); }
-       'cmpneqss' { RET_INSN_NS(ssecmpss, 0x04F3, CPU_SSE); }
-       'cmpnleps' { RET_INSN_NS(ssecmpps, 0x06, CPU_SSE); }
-       'cmpnless' { RET_INSN_NS(ssecmpss, 0x06F3, CPU_SSE); }
-       'cmpnltps' { RET_INSN_NS(ssecmpps, 0x05, CPU_SSE); }
-       'cmpnltss' { RET_INSN_NS(ssecmpss, 0x05F3, CPU_SSE); }
-       'cmpordps' { RET_INSN_NS(ssecmpps, 0x07, CPU_SSE); }
-       'cmpordss' { RET_INSN_NS(ssecmpss, 0x07F3, CPU_SSE); }
-       'cmpunordps' { RET_INSN_NS(ssecmpps, 0x03, CPU_SSE); }
-       'cmpunordss' { RET_INSN_NS(ssecmpss, 0x03F3, CPU_SSE); }
-       'cmpps' { RET_INSN_NS(ssepsimm, 0xC2, CPU_SSE); }
-       'cmpss' { RET_INSN_NS(ssessimm, 0xF3C2, CPU_SSE); }
-       'comiss' { RET_INSN_NS(sseps, 0x2F, CPU_SSE); }
-       'cvtpi2ps' { RET_INSN_NS(cvt_xmm_mm_ps, 0x2A, CPU_SSE); }
-       'cvtps2pi' { RET_INSN_NS(cvt_mm_xmm64, 0x2D, CPU_SSE); }
-       'cvtsi2ss' [lLqQ]? { RET_INSN(8, cvt_xmm_rmx, 0xF32A, CPU_SSE); }
-       'cvtss2si' [lLqQ]? { RET_INSN(8, cvt_rx_xmm32, 0xF32D, CPU_SSE); }
-       'cvttps2pi' { RET_INSN_NS(cvt_mm_xmm64, 0x2C, CPU_SSE); }
-       'cvttss2si' [lLqQ]? { RET_INSN(9, cvt_rx_xmm32, 0xF32C, CPU_SSE); }
-       'divps' { RET_INSN_NS(sseps, 0x5E, CPU_SSE); }
-       'divss' { RET_INSN_NS(ssess, 0xF35E, CPU_SSE); }
-       'ldmxcsr' { RET_INSN_NS(ldstmxcsr, 0x02, CPU_SSE); }
-       'maskmovq' { RET_INSN_NS(maskmovq, 0, CPU_P3|CPU_MMX); }
-       'maxps' { RET_INSN_NS(sseps, 0x5F, CPU_SSE); }
-       'maxss' { RET_INSN_NS(ssess, 0xF35F, CPU_SSE); }
-       'minps' { RET_INSN_NS(sseps, 0x5D, CPU_SSE); }
-       'minss' { RET_INSN_NS(ssess, 0xF35D, CPU_SSE); }
-       'movaps' { RET_INSN_NS(movaups, 0x28, CPU_SSE); }
-       'movhlps' { RET_INSN_NS(movhllhps, 0x12, CPU_SSE); }
-       'movhps' { RET_INSN_NS(movhlps, 0x16, CPU_SSE); }
-       'movlhps' { RET_INSN_NS(movhllhps, 0x16, CPU_SSE); }
-       'movlps' { RET_INSN_NS(movhlps, 0x12, CPU_SSE); }
-       'movmskps' [lLqQ]? { RET_INSN(8, movmskps, 0, CPU_SSE); }
-       'movntps' { RET_INSN_NS(movntps, 0, CPU_SSE); }
-       'movntq' { RET_INSN_NS(movntq, 0, CPU_SSE); }
-       'movss' { RET_INSN_NS(movss, 0, CPU_SSE); }
-       'movups' { RET_INSN_NS(movaups, 0x10, CPU_SSE); }
-       'mulps' { RET_INSN_NS(sseps, 0x59, CPU_SSE); }
-       'mulss' { RET_INSN_NS(ssess, 0xF359, CPU_SSE); }
-       'orps' { RET_INSN_NS(sseps, 0x56, CPU_SSE); }
-       'pavgb' { RET_INSN_NS(mmxsse2, 0xE0, CPU_P3|CPU_MMX); }
-       'pavgw' { RET_INSN_NS(mmxsse2, 0xE3, CPU_P3|CPU_MMX); }
-       'pextrw' [lLqQ]? { RET_INSN(6, pextrw, 0, CPU_P3|CPU_MMX); }
-       'pinsrw' [lLqQ]? { RET_INSN(6, pinsrw, 0, CPU_P3|CPU_MMX); }
-       'pmaxsw' { RET_INSN_NS(mmxsse2, 0xEE, CPU_P3|CPU_MMX); }
-       'pmaxub' { RET_INSN_NS(mmxsse2, 0xDE, CPU_P3|CPU_MMX); }
-       'pminsw' { RET_INSN_NS(mmxsse2, 0xEA, CPU_P3|CPU_MMX); }
-       'pminub' { RET_INSN_NS(mmxsse2, 0xDA, CPU_P3|CPU_MMX); }
-       'pmovmskb' [lLqQ]? { RET_INSN(8, pmovmskb, 0, CPU_SSE); }
-       'pmulhuw' { RET_INSN_NS(mmxsse2, 0xE4, CPU_P3|CPU_MMX); }
-       'prefetchnta' { RET_INSN_NS(twobytemem, 0x000F18, CPU_P3); }
-       'prefetcht0' { RET_INSN_NS(twobytemem, 0x010F18, CPU_P3); }
-       'prefetcht1' { RET_INSN_NS(twobytemem, 0x020F18, CPU_P3); }
-       'prefetcht2' { RET_INSN_NS(twobytemem, 0x030F18, CPU_P3); }
-       'psadbw' { RET_INSN_NS(mmxsse2, 0xF6, CPU_P3|CPU_MMX); }
-       'pshufw' { RET_INSN_NS(pshufw, 0, CPU_P3|CPU_MMX); }
-       'rcpps' { RET_INSN_NS(sseps, 0x53, CPU_SSE); }
-       'rcpss' { RET_INSN_NS(ssess, 0xF353, CPU_SSE); }
-       'rsqrtps' { RET_INSN_NS(sseps, 0x52, CPU_SSE); }
-       'rsqrtss' { RET_INSN_NS(ssess, 0xF352, CPU_SSE); }
-       'sfence' { RET_INSN_NS(threebyte, 0x0FAEF8, CPU_P3); }
-       'shufps' { RET_INSN_NS(ssepsimm, 0xC6, CPU_SSE); }
-       'sqrtps' { RET_INSN_NS(sseps, 0x51, CPU_SSE); }
-       'sqrtss' { RET_INSN_NS(ssess, 0xF351, CPU_SSE); }
-       'stmxcsr' { RET_INSN_NS(ldstmxcsr, 0x03, CPU_SSE); }
-       'subps' { RET_INSN_NS(sseps, 0x5C, CPU_SSE); }
-       'subss' { RET_INSN_NS(ssess, 0xF35C, CPU_SSE); }
-       'ucomiss' { RET_INSN_NS(ssess, 0x2E, CPU_SSE); }
-       'unpckhps' { RET_INSN_NS(sseps, 0x15, CPU_SSE); }
-       'unpcklps' { RET_INSN_NS(sseps, 0x14, CPU_SSE); }
-       'xorps' { RET_INSN_NS(sseps, 0x57, CPU_SSE); }
-       /* SSE2 instructions */
-       'addpd' { RET_INSN_NS(ssess, 0x6658, CPU_SSE2); }
-       'addsd' { RET_INSN_NS(ssess, 0xF258, CPU_SSE2); }
-       'andnpd' { RET_INSN_NS(ssess, 0x6655, CPU_SSE2); }
-       'andpd' { RET_INSN_NS(ssess, 0x6654, CPU_SSE2); }
-       'cmpeqpd' { RET_INSN_NS(ssecmpss, 0x0066, CPU_SSE2); }
-       'cmpeqsd' { RET_INSN_NS(ssecmpss, 0x00F2, CPU_SSE2); }
-       'cmplepd' { RET_INSN_NS(ssecmpss, 0x0266, CPU_SSE2); }
-       'cmplesd' { RET_INSN_NS(ssecmpss, 0x02F2, CPU_SSE2); }
-       'cmpltpd' { RET_INSN_NS(ssecmpss, 0x0166, CPU_SSE2); }
-       'cmpltsd' { RET_INSN_NS(ssecmpss, 0x01F2, CPU_SSE2); }
-       'cmpneqpd' { RET_INSN_NS(ssecmpss, 0x0466, CPU_SSE2); }
-       'cmpneqsd' { RET_INSN_NS(ssecmpss, 0x04F2, CPU_SSE2); }
-       'cmpnlepd' { RET_INSN_NS(ssecmpss, 0x0666, CPU_SSE2); }
-       'cmpnlesd' { RET_INSN_NS(ssecmpss, 0x06F2, CPU_SSE2); }
-       'cmpnltpd' { RET_INSN_NS(ssecmpss, 0x0566, CPU_SSE2); }
-       'cmpnltsd' { RET_INSN_NS(ssecmpss, 0x05F2, CPU_SSE2); }
-       'cmpordpd' { RET_INSN_NS(ssecmpss, 0x0766, CPU_SSE2); }
-       'cmpordsd' { RET_INSN_NS(ssecmpss, 0x07F2, CPU_SSE2); }
-       'cmpunordpd' { RET_INSN_NS(ssecmpss, 0x0366, CPU_SSE2); }
-       'cmpunordsd' { RET_INSN_NS(ssecmpss, 0x03F2, CPU_SSE2); }
-       'cmppd' { RET_INSN_NS(ssessimm, 0x66C2, CPU_SSE2); }
-       /* C M P S D is in string instructions above */
-       'comisd' { RET_INSN_NS(ssess, 0x662F, CPU_SSE2); }
-       'cvtpi2pd' { RET_INSN_NS(cvt_xmm_mm_ss, 0x662A, CPU_SSE2); }
-       'cvtsi2sd' [lLqQ]? { RET_INSN(8, cvt_xmm_rmx, 0xF22A, CPU_SSE2); }
-       'divpd' { RET_INSN_NS(ssess, 0x665E, CPU_SSE2); }
-       'divsd' { RET_INSN_NS(ssess, 0xF25E, CPU_SSE2); }
-       'maxpd' { RET_INSN_NS(ssess, 0x665F, CPU_SSE2); }
-       'maxsd' { RET_INSN_NS(ssess, 0xF25F, CPU_SSE2); }
-       'minpd' { RET_INSN_NS(ssess, 0x665D, CPU_SSE2); }
-       'minsd' { RET_INSN_NS(ssess, 0xF25D, CPU_SSE2); }
-       'movapd' { RET_INSN_NS(movaupd, 0x28, CPU_SSE2); }
-       'movhpd' { RET_INSN_NS(movhlpd, 0x16, CPU_SSE2); }
-       'movlpd' { RET_INSN_NS(movhlpd, 0x12, CPU_SSE2); }
-       'movmskpd' [lLqQ]? { RET_INSN(8, movmskpd, 0, CPU_SSE2); }
-       'movntpd' { RET_INSN_NS(movntpddq, 0x2B, CPU_SSE2); }
-       'movntdq' { RET_INSN_NS(movntpddq, 0xE7, CPU_SSE2); }
-       /* M O V S D is in string instructions above */
-       'movupd' { RET_INSN_NS(movaupd, 0x10, CPU_SSE2); }
-       'mulpd' { RET_INSN_NS(ssess, 0x6659, CPU_SSE2); }
-       'mulsd' { RET_INSN_NS(ssess, 0xF259, CPU_SSE2); }
-       'orpd' { RET_INSN_NS(ssess, 0x6656, CPU_SSE2); }
-       'shufpd' { RET_INSN_NS(ssessimm, 0x66C6, CPU_SSE2); }
-       'sqrtpd' { RET_INSN_NS(ssess, 0x6651, CPU_SSE2); }
-       'sqrtsd' { RET_INSN_NS(ssess, 0xF251, CPU_SSE2); }
-       'subpd' { RET_INSN_NS(ssess, 0x665C, CPU_SSE2); }
-       'subsd' { RET_INSN_NS(ssess, 0xF25C, CPU_SSE2); }
-       'ucomisd' { RET_INSN_NS(ssess, 0x662E, CPU_SSE2); }
-       'unpckhpd' { RET_INSN_NS(ssess, 0x6615, CPU_SSE2); }
-       'unpcklpd' { RET_INSN_NS(ssess, 0x6614, CPU_SSE2); }
-       'xorpd' { RET_INSN_NS(ssess, 0x6657, CPU_SSE2); }
-       'cvtdq2pd' { RET_INSN_NS(cvt_xmm_xmm64_ss, 0xF3E6, CPU_SSE2); }
-       'cvtpd2dq' { RET_INSN_NS(ssess, 0xF2E6, CPU_SSE2); }
-       'cvtdq2ps' { RET_INSN_NS(sseps, 0x5B, CPU_SSE2); }
-       'cvtpd2pi' { RET_INSN_NS(cvt_mm_xmm, 0x662D, CPU_SSE2); }
-       'cvtpd2ps' { RET_INSN_NS(ssess, 0x665A, CPU_SSE2); }
-       'cvtps2pd' { RET_INSN_NS(cvt_xmm_xmm64_ps, 0x5A, CPU_SSE2); }
-       'cvtps2dq' { RET_INSN_NS(ssess, 0x665B, CPU_SSE2); }
-       'cvtsd2si' [lLqQ]? { RET_INSN(8, cvt_rx_xmm64, 0xF22D, CPU_SSE2); }
-       'cvtsd2ss' { RET_INSN_NS(cvt_xmm_xmm64_ss, 0xF25A, CPU_SSE2); }
-       /* P4 VMX Instructions */
-       'vmcall' { RET_INSN_NS(threebyte, 0x0F01C1, CPU_P4); }
-       'vmlaunch' { RET_INSN_NS(threebyte, 0x0F01C2, CPU_P4); }
-       'vmresume' { RET_INSN_NS(threebyte, 0x0F01C3, CPU_P4); }
-       'vmxoff' { RET_INSN_NS(threebyte, 0x0F01C4, CPU_P4); }
-       'vmread' [lLqQ]? { RET_INSN(6, vmxmemrd, 0x0F78, CPU_P4); }
-       'vmwrite' [lLqQ]? { RET_INSN(7, vmxmemwr, 0x0F79, CPU_P4); }
-       'vmptrld' { RET_INSN_NS(vmxtwobytemem, 0x06C7, CPU_P4); }
-       'vmptrst' { RET_INSN_NS(vmxtwobytemem, 0x07C7, CPU_P4); }
-       'vmclear' { RET_INSN_NS(vmxthreebytemem, 0x0666C7, CPU_P4); }
-       'vmxon' { RET_INSN_NS(vmxthreebytemem, 0x06F3C7, CPU_P4); }
-       'cvtss2sd' { RET_INSN_NS(cvt_xmm_xmm32, 0xF35A, CPU_SSE2); }
-       'cvttpd2pi' { RET_INSN_NS(cvt_mm_xmm, 0x662C, CPU_SSE2); }
-       'cvttsd2si' [lLqQ]? { RET_INSN(9, cvt_rx_xmm64, 0xF22C, CPU_SSE2); }
-       'cvttpd2dq' { RET_INSN_NS(ssess, 0x66E6, CPU_SSE2); }
-       'cvttps2dq' { RET_INSN_NS(ssess, 0xF35B, CPU_SSE2); }
-       'maskmovdqu' { RET_INSN_NS(maskmovdqu, 0, CPU_SSE2); }
-       'movdqa' { RET_INSN_NS(movdqau, 0x66, CPU_SSE2); }
-       'movdqu' { RET_INSN_NS(movdqau, 0xF3, CPU_SSE2); }
-       'movdq2q' { RET_INSN_NS(movdq2q, 0, CPU_SSE2); }
-       'movq2dq' { RET_INSN_NS(movq2dq, 0, CPU_SSE2); }
-       'pmuludq' { RET_INSN_NS(mmxsse2, 0xF4, CPU_SSE2); }
-       'pshufd' { RET_INSN_NS(ssessimm, 0x6670, CPU_SSE2); }
-       'pshufhw' { RET_INSN_NS(ssessimm, 0xF370, CPU_SSE2); }
-       'pshuflw' { RET_INSN_NS(ssessimm, 0xF270, CPU_SSE2); }
-       'pslldq' { RET_INSN_NS(pslrldq, 0x07, CPU_SSE2); }
-       'psrldq' { RET_INSN_NS(pslrldq, 0x03, CPU_SSE2); }
-       'punpckhqdq' { RET_INSN_NS(ssess, 0x666D, CPU_SSE2); }
-       'punpcklqdq' { RET_INSN_NS(ssess, 0x666C, CPU_SSE2); }
-       /* SSE3 / PNI (Prescott New Instructions) instructions */
-       'addsubpd' { RET_INSN_NS(ssess, 0x66D0, CPU_SSE3); }
-       'addsubps' { RET_INSN_NS(ssess, 0xF2D0, CPU_SSE3); }
-       'fisttp' [sSlLqQ]? { RET_INSN(6, fildstp, 0x010001, CPU_SSE3); }
-       'fisttpll' {
-           suffix_over='q';
-           RET_INSN_GAS(8, fildstp, 0x07, CPU_FPU);
-       }
-       'haddpd' { RET_INSN_NS(ssess, 0x667C, CPU_SSE3); }
-       'haddps' { RET_INSN_NS(ssess, 0xF27C, CPU_SSE3); }
-       'hsubpd' { RET_INSN_NS(ssess, 0x667D, CPU_SSE3); }
-       'hsubps' { RET_INSN_NS(ssess, 0xF27D, CPU_SSE3); }
-       'lddqu' { RET_INSN_NS(lddqu, 0, CPU_SSE3); }
-       'monitor' { RET_INSN_NS(threebyte, 0x0F01C8, CPU_SSE3); }
-       'movddup' { RET_INSN_NS(cvt_xmm_xmm64_ss, 0xF212, CPU_SSE3); }
-       'movshdup' { RET_INSN_NS(ssess, 0xF316, CPU_SSE3); }
-       'movsldup' { RET_INSN_NS(ssess, 0xF312, CPU_SSE3); }
-       'mwait' { RET_INSN_NS(threebyte, 0x0F01C9, CPU_SSE3); }
-       /* AMD 3DNow! instructions */
-       'prefetch' { RET_INSN_NS(twobytemem, 0x000F0D, CPU_3DNow); }
-       'prefetchw' { RET_INSN_NS(twobytemem, 0x010F0D, CPU_3DNow); }
-       'femms' { RET_INSN_NS(twobyte, 0x0F0E, CPU_3DNow); }
-       'pavgusb' { RET_INSN_NS(now3d, 0xBF, CPU_3DNow); }
-       'pf2id' { RET_INSN_NS(now3d, 0x1D, CPU_3DNow); }
-       'pf2iw' { RET_INSN_NS(now3d, 0x1C, CPU_Athlon|CPU_3DNow); }
-       'pfacc' { RET_INSN_NS(now3d, 0xAE, CPU_3DNow); }
-       'pfadd' { RET_INSN_NS(now3d, 0x9E, CPU_3DNow); }
-       'pfcmpeq' { RET_INSN_NS(now3d, 0xB0, CPU_3DNow); }
-       'pfcmpge' { RET_INSN_NS(now3d, 0x90, CPU_3DNow); }
-       'pfcmpgt' { RET_INSN_NS(now3d, 0xA0, CPU_3DNow); }
-       'pfmax' { RET_INSN_NS(now3d, 0xA4, CPU_3DNow); }
-       'pfmin' { RET_INSN_NS(now3d, 0x94, CPU_3DNow); }
-       'pfmul' { RET_INSN_NS(now3d, 0xB4, CPU_3DNow); }
-       'pfnacc' { RET_INSN_NS(now3d, 0x8A, CPU_Athlon|CPU_3DNow); }
-       'pfpnacc' { RET_INSN_NS(now3d, 0x8E, CPU_Athlon|CPU_3DNow); }
-       'pfrcp' { RET_INSN_NS(now3d, 0x96, CPU_3DNow); }
-       'pfrcpit1' { RET_INSN_NS(now3d, 0xA6, CPU_3DNow); }
-       'pfrcpit2' { RET_INSN_NS(now3d, 0xB6, CPU_3DNow); }
-       'pfrsqit1' { RET_INSN_NS(now3d, 0xA7, CPU_3DNow); }
-       'pfrsqrt' { RET_INSN_NS(now3d, 0x97, CPU_3DNow); }
-       'pfsub' { RET_INSN_NS(now3d, 0x9A, CPU_3DNow); }
-       'pfsubr' { RET_INSN_NS(now3d, 0xAA, CPU_3DNow); }
-       'pi2fd' { RET_INSN_NS(now3d, 0x0D, CPU_3DNow); }
-       'pi2fw' { RET_INSN_NS(now3d, 0x0C, CPU_Athlon|CPU_3DNow); }
-       'pmulhrwa' { RET_INSN_NS(now3d, 0xB7, CPU_3DNow); }
-       'pswapd' { RET_INSN_NS(now3d, 0xBB, CPU_Athlon|CPU_3DNow); }
-       /* AMD extensions */
-       'syscall' { RET_INSN_NS(twobyte, 0x0F05, CPU_686|CPU_AMD); }
-       'sysret' [lLqQ]? { RET_INSN(6, twobyte, 0x0F07, CPU_686|CPU_AMD|CPU_Priv); }
-       /* AMD x86-64 extensions */
-       'swapgs' {
-           warn64 = 1;
-           RET_INSN_NS(threebyte, 0x0F01F8, CPU_Hammer|CPU_64);
-       }
-       'rdtscp' { RET_INSN_NS(threebyte, 0x0F01F9, CPU_686|CPU_AMD|CPU_Priv); }
-       /* AMD Pacifica (SVM) instructions */
-       'clgi' { RET_INSN_NS(threebyte, 0x0F01DD, CPU_Hammer|CPU_64|CPU_SVM); }
-       'invlpga' { RET_INSN_NS(invlpga, 0, CPU_Hammer|CPU_64|CPU_SVM); }
-       'skinit' { RET_INSN_NS(skinit, 0, CPU_Hammer|CPU_64|CPU_SVM); }
-       'stgi' { RET_INSN_NS(threebyte, 0x0F01DC, CPU_Hammer|CPU_64|CPU_SVM); }
-       'vmload' { RET_INSN_NS(svm_rax, 0xDA, CPU_Hammer|CPU_64|CPU_SVM); }
-       'vmmcall' { RET_INSN_NS(threebyte, 0x0F01D9, CPU_Hammer|CPU_64|CPU_SVM); }
-       'vmrun' { RET_INSN_NS(svm_rax, 0xD8, CPU_Hammer|CPU_64|CPU_SVM); }
-       'vmsave' { RET_INSN_NS(svm_rax, 0xDB, CPU_Hammer|CPU_64|CPU_SVM); }
-       /* VIA PadLock instructions */
-       'xstore' ('rng')? { RET_INSN_NS(padlock, 0xC000A7, CPU_PadLock); }
-       'xcryptecb' { RET_INSN_NS(padlock, 0xC8F3A7, CPU_PadLock); }
-       'xcryptcbc' { RET_INSN_NS(padlock, 0xD0F3A7, CPU_PadLock); }
-       'xcryptctr' { RET_INSN_NS(padlock, 0xD8F3A7, CPU_PadLock); }
-       'xcryptcfb' { RET_INSN_NS(padlock, 0xE0F3A7, CPU_PadLock); }
-       'xcryptofb' { RET_INSN_NS(padlock, 0xE8F3A7, CPU_PadLock); }
-       'montmul' { RET_INSN_NS(padlock, 0xC0F3A6, CPU_PadLock); }
-       'xsha1' { RET_INSN_NS(padlock, 0xC8F3A6, CPU_PadLock); }
-       'xsha256' { RET_INSN_NS(padlock, 0xD0F3A6, CPU_PadLock); }
-       /* Cyrix MMX instructions */
-       'paddsiw' { RET_INSN_NS(cyrixmmx, 0x51, CPU_Cyrix|CPU_MMX); }
-       'paveb' { RET_INSN_NS(cyrixmmx, 0x50, CPU_Cyrix|CPU_MMX); }
-       'pdistib' { RET_INSN_NS(cyrixmmx, 0x54, CPU_Cyrix|CPU_MMX); }
-       'pmachriw' { RET_INSN_NS(pmachriw, 0, CPU_Cyrix|CPU_MMX); }
-       'pmagw' { RET_INSN_NS(cyrixmmx, 0x52, CPU_Cyrix|CPU_MMX); }
-       'pmulhriw' { RET_INSN_NS(cyrixmmx, 0x5D, CPU_Cyrix|CPU_MMX); }
-       'pmulhrwc' { RET_INSN_NS(cyrixmmx, 0x59, CPU_Cyrix|CPU_MMX); }
-       'pmvgezb' { RET_INSN_NS(cyrixmmx, 0x5C, CPU_Cyrix|CPU_MMX); }
-       'pmvlzb' { RET_INSN_NS(cyrixmmx, 0x5B, CPU_Cyrix|CPU_MMX); }
-       'pmvnzb' { RET_INSN_NS(cyrixmmx, 0x5A, CPU_Cyrix|CPU_MMX); }
-       'pmvzb' { RET_INSN_NS(cyrixmmx, 0x58, CPU_Cyrix|CPU_MMX); }
-       'psubsiw' { RET_INSN_NS(cyrixmmx, 0x55, CPU_Cyrix|CPU_MMX); }
-       /* Cyrix extensions */
-       'rdshr' { RET_INSN_NS(twobyte, 0x0F36, CPU_686|CPU_Cyrix|CPU_SMM); }
-       'rsdc' { RET_INSN_NS(rsdc, 0, CPU_486|CPU_Cyrix|CPU_SMM); }
-       'rsldt' { RET_INSN_NS(cyrixsmm, 0x7B, CPU_486|CPU_Cyrix|CPU_SMM); }
-       'rsts' { RET_INSN_NS(cyrixsmm, 0x7D, CPU_486|CPU_Cyrix|CPU_SMM); }
-       'svdc' { RET_INSN_NS(svdc, 0, CPU_486|CPU_Cyrix|CPU_SMM); }
-       'svldt' { RET_INSN_NS(cyrixsmm, 0x7A, CPU_486|CPU_Cyrix|CPU_SMM); }
-       'svts' { RET_INSN_NS(cyrixsmm, 0x7C, CPU_486|CPU_Cyrix|CPU_SMM); }
-       'smint' { RET_INSN_NS(twobyte, 0x0F38, CPU_686|CPU_Cyrix); }
-       'smintold' { RET_INSN_NS(twobyte, 0x0F7E, CPU_486|CPU_Cyrix|CPU_Obs); }
-       'wrshr' { RET_INSN_NS(twobyte, 0x0F37, CPU_686|CPU_Cyrix|CPU_SMM); }
-       /* Obsolete/undocumented instructions */
-       'fsetpm' { RET_INSN_NS(twobyte, 0xDBE4, CPU_286|CPU_FPU|CPU_Obs); }
-       'ibts' { RET_INSN_NS(ibts, 0, CPU_386|CPU_Undoc|CPU_Obs); }
-       'loadall' { RET_INSN_NS(twobyte, 0x0F07, CPU_386|CPU_Undoc); }
-       'loadall286' { RET_INSN_NS(twobyte, 0x0F05, CPU_286|CPU_Undoc); }
-       'salc' {
-           not64 = 1;
-           RET_INSN_NS(onebyte, 0x00D6, CPU_Undoc);
-       }
-       'smi' { RET_INSN_NS(onebyte, 0x00F1, CPU_386|CPU_Undoc); }
-       'umov' { RET_INSN_NS(umov, 0, CPU_386|CPU_Undoc); }
-       'xbts' { RET_INSN_NS(xbts, 0, CPU_386|CPU_Undoc|CPU_Obs); }
-
-
-       /* catchalls */
-       [\001-\377]+    {
-           return 0;
-       }
-       [\000]  {
-           return 0;
-       }
-    */
-done:
-    if (suffix) {
-       /* If not using the GAS parser, no instructions have suffixes. */
-       if (arch_x86->parser != X86_PARSER_GAS)
-           return 0;
-
-       if (suffix_over == '\0')
-           suffix_over = id[suffix_ofs];
-       /* Match suffixes */
-       switch (suffix_over) {
-           case 'b':
-           case 'B':
-               data[3] |= (MOD_GasSufB >> MOD_GasSuf_SHIFT) << 8;
-               break;
-           case 'w':
-           case 'W':
-               data[3] |= (MOD_GasSufW >> MOD_GasSuf_SHIFT) << 8;
-               break;
-           case 'l':
-           case 'L':
-               data[3] |= (MOD_GasSufL >> MOD_GasSuf_SHIFT) << 8;
-               break;
-           case 'q':
-           case 'Q':
-               data[3] |= (MOD_GasSufQ >> MOD_GasSuf_SHIFT) << 8;
-               break;
-           case 's':
-           case 'S':
-               data[3] |= (MOD_GasSufS >> MOD_GasSuf_SHIFT) << 8;
-               break;
-           default:
-               yasm_internal_error(N_("unrecognized suffix"));
-       }
-    }
-    if (warn64 && arch_x86->mode_bits != 64) {
+    /*@null@*/ const regtmod_parse_data *pdata;
+    size_t i;
+    static char lcaseid[8];
+    unsigned int bits;
+    yasm_arch_regtmod type;
+
+    if (id_len > 7)
+       return YASM_ARCH_NOTREGTMOD;
+    for (i=0; i<id_len; i++)
+       lcaseid[i] = tolower(id[i]);
+    lcaseid[id_len] = '\0';
+
+    pdata = regtmod_find(lcaseid, id_len);
+    if (!pdata)
+       return YASM_ARCH_NOTREGTMOD;
+
+    type = (yasm_arch_regtmod)(pdata->regtmod >> 24);
+    bits = (pdata->regtmod >> 16) & 0xFF;
+
+    if (type == YASM_ARCH_REG && bits != 0 && arch_x86->mode_bits != bits) {
        yasm__warning(YASM_WARN_GENERAL, line,
-                     N_("`%s' is an instruction in 64-bit mode"),
-                     oid);
-       return 0;
+                     N_("`%s' is a register in %u-bit mode"), id, bits);
+       return YASM_ARCH_NOTREGTMOD;
     }
-    if (not64 && arch_x86->mode_bits == 64) {
-       yasm__error(line, N_("`%s' invalid in 64-bit mode"), oid);
-       DEF_INSN_DATA(not64, 0, CPU_Not64);
-       return 1;
+
+    if (type == YASM_ARCH_SEGREG && bits != 0 && arch_x86->mode_bits == bits) {
+       yasm__warning(YASM_WARN_GENERAL, line,
+                     N_("`%s' segment register ignored in %u-bit mode"), id,
+                     bits);
     }
-    return 1;
+
+    *data = pdata->regtmod & 0x0000FFFFUL;
+    return type;
 }
+
diff --git a/modules/arch/x86/x86parse.gap b/modules/arch/x86/x86parse.gap
new file mode 100644 (file)
index 0000000..b483841
--- /dev/null
@@ -0,0 +1,1143 @@
+# GAP (gen_arch_parse) input file for x86 architecture
+# $Id$
+
+# Configure GAP for x86 generation mode
+ARCH   x86
+
+# Supported x86 parsers
+PARSERS        nasm gas
+
+# INSN parameters:
+# - parser (- if any)
+# - base name of instruction
+# - if string, each character is an allowed GAS suffix
+#   if defined name, value is GAS suffix mode set (no character suffix reqd)
+# - instruction group (sans _insn suffix)
+# - modifiers (up to 3 bytes)
+# - CPU flags
+#
+# The string mode of the second parameter is a shortcut for GAS forms, e.g.:
+# INSN -       mov     "bwl"   mov     0       CPU_Any
+# is equivalent to:
+# INSN -       mov     NONE    mov     0       CPU_Any
+# INSN gas     movb    SUF_B   mov     0       CPU_Any
+# INSN gas     movw    SUF_W   mov     0       CPU_Any
+# INSN gas     movl    SUF_L   mov     0       CPU_Any
+
+# Move
+INSN   -       mov     "bwl"   mov     0               CPU_Any
+INSN   gas     movabs  "bwlq"  movabs  0               CPU_Hammer|CPU_64
+
+# Move with sign/zero extend
+INSN   gas     movsbw  SUF_B   movszx  0xBE            CPU_386
+INSN   gas     movsbl  SUF_B   movszx  0xBE            CPU_386
+INSN   gas     movswl  SUF_W   movszx  0xBE            CPU_386
+INSN   gas     movsbq  SUF_B   movszx  0xBE            CPU_Hammer|CPU_64
+INSN   gas     movswq  SUF_W   movszx  0xBE            CPU_Hammer|CPU_64
+INSN   -       movsx   "bw"    movszx  0xBE            CPU_386
+INSN   gas     movslq  SUF_L   movsxd  0               CPU_Hammer|CPU_64
+INSN   nasm    movsxd  NONE    movsxd  0               CPU_Hammer|CPU_64
+INSN   gas     movzbw  SUF_B   movszx  0xB6            CPU_386
+INSN   gas     movzbl  SUF_B   movszx  0xB6            CPU_386
+INSN   gas     movzwl  SUF_W   movszx  0xB6            CPU_386
+INSN   gas     movzbq  SUF_B   movszx  0xB6            CPU_Hammer|CPU_64
+INSN   gas     movzwq  SUF_W   movszx  0xB6            CPU_Hammer|CPU_64
+INSN   -       movzx   NONE    movszx  0xB6            CPU_386
+
+# Push instructions
+INSN   -       push    "wlq"   push    0               CPU_Any
+INSN   -       pusha   NONE    onebyte 0x0060          CPU_186|CPU_Not64
+INSN   nasm    pushad  NONE    onebyte 0x2060          CPU_386|CPU_Not64
+INSN   gas     pushal  NONE    onebyte 0x2060          CPU_386|CPU_Not64
+INSN   -       pushaw  NONE    onebyte 0x1060          CPU_186|CPU_Not64
+
+# Pop instructions
+INSN   -       pop     "wlq"   pop     0               CPU_Any
+INSN   -       popa    NONE    onebyte 0x0061          CPU_186|CPU_Not64
+INSN   nasm    popad   NONE    onebyte 0x2061          CPU_386|CPU_Not64
+INSN   gas     popal   NONE    onebyte 0x2061          CPU_386|CPU_Not64
+INSN   -       popaw   NONE    onebyte 0x1061          CPU_186|CPU_Not64
+
+# Exchange
+INSN   -       xchg    "bwlq"  xchg    0               CPU_Any
+
+# In/out from ports
+INSN   -       in      "bwl"   in      0               CPU_Any
+INSN   -       out     "bwl"   out     0               CPU_Any
+# Load effective address
+INSN   -       lea     "wlq"   lea     0               CPU_Any
+# Load segment registers from memory
+INSN   -       lds     "wl"    ldes    0xC5            CPU_Not64
+INSN   -       les     "wl"    ldes    0xC4            CPU_Not64
+INSN   -       lfs     "wl"    lfgss   0xB4            CPU_386
+INSN   -       lgs     "wl"    lfgss   0xB5            CPU_386
+INSN   -       lss     "wl"    lfgss   0xB2            CPU_386
+# Flags register instructions
+INSN   -       clc     NONE    onebyte 0x00F8          CPU_Any
+INSN   -       cld     NONE    onebyte 0x00FC          CPU_Any
+INSN   -       cli     NONE    onebyte 0x00FA          CPU_Any
+INSN   -       clts    NONE    twobyte 0x0F06          CPU_286|CPU_Priv
+INSN   -       cmc     NONE    onebyte 0x00F5          CPU_Any
+INSN   -       lahf    NONE    onebyte 0x009F          CPU_Any
+INSN   -       sahf    NONE    onebyte 0x009E          CPU_Any
+INSN   -       pushf   NONE    onebyte 0x009C          CPU_Any
+INSN   nasm    pushfd  NONE    onebyte 0x209C          CPU_386
+INSN   gas     pushfl  NONE    onebyte 0x209C          CPU_386
+INSN   -       pushfw  NONE    onebyte 0x109C          CPU_Any
+INSN   -       pushfq  NONE    onebyte 0x409C          CPU_Hammer|CPU_64
+INSN   -       popf    NONE    onebyte 0x40009D        CPU_Any
+INSN   nasm    popfd   NONE    onebyte 0x00209D        CPU_386|CPU_Not64
+INSN   gas     popfl   NONE    onebyte 0x00209D        CPU_386|CPU_Not64
+INSN   -       popfw   NONE    onebyte 0x40109D        CPU_Any
+INSN   -       popfq   NONE    onebyte 0x40409D        CPU_Hammer|CPU_64
+INSN   -       stc     NONE    onebyte 0x00F9          CPU_Any
+INSN   -       std     NONE    onebyte 0x00FD          CPU_Any
+INSN   -       sti     NONE    onebyte 0x00FB          CPU_Any
+# Arithmetic
+INSN   -       add     "bwlq"  arith   0x0000          CPU_Any
+INSN   -       inc     "bwlq"  incdec  0x0040          CPU_Any
+INSN   -       sub     "bwlq"  arith   0x0528          CPU_Any
+INSN   -       dec     "bwlq"  incdec  0x0148          CPU_Any
+INSN   -       sbb     "bwlq"  arith   0x0318          CPU_Any
+INSN   -       cmp     "bwlq"  arith   0x0738          CPU_Any
+INSN   -       test    "bwlq"  test    0               CPU_Any
+INSN   -       and     "bwlq"  arith   0x0420          CPU_Any
+INSN   -       or      "bwlq"  arith   0x0108          CPU_Any
+INSN   -       xor     "bwlq"  arith   0x0630          CPU_Any
+INSN   -       adc     "bwlq"  arith   0x0210          CPU_Any
+INSN   -       neg     "bwlq"  f6      0x03            CPU_Any
+INSN   -       not     "bwlq"  f6      0x02            CPU_Any
+INSN   -       aaa     NONE    onebyte 0x0037          CPU_Not64
+INSN   -       aas     NONE    onebyte 0x003F          CPU_Not64
+INSN   -       daa     NONE    onebyte 0x0027          CPU_Not64
+INSN   -       das     NONE    onebyte 0x002F          CPU_Not64
+INSN   -       aad     NONE    aadm    0x01            CPU_Not64
+INSN   -       aam     NONE    aadm    0x00            CPU_Not64
+# Conversion instructions
+INSN   -       cbw     NONE    onebyte 0x1098          CPU_Any
+INSN   -       cwde    NONE    onebyte 0x2098          CPU_386
+INSN   -       cdqe    NONE    onebyte 0x4098          CPU_Hammer|CPU_64
+INSN   -       cwd     NONE    onebyte 0x1099          CPU_Any
+INSN   -       cdq     NONE    onebyte 0x2099          CPU_386
+INSN   -       cqo     NONE    onebyte 0x4099          CPU_Hammer|CPU_64
+# Conversion instructions - GAS / AT&T naming
+INSN   gas     cbtw    NONE    onebyte 0x1098          CPU_Any
+INSN   gas     cwtl    NONE    onebyte 0x2098          CPU_386
+INSN   gas     cltq    NONE    onebyte 0x4098          CPU_Hammer|CPU_64
+INSN   gas     cwtd    NONE    onebyte 0x1099          CPU_Any
+INSN   gas     cltd    NONE    onebyte 0x2099          CPU_386
+INSN   gas     cqto    NONE    onebyte 0x4099          CPU_Hammer|CPU_64
+# Multiplication and division
+INSN   -       mul     "bwlq"  f6      0x04            CPU_Any
+INSN   -       imul    "bwlq"  imul    0               CPU_Any
+INSN   -       div     "bwlq"  div     0x06            CPU_Any
+INSN   -       idiv    "bwlq"  div     0x07            CPU_Any
+# Shifts
+INSN   -       rol     "bwlq"  shift   0x00            CPU_Any
+INSN   -       ror     "bwlq"  shift   0x01            CPU_Any
+INSN   -       rcl     "bwlq"  shift   0x02            CPU_Any
+INSN   -       rcr     "bwlq"  shift   0x03            CPU_Any
+INSN   -       sal     "bwlq"  shift   0x04            CPU_Any
+INSN   -       shl     "bwlq"  shift   0x04            CPU_Any
+INSN   -       shr     "bwlq"  shift   0x05            CPU_Any
+INSN   -       sar     "bwlq"  shift   0x07            CPU_Any
+INSN   -       shld    "wlq"   shlrd   0xA4            CPU_386
+INSN   -       shrd    "wlq"   shlrd   0xAC            CPU_386
+# Control transfer instructions unconditional)
+INSN   -       call    NONE    call    0               CPU_Any
+INSN   -       jmp     NONE    jmp     0               CPU_Any
+INSN   -       ret     NONE    retnf   0x00C2          CPU_Any
+INSN   gas     retw    NONE    retnf   0x10C2          CPU_Any
+INSN   gas     retl    NONE    retnf   0x00C2          CPU_Not64
+INSN   gas     retq    NONE    retnf   0x00C2          CPU_Hammer|CPU_64
+INSN   nasm    retn    NONE    retnf   0x00C2          CPU_Any
+INSN   nasm    retf    NONE    retnf   0x40CA          CPU_Any
+INSN   gas     lretw   NONE    retnf   0x10CA          CPU_Any
+INSN   gas     lretl   NONE    retnf   0x00CA          CPU_Any
+INSN   gas     lretq   NONE    retnf   0x40CA          CPU_Hammer|CPU_64
+INSN   -       enter   "wlq"   enter   0               CPU_186
+INSN   -       leave   NONE    onebyte 0x4000C9        CPU_186
+INSN   gas     leavew  NONE    onebyte 0x0010C9        CPU_186
+INSN   gas     leavel  NONE    onebyte 0x4000C9        CPU_186
+INSN   gas     leaveq  NONE    onebyte 0x4000C9        CPU_Hammer|CPU_64
+# Conditional jumps
+INSN   -       jo      NONE    jcc     0x00            CPU_Any
+INSN   -       jno     NONE    jcc     0x01            CPU_Any
+INSN   -       jb      NONE    jcc     0x02            CPU_Any
+INSN   -       jc      NONE    jcc     0x02            CPU_Any
+INSN   -       jnae    NONE    jcc     0x02            CPU_Any
+INSN   -       jnb     NONE    jcc     0x03            CPU_Any
+INSN   -       jnc     NONE    jcc     0x03            CPU_Any
+INSN   -       jae     NONE    jcc     0x03            CPU_Any
+INSN   -       je      NONE    jcc     0x04            CPU_Any
+INSN   -       jz      NONE    jcc     0x04            CPU_Any
+INSN   -       jne     NONE    jcc     0x05            CPU_Any
+INSN   -       jnz     NONE    jcc     0x05            CPU_Any
+INSN   -       jbe     NONE    jcc     0x06            CPU_Any
+INSN   -       jna     NONE    jcc     0x06            CPU_Any
+INSN   -       jnbe    NONE    jcc     0x07            CPU_Any
+INSN   -       ja      NONE    jcc     0x07            CPU_Any
+INSN   -       js      NONE    jcc     0x08            CPU_Any
+INSN   -       jns     NONE    jcc     0x09            CPU_Any
+INSN   -       jp      NONE    jcc     0x0A            CPU_Any
+INSN   -       jpe     NONE    jcc     0x0A            CPU_Any
+INSN   -       jnp     NONE    jcc     0x0B            CPU_Any
+INSN   -       jpo     NONE    jcc     0x0B            CPU_Any
+INSN   -       jl      NONE    jcc     0x0C            CPU_Any
+INSN   -       jnge    NONE    jcc     0x0C            CPU_Any
+INSN   -       jnl     NONE    jcc     0x0D            CPU_Any
+INSN   -       jge     NONE    jcc     0x0D            CPU_Any
+INSN   -       jle     NONE    jcc     0x0E            CPU_Any
+INSN   -       jng     NONE    jcc     0x0E            CPU_Any
+INSN   -       jnle    NONE    jcc     0x0F            CPU_Any
+INSN   -       jg      NONE    jcc     0x0F            CPU_Any
+INSN   -       jcxz    NONE    jcxz    0x10            CPU_Any
+INSN   -       jecxz   NONE    jcxz    0x20            CPU_386
+INSN   -       jrcxz   NONE    jcxz    0x40            CPU_Hammer|CPU_64
+# Loop instructions
+INSN   -       loop    NONE    loop    0x02            CPU_Any
+INSN   -       loopz   NONE    loop    0x01            CPU_Any
+INSN   -       loope   NONE    loop    0x01            CPU_Any
+INSN   -       loopnz  NONE    loop    0x00            CPU_Any
+INSN   -       loopne  NONE    loop    0x00            CPU_Any
+# Set byte on flag instructions
+INSN   -       seto    "b"     setcc   0x00            CPU_386
+INSN   -       setno   "b"     setcc   0x01            CPU_386
+INSN   -       setb    "b"     setcc   0x02            CPU_386
+INSN   -       setc    "b"     setcc   0x02            CPU_386
+INSN   -       setnae  "b"     setcc   0x02            CPU_386
+INSN   -       setnb   "b"     setcc   0x03            CPU_386
+INSN   -       setnc   "b"     setcc   0x03            CPU_386
+INSN   -       setae   "b"     setcc   0x03            CPU_386
+INSN   -       sete    "b"     setcc   0x04            CPU_386
+INSN   -       setz    "b"     setcc   0x04            CPU_386
+INSN   -       setne   "b"     setcc   0x05            CPU_386
+INSN   -       setnz   "b"     setcc   0x05            CPU_386
+INSN   -       setbe   "b"     setcc   0x06            CPU_386
+INSN   -       setna   "b"     setcc   0x06            CPU_386
+INSN   -       setnbe  "b"     setcc   0x07            CPU_386
+INSN   -       seta    "b"     setcc   0x07            CPU_386
+INSN   -       sets    "b"     setcc   0x08            CPU_386
+INSN   -       setns   "b"     setcc   0x09            CPU_386
+INSN   -       setp    "b"     setcc   0x0A            CPU_386
+INSN   -       setpe   "b"     setcc   0x0A            CPU_386
+INSN   -       setnp   "b"     setcc   0x0B            CPU_386
+INSN   -       setpo   "b"     setcc   0x0B            CPU_386
+INSN   -       setl    "b"     setcc   0x0C            CPU_386
+INSN   -       setnge  "b"     setcc   0x0C            CPU_386
+INSN   -       setnl   "b"     setcc   0x0D            CPU_386
+INSN   -       setge   "b"     setcc   0x0D            CPU_386
+INSN   -       setle   "b"     setcc   0x0E            CPU_386
+INSN   -       setng   "b"     setcc   0x0E            CPU_386
+INSN   -       setnle  "b"     setcc   0x0F            CPU_386
+INSN   -       setg    "b"     setcc   0x0F            CPU_386
+# String instructions
+INSN   -       cmpsb   NONE    onebyte 0x00A6          CPU_Any
+INSN   -       cmpsw   NONE    onebyte 0x10A7          CPU_Any
+INSN   -       cmpsd   NONE    cmpsd   0               CPU_Any
+INSN   gas     cmpsl   NONE    onebyte 0x20A7          CPU_386
+INSN   -       cmpsq   NONE    onebyte 0x40A7          CPU_Hammer|CPU_64
+INSN   -       insb    NONE    onebyte 0x006C          CPU_Any
+INSN   -       insw    NONE    onebyte 0x106D          CPU_Any
+INSN   nasm    insd    NONE    onebyte 0x206D          CPU_386
+INSN   gas     insl    NONE    onebyte 0x206D          CPU_386
+INSN   -       outsb   NONE    onebyte 0x006E          CPU_Any
+INSN   -       outsw   NONE    onebyte 0x106F          CPU_Any
+INSN   nasm    outsd   NONE    onebyte 0x206F          CPU_386
+INSN   gas     outsl   NONE    onebyte 0x206F          CPU_386
+INSN   -       lodsb   NONE    onebyte 0x00AC          CPU_Any
+INSN   -       lodsw   NONE    onebyte 0x10AD          CPU_Any
+INSN   nasm    lodsd   NONE    onebyte 0x20AD          CPU_386
+INSN   gas     lodsl   NONE    onebyte 0x20AD          CPU_386
+INSN   -       lodsq   NONE    onebyte 0x40AD          CPU_Hammer|CPU_64
+INSN   -       movsb   NONE    onebyte 0x00A4          CPU_Any
+INSN   -       movsw   NONE    onebyte 0x10A5          CPU_Any
+INSN   -       movsd   NONE    movsd   0               CPU_Any
+INSN   gas     movsl   NONE    onebyte 0x20A5          CPU_386
+INSN   -       movsq   NONE    onebyte 0x40A5          CPU_Hammer|CPU_64
+# smov alias for movs in GAS mode
+INSN   gas     smovb   NONE    onebyte 0x00A4          CPU_Any
+INSN   gas     smovw   NONE    onebyte 0x10A5          CPU_Any
+INSN   gas     smovl   NONE    onebyte 0x20A5          CPU_386
+INSN   gas     smovq   NONE    onebyte 0x40A5          CPU_Hammer|CPU_64
+INSN   -       scasb   NONE    onebyte 0x00AE          CPU_Any
+INSN   -       scasw   NONE    onebyte 0x10AF          CPU_Any
+INSN   nasm    scasd   NONE    onebyte 0x20AF          CPU_386
+INSN   gas     scasl   NONE    onebyte 0x20AF          CPU_386
+INSN   -       scasq   NONE    onebyte 0x40AF          CPU_Hammer|CPU_64
+# ssca alias for scas in GAS mode
+INSN   gas     sscab   NONE    onebyte 0x00AE          CPU_Any
+INSN   gas     sscaw   NONE    onebyte 0x10AF          CPU_Any
+INSN   gas     sscal   NONE    onebyte 0x20AF          CPU_386
+INSN   gas     sscaq   NONE    onebyte 0x40AF          CPU_Hammer|CPU_64
+INSN   -       stosb   NONE    onebyte 0x00AA          CPU_Any
+INSN   -       stosw   NONE    onebyte 0x10AB          CPU_Any
+INSN   nasm    stosd   NONE    onebyte 0x20AB          CPU_386
+INSN   gas     stosl   NONE    onebyte 0x20AB          CPU_386
+INSN   -       stosq   NONE    onebyte 0x40AB          CPU_Hammer|CPU_64
+INSN   -       xlatb   NONE    onebyte 0x00D7          CPU_Any
+# Bit manipulation
+INSN   -       bsf     "wlq"   bsfr    0xBC            CPU_386
+INSN   -       bsr     "wlq"   bsfr    0xBD            CPU_386
+INSN   -       bt      "wlq"   bittest 0x04A3          CPU_386
+INSN   -       btc     "wlq"   bittest 0x07BB          CPU_386
+INSN   -       btr     "wlq"   bittest 0x06B3          CPU_386
+INSN   -       bts     "wlq"   bittest 0x05AB          CPU_386
+# Interrupts and operating system instructions
+INSN   -       int     NONE    int     0               CPU_Any
+INSN   -       int3    NONE    onebyte 0x00CC          CPU_Any
+INSN   nasm    int03   NONE    onebyte 0x00CC          CPU_Any
+INSN   -       into    NONE    onebyte 0x00CE          CPU_Not64
+INSN   -       iret    NONE    onebyte 0x00CF          CPU_Any
+INSN   -       iretw   NONE    onebyte 0x10CF          CPU_Any
+INSN   nasm    iretd   NONE    onebyte 0x20CF          CPU_386
+INSN   gas     iretl   NONE    onebyte 0x20CF          CPU_386
+INSN   -       iretq   NONE    onebyte 0x40CF          CPU_Hammer|CPU_64
+INSN   -       rsm     NONE    twobyte 0x0FAA          CPU_586|CPU_SMM
+INSN   -       bound   "wl"    bound   0               CPU_186|CPU_Not64
+INSN   -       hlt     NONE    onebyte 0x00F4          CPU_Priv
+INSN   -       nop     NONE    onebyte 0x0090          CPU_Any
+# Protection control
+INSN   -       arpl    "w"     arpl    0               CPU_286|CPU_Prot|CPU_Not64
+INSN   -       lar     "wlq"   bsfr    0x02            CPU_286|CPU_Prot
+INSN   -       lgdt    "wlq"   twobytemem  0x020F01    CPU_286|CPU_Priv
+INSN   -       lidt    "wlq"   twobytemem  0x030F01    CPU_286|CPU_Priv
+INSN   -       lldt    "w"     prot286 0x0200          CPU_286|CPU_Prot|CPU_Priv
+INSN   -       lmsw    "w"     prot286 0x0601          CPU_286|CPU_Priv
+INSN   -       lsl     "wlq"   bsfr    0x03            CPU_286|CPU_Prot
+INSN   -       ltr     "w"     prot286 0x0300          CPU_286|CPU_Prot|CPU_Priv
+INSN   -       sgdt    "wlq"   twobytemem  0x000F01    CPU_286|CPU_Priv
+INSN   -       sidt    "wlq"   twobytemem  0x010F01    CPU_286|CPU_Priv
+INSN   -       sldt    "wlq"   sldtmsw 0x0000          CPU_286
+INSN   -       smsw    "wlq"   sldtmsw 0x0401          CPU_286
+INSN   -       str     "wlq"   str     0               CPU_286|CPU_Prot
+INSN   -       verr    "w"     prot286 0x0400          CPU_286|CPU_Prot
+INSN   -       verw    "w"     prot286 0x0500          CPU_286|CPU_Prot
+# Floating point instructions
+INSN   -       fld     "ls"    fld     0               CPU_FPU
+INSN   gas     fldt    WEAK    fldstpt 0x05            CPU_FPU
+INSN   -       fild    "lqs"   fildstp 0x050200        CPU_FPU
+INSN   gas     fildll  NONE    fbldstp 0x05            CPU_FPU
+INSN   -       fbld    NONE    fbldstp 0x04            CPU_FPU
+INSN   -       fst     "ls"    fst     0               CPU_FPU
+INSN   -       fist    "ls"    fiarith 0x02DB          CPU_FPU
+INSN   -       fstp    "ls"    fstp    0               CPU_FPU
+INSN   gas     fstpt   WEAK    fldstpt 0x07            CPU_FPU
+INSN   -       fistp   "lqs"   fildstp 0x070203        CPU_FPU
+INSN   gas     fistpll NONE    fbldstp 0x07            CPU_FPU
+INSN   -       fbstp   NONE    fbldstp 0x06            CPU_FPU
+INSN   -       fxch    NONE    fxch    0               CPU_FPU
+INSN   -       fcom    "ls"    fcom    0x02D0          CPU_FPU
+INSN   -       ficom   "ls"    fiarith 0x02DA          CPU_FPU
+INSN   -       fcomp   "ls"    fcom    0x03D8          CPU_FPU
+INSN   -       ficomp  "ls"    fiarith 0x03DA          CPU_FPU
+INSN   -       fcompp  NONE    twobyte 0xDED9          CPU_FPU
+INSN   -       fucom   NONE    fcom2   0xDDE0          CPU_286|CPU_FPU
+INSN   -       fucomp  NONE    fcom2   0xDDE8          CPU_286|CPU_FPU
+INSN   -       fucompp NONE    twobyte 0xDAE9          CPU_286|CPU_FPU
+INSN   -       ftst    NONE    twobyte 0xD9E4          CPU_FPU
+INSN   -       fxam    NONE    twobyte 0xD9E5          CPU_FPU
+INSN   -       fld1    NONE    twobyte 0xD9E8          CPU_FPU
+INSN   -       fldl2t  NONE    twobyte 0xD9E9          CPU_FPU
+INSN   -       fldl2e  NONE    twobyte 0xD9EA          CPU_FPU
+INSN   -       fldpi   NONE    twobyte 0xD9EB          CPU_FPU
+INSN   -       fldlg2  NONE    twobyte 0xD9EC          CPU_FPU
+INSN   -       fldln2  NONE    twobyte 0xD9ED          CPU_FPU
+INSN   -       fldz    NONE    twobyte 0xD9EE          CPU_FPU
+INSN   -       fadd    "ls"    farith  0x00C0C0        CPU_FPU
+INSN   -       faddp   NONE    farithp 0xC0            CPU_FPU
+INSN   -       fiadd   "ls"    fiarith 0x00DA          CPU_FPU
+INSN   -       fsub    "ls"    farith  0x04E0E8        CPU_FPU
+INSN   -       fisub   "ls"    fiarith 0x04DA          CPU_FPU
+INSN   -       fsubp   NONE    farithp 0xE8            CPU_FPU
+INSN   -       fsubr   "ls"    farith  0x05E8E0        CPU_FPU
+INSN   -       fisubr  "ls"    fiarith 0x05DA          CPU_FPU
+INSN   -       fsubrp  NONE    farithp 0xE0            CPU_FPU
+INSN   -       fmul    "ls"    farith  0x01C8C8        CPU_FPU
+INSN   -       fimul   "ls"    fiarith 0x01DA          CPU_FPU
+INSN   -       fmulp   NONE    farithp 0xC8            CPU_FPU
+INSN   -       fdiv    "ls"    farith  0x06F0F8        CPU_FPU
+INSN   -       fidiv   "ls"    fiarith 0x06DA          CPU_FPU
+INSN   -       fdivp   NONE    farithp 0xF8            CPU_FPU
+INSN   -       fdivr   "ls"    farith  0x07F8F0        CPU_FPU
+INSN   -       fidivr  "ls"    fiarith 0x07DA          CPU_FPU
+INSN   -       fdivrp  NONE    farithp 0xF0            CPU_FPU
+INSN   -       f2xm1   NONE    twobyte 0xD9F0          CPU_FPU
+INSN   -       fyl2x   NONE    twobyte 0xD9F1          CPU_FPU
+INSN   -       fptan   NONE    twobyte 0xD9F2          CPU_FPU
+INSN   -       fpatan  NONE    twobyte 0xD9F3          CPU_FPU
+INSN   -       fxtract NONE    twobyte 0xD9F4          CPU_FPU
+INSN   -       fprem1  NONE    twobyte 0xD9F5          CPU_286|CPU_FPU
+INSN   -       fdecstp NONE    twobyte 0xD9F6          CPU_FPU
+INSN   -       fincstp NONE    twobyte 0xD9F7          CPU_FPU
+INSN   -       fprem   NONE    twobyte 0xD9F8          CPU_FPU
+INSN   -       fyl2xp1 NONE    twobyte 0xD9F9          CPU_FPU
+INSN   -       fsqrt   NONE    twobyte 0xD9FA          CPU_FPU
+INSN   -       fsincos NONE    twobyte 0xD9FB          CPU_286|CPU_FPU
+INSN   -       frndint NONE    twobyte 0xD9FC          CPU_FPU
+INSN   -       fscale  NONE    twobyte 0xD9FD          CPU_FPU
+INSN   -       fsin    NONE    twobyte 0xD9FE          CPU_286|CPU_FPU
+INSN   -       fcos    NONE    twobyte 0xD9FF          CPU_286|CPU_FPU
+INSN   -       fchs    NONE    twobyte 0xD9E0          CPU_FPU
+INSN   -       fabs    NONE    twobyte 0xD9E1          CPU_FPU
+INSN   -       fninit  NONE    twobyte 0xDBE3          CPU_FPU
+INSN   -       finit   NONE    threebyte   0x9BDBE3    CPU_FPU
+INSN   -       fldcw   "w"     fldnstcw        0x05    CPU_FPU
+INSN   -       fnstcw  "w"     fldnstcw        0x07    CPU_FPU
+INSN   -       fstcw   "w"     fstcw   0               CPU_FPU
+INSN   -       fnstsw  "w"     fnstsw  0               CPU_FPU
+INSN   -       fstsw   "w"     fstsw   0               CPU_FPU
+INSN   -       fnclex  NONE    twobyte 0xDBE2          CPU_FPU
+INSN   -       fclex   NONE    threebyte   0x9BDBE2    CPU_FPU
+INSN   -       fnstenv "ls"    onebytemem 0x06D9       CPU_FPU
+INSN   -       fstenv  "ls"    twobytemem 0x069BD9     CPU_FPU
+INSN   -       fldenv  "ls"    onebytemem 0x04D9       CPU_FPU
+INSN   -       fnsave  "ls"    onebytemem 0x06DD       CPU_FPU
+INSN   -       fsave   "ls"    twobytemem 0x069BDD     CPU_FPU
+INSN   -       frstor  "ls"    onebytemem 0x04DD       CPU_FPU
+INSN   -       ffree   NONE    ffree   0xDD            CPU_FPU
+INSN   -       ffreep  NONE    ffree   0xDF            CPU_686|CPU_FPU|CPU_Undoc
+INSN   -       fnop    NONE    twobyte 0xD9D0          CPU_FPU
+INSN   -       fwait   NONE    onebyte 0x009B          CPU_FPU
+# Prefixes should the others be here too? should wait be a prefix?
+INSN   -       wait    NONE    onebyte 0x009B          CPU_Any
+# 486 extensions
+INSN   -       bswap   "lq"    bswap   0               CPU_486
+INSN   -       xadd    "bwlq"  cmpxchgxadd 0xC0        CPU_486
+INSN   -       cmpxchg "bwlq"  cmpxchgxadd 0xB0        CPU_486
+INSN   nasm    cmpxchg486 NONE cmpxchgxadd 0xA6        CPU_486|CPU_Undoc
+INSN   -       invd    NONE    twobyte 0x0F08          CPU_486|CPU_Priv
+INSN   -       wbinvd  NONE    twobyte 0x0F09          CPU_486|CPU_Priv
+INSN   -       invlpg  NONE    twobytemem  0x070F01    CPU_486|CPU_Priv
+# 586+ and late 486 extensions
+INSN   -       cpuid   NONE    twobyte 0x0FA2          CPU_486
+# Pentium extensions
+INSN   -       wrmsr   NONE    twobyte 0x0F30          CPU_586|CPU_Priv
+INSN   -       rdtsc   NONE    twobyte 0x0F31          CPU_586
+INSN   -       rdmsr   NONE    twobyte 0x0F32          CPU_586|CPU_Priv
+INSN   -       cmpxchg8b "q"   cmpxchg8b       0       CPU_586
+# Pentium II/Pentium Pro extensions
+INSN   -       sysenter NONE   twobyte 0x0F34          CPU_686|CPU_Not64
+INSN   -       sysexit NONE    twobyte 0x0F35          CPU_686|CPU_Priv|CPU_Not64
+INSN   -       fxsave  "q"     twobytemem  0x000FAE    CPU_686|CPU_FPU
+INSN   -       fxrstor "q"     twobytemem  0x010FAE    CPU_686|CPU_FPU
+INSN   -       rdpmc   NONE    twobyte 0x0F33          CPU_686
+INSN   -       ud2     NONE    twobyte 0x0F0B          CPU_286
+INSN   -       ud1     NONE    twobyte 0x0FB9          CPU_286|CPU_Undoc
+INSN   -       cmovo   "wlq"   cmovcc  0x00            CPU_686
+INSN   -       cmovno  "wlq"   cmovcc  0x01            CPU_686
+INSN   -       cmovb   "wlq"   cmovcc  0x02            CPU_686
+INSN   -       cmovc   "wlq"   cmovcc  0x02            CPU_686
+INSN   -       cmovnae "wlq"   cmovcc  0x02            CPU_686
+INSN   -       cmovnb  "wlq"   cmovcc  0x03            CPU_686
+INSN   -       cmovnc  "wlq"   cmovcc  0x03            CPU_686
+INSN   -       cmovae  "wlq"   cmovcc  0x03            CPU_686
+INSN   -       cmove   "wlq"   cmovcc  0x04            CPU_686
+INSN   -       cmovz   "wlq"   cmovcc  0x04            CPU_686
+INSN   -       cmovne  "wlq"   cmovcc  0x05            CPU_686
+INSN   -       cmovnz  "wlq"   cmovcc  0x05            CPU_686
+INSN   -       cmovbe  "wlq"   cmovcc  0x06            CPU_686
+INSN   -       cmovna  "wlq"   cmovcc  0x06            CPU_686
+INSN   -       cmovnbe "wlq"   cmovcc  0x07            CPU_686
+INSN   -       cmova   "wlq"   cmovcc  0x07            CPU_686
+INSN   -       cmovs   "wlq"   cmovcc  0x08            CPU_686
+INSN   -       cmovns  "wlq"   cmovcc  0x09            CPU_686
+INSN   -       cmovp   "wlq"   cmovcc  0x0A            CPU_686
+INSN   -       cmovpe  "wlq"   cmovcc  0x0A            CPU_686
+INSN   -       cmovnp  "wlq"   cmovcc  0x0B            CPU_686
+INSN   -       cmovpo  "wlq"   cmovcc  0x0B            CPU_686
+INSN   -       cmovl   "wlq"   cmovcc  0x0C            CPU_686
+INSN   -       cmovnge "wlq"   cmovcc  0x0C            CPU_686
+INSN   -       cmovnl  "wlq"   cmovcc  0x0D            CPU_686
+INSN   -       cmovge  "wlq"   cmovcc  0x0D            CPU_686
+INSN   -       cmovle  "wlq"   cmovcc  0x0E            CPU_686
+INSN   -       cmovng  "wlq"   cmovcc  0x0E            CPU_686
+INSN   -       cmovnle "wlq"   cmovcc  0x0F            CPU_686
+INSN   -       cmovg   "wlq"   cmovcc  0x0F            CPU_686
+INSN   -       fcmovb  NONE    fcmovcc 0xDAC0          CPU_686|CPU_FPU
+INSN   -       fcmove  NONE    fcmovcc 0xDAC8          CPU_686|CPU_FPU
+INSN   -       fcmovbe NONE    fcmovcc 0xDAD0          CPU_686|CPU_FPU
+INSN   -       fcmovu  NONE    fcmovcc 0xDAD8          CPU_686|CPU_FPU
+INSN   -       fcmovnb NONE    fcmovcc 0xDBC0          CPU_686|CPU_FPU
+INSN   -       fcmovne NONE    fcmovcc 0xDBC8          CPU_686|CPU_FPU
+INSN   -       fcmovnbe NONE   fcmovcc 0xDBD0          CPU_686|CPU_FPU
+INSN   -       fcmovnu NONE    fcmovcc 0xDBD8          CPU_686|CPU_FPU
+INSN   -       fcomi   NONE    fcom2   0xDBF0          CPU_686|CPU_FPU
+INSN   -       fucomi  NONE    fcom2   0xDBE8          CPU_686|CPU_FPU
+INSN   -       fcomip  NONE    fcom2   0xDFF0          CPU_686|CPU_FPU
+INSN   -       fucomip NONE    fcom2   0xDFE8          CPU_686|CPU_FPU
+# Pentium4 extensions
+INSN   -       movnti  "lq"    movnti  0               CPU_P4
+INSN   -       clflush NONE    clflush 0               CPU_P3
+INSN   -       lfence  NONE    threebyte   0x0FAEE8    CPU_P3
+INSN   -       mfence  NONE    threebyte   0x0FAEF0    CPU_P3
+INSN   -       pause   NONE    onebyte_prefix  0xF390  CPU_P4
+# MMX/SSE2 instructions
+INSN   -       emms    NONE    twobyte 0x0F77          CPU_MMX
+INSN   -       movd    NONE    movd    0               CPU_MMX
+# For GAS movq must use standard mov instruction.
+# For NASM it can use a dedicated instruction.
+INSN   gas     movq    SUF_Q   mov     0               CPU_Any
+INSN   nasm    movq    NONE    movq    0               CPU_MMX
+INSN   -       packssdw NONE   mmxsse2 0x6B            CPU_MMX
+INSN   -       packsswb NONE   mmxsse2 0x63            CPU_MMX
+INSN   -       packuswb NONE   mmxsse2 0x67            CPU_MMX
+INSN   -       paddb   NONE    mmxsse2 0xFC            CPU_MMX
+INSN   -       paddw   NONE    mmxsse2 0xFD            CPU_MMX
+INSN   -       paddd   NONE    mmxsse2 0xFE            CPU_MMX
+INSN   -       paddq   NONE    mmxsse2 0xD4            CPU_MMX
+INSN   -       paddsb  NONE    mmxsse2 0xEC            CPU_MMX
+INSN   -       paddsw  NONE    mmxsse2 0xED            CPU_MMX
+INSN   -       paddusb NONE    mmxsse2 0xDC            CPU_MMX
+INSN   -       paddusw NONE    mmxsse2 0xDD            CPU_MMX
+INSN   -       pand    NONE    mmxsse2 0xDB            CPU_MMX
+INSN   -       pandn   NONE    mmxsse2 0xDF            CPU_MMX
+INSN   -       pcmpeqb NONE    mmxsse2 0x74            CPU_MMX
+INSN   -       pcmpeqw NONE    mmxsse2 0x75            CPU_MMX
+INSN   -       pcmpeqd NONE    mmxsse2 0x76            CPU_MMX
+INSN   -       pcmpgtb NONE    mmxsse2 0x64            CPU_MMX
+INSN   -       pcmpgtw NONE    mmxsse2 0x65            CPU_MMX
+INSN   -       pcmpgtd NONE    mmxsse2 0x66            CPU_MMX
+INSN   -       pmaddwd NONE    mmxsse2 0xF5            CPU_MMX
+INSN   -       pmulhw  NONE    mmxsse2 0xE5            CPU_MMX
+INSN   -       pmullw  NONE    mmxsse2 0xD5            CPU_MMX
+INSN   -       por     NONE    mmxsse2 0xEB            CPU_MMX
+INSN   -       psllw   NONE    pshift  0x0671F1        CPU_MMX
+INSN   -       pslld   NONE    pshift  0x0672F2        CPU_MMX
+INSN   -       psllq   NONE    pshift  0x0673F3        CPU_MMX
+INSN   -       psraw   NONE    pshift  0x0471E1        CPU_MMX
+INSN   -       psrad   NONE    pshift  0x0472E2        CPU_MMX
+INSN   -       psrlw   NONE    pshift  0x0271D1        CPU_MMX
+INSN   -       psrld   NONE    pshift  0x0272D2        CPU_MMX
+INSN   -       psrlq   NONE    pshift  0x0273D3        CPU_MMX
+INSN   -       psubb   NONE    mmxsse2 0xF8            CPU_MMX
+INSN   -       psubw   NONE    mmxsse2 0xF9            CPU_MMX
+INSN   -       psubd   NONE    mmxsse2 0xFA            CPU_MMX
+INSN   -       psubq   NONE    mmxsse2 0xFB            CPU_MMX
+INSN   -       psubsb  NONE    mmxsse2 0xE8            CPU_MMX
+INSN   -       psubsw  NONE    mmxsse2 0xE9            CPU_MMX
+INSN   -       psubusb NONE    mmxsse2 0xD8            CPU_MMX
+INSN   -       psubusw NONE    mmxsse2 0xD9            CPU_MMX
+INSN   -       punpckhbw NONE  mmxsse2 0x68            CPU_MMX
+INSN   -       punpckhwd NONE  mmxsse2 0x69            CPU_MMX
+INSN   -       punpckhdq NONE  mmxsse2 0x6A            CPU_MMX
+INSN   -       punpcklbw NONE  mmxsse2 0x60            CPU_MMX
+INSN   -       punpcklwd NONE  mmxsse2 0x61            CPU_MMX
+INSN   -       punpckldq NONE  mmxsse2 0x62            CPU_MMX
+INSN   -       pxor    NONE    mmxsse2 0xEF            CPU_MMX
+# PIII Katmai new instructions / SIMD instructions
+INSN   -       addps   NONE    sseps   0x58            CPU_SSE
+INSN   -       addss   NONE    ssess   0xF358          CPU_SSE
+INSN   -       andnps  NONE    sseps   0x55            CPU_SSE
+INSN   -       andps   NONE    sseps   0x54            CPU_SSE
+INSN   -       cmpeqps NONE    ssecmpps        0x00    CPU_SSE
+INSN   -       cmpeqss NONE    ssecmpss        0x00F3  CPU_SSE
+INSN   -       cmpleps NONE    ssecmpps        0x02    CPU_SSE
+INSN   -       cmpless NONE    ssecmpss        0x02F3  CPU_SSE
+INSN   -       cmpltps NONE    ssecmpps        0x01    CPU_SSE
+INSN   -       cmpltss NONE    ssecmpss        0x01F3  CPU_SSE
+INSN   -       cmpneqps NONE   ssecmpps        0x04    CPU_SSE
+INSN   -       cmpneqss NONE   ssecmpss        0x04F3  CPU_SSE
+INSN   -       cmpnleps NONE   ssecmpps        0x06    CPU_SSE
+INSN   -       cmpnless NONE   ssecmpss        0x06F3  CPU_SSE
+INSN   -       cmpnltps NONE   ssecmpps        0x05    CPU_SSE
+INSN   -       cmpnltss NONE   ssecmpss        0x05F3  CPU_SSE
+INSN   -       cmpordps NONE   ssecmpps        0x07    CPU_SSE
+INSN   -       cmpordss NONE   ssecmpss        0x07F3  CPU_SSE
+INSN   -       cmpunordps NONE ssecmpps        0x03    CPU_SSE
+INSN   -       cmpunordss NONE ssecmpss        0x03F3  CPU_SSE
+INSN   -       cmpps   NONE    ssepsimm        0xC2    CPU_SSE
+INSN   -       cmpss   NONE    ssessimm        0xF3C2  CPU_SSE
+INSN   -       comiss  NONE    sseps   0x2F            CPU_SSE
+INSN   -       cvtpi2ps NONE   cvt_xmm_mm_ps  0x2A     CPU_SSE
+INSN   -       cvtps2pi NONE   cvt_mm_xmm64   0x2D     CPU_SSE
+INSN   -       cvtsi2ss "lq"   cvt_xmm_rmx    0xF32A   CPU_SSE
+INSN   -       cvtss2si "lq"   cvt_rx_xmm32   0xF32D   CPU_SSE
+INSN   -       cvttps2pi NONE  cvt_mm_xmm64   0x2C     CPU_SSE
+INSN   -       cvttss2si "lq"  cvt_rx_xmm32   0xF32C   CPU_SSE
+INSN   -       divps   NONE    sseps   0x5E            CPU_SSE
+INSN   -       divss   NONE    ssess   0xF35E          CPU_SSE
+INSN   -       ldmxcsr NONE    ldstmxcsr       0x02    CPU_SSE
+INSN   -       maskmovq NONE   maskmovq        0       CPU_P3|CPU_MMX
+INSN   -       maxps   NONE    sseps   0x5F            CPU_SSE
+INSN   -       maxss   NONE    ssess   0xF35F          CPU_SSE
+INSN   -       minps   NONE    sseps   0x5D            CPU_SSE
+INSN   -       minss   NONE    ssess   0xF35D          CPU_SSE
+INSN   -       movaps  NONE    movaups 0x28            CPU_SSE
+INSN   -       movhlps NONE    movhllhps       0x12    CPU_SSE
+INSN   -       movhps  NONE    movhlps 0x16            CPU_SSE
+INSN   -       movlhps NONE    movhllhps       0x16    CPU_SSE
+INSN   -       movlps  NONE    movhlps 0x12            CPU_SSE
+INSN   -       movmskps "lq"   movmskps        0       CPU_SSE
+INSN   -       movntps NONE    movntps 0               CPU_SSE
+INSN   -       movntq  NONE    movntq  0               CPU_SSE
+INSN   -       movss   NONE    movss   0               CPU_SSE
+INSN   -       movups  NONE    movaups 0x10            CPU_SSE
+INSN   -       mulps   NONE    sseps   0x59            CPU_SSE
+INSN   -       mulss   NONE    ssess   0xF359          CPU_SSE
+INSN   -       orps    NONE    sseps   0x56            CPU_SSE
+INSN   -       pavgb   NONE    mmxsse2 0xE0            CPU_P3|CPU_MMX
+INSN   -       pavgw   NONE    mmxsse2 0xE3            CPU_P3|CPU_MMX
+INSN   -       pextrw  "lq"    pextrw  0               CPU_P3|CPU_MMX
+INSN   -       pinsrw  "lq"    pinsrw  0               CPU_P3|CPU_MMX
+INSN   -       pmaxsw  NONE    mmxsse2 0xEE            CPU_P3|CPU_MMX
+INSN   -       pmaxub  NONE    mmxsse2 0xDE            CPU_P3|CPU_MMX
+INSN   -       pminsw  NONE    mmxsse2 0xEA            CPU_P3|CPU_MMX
+INSN   -       pminub  NONE    mmxsse2 0xDA            CPU_P3|CPU_MMX
+INSN   -       pmovmskb "lq"   pmovmskb        0       CPU_SSE
+INSN   -       pmulhuw NONE    mmxsse2 0xE4            CPU_P3|CPU_MMX
+INSN   -       prefetchnta NONE twobytemem 0x000F18    CPU_P3
+INSN   -       prefetcht0 NONE twobytemem  0x010F18    CPU_P3
+INSN   -       prefetcht1 NONE twobytemem  0x020F18    CPU_P3
+INSN   -       prefetcht2 NONE twobytemem  0x030F18    CPU_P3
+INSN   -       psadbw  NONE    mmxsse2 0xF6            CPU_P3|CPU_MMX
+INSN   -       pshufw  NONE    pshufw  0               CPU_P3|CPU_MMX
+INSN   -       rcpps   NONE    sseps   0x53            CPU_SSE
+INSN   -       rcpss   NONE    ssess   0xF353          CPU_SSE
+INSN   -       rsqrtps NONE    sseps   0x52            CPU_SSE
+INSN   -       rsqrtss NONE    ssess   0xF352          CPU_SSE
+INSN   -       sfence  NONE    threebyte   0x0FAEF8    CPU_P3
+INSN   -       shufps  NONE    ssepsimm        0xC6    CPU_SSE
+INSN   -       sqrtps  NONE    sseps   0x51            CPU_SSE
+INSN   -       sqrtss  NONE    ssess   0xF351          CPU_SSE
+INSN   -       stmxcsr NONE    ldstmxcsr       0x03    CPU_SSE
+INSN   -       subps   NONE    sseps   0x5C            CPU_SSE
+INSN   -       subss   NONE    ssess   0xF35C          CPU_SSE
+INSN   -       ucomiss NONE    ssess   0x2E            CPU_SSE
+INSN   -       unpckhps NONE   sseps   0x15            CPU_SSE
+INSN   -       unpcklps NONE   sseps   0x14            CPU_SSE
+INSN   -       xorps   NONE    sseps   0x57            CPU_SSE
+# SSE2 instructions
+INSN   -       addpd   NONE    ssess   0x6658          CPU_SSE2
+INSN   -       addsd   NONE    ssess   0xF258          CPU_SSE2
+INSN   -       andnpd  NONE    ssess   0x6655          CPU_SSE2
+INSN   -       andpd   NONE    ssess   0x6654          CPU_SSE2
+INSN   -       cmpeqpd NONE    ssecmpss        0x0066  CPU_SSE2
+INSN   -       cmpeqsd NONE    ssecmpss        0x00F2  CPU_SSE2
+INSN   -       cmplepd NONE    ssecmpss        0x0266  CPU_SSE2
+INSN   -       cmplesd NONE    ssecmpss        0x02F2  CPU_SSE2
+INSN   -       cmpltpd NONE    ssecmpss        0x0166  CPU_SSE2
+INSN   -       cmpltsd NONE    ssecmpss        0x01F2  CPU_SSE2
+INSN   -       cmpneqpd NONE   ssecmpss        0x0466  CPU_SSE2
+INSN   -       cmpneqsd NONE   ssecmpss        0x04F2  CPU_SSE2
+INSN   -       cmpnlepd NONE   ssecmpss        0x0666  CPU_SSE2
+INSN   -       cmpnlesd NONE   ssecmpss        0x06F2  CPU_SSE2
+INSN   -       cmpnltpd NONE   ssecmpss        0x0566  CPU_SSE2
+INSN   -       cmpnltsd NONE   ssecmpss        0x05F2  CPU_SSE2
+INSN   -       cmpordpd NONE   ssecmpss        0x0766  CPU_SSE2
+INSN   -       cmpordsd NONE   ssecmpss        0x07F2  CPU_SSE2
+INSN   -       cmpunordpd NONE ssecmpss        0x0366  CPU_SSE2
+INSN   -       cmpunordsd NONE ssecmpss        0x03F2  CPU_SSE2
+INSN   -       cmppd   NONE    ssessimm        0x66C2  CPU_SSE2
+# cmpsd is in string instructions above
+INSN   -       comisd  NONE    ssess   0x662F          CPU_SSE2
+INSN   -       cvtpi2pd NONE   cvt_xmm_mm_ss   0x662A  CPU_SSE2
+INSN   -       cvtsi2sd "lq"   cvt_xmm_rmx     0xF22A  CPU_SSE2
+INSN   -       divpd   NONE    ssess   0x665E          CPU_SSE2
+INSN   -       divsd   NONE    ssess   0xF25E          CPU_SSE2
+INSN   -       maxpd   NONE    ssess   0x665F          CPU_SSE2
+INSN   -       maxsd   NONE    ssess   0xF25F          CPU_SSE2
+INSN   -       minpd   NONE    ssess   0x665D          CPU_SSE2
+INSN   -       minsd   NONE    ssess   0xF25D          CPU_SSE2
+INSN   -       movapd  NONE    movaupd 0x28            CPU_SSE2
+INSN   -       movhpd  NONE    movhlpd 0x16            CPU_SSE2
+INSN   -       movlpd  NONE    movhlpd 0x12            CPU_SSE2
+INSN   -       movmskpd "lq"   movmskpd        0       CPU_SSE2
+INSN   -       movntpd NONE    movntpddq       0x2B    CPU_SSE2
+INSN   -       movntdq NONE    movntpddq       0xE7    CPU_SSE2
+# movsd is in string instructions above
+INSN   -       movupd  NONE    movaupd 0x10            CPU_SSE2
+INSN   -       mulpd   NONE    ssess   0x6659          CPU_SSE2
+INSN   -       mulsd   NONE    ssess   0xF259          CPU_SSE2
+INSN   -       orpd    NONE    ssess   0x6656          CPU_SSE2
+INSN   -       shufpd  NONE    ssessimm        0x66C6  CPU_SSE2
+INSN   -       sqrtpd  NONE    ssess   0x6651          CPU_SSE2
+INSN   -       sqrtsd  NONE    ssess   0xF251          CPU_SSE2
+INSN   -       subpd   NONE    ssess   0x665C          CPU_SSE2
+INSN   -       subsd   NONE    ssess   0xF25C          CPU_SSE2
+INSN   -       ucomisd NONE    ssess   0x662E          CPU_SSE2
+INSN   -       unpckhpd NONE   ssess   0x6615          CPU_SSE2
+INSN   -       unpcklpd NONE   ssess   0x6614          CPU_SSE2
+INSN   -       xorpd   NONE    ssess   0x6657          CPU_SSE2
+INSN   -       cvtdq2pd NONE   cvt_xmm_xmm64_ss 0xF3E6 CPU_SSE2
+INSN   -       cvtpd2dq NONE   ssess   0xF2E6          CPU_SSE2
+INSN   -       cvtdq2ps NONE   sseps   0x5B            CPU_SSE2
+INSN   -       cvtpd2pi NONE   cvt_mm_xmm      0x662D  CPU_SSE2
+INSN   -       cvtpd2ps NONE   ssess   0x665A          CPU_SSE2
+INSN   -       cvtps2pd NONE   cvt_xmm_xmm64_ps 0x5A   CPU_SSE2
+INSN   -       cvtps2dq NONE   ssess   0x665B          CPU_SSE2
+INSN   -       cvtsd2si "lq"   cvt_rx_xmm64    0xF22D  CPU_SSE2
+INSN   -       cvtsd2ss NONE   cvt_xmm_xmm64_ss 0xF25A CPU_SSE2
+# P4 VMX Instructions
+INSN   -       vmcall  NONE    threebyte   0x0F01C1    CPU_P4
+INSN   -       vmlaunch NONE   threebyte   0x0F01C2    CPU_P4
+INSN   -       vmresume NONE   threebyte   0x0F01C3    CPU_P4
+INSN   -       vmxoff  NONE    threebyte   0x0F01C4    CPU_P4
+INSN   -       vmread  "lq"    vmxmemrd    0x0F78      CPU_P4
+INSN   -       vmwrite "lq"    vmxmemwr    0x0F79      CPU_P4
+INSN   -       vmptrld NONE    vmxtwobytemem   0x06C7  CPU_P4
+INSN   -       vmptrst NONE    vmxtwobytemem   0x07C7  CPU_P4
+INSN   -       vmclear NONE    vmxthreebytemem 0x0666C7 CPU_P4
+INSN   -       vmxon   NONE    vmxthreebytemem 0x06F3C7 CPU_P4
+INSN   -       cvtss2sd NONE   cvt_xmm_xmm32   0xF35A  CPU_SSE2
+INSN   -       cvttpd2pi NONE  cvt_mm_xmm      0x662C  CPU_SSE2
+INSN   -       cvttsd2si "lq"  cvt_rx_xmm64    0xF22C  CPU_SSE2
+INSN   -       cvttpd2dq NONE  ssess   0x66E6          CPU_SSE2
+INSN   -       cvttps2dq NONE  ssess   0xF35B          CPU_SSE2
+INSN   -       maskmovdqu NONE maskmovdqu      0       CPU_SSE2
+INSN   -       movdqa  NONE    movdqau 0x66            CPU_SSE2
+INSN   -       movdqu  NONE    movdqau 0xF3            CPU_SSE2
+INSN   -       movdq2q NONE    movdq2q 0               CPU_SSE2
+INSN   -       movq2dq NONE    movq2dq 0               CPU_SSE2
+INSN   -       pmuludq NONE    mmxsse2 0xF4            CPU_SSE2
+INSN   -       pshufd  NONE    ssessimm        0x6670  CPU_SSE2
+INSN   -       pshufhw NONE    ssessimm        0xF370  CPU_SSE2
+INSN   -       pshuflw NONE    ssessimm        0xF270  CPU_SSE2
+INSN   -       pslldq  NONE    pslrldq 0x07            CPU_SSE2
+INSN   -       psrldq  NONE    pslrldq 0x03            CPU_SSE2
+INSN   -       punpckhqdq NONE ssess   0x666D          CPU_SSE2
+INSN   -       punpcklqdq NONE ssess   0x666C          CPU_SSE2
+# SSE3 / PNI Prescott New Instructions instructions
+INSN   -       addsubpd NONE   ssess   0x66D0          CPU_SSE3
+INSN   -       addsubps NONE   ssess   0xF2D0          CPU_SSE3
+INSN   -       fisttp  "lqs"   fildstp 0x010001        CPU_SSE3
+INSN   gas     fisttpll SUF_Q  fildstp 0x07            CPU_FPU
+INSN   -       haddpd  NONE    ssess   0x667C          CPU_SSE3
+INSN   -       haddps  NONE    ssess   0xF27C          CPU_SSE3
+INSN   -       hsubpd  NONE    ssess   0x667D          CPU_SSE3
+INSN   -       hsubps  NONE    ssess   0xF27D          CPU_SSE3
+INSN   -       lddqu   NONE    lddqu   0               CPU_SSE3
+INSN   -       monitor NONE    threebyte   0x0F01C8    CPU_SSE3
+INSN   -       movddup NONE    cvt_xmm_xmm64_ss 0xF212 CPU_SSE3
+INSN   -       movshdup NONE   ssess   0xF316          CPU_SSE3
+INSN   -       movsldup NONE   ssess   0xF312          CPU_SSE3
+INSN   -       mwait   NONE    threebyte   0x0F01C9    CPU_SSE3
+# AMD 3DNow! instructions
+INSN   -       prefetch NONE   twobytemem  0x000F0D    CPU_3DNow
+INSN   -       prefetchw NONE  twobytemem  0x010F0D    CPU_3DNow
+INSN   -       femms   NONE    twobyte 0x0F0E          CPU_3DNow
+INSN   -       pavgusb NONE    now3d   0xBF            CPU_3DNow
+INSN   -       pf2id   NONE    now3d   0x1D            CPU_3DNow
+INSN   -       pf2iw   NONE    now3d   0x1C            CPU_Athlon|CPU_3DNow
+INSN   -       pfacc   NONE    now3d   0xAE            CPU_3DNow
+INSN   -       pfadd   NONE    now3d   0x9E            CPU_3DNow
+INSN   -       pfcmpeq NONE    now3d   0xB0            CPU_3DNow
+INSN   -       pfcmpge NONE    now3d   0x90            CPU_3DNow
+INSN   -       pfcmpgt NONE    now3d   0xA0            CPU_3DNow
+INSN   -       pfmax   NONE    now3d   0xA4            CPU_3DNow
+INSN   -       pfmin   NONE    now3d   0x94            CPU_3DNow
+INSN   -       pfmul   NONE    now3d   0xB4            CPU_3DNow
+INSN   -       pfnacc  NONE    now3d   0x8A            CPU_Athlon|CPU_3DNow
+INSN   -       pfpnacc NONE    now3d   0x8E            CPU_Athlon|CPU_3DNow
+INSN   -       pfrcp   NONE    now3d   0x96            CPU_3DNow
+INSN   -       pfrcpit1 NONE   now3d   0xA6            CPU_3DNow
+INSN   -       pfrcpit2 NONE   now3d   0xB6            CPU_3DNow
+INSN   -       pfrsqit1 NONE   now3d   0xA7            CPU_3DNow
+INSN   -       pfrsqrt NONE    now3d   0x97            CPU_3DNow
+INSN   -       pfsub   NONE    now3d   0x9A            CPU_3DNow
+INSN   -       pfsubr  NONE    now3d   0xAA            CPU_3DNow
+INSN   -       pi2fd   NONE    now3d   0x0D            CPU_3DNow
+INSN   -       pi2fw   NONE    now3d   0x0C            CPU_Athlon|CPU_3DNow
+INSN   -       pmulhrwa NONE   now3d   0xB7            CPU_3DNow
+INSN   -       pswapd  NONE    now3d   0xBB            CPU_Athlon|CPU_3DNow
+# AMD extensions
+INSN   -       syscall NONE    twobyte 0x0F05          CPU_686|CPU_AMD
+INSN   -       sysret  "lq"    twobyte 0x0F07          CPU_686|CPU_AMD|CPU_Priv
+# AMD x86-64 extensions
+INSN   -       swapgs  NONE    threebyte   0x0F01F8    CPU_Hammer|CPU_64
+INSN   -       rdtscp  NONE    threebyte   0x0F01F9    CPU_686|CPU_AMD|CPU_Priv
+# AMD Pacifica SVM instructions
+INSN   -       clgi    NONE    threebyte   0x0F01DD    CPU_Hammer|CPU_64|CPU_SVM
+INSN   -       invlpga NONE    invlpga     0           CPU_Hammer|CPU_64|CPU_SVM
+INSN   -       skinit  NONE    skinit      0           CPU_Hammer|CPU_64|CPU_SVM
+INSN   -       stgi    NONE    threebyte   0x0F01DC    CPU_Hammer|CPU_64|CPU_SVM
+INSN   -       vmload  NONE    svm_rax     0xDA        CPU_Hammer|CPU_64|CPU_SVM
+INSN   -       vmmcall NONE    threebyte   0x0F01D9    CPU_Hammer|CPU_64|CPU_SVM
+INSN   -       vmrun   NONE    svm_rax     0xD8        CPU_Hammer|CPU_64|CPU_SVM
+INSN   -       vmsave  NONE    svm_rax     0xDB        CPU_Hammer|CPU_64|CPU_SVM
+# VIA PadLock instructions
+INSN   -       xstore  NONE    padlock 0xC000A7   CPU_PadLock
+INSN   -       xstorerng NONE  padlock 0xC000A7   CPU_PadLock
+INSN   -       xcryptecb NONE  padlock 0xC8F3A7   CPU_PadLock
+INSN   -       xcryptcbc NONE  padlock 0xD0F3A7   CPU_PadLock
+INSN   -       xcryptctr NONE  padlock 0xD8F3A7   CPU_PadLock
+INSN   -       xcryptcfb NONE  padlock 0xE0F3A7   CPU_PadLock
+INSN   -       xcryptofb NONE  padlock 0xE8F3A7   CPU_PadLock
+INSN   -       montmul NONE    padlock 0xC0F3A6   CPU_PadLock
+INSN   -       xsha1   NONE    padlock 0xC8F3A6   CPU_PadLock
+INSN   -       xsha256 NONE    padlock 0xD0F3A6   CPU_PadLock
+# Cyrix MMX instructions
+INSN   -       paddsiw NONE    cyrixmmx    0x51        CPU_Cyrix|CPU_MMX
+INSN   -       paveb   NONE    cyrixmmx    0x50        CPU_Cyrix|CPU_MMX
+INSN   -       pdistib NONE    cyrixmmx    0x54        CPU_Cyrix|CPU_MMX
+INSN   -       pmachriw NONE   pmachriw    0           CPU_Cyrix|CPU_MMX
+INSN   -       pmagw   NONE    cyrixmmx    0x52        CPU_Cyrix|CPU_MMX
+INSN   -       pmulhriw NONE   cyrixmmx    0x5D        CPU_Cyrix|CPU_MMX
+INSN   -       pmulhrwc NONE   cyrixmmx    0x59        CPU_Cyrix|CPU_MMX
+INSN   -       pmvgezb NONE    cyrixmmx    0x5C        CPU_Cyrix|CPU_MMX
+INSN   -       pmvlzb  NONE    cyrixmmx    0x5B        CPU_Cyrix|CPU_MMX
+INSN   -       pmvnzb  NONE    cyrixmmx    0x5A        CPU_Cyrix|CPU_MMX
+INSN   -       pmvzb   NONE    cyrixmmx    0x58        CPU_Cyrix|CPU_MMX
+INSN   -       psubsiw NONE    cyrixmmx    0x55        CPU_Cyrix|CPU_MMX
+# Cyrix extensions
+INSN   -       rdshr   NONE    twobyte     0x0F36      CPU_686|CPU_Cyrix|CPU_SMM
+INSN   -       rsdc    NONE    rsdc        0           CPU_486|CPU_Cyrix|CPU_SMM
+INSN   -       rsldt   NONE    cyrixsmm    0x7B        CPU_486|CPU_Cyrix|CPU_SMM
+INSN   -       rsts    NONE    cyrixsmm    0x7D        CPU_486|CPU_Cyrix|CPU_SMM
+INSN   -       svdc    NONE    svdc        0           CPU_486|CPU_Cyrix|CPU_SMM
+INSN   -       svldt   NONE    cyrixsmm    0x7A        CPU_486|CPU_Cyrix|CPU_SMM
+INSN   -       svts    NONE    cyrixsmm    0x7C        CPU_486|CPU_Cyrix|CPU_SMM
+INSN   -       smint   NONE    twobyte     0x0F38      CPU_686|CPU_Cyrix
+INSN   -       smintold NONE   twobyte     0x0F7E      CPU_486|CPU_Cyrix|CPU_Obs
+INSN   -       wrshr   NONE    twobyte     0x0F37      CPU_686|CPU_Cyrix|CPU_SMM
+# Obsolete/undocumented instructions
+INSN   -       fsetpm  NONE    twobyte 0xDBE4          CPU_286|CPU_FPU|CPU_Obs
+INSN   -       ibts    NONE    ibts    0               CPU_386|CPU_Undoc|CPU_Obs
+INSN   -       loadall NONE    twobyte 0x0F07          CPU_386|CPU_Undoc
+INSN   -       loadall286 NONE twobyte 0x0F05          CPU_286|CPU_Undoc
+INSN   -       salc    NONE    onebyte 0x00D6          CPU_Undoc|CPU_Not64
+INSN   -       smi     NONE    onebyte 0x00F1          CPU_386|CPU_Undoc
+INSN   -       umov    NONE    umov    0               CPU_386|CPU_Undoc
+INSN   -       xbts    NONE    xbts    0               CPU_386|CPU_Undoc|CPU_Obs
+
+
+# DEF_CPU parameters:
+# - CPU name
+# - CPU flags to set
+# DEF_CPU_ALIAS parameters:
+# - CPU alias name
+# - CPU base name
+# DEF_CPU_FEATURE parameters:
+# - CPU feature name
+# - CPU flag to set feature name alone or unset ("no" + feature name)
+
+# The standard CPU names /set/ cpu_enabled.
+CPU            8086    CPU_Priv
+CPU            186     CPU_186|CPU_Priv
+CPU_ALIAS      80186           186
+CPU_ALIAS      i186            186
+CPU            286     CPU_186|CPU_286|CPU_Priv
+CPU_ALIAS      80286           286
+CPU_ALIAS      i286            286
+CPU            386     CPU_186|CPU_286|CPU_386|CPU_SMM|CPU_Prot|CPU_Priv
+CPU_ALIAS      80386           386
+CPU_ALIAS      i386            386
+CPU            486     CPU_186|CPU_286|CPU_386|CPU_486|CPU_FPU|CPU_SMM|\
+                       CPU_Prot|CPU_Priv
+CPU_ALIAS      80486           486
+CPU_ALIAS      i486            486
+CPU            586     CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_FPU|\
+                       CPU_SMM|CPU_Prot|CPU_Priv
+CPU_ALIAS      i586            586
+CPU_ALIAS      pentium         586
+CPU_ALIAS      p5              586
+CPU            686     CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|\
+                       CPU_FPU|CPU_SMM|CPU_Prot|CPU_Priv
+CPU_ALIAS      i686            686
+CPU_ALIAS      p6              686
+CPU_ALIAS      ppro            686
+CPU_ALIAS      pentiumpro      686
+CPU            p2      CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|\
+                       CPU_FPU|CPU_MMX|CPU_SMM|CPU_Prot|CPU_Priv
+CPU_ALIAS      pentium2        p2
+CPU_ALIAS      pentium-2       p2
+CPU_ALIAS      pentiumii       p2
+CPU_ALIAS      pentium-ii      p2
+CPU            p3      CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|\
+                       CPU_P3|CPU_FPU|CPU_MMX|CPU_SSE|CPU_SMM|CPU_Prot|\
+                       CPU_Priv
+CPU_ALIAS      pentium3        p3
+CPU_ALIAS      pentium-3       p3
+CPU_ALIAS      pentiumiii      p3
+CPU_ALIAS      pentium-iii     p3
+CPU_ALIAS      katmai  p3
+CPU            p4      CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|\
+                       CPU_P3|CPU_P4|CPU_FPU|CPU_MMX|CPU_SSE|CPU_SSE2|\
+                       CPU_SMM|CPU_Prot|CPU_Priv
+CPU_ALIAS      pentium4        p4
+CPU_ALIAS      pentium-4       p4
+CPU_ALIAS      pentiumiv       p4
+CPU_ALIAS      pentium-iv      p4
+CPU_ALIAS      williamette     p4
+CPU            ia64    CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|\
+                       CPU_P3|CPU_P4|CPU_IA64|CPU_FPU|CPU_MMX|CPU_SSE|\
+                       CPU_SSE2|CPU_SMM|CPU_Prot|CPU_Priv
+CPU_ALIAS      ia-64           ia64
+CPU_ALIAS      itanium         ia64
+CPU            k6      CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|\
+                       CPU_K6|CPU_FPU|CPU_MMX|CPU_3DNow|CPU_SMM|CPU_Prot|\
+                       CPU_Priv
+CPU            k7      CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|\
+                       CPU_K6|CPU_Athlon|CPU_FPU|CPU_MMX|CPU_SSE|CPU_3DNow|\
+                       CPU_SMM|CPU_Prot|CPU_Priv
+CPU_ALIAS      athlon          k7
+CPU            hammer  CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|\
+                       CPU_K6|CPU_Athlon|CPU_Hammer|CPU_FPU|CPU_MMX|\
+                       CPU_SSE|CPU_SSE2|CPU_3DNow|CPU_SMM|CPU_Prot|\
+                       CPU_Priv
+CPU_ALIAS      sledgehammer    hammer
+CPU_ALIAS      opteron         hammer
+CPU_ALIAS      athlon64        hammer
+CPU_ALIAS      athlon-64       hammer
+CPU            prescott CPU_186|CPU_286|CPU_386|CPU_486|CPU_586|CPU_686|\
+                       CPU_K6|CPU_Athlon|CPU_Hammer|CPU_FPU|CPU_MMX|\
+                       CPU_SSE|CPU_SSE2|CPU_SSE3|CPU_3DNow|CPU_SMM|\
+                       CPU_Prot|CPU_Priv
+
+# Features have "no" versions to disable them, and only set/reset the
+# specific feature being changed.  All other bits are left alone.
+
+CPU_FEATURE    fpu     CPU_FPU
+CPU_FEATURE    mmx     CPU_MMX
+CPU_FEATURE    sse     CPU_SSE
+CPU_FEATURE    sse2    CPU_SSE2
+CPU_FEATURE    sse3    CPU_SSE3
+#CPU_FEATURE   pni     CPU_PNI
+CPU_FEATURE    3dnow   CPU_3DNow
+CPU_FEATURE    cyrix   CPU_Cyrix
+CPU_FEATURE    amd     CPU_AMD
+CPU_FEATURE    smm     CPU_SMM
+CPU_FEATURE    prot    CPU_Prot
+CPU_FEATURE    undoc   CPU_Undoc
+CPU_FEATURE    obs     CPU_Obs
+CPU_FEATURE    priv    CPU_Priv
+CPU_FEATURE    svm     CPU_SVM
+CPU_FEATURE    padlock CPU_PadLock
+
+
+# TARGETMOD parameters:
+# - target modifier name
+# - modifier to return
+
+TARGETMOD      near    X86_NEAR
+TARGETMOD      short   X86_SHORT
+TARGETMOD      far     X86_FAR
+TARGETMOD      to      X86_TO
+
+
+# PREFIX parameters:
+# - parser
+# - prefix name
+# - prefix type
+# - prefix value
+
+# operand size overrides
+PREFIX nasm    o16     X86_OPERSIZE    16
+PREFIX gas     data16  X86_OPERSIZE    16
+PREFIX gas     word    X86_OPERSIZE    16
+PREFIX nasm    o32     X86_OPERSIZE    32
+PREFIX gas     data32  X86_OPERSIZE    32
+PREFIX gas     dword   X86_OPERSIZE    32
+PREFIX nasm    o64     X86_OPERSIZE    64
+PREFIX gas     data64  X86_OPERSIZE    64
+PREFIX gas     qword   X86_OPERSIZE    64
+
+# address size overrides
+PREFIX nasm    a16     X86_ADDRSIZE    16
+PREFIX gas     addr16  X86_ADDRSIZE    16
+PREFIX gas     aword   X86_ADDRSIZE    16
+PREFIX nasm    a32     X86_ADDRSIZE    32
+PREFIX gas     addr32  X86_ADDRSIZE    32
+PREFIX gas     adword  X86_ADDRSIZE    32
+PREFIX nasm    a64     X86_ADDRSIZE    64
+PREFIX gas     addr64  X86_ADDRSIZE    64
+PREFIX gas     aqword  X86_ADDRSIZE    64
+
+# instruction prefixes
+PREFIX -       lock    X86_LOCKREP     0xF0
+PREFIX -       repne   X86_LOCKREP     0xF2
+PREFIX -       repnz   X86_LOCKREP     0xF2
+PREFIX -       rep     X86_LOCKREP     0xF3
+PREFIX -       repe    X86_LOCKREP     0xF3
+PREFIX -       repz    X86_LOCKREP     0xF3
+
+# other prefixes, limited to GAS-only at the moment
+# Hint taken/not taken for jumps
+PREFIX gas     ht      X86_SEGREG      0x3E
+PREFIX gas     hnt     X86_SEGREG      0x2E
+
+# REX byte explicit prefixes
+PREFIX gas     rex     X86_REX         0x40
+PREFIX gas     rexz    X86_REX         0x41
+PREFIX gas     rexy    X86_REX         0x42
+PREFIX gas     rexyz   X86_REX         0x43
+PREFIX gas     rexx    X86_REX         0x44
+PREFIX gas     rexxz   X86_REX         0x45
+PREFIX gas     rexxy   X86_REX         0x46
+PREFIX gas     rexxyz  X86_REX         0x47
+PREFIX gas     rex64   X86_REX         0x48
+PREFIX gas     rex64z  X86_REX         0x49
+PREFIX gas     rex64y  X86_REX         0x4A
+PREFIX gas     rex64yz X86_REX         0x4B
+PREFIX gas     rex64x  X86_REX         0x4C
+PREFIX gas     rex64xz X86_REX         0x4D
+PREFIX gas     rex64xy X86_REX         0x4E
+PREFIX gas     rex64xyz X86_REX        0x4F
+
+
+# REG parameters:
+# - register name
+# - register type
+# - register index
+# - required BITS setting (0 for any)
+#
+# REGGROUP parameters:
+# - register group name
+# - register group type
+#
+# SEGREG parameters:
+# - segment register name
+# - prefix encoding
+# - register encoding
+# - BITS in which the segment is ignored
+
+# control, debug, and test registers
+REG    cr0     X86_CRREG       0       0
+REG    cr2     X86_CRREG       2       0
+REG    cr3     X86_CRREG       3       0
+REG    cr4     X86_CRREG       4       0
+REG    cr8     X86_CRREG       8       64
+
+REG    dr0     X86_DRREG       0       0
+REG    dr1     X86_DRREG       1       0
+REG    dr2     X86_DRREG       2       0
+REG    dr3     X86_DRREG       3       0
+REG    dr4     X86_DRREG       4       0
+REG    dr5     X86_DRREG       5       0
+REG    dr6     X86_DRREG       6       0
+REG    dr7     X86_DRREG       7       0
+
+REG    tr0     X86_TRREG       0       0
+REG    tr1     X86_TRREG       1       0
+REG    tr2     X86_TRREG       2       0
+REG    tr3     X86_TRREG       3       0
+REG    tr4     X86_TRREG       4       0
+REG    tr5     X86_TRREG       5       0
+REG    tr6     X86_TRREG       6       0
+REG    tr7     X86_TRREG       7       0
+
+# floating point, MMX, and SSE/SSE2 registers
+REG    st0     X86_FPUREG      0       0
+REG    st1     X86_FPUREG      1       0
+REG    st2     X86_FPUREG      2       0
+REG    st3     X86_FPUREG      3       0
+REG    st4     X86_FPUREG      4       0
+REG    st5     X86_FPUREG      5       0
+REG    st6     X86_FPUREG      6       0
+REG    st7     X86_FPUREG      7       0
+
+REG    mm0     X86_MMXREG      0       0
+REG    mm1     X86_MMXREG      1       0
+REG    mm2     X86_MMXREG      2       0
+REG    mm3     X86_MMXREG      3       0
+REG    mm4     X86_MMXREG      4       0
+REG    mm5     X86_MMXREG      5       0
+REG    mm6     X86_MMXREG      6       0
+REG    mm7     X86_MMXREG      7       0
+
+REG    xmm0    X86_XMMREG      0       0
+REG    xmm1    X86_XMMREG      1       0
+REG    xmm2    X86_XMMREG      2       0
+REG    xmm3    X86_XMMREG      3       0
+REG    xmm4    X86_XMMREG      4       0
+REG    xmm5    X86_XMMREG      5       0
+REG    xmm6    X86_XMMREG      6       0
+REG    xmm7    X86_XMMREG      7       0
+REG    xmm8    X86_XMMREG      8       64
+REG    xmm9    X86_XMMREG      9       64
+REG    xmm10   X86_XMMREG      10      64
+REG    xmm11   X86_XMMREG      11      64
+REG    xmm12   X86_XMMREG      12      64
+REG    xmm13   X86_XMMREG      13      64
+REG    xmm14   X86_XMMREG      14      64
+REG    xmm15   X86_XMMREG      15      64
+
+# integer registers
+REG    rax     X86_REG64       0       64
+REG    rcx     X86_REG64       1       64
+REG    rdx     X86_REG64       2       64
+REG    rbx     X86_REG64       3       64
+REG    rsp     X86_REG64       4       64
+REG    rbp     X86_REG64       5       64
+REG    rsi     X86_REG64       6       64
+REG    rdi     X86_REG64       7       64
+REG    r8      X86_REG64       8       64
+REG    r9      X86_REG64       9       64
+REG    r10     X86_REG64       10      64
+REG    r11     X86_REG64       11      64
+REG    r12     X86_REG64       12      64
+REG    r13     X86_REG64       13      64
+REG    r14     X86_REG64       14      64
+REG    r15     X86_REG64       15      64
+
+REG    eax     X86_REG32       0       0
+REG    ecx     X86_REG32       1       0
+REG    edx     X86_REG32       2       0
+REG    ebx     X86_REG32       3       0
+REG    esp     X86_REG32       4       0
+REG    ebp     X86_REG32       5       0
+REG    esi     X86_REG32       6       0
+REG    edi     X86_REG32       7       0
+REG    r8d     X86_REG32       8       64
+REG    r9d     X86_REG32       9       64
+REG    r10d    X86_REG32       10      64
+REG    r11d    X86_REG32       11      64
+REG    r12d    X86_REG32       12      64
+REG    r13d    X86_REG32       13      64
+REG    r14d    X86_REG32       14      64
+REG    r15d    X86_REG32       15      64
+
+REG    ax      X86_REG16       0       0
+REG    cx      X86_REG16       1       0
+REG    dx      X86_REG16       2       0
+REG    bx      X86_REG16       3       0
+REG    sp      X86_REG16       4       0
+REG    bp      X86_REG16       5       0
+REG    si      X86_REG16       6       0
+REG    di      X86_REG16       7       0
+REG    r8w     X86_REG16       8       64
+REG    r9w     X86_REG16       9       64
+REG    r10w    X86_REG16       10      64
+REG    r11w    X86_REG16       11      64
+REG    r12w    X86_REG16       12      64
+REG    r13w    X86_REG16       13      64
+REG    r14w    X86_REG16       14      64
+REG    r15w    X86_REG16       15      64
+
+REG    al      X86_REG8        0       0
+REG    cl      X86_REG8        1       0
+REG    dl      X86_REG8        2       0
+REG    bl      X86_REG8        3       0
+REG    ah      X86_REG8        4       0
+REG    ch      X86_REG8        5       0
+REG    dh      X86_REG8        6       0
+REG    bh      X86_REG8        7       0
+REG    r8b     X86_REG8        8       64
+REG    r9b     X86_REG8        9       64
+REG    r10b    X86_REG8        10      64
+REG    r11b    X86_REG8        11      64
+REG    r12b    X86_REG8        12      64
+REG    r13b    X86_REG8        13      64
+REG    r14b    X86_REG8        14      64
+REG    r15b    X86_REG8        15      64
+
+REG    spl     X86_REG8X       4       64
+REG    bpl     X86_REG8X       5       64
+REG    sil     X86_REG8X       6       64
+REG    dil     X86_REG8X       7       64
+
+REG    rip     X86_RIP         0       64
+
+# floating point, MMX, and SSE/SSE2 registers
+REGGROUP       st      X86_FPUREG
+REGGROUP       mm      X86_MMXREG
+REGGROUP       xmm     X86_XMMREG
+
+# segment registers
+SEGREG es      0x26    0x00    64
+SEGREG cs      0x2e    0x01    0
+SEGREG ss      0x36    0x02    64
+SEGREG ds      0x3e    0x03    64
+SEGREG fs      0x64    0x04    0
+SEGREG gs      0x65    0x05    0
+
index f6e97bca6a870a57db74ee2721e591d6d80ec402..247c8980904c0a863e8f065c38fdb03549d26a2a 100644 (file)
@@ -410,22 +410,20 @@ scan:
        [%][a-zA-Z0-9]+ {
            savech = s->tok[TOKLEN];
            s->tok[TOKLEN] = '\0';
-           if (yasm_arch_parse_check_reg(parser_gas->arch, lvalp->arch_data,
-                                         s->tok+1, cur_line)) {
-               s->tok[TOKLEN] = savech;
-               RETURN(REG);
-           }
-           if (yasm_arch_parse_check_reggroup(parser_gas->arch,
-                                              lvalp->arch_data, s->tok+1,
-                                              cur_line)) {
-               s->tok[TOKLEN] = savech;
-               RETURN(REGGROUP);
-           }
-           if (yasm_arch_parse_check_segreg(parser_gas->arch,
-                                            lvalp->arch_data, s->tok+1,
-                                            cur_line)) {
-               s->tok[TOKLEN] = savech;
-               RETURN(SEGREG);
+           switch (yasm_arch_parse_check_regtmod
+                   (parser_gas->arch, lvalp->arch_data, s->tok+1, TOKLEN-1,
+                    cur_line)) {
+               case YASM_ARCH_REG:
+                   s->tok[TOKLEN] = savech;
+                   RETURN(REG);
+               case YASM_ARCH_REGGROUP:
+                   s->tok[TOKLEN] = savech;
+                   RETURN(REGGROUP);
+               case YASM_ARCH_SEGREG:
+                   s->tok[TOKLEN] = savech;
+                   RETURN(SEGREG);
+               default:
+                   break;
            }
            yasm__error(cur_line, N_("Unrecognized register name `%s'"),
                        s->tok);
@@ -457,20 +455,19 @@ scan:
            if (parser_gas->state != INSTDIR) {
                savech = s->tok[TOKLEN];
                s->tok[TOKLEN] = '\0';
-               if (yasm_arch_parse_check_insn(parser_gas->arch,
-                                              lvalp->arch_data, s->tok,
-                                              cur_line)) {
-                   s->tok[TOKLEN] = savech;
-                   parser_gas->state = INSTDIR;
-                   RETURN(INSN);
-               }
-               if (yasm_arch_parse_check_prefix(parser_gas->arch,
-                                                lvalp->arch_data, s->tok,
-                                                cur_line)) {
-                   s->tok[TOKLEN] = savech;
-                   RETURN(PREFIX);
+               switch (yasm_arch_parse_check_insnprefix
+                       (parser_gas->arch, lvalp->arch_data, s->tok, TOKLEN,
+                        cur_line)) {
+                   case YASM_ARCH_INSN:
+                       s->tok[TOKLEN] = savech;
+                       parser_gas->state = INSTDIR;
+                       RETURN(INSN);
+                   case YASM_ARCH_PREFIX:
+                       s->tok[TOKLEN] = savech;
+                       RETURN(PREFIX);
+                   default:
+                       s->tok[TOKLEN] = savech;
                }
-               s->tok[TOKLEN] = savech;
            }
            /* Just an identifier, return as such. */
            lvalp->str_val = yasm__xstrndup(s->tok, TOKLEN);
index a56bc6587c6049ff74b884a39ed5afadefdfb439..cd9183220c7377346485f07fffa1e9d0ebabf0d5 100644 (file)
@@ -638,7 +638,8 @@ nasm_parser_directive(yasm_parser_nasm *parser_nasm, const char *name,
     } else if (yasm__strcasecmp(name, "cpu") == 0) {
        yasm_vps_foreach(vp, valparams) {
            if (vp->val)
-               yasm_arch_parse_cpu(parser_nasm->arch, vp->val, line);
+               yasm_arch_parse_cpu(parser_nasm->arch, vp->val,
+                                   strlen(vp->val), line);
            else if (vp->param) {
                const yasm_intnum *intcpu;
                intcpu = yasm_expr_get_intnum(&vp->param, NULL);
@@ -647,7 +648,8 @@ nasm_parser_directive(yasm_parser_nasm *parser_nasm, const char *name,
                else {
                    char strcpu[16];
                    sprintf(strcpu, "%lu", yasm_intnum_get_uint(intcpu));
-                   yasm_arch_parse_cpu(parser_nasm->arch, strcpu, line);
+                   yasm_arch_parse_cpu(parser_nasm->arch, strcpu,
+                                       strlen(strcpu), line);
                }
            }
        }
index d0062d2b84e428ff1d2a499bb09f8e9f26d5ba68..c10d001612640782c25fe9e530218fd0177e83f9 100644 (file)
@@ -69,7 +69,8 @@ typedef struct yasm_parser_nasm {
        DIRECTIVE,
        DIRECTIVE2,
        LINECHG,
-       LINECHG2
+       LINECHG2,
+       INSTRUCTION
     } state;
 } yasm_parser_nasm;
 
index 41a1377a9a0fb9b0b180a3df3b7d26e471f6772a..6d9f00647667a0223fcdcae9b07fd90dc36a010d 100644 (file)
@@ -382,35 +382,35 @@ scan:
        [a-zA-Z_?][a-zA-Z0-9_$#@~.?]* {
            savech = s->tok[TOKLEN];
            s->tok[TOKLEN] = '\0';
-           if (yasm_arch_parse_check_reg(parser_nasm->arch, lvalp->arch_data,
-                                         s->tok, cur_line)) {
-               s->tok[TOKLEN] = savech;
-               RETURN(REG);
+           if (parser_nasm->state != INSTRUCTION)
+               switch (yasm_arch_parse_check_insnprefix
+                       (parser_nasm->arch, lvalp->arch_data, s->tok, TOKLEN,
+                        cur_line)) {
+                   case YASM_ARCH_INSN:
+                       parser_nasm->state = INSTRUCTION;
+                       s->tok[TOKLEN] = savech;
+                       RETURN(INSN);
+                   case YASM_ARCH_PREFIX:
+                       s->tok[TOKLEN] = savech;
+                       RETURN(PREFIX);
+                   default:
+                       break;
+               }
+           switch (yasm_arch_parse_check_regtmod
+                   (parser_nasm->arch, lvalp->arch_data, s->tok, TOKLEN,
+                    cur_line)) {
+               case YASM_ARCH_REG:
+                   s->tok[TOKLEN] = savech;
+                   RETURN(REG);
+               case YASM_ARCH_SEGREG:
+                   s->tok[TOKLEN] = savech;
+                   RETURN(SEGREG);
+               case YASM_ARCH_TARGETMOD:
+                   s->tok[TOKLEN] = savech;
+                   RETURN(TARGETMOD);
+               default:
+                   s->tok[TOKLEN] = savech;
            }
-           if (yasm_arch_parse_check_insn(parser_nasm->arch, lvalp->arch_data,
-                                          s->tok, cur_line)) {
-               s->tok[TOKLEN] = savech;
-               RETURN(INSN);
-           }
-           if (yasm_arch_parse_check_segreg(parser_nasm->arch,
-                                            lvalp->arch_data, s->tok,
-                                            cur_line)) {
-               s->tok[TOKLEN] = savech;
-               RETURN(SEGREG);
-           }
-           if (yasm_arch_parse_check_prefix(parser_nasm->arch,
-                                            lvalp->arch_data, s->tok,
-                                            cur_line)) {
-               s->tok[TOKLEN] = savech;
-               RETURN(PREFIX);
-           }
-           if (yasm_arch_parse_check_targetmod(parser_nasm->arch,
-                                               lvalp->arch_data, s->tok,
-                                               cur_line)) {
-               s->tok[TOKLEN] = savech;
-               RETURN(TARGETMOD);
-           }
-           s->tok[TOKLEN] = savech;
            /* Just an identifier, return as such. */
            lvalp->str_val = yasm__xstrndup(s->tok, TOKLEN);
            RETURN(ID);
index 89ebb8f813223b3d0d3766a66fa3135b4a8955e6..52ab74b38c711f6299e50232b055debcee8abac8 100644 (file)
@@ -6,6 +6,8 @@
 
 frontends/yasm/yasm-options.c
 frontends/yasm/yasm.c
+gas-bison.c
+gas-token.c
 lc3bid.c
 libyasm/bitvect.c
 libyasm/bytecode.c
@@ -14,7 +16,6 @@ libyasm/expr.c
 libyasm/floatnum.c
 libyasm/hamt.c
 libyasm/intnum.c
-libyasm/linemgr.c
 libyasm/section.c
 libyasm/symrec.c
 libyasm/xmalloc.c
@@ -23,13 +24,23 @@ modules/arch/lc3b/lc3bbc.c
 modules/arch/x86/x86arch.c
 modules/arch/x86/x86bc.c
 modules/arch/x86/x86expr.c
+modules/arch/x86/x86id.c
+modules/dbgfmts/dwarf2/dwarf2-dbgfmt.c
+modules/dbgfmts/dwarf2/dwarf2-info.c
+modules/dbgfmts/dwarf2/dwarf2-line.c
+modules/dbgfmts/stabs/stabs-dbgfmt.c
+modules/listfmts/nasm/nasm-listfmt.c
 modules/objfmts/bin/bin-objfmt.c
 modules/objfmts/coff/coff-objfmt.c
 modules/objfmts/dbg/dbg-objfmt.c
+modules/objfmts/elf/elf-objfmt.c
+modules/objfmts/elf/elf-x86-amd64.c
+modules/objfmts/elf/elf-x86-x86.c
+modules/objfmts/elf/elf.c
+modules/objfmts/xdf/xdf-objfmt.c
 modules/optimizers/basic/basic-optimizer.c
+modules/parsers/gas/gas-parser.c
 modules/preprocs/nasm/nasm-pp.c
-modules/preprocs/nasm/nasm-preproc.c
 modules/preprocs/raw/raw-preproc.c
 nasm-bison.c
 nasm-token.c
-x86id.c
index 4e6ec10e9a2e2b91516cf167f9d67be0ed789801..264b8e1643022388f0b79e3c0cb42317d1372d1f 100644 (file)
@@ -1,5 +1,7 @@
 # $Id$
 
 EXTRA_DIST += tools/re2c/Makefile.inc
+EXTRA_DIST += tools/gap/Makefile.inc
 
 include tools/re2c/Makefile.inc
+include tools/gap/Makefile.inc
diff --git a/tools/gap/Makefile.inc b/tools/gap/Makefile.inc
new file mode 100644 (file)
index 0000000..a6bf9a3
--- /dev/null
@@ -0,0 +1,38 @@
+# $Id$
+
+# These utility programs have to be built for BUILD host in cross-build.
+# This makes things rather non-standard automake
+
+noinst_PROGRAMS += gap
+
+gap_SOURCES =
+EXTRA_DIST += tools/gap/gap.c
+EXTRA_DIST += tools/gap/perfect.c
+EXTRA_DIST += tools/gap/perfect.h
+EXTRA_DIST += tools/gap/standard.h
+gap_LDADD  = gap.$(OBJEXT)
+gap_LDADD += gap-perfect.$(OBJEXT)
+gap_LDADD += gap-phash.$(OBJEXT)
+gap_LDADD += gap-hamt.$(OBJEXT)
+gap_LDADD += gap-xmalloc.$(OBJEXT)
+gap_LDADD += gap-xstrdup.$(OBJEXT)
+gap_LINK = $(CCLD_FOR_BUILD) -o $@
+
+gap.$(OBJEXT): tools/gap/gap.c
+       $(CC_FOR_BUILD) $(DEFAULT_INCLUDES) $(INCLUDES) -g -c -o $@ `test -f tools/gap/gap.c || echo '$(srcdir)/'`tools/gap/gap.c
+
+gap-perfect.$(OBJEXT): tools/gap/perfect.c
+       $(CC_FOR_BUILD) $(DEFAULT_INCLUDES) $(INCLUDES) -g -c -o $@ `test -f tools/gap/perfect.c || echo '$(srcdir)/'`tools/gap/perfect.c
+
+gap-phash.$(OBJEXT): libyasm/phash.c
+       $(CC_FOR_BUILD) $(DEFAULT_INCLUDES) $(INCLUDES) -g -c -o $@ `test -f libyasm/phash.c || echo '$(srcdir)/'`libyasm/phash.c
+
+gap-hamt.$(OBJEXT): libyasm/hamt.c
+       $(CC_FOR_BUILD) $(DEFAULT_INCLUDES) $(INCLUDES) -g -c -o $@ `test -f libyasm/hamt.c || echo '$(srcdir)/'`libyasm/hamt.c
+
+gap-xmalloc.$(OBJEXT): libyasm/xmalloc.c
+       $(CC_FOR_BUILD) $(DEFAULT_INCLUDES) $(INCLUDES) -g -c -o $@ `test -f libyasm/xmalloc.c || echo '$(srcdir)/'`libyasm/xmalloc.c
+
+gap-xstrdup.$(OBJEXT): libyasm/xstrdup.c
+       $(CC_FOR_BUILD) $(DEFAULT_INCLUDES) $(INCLUDES) -g -c -o $@ `test -f libyasm/xstrdup.c || echo '$(srcdir)/'`libyasm/xstrdup.c
+
diff --git a/tools/gap/gap.c b/tools/gap/gap.c
new file mode 100644 (file)
index 0000000..981649c
--- /dev/null
@@ -0,0 +1,877 @@
+/* $Id$
+ *
+ * Generate Arch Parser (GAP): generates ARCHparse.c from ARCHparse.gap.
+ *
+ *  Copyright (C) 2006  Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHOR AND OTHER 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 AUTHOR OR OTHER 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.
+ */
+#include <stdio.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <string.h>
+#include "tools/gap/perfect.h"
+#include "libyasm/compat-queue.h"
+#include "libyasm/coretype.h"
+#include "libyasm/hamt.h"
+
+typedef STAILQ_HEAD(slist, sval) slist;
+typedef struct sval {
+    STAILQ_ENTRY(sval) link;
+    char *str;
+} sval;
+
+typedef struct dir {
+    char *name;
+    const char *func;
+    slist args;
+} dir;
+
+typedef STAILQ_HEAD(dir_byp_list, dir_byp) dir_byp_list;
+typedef struct dir_byp {
+    STAILQ_ENTRY(dir_byp) link;
+    /*@null@*/ char *parser;
+    HAMT *dirs;
+} dir_byp;
+
+typedef enum {
+    ARCH = 0,
+    PARSERS,
+    INSN,
+    CPU,
+    CPU_ALIAS,
+    CPU_FEATURE,
+    TARGETMOD,
+    PREFIX,
+    REG,
+    REGGROUP,
+    SEGREG,
+    NUM_DIRS
+} dir_type;
+
+typedef struct {
+    void (*parse_insn) (void); /* arch-specific parse_insn */
+    int multi_parser[NUM_DIRS]; /* whether it has an initial parser field */
+} arch_handler;
+
+static void x86_parse_insn(void);
+static const arch_handler arch_x86 = {
+    x86_parse_insn,
+    {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0}
+};
+
+static struct {
+    const char *name;
+    const arch_handler *arch;
+} archs[] = {
+    {"x86", &arch_x86},
+};
+
+static char line[1024];
+static unsigned int cur_line = 0, next_line = 1;
+static int errors = 0;
+static const arch_handler *arch = NULL;
+
+/* Lists of directives, keyed by parser name */
+static dir_byp_list insnprefix_byp;
+static dir_byp_list cpu_byp;
+static dir_byp_list regtmod_byp;
+
+static void
+report_error(const char *fmt, ...)
+{
+    va_list ap;
+
+    fprintf(stderr, "%u: ", cur_line);
+    va_start(ap, fmt);
+    vfprintf(stderr, fmt, ap);
+    va_end(ap);
+    fputc('\n', stderr);
+    errors++;
+}
+
+void
+yasm__fatal(const char *message, ...)
+{
+    abort();
+}
+
+static void
+hamt_error(const char *file, unsigned int line, const char *message)
+{
+    abort();
+}
+
+void
+dup_slist(slist *out, slist *in)
+{
+    sval *sv;
+
+    STAILQ_INIT(out);
+    STAILQ_FOREACH(sv, in, link) {
+       sval *nsv = yasm_xmalloc(sizeof(sval));
+       nsv->str = yasm__xstrdup(sv->str);
+       STAILQ_INSERT_TAIL(out, nsv, link);
+    }
+}
+
+dir *
+dup_dir(dir *in)
+{
+    dir *out = yasm_xmalloc(sizeof(dir));
+    out->name = yasm__xstrdup(in->name);
+    out->func = in->func;
+    dup_slist(&out->args, &in->args);
+    return out;
+}
+
+static HAMT *
+get_dirs(dir_byp_list *byp, /*@null@*/ const char *parser)
+{
+    HAMT *found = NULL;
+    dir_byp *db;
+
+    if (STAILQ_EMPTY(byp)) {
+       report_error("PARSERS not yet specified");
+       return NULL;
+    }
+
+    STAILQ_FOREACH(db, byp, link) {
+       if ((!parser && !db->parser) ||
+           (parser && db->parser && strcmp(parser, db->parser) == 0)) {
+           found = db->dirs;
+           break;
+       }
+    }
+
+    return found;
+}
+
+/* Add a keyword/data to a slist of slist keyed by parser name.
+ * Returns nonzero on error.
+ */
+static int
+add_dir(dir_byp_list *byp, /*@null@*/ const char *parser, dir *d)
+{
+    HAMT *found = get_dirs(byp, parser);
+    dir *new;
+    int replace;
+
+    if (found) {
+       replace = 0;
+       new = HAMT_insert(found, d->name, d, &replace, free);
+       if (new != d) {
+           report_error("duplicate `%s'", d->name);
+           return 1;
+       }
+       return 0;
+    } else if (!parser) {
+       /* Add separately to all */
+       dir_byp *db;
+       int first = 1;
+       STAILQ_FOREACH(db, byp, link) {
+           if (!first)
+               d = dup_dir(d);
+           first = 0;
+           replace = 0;
+           new = HAMT_insert(db->dirs, d->name, d, &replace, free);
+           if (new != d) {
+               report_error("duplicate `%s'", d->name);
+               return 1;
+           }
+       }
+       return 0;
+    } else {
+       report_error("parser not found");
+       return 1;
+    }
+}
+
+static char *
+check_parser(dir_type type)
+{
+    char *parser = NULL;
+
+    if (arch->multi_parser[type]) {
+       parser = strtok(NULL, " \t\n");
+       if (strcmp(parser, "-") == 0)
+           parser = NULL;
+    }
+
+    return parser;
+}
+
+static void
+parse_args(slist *args)
+{
+    char *tok;
+    sval *sv;
+
+    STAILQ_INIT(args);
+
+    tok = strtok(NULL, " \t\n");
+    if (!tok) {
+       report_error("no args");
+       return;
+    }
+
+    while (tok) {
+       sv = yasm_xmalloc(sizeof(sval));
+       sv->str = yasm__xstrdup(tok);
+       STAILQ_INSERT_TAIL(args, sv, link);
+       tok = strtok(NULL, " \t\n");
+    }
+}
+
+static dir *
+parse_generic(dir_type type, const char *func, dir_byp_list *byp)
+{
+    char *parser = check_parser(type);
+    char *name = strtok(NULL, " \t\n");
+    dir *d = yasm_xmalloc(sizeof(dir));
+
+    d->name = yasm__xstrdup(name);
+    d->func = func;
+    parse_args(&d->args);
+
+    add_dir(byp, parser, d);
+    return d;
+}
+
+static void
+parse_arch(void)
+{
+    int i;
+    int found = 0;
+    char *tok = strtok(NULL, " \t\n");
+
+    if (!tok) {
+       report_error("ARCH requires an operand");
+       return;
+    }
+    for (i=0; i<sizeof(archs)/sizeof(archs[0]); i++) {
+       if (strcmp(archs[i].name, tok) == 0) {
+           found = 1;
+           break;
+       }
+    }
+    if (!found) {
+       report_error("unrecognized ARCH");
+       return;
+    }
+
+    arch = archs[i].arch;
+}
+
+static void
+parse_parsers(void)
+{
+    dir_byp *db;
+    char *tok;
+
+    if (!arch) {
+       report_error("ARCH not specified before PARSERS");
+       return;
+    }
+
+    tok = strtok(NULL, " \t\n");
+    if (!tok) {
+       report_error("no PARSERS parameter");
+       return;
+    }
+
+    while (tok) {
+       /* Insert into each slist of slist if broken out by parser */
+       if (arch->multi_parser[INSN] || arch->multi_parser[PREFIX]) {
+           db = yasm_xmalloc(sizeof(dir_byp));
+           db->parser = yasm__xstrdup(tok);
+           db->dirs = HAMT_create(hamt_error);
+
+           STAILQ_INSERT_TAIL(&insnprefix_byp, db, link);
+       }
+       if (arch->multi_parser[CPU] || arch->multi_parser[CPU_ALIAS] ||
+           arch->multi_parser[CPU_FEATURE]) {
+           db = yasm_xmalloc(sizeof(dir_byp));
+           db->parser = yasm__xstrdup(tok);
+           db->dirs = HAMT_create(hamt_error);
+
+           STAILQ_INSERT_TAIL(&cpu_byp, db, link);
+       }
+       if (arch->multi_parser[TARGETMOD] || arch->multi_parser[REG] ||
+           arch->multi_parser[REGGROUP] || arch->multi_parser[SEGREG]) {
+           db = yasm_xmalloc(sizeof(dir_byp));
+           db->parser = yasm__xstrdup(tok);
+           db->dirs = HAMT_create(hamt_error);
+
+           STAILQ_INSERT_TAIL(&regtmod_byp, db, link);
+       }
+       tok = strtok(NULL, " \t\n");
+    }
+
+    /* Add NULL (global) versions if not already created */
+    if (STAILQ_EMPTY(&insnprefix_byp)) {
+       db = yasm_xmalloc(sizeof(dir_byp));
+       db->parser = NULL;
+       db->dirs = HAMT_create(hamt_error);
+
+       STAILQ_INSERT_TAIL(&insnprefix_byp, db, link);
+    }
+    if (STAILQ_EMPTY(&cpu_byp)) {
+       db = yasm_xmalloc(sizeof(dir_byp));
+       db->parser = NULL;
+       db->dirs = HAMT_create(hamt_error);
+
+       STAILQ_INSERT_TAIL(&cpu_byp, db, link);
+    }
+    if (STAILQ_EMPTY(&regtmod_byp)) {
+       db = yasm_xmalloc(sizeof(dir_byp));
+       db->parser = NULL;
+       db->dirs = HAMT_create(hamt_error);
+
+       STAILQ_INSERT_TAIL(&regtmod_byp, db, link);
+    }
+}
+
+static void
+x86_parse_insn(void)
+{
+    char *parser = check_parser(INSN);
+    char *bname = strtok(NULL, " \t\n");
+    char *suffix = strtok(NULL, " \t\n");
+    dir *d;
+    slist args;
+    sval *sv;
+
+    if (!suffix) {
+       report_error("INSN requires suffix");
+       return;
+    }
+
+    /* save the remainder of args */
+    parse_args(&args);
+
+    if (suffix[0] != '"') {
+       /* Just one instruction to generate */
+       sv = yasm_xmalloc(sizeof(sval));
+       sv->str = yasm__xstrdup(suffix);
+       STAILQ_INSERT_HEAD(&args, sv, link);
+
+       d = yasm_xmalloc(sizeof(dir));
+       d->name = yasm__xstrdup(bname);
+       d->func = "INSN";
+       d->args = args;
+       add_dir(&insnprefix_byp, parser, d);
+    } else {
+       /* Need to generate with suffixes for gas */
+       char *p;
+       char sufstr[6];
+       size_t bnamelen = strlen(bname);
+
+       strcpy(sufstr, "SUF_X");
+
+       for (p = &suffix[1]; *p != '"'; p++) {
+           sufstr[4] = toupper(*p);
+
+           d = yasm_xmalloc(sizeof(dir));
+
+           d->name = yasm_xmalloc(bnamelen+2);
+           strcpy(d->name, bname);
+           d->name[bnamelen] = tolower(*p);
+           d->name[bnamelen+1] = '\0';
+
+           d->func = "INSN";
+           dup_slist(&d->args, &args);
+
+           sv = yasm_xmalloc(sizeof(sval));
+           sv->str = yasm__xstrdup(sufstr);
+           STAILQ_INSERT_HEAD(&d->args, sv, link);
+
+           add_dir(&insnprefix_byp, "gas", d);
+       }
+
+       /* And finally the version sans suffix */
+       sv = yasm_xmalloc(sizeof(sval));
+       sv->str = yasm__xstrdup("NONE");
+       STAILQ_INSERT_HEAD(&args, sv, link);
+
+       d = yasm_xmalloc(sizeof(dir));
+       d->name = yasm__xstrdup(bname);
+       d->func = "INSN";
+       d->args = args;
+       add_dir(&insnprefix_byp, parser, d);
+    }
+}
+
+static void
+parse_insn(void)
+{
+    if (!arch) {
+       report_error("ARCH not defined prior to INSN");
+       return;
+    }
+    arch->parse_insn();
+}
+
+static void
+parse_cpu(void)
+{
+    dir *d = parse_generic(CPU, "CPU", &cpu_byp);
+    sval *sv = yasm_xmalloc(sizeof(sval));
+    sv->str = yasm__xstrdup("CPU_MODE_VERBATIM");
+    STAILQ_INSERT_TAIL(&d->args, sv, link);
+}
+
+static void
+parse_cpu_alias(void)
+{
+    char *parser = check_parser(CPU_ALIAS);
+    char *name = strtok(NULL, " \t\n");
+    char *alias = strtok(NULL, " \t\n");
+    HAMT *dirs = get_dirs(&cpu_byp, parser);
+    dir *aliasd, *d;
+
+    if (!alias) {
+       report_error("CPU_ALIAS requires an operand");
+       return;
+    }
+
+    aliasd = HAMT_search(dirs, alias);
+    if (!aliasd) {
+       report_error("could not find `%s'", alias);
+       return;
+    }
+
+    d = yasm_xmalloc(sizeof(dir));
+    d->name = yasm__xstrdup(name);
+    d->func = "CPU";
+    dup_slist(&d->args, &aliasd->args);
+
+    add_dir(&cpu_byp, parser, d);
+}
+
+static void
+parse_cpu_feature(void)
+{
+    char *parser = check_parser(CPU_FEATURE);
+    char *name = strtok(NULL, " \t\n");
+    dir *name_dir = yasm_xmalloc(sizeof(dir));
+    dir *noname_dir = yasm_xmalloc(sizeof(dir));
+    sval *sv;
+
+    name_dir->name = yasm__xstrdup(name);
+    name_dir->func = "CPU_FEATURE";
+    parse_args(&name_dir->args);
+
+    noname_dir->name = yasm_xmalloc(strlen(name)+3);
+    strcpy(noname_dir->name, "no");
+    strcat(noname_dir->name, name);
+    noname_dir->func = name_dir->func;
+    dup_slist(&noname_dir->args, &name_dir->args);
+
+    sv = yasm_xmalloc(sizeof(sval));
+    sv->str = yasm__xstrdup("CPU_MODE_SET");
+    STAILQ_INSERT_TAIL(&name_dir->args, sv, link);
+
+    sv = yasm_xmalloc(sizeof(sval));
+    sv->str = yasm__xstrdup("CPU_MODE_CLEAR");
+    STAILQ_INSERT_TAIL(&noname_dir->args, sv, link);
+
+    add_dir(&cpu_byp, parser, name_dir);
+    add_dir(&cpu_byp, parser, noname_dir);
+}
+
+static void
+parse_targetmod(void)
+{
+    parse_generic(TARGETMOD, "TARGETMOD", &regtmod_byp);
+}
+
+static void
+parse_prefix(void)
+{
+    parse_generic(PREFIX, "PREFIX", &insnprefix_byp);
+}
+
+static void
+parse_reg(void)
+{
+    parse_generic(REG, "REG", &regtmod_byp);
+}
+
+static void
+parse_reggroup(void)
+{
+    parse_generic(REGGROUP, "REGGROUP", &regtmod_byp);
+}
+
+static void
+parse_segreg(void)
+{
+    parse_generic(SEGREG, "SEGREG", &regtmod_byp);
+}
+
+/* make the c output for the perfect hash tab array */
+static void
+make_c_tab(
+    FILE *f,
+    const char *which,
+    const char *parser,
+    bstuff *tab,       /* table indexed by b */
+    ub4 smax,          /* range of scramble[] */
+    ub4 blen,          /* b in 0..blen-1, power of 2 */
+    ub4 *scramble)     /* used in final hash */
+{
+    ub4   i;
+    /* table for the mapping for the perfect hash */
+    if (blen >= USE_SCRAMBLE) {
+       /* A way to make the 1-byte values in tab bigger */
+       if (smax > UB2MAXVAL+1) {
+           fprintf(f, "static const unsigned long %s_", which);
+           if (parser)
+               fprintf(f, "%s_", parser);
+           fprintf(f, "scramble[] = {\n");
+           for (i=0; i<=UB1MAXVAL; i+=4)
+               fprintf(f, "0x%.8lx, 0x%.8lx, 0x%.8lx, 0x%.8lx,\n",
+                   scramble[i+0], scramble[i+1], scramble[i+2], scramble[i+3]);
+       } else {
+           fprintf(f, "static const unsigned short %s_", which);
+           if (parser)
+               fprintf(f, "%s_", parser);
+           fprintf(f, "scramble[] = {\n");
+           for (i=0; i<=UB1MAXVAL; i+=8)
+               fprintf(f, 
+"0x%.4lx, 0x%.4lx, 0x%.4lx, 0x%.4lx, 0x%.4lx, 0x%.4lx, 0x%.4lx, 0x%.4lx,\n",
+                   scramble[i+0], scramble[i+1], scramble[i+2], scramble[i+3],
+                   scramble[i+4], scramble[i+5], scramble[i+6], scramble[i+7]);
+       }
+       fprintf(f, "};\n");
+       fprintf(f, "\n");
+    }
+
+    if (blen > 0) {
+       /* small adjustments to _a_ to make values distinct */
+       if (smax <= UB1MAXVAL+1 || blen >= USE_SCRAMBLE)
+           fprintf(f, "static const unsigned char %s_", which);
+       else
+           fprintf(f, "static const unsigned short %s_", which);
+       if (parser)
+           fprintf(f, "%s_", parser);
+       fprintf(f, "tab[] = {\n");
+
+       if (blen < 16) {
+           for (i=0; i<blen; ++i)
+               fprintf(f, "%3d,", scramble[tab[i].val_b]);
+       } else if (blen <= 1024) {
+           for (i=0; i<blen; i+=16)
+               fprintf(f, "%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,\n",
+                   scramble[tab[i+0].val_b], scramble[tab[i+1].val_b], 
+                   scramble[tab[i+2].val_b], scramble[tab[i+3].val_b], 
+                   scramble[tab[i+4].val_b], scramble[tab[i+5].val_b], 
+                   scramble[tab[i+6].val_b], scramble[tab[i+7].val_b], 
+                   scramble[tab[i+8].val_b], scramble[tab[i+9].val_b], 
+                   scramble[tab[i+10].val_b], scramble[tab[i+11].val_b], 
+                   scramble[tab[i+12].val_b], scramble[tab[i+13].val_b], 
+                   scramble[tab[i+14].val_b], scramble[tab[i+15].val_b]); 
+       } else if (blen < USE_SCRAMBLE) {
+           for (i=0; i<blen; i+=8)
+               fprintf(f, "%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,\n",
+                   scramble[tab[i+0].val_b], scramble[tab[i+1].val_b], 
+                   scramble[tab[i+2].val_b], scramble[tab[i+3].val_b], 
+                   scramble[tab[i+4].val_b], scramble[tab[i+5].val_b], 
+                   scramble[tab[i+6].val_b], scramble[tab[i+7].val_b]); 
+       } else {
+           for (i=0; i<blen; i+=16)
+               fprintf(f, "%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,\n",
+                   tab[i+0].val_b, tab[i+1].val_b, 
+                   tab[i+2].val_b, tab[i+3].val_b, 
+                   tab[i+4].val_b, tab[i+5].val_b, 
+                   tab[i+6].val_b, tab[i+7].val_b, 
+                   tab[i+8].val_b, tab[i+9].val_b, 
+                   tab[i+10].val_b, tab[i+11].val_b, 
+                   tab[i+12].val_b, tab[i+13].val_b, 
+                   tab[i+14].val_b, tab[i+15].val_b); 
+       }
+       fprintf(f, "};\n");
+       fprintf(f, "\n");
+    }
+}
+
+typedef struct perfect_add_key_data {
+    ub4 nkeys;
+    key *keys;
+} perfect_add_key_data;
+
+static int
+perfect_add_key(void *node, void *data)
+{
+    dir *d = (dir *)node;
+    perfect_add_key_data *pakd = (perfect_add_key_data *)data;
+    key *k = yasm_xmalloc(sizeof(key));
+
+    k->name_k = yasm__xstrdup(d->name);
+    k->len_k = strlen(d->name);
+    k->next_k = pakd->keys;
+    pakd->keys = k;
+    pakd->nkeys++;
+    return 0;
+}
+
+static void
+perfect_dir(FILE *out, const char *which, const char *parser, HAMT *dirs)
+{
+    perfect_add_key_data pakd;
+    hashform form;
+    bstuff *tab;               /* table indexed by b */
+    hstuff *tabh;              /* table indexed by hash value */
+    ub4 smax;          /* scramble[] values in 0..smax-1, a power of 2 */
+    ub4 alen;                  /* a in 0..alen-1, a power of 2 */
+    ub4 blen;                  /* b in 0..blen-1, a power of 2 */
+    ub4 salt;                  /* a parameter to the hash function */
+    gencode final;             /* code for final hash */
+    ub4 i;
+    ub4 scramble[SCRAMBLE_LEN];        /* used in final hash function */
+    char buf[10][80];          /* buffer for generated code */
+    char *buf2[10];            /* also for generated code */
+    int cpumode = strcmp(which, "cpu") == 0;
+
+    /* perfect hash configuration */
+    form.mode = NORMAL_HM;
+    form.hashtype = STRING_HT;
+    form.perfect = MINIMAL_HP;
+    form.speed = SLOW_HS;
+
+    /* set up code for final hash */
+    final.line = buf2;
+    final.used = 0;
+    final.len  = 10;
+    for (i=0; i<10; i++)
+       final.line[i] = buf[i];
+
+    /* build list of keys */
+    pakd.nkeys = 0;
+    pakd.keys = NULL;
+    HAMT_traverse(dirs, &pakd, perfect_add_key);
+
+    /* find the hash */
+    findhash(&tab, &tabh, &alen, &blen, &salt, &final, 
+            scramble, &smax, pakd.keys, pakd.nkeys, &form);
+
+    /* output the dir table: this should loop up to smax for NORMAL_HP,
+     * or up to pakd.nkeys for MINIMAL_HP.
+     */
+    fprintf(out, "static const %s_parse_data %s_", which, which);
+    if (parser)
+       fprintf(out, "%s_", parser);
+    fprintf(out, "pd[%lu] = {\n", pakd.nkeys);
+    for (i=0; i<pakd.nkeys; i++) {
+       if (tabh[i].key_h) {
+           dir *d = HAMT_search(dirs, tabh[i].key_h->name_k);
+           sval *sv;
+           if (!d) {
+               report_error("internal error: could not find `%s'",
+                            tabh[i].key_h->name_k);
+               break;
+           }
+           if (cpumode)
+               fprintf(out, "{\"%s\",", d->name);
+           else
+               fprintf(out, "%s(\"%s\",", d->func, d->name);
+           STAILQ_FOREACH(sv, &d->args, link) {
+               fprintf(out, " %s", sv->str);
+               if (STAILQ_NEXT(sv, link))
+                   fprintf(out, ",");
+           }
+           fprintf(out, cpumode ? "}" : ")");
+       } else
+           fprintf(out, "  { NULL }");
+
+       if (i < pakd.nkeys-1)
+           fprintf(out, ",");
+       fprintf(out, "\n");
+    }
+    fprintf(out, "};\n");
+
+    /* output the hash tab[] array */
+    make_c_tab(out, which, parser, tab, smax, blen, scramble);
+
+    /* The hash function */
+    fprintf(out, "#define tab %s_", which);
+    if (parser)
+       fprintf(out, "%s_", parser);
+    fprintf(out, "tab\n");
+    fprintf(out, "static const %s_parse_data *\n%s_", which, which);
+    if (parser)
+       fprintf(out, "%s_", parser);
+    fprintf(out, "find(const char *key, size_t len)\n");
+    fprintf(out, "{\n");
+    fprintf(out, "  const %s_parse_data *ret;\n", which);
+    for (i=0; i<final.used; ++i)
+       fprintf(out, final.line[i]);
+    fprintf(out, "  if (rsl >= %lu) return NULL;\n", pakd.nkeys);
+    fprintf(out, "  ret = &%s_", which);
+    if (parser)
+       fprintf(out, "%s_", parser);
+    fprintf(out, "pd[rsl];\n");
+    fprintf(out, "  if (strcmp(key, ret->name) != 0) return NULL;\n");
+    fprintf(out, "  return ret;\n");
+    fprintf(out, "}\n");
+    fprintf(out, "#undef tab\n\n");
+
+    free(tab);
+    free(tabh);
+}
+
+/* Get an entire "real" line from the input file by combining any
+ * \\\n continuations.
+ */
+static int get_line(FILE *in)
+{
+    char *p = line;
+    cur_line = next_line;
+
+    if (feof(in))
+       return 0;
+
+    while (p < &line[1023-128]) {
+       if (!fgets(p, 128, in))
+           return 1;
+       next_line++;
+       /* if continuation, strip out leading whitespace */
+       if (p > line) {
+           char *p2 = p;
+           while (isspace(*p2)) p2++;
+           if (p2 > p)
+               memmove(p, p2, strlen(p2)+1);
+       }
+       while (*p) p++;
+       if (p[-2] != '\\' || p[-1] != '\n') {
+           if (p[-1] == '\n')
+               p[-1] = '\0';
+           return 1;
+       }
+       p -= 2;
+    }
+}
+
+static struct {
+    const char *name;
+    int indx;
+    void (*handler) (void);
+} directives[] = {
+    {"ARCH", ARCH, parse_arch},
+    {"PARSERS", PARSERS, parse_parsers},
+    {"INSN", INSN, parse_insn},
+    {"CPU", CPU, parse_cpu},
+    {"CPU_ALIAS", CPU_ALIAS, parse_cpu_alias},
+    {"CPU_FEATURE", CPU_FEATURE, parse_cpu_feature},
+    {"TARGETMOD", TARGETMOD, parse_targetmod},
+    {"PREFIX", PREFIX, parse_prefix},
+    {"REG", REG, parse_reg},
+    {"REGGROUP", REGGROUP, parse_reggroup},
+    {"SEGREG", SEGREG, parse_segreg},
+};
+
+int
+main(int argc, char *argv[])
+{
+    FILE *in, *out;
+    int i, t;
+    int insn_numnongas = 0, insn_numgas = 0, insn_numcommon = 0;
+    int cpu_num = 0, cpu_numalias = 0, cpu_numfeature = 0;
+    int prefix_numnongas = 0, prefix_numgas = 0, prefix_numcommon = 0;
+    int reg_numcommon = 0, reg_num64 = 0, reg_numgroup = 0, reg_numseg = 0;
+    char *tok;
+    int count[NUM_DIRS];
+    dir_byp *db;
+
+    for (i=0; i<NUM_DIRS; i++)
+       count[i] = 0;
+
+    if (argc != 3) {
+       fprintf(stderr, "Usage: gap <in> <out>\n");
+       return EXIT_FAILURE;
+    }
+
+    in = fopen(argv[1], "rt");
+    if (!in) {
+       fprintf(stderr, "Could not open `%s' for reading\n", argv[1]);
+       return EXIT_FAILURE;
+    }
+
+    STAILQ_INIT(&insnprefix_byp);
+    STAILQ_INIT(&cpu_byp);
+    STAILQ_INIT(&regtmod_byp);
+
+    /* Parse input file */
+    while (get_line(in)) {
+       int found;
+       /*printf("%s\n", line);*/
+       tok = strtok(line, " \t\n");
+       if (!tok)
+           continue;
+
+       /* Comments start with # as the first thing on a line */
+       if (tok[0] == '#')
+           continue;
+
+       /* Look for directive */
+       found = 0;
+       for (i=0; i<sizeof(directives)/sizeof(directives[0]); i++) {
+           if (strcmp(tok, directives[i].name) == 0) {
+               count[directives[i].indx]++;
+               directives[i].handler();
+               found = 1;
+               break;
+           }
+       }
+       if (!found)
+           report_error("unknown directive `%s'\n", tok);
+    }
+
+    /* Output some informational statistics */
+    printf("Directives read:\n");
+    for (i=0; i<sizeof(directives)/sizeof(directives[0]); i++)
+       printf("\t%d\t%s\n", count[directives[i].indx], directives[i].name);
+
+    if (errors > 0)
+       return EXIT_FAILURE;
+
+    out = fopen(argv[2], "wt");
+    if (!out) {
+       fprintf(stderr, "Could not open `%s' for writing\n", argv[2]);
+       return EXIT_FAILURE;
+    }
+
+    /* Get perfect hashes for the three lists of directives */
+    STAILQ_FOREACH(db, &insnprefix_byp, link)
+       perfect_dir(out, "insnprefix", db->parser, db->dirs);
+    STAILQ_FOREACH(db, &cpu_byp, link)
+       perfect_dir(out, "cpu", db->parser, db->dirs);
+    STAILQ_FOREACH(db, &regtmod_byp, link)
+       perfect_dir(out, "regtmod", db->parser, db->dirs);
+
+    if (errors > 0)
+       return EXIT_FAILURE;
+
+    return EXIT_SUCCESS;
+}
+
diff --git a/tools/gap/perfect.c b/tools/gap/perfect.c
new file mode 100644 (file)
index 0000000..2eae6c6
--- /dev/null
@@ -0,0 +1,1192 @@
+/* Modified for use with yasm by Peter Johnson.
+ * $Id$
+ */
+/*
+------------------------------------------------------------------------------
+perfect.c: code to generate code for a hash for perfect hashing.
+(c) Bob Jenkins, September 1996, December 1999
+You may use this code in any way you wish, and it is free.  No warranty.
+I hereby place this in the public domain.
+Source is http://burtleburtle.net/bob/c/perfect.c
+
+This generates a minimal perfect hash function.  That means, given a
+set of n keys, this determines a hash function that maps each of
+those keys into a value in 0..n-1 with no collisions.
+
+The perfect hash function first uses a normal hash function on the key
+to determine (a,b) such that the pair (a,b) is distinct for all
+keys, then it computes a^scramble[tab[b]] to get the final perfect hash.
+tab[] is an array of 1-byte values and scramble[] is a 256-term array of 
+2-byte or 4-byte values.  If there are n keys, the length of tab[] is a 
+power of two between n/3 and n.
+
+I found the idea of computing distinct (a,b) values in "Practical minimal 
+perfect hash functions for large databases", Fox, Heath, Chen, and Daoud, 
+Communications of the ACM, January 1992.  They found the idea in Chichelli 
+(CACM Jan 1980).  Beyond that, our methods differ.
+
+The key is hashed to a pair (a,b) where a in 0..*alen*-1 and b in
+0..*blen*-1.  A fast hash function determines both a and b
+simultaneously.  Any decent hash function is likely to produce
+hashes so that (a,b) is distinct for all pairs.  I try the hash
+using different values of *salt* until all pairs are distinct.
+
+The final hash is (a XOR scramble[tab[b]]).  *scramble* is a
+predetermined mapping of 0..255 into 0..smax-1.  *tab* is an
+array that we fill in in such a way as to make the hash perfect.
+
+First we fill in all values of *tab* that are used by more than one
+key.  We try all possible values for each position until one works.
+
+This leaves m unmapped keys and m values that something could hash to.
+If you treat unmapped keys as lefthand nodes and unused hash values
+as righthand nodes, and draw a line connecting each key to each hash
+value it could map to, you get a bipartite graph.  We attempt to
+find a perfect matching in this graph.  If we succeed, we have
+determined a perfect hash for the whole set of keys.
+
+*scramble* is used because (a^tab[i]) clusters keys around *a*.
+------------------------------------------------------------------------------
+*/
+
+#include "tools/gap/standard.h"
+#include "libyasm/coretype.h"
+#include "libyasm/phash.h"
+#include "tools/gap/perfect.h"
+
+#define CHECKSTATE 8
+
+/*
+------------------------------------------------------------------------------
+Find the mapping that will produce a perfect hash
+------------------------------------------------------------------------------
+*/
+
+/* return the ceiling of the log (base 2) of val */
+ub4  phash_log2(val)
+ub4  val;
+{
+  ub4 i;
+  for (i=0; ((ub4)1<<i) < val; ++i)
+    ;
+  return i;
+}
+
+/* compute p(x), where p is a permutation of 0..(1<<nbits)-1 */
+/* permute(0)=0.  This is intended and useful. */
+static ub4  permute(x, nbits)
+ub4 x;                                       /* input, a value in some range */
+ub4 nbits;                                 /* input, number of bits in range */
+{
+  int i;
+  int mask   = ((ub4)1<<nbits)-1;                                /* all ones */
+  int const2 = 1+nbits/2;
+  int const3 = 1+nbits/3;
+  int const4 = 1+nbits/4;
+  int const5 = 1+nbits/5;
+  for (i=0; i<20; ++i)
+  {
+    x = (x+(x<<const2)) & mask; 
+    x = (x^(x>>const3));
+    x = (x+(x<<const4)) & mask;
+    x = (x^(x>>const5));
+  }
+  return x;
+}
+
+/* initialize scramble[] with distinct random values in 0..smax-1 */
+static void scrambleinit(scramble, smax)
+ub4      *scramble;                            /* hash is a^scramble[tab[b]] */
+ub4       smax;                    /* scramble values should be in 0..smax-1 */
+{
+  ub4 i;
+
+  /* fill scramble[] with distinct random integers in 0..smax-1 */
+  for (i=0; i<SCRAMBLE_LEN; ++i)
+  {
+    scramble[i] = permute(i, phash_log2(smax));
+  }
+}
+
+/* 
+ * Check if key1 and key2 are the same. 
+ * We already checked (a,b) are the same.
+ */
+static void checkdup(key1, key2, form)
+key      *key1;
+key      *key2;
+hashform *form;
+{
+  switch(form->hashtype)
+  {
+  case STRING_HT:
+    if ((key1->len_k == key2->len_k) &&
+       !memcmp(key1->name_k, key2->name_k, (size_t)key1->len_k))
+    {
+      fprintf(stderr, "perfect.c: Duplicates keys!  %.*s\n",
+             key1->len_k, key1->name_k);
+      exit(EXIT_SUCCESS);
+    }
+    break;
+  case INT_HT:
+    if (key1->hash_k == key2->hash_k)
+    {
+      fprintf(stderr, "perfect.c: Duplicate keys!  %.8lx\n", key1->hash_k);
+      exit(EXIT_SUCCESS);
+    }
+    break;
+  case AB_HT:
+    fprintf(stderr, "perfect.c: Duplicate keys!  %.8lx %.8lx\n",
+           key1->a_k, key1->b_k);
+    exit(EXIT_SUCCESS);
+    break;
+  default:
+    fprintf(stderr, "perfect.c: Illegal hash type %ld\n", (ub4)form->hashtype);
+    exit(EXIT_SUCCESS);
+    break;
+  }
+}
+
+
+/* 
+ * put keys in tabb according to key->b_k
+ * check if the initial hash might work 
+ */
+static int inittab(tabb, blen, keys, form, complete)
+bstuff   *tabb;                     /* output, list of keys with b for (a,b) */
+ub4       blen;                                            /* length of tabb */
+key      *keys;                               /* list of keys already hashed */
+hashform *form;                                           /* user directives */
+int       complete;        /* TRUE means to complete init despite collisions */
+{
+  int  nocollision = TRUE;
+  key *mykey;
+
+  memset((void *)tabb, 0, (size_t)(sizeof(bstuff)*blen));
+
+  /* Two keys with the same (a,b) guarantees a collision */
+  for (mykey=keys; mykey; mykey=mykey->next_k)
+  {
+    key *otherkey;
+
+    for (otherkey=tabb[mykey->b_k].list_b; 
+        otherkey; 
+        otherkey=otherkey->nextb_k)
+    {
+      if (mykey->a_k == otherkey->a_k)
+      {
+        nocollision = FALSE;
+       checkdup(mykey, otherkey, form);
+       if (!complete)
+         return FALSE;
+      }
+    }
+    ++tabb[mykey->b_k].listlen_b;
+    mykey->nextb_k = tabb[mykey->b_k].list_b;
+    tabb[mykey->b_k].list_b = mykey;
+  }
+
+  /* no two keys have the same (a,b) pair */
+  return nocollision;
+}
+
+
+/* Do the initial hash for normal mode (use lookup and checksum) */
+static void initnorm(keys, alen, blen, smax, salt, final)
+key      *keys;                                          /* list of all keys */
+ub4       alen;                    /* (a,b) has a in 0..alen-1, a power of 2 */
+ub4       blen;                    /* (a,b) has b in 0..blen-1, a power of 2 */
+ub4       smax;                   /* maximum range of computable hash values */
+ub4       salt;                     /* used to initialize the hash function */
+gencode  *final;                          /* output, code for the final hash */
+{
+  key *mykey;
+  if (phash_log2(alen)+phash_log2(blen) > UB4BITS)
+  {
+    ub4 initlev = salt*0x9e3779b9;  /* the golden ratio; an arbitrary value */
+
+    for (mykey=keys; mykey; mykey=mykey->next_k)
+    {
+      ub4 i, state[CHECKSTATE];
+      for (i=0; i<CHECKSTATE; ++i) state[i] = initlev;
+      phash_checksum( mykey->name_k, mykey->len_k, state);
+      mykey->a_k = state[0]&(alen-1);
+      mykey->b_k = state[1]&(blen-1);
+    }
+    final->used = 4;
+    sprintf(final->line[0], 
+           "  unsigned long i,state[CHECKSTATE],rsl;\n");
+    sprintf(final->line[1], 
+           "  for (i=0; i<CHECKSTATE; ++i) state[i]=0x%lx;\n",initlev);
+    sprintf(final->line[2],
+           "  phash_checksum(key, len, state);\n");
+    sprintf(final->line[3], 
+           "  rsl = ((state[0]&0x%x)^scramble[tab[state[1]&0x%x]]);\n",
+           alen-1, blen-1);
+  }
+  else
+  {
+    ub4 loga = phash_log2(alen);                            /* log based 2 of blen */
+    ub4 initlev = salt*0x9e3779b9;  /* the golden ratio; an arbitrary value */
+
+    for (mykey=keys; mykey; mykey=mykey->next_k)
+    {
+      ub4 hash = phash_lookup(mykey->name_k, mykey->len_k, initlev);
+      mykey->a_k = (loga > 0) ? hash>>(UB4BITS-loga) : 0;
+      mykey->b_k = (blen > 1) ? hash&(blen-1) : 0;
+    }
+    final->used = 2;
+    sprintf(final->line[0], 
+           "  unsigned long rsl, val = phash_lookup(key, len, 0x%lxUL);\n", initlev);
+    if (smax <= 1)
+    {
+      sprintf(final->line[1], "  rsl = 0;\n");
+    }
+    else if (blen < USE_SCRAMBLE)
+    {
+      sprintf(final->line[1], "  rsl = ((val>>%ld)^tab[val&0x%x]);\n",
+             UB4BITS-phash_log2(alen), blen-1);
+    }
+    else
+    {
+      sprintf(final->line[1], "  rsl = ((val>>%ld)^scramble[tab[val&0x%x]]);\n",
+             UB4BITS-phash_log2(alen), blen-1);
+    }
+  }
+}
+
+
+
+/* Do initial hash for inline mode */
+static void initinl(keys, alen, blen, smax, salt, final)
+key      *keys;                                          /* list of all keys */
+ub4       alen;                    /* (a,b) has a in 0..alen-1, a power of 2 */
+ub4       blen;                    /* (a,b) has b in 0..blen-1, a power of 2 */
+ub4       smax;                           /* range of computable hash values */
+ub4       salt;                     /* used to initialize the hash function */
+gencode  *final;                            /* generated code for final hash */
+{
+  key *mykey;
+  ub4  amask = alen-1;
+  ub4  blog  = phash_log2(blen);
+  ub4  initval = salt*0x9e3779b9;    /* the golden ratio; an arbitrary value */
+
+  /* It's more important to have b uniform than a, so b is the low bits */
+  for (mykey = keys;  mykey != (key *)0;  mykey = mykey->next_k)
+  {
+    ub4   hash = initval;
+    ub4   i;
+    for (i=0; i<mykey->len_k; ++i)
+    {
+      hash = (mykey->name_k[i] ^ hash) + ((hash<<(UB4BITS-6))+(hash>>6));
+    }
+    mykey->hash_k = hash;
+    mykey->a_k = (alen > 1) ? (hash & amask) : 0;
+    mykey->b_k = (blen > 1) ? (hash >> (UB4BITS-blog)) : 0;
+  }
+  final->used = 1;
+  if (smax <= 1)
+  {
+    sprintf(final->line[0], "  unsigned long rsl = 0;\n");
+  }
+  else if (blen < USE_SCRAMBLE)
+  {
+    sprintf(final->line[0], "  unsigned long rsl = ((val & 0x%lx) ^ tab[val >> %ld]);\n",
+           amask, UB4BITS-blog);
+  }
+  else
+  {
+    sprintf(final->line[0], "  unsigned long rsl = ((val & 0x%lx) ^ scramble[tab[val >> %ld]]);\n",
+           amask, UB4BITS-blog);
+  }
+}
+
+
+/* 
+ * Run a hash function on the key to get a and b 
+ * Returns:
+ *   0: didn't find distinct (a,b) for all keys
+ *   1: found distinct (a,b) for all keys, put keys in tabb[]
+ *   2: found a perfect hash, no need to do any more work
+ */
+static ub4 initkey(keys, nkeys, tabb, alen, blen, smax, salt, form, final)
+key      *keys;                                          /* list of all keys */
+ub4       nkeys;                                     /* total number of keys */
+bstuff   *tabb;                                        /* stuff indexed by b */
+ub4       alen;                    /* (a,b) has a in 0..alen-1, a power of 2 */
+ub4       blen;                    /* (a,b) has b in 0..blen-1, a power of 2 */
+ub4       smax;                           /* range of computable hash values */
+ub4       salt;                     /* used to initialize the hash function */
+hashform *form;                                           /* user directives */
+gencode  *final;                                      /* code for final hash */
+{
+  ub4 finished;
+
+  /* Do the initial hash of the keys */
+  switch(form->mode)
+  {
+  case NORMAL_HM:
+    initnorm(keys, alen, blen, smax, salt, final);
+    break;
+  case INLINE_HM:
+    initinl(keys, alen, blen, smax, salt, final);
+    break;
+#if 0
+  case HEX_HM:
+  case DECIMAL_HM:
+    finished = inithex(keys, nkeys, alen, blen, smax, salt, final, form); 
+    if (finished) return 2;
+    break;
+#endif
+  default:
+    fprintf(stderr, "fatal error: illegal mode\n"); 
+    exit(1);
+  }
+
+  if (nkeys <= 1)
+  {
+    final->used = 1;
+    sprintf(final->line[0], "  unsigned long rsl = 0;\n");
+    return 2;
+  }
+
+  return inittab(tabb, blen, keys, form, FALSE);
+}
+
+/* Print an error message and exit if there are duplicates */
+static void duplicates(tabb, blen, keys, form)
+bstuff   *tabb;                    /* array of lists of keys with the same b */
+ub4       blen;                              /* length of tabb, a power of 2 */
+key      *keys;
+hashform *form;                                           /* user directives */
+{
+  ub4  i;
+  key *key1;
+  key *key2;
+
+  (void)inittab(tabb, blen, keys, form, TRUE);
+
+  /* for each b, do nested loops through key list looking for duplicates */
+  for (i=0; i<blen; ++i)
+    for (key1=tabb[i].list_b; key1; key1=key1->nextb_k)
+      for (key2=key1->nextb_k; key2; key2=key2->nextb_k)
+       checkdup(key1, key2, form);
+}
+
+
+/* Try to apply an augmenting list */
+static int apply(tabb, tabh, tabq, blen, scramble, tail, rollback)
+bstuff *tabb;
+hstuff *tabh;
+qstuff *tabq;
+ub4     blen;
+ub4    *scramble;
+ub4     tail;
+int     rollback;          /* FALSE applies augmenting path, TRUE rolls back */
+{
+  ub4     hash;
+  key    *mykey;
+  bstuff *pb;
+  ub4     child;
+  ub4     parent;
+  ub4     stabb;                                         /* scramble[tab[b]] */
+
+  /* walk from child to parent */
+  for (child=tail-1; child; child=parent)
+  {
+    parent = tabq[child].parent_q;                    /* find child's parent */
+    pb     = tabq[parent].b_q;             /* find parent's list of siblings */
+
+    /* erase old hash values */
+    stabb = scramble[pb->val_b];
+    for (mykey=pb->list_b; mykey; mykey=mykey->nextb_k)
+    {
+      hash = mykey->a_k^stabb;
+      if (mykey == tabh[hash].key_h)
+      {                            /* erase hash for all of child's siblings */
+       tabh[hash].key_h = (key *)0;
+      }
+    }
+
+    /* change pb->val_b, which will change the hashes of all parent siblings */
+    pb->val_b = (rollback ? tabq[child].oldval_q : tabq[child].newval_q);
+
+    /* set new hash values */
+    stabb = scramble[pb->val_b];
+    for (mykey=pb->list_b; mykey; mykey=mykey->nextb_k)
+    {
+      hash = mykey->a_k^stabb;
+      if (rollback)
+      {
+       if (parent == 0) continue;                  /* root never had a hash */
+      }
+      else if (tabh[hash].key_h)
+      {
+       /* very rare: roll back any changes */
+       (void *)apply(tabb, tabh, tabq, blen, scramble, tail, TRUE);
+       return FALSE;                                  /* failure, collision */
+      }
+      tabh[hash].key_h = mykey;
+    }
+  }
+  return TRUE;
+}
+
+
+/*
+-------------------------------------------------------------------------------
+augment(): Add item to the mapping.
+
+Construct a spanning tree of *b*s with *item* as root, where each
+parent can have all its hashes changed (by some new val_b) with 
+at most one collision, and each child is the b of that collision.
+
+I got this from Tarjan's "Data Structures and Network Algorithms".  The
+path from *item* to a *b* that can be remapped with no collision is 
+an "augmenting path".  Change values of tab[b] along the path so that 
+the unmapped key gets mapped and the unused hash value gets used.
+
+Assuming 1 key per b, if m out of n hash values are still unused, 
+you should expect the transitive closure to cover n/m nodes before 
+an unused node is found.  Sum(i=1..n)(n/i) is about nlogn, so expect
+this approach to take about nlogn time to map all single-key b's.
+-------------------------------------------------------------------------------
+*/
+static int augment(tabb, tabh, tabq, blen, scramble, smax, item, nkeys, 
+                  highwater, form)
+bstuff   *tabb;                                        /* stuff indexed by b */
+hstuff   *tabh;  /* which key is associated with which hash, indexed by hash */
+qstuff   *tabq;            /* queue of *b* values, this is the spanning tree */
+ub4       blen;                                            /* length of tabb */
+ub4      *scramble;                      /* final hash is a^scramble[tab[b]] */
+ub4       smax;                                 /* highest value in scramble */
+bstuff   *item;                           /* &tabb[b] for the b to be mapped */
+ub4       nkeys;                         /* final hash must be in 0..nkeys-1 */
+ub4       highwater;        /* a value higher than any now in tabb[].water_b */
+hashform *form;               /* TRUE if we should do a minimal perfect hash */
+{
+  ub4  q;                      /* current position walking through the queue */
+  ub4  tail;              /* tail of the queue.  0 is the head of the queue. */
+  ub4  limit=((blen < USE_SCRAMBLE) ? smax : UB1MAXVAL+1);
+  ub4  highhash = ((form->perfect == MINIMAL_HP) ? nkeys : smax);
+  int  trans = (form->speed == SLOW_HS || form->perfect == MINIMAL_HP);
+
+  /* initialize the root of the spanning tree */
+  tabq[0].b_q = item;
+  tail = 1;
+
+  /* construct the spanning tree by walking the queue, add children to tail */
+  for (q=0; q<tail; ++q)
+  {
+    bstuff *myb = tabq[q].b_q;                        /* the b for this node */
+    ub4     i;                              /* possible value for myb->val_b */
+
+    if (!trans && (q == 1)) 
+      break;                                  /* don't do transitive closure */
+
+    for (i=0; i<limit; ++i)
+    {
+      bstuff *childb = (bstuff *)0;             /* the b that this i maps to */
+      key    *mykey;                       /* for walking through myb's keys */
+
+      for (mykey = myb->list_b; mykey; mykey=mykey->nextb_k)
+      {
+       key    *childkey;
+       ub4 hash = mykey->a_k^scramble[i];
+
+       if (hash >= highhash) break;                        /* out of bounds */
+       childkey = tabh[hash].key_h;
+
+       if (childkey)
+       {
+         bstuff *hitb = &tabb[childkey->b_k];
+
+         if (childb)
+         {
+           if (childb != hitb) break;            /* hit at most one child b */
+         }
+         else
+         {
+           childb = hitb;                        /* remember this as childb */
+           if (childb->water_b == highwater) break;     /* already explored */
+         }
+       }
+      }
+      if (mykey) continue;             /* myb with i has multiple collisions */
+
+      /* add childb to the queue of reachable things */
+      if (childb) childb->water_b = highwater;
+      tabq[tail].b_q      = childb;
+      tabq[tail].newval_q = i;     /* how to make parent (myb) use this hash */
+      tabq[tail].oldval_q = myb->val_b;            /* need this for rollback */
+      tabq[tail].parent_q = q;
+      ++tail;
+
+      if (!childb)
+      {                                  /* found an *i* with no collisions? */
+       /* try to apply the augmenting path */
+       if (apply(tabb, tabh, tabq, blen, scramble, tail, FALSE))
+         return TRUE;        /* success, item was added to the perfect hash */
+
+       --tail;                    /* don't know how to handle such a child! */
+      }
+    }
+  }
+  return FALSE;
+}
+
+
+/* find a mapping that makes this a perfect hash */
+static int perfect(tabb, tabh, tabq, blen, smax, scramble, nkeys, form)
+bstuff   *tabb;
+hstuff   *tabh;
+qstuff   *tabq;
+ub4       blen;
+ub4       smax;
+ub4      *scramble;
+ub4       nkeys;
+hashform *form;
+{
+  ub4 maxkeys;                           /* maximum number of keys for any b */
+  ub4 i, j;
+
+  /* clear any state from previous attempts */
+  memset((void *)tabh, 0, 
+        (size_t)(sizeof(hstuff)*
+                 ((form->perfect == MINIMAL_HP) ? nkeys : smax)));
+  memset((void *)tabq, 0, (size_t)(sizeof(qstuff)*(blen+1)));
+
+  for (maxkeys=0,i=0; i<blen; ++i) 
+    if (tabb[i].listlen_b > maxkeys) 
+      maxkeys = tabb[i].listlen_b;
+
+  /* In descending order by number of keys, map all *b*s */
+  for (j=maxkeys; j>0; --j)
+    for (i=0; i<blen; ++i)
+      if (tabb[i].listlen_b == j)
+       if (!augment(tabb, tabh, tabq, blen, scramble, smax, &tabb[i], nkeys, 
+                    i+1, form))
+       {
+         printf("fail to map group of size %ld for tab size %ld\n", j, blen);
+         return FALSE;
+       }
+
+  /* Success!  We found a perfect hash of all keys into 0..nkeys-1. */
+  return TRUE;
+}
+
+
+/*
+ * Simple case: user gave (a,b).  No more mixing, no guessing alen or blen. 
+ * This assumes a,b reside in (key->a_k, key->b_k), and final->form == AB_HK.
+ */
+static void hash_ab(tabb, alen, blen, salt, final, 
+            scramble, smax, keys, nkeys, form)
+bstuff  **tabb;           /* output, tab[] of the perfect hash, length *blen */
+ub4      *alen;                 /* output, 0..alen-1 is range for a of (a,b) */
+ub4      *blen;                 /* output, 0..blen-1 is range for b of (a,b) */
+ub4      *salt;                         /* output, initializes initial hash */
+gencode  *final;                                      /* code for final hash */
+ub4      *scramble;                      /* input, hash = a^scramble[tab[b]] */
+ub4      *smax;                           /* input, scramble[i] in 0..smax-1 */
+key      *keys;                                       /* input, keys to hash */
+ub4       nkeys;                       /* input, number of keys being hashed */
+hashform *form;                                           /* user directives */
+{
+  hstuff *tabh;
+  qstuff *tabq;
+  key    *mykey;
+  ub4     i;
+  int     used_tab;
+
+  /* initially make smax the first power of two bigger than nkeys */
+  *smax = ((ub4)1<<phash_log2(nkeys));
+  scrambleinit(scramble, *smax);
+
+  /* set *alen and *blen based on max A and B from user */
+  *alen = 1;
+  *blen = 1;
+  for (mykey = keys;  mykey != (key *)0;  mykey = mykey->next_k)
+  {
+    while (*alen <= mykey->a_k) *alen *= 2;
+    while (*blen <= mykey->b_k) *blen *= 2;
+  }
+  if (*alen > 2**smax)
+  {
+    fprintf(stderr,
+      "perfect.c: Can't deal with (A,B) having A bigger than twice \n");
+    fprintf(stderr,
+      "  the smallest power of two greater or equal to any legal hash.\n");
+    exit(EXIT_SUCCESS);
+  }
+
+  /* allocate working memory */
+  *tabb = (bstuff *)yasm_xmalloc((size_t)(sizeof(bstuff)*(*blen)));
+  tabq  = (qstuff *)yasm_xmalloc(sizeof(qstuff)*(*blen+1));
+  tabh  = (hstuff *)yasm_xmalloc(sizeof(hstuff)*(form->perfect == MINIMAL_HP ? 
+                                            nkeys : *smax));
+
+  /* check that (a,b) are distinct and put them in tabb indexed by b */
+  (void)inittab(*tabb, *blen, keys, form, FALSE);
+
+  /* try with smax */
+  if (!perfect(*tabb, tabh, tabq, *blen, *smax, scramble, nkeys, form))
+  {
+    if (form->perfect == MINIMAL_HP)
+    {
+      printf("fatal error: Cannot find perfect hash for user (A,B) pairs\n");
+      exit(EXIT_SUCCESS);
+    }
+    else
+    {
+      /* try with 2*smax */
+      free((void *)tabh);
+      *smax = *smax * 2;
+      scrambleinit(scramble, *smax);
+      tabh = (hstuff *)yasm_xmalloc(sizeof(hstuff)*(form->perfect == MINIMAL_HP ?
+                                               nkeys : *smax));
+      if (!perfect(*tabb, tabh, tabq, *blen, *smax, scramble, nkeys, form))
+      {
+       printf("fatal error: Cannot find perfect hash for user (A,B) pairs\n");
+       exit(EXIT_SUCCESS);
+      }
+    }
+  }
+
+  /* check if tab[] was really needed */
+  for (i=0; i<*blen; ++i)
+  {
+    if ((*tabb)[i].val_b != 0) break;            /* assumes permute(0) == 0 */
+  }
+  used_tab = (i < *blen);
+
+  /* write the code for the perfect hash */
+  *salt = 1;
+  final->used = 1;
+  if (!used_tab)
+  {
+    sprintf(final->line[0], "  unsigned long rsl = a;\n");
+  }
+  else if (*blen < USE_SCRAMBLE)
+  {
+    sprintf(final->line[0], "  unsigned long rsl = (a ^ tab[b]);\n");
+  }
+  else
+  {
+    sprintf(final->line[0], "  unsigned long rsl = (a ^ scramble[tab[b]]);\n");
+  }
+
+  printf("success, found a perfect hash\n");
+
+  free((void *)tabq);
+  free((void *)tabh);
+}
+
+
+/* guess initial values for alen and blen */
+static void initalen(alen, blen, smax, nkeys, form)
+ub4      *alen;                                      /* output, initial alen */
+ub4      *blen;                                      /* output, initial blen */
+ub4      *smax;    /* input, power of two greater or equal to max hash value */
+ub4       nkeys;                              /* number of keys being hashed */
+hashform *form;                                           /* user directives */
+{
+  /*
+   * Find initial *alen, *blen
+   * Initial alen and blen values were found empirically.  Some factors:
+   *
+   * If smax<256 there is no scramble, so tab[b] needs to cover 0..smax-1.
+   *
+   * alen and blen must be powers of 2 because the values in 0..alen-1 and
+   * 0..blen-1 are produced by applying a bitmask to the initial hash function.
+   *
+   * alen must be less than smax, in fact less than nkeys, because otherwise
+   * there would often be no i such that a^scramble[i] is in 0..nkeys-1 for
+   * all the *a*s associated with a given *b*, so there would be no legal
+   * value to assign to tab[b].  This only matters when we're doing a minimal
+   * perfect hash.
+   *
+   * It takes around 800 trials to find distinct (a,b) with nkey=smax*(5/8)
+   * and alen*blen = smax*smax/32.
+   *
+   * Values of blen less than smax/4 never work, and smax/2 always works.
+   *
+   * We want blen as small as possible because it is the number of bytes in
+   * the huge array we must create for the perfect hash.
+   *
+   * When nkey <= smax*(5/8), blen=smax/4 works much more often with 
+   * alen=smax/8 than with alen=smax/4.  Above smax*(5/8), blen=smax/4
+   * doesn't seem to care whether alen=smax/8 or alen=smax/4.  I think it
+   * has something to do with 5/8 = 1/8 * 5.  For example examine 80000, 
+   * 85000, and 90000 keys with different values of alen.  This only matters
+   * if we're doing a minimal perfect hash.
+   *
+   * When alen*blen <= 1<<UB4BITS, the initial hash must produce one integer.
+   * Bigger than that it must produce two integers, which increases the
+   * cost of the hash per character hashed.
+   */
+  if (form->perfect == NORMAL_HP)
+  {
+    if ((form->speed == FAST_HS) && (nkeys > *smax*0.8))
+    {
+      *smax = *smax * 2;
+    }
+
+    *alen = ((form->hashtype==INT_HT) && *smax>131072) ? 
+      ((ub4)1<<(UB4BITS-phash_log2(*blen))) :   /* distinct keys => distinct (A,B) */
+      *smax;                         /* no reason to restrict alen to smax/2 */
+    if ((form->hashtype == INT_HT) && *smax < 32)
+      *blen = *smax;                      /* go for function speed not space */
+    else if (*smax/4 <= (1<<14))
+      *blen = ((nkeys <= *smax*0.56) ? *smax/32 :
+              (nkeys <= *smax*0.74) ? *smax/16 : *smax/8);
+    else
+      *blen = ((nkeys <= *smax*0.6) ? *smax/16 : 
+              (nkeys <= *smax*0.8) ? *smax/8 : *smax/4);
+
+    if ((form->speed == FAST_HS) && (*blen < *smax/8))
+      *blen = *smax/8;
+
+    if (*alen < 1) *alen = 1;
+    if (*blen < 1) *blen = 1;
+  }
+  else
+  {
+    switch(phash_log2(*smax))
+    {
+    case 0:
+      *alen = 1;
+      *blen = 1;
+    case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8:
+      *alen = (form->perfect == NORMAL_HP) ? *smax : *smax/2;
+      *blen = *smax/2;
+      break;
+    case 9:
+    case 10:
+    case 11:
+    case 12:
+    case 13:
+    case 14:
+    case 15:
+    case 16:
+    case 17:
+      if (form->speed == FAST_HS)
+      {
+       *alen = *smax/2;
+       *blen = *smax/4;
+      }
+      else if (*smax/4 < USE_SCRAMBLE)
+      {
+       *alen = ((nkeys <= *smax*0.52) ? *smax/8 : *smax/4);
+       *blen = ((nkeys <= *smax*0.52) ? *smax/8 : *smax/4);
+      }
+      else
+      {
+       *alen = ((nkeys <= *smax*(5.0/8.0)) ? *smax/8 : 
+                (nkeys <= *smax*(3.0/4.0)) ? *smax/4 : *smax/2);
+       *blen = *smax/4;                /* always give the small size a shot */
+      }
+      break;
+    case 18:
+      if (form->speed == FAST_HS)
+      {
+       *alen = *smax/2;
+       *blen = *smax/2;
+      }
+      else
+      {
+       *alen = *smax/8;                 /* never require the multiword hash */
+       *blen = (nkeys <= *smax*(5.0/8.0)) ? *smax/4 : *smax/2;
+      }
+      break;
+    case 19:
+    case 20:
+      *alen = (nkeys <= *smax*(5.0/8.0)) ? *smax/8 : *smax/2;
+      *blen = (nkeys <= *smax*(5.0/8.0)) ? *smax/4 : *smax/2;
+      break;
+    default:
+      *alen = *smax/2;              /* just find a hash as quick as possible */
+      *blen = *smax/2;     /* we'll be thrashing virtual memory at this size */
+      break;
+    }
+  }
+}
+
+/* 
+** Try to find a perfect hash function.  
+** Return the successful initializer for the initial hash. 
+** Return 0 if no perfect hash could be found.
+*/
+void findhash(
+    bstuff  **tabb,       /* output, tab[] of the perfect hash, length *blen */
+    hstuff  **tabh,      /* output, table of keys indexed by hash value */
+    ub4      *alen,             /* output, 0..alen-1 is range for a of (a,b) */
+    ub4      *blen,             /* output, 0..blen-1 is range for b of (a,b) */
+    ub4      *salt,                     /* output, initializes initial hash */
+    gencode  *final,                                  /* code for final hash */
+    ub4      *scramble,                  /* input, hash = a^scramble[tab[b]] */
+    ub4      *smax,                       /* input, scramble[i] in 0..smax-1 */
+    key      *keys,                                   /* input, keys to hash */
+    ub4       nkeys,                   /* input, number of keys being hashed */
+    hashform *form)                                       /* user directives */
+{
+  ub4 bad_initkey;                       /* how many times did initkey fail? */
+  ub4 bad_perfect;                       /* how many times did perfect fail? */
+  ub4 trysalt;                        /* trial initializer for initial hash */
+  ub4 maxalen;
+  qstuff *tabq;    /* table of stuff indexed by queue value, used by augment */
+
+  /* The case of (A,B) supplied by the user is a special case */
+  if (form->hashtype == AB_HT)
+  {
+    hash_ab(tabb, alen, blen, salt, final, 
+           scramble, smax, keys, nkeys, form);
+    return;
+  }
+
+  /* guess initial values for smax, alen and blen */
+  *smax = ((ub4)1<<phash_log2(nkeys));
+  initalen(alen, blen, smax, nkeys, form);
+
+  scrambleinit(scramble, *smax);
+
+  maxalen = (form->perfect == MINIMAL_HP) ? *smax/2 : *smax;
+
+  /* allocate working memory */
+  *tabb = (bstuff *)yasm_xmalloc((size_t)(sizeof(bstuff)*(*blen)));
+  tabq  = (qstuff *)yasm_xmalloc(sizeof(qstuff)*(*blen+1));
+  *tabh  = (hstuff *)yasm_xmalloc(sizeof(hstuff)*(form->perfect == MINIMAL_HP ? 
+                                            nkeys : *smax));
+
+  /* Actually find the perfect hash */
+  *salt = 0;
+  bad_initkey = 0;
+  bad_perfect = 0;
+  for (trysalt=1; ; ++trysalt)
+  {
+    ub4 rslinit;
+    /* Try to find distinct (A,B) for all keys */
+    
+    rslinit = initkey(keys, nkeys, *tabb, *alen, *blen, *smax, trysalt,
+                     form, final);
+
+    if (rslinit == 2)
+    {      /* initkey actually found a perfect hash, not just distinct (a,b) */
+      *salt = 1;
+      *blen = 0;
+      break;
+    }
+    else if (rslinit == 0)
+    {
+      /* didn't find distinct (a,b) */
+      if (++bad_initkey >= RETRY_INITKEY)
+      {
+       /* Try to put more bits in (A,B) to make distinct (A,B) more likely */
+       if (*alen < maxalen)
+       {
+         *alen *= 2;
+       } 
+       else if (*blen < *smax)
+       {
+         *blen *= 2;
+         free(tabq);
+         free(*tabb);
+         *tabb  = (bstuff *)yasm_xmalloc((size_t)(sizeof(bstuff)*(*blen)));
+         tabq  = (qstuff *)yasm_xmalloc((size_t)(sizeof(qstuff)*(*blen+1)));
+       }
+       else
+       {
+         duplicates(*tabb, *blen, keys, form);      /* check for duplicates */
+         printf("fatal error: Cannot perfect hash: cannot find distinct (A,B)\n");
+         exit(EXIT_SUCCESS);
+       }
+       bad_initkey = 0;
+       bad_perfect = 0;
+      }
+      continue;                             /* two keys have same (a,b) pair */
+    }
+
+    printf("found distinct (A,B) on attempt %ld\n", trysalt);
+
+    /* Given distinct (A,B) for all keys, build a perfect hash */
+    if (!perfect(*tabb, *tabh, tabq, *blen, *smax, scramble, nkeys, form))
+    {
+      if ((form->hashtype != INT_HT && ++bad_perfect >= RETRY_PERFECT) || 
+         (form->hashtype == INT_HT && ++bad_perfect >= RETRY_HEX))
+      {
+       if (*blen < *smax)
+       {
+         *blen *= 2;
+         free(*tabb);
+         free(tabq);
+         *tabb  = (bstuff *)yasm_xmalloc((size_t)(sizeof(bstuff)*(*blen)));
+         tabq  = (qstuff *)yasm_xmalloc((size_t)(sizeof(qstuff)*(*blen+1)));
+         --trysalt;               /* we know this salt got distinct (A,B) */
+       }
+       else
+       {
+         printf("fatal error: Cannot perfect hash: cannot build tab[]\n");
+         exit(EXIT_SUCCESS);
+       }
+       bad_perfect = 0;
+      }
+      continue;
+    }
+    
+    *salt = trysalt;
+    break;
+  }
+
+  printf("built perfect hash table of size %ld\n", *blen);
+
+  /* free working memory */
+  free((void *)tabq);
+}
+
+#if 0
+/*
+------------------------------------------------------------------------------
+Input/output type routines
+------------------------------------------------------------------------------
+*/
+
+/* get the list of keys */
+static void getkeys(keys, nkeys, textroot, keyroot, form)
+key      **keys;                                         /* list of all keys */
+ub4       *nkeys;                                          /* number of keys */
+reroot    *textroot;                          /* get space to store key text */
+reroot    *keyroot;                                    /* get space for keys */
+hashform  *form;                                          /* user directives */
+{
+  key  *mykey;
+  char *mytext;
+  mytext = (char *)renew(textroot);
+  *keys = 0;
+  *nkeys = 0;
+  while (fgets(mytext, MAXKEYLEN, stdin))
+  {
+    mykey = (key *)renew(keyroot);
+    if (form->mode == AB_HM)
+    {
+      sscanf(mytext, "%lx %lx ", &mykey->a_k, &mykey->b_k);
+    }
+    else if (form->mode == ABDEC_HM)
+    {
+      sscanf(mytext, "%ld %ld ", &mykey->a_k, &mykey->b_k);
+    }
+    else if (form->mode == HEX_HM)
+    {
+      sscanf(mytext, "%lx ", &mykey->hash_k);
+    }
+    else if (form->mode == DECIMAL_HM)
+    {
+      sscanf(mytext, "%ld ", &mykey->hash_k);
+    }
+    else
+    {
+      mykey->name_k = (ub1 *)mytext;
+      mytext = (char *)renew(textroot);
+      mykey->len_k  = (ub4)(strlen((char *)mykey->name_k)-1);
+    }
+    mykey->next_k = *keys;
+    *keys = mykey;
+    ++*nkeys;
+  }
+  redel(textroot, mytext);
+}
+
+/* make the .c file */
+static void make_c(tab, smax, blen, scramble, final, form)
+bstuff   *tab;                                         /* table indexed by b */
+ub4       smax;                                       /* range of scramble[] */
+ub4       blen;                                /* b in 0..blen-1, power of 2 */
+ub4      *scramble;                                    /* used in final hash */
+gencode  *final;                                  /* code for the final hash */
+hashform *form;                                           /* user directives */
+{
+  ub4   i;
+  FILE *f;
+  f = fopen("phash.c", "w");
+  fprintf(f, "/* table for the mapping for the perfect hash */\n");
+  fprintf(f, "#include \"lookupa.h\"\n");
+  fprintf(f, "\n");
+  if (blen >= USE_SCRAMBLE)
+  {
+    fprintf(f, "/* A way to make the 1-byte values in tab bigger */\n");
+    if (smax > UB2MAXVAL+1)
+    {
+      fprintf(f, "unsigned long scramble[] = {\n");
+      for (i=0; i<=UB1MAXVAL; i+=4)
+        fprintf(f, "0x%.8lx, 0x%.8lx, 0x%.8lx, 0x%.8lx,\n",
+                scramble[i+0], scramble[i+1], scramble[i+2], scramble[i+3]);
+    }
+    else
+    {
+      fprintf(f, "unsigned short scramble[] = {\n");
+      for (i=0; i<=UB1MAXVAL; i+=8)
+        fprintf(f, 
+"0x%.4lx, 0x%.4lx, 0x%.4lx, 0x%.4lx, 0x%.4lx, 0x%.4lx, 0x%.4lx, 0x%.4lx,\n",
+                scramble[i+0], scramble[i+1], scramble[i+2], scramble[i+3],
+                scramble[i+4], scramble[i+5], scramble[i+6], scramble[i+7]);
+    }
+    fprintf(f, "};\n");
+    fprintf(f, "\n");
+  }
+  if (blen > 0)
+  {
+    fprintf(f, "/* small adjustments to _a_ to make values distinct */\n");
+
+    if (smax <= UB1MAXVAL+1 || blen >= USE_SCRAMBLE)
+      fprintf(f, "unsigned char tab[] = {\n");
+    else
+      fprintf(f, "unsigned short tab[] = {\n");
+
+    if (blen < 16)
+    {
+      for (i=0; i<blen; ++i) fprintf(f, "%3d,", scramble[tab[i].val_b]);
+    }
+    else if (blen <= 1024)
+    {
+      for (i=0; i<blen; i+=16)
+       fprintf(f, "%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,\n",
+               scramble[tab[i+0].val_b], scramble[tab[i+1].val_b], 
+               scramble[tab[i+2].val_b], scramble[tab[i+3].val_b], 
+               scramble[tab[i+4].val_b], scramble[tab[i+5].val_b], 
+               scramble[tab[i+6].val_b], scramble[tab[i+7].val_b], 
+               scramble[tab[i+8].val_b], scramble[tab[i+9].val_b], 
+               scramble[tab[i+10].val_b], scramble[tab[i+11].val_b], 
+               scramble[tab[i+12].val_b], scramble[tab[i+13].val_b], 
+               scramble[tab[i+14].val_b], scramble[tab[i+15].val_b]); 
+    }
+    else if (blen < USE_SCRAMBLE)
+    {
+      for (i=0; i<blen; i+=8)
+       fprintf(f, "%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,\n",
+               scramble[tab[i+0].val_b], scramble[tab[i+1].val_b], 
+               scramble[tab[i+2].val_b], scramble[tab[i+3].val_b], 
+               scramble[tab[i+4].val_b], scramble[tab[i+5].val_b], 
+               scramble[tab[i+6].val_b], scramble[tab[i+7].val_b]); 
+    }
+    else 
+    {
+      for (i=0; i<blen; i+=16)
+       fprintf(f, "%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,\n",
+               tab[i+0].val_b, tab[i+1].val_b, 
+               tab[i+2].val_b, tab[i+3].val_b, 
+               tab[i+4].val_b, tab[i+5].val_b, 
+               tab[i+6].val_b, tab[i+7].val_b, 
+               tab[i+8].val_b, tab[i+9].val_b, 
+               tab[i+10].val_b, tab[i+11].val_b, 
+               tab[i+12].val_b, tab[i+13].val_b, 
+               tab[i+14].val_b, tab[i+15].val_b); 
+    }
+    fprintf(f, "};\n");
+    fprintf(f, "\n");
+  }
+  fprintf(f, "/* The hash function */\n");
+  switch(form->mode)
+  {
+  case NORMAL_HM:
+    fprintf(f, "ub4 phash(key, len)\n");
+    fprintf(f, "char *key;\n");
+    fprintf(f, "int   len;\n");
+    break;
+  case INLINE_HM:
+  case HEX_HM:
+  case DECIMAL_HM:
+    fprintf(f, "ub4 phash(val)\n");
+    fprintf(f, "ub4 val;\n");
+    break;
+  case AB_HM:
+  case ABDEC_HM:
+    fprintf(f, "ub4 phash(a,b)\n");
+    fprintf(f, "ub4 a;\n");
+    fprintf(f, "ub4 b;\n");
+    break;
+  }
+  fprintf(f, "{\n");
+  for (i=0; i<final->used; ++i)
+    fprintf(f, final->line[i]);
+  fprintf(f, "  return rsl;\n");
+  fprintf(f, "}\n");
+  fprintf(f, "\n");
+  fclose(f);
+}
+
+/*
+------------------------------------------------------------------------------
+Read in the keys, find the hash, and write the .c and .h files
+------------------------------------------------------------------------------
+*/
+static void driver(form)
+hashform *form;                                           /* user directives */
+{
+  ub4       nkeys;                                         /* number of keys */
+  key      *keys;                                    /* head of list of keys */
+  bstuff   *tab;                                       /* table indexed by b */
+  ub4       smax;            /* scramble[] values in 0..smax-1, a power of 2 */
+  ub4       alen;                            /* a in 0..alen-1, a power of 2 */
+  ub4       blen;                            /* b in 0..blen-1, a power of 2 */
+  ub4       salt;                       /* a parameter to the hash function */
+  reroot   *textroot;                      /* MAXKEYLEN-character text lines */
+  reroot   *keyroot;                                       /* source of keys */
+  gencode   final;                                    /* code for final hash */
+  ub4       i;
+  ub4       scramble[SCRAMBLE_LEN];           /* used in final hash function */
+  char      buf[10][80];                        /* buffer for generated code */
+  char     *buf2[10];                             /* also for generated code */
+
+  /* set up memory sources */
+  textroot = remkroot((size_t)MAXKEYLEN);
+  keyroot  = remkroot(sizeof(key));
+
+  /* set up code for final hash */
+  final.line = buf2;
+  final.used = 0;
+  final.len  = 10;
+  for (i=0; i<10; ++i) final.line[i] = buf[i];
+
+  /* read in the list of keywords */
+  getkeys(&keys, &nkeys, textroot, keyroot, form);
+  printf("Read in %ld keys\n",nkeys);
+
+  /* find the hash */
+  findhash(&tab, &alen, &blen, &salt, &final, 
+          scramble, &smax, keys, nkeys, form);
+
+  /* generate the phash.c file */
+  make_c(tab, smax, blen, scramble, &final, form);
+  printf("Wrote phash.c\n");
+
+  /* clean up memory sources */
+  refree(textroot);
+  refree(keyroot);
+  free((void *)tab);
+  printf("Cleaned up\n");
+}
+
+
+/* Interpret arguments and call the driver */
+/* See usage_error for the expected arguments */
+int main(argc, argv)
+int    argc;
+char **argv;
+{
+  int      mode_given = FALSE;
+  int      minimal_given = FALSE;
+  int      speed_given = FALSE;
+  hashform form;
+  char    *c;
+
+  /* default behavior */
+  form.mode = NORMAL_HM;
+  form.hashtype = STRING_HT;
+  form.perfect = MINIMAL_HP;
+  form.speed = SLOW_HS;
+
+  /* Generate the [minimal] perfect hash */
+  driver(&form);
+
+  return EXIT_SUCCESS;
+}
+#endif
diff --git a/tools/gap/perfect.h b/tools/gap/perfect.h
new file mode 100644 (file)
index 0000000..297778a
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+------------------------------------------------------------------------------
+perfect.h: code to generate code for a hash for perfect hashing.
+(c) Bob Jenkins, September 1996
+You may use this code in any way you wish, and it is free.  No warranty.
+I hereby place this in the public domain.
+Source is http://burtleburtle.net/bob/c/perfect.h
+------------------------------------------------------------------------------
+*/
+
+#ifndef STANDARD
+#include "standard.h"
+#endif
+
+#ifndef PERFECT
+#define PERFECT
+
+#define MAXKEYLEN 30                              /* maximum length of a key */
+#define USE_SCRAMBLE  4096           /* use scramble if blen >= USE_SCRAMBLE */
+#define SCRAMBLE_LEN ((ub4)1<<16)                    /* length of *scramble* */
+#define RETRY_INITKEY 2048  /* number of times to try to find distinct (a,b) */
+#define RETRY_PERFECT 1     /* number of times to try to make a perfect hash */
+#define RETRY_HEX     200               /* RETRY_PERFECT when hex keys given */
+
+/* the generated code for the final hash, assumes initial hash is done */
+struct gencode
+{
+  char **line;                       /* array of text lines, 80 bytes apiece */
+  /*
+   * The code placed here must declare "ub4 rsl" 
+   * and assign it the value of the perfect hash using the function inputs.
+   * Later code will be tacked on which returns rsl or manipulates it according
+   * to the user directives.
+   *
+   * This code is at the top of the routine; it may and must declare any
+   * local variables it needs.
+   *
+   * Each way of filling in **line should be given a comment that is a unique
+   * tag.  A testcase named with that tag should also be found which tests
+   * the generated code.
+   */
+  ub4    len;                    /* number of lines available for final hash */
+  ub4    used;                         /* number of lines used by final hash */
+
+  ub4    lowbit;                          /* for HEX, lowest interesting bit */
+  ub4    highbit;                        /* for HEX, highest interesting bit */
+  ub4    diffbits;                         /* bits which differ for some key */
+  ub4    i,j,k,l,m,n,o;                      /* state machine used in hexn() */
+};
+typedef  struct gencode  gencode;
+
+/* user directives: perfect hash? minimal perfect hash? input is an int? */
+struct hashform
+{
+  enum {
+    NORMAL_HM,                                            /* key is a string */
+    INLINE_HM,    /* user will do initial hash, we must choose salt for them */
+    HEX_HM,              /* key to be hashed is a hexidecimal 4-byte integer */
+    DECIMAL_HM,              /* key to be hashed is a decimal 4-byte integer */
+    AB_HM,      /* key to be hashed is "A B", where A and B are (A,B) in hex */
+    ABDEC_HM                                   /* like AB_HM, but in decimal */
+  } mode;
+  enum {
+    STRING_HT,                                            /* key is a string */
+    INT_HT,                                             /* key is an integer */
+    AB_HT             /* dunno what key is, but input is distinct (A,B) pair */
+  } hashtype;
+  enum {
+    NORMAL_HP,                                   /* just find a perfect hash */
+    MINIMAL_HP                                /* find a minimal perfect hash */
+  } perfect;
+  enum {
+    FAST_HS,                                                    /* fast mode */
+    SLOW_HS                                                     /* slow mode */
+  } speed;
+};
+typedef  struct hashform  hashform;
+
+/* representation of a key */
+struct key
+{
+  ub1        *name_k;                                      /* the actual key */
+  ub4         len_k;                         /* the length of the actual key */
+  ub4         hash_k;                 /* the initial hash value for this key */
+  struct key *next_k;                                            /* next key */
+/* beyond this point is mapping-dependent */
+  ub4         a_k;                            /* a, of the key maps to (a,b) */
+  ub4         b_k;                            /* b, of the key maps to (a,b) */
+  struct key *nextb_k;                               /* next key with this b */
+};
+typedef  struct key  key;
+
+/* things indexed by b of original (a,b) pair */
+struct bstuff
+{
+  ub2  val_b;                                        /* hash=a^tabb[b].val_b */
+  key *list_b;                   /* tabb[i].list_b is list of keys with b==i */
+  ub4  listlen_b;                                        /* length of list_b */
+  ub4  water_b;           /* high watermark of who has visited this map node */
+};
+typedef  struct bstuff  bstuff;
+
+/* things indexed by final hash value */
+struct hstuff
+{
+  key *key_h;                   /* tabh[i].key_h is the key with a hash of i */
+};
+typedef  struct hstuff hstuff;
+
+/* things indexed by queue position */
+struct qstuff
+{
+  bstuff *b_q;                        /* b that currently occupies this hash */
+  ub4     parent_q;     /* queue position of parent that could use this hash */
+  ub2     newval_q;      /* what to change parent tab[b] to to use this hash */
+  ub2     oldval_q;                              /* original value of tab[b] */
+};
+typedef  struct qstuff  qstuff;
+
+/* return ceiling(log based 2 of x) */
+ub4 phash_log2(ub4 x);
+
+/* Given the keys, scramble[], and hash mode, find the perfect hash */
+void findhash(bstuff **tabb, hstuff **tabh, ub4 *alen, ub4 *blen, ub4 *salt,
+               gencode *final, ub4 *scramble, ub4 *smax, key *keys, ub4 nkeys, 
+               hashform *form);
+
+/* private, but in a different file because it's excessively verbose */
+int inithex(key *keys, ub4 nkeys, ub4 alen, ub4 blen, ub4 smax, ub4 salt,
+           gencode *final, hashform *form);
+
+#endif /* PERFECT */
diff --git a/tools/gap/standard.h b/tools/gap/standard.h
new file mode 100644 (file)
index 0000000..596b893
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+------------------------------------------------------------------------------
+Standard definitions and types, Bob Jenkins
+------------------------------------------------------------------------------
+*/
+#ifndef STANDARD
+#define STANDARD
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+typedef  unsigned long  int  ub4;   /* unsigned 4-byte quantities */
+#define UB4BITS 32
+typedef  unsigned short int  ub2;
+#define UB2MAXVAL 0xffff
+typedef  unsigned       char ub1;
+#define UB1MAXVAL 0xff
+typedef                 int  word;  /* fastest type available */
+
+#define bis(target,mask)  ((target) |=  (mask))
+#define bic(target,mask)  ((target) &= ~(mask))
+#define bit(target,mask)  ((target) &   (mask))
+#ifndef align
+# define align(a) (((ub4)a+(sizeof(void *)-1))&(~(sizeof(void *)-1)))
+#endif /* align */
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#endif /* STANDARD */