From: Peter Johnson Date: Sat, 4 Mar 2006 22:09:26 +0000 (-0000) Subject: Rewrite x86 identifier recognition to use a minimal perfect hash table X-Git-Tag: v0.5.0rc2~5^2~43 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=90a38d71b05fe4e79eab744d79ba555ff4c80986;p=yasm Rewrite x86 identifier recognition to use a minimal perfect hash table 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 --- diff --git a/Makefile.am b/Makefile.am index 8e938d61..45e5dde3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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]* diff --git a/Mkfiles/Makefile.dj b/Mkfiles/Makefile.dj index 4ddcb664..94f3a01a 100644 --- a/Mkfiles/Makefile.dj +++ b/Mkfiles/Makefile.dj @@ -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) diff --git a/Mkfiles/Makefile.flat b/Mkfiles/Makefile.flat index b72e09fb..6752935e 100644 --- a/Mkfiles/Makefile.flat +++ b/Mkfiles/Makefile.flat @@ -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 index 00000000..6bc06a09 --- /dev/null +++ b/Mkfiles/vc/gap/gap.vcproj @@ -0,0 +1,161 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Mkfiles/vc/gap/run.bat b/Mkfiles/vc/gap/run.bat new file mode 100644 index 00000000..d5060801 --- /dev/null +++ b/Mkfiles/vc/gap/run.bat @@ -0,0 +1,2 @@ +cd ..\..\..\ +%1 modules\arch\x86\x86parse.gap x86parse.c diff --git a/Mkfiles/vc/modules/modules.vcproj b/Mkfiles/vc/modules/modules.vcproj index 06b9c79f..fd030f0d 100644 --- a/Mkfiles/vc/modules/modules.vcproj +++ b/Mkfiles/vc/modules/modules.vcproj @@ -252,7 +252,7 @@ + RelativePath="..\..\..\modules\arch\x86\x86id.c"> lc3bid.c -%1 -s modules\arch\x86\x86id.re > x86id.c -%1 -s modules\parsers\nasm\nasm-token.re > nasm-token.c -%1 -s modules\parsers\gas\gas-token.re > gas-token.c +%1 -s -o lc3bid.c modules\arch\lc3b\lc3bid.re +%1 -b -o nasm-token.c modules\parsers\nasm\nasm-token.re +%1 -b -o gas-token.c modules\parsers\gas\gas-token.re diff --git a/Mkfiles/vc/yasm.sln b/Mkfiles/vc/yasm.sln index 56bcfd3f..e496f2da 100644 --- a/Mkfiles/vc/yasm.sln +++ b/Mkfiles/vc/yasm.sln @@ -7,6 +7,7 @@ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "modules", "modules\modules.vcproj", "{D715A3D4-EFAA-442E-AD8B-5B4FF64E1DD6}" ProjectSection(ProjectDependencies) = postProject {3C58BE13-50A3-4583-984D-D8902B3D7713} = {3C58BE13-50A3-4583-984D-D8902B3D7713} + {5758BF4E-ABC4-11DA-B012-B622A1EF5492} = {5758BF4E-ABC4-11DA-B012-B622A1EF5492} {29FE7874-1256-4AD6-B889-68E399DC9608} = {29FE7874-1256-4AD6-B889-68E399DC9608} {225700A5-07B8-434E-AD61-555278BF6733} = {225700A5-07B8-434E-AD61-555278BF6733} EndProjectSection @@ -25,6 +26,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "re2c", "re2c\re2c.vcproj", ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gap", "gap\gap.vcproj", "{5758BF4E-ABC4-11DA-B012-B622A1EF5492}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "genmodule", "genmodule\genmodule.vcproj", "{F0E8B707-00C5-4FF2-B8EF-7C39817132A0}" ProjectSection(ProjectDependencies) = postProject EndProjectSection @@ -55,6 +60,10 @@ Global {3C58BE13-50A3-4583-984D-D8902B3D7713}.Debug.Build.0 = Debug|Win32 {3C58BE13-50A3-4583-984D-D8902B3D7713}.Release.ActiveCfg = Release|Win32 {3C58BE13-50A3-4583-984D-D8902B3D7713}.Release.Build.0 = Release|Win32 + {5758BF4E-ABC4-11DA-B012-B622A1EF5492}.Debug.ActiveCfg = Debug|Win32 + {5758BF4E-ABC4-11DA-B012-B622A1EF5492}.Debug.Build.0 = Debug|Win32 + {5758BF4E-ABC4-11DA-B012-B622A1EF5492}.Release.ActiveCfg = Release|Win32 + {5758BF4E-ABC4-11DA-B012-B622A1EF5492}.Release.Build.0 = Release|Win32 {F0E8B707-00C5-4FF2-B8EF-7C39817132A0}.Debug.ActiveCfg = Debug|Win32 {F0E8B707-00C5-4FF2-B8EF-7C39817132A0}.Debug.Build.0 = Debug|Win32 {F0E8B707-00C5-4FF2-B8EF-7C39817132A0}.Release.ActiveCfg = Release|Win32 diff --git a/Mkfiles/vc8/gap/gap.vcproj b/Mkfiles/vc8/gap/gap.vcproj new file mode 100644 index 00000000..9643eac0 --- /dev/null +++ b/Mkfiles/vc8/gap/gap.vcproj @@ -0,0 +1,235 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Mkfiles/vc8/gap/run.bat b/Mkfiles/vc8/gap/run.bat new file mode 100644 index 00000000..d5060801 --- /dev/null +++ b/Mkfiles/vc8/gap/run.bat @@ -0,0 +1,2 @@ +cd ..\..\..\ +%1 modules\arch\x86\x86parse.gap x86parse.c diff --git a/Mkfiles/vc8/modules/modules.vcproj b/Mkfiles/vc8/modules/modules.vcproj index 0f4fe881..5584e5c7 100644 --- a/Mkfiles/vc8/modules/modules.vcproj +++ b/Mkfiles/vc8/modules/modules.vcproj @@ -572,7 +572,7 @@ diff --git a/Mkfiles/vc8/re2c/run.bat b/Mkfiles/vc8/re2c/run.bat index e2b51377..cde2a7b6 100644 --- a/Mkfiles/vc8/re2c/run.bat +++ b/Mkfiles/vc8/re2c/run.bat @@ -1,5 +1,4 @@ cd ..\..\..\ -%1 -s modules\arch\lc3b\lc3bid.re > lc3bid.c -%1 -s modules\arch\x86\x86id.re > x86id.c -%1 -s modules\parsers\nasm\nasm-token.re > nasm-token.c -%1 -s modules\parsers\gas\gas-token.re > gas-token.c +%1 -s -o lc3bid.c modules\arch\lc3b\lc3bid.re +%1 -b -o nasm-token.c modules\parsers\nasm\nasm-token.re +%1 -b -o gas-token.c modules\parsers\gas\gas-token.re diff --git a/Mkfiles/vc8/yasm.sln b/Mkfiles/vc8/yasm.sln index 6fb44f4d..274cf5bd 100644 --- a/Mkfiles/vc8/yasm.sln +++ b/Mkfiles/vc8/yasm.sln @@ -8,6 +8,7 @@ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "modules", "modules\modules.vcproj", "{D715A3D4-EFAA-442E-AD8B-5B4FF64E1DD6}" ProjectSection(ProjectDependencies) = postProject {3C58BE13-50A3-4583-984D-D8902B3D7713} = {3C58BE13-50A3-4583-984D-D8902B3D7713} + {5758BF4E-ABC4-11DA-B012-B622A1EF5492} = {5758BF4E-ABC4-11DA-B012-B622A1EF5492} {29FE7874-1256-4AD6-B889-68E399DC9608} = {29FE7874-1256-4AD6-B889-68E399DC9608} {225700A5-07B8-434E-AD61-555278BF6733} = {225700A5-07B8-434E-AD61-555278BF6733} EndProjectSection @@ -22,6 +23,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "genmacro", "genmacro\genmac EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "re2c", "re2c\re2c.vcproj", "{3C58BE13-50A3-4583-984D-D8902B3D7713}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gap", "gap\gap.vcproj", "{5758BF4E-ABC4-11DA-B012-B622A1EF5492}" +EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "genmodule", "genmodule\genmodule.vcproj", "{F0E8B707-00C5-4FF2-B8EF-7C39817132A0}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{825AC694-358C-4D8D-92DE-33A2691978CE}" @@ -77,6 +80,14 @@ Global {3C58BE13-50A3-4583-984D-D8902B3D7713}.Release|Win32.Build.0 = Release|Win32 {3C58BE13-50A3-4583-984D-D8902B3D7713}.Release|x64.ActiveCfg = Release|Win32 {3C58BE13-50A3-4583-984D-D8902B3D7713}.Release|x64.Build.0 = Release|Win32 + {5758BF4E-ABC4-11DA-B012-B622A1EF5492}.Debug|Win32.ActiveCfg = Debug|Win32 + {5758BF4E-ABC4-11DA-B012-B622A1EF5492}.Debug|Win32.Build.0 = Debug|Win32 + {5758BF4E-ABC4-11DA-B012-B622A1EF5492}.Debug|x64.ActiveCfg = Debug|Win32 + {5758BF4E-ABC4-11DA-B012-B622A1EF5492}.Debug|x64.Build.0 = Debug|Win32 + {5758BF4E-ABC4-11DA-B012-B622A1EF5492}.Release|Win32.ActiveCfg = Release|Win32 + {5758BF4E-ABC4-11DA-B012-B622A1EF5492}.Release|Win32.Build.0 = Release|Win32 + {5758BF4E-ABC4-11DA-B012-B622A1EF5492}.Release|x64.ActiveCfg = Release|Win32 + {5758BF4E-ABC4-11DA-B012-B622A1EF5492}.Release|x64.Build.0 = Release|Win32 {F0E8B707-00C5-4FF2-B8EF-7C39817132A0}.Debug|Win32.ActiveCfg = Debug|Win32 {F0E8B707-00C5-4FF2-B8EF-7C39817132A0}.Debug|Win32.Build.0 = Debug|Win32 {F0E8B707-00C5-4FF2-B8EF-7C39817132A0}.Debug|x64.ActiveCfg = Debug|Win32 diff --git a/libyasm/Makefile.inc b/libyasm/Makefile.inc index b220a2a8..3dba3592 100644 --- a/libyasm/Makefile.inc +++ b/libyasm/Makefile.inc @@ -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 diff --git a/libyasm/arch.h b/libyasm/arch.h index bb414355..31f56868 100644 --- a/libyasm/arch.h +++ b/libyasm/arch.h @@ -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 index 00000000..6e23fb4f --- /dev/null +++ b/libyasm/phash.c @@ -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= 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= 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 index 00000000..1f647257 --- /dev/null +++ b/libyasm/phash.h @@ -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); diff --git a/modules/arch/lc3b/lc3barch.c b/modules/arch/lc3b/lc3barch.c index 04e5a9d6..2fb5b8ff 100644 --- a/modules/arch/lc3b/lc3barch.c +++ b/modules/arch/lc3b/lc3barch.c @@ -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, diff --git a/modules/arch/lc3b/lc3barch.h b/modules/arch/lc3b/lc3barch.h index f034d4da..fe5304d3 100644 --- a/modules/arch/lc3b/lc3barch.h +++ b/modules/arch/lc3b/lc3barch.h @@ -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 diff --git a/modules/arch/lc3b/lc3bid.re b/modules/arch/lc3b/lc3bid.re index 85c13648..5c81c460 100644 --- a/modules/arch/lc3b/lc3bid.re +++ b/modules/arch/lc3b/lc3bid.re @@ -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; -} diff --git a/modules/arch/x86/Makefile.inc b/modules/arch/x86/Makefile.inc index b50caf80..24e90fa7 100644 --- a/modules/arch/x86/Makefile.inc +++ b/modules/arch/x86/Makefile.inc @@ -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 diff --git a/modules/arch/x86/x86arch.c b/modules/arch/x86/x86arch.c index 825709b2..eab49089 100644 --- a/modules/arch/x86/x86arch.c +++ b/modules/arch/x86/x86arch.c @@ -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, diff --git a/modules/arch/x86/x86arch.h b/modules/arch/x86/x86arch.h index 03fb75d3..1a3d7b64 100644 --- a/modules/arch/x86/x86arch.h +++ b/modules/arch/x86/x86arch.h @@ -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, diff --git a/modules/arch/x86/x86id.re b/modules/arch/x86/x86id.c similarity index 65% rename from modules/arch/x86/x86id.re rename to modules/arch/x86/x86id.c index 6f79eb2a..1b374a49 100644 --- a/modules/arch/x86/x86id.re +++ b/modules/arch/x86/x86id.c @@ -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 #include RCSID("$Id$"); @@ -31,6 +32,7 @@ RCSID("$Id$"); #define YASM_BC_INTERNAL #define YASM_EXPR_INTERNAL #include +#include #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; iparser) { + 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; imode_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; iregtmod >> 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 index 00000000..b483841a --- /dev/null +++ b/modules/arch/x86/x86parse.gap @@ -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 + diff --git a/modules/parsers/gas/gas-token.re b/modules/parsers/gas/gas-token.re index f6e97bca..247c8980 100644 --- a/modules/parsers/gas/gas-token.re +++ b/modules/parsers/gas/gas-token.re @@ -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); diff --git a/modules/parsers/nasm/nasm-bison.y b/modules/parsers/nasm/nasm-bison.y index a56bc658..cd918322 100644 --- a/modules/parsers/nasm/nasm-bison.y +++ b/modules/parsers/nasm/nasm-bison.y @@ -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); } } } diff --git a/modules/parsers/nasm/nasm-parser.h b/modules/parsers/nasm/nasm-parser.h index d0062d2b..c10d0016 100644 --- a/modules/parsers/nasm/nasm-parser.h +++ b/modules/parsers/nasm/nasm-parser.h @@ -69,7 +69,8 @@ typedef struct yasm_parser_nasm { DIRECTIVE, DIRECTIVE2, LINECHG, - LINECHG2 + LINECHG2, + INSTRUCTION } state; } yasm_parser_nasm; diff --git a/modules/parsers/nasm/nasm-token.re b/modules/parsers/nasm/nasm-token.re index 41a1377a..6d9f0064 100644 --- a/modules/parsers/nasm/nasm-token.re +++ b/modules/parsers/nasm/nasm-token.re @@ -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); diff --git a/po/POTFILES.in b/po/POTFILES.in index 89ebb8f8..52ab74b3 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -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 diff --git a/tools/Makefile.inc b/tools/Makefile.inc index 4e6ec10e..264b8e16 100644 --- a/tools/Makefile.inc +++ b/tools/Makefile.inc @@ -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 index 00000000..a6bf9a3e --- /dev/null +++ b/tools/gap/Makefile.inc @@ -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 index 00000000..981649c6 --- /dev/null +++ b/tools/gap/gap.c @@ -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 +#include +#include +#include +#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; imulti_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(®tmod_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(®tmod_byp)) { + db = yasm_xmalloc(sizeof(dir_byp)); + db->parser = NULL; + db->dirs = HAMT_create(hamt_error); + + STAILQ_INSERT_TAIL(®tmod_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", ®tmod_byp); +} + +static void +parse_prefix(void) +{ + parse_generic(PREFIX, "PREFIX", &insnprefix_byp); +} + +static void +parse_reg(void) +{ + parse_generic(REG, "REG", ®tmod_byp); +} + +static void +parse_reggroup(void) +{ + parse_generic(REGGROUP, "REGGROUP", ®tmod_byp); +} + +static void +parse_segreg(void) +{ + parse_generic(SEGREG, "SEGREG", ®tmod_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; iname_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; iname_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= %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 \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(®tmod_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 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, ®tmod_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 index 00000000..2eae6c6f --- /dev/null +++ b/tools/gap/perfect.c @@ -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<>const3)); + 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; ihashtype) + { + 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; iname_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; iline[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; ilen_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; inextb_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; qval_b */ + + if (!trans && (q == 1)) + break; /* don't do transitive closure */ + + for (i=0; ilist_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 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; ia_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<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<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<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; imode) + { + 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; iused; ++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 index 00000000..297778a2 --- /dev/null +++ b/tools/gap/perfect.h @@ -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 index 00000000..596b8936 --- /dev/null +++ b/tools/gap/standard.h @@ -0,0 +1,35 @@ +/* +------------------------------------------------------------------------------ +Standard definitions and types, Bob Jenkins +------------------------------------------------------------------------------ +*/ +#ifndef STANDARD +#define STANDARD + +#include +#include +#include +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 */